feat(editor): add built-in SlashCommand extension#3050
Conversation
Extensible slash command with 14 built-in email commands, 7-tier search scoring, keyboard navigation, and Tippy.js dropdown UI. Exports createSlashCommand() factory for custom command sets + a pre-configured SlashCommand for quick setup.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
3 issues found across 14 files
Confidence score: 3/5
- There is some user-facing risk around slash command navigation:
updateScrollViewinpackages/editor/src/ui/slash-command/utils.tscan mis-scroll when the offset parent isn’t the scroll container. - Search matching can fail with leading/trailing spaces because
packages/editor/src/ui/slash-command/search.tsscores the untrimmed query. - Keyboard navigation can break when there are no items because modulo by zero yields
NaNinpackages/editor/src/ui/slash-command/command-list.tsx, so this isn’t fully safe to merge without tweaks. - Pay close attention to
packages/editor/src/ui/slash-command/utils.ts,packages/editor/src/ui/slash-command/search.ts,packages/editor/src/ui/slash-command/command-list.tsx- scroll behavior, query trimming, and empty-state navigation handling.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/editor/src/ui/slash-command/search.ts">
<violation number="1" location="packages/editor/src/ui/slash-command/search.ts:34">
P2: Use the trimmed query for scoring; otherwise leading/trailing spaces can make valid commands fail to match.</violation>
</file>
<file name="packages/editor/src/ui/slash-command/command-list.tsx">
<violation number="1" location="packages/editor/src/ui/slash-command/command-list.tsx:110">
P2: Guard keyboard navigation when there are no items; modulo by zero sets `selectedIndex` to `NaN`.</violation>
</file>
<file name="packages/editor/src/ui/slash-command/utils.ts">
<violation number="1" location="packages/editor/src/ui/slash-command/utils.ts:21">
P2: `updateScrollView` uses `item.offsetTop` with `container.scrollTop`, which can mis-scroll when the item’s `offsetParent` is not the scroll container. Use viewport-relative rects (or normalize to container coordinates) before adjusting scroll.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
Adds a `component` option to `createSlashCommand()` so consumers can provide their own dropdown UI while reusing the extension plumbing (suggestion plugin, Tippy positioning, keyboard delegation). Exports CommandList, CommandListProps, CommandListRef, and CommandListComponent for consumers to build on or replace.
…only Aligns with existing bubble menu CSS pattern: layout and positioning only, no colors/shadows/borders. Consumers own the visual layer.
offsetTop is relative to offsetParent which may not be the scroll container in custom component layouts. Viewport-relative rects work regardless of DOM nesting.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
commit: |
| onClick={onSelect} | ||
| type="button" | ||
| > | ||
| <Icon size={20} /> |
There was a problem hiding this comment.
should this be coming in as a React.ReactNode? Maybe children?
| } from 'lucide-react'; | ||
| import type { SlashCommandItem } from './types'; | ||
|
|
||
| export const TEXT: SlashCommandItem = { |
There was a problem hiding this comment.
doesn't have to be now, but I wonder if there's a way to have extensions plug into the slash command and show up as an option at the end
|
|
||
| if (!props.clientRect) return; | ||
|
|
||
| popup = tippy('body', { |
There was a problem hiding this comment.
doesn't have to be now either, but could this popover be defined through React components in the React tree and then still be handles by the extension somehow?
maybe the component adds in the extension to the editor when mounting (I think this is possible)
|
@gabrielmfern I've moved all of your comments to the Linear board and we'll tackle those from there as follow-up PRs! Thanks for the awesome review |
Summary
@react-email/editorcreateSlashCommand()factory for custom command sets — designed so the dashboard can consume this and add its own commands (image upload, YouTube, variables, etc.)re-slash-command-prefix) and dark mode supportTest plan
/keypress in an editor instanceSummary by cubic
Adds a built-in, extensible SlashCommand to
@react-email/editorfor fast block insertion via a searchable, keyboard-first menu. Fixes scroll positioning for reliable keyboard navigation in custom dropdowns and bumps@react-email/editorto0.0.0-experimental.15, meeting PRODUCT‑1567.New Features
createSlashCommand()factory + ready‑to‑useSlashCommand; default filter hides column layouts at max column depth.createSlashCommand({ component }); exportsCommandList,CommandListProps,CommandListRef,CommandListComponent.tippy.js; layout‑only styles at@react-email/editor/styles/slash-command.cssusingdata-re-attributes; command titles in sentence case; uses React 19refprop; trims queries; guards empty lists.slash-command.css.Dependencies
@tiptap/suggestion.tippy.js.Written for commit c61aaca. Summary will update on new commits.