diff --git a/.changeset/twelve-turtles-cry.md b/.changeset/twelve-turtles-cry.md new file mode 100644 index 0000000000..25f800d153 --- /dev/null +++ b/.changeset/twelve-turtles-cry.md @@ -0,0 +1,8 @@ +--- +"@tiptap/extension-bubble-menu": patch +"@tiptap/react": patch +"@tiptap/vue-2": patch +"@tiptap/vue-3": patch +--- + +Added a `focusout` event listener to handle blur events on the bubble menu element, ensuring the menu closes properly when blurred. diff --git a/packages/extension-bubble-menu/src/bubble-menu-plugin.ts b/packages/extension-bubble-menu/src/bubble-menu-plugin.ts index d6d0428cf5..dc62152861 100644 --- a/packages/extension-bubble-menu/src/bubble-menu-plugin.ts +++ b/packages/extension-bubble-menu/src/bubble-menu-plugin.ts @@ -123,6 +123,7 @@ export class BubbleMenuView { } this.element.addEventListener('mousedown', this.mousedownHandler, { capture: true }) + this.element.addEventListener('focusout', this.floatingFocusoutHandler) this.view.dom.addEventListener('dragstart', this.dragstartHandler) this.editor.on('focus', this.focusHandler) this.editor.on('blur', this.blurHandler) @@ -132,6 +133,10 @@ export class BubbleMenuView { this.element.style.visibility = 'visible' } + floatingFocusoutHandler = (event: FocusEvent) => { + this.blurHandler({ event }) + } + mousedownHandler = () => { this.preventHide = true } @@ -303,6 +308,7 @@ export class BubbleMenuView { } this.tippy?.destroy() this.element.removeEventListener('mousedown', this.mousedownHandler, { capture: true }) + this.element.removeEventListener('focusout', this.floatingFocusoutHandler) this.view.dom.removeEventListener('dragstart', this.dragstartHandler) this.editor.off('focus', this.focusHandler) this.editor.off('blur', this.blurHandler) diff --git a/packages/react/src/BubbleMenu.tsx b/packages/react/src/BubbleMenu.tsx index 6628655708..0ab34330e6 100644 --- a/packages/react/src/BubbleMenu.tsx +++ b/packages/react/src/BubbleMenu.tsx @@ -50,7 +50,7 @@ export const BubbleMenu = (props: BubbleMenuProps) => { }, [props.editor, currentEditor, element]) return ( -
+
{props.children}
) diff --git a/packages/vue-2/src/BubbleMenu.ts b/packages/vue-2/src/BubbleMenu.ts index 44112e1419..181b468e9c 100644 --- a/packages/vue-2/src/BubbleMenu.ts +++ b/packages/vue-2/src/BubbleMenu.ts @@ -61,7 +61,7 @@ export const BubbleMenu: Component = { }, render(this: BubbleMenuInterface, createElement: CreateElement) { - return createElement('div', { style: { visibility: 'hidden' } }, this.$slots.default) + return createElement('div', { style: { visibility: 'hidden' }, attrs: { tabIndex: -1 } }, this.$slots.default) }, beforeDestroy(this: BubbleMenuInterface) { diff --git a/packages/vue-3/src/BubbleMenu.ts b/packages/vue-3/src/BubbleMenu.ts index 841da01391..3f7063c44b 100644 --- a/packages/vue-3/src/BubbleMenu.ts +++ b/packages/vue-3/src/BubbleMenu.ts @@ -66,6 +66,6 @@ export const BubbleMenu = defineComponent({ editor.unregisterPlugin(pluginKey) }) - return () => h('div', { ref: root }, slots.default?.()) + return () => h('div', { ref: root, tabindex: -1 }, slots.default?.()) }, })