Repository navigation
feat: @ mention picker in the rich text editor - #237
Merged
Merged
Conversation
Adds an opt-in `mentions` prop: typing `@` (or the toolbar's Mention button) in the rich text WYSIWYG opens a picker backed by the host's `searchUsers`, and picking someone inserts a rich text `user` element. `getUserName` labels mentions in the editor by id. User mentions now round-trip through the WYSIWYG (with bold, italic, strike and underline) instead of forcing the structured editor. The picker's Escape is kept from reaching the inline editor, which would otherwise discard the whole edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51
Contributor
Cloudflare preview✅ Deployed |
Contributor
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
block-kitchen | c8eb5e1 | Commit Preview URL Branch Preview URL |
Oct 12 2026, 02:42 PM |
slack-blocks-to-jsx copies `hooks` into state when `<Message>` mounts and never reads the prop again, so a host that resolves a mention's name after the first paint kept showing the raw `@U…` id. Hand the renderer one stable object that reads through to the latest hooks instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51
Contributor
Author
|
Audit (pnpm) fails here, but this PR didn't cause it. The same job has been red on
No fix exists in an open PR yet. Proposed patch for "overrides": {
"esbuild": ">=0.28.1",
"undici": "^7.29.0",
"prosemirror-view": "^1.42.3"
},
"auditConfig": {
"ignoreGhsas": ["GHSA-vfj7-8cjw-p6xm"]
}Generated by Claude Code |
4 tasks done
Generalize the mention-in-code-block check to every non-text inline and styled text run, matching #238, so the two changes merge cleanly in either order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51
The rich text editor re-seeds from `block` when the emoji resolver changes. That effect can run with a `block` that predates the user's latest edit (the host hasn't re-rendered with it yet), and re-seeding then reverted the edit: an early keystroke, or an `@` pick. Re-seed on a resolver change only while the user hasn't edited. The `@` trigger is now gated by the suggestion's `allow` instead of rebuilding the editor when the host turns mentions on or off, so toggling keeps the editor's content, caret and history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51
Clears GHSA-c8x8-7fp4-3x9w (high; prosemirror-view paste XSS) by pinning prosemirror-view ^1.42.3, and pins prosemirror-model ^1.25.12 with it so the bundle keeps a single ProseMirror model. Ignores GHSA-vfj7-8cjw-p6xm (braces), which has no patched release and only reaches the build toolchain through @tailwindcss/cli. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51
5 tasks done
…nto claude/rich-text-mention-picker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opt-in
mentionsprop. In the rich text WYSIWYG, typing@(or the new Mention toolbar button) opens a picker backed by the host'ssearchUsers, and picking someone inserts a rich textuserelement ({ type: "user", user_id }). An optionalgetUserName(userId)labels mentions in the editor, including ones that arrived with the draft or a loaded message.@tiptap/suggestion(same 3.30.x as the other TipTap packages, so ProseMirror stays deduped).signal, and ignores the@insidename@domain.allow, so a host turningmentionson or off keeps the same editor, with its content, caret and history.userMentionnode imports and exportsuserelements, carrying bold, italic, strike and underline as marks (codeis dropped, since Slack rejects it on auserelement). Mentions withhighlight,client_highlightorunlinkstill fall back to the structured editor. A mention inside a code block falls back too, through the general code-block check fix(editors): keep links and emoji in rich text code blocks #238 added; this branch carries the identical hunk and hasmainmerged in.fix(preview)):slack-blocks-to-jsxcopieshooksinto state when<Message>mounts and never reads the prop again. So a host that resolves a mention's name after the first paint kept showing the raw@U…id. This affected mentions already in a draft too, not only picked ones.SlackBlockPreviewnow hands the renderer one stable object that reads through to the latestpreviewHooks, without remounting.fix(editors)): the editor re-seeds fromblockwhen the emoji dataset finishes loading. That effect could run with ablockolder than the user's latest edit (the host hadn't re-rendered with it yet) and revert the edit. That lost an early keystroke, or undid an@pick and reopened the picker. It now re-seeds on a resolver change only while the user hasn't edited.mentionsget no picker. Existing mentions still round-trip and show as@U….Why
Tightknit's Message Blaster composer (ENG-6346) needs admins to
@mentionmembers while composing. Today the only way is hand-typing a raw Slack id in Advanced mode. The search stays host-brokered, like every other I/O concern in the package.Test plan
pnpm typecheckpnpm lintpnpm test: all 671 tests pass (unit, plus the Storybook browser project with the newWithMentionsstory), run against a pre-provisioned Chromium (BK_CHROMIUM_EXECUTABLE).pnpm storybook(BlockKitchen › With Mentions) with Playwright-driven Chromium:@grand clicking a row inserts@Grace Hopper.New tests:
test/rich-text-tiptap-mentions.test.ts: lossy detection (styles, code block), round-trip with styles, and export droppingnameandcode.test/rich-text-mention-picker.test.tsx:onKeyDown; this test fails without the fix.@,getUserNamelabels, and the no-config path.mentionson after mount keeps the same editor.BlockKitchenpasses the prop down to the editor.test/slack-block-preview-hooks.test.tsx: a preview re-rendered with new hooks uses them, and dropping them falls back to the default. Both fail without the fix.test/rich-text-editor-emoji-load.test.tsx: an edit made before the host re-renders survives the emoji dataset landing (this fails without the fix), and an untouched editor still picks up emoji glyphs.Notes for reviewer
MentionsProviderwraps only<Surface>, since every rich text editor renders inside its block rows. That keeps the diff from re-indenting the whole shell.main. This branch has fix(deps): pin prosemirror-view 1.42.3+ and unblock the pnpm audit #240's commit merged in to fix it. The repo merges PRs with merge commits, so that commit is the same one fix(deps): pin prosemirror-view 1.42.3+ and unblock the pnpm audit #240 lands and won't duplicate or conflict, whichever PR merges first. Thepackage.json/pnpm-lock.yamlchanges in this diff are that commit's, plus@tiptap/suggestion.🤖 Generated with Claude Code
https://claude.ai/code/session_01MTy6g5wxP9DqjWJQshGz51