diff --git a/packages/extension-bubble-menu/src/bubble-menu-plugin.ts b/packages/extension-bubble-menu/src/bubble-menu-plugin.ts index 91635f2c..98254c3f 100644 --- a/packages/extension-bubble-menu/src/bubble-menu-plugin.ts +++ b/packages/extension-bubble-menu/src/bubble-menu-plugin.ts @@ -38,6 +38,8 @@ export class BubbleMenuView { public tippy: Instance | undefined + public tippyOptions?: Partial + public shouldShow: Exclude = ({ state, from, to }) => { const { doc, selection } = state const { empty } = selection @@ -59,7 +61,7 @@ export class BubbleMenuView { editor, element, view, - tippyOptions, + tippyOptions = {}, shouldShow, }: BubbleMenuViewProps) { this.editor = editor @@ -74,13 +76,10 @@ export class BubbleMenuView { this.view.dom.addEventListener('dragstart', this.dragstartHandler) this.editor.on('focus', this.focusHandler) this.editor.on('blur', this.blurHandler) + this.tippyOptions = tippyOptions + // Detaches menu content from its current parent + this.element.remove() this.element.style.visibility = 'visible' - - // We create tippy asynchronously to make sure that `editor.options.element` - // has already been moved to the right position in the DOM - requestAnimationFrame(() => { - this.createTooltip(tippyOptions) - }) } mousedownHandler = () => { @@ -113,17 +112,26 @@ export class BubbleMenuView { this.hide() } - createTooltip(options: Partial = {}) { - this.tippy = tippy(this.editor.options.element, { - duration: 0, - getReferenceClientRect: null, - content: this.element, - interactive: true, - trigger: 'manual', - placement: 'top', - hideOnClick: 'toggle', - ...options, - }) + createTooltip() { + if (this.tippy) { + return + } + + const { element: editorElement } = this.editor.options + + // Wait until editor element is attached to the document + if (editorElement.parentElement) { + this.tippy = tippy(editorElement, { + duration: 0, + getReferenceClientRect: null, + content: this.element, + interactive: true, + trigger: 'manual', + placement: 'top', + hideOnClick: 'toggle', + ...this.tippyOptions, + }) + } } update(view: EditorView, oldState?: EditorState) { @@ -135,6 +143,8 @@ export class BubbleMenuView { return } + this.createTooltip() + // support for CellSelections const { ranges } = selection const from = Math.min(...ranges.map(range => range.$from.pos)) diff --git a/packages/extension-floating-menu/src/floating-menu-plugin.ts b/packages/extension-floating-menu/src/floating-menu-plugin.ts index c060edb9..0749d5ca 100644 --- a/packages/extension-floating-menu/src/floating-menu-plugin.ts +++ b/packages/extension-floating-menu/src/floating-menu-plugin.ts @@ -31,6 +31,8 @@ export class FloatingMenuView { public tippy: Instance | undefined + public tippyOptions?: Partial + public shouldShow: Exclude = ({ state }) => { const { selection } = state const { $anchor, empty } = selection @@ -50,7 +52,7 @@ export class FloatingMenuView { editor, element, view, - tippyOptions, + tippyOptions = {}, shouldShow, }: FloatingMenuViewProps) { this.editor = editor @@ -64,13 +66,10 @@ export class FloatingMenuView { this.element.addEventListener('mousedown', this.mousedownHandler, { capture: true }) this.editor.on('focus', this.focusHandler) this.editor.on('blur', this.blurHandler) + this.tippyOptions = tippyOptions + // Detaches menu content from its current parent + this.element.remove() this.element.style.visibility = 'visible' - - // We create tippy asynchronously to make sure that `editor.options.element` - // has already been moved to the right position in the DOM - requestAnimationFrame(() => { - this.createTooltip(tippyOptions) - }) } mousedownHandler = () => { @@ -99,17 +98,26 @@ export class FloatingMenuView { this.hide() } - createTooltip(options: Partial = {}) { - this.tippy = tippy(this.editor.options.element, { - duration: 0, - getReferenceClientRect: null, - content: this.element, - interactive: true, - trigger: 'manual', - placement: 'right', - hideOnClick: 'toggle', - ...options, - }) + createTooltip() { + if (this.tippy) { + return + } + + const { element: editorElement } = this.editor.options + + // Wait until editor element is attached to the document + if (editorElement.parentElement) { + this.tippy = tippy(editorElement, { + duration: 0, + getReferenceClientRect: null, + content: this.element, + interactive: true, + trigger: 'manual', + placement: 'right', + hideOnClick: 'toggle', + ...this.tippyOptions, + }) + } } update(view: EditorView, oldState?: EditorState) { @@ -122,6 +130,8 @@ export class FloatingMenuView { return } + this.createTooltip() + const shouldShow = this.shouldShow?.({ editor: this.editor, view,