fix: ignore stale BlockNote side menu blocks
This commit is contained in:
@@ -117,6 +117,61 @@
|
||||
}
|
||||
function kn(o, e) {
|
||||
const t = [
|
||||
--- a/src/extensions/SideMenu/SideMenu.ts
|
||||
+++ b/src/extensions/SideMenu/SideMenu.ts
|
||||
@@ -230,38 +230,49 @@
|
||||
// Doesn't update if the menu is already open and the mouse cursor is still hovering the same block.
|
||||
if (
|
||||
this.state?.show &&
|
||||
this.hoveredBlock?.hasAttribute("data-id") &&
|
||||
this.hoveredBlock?.getAttribute("data-id") === block.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hoveredBlock = block.node;
|
||||
+ const hoveredBlockId = this.hoveredBlock.getAttribute("data-id");
|
||||
+ const hoveredEditorBlock = hoveredBlockId
|
||||
+ ? this.editor.getBlock(hoveredBlockId)
|
||||
+ : undefined;
|
||||
+
|
||||
+ if (!hoveredEditorBlock) {
|
||||
+ if (this.state?.show) {
|
||||
+ this.state.show = false;
|
||||
+ this.updateState(this.state);
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
// Shows or updates elements.
|
||||
if (this.editor.isEditable) {
|
||||
const blockContentBoundingBox = block.node.getBoundingClientRect();
|
||||
const column = block.node.closest("[data-node-type=column]");
|
||||
this.state = {
|
||||
show: true,
|
||||
referencePos: new DOMRect(
|
||||
column
|
||||
? // We take the first child as column elements have some default
|
||||
// padding. This is a little weird since this child element will
|
||||
// be the first block, but since it's always non-nested and we
|
||||
// only take the x coordinate, it's ok.
|
||||
column.firstElementChild!.getBoundingClientRect().x
|
||||
: (
|
||||
this.pmView.dom.firstChild as HTMLElement
|
||||
).getBoundingClientRect().x,
|
||||
blockContentBoundingBox.y,
|
||||
blockContentBoundingBox.width,
|
||||
blockContentBoundingBox.height,
|
||||
),
|
||||
- block: this.editor.getBlock(
|
||||
- this.hoveredBlock!.getAttribute("data-id")!,
|
||||
- )!,
|
||||
+ block: hoveredEditorBlock,
|
||||
};
|
||||
this.updateState(this.state);
|
||||
}
|
||||
};
|
||||
--- a/src/extensions/SuggestionMenu/SuggestionMenu.ts
|
||||
+++ b/src/extensions/SuggestionMenu/SuggestionMenu.ts
|
||||
@@ -32,7 +32,7 @@
|
||||
@@ -202,6 +257,48 @@
|
||||
if (
|
||||
--- a/dist/TrailingNode-CxM966vN.js
|
||||
+++ b/dist/TrailingNode-CxM966vN.js
|
||||
@@ -1200,25 +1200,31 @@
|
||||
(r = this.state) != null && r.show && (this.state.show = !1, this.updateState(this.state));
|
||||
return;
|
||||
}
|
||||
- if (!((s = this.state) != null && s.show && ((i = this.hoveredBlock) != null && i.hasAttribute("data-id")) && ((a = this.hoveredBlock) == null ? void 0 : a.getAttribute("data-id")) === t.id) && (this.hoveredBlock = t.node, this.editor.isEditable)) {
|
||||
- const c = t.node.getBoundingClientRect(), l = t.node.closest("[data-node-type=column]");
|
||||
+ if ((s = this.state) != null && s.show && ((i = this.hoveredBlock) != null && i.hasAttribute("data-id")) && ((a = this.hoveredBlock) == null ? void 0 : a.getAttribute("data-id")) === t.id)
|
||||
+ return;
|
||||
+ this.hoveredBlock = t.node;
|
||||
+ const c = this.hoveredBlock.getAttribute("data-id"), l = c ? this.editor.getBlock(c) : void 0;
|
||||
+ if (!l) {
|
||||
+ (i = this.state) != null && i.show && (this.state.show = !1, this.updateState(this.state));
|
||||
+ return;
|
||||
+ }
|
||||
+ if (this.editor.isEditable) {
|
||||
+ const u = t.node.getBoundingClientRect(), h = t.node.closest("[data-node-type=column]");
|
||||
this.state = {
|
||||
show: !0,
|
||||
referencePos: new DOMRect(
|
||||
- l ? (
|
||||
+ h ? (
|
||||
// We take the first child as column elements have some default
|
||||
// padding. This is a little weird since this child element will
|
||||
// be the first block, but since it's always non-nested and we
|
||||
// only take the x coordinate, it's ok.
|
||||
- l.firstElementChild.getBoundingClientRect().x
|
||||
+ h.firstElementChild.getBoundingClientRect().x
|
||||
) : this.pmView.dom.firstChild.getBoundingClientRect().x,
|
||||
- c.y,
|
||||
- c.width,
|
||||
- c.height
|
||||
+ u.y,
|
||||
+ u.width,
|
||||
+ u.height
|
||||
),
|
||||
- block: this.editor.getBlock(
|
||||
- this.hoveredBlock.getAttribute("data-id")
|
||||
- )
|
||||
+ block: l
|
||||
}, this.updateState(this.state);
|
||||
}
|
||||
});
|
||||
@@ -1746,10 +1746,10 @@
|
||||
);
|
||||
this.state.rowIndex !== void 0 && this.state.colIndex !== void 0 && (this.state.rowIndex >= e && (this.state.rowIndex = e - 1), this.state.colIndex >= t && (this.state.colIndex = t - 1));
|
||||
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -6,7 +6,7 @@ settings:
|
||||
|
||||
patchedDependencies:
|
||||
'@blocknote/core@0.46.2':
|
||||
hash: 28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42
|
||||
hash: 05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626
|
||||
path: patches/@blocknote__core@0.46.2.patch
|
||||
'@blocknote/react@0.46.2':
|
||||
hash: e09f7011df33f4ff92c0d3fd8c9060e62f08997d076f3e438e1e82f8c1ab2f76
|
||||
@@ -27,10 +27,10 @@ importers:
|
||||
version: 0.78.0(zod@4.3.6)
|
||||
'@blocknote/code-block':
|
||||
specifier: ^0.46.2
|
||||
version: 0.46.2(@blocknote/core@0.46.2(patch_hash=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0))
|
||||
version: 0.46.2(@blocknote/core@0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0))
|
||||
'@blocknote/core':
|
||||
specifier: ^0.46.2
|
||||
version: 0.46.2(patch_hash=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
version: 0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@blocknote/mantine':
|
||||
specifier: ^0.46.2
|
||||
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)
|
||||
@@ -5359,9 +5359,9 @@ snapshots:
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@blocknote/code-block@0.46.2(@blocknote/core@0.46.2(patch_hash=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0))':
|
||||
'@blocknote/code-block@0.46.2(@blocknote/core@0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0))':
|
||||
dependencies:
|
||||
'@blocknote/core': 0.46.2(patch_hash=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@blocknote/core': 0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@shikijs/core': 3.23.0
|
||||
'@shikijs/engine-javascript': 3.23.0
|
||||
'@shikijs/langs': 3.23.0
|
||||
@@ -5369,7 +5369,7 @@ snapshots:
|
||||
'@shikijs/themes': 3.23.0
|
||||
'@shikijs/types': 3.22.0
|
||||
|
||||
'@blocknote/core@0.46.2(patch_hash=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)':
|
||||
'@blocknote/core@0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)':
|
||||
dependencies:
|
||||
'@emoji-mart/data': 1.2.1
|
||||
'@handlewithcare/prosemirror-inputrules': 0.1.4(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)
|
||||
@@ -5421,7 +5421,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=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@blocknote/core': 0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@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)
|
||||
@@ -5443,7 +5443,7 @@ snapshots:
|
||||
|
||||
'@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=28d8e7bb45cd7d97aff60af3926d65b831605bfe4d582a1da725d214d3fb1f42)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@blocknote/core': 0.46.2(patch_hash=05f1896ec4fac0d7ffd1f823acd036baa82c1d6170a8b5699ddeb6a4dd2b3626)(@types/hast@3.0.4)(highlight.js@11.11.1)(lowlight@3.3.0)
|
||||
'@emoji-mart/data': 1.2.1
|
||||
'@floating-ui/react': 0.27.17(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
||||
72
src/lib/blockNoteSideMenu.regression.test.ts
Normal file
72
src/lib/blockNoteSideMenu.regression.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { SideMenuView } from '../../node_modules/@blocknote/core/src/extensions/SideMenu/SideMenu'
|
||||
|
||||
const originalElementsFromPoint = document.elementsFromPoint
|
||||
|
||||
function createRect({ left, top, width, height }: { left: number; top: number; width: number; height: number }) {
|
||||
return {
|
||||
left,
|
||||
top,
|
||||
right: left + width,
|
||||
bottom: top + height,
|
||||
width,
|
||||
height,
|
||||
x: left,
|
||||
y: top,
|
||||
toJSON: () => ({}),
|
||||
} as DOMRect
|
||||
}
|
||||
|
||||
function createStaleEditorDom() {
|
||||
const editor = document.createElement('div')
|
||||
editor.className = 'bn-editor'
|
||||
editor.getBoundingClientRect = vi.fn(() => createRect({ left: 0, top: 0, width: 480, height: 240 }))
|
||||
|
||||
const blockGroup = document.createElement('div')
|
||||
blockGroup.className = 'bn-block-group'
|
||||
blockGroup.getBoundingClientRect = vi.fn(() => createRect({ left: 20, top: 20, width: 360, height: 160 }))
|
||||
|
||||
const block = document.createElement('div')
|
||||
block.setAttribute('data-node-type', 'blockContainer')
|
||||
block.setAttribute('data-id', 'stale-table-block')
|
||||
block.getBoundingClientRect = vi.fn(() => createRect({ left: 20, top: 40, width: 260, height: 48 }))
|
||||
|
||||
blockGroup.appendChild(block)
|
||||
editor.appendChild(blockGroup)
|
||||
document.body.appendChild(editor)
|
||||
|
||||
return { block, editor }
|
||||
}
|
||||
|
||||
describe('patched BlockNote side menu lifecycle', () => {
|
||||
afterEach(() => {
|
||||
document.elementsFromPoint = originalElementsFromPoint
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
||||
it('does not publish side-menu state for a stale hovered block id', () => {
|
||||
const { block, editor } = createStaleEditorDom()
|
||||
document.elementsFromPoint = vi.fn(() => [block, editor])
|
||||
|
||||
const updates: unknown[] = []
|
||||
const view = new SideMenuView(
|
||||
{
|
||||
getBlock: vi.fn(() => undefined),
|
||||
isEditable: true,
|
||||
} as never,
|
||||
{
|
||||
dom: editor,
|
||||
root: document,
|
||||
} as never,
|
||||
(state) => updates.push(state),
|
||||
)
|
||||
|
||||
try {
|
||||
view.onMouseMove(new MouseEvent('mousemove', { clientX: 40, clientY: 50 }))
|
||||
|
||||
expect(updates).toEqual([])
|
||||
} finally {
|
||||
view.destroy()
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user