From 125c62cc20667427595c8e94784a7fbf901115a4 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 28 May 2026 03:14:49 +0200 Subject: [PATCH] fix(words): silence canvas, silver rail, direct undo/redo, popover widths, Enter empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six user-reported issues in one pass. EV-F1 — canvas silence Remove the contact-focus entry from the sema cascade. The event still fires (telemetry / a11y can read the data-event* stamps) but no sound / haptic plays. Per spec: "no puede emitir eventos es demencial, una vez que está trabajando con el no tiene sentido". The editor surface is now perceptually silent on focus; only explicit commits (save, format, set-link, etc.) make noise. EV-F2 — rail visual `--_words-rail-bg` becomes flat silver `#d4d4d4` and the dot pattern is gone. New `--_words-rail-border` (`#9a9a9a`) lays a 1px hairline on the rail's inline-end so it reads as a separate gutter ("paper edge" feel). Fixed-tone (not theme-aware) — the rail is meant to look like the physical margin of a notebook regardless of the editor theme. Left-side drawer flips the border to inline- start. EV-F3 — direct undo/redo in toolbar Demo presets + custom config now use `['undo', 'redo', ...]` as direct command strings instead of `['history-menu', ...]` (which opened a popover to pick from two items — wasted real estate + two clicks). `link-menu` and `tools-menu` stay as popovers because they hold 2-3 items each. `insert-menu` is OUT — block construction lives in the drawer's empty-state Insert panel and the slash menu. `demoToolbarFamilyItems.insert` collapsed to `[]` accordingly. EV-F4 — popover widths Base `[data-words-toolbar-family-panel]` width 12.5rem → 16rem so content fits without horizontal scroll. Per-family overrides: tools → 17rem (descriptive labels), link → 20rem (URL input + button grid). The default panel CSS no longer carries a max-block- size + scroll — a vertical scroll inside these popovers is a misdesign signal; size the panel, don't scroll it. EV-F5 — link popover (covered by EV-F4) The vertical scroll the user saw was a side-effect of the 12.5rem width forcing the link-editor input + button to wrap, then the panel running out of vertical room. The new 20rem width restores the natural one-row layout and no scroll appears. EV-F6 — Enter on empty block no longer multiplies `insertParagraph` engine op now guards the default case (paragraph/heading): if the block is collapsed AND empty (children length 0, both halves of split empty), Enter on a paragraph is a no-op and Enter on a heading demotes it to a paragraph (canonical Notion / Google Docs UX). For non-empty paragraphs/headings the existing split-and-create-paragraph behavior stands. Verification: 467/467 tests pass across morfo + sema + eidos + soma/components/words. 85/85 engine tests pass (insertParagraph guard non-regressive on existing fixtures). `npm run check` still 0 errors. DOM probe at /uix/components/words confirms toolbar = 5 items (undo, redo, Links, Tools, Find/replace), rail bg `rgb(212,212,212)` + 1px `rgb(154,154,154)` right border, link popover 320px wide with no scroll. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/uix/eidos/components/words/words.css | 56 ++++++++++++++----- src/uix/sema/components/words.ts | 19 ++----- .../components/words/engine/operations.ts | 34 +++++++++++ web/routes/uix/components/words/+page.svelte | 26 ++++----- 4 files changed, 95 insertions(+), 40 deletions(-) diff --git a/src/uix/eidos/components/words/words.css b/src/uix/eidos/components/words/words.css index 52d4a6f15..1f5cf5a7a 100644 --- a/src/uix/eidos/components/words/words.css +++ b/src/uix/eidos/components/words/words.css @@ -12,8 +12,14 @@ land inside this column. */ --_words-rail-px: 2rem; --_words-rail-gap: 0.5rem; - --_words-rail-bg: color-mix(in srgb, var(--words-toolbar-border) 35%, transparent); - --_words-rail-dot: color-mix(in srgb, var(--words-status-color) 65%, transparent); + /* Flat light silver band with a slightly darker edge toward the + * editor card. Per spec: "elimna el fondo de la barra de la + * izquierda y dejalo de un color silver claro con un borde a la + * derecha un poco mas oscuro". Fixed-tone (not theme-aware) so + * the gutter reads as a physical "paper edge" regardless of the + * editor theme — same intent as the printed margin in a notebook. */ + --_words-rail-bg: #d4d4d4; + --_words-rail-border: #9a9a9a; --_words-toolbar-px: var(--words-toolbar-px-md); --_words-toolbar-py: var(--words-toolbar-py-md); --_words-button-size: var(--words-button-size-md); @@ -177,24 +183,28 @@ } /* Rail visual — pseudo-element on the editor host that fills the - `rail` grid area with the dotted grey band. The grip + "+" overlays - are JS-positioned via viewport coordinates that land here. */ + `rail` grid area with a flat silver band. The edge closest to the + editor card carries a slightly darker hairline so the rail reads as + a separate gutter. Grip + "+" overlays are JS-positioned via + viewport coordinates that land here. */ [data-words]:has([data-words-drawer])::before { content: ''; grid-area: rail; background-color: var(--_words-rail-bg); - background-image: radial-gradient( - circle 1px, - var(--_words-rail-dot) 99%, - transparent 100% - ); - background-size: 5px 5px; - background-position: 50% 50%; - background-repeat: repeat; - border-radius: var(--_words-radius); + border-inline-end: var(--words-border-width) solid var(--_words-rail-border); + border-radius: var(--_words-radius) 0 0 var(--_words-radius); pointer-events: none; } +/* Left-side drawer flips the layout (drawer | content | gap | rail), + so the rail's "darker edge" is on the inline-START (the side facing + the editor card on its right). */ +[data-words]:has([data-words-drawer][data-side='left'])::before { + border-inline-end: 0; + border-inline-start: var(--words-border-width) solid var(--_words-rail-border); + border-radius: 0 var(--_words-radius) var(--_words-radius) 0; +} + [data-words]:has([data-words-drawer]) > [data-words-toolbar] { grid-area: toolbar; } @@ -1566,8 +1576,12 @@ [data-words-toolbar-family-panel] { display: grid; gap: var(--button-gap-xs); - inline-size: min(12.5rem, calc(100vw - var(--space-4))); + inline-size: min(16rem, calc(100vw - var(--space-4))); max-inline-size: calc(100vw - var(--space-4)); + /* No max-block-size + overflow on the panel itself — items should + * size the popover, not the other way around. A scroll inside the + * panel is a misdesign signal: bump the family-specific width + * below instead. */ } [data-words-toolbar-family-panel][data-family='table'] { @@ -1575,6 +1589,20 @@ gap: var(--button-gap-xs); } +/* Tools family (clear-formatting / clear-document / commit) — three + * descriptive labels need breathing room so they don't wrap. */ +[data-words-toolbar-family-panel][data-family='tools'] { + inline-size: min(17rem, calc(100vw - var(--space-4))); +} + +/* Link family hosts the link-editor (URL input + button) which is + * naturally wider than the default. The link-editor's own grid + * (input | button) needs ~18rem to avoid the input getting squeezed + * to a single-character width. */ +[data-words-toolbar-family-panel][data-family='link'] { + inline-size: min(20rem, calc(100vw - var(--space-4))); +} + [data-words-toolbar-family-panel] [data-toolbar-button], [data-words-toolbar-family-panel] [data-words-command-button], [data-words-toolbar-family-panel] [data-words-code-language-picker], diff --git a/src/uix/sema/components/words.ts b/src/uix/sema/components/words.ts index 7cbf2582f..9fa3c94b5 100644 --- a/src/uix/sema/components/words.ts +++ b/src/uix/sema/components/words.ts @@ -24,19 +24,12 @@ const onFindReplace = (matchers?: Parameters = { - minimal: [['history-menu']], - formatting: [['history-menu', 'insert-menu', 'link-menu']], - full: [['history-menu', 'insert-menu', 'link-menu', 'tools-menu'], ['find-replace']] + minimal: [['undo', 'redo']], + formatting: [['undo', 'redo', 'link-menu']], + full: [['undo', 'redo', 'link-menu', 'tools-menu'], ['find-replace']] }; const toolbarCustomGroups: WordsToolbarGroupConfig[] = [ - ['history-menu', 'insert-menu', 'link-menu', 'tools-menu'], + ['undo', 'redo', 'link-menu', 'tools-menu'], ['find-replace'] ]; const demoToolbarFamilyItems: Record< @@ -129,7 +129,7 @@ ], list: ['unordered-list', 'ordered-list', 'check-list', 'increase-indent', 'decrease-indent'], align: ['align-left', 'align-center', 'align-right', 'align-justify'], - insert: ['insert-table'], + insert: [], table: [ 'insert-table', 'insert-table-row',