Repository navigation
fix(react): fast typing no longer breaks suggestion menus - #3249
nperez0111 merged 2 commits into
Conversation
…t move SuggestionMenuController and GridSuggestionMenuController built the popover reference with an inline selector, so it was a new object on every store update. GenericPopover then set its position reference again on each keystroke. With fast typing, React counted these queued updates as nested updates and threw error 185 after about 50 keys. The reference now changes only with the editor element and the values of referencePos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@safaweslati is attempting to deploy a commit to the TypeCell Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Equality function API packages/react/src/hooks/useStore.ts, packages/react/src/hooks/useExtension.ts |
useStore accepts an optional equality function, defaulting to shallow, and passes it to the selector hook. useExtensionState accepts and forwards the function with its selector. |
Suggestion-menu reference comparison packages/react/src/components/SuggestionMenu/SuggestionMenuController.tsx, packages/react/src/components/SuggestionMenu/GridSuggestionMenu/GridSuggestionMenuController.tsx, packages/react/src/components/SuggestionMenu/SuggestionMenuController.reference.test.tsx |
Both controllers compare menu references using the anchor element and its bounding-rectangle coordinates and dimensions. Tests check that list and grid menu references retain the same identity across typing transactions. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Suggested reviewers: nperez0111, matthewlipski, yousefed
Merge Risk: 
Minimal · up to 04e77
-
The change preserves existing defaults and stabilizes suggestion-menu references without an established merge-blocking regression.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description includes all required sections, explains the problem and rationale, lists the implementation changes, documents impact and testing, and records the unavailable type-aware lint step. The documentation checklist item remains unchecked, but this is non-critical for the fix.
Full details: Title check
-
Explanation
The title "fix(react): fast typing no longer breaks suggestion menus" matches the main change. The PR keeps the suggestion menu popover reference stable while the anchor does not move, which prevents repeated reference updates during fast typing (linked to React error 185). The title names the user-visible symptom and the affected area (react suggestion menus). It uses the conventional commit prefix and stays under 60 characters. It does not name the mechanism (reference memoization via equalityFn), but that detail is not required for a title.
-
Finishing Touches: 💡 1
-
🛠️ Fix failing CI checks: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
A rabbit checks the menu's place
While queries hop at a steady pace
The anchor stays, the bounds align
Each reference holds its line
Then carrots mark the test as fine
Comment @coderabbitai help to get the list of available commands.
9354821 to
04e779c
Compare
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/diagram-block
@blocknote/mantine
@blocknote/math-block
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
@blocknote/xl-typst-exporter
commit: |
|
Thanks @safaweslati for the fix |
Summary
Fast typing while a suggestion menu trigger is active can crash a React app with error 185 ("Maximum update depth exceeded"). This PR keeps the
referencethatSuggestionMenuControllerandGridSuggestionMenuControllergive toGenericPopoverstable while the menu does not move.Rationale
Both controllers build
referencewith an inlineuseExtensionStateselector. The selector returns a new object on every store update. Also,SuggestionMenuViewwritesreferencePoswithgetBoundingClientRect().toJSON(), which is a new object on every update, also when the menu stays at the same place.GenericPopoverhas an effect onprops.referencethat callsrefs.setPositionReference(...). That is a state update in Floating UI. So each keystroke adds one more update that runs after the commit.When keys arrive back to back, the browser handles the input before React gets to that update. Each sync commit then finishes with the update still waiting, and React counts it as a nested update. After about 50 keys, React throws error 185. It is not an infinite loop. It is a counter that the queued updates fill.
We see this in production. A user types
/(or another trigger character) and then a sentence, quickly, on a slow machine. We reproduce it with Playwright and with Chrome DevTools CPU throttling at human speeds: 4x slower CPU at 100 ms per key, and 6x slower CPU at 150 ms per key.Changes
SuggestionMenuControllerandGridSuggestionMenuControllerbuildreferencewithuseMemo. The memo uses the editor element and thex,y,widthandheightvalues ofreferencePos, not the object identity.getBoundingClientRectbuilds aDOMRectfrom those values, so it never returns a stale rectangle.SuggestionMenuController.reference.test.tsx, opens each menu, types a query and checks thatGenericPopovergets one reference for the whole query.Impact
When the anchor moves (the query wraps to a new line, or the editor scrolls), the values change, so the popover gets a new reference and moves as before. When the anchor does not move, the popover no longer sets its position reference again on each keystroke.
Testing
main(5 references for 5 keys, in both controllers) and passes with the change (1 reference).pnpm testinpackages/reactpasses.tsc --noEmitinpackages/reactpasses. Lint and the formatter pass on the changed files. On Windows I could not run the type-aware lint step (tsgolintdoes not start), so CI is the first run of that step.pnpm patchto@blocknote/react@0.55.0in our app. In a production build, fast typing after/and[gave no error in 7 of 7 runs. Before the change, the same input crashed in 2 of 3 runs. The two throttled human speeds above also gave no error.Screenshots/Video
N/A. No visual change.
Checklist
Additional Notes
None.
🤖 Generated with Claude Code
Summary by CodeRabbit