fix: prevent phantom mouseover from hijacking slash menu

This commit is contained in:
zhayujie
2026-03-30 11:52:05 +08:00
parent ef33a93654
commit e57ef37167

View File

@@ -464,6 +464,8 @@ let slashActiveIdx = 0;
let slashFiltered = []; let slashFiltered = [];
let slashJustSelected = false; let slashJustSelected = false;
let slashLastFilter = ''; let slashLastFilter = '';
let slashLastMouseX = -1;
let slashLastMouseY = -1;
function showSlashMenu(filter) { function showSlashMenu(filter) {
const q = filter.toLowerCase(); const q = filter.toLowerCase();
@@ -482,6 +484,7 @@ function showSlashMenu(filter) {
if (changed) slashActiveIdx = 0; if (changed) slashActiveIdx = 0;
slashActiveIdx = Math.min(slashActiveIdx, slashFiltered.length - 1); slashActiveIdx = Math.min(slashActiveIdx, slashFiltered.length - 1);
slashNavByKeyboard = true;
renderSlashItems(); renderSlashItems();
slashMenu.classList.remove('hidden'); slashMenu.classList.remove('hidden');
} }
@@ -492,6 +495,9 @@ function hideSlashMenu() {
slashFiltered = []; slashFiltered = [];
slashActiveIdx = -1; slashActiveIdx = -1;
slashLastFilter = ''; slashLastFilter = '';
slashNavByKeyboard = false;
slashLastMouseX = -1;
slashLastMouseY = -1;
} }
function isSlashMenuVisible() { function isSlashMenuVisible() {
@@ -512,7 +518,25 @@ function renderSlashItems() {
} }
// Delegated events on the persistent slashMenu container (not destroyed by innerHTML) // Delegated events on the persistent slashMenu container (not destroyed by innerHTML)
// Use coordinate comparison to distinguish real mouse movement from DOM-rebuild phantom events.
slashMenu.addEventListener('mousemove', (e) => {
if (e.clientX === slashLastMouseX && e.clientY === slashLastMouseY) return;
slashLastMouseX = e.clientX;
slashLastMouseY = e.clientY;
if (!slashNavByKeyboard) return;
slashNavByKeyboard = false;
const item = e.target.closest('.slash-menu-item');
if (!item) return;
const idx = parseInt(item.dataset.idx);
if (idx === slashActiveIdx) return;
slashActiveIdx = idx;
slashMenu.querySelectorAll('.slash-menu-item').forEach(el => {
el.classList.toggle('active', parseInt(el.dataset.idx) === idx);
});
});
slashMenu.addEventListener('mouseover', (e) => { slashMenu.addEventListener('mouseover', (e) => {
if (slashNavByKeyboard) return;
const item = e.target.closest('.slash-menu-item'); const item = e.target.closest('.slash-menu-item');
if (!item) return; if (!item) return;
const idx = parseInt(item.dataset.idx); const idx = parseInt(item.dataset.idx);
@@ -565,12 +589,14 @@ chatInput.addEventListener('keydown', function(e) {
if (isSlashMenuVisible()) { if (isSlashMenuVisible()) {
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
e.preventDefault(); e.preventDefault();
slashNavByKeyboard = true;
slashActiveIdx = Math.min(slashActiveIdx + 1, slashFiltered.length - 1); slashActiveIdx = Math.min(slashActiveIdx + 1, slashFiltered.length - 1);
renderSlashItems(); renderSlashItems();
return; return;
} }
if (e.key === 'ArrowUp') { if (e.key === 'ArrowUp') {
e.preventDefault(); e.preventDefault();
slashNavByKeyboard = true;
slashActiveIdx = Math.max(slashActiveIdx - 1, 0); slashActiveIdx = Math.max(slashActiveIdx - 1, 0);
renderSlashItems(); renderSlashItems();
return; return;