Skip to content

Upgrade blocknote dependencies from 0.31.1 to 0.47.0.#18207

Merged
FelixMalfait merged 12 commits intomainfrom
blocknote-up
Feb 27, 2026
Merged

Upgrade blocknote dependencies from 0.31.1 to 0.47.0.#18207
FelixMalfait merged 12 commits intomainfrom
blocknote-up

Conversation

@mabdullahabaid
Copy link
Copy Markdown
Member

This PR pgrades all BlockNote packages (@blocknote/core, @blocknote/react, @blocknote/mantine, @blocknote/server-util, @blocknote/xl-docx-exporter, @blocknote/xl-pdf-exporter) to 0.47.0 and adapts the codebase to the new API.

Changes

  • Dependency upgrades: Bumped all BlockNote packages to 0.47.0, added required Mantine v8 peer dependencies, removed unnecessary prosemirror resolutions
  • Formatting toolbar: Replaced the manual reimplementation of FormattingToolbarController (which handled visibility, positioning, portal rendering, text-alignment-based placement, and a dangerouslySetInnerHTML transition trick) with BlockNote's built-in FormattingToolbarController. The toolbar buttons themselves are unchanged.
  • Side menu: Replaced manual drag handle menu positioning and rendering (DashboardBlockDragHandleMenu, DashboardBlockColorPicker, and their floating configs) with BlockNote's built-in SideMenuController, DragHandleButton, and DragHandleMenu components. Deleted 4 files that became dead code.
  • Extension API migration: Replaced deprecated editor.suggestionMenus and editor.formattingToolbar APIs with the new extension system (SuggestionMenu, useExtensionState, editor.getExtension())
  • Slash menu fixes: Filtered out BlockNote's new default "File" item (added in 0.47) to avoid duplicates with our custom one; added icon mappings for new block types (Toggle List, Divider, Toggle Headings, Headings 4-6)
  • Server-side: Switched @blocknote/server-util to dynamic import() to handle ESM-only transitive dependencies in CJS context

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 27 files

Prompt for AI agents (all 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/twenty-front/src/modules/blocknote-editor/utils/getFirstNonEmptyLineOfRichText.ts">

<violation number="1" location="packages/twenty-front/src/modules/blocknote-editor/utils/getFirstNonEmptyLineOfRichText.ts:20">
P2: Link inline content is now ignored, so a line that only contains a link returns an empty string. Handle BlockNote’s `link` inline content by extracting its text (or href) instead of skipping it.</violation>
</file>

<file name="packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx">

<violation number="1" location="packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx:51">
P2: Avoid calling setState or triggering side effects during render. Move this logic into a useEffect that runs when isSlashMenuShowing changes to prevent render-time updates and potential loops.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

);

