From 8cdc4e3b9eae891c7196b2d74cbf0bf0a78e0afb Mon Sep 17 00:00:00 2001 From: dev Date: Sun, 31 May 2026 13:59:46 +0200 Subject: [PATCH] fix(words): column inserter `+` reveals on hover for non-empty columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pointer-events: none` on the inserter wrap (required so caret/text events pass through to the contenteditable below) ALSO disabled CSS `:hover` detection — the browser doesn't dispatch `mouseover` to pointer-events:none elements, so the wrap's `:hover` styles never fired and the `+` trigger stayed at opacity 0 forever. Fix: track hover via JS — listen to `mouseenter`/`mouseleave` on the column elements directly, stash the key in `hoveredColumnKey`, expose to CSS via `data-hovered` on the wrap. CSS now uses `[data-words-column-inserter][data-hovered]` instead of `:hover`. Effect: hovering a non-empty column now reveals the `+` at the bottom of the column, allowing users to add more blocks below the existing content. Same fix applied to the empty-column reveal-on-hover (the opacity-1 boost when fully hovered). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../words/words-column-inserter.svelte | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) 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 @@