--- a/dist/defaultBlocks-DE5GNdJH.js +++ b/dist/defaultBlocks-DE5GNdJH.js @@ -1120,6 +1120,8 @@ ), i.value = t.props.language || e.defaultLanguage || "text", n.isEditable) { const l = (u) => { const d = u.target.value; + if (!n.getBlock(t.id)) + return; n.updateBlock(t.id, { props: { language: d } }); }; i.addEventListener("change", l), s = () => i.removeEventListener("change", l); @@ -2639,7 +2641,7 @@ this.editor = t, this.pluginState = void 0, this.emitUpdate = (a) => { var s; if (!this.state) - throw new Error("Attempting to update uninitialized suggestions menu"); + return; n(a, { ...this.state, ignoreQueryLength: (s = this.pluginState) == null ? void 0 : s.ignoreQueryLength @@ -2651,17 +2653,23 @@ if (!a && !(o !== void 0 && r !== void 0) && !s) return; if (this.pluginState = s ? o : r, s || !this.editor.isEditable) { - this.state && (this.state.show = !1), this.emitUpdate(this.pluginState.triggerCharacter); + if (!this.state) + return; + this.state.show = !1, this.emitUpdate(this.pluginState.triggerCharacter); return; } const c = (l = this.rootEl) == null ? void 0 : l.querySelector( `[data-decoration-id="${this.pluginState.decorationId}"]` ); - this.editor.isEditable && c && (this.state = { + if (!c) { + this.state && (this.state.show = !1, this.emitUpdate(this.pluginState.triggerCharacter)); + return; + } + this.state = { show: !0, referencePos: c.getBoundingClientRect().toJSON(), query: this.pluginState.query - }, this.emitUpdate(this.pluginState.triggerCharacter)); + }, this.emitUpdate(this.pluginState.triggerCharacter); } destroy() { var t; @@ -2761,7 +2770,7 @@ if (a === s) { const c = r.state.doc; for (const l of t) { - const u = l.length > 1 ? c.textBetween(a - l.length, a) + i : i; + const u = l.length > 1 ? c.textBetween(a - (l.length - 1), a) + i : i; if (l === u) return r.dispatch(r.state.tr.insertText(i)), r.dispatch( r.state.tr.setMeta(B, { --- a/src/blocks/Code/block.ts +++ b/src/blocks/Code/block.ts @@ -132,7 +132,11 @@ if (editor.isEditable) { const handleLanguageChange = (event: Event) => { const language = (event.target as HTMLSelectElement).value; - + + if (!editor.getBlock(block.id)) { + return; + } + editor.updateBlock(block.id, { props: { language } }); }; select.addEventListener("change", handleLanguageChange); --- a/src/editor/managers/ExtensionManager/extensions.ts +++ b/src/editor/managers/ExtensionManager/extensions.ts @@ -84,7 +84,10 @@ }).configure({ defaultProtocol: DEFAULT_LINK_PROTOCOL, // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450 - protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS, + // Tolaria routes editor link clicks through its guarded native opener. + openOnClick: false, + // Tolaria pre-registers BlockNote's non-native protocols before linkify initializes. + protocols: [], }), ...(Object.values(editor.schema.styleSpecs).map((styleSpec) => { return styleSpec.implementation.mark.configure({ --- a/dist/blocknote.js +++ b/dist/blocknote.js @@ -2037,7 +2037,9 @@ ] }) ); -let fe = !1; +const bnLinkifyProtocolFlag = "__tolariaBlockNoteLinkifyProtocolsRegistered"; +const bnGlobalObject = typeof globalThis > "u" ? void 0 : globalThis; +let fe = Boolean(bnGlobalObject && bnGlobalObject[bnLinkifyProtocolFlag]); function mn(o, e) { const t = [ I.ClipboardTextSerializer, @@ -2062,7 +2064,10 @@ }).configure({ defaultProtocol: Ct, // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450 - protocols: fe ? [] : Bt + // Tolaria routes editor link clicks through its guarded native opener. + openOnClick: !1, + // Tolaria pre-registers BlockNote's non-native protocols before linkify initializes. + protocols: [] }), ...Object.values(o.schema.styleSpecs).map((n) => n.implementation.mark.configure({ editor: o @@ -2112,7 +2115,7 @@ ), Do(o) ]; - return fe = !0, t; + return fe = !0, bnGlobalObject && (bnGlobalObject[bnLinkifyProtocolFlag] = !0), t; } 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 @@ this.emitUpdate = (menuName: string) => { if (!this.state) { - throw new Error("Attempting to update uninitialized suggestions menu"); + return; } emitUpdate(menuName, { @@ -83,29 +83,38 @@ this.pluginState = stopped ? prev : next; if (stopped || !this.editor.isEditable) { - if (this.state) { - this.state.show = false; - } + if (!this.state) { + return; + } + + this.state.show = false; this.emitUpdate(this.pluginState!.triggerCharacter); return; } const decorationNode = this.rootEl?.querySelector( `[data-decoration-id="${this.pluginState!.decorationId}"]`, ); - if (this.editor.isEditable && decorationNode) { - this.state = { - show: true, - referencePos: decorationNode - .getBoundingClientRect() - .toJSON() as DOMRect, - query: this.pluginState!.query, - }; - - this.emitUpdate(this.pluginState!.triggerCharacter!); + if (!decorationNode) { + if (this.state) { + this.state.show = false; + this.emitUpdate(this.pluginState!.triggerCharacter!); + } + + return; } + + this.state = { + show: true, + referencePos: decorationNode + .getBoundingClientRect() + .toJSON() as DOMRect, + query: this.pluginState!.query, + }; + + this.emitUpdate(this.pluginState!.triggerCharacter!); } destroy() { --- a/src/extensions/TableHandles/TableHandles.ts +++ b/src/extensions/TableHandles/TableHandles.ts @@ -572,9 +572,14 @@ const tableBody = this.tableElement!.querySelector("tbody"); if (!tableBody) { - throw new Error( - "Table block does not contain a 'tbody' HTML element. This should never happen.", - ); + this.state.show = false; + this.state.showAddOrRemoveRowsButton = false; + this.state.showAddOrRemoveColumnsButton = false; + this.state.rowIndex = undefined; + this.state.colIndex = undefined; + this.state.referencePosCell = undefined; + this.emitUpdate(); + return; } 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)); const o = this.tableElement.querySelector("tbody"); - if (!o) - throw new Error( - "Table block does not contain a 'tbody' HTML element. This should never happen." - ); + if (!o) { + this.state.show = !1, this.state.showAddOrRemoveRowsButton = !1, this.state.showAddOrRemoveColumnsButton = !1, this.state.rowIndex = void 0, this.state.colIndex = void 0, this.state.referencePosCell = void 0, this.emitUpdate(); + return; + } if (this.state.rowIndex !== void 0 && this.state.colIndex !== void 0) { const i = o.children[this.state.rowIndex].children[this.state.colIndex]; i ? this.state.referencePosCell = i.getBoundingClientRect() : (this.state.rowIndex = void 0, this.state.colIndex = void 0);