editor.suggestionMenus.on('update /', updateCallBack);
if (prevShowing !== isSlashMenuShowing) {
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Avoid calling setState or triggering side effects during render. Move this logic into a useEffect that runs when isSlashMenuShowing changes to prevent render-time updates and potential loops.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx, line 51:

<comment>Avoid calling setState or triggering side effects during render. Move this logic into a useEffect that runs when isSlashMenuShowing changes to prevent render-time updates and potential loops.</comment>

<file context>
@@ -60,7 +48,10 @@ export const BlockEditorDropdownFocusEffect = ({
   );
 
-  editor.suggestionMenus.on('update /', updateCallBack);
+  if (prevShowing !== isSlashMenuShowing) {
+    setPrevShowing(isSlashMenuShowing);
+    syncSlashMenuState(isSlashMenuShowing);
</file context>
Fix with Cubic

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockNote 0.47.0 replaced the event-based editor.suggestionMenus.on() API with useExtensionState(SuggestionMenu), a React-reactive hook — there is no event to subscribe to anymore. To synchronize this value with our Jotai store, we use React's documented pattern for adjusting state during render: a useState guard that compares the previous value and only syncs when it changes. This technically calls setState during render, but React explicitly supports this — it retries the render with updated state, and the guard prevents infinite loops. The store.set() calls are also safe, as Jotai batches updates without triggering synchronous re-renders.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 24, 2026

Greptile Summary

This PR successfully upgrades BlockNote from 0.31.1 to 0.47.0, migrating the codebase to the new extension API and leveraging built-in components to reduce custom code.

Major Changes:

  • Replaced deprecated editor.suggestionMenus and editor.formattingToolbar APIs with the new extension system (SuggestionMenu, useExtensionState, editor.getExtension())
  • Replaced manual FormattingToolbarController implementation with BlockNote's built-in controller, removing ~160 lines of complex positioning logic
  • Replaced manual side menu drag handle implementation with SideMenuController, DragHandleButton, and DragHandleMenu components
  • Added Mantine v8 peer dependencies (@mantine/core, @mantine/hooks, @mantine/utils)
  • Removed prosemirror resolutions and docx dependency
  • Filtered out duplicate "File" item from slash menu (BlockNote 0.47 added it by default)
  • Added icon mappings for new block types (Heading 4-6, Toggle List, Divider)
  • Server-side: Implemented native import() workaround to handle ESM-only transitive dependencies in CJS context

Critical Issue:

  • BlockEditorDropdownFocusEffect.tsx calls setState during render (lines 51-54), which violates React's rendering rules and will cause unnecessary re-renders. This needs to be moved into a useEffect hook.

Confidence Score: 3/5

  • This PR is mostly safe but has one critical React anti-pattern that needs fixing before merge
  • The upgrade is well-executed with proper API migrations and significant code simplification through built-in components. However, the setState-during-render bug in BlockEditorDropdownFocusEffect.tsx is a critical issue that violates React's rules and will cause performance problems. Once fixed, this would be a 4/5.
  • Pay close attention to packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx - the setState during render must be fixed

Important Files Changed

Filename Overview
packages/twenty-front/src/modules/blocknote-editor/components/BlockEditorDropdownFocusEffect.tsx Migrated to new extension API but has a critical setState-during-render bug that causes unnecessary re-renders
packages/twenty-front/package.json Updated BlockNote packages to 0.47.0, added Mantine v8 peer dependencies, removed docx dependency
packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardFormattingToolbar.tsx Replaced manual toolbar implementation with BlockNote's built-in FormattingToolbarController, significantly simplifying code
packages/twenty-front/src/modules/page-layout/widgets/standalone-rich-text/components/DashboardEditorSideMenu.tsx Replaced manual side menu with BlockNote's built-in SideMenuController and DragHandleButton components
packages/twenty-server/src/engine/core-modules/record-transformer/utils/transform-rich-text-v2.util.ts Added native import() workaround for ESM-only dependencies in CJS context with proper TypeScript typing
packages/twenty-front/src/modules/blocknote-editor/utils/getSlashMenu.ts Filtered out duplicate "File" item, added icon mappings for new block types (H4-6, Toggle List, Divider)

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[BlockNote 0.31.1] --> B[BlockNote 0.47.0]
    
    B --> C[New Extension API]
    B --> D[Built-in Controllers]
    B --> E[Mantine v8]
    
    C --> C1[SuggestionMenu Extension]
    C --> C2[useExtensionState Hook]
    C1 --> F1[BlockEditorDropdownFocusEffect]
    C1 --> F2[CustomAddBlockItem]
    C2 --> F1
    
    D --> D1[FormattingToolbarController]
    D --> D2[SideMenuController]
    D --> D3[DragHandleButton/Menu]
    D1 --> G1[DashboardFormattingToolbar]
    D2 --> G2[DashboardEditorSideMenu]
    D3 --> G2
    
    E --> H1[Added @mantine/core 8.3.11]
    E --> H2[Added @mantine/hooks 8.3.11]
    
    I[Server-Side] --> J[ESM/CJS Compatibility]
    J --> K[Native import for ESM modules]
    K --> L[transform-rich-text-v2.util]
    
    M[UI Updates] --> N[New Block Types]
    N --> N1[Heading 4-6]
    N --> N2[Toggle List]
    N --> N3[Divider]
    N1 --> O[Added IconH4/H5/H6]
    
    P[Dead Code Removal] --> P1[DashboardBlockDragHandleMenu]
    P --> P2[DashboardBlockColorPicker]
    P --> P3[FloatingConfig Files]
Loading

Last reviewed commit: c067bd8

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

27 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +51 to +54
if (prevShowing !== isSlashMenuShowing) {
setPrevShowing(isSlashMenuShowing);
syncSlashMenuState(isSlashMenuShowing);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling setState during render creates a React anti-pattern. This will trigger unnecessary re-renders and could cause infinite loops.

Suggested change
if (prevShowing !== isSlashMenuShowing) {
setPrevShowing(isSlashMenuShowing);
syncSlashMenuState(isSlashMenuShowing);
}
useEffect(() => {
syncSlashMenuState(isSlashMenuShowing);
}, [isSlashMenuShowing, syncSlashMenuState]);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replied to Cubic with reasoning.

@socket-security
Copy link
Copy Markdown

socket-security bot commented Feb 24, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm @ai-sdk/anthropic is 98.0% likely obfuscated

Confidence: 0.98

Location: Package overview

From: packages/twenty-server/package.jsonnpm/@ai-sdk/anthropic@3.0.47

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@ai-sdk/anthropic@3.0.47. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all 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/twenty-front/src/modules/blocknote-editor/utils/getFirstNonEmptyLineOfRichText.ts">

<violation number="1">
P2: Guard against non-array `block.content` values before treating it as an array; the previous Array.isArray check was removed, so unexpected shapes will now cause runtime errors when reading `length` or iterating.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@FelixMalfait FelixMalfait merged commit 4ed09a3 into main Feb 27, 2026
62 of 76 checks passed
@FelixMalfait FelixMalfait deleted the blocknote-up branch February 27, 2026 08:16
@twenty-eng-sync
Copy link
Copy Markdown

Hey @mabdullahabaid! After you've done the QA of your Pull Request, you can mark it as done here. Thank you!

@greptile-apps greptile-apps bot mentioned this pull request Feb 27, 2026
sonarly bot pushed a commit that referenced this pull request Mar 13, 2026
https://sonarly.com/issue/14499?type=bug

BlockNote 0.31.1's Enter key handler throws an unhandled `TransformError: Cannot join blockGroup onto blockContainer` when splitting blocks in rich text fields containing table blocks, crashing the editor.

Fix: No code changes needed. The bug is in BlockNote 0.31.1's internal Enter key handler (`Ou` function), which calls `Transaction.split(pos, 2)` and produces an invalid `ReplaceStep` when table blocks are present in the document. This is a third-party library bug.

The fix was already merged by Abdullah (@mabdullahabaid) in commit `4ed09a3feb` ("Upgrade blocknote dependencies from 0.31.1 to 0.47.0", PR #18207, Feb 27 2026). This upgrade brings in 16 minor versions of BlockNote fixes including improvements to block splitting, table handling, and the Enter key handler.

The bug persists in production only because v1.18.1 (released Feb 20) predates the upgrade. Deploying the next release will resolve this issue for all users.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants