diff --git a/packages/core/src/api/clipboard/fromClipboard/handleFileInsertion.ts b/packages/core/src/api/clipboard/fromClipboard/handleFileInsertion.ts index 38c9921f18..aa422bb23a 100644 --- a/packages/core/src/api/clipboard/fromClipboard/handleFileInsertion.ts +++ b/packages/core/src/api/clipboard/fromClipboard/handleFileInsertion.ts @@ -170,9 +170,14 @@ export async function handleFileInsertion< const blockRect = blockElement?.getBoundingClientRect(); + const existingBlock = editor.getBlock(id); + if (!existingBlock) { + return; + } + return insertOrUpdateBlock( editor, - editor.getBlock(id)!, + existingBlock, fileBlock, blockRect && (blockRect.top + blockRect.bottom) / 2 > coords.top ? "before" @@ -183,6 +188,10 @@ export async function handleFileInsertion< return; } + if (!insertedBlockId) { + return; + } + const updateData = await editor.uploadFile(file, insertedBlockId); const updatedFileBlock = diff --git a/packages/core/src/blocks/ToggleWrapper/createToggleWrapper.ts b/packages/core/src/blocks/ToggleWrapper/createToggleWrapper.ts index de2ba427c1..257fd7ce6f 100644 --- a/packages/core/src/blocks/ToggleWrapper/createToggleWrapper.ts +++ b/packages/core/src/blocks/ToggleWrapper/createToggleWrapper.ts @@ -50,20 +50,25 @@ export const createToggleWrapper = ( const toggleButtonOnClick = () => { // Toggles visibility of child blocks. Also adds/removes the "add block" // button if there are no child blocks. + const currentBlock = editor.getBlock(block); + if (!currentBlock) { + return; + } + if (toggleWrapper.getAttribute("data-show-children") === "true") { toggleWrapper.setAttribute("data-show-children", "false"); - toggledState.set(editor.getBlock(block)!, false); + toggledState.set(currentBlock, false); if (dom.contains(toggleAddBlockButton)) { dom.removeChild(toggleAddBlockButton); } } else { toggleWrapper.setAttribute("data-show-children", "true"); - toggledState.set(editor.getBlock(block)!, true); + toggledState.set(currentBlock, true); if ( editor.isEditable && - editor.getBlock(block)?.children.length === 0 && + currentBlock.children.length === 0 && !dom.contains(toggleAddBlockButton) ) { dom.appendChild(toggleAddBlockButton); @@ -111,7 +116,10 @@ export const createToggleWrapper = ( // If a child block is added while children are hidden, show children. if (toggleWrapper.getAttribute("data-show-children") === "false") { toggleWrapper.setAttribute("data-show-children", "true"); - toggledState.set(editor.getBlock(block)!, true); + const currentBlock = editor.getBlock(block); + if (currentBlock) { + toggledState.set(currentBlock, true); + } } // Remove the "add block" button as we want to show child blocks and @@ -124,7 +132,10 @@ export const createToggleWrapper = ( // children. if (toggleWrapper.getAttribute("data-show-children") === "true") { toggleWrapper.setAttribute("data-show-children", "false"); - toggledState.set(editor.getBlock(block)!, false); + const currentBlock = editor.getBlock(block); + if (currentBlock) { + toggledState.set(currentBlock, false); + } } // Remove the "add block" button as we want to hide child blocks, diff --git a/packages/core/src/extensions/SideMenu/SideMenu.ts b/packages/core/src/extensions/SideMenu/SideMenu.ts index e5572c004c..d53a8444cc 100644 --- a/packages/core/src/extensions/SideMenu/SideMenu.ts +++ b/packages/core/src/extensions/SideMenu/SideMenu.ts @@ -241,6 +241,17 @@ export class SideMenuView< if (this.editor.isEditable) { const blockContentBoundingBox = block.node.getBoundingClientRect(); const column = block.node.closest("[data-node-type=column]"); + const sideMenuBlock = this.editor.getBlock( + this.hoveredBlock!.getAttribute("data-id")!, + ); + if (!sideMenuBlock) { + if (this.state?.show) { + this.state.show = false; + this.hoveredBlock = undefined; + this.emitUpdate(this.state); + } + return; + } this.state = { show: true, referencePos: new DOMRect( @@ -257,9 +268,7 @@ export class SideMenuView< blockContentBoundingBox.width, blockContentBoundingBox.height, ), - block: this.editor.getBlock( - this.hoveredBlock!.getAttribute("data-id")!, - )!, + block: sideMenuBlock, }; this.updateState(this.state); } diff --git a/packages/core/src/extensions/TableHandles/TableHandles.ts b/packages/core/src/extensions/TableHandles/TableHandles.ts index 4616d76b70..4a019aa3db 100644 --- a/packages/core/src/extensions/TableHandles/TableHandles.ts +++ b/packages/core/src/extensions/TableHandles/TableHandles.ts @@ -533,10 +533,10 @@ export class TableHandlesView implements PluginView { } // Hide handles if the table block has been removed. - this.state.block = this.editor.getBlock(this.state.block.id)!; + const refreshedBlock = this.editor.getBlock(this.state.block.id); if ( - !this.state.block || - this.state.block.type !== "table" || + !refreshedBlock || + refreshedBlock.type !== "table" || // when collaborating, the table element might be replaced and out of date // because yjs replaces the element when for example you change the color via the side menu !this.tableElement?.isConnected @@ -548,6 +548,7 @@ export class TableHandlesView implements PluginView { return; } + this.state.block = refreshedBlock as typeof this.state.block; const { height: rowCount, width: colCount } = getDimensionsOfTable( this.state.block, diff --git a/packages/react/src/blocks/ToggleWrapper/ToggleWrapper.tsx b/packages/react/src/blocks/ToggleWrapper/ToggleWrapper.tsx index 7fa0a4bc9a..b35fc8d779 100644 --- a/packages/react/src/blocks/ToggleWrapper/ToggleWrapper.tsx +++ b/packages/react/src/blocks/ToggleWrapper/ToggleWrapper.tsx @@ -58,10 +58,11 @@ export const ToggleWrapper = ( ); const handleToggle = (block: Block) => { - (toggledState || defaultToggledState).set( - editor.getBlock(block)!, - !showChildren, - ); + const currentBlock = editor.getBlock(block); + if (!currentBlock) { + return; + } + (toggledState || defaultToggledState).set(currentBlock, !showChildren); dispatch({ type: "toggled", }); @@ -91,7 +92,10 @@ export const ToggleWrapper = ( return 0; } - const newBlock = editor.getBlock(block)!; + const newBlock = editor.getBlock(block); + if (!newBlock) { + return 0; + } const newChildCount = newBlock.children.length || 0; if (newChildCount > childCount) { @@ -122,7 +126,7 @@ export const ToggleWrapper = ( className="bn-toggle-button" type="button" onMouseDown={(event) => event.preventDefault()} - onClick={() => handleToggle(editor.getBlock(block)!)} + onClick={() => handleToggle(block)} > (); - const block = editor.getBlock(props.blockId)!; + const block = editor.getBlock(props.blockId); const [currentURL, setCurrentURL] = useState(""); @@ -41,7 +41,10 @@ export const EmbedTab = < (event: KeyboardEvent) => { if (event.key === "Enter" && !event.nativeEvent.isComposing) { event.preventDefault(); - editor.updateBlock(block.id, { + if (!editor.getBlock(props.blockId)) { + return; + } + editor.updateBlock(props.blockId, { props: { name: filenameFromURL(currentURL), url: currentURL, @@ -49,17 +52,24 @@ export const EmbedTab = < }); } }, - [editor, block.id, currentURL], + [editor, props.blockId, currentURL], ); const handleURLClick = useCallback(() => { - editor.updateBlock(block.id, { + if (!editor.getBlock(props.blockId)) { + return; + } + editor.updateBlock(props.blockId, { props: { name: filenameFromURL(currentURL), url: currentURL, } as any, }); - }, [editor, block.id, currentURL]); + }, [editor, props.blockId, currentURL]); + + if (!block) { + return null; + } return ( diff --git a/packages/react/src/components/FilePanel/DefaultTabs/UploadTab.tsx b/packages/react/src/components/FilePanel/DefaultTabs/UploadTab.tsx index fa8a5a2d49..41e726ca72 100644 --- a/packages/react/src/components/FilePanel/DefaultTabs/UploadTab.tsx +++ b/packages/react/src/components/FilePanel/DefaultTabs/UploadTab.tsx @@ -29,7 +29,7 @@ export const UploadTab = < const editor = useBlockNoteEditor(); - const block = editor.getBlock(props.blockId)!; + const block = editor.getBlock(props.blockId); const [uploadFailed, setUploadFailed] = useState(false); @@ -53,6 +53,9 @@ export const UploadTab = < if (editor.uploadFile !== undefined) { try { let updateData = await editor.uploadFile(file, props.blockId); + if (!editor.getBlock(props.blockId)) { + return; + } if (typeof updateData === "string") { // received a url updateData = { @@ -76,6 +79,10 @@ export const UploadTab = < [props.blockId, editor, setLoading], ); + if (!block) { + return null; + } + const spec = editor.schema.blockSpecs[block.type]; const accept = spec.implementation.meta?.fileBlockAccept?.length ? spec.implementation.meta.fileBlockAccept.join(",") diff --git a/packages/xl-ai/src/api/formats/markdown-blocks/tools/rebaseTool.ts b/packages/xl-ai/src/api/formats/markdown-blocks/tools/rebaseTool.ts index aff89b423b..2e4b31136f 100644 --- a/packages/xl-ai/src/api/formats/markdown-blocks/tools/rebaseTool.ts +++ b/packages/xl-ai/src/api/formats/markdown-blocks/tools/rebaseTool.ts @@ -11,7 +11,11 @@ export function createMDRebaseTool( editor: BlockNoteEditor, ) { const tr = getApplySuggestionsTr(editor); - const md = editor.blocksToMarkdownLossy([getBlock(tr.doc, id)!]); + const block = getBlock(tr.doc, id); + if (!block) { + throw new Error("block not found"); + } + const md = editor.blocksToMarkdownLossy([block]); const blocks = editor.tryParseMarkdownToBlocks(md); const steps = updateToReplaceSteps(