…33) (#37)
* feat(composer): hand-rolled contenteditable editor engine; TipTap becomes Composer.TextareaLegacy
* feat(composer): editable-routed event callbacks with consumer-first override semantics
* fix(composer): hide placeholder during IME composition; add native placeholder prop
* refactor(composer): single-writer hasContent; placeholder gates on engine isComposing
* feat(composer): submitOn prop for Enter/Shift+Enter mapping; soft break dismisses active trigger token
* fix(composer): repaint on br-count drift — collapse on emptied editor + phantom newlines
* fix(composer): whitespace-only docs count as content — placeholder no longer overlays line breaks
* feat(composer): ghost-text completion of the highlighted command item (#35)
* feat(composer): ghost-text completion of the highlighted command item
* style(composer): borderless chip + badge surface in the input
* feat(composer): per-prefix suggestion flag gating ghost-text completion
* feat(composer): per-prefix command placeholder, exclusive with suggestion
* refactor(composer): badge hints as a real command-hint slot element, replacing ::after attribute CSS
Notion-style inline completion, stacked on #33: while the command popup is open, the highlighted item's remaining label renders as ghost text after the query —
@Teshowsst Documentfaded; Tab/Enter accepts as before.Zero new API, zero engine changes:
suggestionRemainder(query, label)— pure helper infuzzy.ts: completes only case-insensitive prefix matches (inline-completing a fuzzy hit would read as broken); empty query → full label; exact match → nothing.ComposerCommandstampsdata-command-suggestiononto the badge span via a layout effect (same badge-query pattern as the popover anchor). Re-stamping survives badge rewraps because those always coincide with a query/highlight re-render.::after { content: attr(data-command-suggestion) }in the styled layer — no real DOM, so the caret, reader, selection, and IME are untouched by construction. A double-attribute rule outranks the "Type to filter" hint when both apply.TextareaLegacythe ghost degrades gracefully (PM recreates decoration spans on selection-only transactions without a React re-render) — not a target; the legacy editor is a frozen baseline.Manual checks
@with items → highlighted item's label ghosts after the caret (replaces "Type to filter")@Te) → ghost shows the remainder; a fuzzy-only match shows no ghost