From 7e0d145ce9c48842da700e2f4882ae7a8c926493 Mon Sep 17 00:00:00 2001 From: fantasticit Date: Mon, 9 May 2022 15:26:47 +0800 Subject: [PATCH] tiptap: fix bubble menu --- .../tiptap/core/wrappers/callout/index.tsx | 2 +- .../tiptap/editor/menus/callout/bubble.tsx | 10 +- .../tiptap/editor/menus/code-block/bubble.tsx | 8 +- .../src/tiptap/editor/menus/image/bubble.tsx | 9 +- .../src/tiptap/editor/menus/mind/bubble.tsx | 9 +- .../src/tiptap/editor/menus/table/bubble.tsx | 3 +- .../src/tiptap/editor/views/float-menu.tsx | 173 ------------------ 7 files changed, 33 insertions(+), 181 deletions(-) delete mode 100644 packages/client/src/tiptap/editor/views/float-menu.tsx diff --git a/packages/client/src/tiptap/core/wrappers/callout/index.tsx b/packages/client/src/tiptap/core/wrappers/callout/index.tsx index cd3661e7..19be6bbe 100644 --- a/packages/client/src/tiptap/core/wrappers/callout/index.tsx +++ b/packages/client/src/tiptap/core/wrappers/callout/index.tsx @@ -16,7 +16,7 @@ export const CalloutWrapper = ({ editor, node, updateAttributes }) => { ); return ( - +
= ({ editor }) => { editor.isActive(Callout.name)} - matchRenderContainer={(node) => node && node.id === 'js-bannber-container'} + getRenderContainer={(node) => { + let container = node; + while (container && container.id !== 'js-callout-container') { + container = container.parentElement; + } + return container; + }} > diff --git a/packages/client/src/tiptap/editor/menus/code-block/bubble.tsx b/packages/client/src/tiptap/editor/menus/code-block/bubble.tsx index 4ab1c0db..5ea40a46 100644 --- a/packages/client/src/tiptap/editor/menus/code-block/bubble.tsx +++ b/packages/client/src/tiptap/editor/menus/code-block/bubble.tsx @@ -18,7 +18,13 @@ export const CodeBlockBubbleMenu = ({ editor }) => { pluginKey="code-block-bubble-menu" shouldShow={() => editor.isActive(CodeBlock.name)} tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }} - matchRenderContainer={(node: HTMLElement) => node && node.classList && node.classList.contains('node-codeBlock')} + getRenderContainer={(node) => { + let container = node; + while (container && container.classList && !container.classList.contains('node-codeBlock')) { + container = container.parentElement; + } + return container; + }} > diff --git a/packages/client/src/tiptap/editor/menus/image/bubble.tsx b/packages/client/src/tiptap/editor/menus/image/bubble.tsx index caa4998e..7f11ee9e 100644 --- a/packages/client/src/tiptap/editor/menus/image/bubble.tsx +++ b/packages/client/src/tiptap/editor/menus/image/bubble.tsx @@ -79,7 +79,14 @@ export const ImageBubbleMenu = ({ editor }) => { tippyOptions={{ maxWidth: 'calc(100vw - 100px)', }} - matchRenderContainer={(node) => node && node.id === 'js-resizeable-container'} + getRenderContainer={(node) => { + try { + const inner = node.querySelector('#js-resizeable-container'); + return inner as HTMLElement; + } catch (e) { + return node; + } + }} > diff --git a/packages/client/src/tiptap/editor/menus/mind/bubble.tsx b/packages/client/src/tiptap/editor/menus/mind/bubble.tsx index 83a9a3c0..4599d51e 100644 --- a/packages/client/src/tiptap/editor/menus/mind/bubble.tsx +++ b/packages/client/src/tiptap/editor/menus/mind/bubble.tsx @@ -30,7 +30,14 @@ export const MindBubbleMenu = ({ editor }) => { pluginKey="mind-bubble-menu" shouldShow={() => editor.isActive(Mind.name)} tippyOptions={{ maxWidth: 'calc(100vw - 100px)' }} - matchRenderContainer={(node) => node && node.id === 'js-resizeable-container'} + getRenderContainer={(node) => { + try { + const inner = node.querySelector('#js-resizeable-container'); + return inner as HTMLElement; + } catch (e) { + return node; + } + }} > diff --git a/packages/client/src/tiptap/editor/menus/table/bubble.tsx b/packages/client/src/tiptap/editor/menus/table/bubble.tsx index ca07752d..c9e8a18b 100644 --- a/packages/client/src/tiptap/editor/menus/table/bubble.tsx +++ b/packages/client/src/tiptap/editor/menus/table/bubble.tsx @@ -46,7 +46,6 @@ export const TableBubbleMenu = ({ editor }) => { tippyOptions={{ maxWidth: 'calc(100vw - 100px)', placement: 'bottom', - offset: [0, 20], }} shouldShow={() => { return editor.isActive(Table.name); @@ -56,7 +55,7 @@ export const TableBubbleMenu = ({ editor }) => { while (container.tagName !== 'TABLE') { container = container.parentElement; } - return container; + return container.parentElement; }} > diff --git a/packages/client/src/tiptap/editor/views/float-menu.tsx b/packages/client/src/tiptap/editor/views/float-menu.tsx deleted file mode 100644 index 02a4810e..00000000 --- a/packages/client/src/tiptap/editor/views/float-menu.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { Editor, isNodeSelection, posToDOMRect, Range } from '@tiptap/core'; -import tippy, { Instance, Props } from 'tippy.js'; -import { EditorView } from 'prosemirror-view'; -import { EditorState } from 'prosemirror-state'; - -export type FloatMenuViewOptions = { - editor: Editor; - getReferenceClientRect?: (props: { editor: Editor; range: Range; oldState?: EditorState }) => DOMRect; - shouldShow: (props: { editor: Editor; range: Range; oldState?: EditorState }, instance: FloatMenuView) => boolean; - init: (dom: HTMLElement, editor: Editor) => void; - update?: ( - dom: HTMLElement, - props: { - editor: Editor; - oldState?: EditorState; - range: Range; - show: () => void; - hide: () => void; - } - ) => void; - tippyOptions?: Partial; -}; - -export class FloatMenuView { - public editor: Editor; - public parentNode: null | HTMLElement; - public container: null | HTMLElement; - private dom: HTMLElement; - private popup: Instance; - private _update: FloatMenuViewOptions['update']; - private shouldShow: FloatMenuViewOptions['shouldShow']; - private tippyOptions: FloatMenuViewOptions['tippyOptions']; - private getReferenceClientRect: NonNullable = ({ editor, range }) => { - const { view, state } = editor; - if (this.parentNode) { - return this.parentNode.getBoundingClientRect(); - } - if (isNodeSelection(state.selection)) { - const node = view.nodeDOM(range.from) as HTMLElement; - - if (node) { - return node.getBoundingClientRect(); - } - } - - const rangeRect = posToDOMRect(view, range.from, range.to); - - if (this.container) { - const containerRect = this.container.getBoundingClientRect(); - - if (rangeRect.width > containerRect.width) { - return containerRect; - } - } - - return rangeRect; - }; - - constructor(props: FloatMenuViewOptions) { - this.editor = props.editor; - this.shouldShow = props.shouldShow; - this.tippyOptions = props.tippyOptions || {}; - if (props.getReferenceClientRect) { - this.getReferenceClientRect = props.getReferenceClientRect; - } - this._update = props.update; - this.dom = document.createElement('div'); - - // init - props.init(this.dom, this.editor); - - // popup - this.createPopup(); - } - - setConatiner(el) { - this.container = el; - // this.popup?.setProps({ - // appendTo: el, - // }); - // this.popup?. - } - - createPopup() { - const { element: editorElement } = this.editor.options; - const editorIsAttached = !!editorElement.parentElement; - - if (this.popup || !editorIsAttached) { - return; - } - - this.popup = tippy(editorElement, { - getReferenceClientRect: null, - content: this.dom, - interactive: true, - trigger: 'manual', - placement: 'top', - hideOnClick: 'toggle', - ...Object.assign({ zIndex: 99 }, this.tippyOptions), - }); - } - - public update(view: EditorView, oldState?: EditorState) { - const { state, composing } = view; - const { doc, selection } = state; - const isSame = oldState && oldState.doc.eq(doc) && oldState.selection.eq(selection); - - if (composing || isSame) { - return; - } - - this.createPopup(); - - const { ranges } = selection; - const from = Math.min(...ranges.map((range) => range.$from.pos)); - const to = Math.max(...ranges.map((range) => range.$to.pos)); - - const shouldShow = this.shouldShow?.( - { - editor: this.editor, - oldState, - range: { - from, - to, - }, - }, - this - ); - - if (!shouldShow) { - this.hide(); - return; - } - - this._update?.(this.dom, { - editor: this.editor, - oldState, - range: { - from, - to, - }, - show: this.show.bind(this), - hide: this.hide.bind(this), - }); - - this.popup.setProps({ - getReferenceClientRect: () => { - return this.getReferenceClientRect({ - editor: this.editor, - oldState, - range: { - from, - to, - }, - }); - }, - }); - - this.show(); - } - - show() { - this.popup?.show(); - } - - hide() { - this.popup?.hide(); - } - - public destroy() { - this.popup?.destroy(); - } -}