mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-07 01:12:56 +08:00

* start experimenting with floating-ui * add options to floating-ui bubble menu plugin & fix smaller issues * add vue support for new floating-ui * start experimenting with floating-ui * adjust floating-menu plugin for floating-ui & update react component * add vue support for floating-menu with floating-ui * update tests for new floating-ui integration * added changeset file * move floating-ui dependency to peerDeps * add install notice to changelog * remove unnecessary code for destroying and removing component element in Vue suggestion.js * remove unnecessary code for destroying and removing component element in React suggestion.js * sync package-lock * widen range for peerDeps again
78 lines
1.9 KiB
TypeScript
78 lines
1.9 KiB
TypeScript
import { FloatingMenuPlugin, FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'
|
|
import React, {
|
|
useEffect, useRef,
|
|
} from 'react'
|
|
import { createPortal } from 'react-dom'
|
|
|
|
import { useCurrentEditor } from './Context.js'
|
|
|
|
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
|
|
|
|
export type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {
|
|
editor: FloatingMenuPluginProps['editor'] | null;
|
|
className?: string,
|
|
children: React.ReactNode
|
|
options?: FloatingMenuPluginProps['options']
|
|
}
|
|
|
|
export const FloatingMenu = (props: FloatingMenuProps) => {
|
|
const menuEl = useRef(document.createElement('div'))
|
|
const { editor: currentEditor } = useCurrentEditor()
|
|
|
|
useEffect(() => {
|
|
menuEl.current.style.visibility = 'hidden'
|
|
menuEl.current.style.position = 'absolute'
|
|
|
|
if (props.editor?.isDestroyed || currentEditor?.isDestroyed) {
|
|
return
|
|
}
|
|
|
|
const {
|
|
pluginKey = 'floatingMenu',
|
|
editor,
|
|
options,
|
|
shouldShow = null,
|
|
} = props
|
|
|
|
const menuEditor = editor || currentEditor
|
|
|
|
if (!menuEditor) {
|
|
console.warn('FloatingMenu component is not rendered inside of an editor component or does not have editor prop.')
|
|
return
|
|
}
|
|
|
|
const plugin = FloatingMenuPlugin({
|
|
pluginKey,
|
|
editor: menuEditor,
|
|
element: menuEl.current,
|
|
options,
|
|
shouldShow,
|
|
})
|
|
|
|
menuEditor.registerPlugin(plugin)
|
|
return () => {
|
|
menuEditor.unregisterPlugin(pluginKey)
|
|
window.requestAnimationFrame(() => {
|
|
if (menuEl.current.parentNode) {
|
|
menuEl.current.parentNode.removeChild(menuEl.current)
|
|
}
|
|
})
|
|
}
|
|
}, [
|
|
props.editor,
|
|
currentEditor,
|
|
])
|
|
|
|
const portal = createPortal(
|
|
(
|
|
<div className={props.className}>
|
|
{props.children}
|
|
</div>
|
|
), menuEl.current,
|
|
)
|
|
|
|
return (
|
|
<>{portal}</>
|
|
)
|
|
}
|