From 2e40945c2da18a1156502b534be94e392a6fee86 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Thu, 30 Apr 2026 01:20:12 +0200 Subject: [PATCH] fix: guard blocknote popover references --- patches/@blocknote__react@0.46.2.patch | 24 +++++++++++++++------ pnpm-lock.yaml | 8 +++---- src/lib/blockNotePopover.regression.test.ts | 15 +++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 src/lib/blockNotePopover.regression.test.ts diff --git a/patches/@blocknote__react@0.46.2.patch b/patches/@blocknote__react@0.46.2.patch index 46db79b1..ba191c46 100644 --- a/patches/@blocknote__react@0.46.2.patch +++ b/patches/@blocknote__react@0.46.2.patch @@ -2,9 +2,21 @@ diff --git a/dist/blocknote-react.js b/dist/blocknote-react.js index 6271d12d2cd5152e924c5bfe78f3b8904844dbfe..12bb96bb36d445a77d51a18d0de446a3f9f0ea59 100644 --- a/dist/blocknote-react.js +++ b/dist/blocknote-react.js -@@ -157,6 +157,16 @@ function so(e) { - const n = "getBoundingClientRect" in e ? () => e.getBoundingClientRect() : () => e.element.getBoundingClientRect(); - return () => "element" in e && (e.cacheMountedBoundingClientRect ?? !0) ? (e.element.isConnected && (t = n()), t) : n(); +@@ -155,8 +155,26 @@ var Rt = (e) => { + function so(e) { + let t = new DOMRect(); +- const n = "getBoundingClientRect" in e ? () => e.getBoundingClientRect() : () => e.element.getBoundingClientRect(); +- return () => "element" in e && (e.cacheMountedBoundingClientRect ?? !0) ? (e.element.isConnected && (t = n()), t) : n(); ++ const n = () => "getBoundingClientRect" in e ? e.getBoundingClientRect() : e.element instanceof Element ? e.element.getBoundingClientRect() : t; ++ return () => { ++ if (!("element" in e) || !(e.cacheMountedBoundingClientRect ?? !0)) ++ return n(); ++ if (!(e.element instanceof Element)) ++ return n(); ++ if (e.element.isConnected) ++ t = n(); ++ return t; ++ }; } +function __bnSafeDomAtPos(e, t) { + const n = e.prosemirrorView; @@ -19,7 +31,7 @@ index 6271d12d2cd5152e924c5bfe78f3b8904844dbfe..12bb96bb36d445a77d51a18d0de446a3 const z = (e) => { var h, b, p; const { refs: t, floatingStyles: n, context: o } = Ze({ -@@ -216,9 +226,7 @@ const Lt = (e) => { +@@ -216,9 +234,7 @@ const Lt = (e) => { const s = Ue(t, c.doc); if (!s) return; @@ -30,7 +42,7 @@ index 6271d12d2cd5152e924c5bfe78f3b8904844dbfe..12bb96bb36d445a77d51a18d0de446a3 if (a instanceof Element) return { element: a -@@ -3306,14 +3314,15 @@ const pi = (e) => { +@@ -3306,14 +3322,15 @@ const pi = (e) => { ); if (!m) return {}; @@ -49,7 +61,7 @@ index 6271d12d2cd5152e924c5bfe78f3b8904844dbfe..12bb96bb36d445a77d51a18d0de446a3 return p instanceof Element ? (d.cellReference = { element: p }, d.rowReference = { element: f, getBoundingClientRect: () => { -@@ -4371,7 +4380,7 @@ const El = (e) => { +@@ -4371,7 +4388,7 @@ const El = (e) => { const a = Ue(t, c.prosemirrorState.doc); if (!a) return; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6b006e9..98d15dd4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ patchedDependencies: hash: dc394d11ab419b36b8d306cbbb6ce39f0722e042b63b2b7d254c7d7f90782e94 path: patches/@blocknote__core@0.46.2.patch '@blocknote/react@0.46.2': - hash: e3726d75ed65e07adb1fd48262d6a15f8e52b1cc257177aaf632937830170c97 + hash: e09f7011df33f4ff92c0d3fd8c9060e62f08997d076f3e438e1e82f8c1ab2f76 path: patches/@blocknote__react@0.46.2.patch '@tiptap/extension-link@3.19.0': hash: fbe59b1b8b798ba3fefa371c0729b5aa3458e1ea70a4b86cd5267f9f62529284 @@ -36,7 +36,7 @@ importers: version: 0.46.2(@floating-ui/dom@1.7.5)(@mantine/core@8.3.14(@mantine/hooks@8.3.14(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@8.3.14(react@19.2.4))(@mantine/utils@6.0.22(react@19.2.4))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@blocknote/react': specifier: ^0.46.2 - version: 0.46.2(patch_hash=e3726d75ed65e07adb1fd48262d6a15f8e52b1cc257177aaf632937830170c97)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 0.46.2(patch_hash=e09f7011df33f4ff92c0d3fd8c9060e62f08997d076f3e438e1e82f8c1ab2f76)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@codemirror/commands': specifier: ^6.10.2 version: 6.10.2 @@ -5422,7 +5422,7 @@ snapshots: '@blocknote/mantine@0.46.2(@floating-ui/dom@1.7.5)(@mantine/core@8.3.14(@mantine/hooks@8.3.14(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@8.3.14(react@19.2.4))(@mantine/utils@6.0.22(react@19.2.4))(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@blocknote/core': 0.46.2(patch_hash=dc394d11ab419b36b8d306cbbb6ce39f0722e042b63b2b7d254c7d7f90782e94)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0) - '@blocknote/react': 0.46.2(patch_hash=e3726d75ed65e07adb1fd48262d6a15f8e52b1cc257177aaf632937830170c97)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@blocknote/react': 0.46.2(patch_hash=e09f7011df33f4ff92c0d3fd8c9060e62f08997d076f3e438e1e82f8c1ab2f76)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@mantine/core': 8.3.14(@mantine/hooks@8.3.14(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@mantine/hooks': 8.3.14(react@19.2.4) '@mantine/utils': 6.0.22(react@19.2.4) @@ -5441,7 +5441,7 @@ snapshots: - sugar-high - supports-color - '@blocknote/react@0.46.2(patch_hash=e3726d75ed65e07adb1fd48262d6a15f8e52b1cc257177aaf632937830170c97)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@blocknote/react@0.46.2(patch_hash=e09f7011df33f4ff92c0d3fd8c9060e62f08997d076f3e438e1e82f8c1ab2f76)(@floating-ui/dom@1.7.5)(@types/hast@3.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@blocknote/core': 0.46.2(patch_hash=dc394d11ab419b36b8d306cbbb6ce39f0722e042b63b2b7d254c7d7f90782e94)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0) '@emoji-mart/data': 1.2.1 diff --git a/src/lib/blockNotePopover.regression.test.ts b/src/lib/blockNotePopover.regression.test.ts new file mode 100644 index 00000000..9a4ce0b7 --- /dev/null +++ b/src/lib/blockNotePopover.regression.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from 'vitest' +import { getMountedBoundingClientRectCache } from '@blocknote/react' + +describe('patched BlockNote popover references', () => { + it('uses the virtual rect when a remounting suggestion menu has no DOM element', () => { + const fallbackRect = new DOMRect(4, 8, 16, 24) + const readRect = getMountedBoundingClientRectCache({ + element: undefined, + getBoundingClientRect: () => fallbackRect, + } as never) + + expect(() => readRect()).not.toThrow() + expect(readRect()).toBe(fallbackRect) + }) +})