fix(editor): run the slash command that was clicked
Closes #3746.
Problem
With no query typed, the slash command menu can run a different item's command than the one clicked or highlighted. Using the docs' own custom commands example (an Image item with category: 'Media' appended to defaultSlashCommands), the menu shows Text → Media → Layout, but clicking Image inserts a Button, and arrow keys highlight one row while Enter runs another.
Root cause
The two sides numbered the rows differently.
ui/slash-command/command-list.tsxreorders the items for display:groupByCategorypulls the categories inCATEGORY_ORDERto the front, everything else follows in first-seen order. Each row then calledonSelect(flatIndex)— its position in the grouped display order — and highlighted itself with the same number.ui/slash-command/root.tsxresolves bothonSelectand the Enter handler againstsuggestionItemsRef.current[index], i.e. the original, unordered array, and the arrow keys walk that same array.
As long as the array happens to be in CATEGORY_ORDER the two orders agree, which is why the built-in commands don't show it. Any other order — a custom category, a translated one, or a command appended at the end — shifts every row after the first group. With a query typed the list is rendered flat, so it works.
Change
command-list.tsx:groupByCategorynow carries each item's index in the list the root holds, and the rows use that index for bothonSelectanddata-selected, instead of counting display positions. NoflatIndexcounter.command-list.tsx: exportsorderItemsByCategory, the same grouping flattened back into a list.root.tsx:defaultFilterItemsreturns the items in that display order when there is no query, so the arrow keys move down the list the way it is drawn instead of jumping between groups. With a query the list stays flat and ranked by score.
What I deliberately left alone
CATEGORY_ORDERitself, and the choice to group only when there is no query.- A custom
filterItemsstill controls its own order — the index bookkeeping keeps clicks correct whatever order it returns, including categories interleaved in the array. search.tsranking is untouched.
Test
packages/editor/src/ui/slash-command/command-list.spec.tsx renders the menu with [Text (Text), Divider (Layout), Image (Media)] — display order Text → Media → Layout, array order Text → Layout → Media — and covers the click index, the highlighted row and orderItemsByCategory.
$ cd packages/editor && pnpm vitest run --project unit
Test Files 53 passed (53)
Tests 516 passed (516)
$ pnpm typecheck # clean
$ pnpm biome check packages/editor/src/ui/slash-command # clean
Before the fix, the new tests fail exactly the way the issue describes:
× selects the clicked item and not the one in its display position
AssertionError: expected "vi.fn()" to be called with arguments: [ 2 ]
Received: 1 // clicking Image selected Divider
× highlights the item the index points at
AssertionError: expected 'Divider' to contain 'Image'
🤖 Generated with Claude Code
https://claude.ai/code/session_011Yyp6p2GWzkWKLsrxxJR1U
Summary by cubic
Fixes the slash command menu running a different command than clicked and arrow keys landing on the wrong row when categories display out of array order — for example, a custom Image command appended after the defaults could insert a Button.
- Rows resolve clicks and highlighting against the original item index, not their display position.
- Sorts items into displayed category order in the root after filtering, only when the built-in list renders with no query, so arrow keys follow the drawn rows even with a custom
filterItems. - Keeps custom
childrenrenderers receiving items in array order. - Exports
orderItemsByCategoryand adds unit tests for click, highlight, arrow-key, and renderer ordering.