From 5a3029e58984fb58c393f170ca980f72789fce97 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 28 May 2026 00:16:08 +0200 Subject: [PATCH] feat(words): real gutter rail for the block-handle + inserter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The grip `::` and the "+" inserter were positioned at `block.rect.left - 28..32` — fine in theory but the content area had symmetric `padding-inline` so that math landed the overlays in empty body space outside the editor box. User-visible result: the left band had no width, the grip dragged on/off the edge unevenly, and the click target felt invisible. Fix: dedicate a visible rail of `2.5rem` (~40px) on the side OPPOSITE the drawer, by switching the content + placeholder from symmetric `padding-inline` to an asymmetric pair (`padding-inline-start` + `padding-inline-end`). New token `--_words-rail-px` is added to one of those sides per drawer position. - Drawer on RIGHT (default): rail is on the LEFT — content's `padding-inline-start` becomes `content-px + rail-px`. The grip at `block.rect.left - 32` now lands inside that visible band (≈ 24-52 px from the editor's left edge), with the inserter "+" button at -28 alongside it. Block text starts 56 px from the editor's left edge. - Drawer on LEFT: mirrored — the asymmetric padding flips via `[data-words]:has([data-words-drawer][data-side='left']) > [data-words-content]` so the rail moves to the inline-end side where the overlays now render. No JS changes needed — the existing geometry-based positioning (`block.rect.left - 32`, `seam.left - 28` for the "+", with the drawer-side detection added in an earlier commit) automatically lands in the new band because `block.rect.left` shifted right by the rail width. Verified in browser: hovering anywhere over a paragraph reveals the grip at the expected band position, with no flicker, and the hit area is comfortably wide for a click. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/uix/eidos/components/words/words.css | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/uix/eidos/components/words/words.css b/src/uix/eidos/components/words/words.css index fd7adfc36..b780b8b7f 100644 --- a/src/uix/eidos/components/words/words.css +++ b/src/uix/eidos/components/words/words.css @@ -4,6 +4,11 @@ --_words-content-px: var(--words-content-px-md); --_words-content-py: var(--words-content-py-md); --_words-content-min-block-size: var(--words-content-min-block-size-md); + /* Gutter reserved for the block-handle grip + inserter "+" overlay. + Content is padded by this much on the side OPPOSITE to the drawer + so the floating overlays have a visible band to land in. ~40px + fits a 28×28 hit area with 12px breathing room before the text. */ + --_words-rail-px: 2.5rem; --_words-toolbar-px: var(--words-toolbar-px-md); --_words-toolbar-py: var(--words-toolbar-py-md); --_words-button-size: var(--words-button-size-md); @@ -1759,7 +1764,9 @@ [data-words-placeholder] { display: block; padding-block-start: var(--_words-content-py); - padding-inline: var(--_words-content-px); + /* Default (drawer on right): rail on the LEFT for the grip. */ + padding-inline-start: calc(var(--_words-content-px) + var(--_words-rail-px)); + padding-inline-end: var(--_words-content-px); color: var(--words-placeholder-color); pointer-events: none; } @@ -1772,7 +1779,9 @@ [data-words-content] { min-block-size: var(--_words-content-min-block-size); padding-block: var(--_words-content-py); - padding-inline: var(--_words-content-px); + /* Default (drawer on right): rail on the LEFT for the grip + "+". */ + padding-inline-start: calc(var(--_words-content-px) + var(--_words-rail-px)); + padding-inline-end: var(--_words-content-px); color: var(--words-content-color); outline: none; overflow-wrap: anywhere; @@ -1782,6 +1791,14 @@ -webkit-user-select: text; } +/* When the drawer lives on the LEFT, mirror: rail moves to the RIGHT + so the grip + "+" don't fight the drawer's gutter. */ +[data-words]:has([data-words-drawer][data-side='left']) > [data-words-content], +[data-words]:has([data-words-drawer][data-side='left']) > [data-words-placeholder] { + padding-inline-start: var(--_words-content-px); + padding-inline-end: calc(var(--_words-content-px) + var(--_words-rail-px)); +} + [data-words-content] * { user-select: text; -webkit-user-select: text;