diff --git a/src/uix/eidos/components/words/words-column-inserter.svelte b/src/uix/eidos/components/words/words-column-inserter.svelte index 1bcaf99b9..90c5991fc 100644 --- a/src/uix/eidos/components/words/words-column-inserter.svelte +++ b/src/uix/eidos/components/words/words-column-inserter.svelte @@ -64,6 +64,7 @@ let slots = $state([]); let openColumnKey = $state(null); + let hoveredColumnKey = $state(null); let raf = 0; // Re-entrancy guard. The dropdown can fire `onSelect` twice in a // row (pointerup + keyboard activation, or a single-click that gets @@ -152,6 +153,39 @@ schedule(); }); + // Track which column the mouse is over — `pointer-events: none` on + // the inserter wrap is required so caret/text events pass through to + // the contenteditable below, but it ALSO disables CSS `:hover` + // detection on the wrap (the browser can't dispatch `mouseover` to a + // pointer-events:none element). So we listen on the column elements + // directly and stash the key in `hoveredColumnKey` — the wrap then + // reveals its trigger via `data-hovered={key === hoveredColumnKey}`. + $effect(() => { + // Re-bind when slots change (so we attach to fresh column elements). + void slots; + if (!content) return; + const cols = Array.from(content.querySelectorAll('[data-words-column]')) as HTMLElement[]; + const disposers: Array<() => void> = []; + for (const col of cols) { + const ids = readColumnPath(col); + if (!ids) continue; + const key = `${ids.columnsIdx}-${ids.colIdx}`; + disposers.push( + dom.listen(col, 'mouseenter', () => { + hoveredColumnKey = key; + }) + ); + disposers.push( + dom.listen(col, 'mouseleave', () => { + if (hoveredColumnKey === key) hoveredColumnKey = null; + }) + ); + } + return () => { + for (const d of disposers) d?.(); + }; + }); + function emptyParagraph(): WordsBlock { return { type: 'paragraph', children: [{ type: 'text', text: '' }] } as WordsBlock; } @@ -326,6 +360,7 @@