The living catalog

Elements08/15

Ink

G8

The editing feel: there is no edit mode. One ProseMirror-backed primitive for every text seat — line/text/prose — with continuous save, real undo, Esc burst-revert, and [[ mentions.

Posture

line — Enter commits and blurs; empty reverts

prose — markdown shortcuts, ⌘B/⌘I, [[ mentions; right-click for the menu

The words are simply kept — no spinner, no saved-toast. The border above belongs to the panel, not the seat: reading and writing are the same visual state.

npx candlelight-ds add ink

Use when

Any text the user owns — titles, names, descriptions, documents.

Don't use when

Genuine configuration (URLs, keys — forms stay forms) or search fields (queries, not documents). Create-inputs and renames under navigating links (InlineEdit).

States
reading (identical to writing)writing (caret only)empty (placeholder)read-only (same face)mention popup open
Keyboard
  • Enter (line)commits and blurs — Enter stays sacred to the commit key
  • Escreverts the current burst since the last save
  • ⌘Zreal undo, alive across saves
  • ⌘B/⌘I (prose)bold/italic; markdown shortcuts free
  • [[ (prose)opens the mention popup; ↑↓ walk, Enter picks, Esc closes
Traps
  • Suggestion-popup key priority: popup keys MUST be handled in editorProps.handleKeyDown — a React wrapper's onKeyDown runs after ProseMirror's keymaps, so Enter splits the paragraph instead of picking.
Acceptance
  • The squint test: a screenshot of editing vs reading is identical but the caret.
  • The keystroke test: typing is indistinguishable from a bare textarea (zero React renders per keystroke).
  • The crash test: kill the tab mid-word, lose at most one debounce window of words.
  • The undo test: ⌘Z works across saves because the editor never unmounts.
  • The menu test: no seat without a right-click menu.
  • The one-feel test: a stranger can't tell any two seats were different components.

Raw twin: /components/ink.md·Registry item: /r/ink.json