Skip to content

fix(editor): four things that were quietly not working - #16

Merged
christianhuening merged 1 commit into
chore/pre-tiptap3-groundworkfrom
fix/editor-pre-existing-bugs
Sep 5, 2026
Merged

fix(editor): four things that were quietly not working#16
christianhuening merged 1 commit into
chore/pre-tiptap3-groundworkfrom
fix/editor-pre-existing-bugs

Conversation

@christianhuening

Copy link
Copy Markdown
Contributor

Stacked on #15 — the parity and extension-set checks added there are what surfaced most of these. Retarget to main once #15 merges.

All four predate that work. Each was reproduced first, then fixed, then verified by reverting the fix and watching the new test go red.

List keyboard shortcuts threw

toggleBulletList() raised There is no node type named 'listItem', so Mod+Shift+8 and Mod+Shift+7 did nothing but log. Renaming a node doesn't rewrite the options its own commands read — options.itemTypeName was still "listItem".

The toolbar buttons pass both names explicitly, which is why only the shortcuts were affected and nobody noticed.

Link titles were dropped

tools/schema.json declares title on the link mark and both from_markdown and to_markdown honour it — but Tiptap's Link has no such attribute, and ProseMirror discards what its schema doesn't declare. [text](url "title") survived import and was rewritten without the title the first time anyone edited the document. In storage, for every reader, silently.

UNIMPLEMENTED_ATTRS in schema.test.ts is now empty and should stay that way.

Peer colours were an unsupported format

y-prosemirror accepts only #rrggbb for a caret; colorFor() emitted hsl(), so every collaborative session logs A user uses an unsupported color format once per peer. v2 still renders the caret, so this is noise rather than breakage today — but the successor extension replaces a non-matching colour with transparent, which would make every remote caret invisible. Fixing it now also closes migration blocker B4.

Same palette, converted rather than re-picked — hsl(0,70%,45%)#c32222. No avatar changes colour.

Three CSS selectors matched nothing

A React node view's outer element is Tiptap's own div.react-renderer; the NodeViewWrapper carrying our attributes renders inside it. So .ProseMirror > pre and .ProseMirror > [data-testid=…] never selected anything.

The failure was invisible because .ProseMirror > * still applied — code blocks, Mermaid diagrams and Excalidraw boards were held at the 712px prose measure in wide mode instead of taking their own width. My own regression from the width feature in 0.4.0.

Retargeted at the node-<type> class Tiptap stamps on the wrapper, confirmed against a DOM dump from Chromium rather than inference. Covered in doc-width.spec.ts by measuring rendered widths; that test fails against the old selectors.

A .collaboration-cursor__selection rule was dead too — y-prosemirror emits .ProseMirror-yjs-selection with the colour set inline, so it neither matched nor could have overridden anything. Removed.

Deliberately not fixed

to_markdown.rs's _ => {} arm silently discards an unknown mark. tracing isn't a dependency of knot-markdown, and the extension-set and parity checks now prevent an unknown mark being written at all — a stronger guarantee than a log line.


tsc, eslint --max-warnings 0, 151 unit tests, and 18 e2e specs across doc-width, mermaid, excalidraw, editor-toolbar, two-users-converge, import-markdown, import-export and collab.

🤖 Generated with Claude Code

Found while building the Tiptap 3 baseline coverage. All four predate that
work; each was reproduced before being fixed, and each fix was verified by
reverting it and watching the new test go red.

List keyboard shortcuts threw. Renaming a node does not rewrite the options
its own commands read: BulletList and OrderedList resolve
`options.itemTypeName`, still the camelCase "listItem", so
`toggleBulletList()` raised "There is no node type named 'listItem'" and
Mod-Shift-8 / Mod-Shift-7 did nothing but log. The toolbar buttons pass both
names explicitly, which is why only the shortcuts were affected. ListItem
declares bulletListTypeName/orderedListTypeName too, but nothing in v2 reads
them -- its keymaps pass `this.name` -- so they are deliberately left alone
rather than configured to no effect.

Link titles were dropped. tools/schema.json declares `title` on the link
mark and both from_markdown and to_markdown honour it, but Tiptap's Link has
no such attribute and ProseMirror discards what its schema does not declare.
So `[text](url "title")` survived import and was rewritten without the title
the first time anyone edited the document -- in storage, for every reader.
The parity check added in the previous commit now catches this class outright,
so UNIMPLEMENTED_ATTRS is empty and should stay that way.

Peer colours were an unsupported format. y-prosemirror accepts only
`#rrggbb` for a caret; colorFor() emitted `hsl()`, so every collaborative
session logged "A user uses an unsupported color format" once per peer. v2
still renders the caret, so this was noise rather than breakage -- but the
successor extension replaces a non-matching colour with `transparent`, which
would have made every remote caret invisible. Same palette, converted rather
than re-picked: no avatar changes colour.

Three CSS selectors matched nothing. A React node view's outer element is
Tiptap's own `div.react-renderer`, and the NodeViewWrapper carrying our
attributes renders inside it -- so `.ProseMirror > pre` and
`.ProseMirror > [data-testid=…]` never selected anything. The failure was
invisible because `.ProseMirror > *` still applied: code blocks, Mermaid
diagrams and Excalidraw boards were held at the 712px prose measure in wide
mode instead of taking their own width. Retargeted at the `node-<type>` class
Tiptap stamps on the wrapper. Regression covered in doc-width.spec.ts by
measuring rendered widths, which fails against the old selectors.

Also dead: a `.collaboration-cursor__selection` rule. y-prosemirror emits
`.ProseMirror-yjs-selection` with the peer's colour set inline, so the rule
neither matched nor could have overridden anything. Removed.

Not fixed here, deliberately: to_markdown's `_ => {}` arm silently discards
an unknown mark. tracing is not a dependency of knot-markdown, and the
extension-set and parity checks now prevent an unknown mark being written at
all, which is a stronger guarantee than a log line.

18 e2e specs across doc-width, mermaid, excalidraw, editor-toolbar,
two-users-converge, import-markdown, import-export and collab pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@christianhuening
christianhuening merged commit 19c90d6 into chore/pre-tiptap3-groundwork Sep 5, 2026
5 checks passed
@christianhuening
christianhuening deleted the fix/editor-pre-existing-bugs branch September 5, 2026 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant