5.1.4 Mention capability in `MarkdownEditor` + mention-chip rendering in `MarkdownView` (tiptap Mention + `mention:` token round-trip)
Estimate: 30m · Depends on: 5.1.3, 5.1.2
The editor-level mention capability — built into the SHARED MarkdownEditor primitive (2.3.5) so comments (5.1.5) AND the existing description fields (create modal, edit form) gain mentions in one place — the Jira-faithful scope (mentions work in description too). Design-gated UI: carries 5.1.3 in dependsOn (the popup + chip are designed there) and 5.1.2 (the token format + candidate scoping are the service's contract).
Editor side. Add @tiptap/extension-mention (suggestion plugin) to MarkdownEditor: typing @ opens the caret-anchored member listbox from the 5.1.3 design (Combobox option-row vocabulary — Avatar · name · email; filter-as-you-type; ↑/↓/Enter/Esc; aria-activedescendant — the a11y bar the shipped Combobox sets). Candidates come from a mentionCandidates prop the host surface supplies (the detail/comment surfaces pass the issue-scoped viewable members from 5.1.2's candidate read; the primitive itself stays data-source-agnostic and mention support is OFF when the prop is absent — existing consumers are untouched until wired). The mention node serializes to the durable Markdown token [@Display Name](mention:<userId>) via the tiptap-markdown serializer, and parses back on load (round-trip stable — editing a body with mentions preserves them).
Render side. MarkdownView / lib/markdown/render.tsx: allow the mention: protocol through rehype-sanitize (extend the schema's allowed protocols — the default strips unknown schemes) and map mention links to a user chip (the 5.1.3 treatment: accent tint bg + --el-text-strong, finding #35 AA) instead of a navigable anchor. Unknown/stale user ids degrade to plain text of the display name — never a broken link.
Acceptance criteria
MarkdownEditoraccepts an optionalmentionCandidatessource; with it,@opens the designed picker (keyboard-complete, axe-clean) and inserts a mention that serializes to[@Name](mention:<userId>)and round-trips through load→edit→getMarkdown()unchanged; without it, behaviour is byte-identical to today (existing tests untouched).MarkdownViewrenders mention tokens as the designed chip (no navigation), sanitize still strips every other non-allowlisted protocol (no XSS regression — testjavascript:stays dead), and a stale id degrades to plain text.- No raw
--color-*/Tier-0 utilities; chip + popup colour through--el-*, shape through element tokens (adding tokens per the growth pattern if 5.1.3's notes call for them). - Component tests: serialization round-trip, the sanitize allowlist, the picker's keyboard path;
pnpm test:coverageholds the gate.
Context refs
design/work-items/comments.mock.html+ design-notes (5.1.3) — the popup + chip designcomponents/ui/MarkdownEditor.tsx(2.3.5 — tiptap v3 + tiptap-markdown,html: false),lib/markdown/render.tsx+rehype-sanitizeschemalib/mentions/parse.ts+ the candidate read (5.1.2) — the token format + scoping contract the editor must matchcomponents/ui/Combobox.tsx— the option-row +aria-activedescendantvocabulary the popup mirrors