Sign In

@tiptap/react

Package Overview
Dependencies
Maintainers
6
Versions
409
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tiptap/react - npm Package Compare versions

Comparing version
3.23.6
to
3.24.0
+36
-12
dist/index.cjs

@@ -340,3 +340,5 @@ "use strict";

if (immediatelyRender && isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
console.warn(
"SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches"
);
}

@@ -600,4 +602,11 @@ immediatelyRender = false;

});
var ReactNodeViewContentProvider = ({ children, content }) => {
return (0, import_react5.createElement)(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children);
var ReactNodeViewContentProvider = ({
children,
content
}) => {
return (0, import_react5.createElement)(
ReactNodeViewContext.Provider,
{ value: { nodeViewContentChildren: content } },
children
);
};

@@ -824,3 +833,6 @@ var useReactNodeView = () => (0, import_react5.useContext)(ReactNodeViewContext);

const { as = "span", attrs, className = "" } = options || {};
const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) };
const componentProps = {
...props,
updateAttributes: this.updateAttributes.bind(this)
};
this.contentDOMElement = document.createElement("span");

@@ -835,5 +847,7 @@ const markViewContentRef = (el) => {

};
const ReactMarkViewProvider = import_react8.default.memo((componentProps2) => {
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ReactMarkViewContext.Provider, { value: context, children: import_react8.default.createElement(component, componentProps2) });
});
const ReactMarkViewProvider = import_react8.default.memo(
(componentProps2) => {
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ReactMarkViewContext.Provider, { value: context, children: import_react8.default.createElement(component, componentProps2) });
}
);
ReactMarkViewProvider.displayName = "ReactMarkView";

@@ -965,5 +979,7 @@ this.renderer = new ReactRenderer(ReactMarkViewProvider, {

const Component = this.component;
const ReactNodeViewProvider = (0, import_react9.memo)((componentProps) => {
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ReactNodeViewContext.Provider, { value: context, children: (0, import_react9.createElement)(Component, componentProps) });
});
const ReactNodeViewProvider = (0, import_react9.memo)(
(componentProps) => {
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ReactNodeViewContext.Provider, { value: context, children: (0, import_react9.createElement)(Component, componentProps) });
}
);
ReactNodeViewProvider.displayName = "ReactNodeView";

@@ -1070,3 +1086,8 @@ let as = this.node.isInline ? "span" : "div";

innerDecorations,
updateProps: () => rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage })
updateProps: () => rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage
})
});

@@ -1183,3 +1204,6 @@ }

}
const tiptapContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]);
const tiptapContextValue = (0, import_react10.useMemo)(
() => ({ editor: resolvedEditor }),
[resolvedEditor]
);
const legacyContextValue = (0, import_react10.useMemo)(() => ({ editor: resolvedEditor }), [resolvedEditor]);

@@ -1186,0 +1210,0 @@ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EditorContext.Provider, { value: legacyContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TiptapContext.Provider, { value: tiptapContextValue, children }) });

@@ -550,3 +550,3 @@ import * as react_jsx_runtime from 'react/jsx-runtime';

declare const ReactNodeViewContext: React.Context<ReactNodeViewContextProps>;
declare const ReactNodeViewContentProvider: ({ children, content }: {
declare const ReactNodeViewContentProvider: ({ children, content, }: {
children: ReactNode;

@@ -553,0 +553,0 @@ content: ReactNode;

@@ -550,3 +550,3 @@ import * as react_jsx_runtime from 'react/jsx-runtime';

declare const ReactNodeViewContext: React.Context<ReactNodeViewContextProps>;
declare const ReactNodeViewContentProvider: ({ children, content }: {
declare const ReactNodeViewContentProvider: ({ children, content, }: {
children: ReactNode;

@@ -553,0 +553,0 @@ content: ReactNode;

@@ -278,3 +278,5 @@ // src/Context.tsx

if (immediatelyRender && isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
console.warn(
"SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches"
);
}

@@ -538,4 +540,11 @@ immediatelyRender = false;

});
var ReactNodeViewContentProvider = ({ children, content }) => {
return createElement(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children);
var ReactNodeViewContentProvider = ({
children,
content
}) => {
return createElement(
ReactNodeViewContext.Provider,
{ value: { nodeViewContentChildren: content } },
children
);
};

@@ -762,3 +771,6 @@ var useReactNodeView = () => useContext2(ReactNodeViewContext);

const { as = "span", attrs, className = "" } = options || {};
const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) };
const componentProps = {
...props,
updateAttributes: this.updateAttributes.bind(this)
};
this.contentDOMElement = document.createElement("span");

@@ -773,5 +785,7 @@ const markViewContentRef = (el) => {

};
const ReactMarkViewProvider = React4.memo((componentProps2) => {
return /* @__PURE__ */ jsx6(ReactMarkViewContext.Provider, { value: context, children: React4.createElement(component, componentProps2) });
});
const ReactMarkViewProvider = React4.memo(
(componentProps2) => {
return /* @__PURE__ */ jsx6(ReactMarkViewContext.Provider, { value: context, children: React4.createElement(component, componentProps2) });
}
);
ReactMarkViewProvider.displayName = "ReactMarkView";

@@ -903,5 +917,7 @@ this.renderer = new ReactRenderer(ReactMarkViewProvider, {

const Component = this.component;
const ReactNodeViewProvider = memo((componentProps) => {
return /* @__PURE__ */ jsx7(ReactNodeViewContext.Provider, { value: context, children: createElement2(Component, componentProps) });
});
const ReactNodeViewProvider = memo(
(componentProps) => {
return /* @__PURE__ */ jsx7(ReactNodeViewContext.Provider, { value: context, children: createElement2(Component, componentProps) });
}
);
ReactNodeViewProvider.displayName = "ReactNodeView";

@@ -1008,3 +1024,8 @@ let as = this.node.isInline ? "span" : "div";

innerDecorations,
updateProps: () => rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage })
updateProps: () => rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage
})
});

@@ -1121,3 +1142,6 @@ }

}
const tiptapContextValue = useMemo2(() => ({ editor: resolvedEditor }), [resolvedEditor]);
const tiptapContextValue = useMemo2(
() => ({ editor: resolvedEditor }),
[resolvedEditor]
);
const legacyContextValue = useMemo2(() => ({ editor: resolvedEditor }), [resolvedEditor]);

@@ -1124,0 +1148,0 @@ return /* @__PURE__ */ jsx8(EditorContext.Provider, { value: legacyContextValue, children: /* @__PURE__ */ jsx8(TiptapContext.Provider, { value: tiptapContextValue, children }) });

@@ -53,3 +53,10 @@ "use strict";

var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
var PLUGIN_MANAGED_STYLE_PROPERTIES = /* @__PURE__ */ new Set(["left", "opacity", "position", "top", "visibility", "width"]);
var PLUGIN_MANAGED_STYLE_PROPERTIES = /* @__PURE__ */ new Set([
"left",
"opacity",
"position",
"top",
"visibility",
"width"
]);
var UNITLESS_STYLE_PROPERTIES = /* @__PURE__ */ new Set([

@@ -335,3 +342,5 @@ "animationIterationCount",

const menuEl = (0, import_react3.useRef)(document.createElement("div"));
const resolvedPluginKey = (0, import_react3.useRef)(getAutoPluginKey(pluginKey, "bubbleMenu")).current;
const resolvedPluginKey = (0, import_react3.useRef)(
getAutoPluginKey(pluginKey, "bubbleMenu")
).current;
useMenuElementProps(menuEl.current, restProps);

@@ -363,3 +372,5 @@ if (typeof ref === "function") {

if (!pluginEditor) {
console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop.");
console.warn(
"BubbleMenu component is not rendered inside of an editor component or does not have editor prop."
);
return;

@@ -424,5 +435,17 @@ }

var FloatingMenu = import_react5.default.forwardRef(
({ pluginKey, editor, updateDelay, resizeDelay, appendTo, shouldShow = null, options, children, ...restProps }, ref) => {
({
pluginKey,
editor,
updateDelay,
resizeDelay,
appendTo,
shouldShow = null,
options,
children,
...restProps
}, ref) => {
const menuEl = (0, import_react5.useRef)(document.createElement("div"));
const resolvedPluginKey = (0, import_react5.useRef)(getAutoPluginKey(pluginKey, "floatingMenu")).current;
const resolvedPluginKey = (0, import_react5.useRef)(
getAutoPluginKey(pluginKey, "floatingMenu")
).current;
useMenuElementProps(menuEl.current, restProps);

@@ -494,3 +517,12 @@ if (typeof ref === "function") {

);
}, [pluginInitialized, pluginEditor, updateDelay, resizeDelay, shouldShow, options, appendTo, resolvedPluginKey]);
}, [
pluginInitialized,
pluginEditor,
updateDelay,
resizeDelay,
shouldShow,
options,
appendTo,
resolvedPluginKey
]);
return (0, import_react_dom2.createPortal)(children, menuEl.current);

@@ -497,0 +529,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/menus/index.ts","../../src/menus/BubbleMenu.tsx","../../src/menus/getAutoPluginKey.ts","../../src/menus/useMenuElementProps.ts","../../src/menus/FloatingMenu.tsx"],"sourcesContent":["export * from './BubbleMenu.js'\nexport * from './FloatingMenu.js'\n","import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type BubbleMenuProps = Optional<Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>, 'editor'> &\n React.HTMLAttributes<HTMLDivElement>\n\nexport const BubbleMenu = React.forwardRef<HTMLDivElement, BubbleMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n getReferencedVirtualElement,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'bubbleMenu')).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the bubble menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const bubbleMenuPluginProps: Omit<BubbleMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n getReferencedVirtualElement,\n options,\n }\n /**\n * The props for the bubble menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const bubbleMenuPluginPropsRef = useRef(bubbleMenuPluginProps)\n bubbleMenuPluginPropsRef.current = bubbleMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.')\n return\n }\n\n const bubbleMenuElement = menuEl.current\n bubbleMenuElement.style.visibility = 'hidden'\n bubbleMenuElement.style.position = 'absolute'\n\n const plugin = BubbleMenuPlugin({\n ...bubbleMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: bubbleMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = bubbleMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (bubbleMenuElement.parentNode) {\n bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: bubbleMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n getReferencedVirtualElement,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n","import { PluginKey } from '@tiptap/pm/state'\n\nexport function getAutoPluginKey(pluginKey: PluginKey | string | undefined, defaultName: string) {\n return pluginKey ?? new PluginKey(defaultName)\n}\n","import type { CSSProperties, HTMLAttributes } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\ntype MenuElementProps = HTMLAttributes<HTMLDivElement>\ntype MenuSyntheticEvent = Event & {\n nativeEvent: Event\n currentTarget: HTMLDivElement\n target: EventTarget | null\n persist: () => void\n isDefaultPrevented: () => boolean\n isPropagationStopped: () => boolean\n}\ntype MenuEventListener = (event: MenuSyntheticEvent) => void\ntype MenuNativeListener = (event: Event) => void\ntype MenuEventListenerOptions = {\n capture?: boolean\n}\n\ntype EventListenerEntry = {\n eventName: string\n listener: MenuNativeListener\n options?: MenuEventListenerOptions\n}\n\nconst PLUGIN_MANAGED_STYLE_PROPERTIES = new Set(['left', 'opacity', 'position', 'top', 'visibility', 'width'])\nconst UNITLESS_STYLE_PROPERTIES = new Set([\n 'animationIterationCount',\n 'aspectRatio',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'columnCount',\n 'columns',\n 'fillOpacity',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridArea',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'scale',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n])\nconst ATTRIBUTE_EXCLUSIONS = new Set(['children', 'className', 'style'])\nconst DIRECT_PROPERTY_KEYS = new Set(['tabIndex'])\nconst FORWARDED_ATTRIBUTE_KEYS = new Set([\n 'accessKey',\n 'autoCapitalize',\n 'contentEditable',\n 'contextMenu',\n 'dir',\n 'draggable',\n 'enterKeyHint',\n 'hidden',\n 'id',\n 'lang',\n 'nonce',\n 'role',\n 'slot',\n 'spellCheck',\n 'tabIndex',\n 'title',\n 'translate',\n])\nconst SPECIAL_EVENT_NAMES: Record<string, string> = {\n Blur: 'focusout',\n DoubleClick: 'dblclick',\n Focus: 'focusin',\n MouseEnter: 'mouseenter',\n MouseLeave: 'mouseleave',\n}\n\nfunction isEventProp(key: string, value: unknown): value is MenuEventListener {\n return /^on[A-Z]/.test(key) && typeof value === 'function'\n}\n\nfunction toAttributeName(key: string) {\n if (key.startsWith('aria-') || key.startsWith('data-')) {\n return key\n }\n\n return key\n}\n\nfunction isForwardedAttributeKey(key: string) {\n return key.startsWith('aria-') || key.startsWith('data-') || FORWARDED_ATTRIBUTE_KEYS.has(key)\n}\n\nfunction toStylePropertyName(key: string) {\n if (key.startsWith('--')) {\n return key\n }\n\n return key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)\n}\n\nfunction toEventConfig(key: string) {\n const useCapture = key.endsWith('Capture')\n const baseKey = useCapture ? key.slice(0, -7) : key\n const reactEventName = baseKey.slice(2)\n const eventName = SPECIAL_EVENT_NAMES[reactEventName] ?? reactEventName.toLowerCase()\n\n return {\n eventName,\n options: useCapture ? { capture: true } : undefined,\n }\n}\n\nfunction createSyntheticEvent(element: HTMLDivElement, nativeEvent: Event): MenuSyntheticEvent {\n let defaultPrevented = nativeEvent.defaultPrevented\n let propagationStopped = false\n const syntheticEvent = Object.create(nativeEvent)\n\n Object.defineProperties(syntheticEvent, {\n nativeEvent: { value: nativeEvent },\n currentTarget: { value: element },\n target: { value: nativeEvent.target },\n persist: { value: () => undefined },\n isDefaultPrevented: { value: () => defaultPrevented },\n isPropagationStopped: { value: () => propagationStopped },\n preventDefault: {\n value: () => {\n defaultPrevented = true\n nativeEvent.preventDefault()\n },\n },\n stopPropagation: {\n value: () => {\n propagationStopped = true\n nativeEvent.stopPropagation()\n },\n },\n })\n\n return syntheticEvent as MenuSyntheticEvent\n}\n\nfunction isDirectPropertyKey(key: string) {\n return DIRECT_PROPERTY_KEYS.has(key)\n}\n\nfunction setDirectProperty(element: HTMLDivElement, key: string, value: unknown) {\n if (key === 'tabIndex') {\n element.tabIndex = Number(value)\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = value\n}\n\nfunction clearDirectProperty(element: HTMLDivElement, key: string) {\n if (key === 'tabIndex') {\n element.removeAttribute('tabindex')\n return\n }\n\n const propertyValue = (element as unknown as Record<string, unknown>)[key]\n\n if (typeof propertyValue === 'boolean') {\n ;(element as unknown as Record<string, unknown>)[key] = false\n return\n }\n\n if (typeof propertyValue === 'number') {\n ;(element as unknown as Record<string, unknown>)[key] = 0\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = ''\n}\n\nfunction toStyleValue(styleName: string, value: string | number) {\n if (\n typeof value !== 'number' ||\n value === 0 ||\n styleName.startsWith('--') ||\n UNITLESS_STYLE_PROPERTIES.has(styleName)\n ) {\n return String(value)\n }\n\n return `${value}px`\n}\n\nfunction removeStyleProperty(element: HTMLDivElement, styleName: string) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.removeProperty(toStylePropertyName(styleName))\n}\n\nfunction applyStyleProperty(element: HTMLDivElement, styleName: string, value: string | number) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.setProperty(toStylePropertyName(styleName), toStyleValue(styleName, value))\n}\n\nfunction syncAttributes(element: HTMLDivElement, prevProps: MenuElementProps, nextProps: MenuElementProps) {\n const allKeys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)])\n\n allKeys.forEach(key => {\n if (\n ATTRIBUTE_EXCLUSIONS.has(key) ||\n !isForwardedAttributeKey(key) ||\n isEventProp(key, prevProps[key as keyof MenuElementProps]) ||\n isEventProp(key, nextProps[key as keyof MenuElementProps])\n ) {\n return\n }\n\n const prevValue = prevProps[key as keyof MenuElementProps]\n const nextValue = nextProps[key as keyof MenuElementProps]\n\n if (prevValue === nextValue) {\n return\n }\n\n const attributeName = toAttributeName(key)\n\n if (nextValue == null || nextValue === false) {\n if (isDirectPropertyKey(key)) {\n clearDirectProperty(element, key)\n }\n\n element.removeAttribute(attributeName)\n return\n }\n\n if (nextValue === true) {\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, true)\n }\n\n element.setAttribute(attributeName, '')\n return\n }\n\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, nextValue)\n return\n }\n\n element.setAttribute(attributeName, String(nextValue))\n })\n}\n\nfunction syncClassName(element: HTMLDivElement, prevClassName?: string, nextClassName?: string) {\n if (prevClassName === nextClassName) {\n return\n }\n\n if (nextClassName) {\n element.className = nextClassName\n return\n }\n\n element.removeAttribute('class')\n}\n\nfunction syncStyles(\n element: HTMLDivElement,\n prevStyle: CSSProperties | undefined,\n nextStyle: CSSProperties | undefined,\n) {\n const previousStyle = prevStyle ?? {}\n const currentStyle = nextStyle ?? {}\n const allStyleNames = new Set([...Object.keys(previousStyle), ...Object.keys(currentStyle)])\n\n allStyleNames.forEach(styleName => {\n const prevValue = previousStyle[styleName as keyof CSSProperties]\n const nextValue = currentStyle[styleName as keyof CSSProperties]\n\n if (prevValue === nextValue) {\n return\n }\n\n if (nextValue == null) {\n removeStyleProperty(element, styleName)\n return\n }\n\n applyStyleProperty(element, styleName, nextValue as string | number)\n })\n}\n\nfunction syncEventListeners(element: HTMLDivElement, prevListeners: EventListenerEntry[], nextProps: MenuElementProps) {\n prevListeners.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n\n const nextListeners: EventListenerEntry[] = []\n\n Object.entries(nextProps).forEach(([key, value]) => {\n if (!isEventProp(key, value)) {\n return\n }\n\n const { eventName, options } = toEventConfig(key)\n const listener: MenuNativeListener = event => {\n value(createSyntheticEvent(element, event))\n }\n\n element.addEventListener(eventName, listener, options)\n nextListeners.push({ eventName, listener, options })\n })\n\n return nextListeners\n}\n\nexport function useMenuElementProps(element: HTMLDivElement, props: MenuElementProps) {\n const previousPropsRef = useRef<MenuElementProps>({})\n const listenersRef = useRef<EventListenerEntry[]>([])\n\n useIsomorphicLayoutEffect(() => {\n const previousProps = previousPropsRef.current\n\n syncClassName(element, previousProps.className, props.className)\n syncStyles(element, previousProps.style, props.style)\n syncAttributes(element, previousProps, props)\n listenersRef.current = syncEventListeners(element, listenersRef.current, props)\n previousPropsRef.current = props\n\n return () => {\n listenersRef.current.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n listenersRef.current = []\n }\n }, [element, props])\n}\n","import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'\nimport { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {\n editor: FloatingMenuPluginProps['editor'] | null\n options?: FloatingMenuPluginProps['options']\n} & React.HTMLAttributes<HTMLDivElement>\n\nexport const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(\n (\n { pluginKey, editor, updateDelay, resizeDelay, appendTo, shouldShow = null, options, children, ...restProps },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'floatingMenu')).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the floating menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const floatingMenuPluginProps: Omit<FloatingMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n options,\n }\n\n /**\n * The props for the floating menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const floatingMenuPluginPropsRef = useRef(floatingMenuPluginProps)\n floatingMenuPluginPropsRef.current = floatingMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const floatingMenuElement = menuEl.current\n floatingMenuElement.style.visibility = 'hidden'\n floatingMenuElement.style.position = 'absolute'\n\n const plugin = FloatingMenuPlugin({\n ...floatingMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: floatingMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = floatingMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (floatingMenuElement.parentNode) {\n floatingMenuElement.parentNode.removeChild(floatingMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: floatingMenuPluginPropsRef.current,\n }),\n )\n }, [pluginInitialized, pluginEditor, updateDelay, resizeDelay, shouldShow, options, appendTo, resolvedPluginKey])\n\n return createPortal(children, menuEl.current)\n },\n)\n"],"mappings":"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","names":["import_react","React","import_react","import_react_dom","React"]}
{"version":3,"sources":["../../src/menus/index.ts","../../src/menus/BubbleMenu.tsx","../../src/menus/getAutoPluginKey.ts","../../src/menus/useMenuElementProps.ts","../../src/menus/FloatingMenu.tsx"],"sourcesContent":["export * from './BubbleMenu.js'\nexport * from './FloatingMenu.js'\n","import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type BubbleMenuProps = Optional<\n Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>,\n 'editor'\n> &\n React.HTMLAttributes<HTMLDivElement>\n\nexport const BubbleMenu = React.forwardRef<HTMLDivElement, BubbleMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n getReferencedVirtualElement,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(\n getAutoPluginKey(pluginKey, 'bubbleMenu'),\n ).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the bubble menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const bubbleMenuPluginProps: Omit<BubbleMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n getReferencedVirtualElement,\n options,\n }\n /**\n * The props for the bubble menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const bubbleMenuPluginPropsRef = useRef(bubbleMenuPluginProps)\n bubbleMenuPluginPropsRef.current = bubbleMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'BubbleMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const bubbleMenuElement = menuEl.current\n bubbleMenuElement.style.visibility = 'hidden'\n bubbleMenuElement.style.position = 'absolute'\n\n const plugin = BubbleMenuPlugin({\n ...bubbleMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: bubbleMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = bubbleMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (bubbleMenuElement.parentNode) {\n bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: bubbleMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n getReferencedVirtualElement,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n","import { PluginKey } from '@tiptap/pm/state'\n\nexport function getAutoPluginKey(pluginKey: PluginKey | string | undefined, defaultName: string) {\n return pluginKey ?? new PluginKey(defaultName)\n}\n","import type { CSSProperties, HTMLAttributes } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\ntype MenuElementProps = HTMLAttributes<HTMLDivElement>\ntype MenuSyntheticEvent = Event & {\n nativeEvent: Event\n currentTarget: HTMLDivElement\n target: EventTarget | null\n persist: () => void\n isDefaultPrevented: () => boolean\n isPropagationStopped: () => boolean\n}\ntype MenuEventListener = (event: MenuSyntheticEvent) => void\ntype MenuNativeListener = (event: Event) => void\ntype MenuEventListenerOptions = {\n capture?: boolean\n}\n\ntype EventListenerEntry = {\n eventName: string\n listener: MenuNativeListener\n options?: MenuEventListenerOptions\n}\n\nconst PLUGIN_MANAGED_STYLE_PROPERTIES = new Set([\n 'left',\n 'opacity',\n 'position',\n 'top',\n 'visibility',\n 'width',\n])\nconst UNITLESS_STYLE_PROPERTIES = new Set([\n 'animationIterationCount',\n 'aspectRatio',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'columnCount',\n 'columns',\n 'fillOpacity',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridArea',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'scale',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n])\nconst ATTRIBUTE_EXCLUSIONS = new Set(['children', 'className', 'style'])\nconst DIRECT_PROPERTY_KEYS = new Set(['tabIndex'])\nconst FORWARDED_ATTRIBUTE_KEYS = new Set([\n 'accessKey',\n 'autoCapitalize',\n 'contentEditable',\n 'contextMenu',\n 'dir',\n 'draggable',\n 'enterKeyHint',\n 'hidden',\n 'id',\n 'lang',\n 'nonce',\n 'role',\n 'slot',\n 'spellCheck',\n 'tabIndex',\n 'title',\n 'translate',\n])\nconst SPECIAL_EVENT_NAMES: Record<string, string> = {\n Blur: 'focusout',\n DoubleClick: 'dblclick',\n Focus: 'focusin',\n MouseEnter: 'mouseenter',\n MouseLeave: 'mouseleave',\n}\n\nfunction isEventProp(key: string, value: unknown): value is MenuEventListener {\n return /^on[A-Z]/.test(key) && typeof value === 'function'\n}\n\nfunction toAttributeName(key: string) {\n if (key.startsWith('aria-') || key.startsWith('data-')) {\n return key\n }\n\n return key\n}\n\nfunction isForwardedAttributeKey(key: string) {\n return key.startsWith('aria-') || key.startsWith('data-') || FORWARDED_ATTRIBUTE_KEYS.has(key)\n}\n\nfunction toStylePropertyName(key: string) {\n if (key.startsWith('--')) {\n return key\n }\n\n return key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)\n}\n\nfunction toEventConfig(key: string) {\n const useCapture = key.endsWith('Capture')\n const baseKey = useCapture ? key.slice(0, -7) : key\n const reactEventName = baseKey.slice(2)\n const eventName = SPECIAL_EVENT_NAMES[reactEventName] ?? reactEventName.toLowerCase()\n\n return {\n eventName,\n options: useCapture ? { capture: true } : undefined,\n }\n}\n\nfunction createSyntheticEvent(element: HTMLDivElement, nativeEvent: Event): MenuSyntheticEvent {\n let defaultPrevented = nativeEvent.defaultPrevented\n let propagationStopped = false\n const syntheticEvent = Object.create(nativeEvent)\n\n Object.defineProperties(syntheticEvent, {\n nativeEvent: { value: nativeEvent },\n currentTarget: { value: element },\n target: { value: nativeEvent.target },\n persist: { value: () => undefined },\n isDefaultPrevented: { value: () => defaultPrevented },\n isPropagationStopped: { value: () => propagationStopped },\n preventDefault: {\n value: () => {\n defaultPrevented = true\n nativeEvent.preventDefault()\n },\n },\n stopPropagation: {\n value: () => {\n propagationStopped = true\n nativeEvent.stopPropagation()\n },\n },\n })\n\n return syntheticEvent as MenuSyntheticEvent\n}\n\nfunction isDirectPropertyKey(key: string) {\n return DIRECT_PROPERTY_KEYS.has(key)\n}\n\nfunction setDirectProperty(element: HTMLDivElement, key: string, value: unknown) {\n if (key === 'tabIndex') {\n element.tabIndex = Number(value)\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = value\n}\n\nfunction clearDirectProperty(element: HTMLDivElement, key: string) {\n if (key === 'tabIndex') {\n element.removeAttribute('tabindex')\n return\n }\n\n const propertyValue = (element as unknown as Record<string, unknown>)[key]\n\n if (typeof propertyValue === 'boolean') {\n ;(element as unknown as Record<string, unknown>)[key] = false\n return\n }\n\n if (typeof propertyValue === 'number') {\n ;(element as unknown as Record<string, unknown>)[key] = 0\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = ''\n}\n\nfunction toStyleValue(styleName: string, value: string | number) {\n if (\n typeof value !== 'number' ||\n value === 0 ||\n styleName.startsWith('--') ||\n UNITLESS_STYLE_PROPERTIES.has(styleName)\n ) {\n return String(value)\n }\n\n return `${value}px`\n}\n\nfunction removeStyleProperty(element: HTMLDivElement, styleName: string) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.removeProperty(toStylePropertyName(styleName))\n}\n\nfunction applyStyleProperty(element: HTMLDivElement, styleName: string, value: string | number) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.setProperty(toStylePropertyName(styleName), toStyleValue(styleName, value))\n}\n\nfunction syncAttributes(\n element: HTMLDivElement,\n prevProps: MenuElementProps,\n nextProps: MenuElementProps,\n) {\n const allKeys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)])\n\n allKeys.forEach(key => {\n if (\n ATTRIBUTE_EXCLUSIONS.has(key) ||\n !isForwardedAttributeKey(key) ||\n isEventProp(key, prevProps[key as keyof MenuElementProps]) ||\n isEventProp(key, nextProps[key as keyof MenuElementProps])\n ) {\n return\n }\n\n const prevValue = prevProps[key as keyof MenuElementProps]\n const nextValue = nextProps[key as keyof MenuElementProps]\n\n if (prevValue === nextValue) {\n return\n }\n\n const attributeName = toAttributeName(key)\n\n if (nextValue == null || nextValue === false) {\n if (isDirectPropertyKey(key)) {\n clearDirectProperty(element, key)\n }\n\n element.removeAttribute(attributeName)\n return\n }\n\n if (nextValue === true) {\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, true)\n }\n\n element.setAttribute(attributeName, '')\n return\n }\n\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, nextValue)\n return\n }\n\n element.setAttribute(attributeName, String(nextValue))\n })\n}\n\nfunction syncClassName(element: HTMLDivElement, prevClassName?: string, nextClassName?: string) {\n if (prevClassName === nextClassName) {\n return\n }\n\n if (nextClassName) {\n element.className = nextClassName\n return\n }\n\n element.removeAttribute('class')\n}\n\nfunction syncStyles(\n element: HTMLDivElement,\n prevStyle: CSSProperties | undefined,\n nextStyle: CSSProperties | undefined,\n) {\n const previousStyle = prevStyle ?? {}\n const currentStyle = nextStyle ?? {}\n const allStyleNames = new Set([...Object.keys(previousStyle), ...Object.keys(currentStyle)])\n\n allStyleNames.forEach(styleName => {\n const prevValue = previousStyle[styleName as keyof CSSProperties]\n const nextValue = currentStyle[styleName as keyof CSSProperties]\n\n if (prevValue === nextValue) {\n return\n }\n\n if (nextValue == null) {\n removeStyleProperty(element, styleName)\n return\n }\n\n applyStyleProperty(element, styleName, nextValue as string | number)\n })\n}\n\nfunction syncEventListeners(\n element: HTMLDivElement,\n prevListeners: EventListenerEntry[],\n nextProps: MenuElementProps,\n) {\n prevListeners.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n\n const nextListeners: EventListenerEntry[] = []\n\n Object.entries(nextProps).forEach(([key, value]) => {\n if (!isEventProp(key, value)) {\n return\n }\n\n const { eventName, options } = toEventConfig(key)\n const listener: MenuNativeListener = event => {\n value(createSyntheticEvent(element, event))\n }\n\n element.addEventListener(eventName, listener, options)\n nextListeners.push({ eventName, listener, options })\n })\n\n return nextListeners\n}\n\nexport function useMenuElementProps(element: HTMLDivElement, props: MenuElementProps) {\n const previousPropsRef = useRef<MenuElementProps>({})\n const listenersRef = useRef<EventListenerEntry[]>([])\n\n useIsomorphicLayoutEffect(() => {\n const previousProps = previousPropsRef.current\n\n syncClassName(element, previousProps.className, props.className)\n syncStyles(element, previousProps.style, props.style)\n syncAttributes(element, previousProps, props)\n listenersRef.current = syncEventListeners(element, listenersRef.current, props)\n previousPropsRef.current = props\n\n return () => {\n listenersRef.current.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n listenersRef.current = []\n }\n }, [element, props])\n}\n","import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'\nimport { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type FloatingMenuProps = Omit<\n Optional<FloatingMenuPluginProps, 'pluginKey'>,\n 'element' | 'editor'\n> & {\n editor: FloatingMenuPluginProps['editor'] | null\n options?: FloatingMenuPluginProps['options']\n} & React.HTMLAttributes<HTMLDivElement>\n\nexport const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(\n getAutoPluginKey(pluginKey, 'floatingMenu'),\n ).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the floating menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const floatingMenuPluginProps: Omit<FloatingMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n options,\n }\n\n /**\n * The props for the floating menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const floatingMenuPluginPropsRef = useRef(floatingMenuPluginProps)\n floatingMenuPluginPropsRef.current = floatingMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const floatingMenuElement = menuEl.current\n floatingMenuElement.style.visibility = 'hidden'\n floatingMenuElement.style.position = 'absolute'\n\n const plugin = FloatingMenuPlugin({\n ...floatingMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: floatingMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = floatingMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (floatingMenuElement.parentNode) {\n floatingMenuElement.parentNode.removeChild(floatingMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: floatingMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n"],"mappings":"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","names":["import_react","React","import_react","import_react_dom","React"]}

@@ -16,3 +16,10 @@ // src/menus/BubbleMenu.tsx

var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
var PLUGIN_MANAGED_STYLE_PROPERTIES = /* @__PURE__ */ new Set(["left", "opacity", "position", "top", "visibility", "width"]);
var PLUGIN_MANAGED_STYLE_PROPERTIES = /* @__PURE__ */ new Set([
"left",
"opacity",
"position",
"top",
"visibility",
"width"
]);
var UNITLESS_STYLE_PROPERTIES = /* @__PURE__ */ new Set([

@@ -298,3 +305,5 @@ "animationIterationCount",

const menuEl = useRef2(document.createElement("div"));
const resolvedPluginKey = useRef2(getAutoPluginKey(pluginKey, "bubbleMenu")).current;
const resolvedPluginKey = useRef2(
getAutoPluginKey(pluginKey, "bubbleMenu")
).current;
useMenuElementProps(menuEl.current, restProps);

@@ -326,3 +335,5 @@ if (typeof ref === "function") {

if (!pluginEditor) {
console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop.");
console.warn(
"BubbleMenu component is not rendered inside of an editor component or does not have editor prop."
);
return;

@@ -387,5 +398,17 @@ }

var FloatingMenu = React2.forwardRef(
({ pluginKey, editor, updateDelay, resizeDelay, appendTo, shouldShow = null, options, children, ...restProps }, ref) => {
({
pluginKey,
editor,
updateDelay,
resizeDelay,
appendTo,
shouldShow = null,
options,
children,
...restProps
}, ref) => {
const menuEl = useRef3(document.createElement("div"));
const resolvedPluginKey = useRef3(getAutoPluginKey(pluginKey, "floatingMenu")).current;
const resolvedPluginKey = useRef3(
getAutoPluginKey(pluginKey, "floatingMenu")
).current;
useMenuElementProps(menuEl.current, restProps);

@@ -457,3 +480,12 @@ if (typeof ref === "function") {

);
}, [pluginInitialized, pluginEditor, updateDelay, resizeDelay, shouldShow, options, appendTo, resolvedPluginKey]);
}, [
pluginInitialized,
pluginEditor,
updateDelay,
resizeDelay,
shouldShow,
options,
appendTo,
resolvedPluginKey
]);
return createPortal2(children, menuEl.current);

@@ -460,0 +492,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/menus/BubbleMenu.tsx","../../src/menus/getAutoPluginKey.ts","../../src/menus/useMenuElementProps.ts","../../src/menus/FloatingMenu.tsx"],"sourcesContent":["import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type BubbleMenuProps = Optional<Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>, 'editor'> &\n React.HTMLAttributes<HTMLDivElement>\n\nexport const BubbleMenu = React.forwardRef<HTMLDivElement, BubbleMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n getReferencedVirtualElement,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'bubbleMenu')).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the bubble menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const bubbleMenuPluginProps: Omit<BubbleMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n getReferencedVirtualElement,\n options,\n }\n /**\n * The props for the bubble menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const bubbleMenuPluginPropsRef = useRef(bubbleMenuPluginProps)\n bubbleMenuPluginPropsRef.current = bubbleMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.')\n return\n }\n\n const bubbleMenuElement = menuEl.current\n bubbleMenuElement.style.visibility = 'hidden'\n bubbleMenuElement.style.position = 'absolute'\n\n const plugin = BubbleMenuPlugin({\n ...bubbleMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: bubbleMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = bubbleMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (bubbleMenuElement.parentNode) {\n bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: bubbleMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n getReferencedVirtualElement,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n","import { PluginKey } from '@tiptap/pm/state'\n\nexport function getAutoPluginKey(pluginKey: PluginKey | string | undefined, defaultName: string) {\n return pluginKey ?? new PluginKey(defaultName)\n}\n","import type { CSSProperties, HTMLAttributes } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\ntype MenuElementProps = HTMLAttributes<HTMLDivElement>\ntype MenuSyntheticEvent = Event & {\n nativeEvent: Event\n currentTarget: HTMLDivElement\n target: EventTarget | null\n persist: () => void\n isDefaultPrevented: () => boolean\n isPropagationStopped: () => boolean\n}\ntype MenuEventListener = (event: MenuSyntheticEvent) => void\ntype MenuNativeListener = (event: Event) => void\ntype MenuEventListenerOptions = {\n capture?: boolean\n}\n\ntype EventListenerEntry = {\n eventName: string\n listener: MenuNativeListener\n options?: MenuEventListenerOptions\n}\n\nconst PLUGIN_MANAGED_STYLE_PROPERTIES = new Set(['left', 'opacity', 'position', 'top', 'visibility', 'width'])\nconst UNITLESS_STYLE_PROPERTIES = new Set([\n 'animationIterationCount',\n 'aspectRatio',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'columnCount',\n 'columns',\n 'fillOpacity',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridArea',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'scale',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n])\nconst ATTRIBUTE_EXCLUSIONS = new Set(['children', 'className', 'style'])\nconst DIRECT_PROPERTY_KEYS = new Set(['tabIndex'])\nconst FORWARDED_ATTRIBUTE_KEYS = new Set([\n 'accessKey',\n 'autoCapitalize',\n 'contentEditable',\n 'contextMenu',\n 'dir',\n 'draggable',\n 'enterKeyHint',\n 'hidden',\n 'id',\n 'lang',\n 'nonce',\n 'role',\n 'slot',\n 'spellCheck',\n 'tabIndex',\n 'title',\n 'translate',\n])\nconst SPECIAL_EVENT_NAMES: Record<string, string> = {\n Blur: 'focusout',\n DoubleClick: 'dblclick',\n Focus: 'focusin',\n MouseEnter: 'mouseenter',\n MouseLeave: 'mouseleave',\n}\n\nfunction isEventProp(key: string, value: unknown): value is MenuEventListener {\n return /^on[A-Z]/.test(key) && typeof value === 'function'\n}\n\nfunction toAttributeName(key: string) {\n if (key.startsWith('aria-') || key.startsWith('data-')) {\n return key\n }\n\n return key\n}\n\nfunction isForwardedAttributeKey(key: string) {\n return key.startsWith('aria-') || key.startsWith('data-') || FORWARDED_ATTRIBUTE_KEYS.has(key)\n}\n\nfunction toStylePropertyName(key: string) {\n if (key.startsWith('--')) {\n return key\n }\n\n return key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)\n}\n\nfunction toEventConfig(key: string) {\n const useCapture = key.endsWith('Capture')\n const baseKey = useCapture ? key.slice(0, -7) : key\n const reactEventName = baseKey.slice(2)\n const eventName = SPECIAL_EVENT_NAMES[reactEventName] ?? reactEventName.toLowerCase()\n\n return {\n eventName,\n options: useCapture ? { capture: true } : undefined,\n }\n}\n\nfunction createSyntheticEvent(element: HTMLDivElement, nativeEvent: Event): MenuSyntheticEvent {\n let defaultPrevented = nativeEvent.defaultPrevented\n let propagationStopped = false\n const syntheticEvent = Object.create(nativeEvent)\n\n Object.defineProperties(syntheticEvent, {\n nativeEvent: { value: nativeEvent },\n currentTarget: { value: element },\n target: { value: nativeEvent.target },\n persist: { value: () => undefined },\n isDefaultPrevented: { value: () => defaultPrevented },\n isPropagationStopped: { value: () => propagationStopped },\n preventDefault: {\n value: () => {\n defaultPrevented = true\n nativeEvent.preventDefault()\n },\n },\n stopPropagation: {\n value: () => {\n propagationStopped = true\n nativeEvent.stopPropagation()\n },\n },\n })\n\n return syntheticEvent as MenuSyntheticEvent\n}\n\nfunction isDirectPropertyKey(key: string) {\n return DIRECT_PROPERTY_KEYS.has(key)\n}\n\nfunction setDirectProperty(element: HTMLDivElement, key: string, value: unknown) {\n if (key === 'tabIndex') {\n element.tabIndex = Number(value)\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = value\n}\n\nfunction clearDirectProperty(element: HTMLDivElement, key: string) {\n if (key === 'tabIndex') {\n element.removeAttribute('tabindex')\n return\n }\n\n const propertyValue = (element as unknown as Record<string, unknown>)[key]\n\n if (typeof propertyValue === 'boolean') {\n ;(element as unknown as Record<string, unknown>)[key] = false\n return\n }\n\n if (typeof propertyValue === 'number') {\n ;(element as unknown as Record<string, unknown>)[key] = 0\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = ''\n}\n\nfunction toStyleValue(styleName: string, value: string | number) {\n if (\n typeof value !== 'number' ||\n value === 0 ||\n styleName.startsWith('--') ||\n UNITLESS_STYLE_PROPERTIES.has(styleName)\n ) {\n return String(value)\n }\n\n return `${value}px`\n}\n\nfunction removeStyleProperty(element: HTMLDivElement, styleName: string) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.removeProperty(toStylePropertyName(styleName))\n}\n\nfunction applyStyleProperty(element: HTMLDivElement, styleName: string, value: string | number) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.setProperty(toStylePropertyName(styleName), toStyleValue(styleName, value))\n}\n\nfunction syncAttributes(element: HTMLDivElement, prevProps: MenuElementProps, nextProps: MenuElementProps) {\n const allKeys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)])\n\n allKeys.forEach(key => {\n if (\n ATTRIBUTE_EXCLUSIONS.has(key) ||\n !isForwardedAttributeKey(key) ||\n isEventProp(key, prevProps[key as keyof MenuElementProps]) ||\n isEventProp(key, nextProps[key as keyof MenuElementProps])\n ) {\n return\n }\n\n const prevValue = prevProps[key as keyof MenuElementProps]\n const nextValue = nextProps[key as keyof MenuElementProps]\n\n if (prevValue === nextValue) {\n return\n }\n\n const attributeName = toAttributeName(key)\n\n if (nextValue == null || nextValue === false) {\n if (isDirectPropertyKey(key)) {\n clearDirectProperty(element, key)\n }\n\n element.removeAttribute(attributeName)\n return\n }\n\n if (nextValue === true) {\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, true)\n }\n\n element.setAttribute(attributeName, '')\n return\n }\n\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, nextValue)\n return\n }\n\n element.setAttribute(attributeName, String(nextValue))\n })\n}\n\nfunction syncClassName(element: HTMLDivElement, prevClassName?: string, nextClassName?: string) {\n if (prevClassName === nextClassName) {\n return\n }\n\n if (nextClassName) {\n element.className = nextClassName\n return\n }\n\n element.removeAttribute('class')\n}\n\nfunction syncStyles(\n element: HTMLDivElement,\n prevStyle: CSSProperties | undefined,\n nextStyle: CSSProperties | undefined,\n) {\n const previousStyle = prevStyle ?? {}\n const currentStyle = nextStyle ?? {}\n const allStyleNames = new Set([...Object.keys(previousStyle), ...Object.keys(currentStyle)])\n\n allStyleNames.forEach(styleName => {\n const prevValue = previousStyle[styleName as keyof CSSProperties]\n const nextValue = currentStyle[styleName as keyof CSSProperties]\n\n if (prevValue === nextValue) {\n return\n }\n\n if (nextValue == null) {\n removeStyleProperty(element, styleName)\n return\n }\n\n applyStyleProperty(element, styleName, nextValue as string | number)\n })\n}\n\nfunction syncEventListeners(element: HTMLDivElement, prevListeners: EventListenerEntry[], nextProps: MenuElementProps) {\n prevListeners.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n\n const nextListeners: EventListenerEntry[] = []\n\n Object.entries(nextProps).forEach(([key, value]) => {\n if (!isEventProp(key, value)) {\n return\n }\n\n const { eventName, options } = toEventConfig(key)\n const listener: MenuNativeListener = event => {\n value(createSyntheticEvent(element, event))\n }\n\n element.addEventListener(eventName, listener, options)\n nextListeners.push({ eventName, listener, options })\n })\n\n return nextListeners\n}\n\nexport function useMenuElementProps(element: HTMLDivElement, props: MenuElementProps) {\n const previousPropsRef = useRef<MenuElementProps>({})\n const listenersRef = useRef<EventListenerEntry[]>([])\n\n useIsomorphicLayoutEffect(() => {\n const previousProps = previousPropsRef.current\n\n syncClassName(element, previousProps.className, props.className)\n syncStyles(element, previousProps.style, props.style)\n syncAttributes(element, previousProps, props)\n listenersRef.current = syncEventListeners(element, listenersRef.current, props)\n previousPropsRef.current = props\n\n return () => {\n listenersRef.current.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n listenersRef.current = []\n }\n }, [element, props])\n}\n","import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'\nimport { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {\n editor: FloatingMenuPluginProps['editor'] | null\n options?: FloatingMenuPluginProps['options']\n} & React.HTMLAttributes<HTMLDivElement>\n\nexport const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(\n (\n { pluginKey, editor, updateDelay, resizeDelay, appendTo, shouldShow = null, options, children, ...restProps },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'floatingMenu')).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the floating menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const floatingMenuPluginProps: Omit<FloatingMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n options,\n }\n\n /**\n * The props for the floating menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const floatingMenuPluginPropsRef = useRef(floatingMenuPluginProps)\n floatingMenuPluginPropsRef.current = floatingMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const floatingMenuElement = menuEl.current\n floatingMenuElement.style.visibility = 'hidden'\n floatingMenuElement.style.position = 'absolute'\n\n const plugin = FloatingMenuPlugin({\n ...floatingMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: floatingMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = floatingMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (floatingMenuElement.parentNode) {\n floatingMenuElement.parentNode.removeChild(floatingMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: floatingMenuPluginPropsRef.current,\n }),\n )\n }, [pluginInitialized, pluginEditor, updateDelay, resizeDelay, shouldShow, options, appendTo, resolvedPluginKey])\n\n return createPortal(children, menuEl.current)\n },\n)\n"],"mappings":";AAAA,SAAqC,wBAAwB;AAE7D,SAAS,wBAAwB;AACjC,OAAO,SAAS,aAAAA,YAAW,UAAAC,SAAQ,gBAAgB;AACnD,SAAS,oBAAoB;;;ACJ7B,SAAS,iBAAiB;AAEnB,SAAS,iBAAiB,WAA2C,aAAqB;AAC/F,SAAO,gCAAa,IAAI,UAAU,WAAW;AAC/C;;;ACHA,SAAS,WAAW,iBAAiB,cAAc;AAEnD,IAAM,4BAA4B,OAAO,WAAW,cAAc,kBAAkB;AAuBpF,IAAM,kCAAkC,oBAAI,IAAI,CAAC,QAAQ,WAAW,YAAY,OAAO,cAAc,OAAO,CAAC;AAC7G,IAAM,4BAA4B,oBAAI,IAAI;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,uBAAuB,oBAAI,IAAI,CAAC,YAAY,aAAa,OAAO,CAAC;AACvE,IAAM,uBAAuB,oBAAI,IAAI,CAAC,UAAU,CAAC;AACjD,IAAM,2BAA2B,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,sBAA8C;AAAA,EAClD,MAAM;AAAA,EACN,aAAa;AAAA,EACb,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,YAAY;AACd;AAEA,SAAS,YAAY,KAAa,OAA4C;AAC5E,SAAO,WAAW,KAAK,GAAG,KAAK,OAAO,UAAU;AAClD;AAEA,SAAS,gBAAgB,KAAa;AACpC,MAAI,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,OAAO,GAAG;AACtD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,wBAAwB,KAAa;AAC5C,SAAO,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,OAAO,KAAK,yBAAyB,IAAI,GAAG;AAC/F;AAEA,SAAS,oBAAoB,KAAa;AACxC,MAAI,IAAI,WAAW,IAAI,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,QAAQ,UAAU,WAAS,IAAI,MAAM,YAAY,CAAC,EAAE;AACjE;AAEA,SAAS,cAAc,KAAa;AArHpC;AAsHE,QAAM,aAAa,IAAI,SAAS,SAAS;AACzC,QAAM,UAAU,aAAa,IAAI,MAAM,GAAG,EAAE,IAAI;AAChD,QAAM,iBAAiB,QAAQ,MAAM,CAAC;AACtC,QAAM,aAAY,yBAAoB,cAAc,MAAlC,YAAuC,eAAe,YAAY;AAEpF,SAAO;AAAA,IACL;AAAA,IACA,SAAS,aAAa,EAAE,SAAS,KAAK,IAAI;AAAA,EAC5C;AACF;AAEA,SAAS,qBAAqB,SAAyB,aAAwC;AAC7F,MAAI,mBAAmB,YAAY;AACnC,MAAI,qBAAqB;AACzB,QAAM,iBAAiB,OAAO,OAAO,WAAW;AAEhD,SAAO,iBAAiB,gBAAgB;AAAA,IACtC,aAAa,EAAE,OAAO,YAAY;AAAA,IAClC,eAAe,EAAE,OAAO,QAAQ;AAAA,IAChC,QAAQ,EAAE,OAAO,YAAY,OAAO;AAAA,IACpC,SAAS,EAAE,OAAO,MAAM,OAAU;AAAA,IAClC,oBAAoB,EAAE,OAAO,MAAM,iBAAiB;AAAA,IACpD,sBAAsB,EAAE,OAAO,MAAM,mBAAmB;AAAA,IACxD,gBAAgB;AAAA,MACd,OAAO,MAAM;AACX,2BAAmB;AACnB,oBAAY,eAAe;AAAA,MAC7B;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,OAAO,MAAM;AACX,6BAAqB;AACrB,oBAAY,gBAAgB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAa;AACxC,SAAO,qBAAqB,IAAI,GAAG;AACrC;AAEA,SAAS,kBAAkB,SAAyB,KAAa,OAAgB;AAC/E,MAAI,QAAQ,YAAY;AACtB,YAAQ,WAAW,OAAO,KAAK;AAC/B;AAAA,EACF;AAEA;AAAC,EAAC,QAA+C,GAAG,IAAI;AAC1D;AAEA,SAAS,oBAAoB,SAAyB,KAAa;AACjE,MAAI,QAAQ,YAAY;AACtB,YAAQ,gBAAgB,UAAU;AAClC;AAAA,EACF;AAEA,QAAM,gBAAiB,QAA+C,GAAG;AAEzE,MAAI,OAAO,kBAAkB,WAAW;AACtC;AAAC,IAAC,QAA+C,GAAG,IAAI;AACxD;AAAA,EACF;AAEA,MAAI,OAAO,kBAAkB,UAAU;AACrC;AAAC,IAAC,QAA+C,GAAG,IAAI;AACxD;AAAA,EACF;AAEA;AAAC,EAAC,QAA+C,GAAG,IAAI;AAC1D;AAEA,SAAS,aAAa,WAAmB,OAAwB;AAC/D,MACE,OAAO,UAAU,YACjB,UAAU,KACV,UAAU,WAAW,IAAI,KACzB,0BAA0B,IAAI,SAAS,GACvC;AACA,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,SAAO,GAAG,KAAK;AACjB;AAEA,SAAS,oBAAoB,SAAyB,WAAmB;AACvE,MAAI,gCAAgC,IAAI,SAAS,GAAG;AAClD;AAAA,EACF;AAEA,UAAQ,MAAM,eAAe,oBAAoB,SAAS,CAAC;AAC7D;AAEA,SAAS,mBAAmB,SAAyB,WAAmB,OAAwB;AAC9F,MAAI,gCAAgC,IAAI,SAAS,GAAG;AAClD;AAAA,EACF;AAEA,UAAQ,MAAM,YAAY,oBAAoB,SAAS,GAAG,aAAa,WAAW,KAAK,CAAC;AAC1F;AAEA,SAAS,eAAe,SAAyB,WAA6B,WAA6B;AACzG,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,SAAS,GAAG,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC;AAE9E,UAAQ,QAAQ,SAAO;AACrB,QACE,qBAAqB,IAAI,GAAG,KAC5B,CAAC,wBAAwB,GAAG,KAC5B,YAAY,KAAK,UAAU,GAA6B,CAAC,KACzD,YAAY,KAAK,UAAU,GAA6B,CAAC,GACzD;AACA;AAAA,IACF;AAEA,UAAM,YAAY,UAAU,GAA6B;AACzD,UAAM,YAAY,UAAU,GAA6B;AAEzD,QAAI,cAAc,WAAW;AAC3B;AAAA,IACF;AAEA,UAAM,gBAAgB,gBAAgB,GAAG;AAEzC,QAAI,aAAa,QAAQ,cAAc,OAAO;AAC5C,UAAI,oBAAoB,GAAG,GAAG;AAC5B,4BAAoB,SAAS,GAAG;AAAA,MAClC;AAEA,cAAQ,gBAAgB,aAAa;AACrC;AAAA,IACF;AAEA,QAAI,cAAc,MAAM;AACtB,UAAI,oBAAoB,GAAG,GAAG;AAC5B,0BAAkB,SAAS,KAAK,IAAI;AAAA,MACtC;AAEA,cAAQ,aAAa,eAAe,EAAE;AACtC;AAAA,IACF;AAEA,QAAI,oBAAoB,GAAG,GAAG;AAC5B,wBAAkB,SAAS,KAAK,SAAS;AACzC;AAAA,IACF;AAEA,YAAQ,aAAa,eAAe,OAAO,SAAS,CAAC;AAAA,EACvD,CAAC;AACH;AAEA,SAAS,cAAc,SAAyB,eAAwB,eAAwB;AAC9F,MAAI,kBAAkB,eAAe;AACnC;AAAA,EACF;AAEA,MAAI,eAAe;AACjB,YAAQ,YAAY;AACpB;AAAA,EACF;AAEA,UAAQ,gBAAgB,OAAO;AACjC;AAEA,SAAS,WACP,SACA,WACA,WACA;AACA,QAAM,gBAAgB,gCAAa,CAAC;AACpC,QAAM,eAAe,gCAAa,CAAC;AACnC,QAAM,gBAAgB,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,aAAa,GAAG,GAAG,OAAO,KAAK,YAAY,CAAC,CAAC;AAE3F,gBAAc,QAAQ,eAAa;AACjC,UAAM,YAAY,cAAc,SAAgC;AAChE,UAAM,YAAY,aAAa,SAAgC;AAE/D,QAAI,cAAc,WAAW;AAC3B;AAAA,IACF;AAEA,QAAI,aAAa,MAAM;AACrB,0BAAoB,SAAS,SAAS;AACtC;AAAA,IACF;AAEA,uBAAmB,SAAS,WAAW,SAA4B;AAAA,EACrE,CAAC;AACH;AAEA,SAAS,mBAAmB,SAAyB,eAAqC,WAA6B;AACrH,gBAAc,QAAQ,CAAC,EAAE,WAAW,UAAU,QAAQ,MAAM;AAC1D,YAAQ,oBAAoB,WAAW,UAAU,OAAO;AAAA,EAC1D,CAAC;AAED,QAAM,gBAAsC,CAAC;AAE7C,SAAO,QAAQ,SAAS,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAClD,QAAI,CAAC,YAAY,KAAK,KAAK,GAAG;AAC5B;AAAA,IACF;AAEA,UAAM,EAAE,WAAW,QAAQ,IAAI,cAAc,GAAG;AAChD,UAAM,WAA+B,WAAS;AAC5C,YAAM,qBAAqB,SAAS,KAAK,CAAC;AAAA,IAC5C;AAEA,YAAQ,iBAAiB,WAAW,UAAU,OAAO;AACrD,kBAAc,KAAK,EAAE,WAAW,UAAU,QAAQ,CAAC;AAAA,EACrD,CAAC;AAED,SAAO;AACT;AAEO,SAAS,oBAAoB,SAAyB,OAAyB;AACpF,QAAM,mBAAmB,OAAyB,CAAC,CAAC;AACpD,QAAM,eAAe,OAA6B,CAAC,CAAC;AAEpD,4BAA0B,MAAM;AAC9B,UAAM,gBAAgB,iBAAiB;AAEvC,kBAAc,SAAS,cAAc,WAAW,MAAM,SAAS;AAC/D,eAAW,SAAS,cAAc,OAAO,MAAM,KAAK;AACpD,mBAAe,SAAS,eAAe,KAAK;AAC5C,iBAAa,UAAU,mBAAmB,SAAS,aAAa,SAAS,KAAK;AAC9E,qBAAiB,UAAU;AAE3B,WAAO,MAAM;AACX,mBAAa,QAAQ,QAAQ,CAAC,EAAE,WAAW,UAAU,QAAQ,MAAM;AACjE,gBAAQ,oBAAoB,WAAW,UAAU,OAAO;AAAA,MAC1D,CAAC;AACD,mBAAa,UAAU,CAAC;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,SAAS,KAAK,CAAC;AACrB;;;AFnVO,IAAM,aAAa,MAAM;AAAA,EAC9B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,SAASC,QAAO,SAAS,cAAc,KAAK,CAAC;AACnD,UAAM,oBAAoBA,QAA2B,iBAAiB,WAAW,YAAY,CAAC,EAAE;AAEhG,wBAAoB,OAAO,SAAS,SAAS;AAE7C,QAAI,OAAO,QAAQ,YAAY;AAC7B,UAAI,OAAO,OAAO;AAAA,IACpB,WAAW,KAAK;AACd,UAAI,UAAU,OAAO;AAAA,IACvB;AAEA,UAAM,EAAE,QAAQ,cAAc,IAAI,iBAAiB;AAKnD,UAAM,eAAe,UAAU;AAI/B,UAAM,wBAA2E;AAAA,MAC/E;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAMA,UAAM,2BAA2BA,QAAO,qBAAqB;AAC7D,6BAAyB,UAAU;AAMnC,UAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAMhE,UAAM,qBAAqBA,QAAO,IAAI;AAEtC,IAAAC,WAAU,MAAM;AACd,UAAI,6CAAc,aAAa;AAC7B;AAAA,MACF;AAEA,UAAI,CAAC,cAAc;AACjB,gBAAQ,KAAK,kGAAkG;AAC/G;AAAA,MACF;AAEA,YAAM,oBAAoB,OAAO;AACjC,wBAAkB,MAAM,aAAa;AACrC,wBAAkB,MAAM,WAAW;AAEnC,YAAM,SAAS,iBAAiB;AAAA,QAC9B,GAAG,yBAAyB;AAAA,QAC5B,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC;AAED,mBAAa,eAAe,MAAM;AAElC,YAAM,mBAAmB,yBAAyB,QAAQ;AAE1D,yBAAmB,UAAU;AAC7B,2BAAqB,IAAI;AAEzB,aAAO,MAAM;AACX,6BAAqB,KAAK;AAC1B,qBAAa,iBAAiB,gBAAgB;AAC9C,eAAO,sBAAsB,MAAM;AACjC,cAAI,kBAAkB,YAAY;AAChC,8BAAkB,WAAW,YAAY,iBAAiB;AAAA,UAC5D;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,GAAG,CAAC,YAAY,CAAC;AAMjB,IAAAA,WAAU,MAAM;AACd,UAAI,CAAC,qBAAqB,CAAC,gBAAgB,aAAa,aAAa;AACnE;AAAA,MACF;AAGA,UAAI,mBAAmB,SAAS;AAC9B,2BAAmB,UAAU;AAC7B;AAAA,MACF;AAEA,mBAAa,KAAK;AAAA,QAChB,aAAa,MAAM,GAAG,QAAQ,mBAAmB;AAAA,UAC/C,MAAM;AAAA,UACN,SAAS,yBAAyB;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,IACF,GAAG;AAAA,MACD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,aAAa,UAAU,OAAO,OAAO;AAAA,EAC9C;AACF;;;AGvJA,SAAS,0BAA0B;AAEnC,SAAS,oBAAAC,yBAAwB;AACjC,OAAOC,UAAS,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AACnD,SAAS,gBAAAC,qBAAoB;AAYtB,IAAM,eAAeC,OAAM;AAAA,EAChC,CACE,EAAE,WAAW,QAAQ,aAAa,aAAa,UAAU,aAAa,MAAM,SAAS,UAAU,GAAG,UAAU,GAC5G,QACG;AACH,UAAM,SAASC,QAAO,SAAS,cAAc,KAAK,CAAC;AACnD,UAAM,oBAAoBA,QAA2B,iBAAiB,WAAW,cAAc,CAAC,EAAE;AAElG,wBAAoB,OAAO,SAAS,SAAS;AAE7C,QAAI,OAAO,QAAQ,YAAY;AAC7B,UAAI,OAAO,OAAO;AAAA,IACpB,WAAW,KAAK;AACd,UAAI,UAAU,OAAO;AAAA,IACvB;AAEA,UAAM,EAAE,QAAQ,cAAc,IAAIC,kBAAiB;AAKnD,UAAM,eAAe,UAAU;AAI/B,UAAM,0BAA+E;AAAA,MACnF;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAOA,UAAM,6BAA6BD,QAAO,uBAAuB;AACjE,+BAA2B,UAAU;AAMrC,UAAM,CAAC,mBAAmB,oBAAoB,IAAIE,UAAS,KAAK;AAMhE,UAAM,qBAAqBF,QAAO,IAAI;AAEtC,IAAAG,WAAU,MAAM;AACd,UAAI,6CAAc,aAAa;AAC7B;AAAA,MACF;AAEA,UAAI,CAAC,cAAc;AACjB,gBAAQ;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,sBAAsB,OAAO;AACnC,0BAAoB,MAAM,aAAa;AACvC,0BAAoB,MAAM,WAAW;AAErC,YAAM,SAAS,mBAAmB;AAAA,QAChC,GAAG,2BAA2B;AAAA,QAC9B,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC;AAED,mBAAa,eAAe,MAAM;AAElC,YAAM,mBAAmB,2BAA2B,QAAQ;AAE5D,yBAAmB,UAAU;AAC7B,2BAAqB,IAAI;AAEzB,aAAO,MAAM;AACX,6BAAqB,KAAK;AAC1B,qBAAa,iBAAiB,gBAAgB;AAC9C,eAAO,sBAAsB,MAAM;AACjC,cAAI,oBAAoB,YAAY;AAClC,gCAAoB,WAAW,YAAY,mBAAmB;AAAA,UAChE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,GAAG,CAAC,YAAY,CAAC;AAMjB,IAAAA,WAAU,MAAM;AACd,UAAI,CAAC,qBAAqB,CAAC,gBAAgB,aAAa,aAAa;AACnE;AAAA,MACF;AAGA,UAAI,mBAAmB,SAAS;AAC9B,2BAAmB,UAAU;AAC7B;AAAA,MACF;AAEA,mBAAa,KAAK;AAAA,QAChB,aAAa,MAAM,GAAG,QAAQ,mBAAmB;AAAA,UAC/C,MAAM;AAAA,UACN,SAAS,2BAA2B;AAAA,QACtC,CAAC;AAAA,MACH;AAAA,IACF,GAAG,CAAC,mBAAmB,cAAc,aAAa,aAAa,YAAY,SAAS,UAAU,iBAAiB,CAAC;AAEhH,WAAOC,cAAa,UAAU,OAAO,OAAO;AAAA,EAC9C;AACF;","names":["useEffect","useRef","useRef","useEffect","useCurrentEditor","React","useEffect","useRef","useState","createPortal","React","useRef","useCurrentEditor","useState","useEffect","createPortal"]}
{"version":3,"sources":["../../src/menus/BubbleMenu.tsx","../../src/menus/getAutoPluginKey.ts","../../src/menus/useMenuElementProps.ts","../../src/menus/FloatingMenu.tsx"],"sourcesContent":["import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type BubbleMenuProps = Optional<\n Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>,\n 'editor'\n> &\n React.HTMLAttributes<HTMLDivElement>\n\nexport const BubbleMenu = React.forwardRef<HTMLDivElement, BubbleMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n getReferencedVirtualElement,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(\n getAutoPluginKey(pluginKey, 'bubbleMenu'),\n ).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the bubble menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const bubbleMenuPluginProps: Omit<BubbleMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n getReferencedVirtualElement,\n options,\n }\n /**\n * The props for the bubble menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const bubbleMenuPluginPropsRef = useRef(bubbleMenuPluginProps)\n bubbleMenuPluginPropsRef.current = bubbleMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'BubbleMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const bubbleMenuElement = menuEl.current\n bubbleMenuElement.style.visibility = 'hidden'\n bubbleMenuElement.style.position = 'absolute'\n\n const plugin = BubbleMenuPlugin({\n ...bubbleMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: bubbleMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = bubbleMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (bubbleMenuElement.parentNode) {\n bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: bubbleMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n getReferencedVirtualElement,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n","import { PluginKey } from '@tiptap/pm/state'\n\nexport function getAutoPluginKey(pluginKey: PluginKey | string | undefined, defaultName: string) {\n return pluginKey ?? new PluginKey(defaultName)\n}\n","import type { CSSProperties, HTMLAttributes } from 'react'\nimport { useEffect, useLayoutEffect, useRef } from 'react'\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\ntype MenuElementProps = HTMLAttributes<HTMLDivElement>\ntype MenuSyntheticEvent = Event & {\n nativeEvent: Event\n currentTarget: HTMLDivElement\n target: EventTarget | null\n persist: () => void\n isDefaultPrevented: () => boolean\n isPropagationStopped: () => boolean\n}\ntype MenuEventListener = (event: MenuSyntheticEvent) => void\ntype MenuNativeListener = (event: Event) => void\ntype MenuEventListenerOptions = {\n capture?: boolean\n}\n\ntype EventListenerEntry = {\n eventName: string\n listener: MenuNativeListener\n options?: MenuEventListenerOptions\n}\n\nconst PLUGIN_MANAGED_STYLE_PROPERTIES = new Set([\n 'left',\n 'opacity',\n 'position',\n 'top',\n 'visibility',\n 'width',\n])\nconst UNITLESS_STYLE_PROPERTIES = new Set([\n 'animationIterationCount',\n 'aspectRatio',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'columnCount',\n 'columns',\n 'fillOpacity',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridArea',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowStart',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'scale',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n])\nconst ATTRIBUTE_EXCLUSIONS = new Set(['children', 'className', 'style'])\nconst DIRECT_PROPERTY_KEYS = new Set(['tabIndex'])\nconst FORWARDED_ATTRIBUTE_KEYS = new Set([\n 'accessKey',\n 'autoCapitalize',\n 'contentEditable',\n 'contextMenu',\n 'dir',\n 'draggable',\n 'enterKeyHint',\n 'hidden',\n 'id',\n 'lang',\n 'nonce',\n 'role',\n 'slot',\n 'spellCheck',\n 'tabIndex',\n 'title',\n 'translate',\n])\nconst SPECIAL_EVENT_NAMES: Record<string, string> = {\n Blur: 'focusout',\n DoubleClick: 'dblclick',\n Focus: 'focusin',\n MouseEnter: 'mouseenter',\n MouseLeave: 'mouseleave',\n}\n\nfunction isEventProp(key: string, value: unknown): value is MenuEventListener {\n return /^on[A-Z]/.test(key) && typeof value === 'function'\n}\n\nfunction toAttributeName(key: string) {\n if (key.startsWith('aria-') || key.startsWith('data-')) {\n return key\n }\n\n return key\n}\n\nfunction isForwardedAttributeKey(key: string) {\n return key.startsWith('aria-') || key.startsWith('data-') || FORWARDED_ATTRIBUTE_KEYS.has(key)\n}\n\nfunction toStylePropertyName(key: string) {\n if (key.startsWith('--')) {\n return key\n }\n\n return key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)\n}\n\nfunction toEventConfig(key: string) {\n const useCapture = key.endsWith('Capture')\n const baseKey = useCapture ? key.slice(0, -7) : key\n const reactEventName = baseKey.slice(2)\n const eventName = SPECIAL_EVENT_NAMES[reactEventName] ?? reactEventName.toLowerCase()\n\n return {\n eventName,\n options: useCapture ? { capture: true } : undefined,\n }\n}\n\nfunction createSyntheticEvent(element: HTMLDivElement, nativeEvent: Event): MenuSyntheticEvent {\n let defaultPrevented = nativeEvent.defaultPrevented\n let propagationStopped = false\n const syntheticEvent = Object.create(nativeEvent)\n\n Object.defineProperties(syntheticEvent, {\n nativeEvent: { value: nativeEvent },\n currentTarget: { value: element },\n target: { value: nativeEvent.target },\n persist: { value: () => undefined },\n isDefaultPrevented: { value: () => defaultPrevented },\n isPropagationStopped: { value: () => propagationStopped },\n preventDefault: {\n value: () => {\n defaultPrevented = true\n nativeEvent.preventDefault()\n },\n },\n stopPropagation: {\n value: () => {\n propagationStopped = true\n nativeEvent.stopPropagation()\n },\n },\n })\n\n return syntheticEvent as MenuSyntheticEvent\n}\n\nfunction isDirectPropertyKey(key: string) {\n return DIRECT_PROPERTY_KEYS.has(key)\n}\n\nfunction setDirectProperty(element: HTMLDivElement, key: string, value: unknown) {\n if (key === 'tabIndex') {\n element.tabIndex = Number(value)\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = value\n}\n\nfunction clearDirectProperty(element: HTMLDivElement, key: string) {\n if (key === 'tabIndex') {\n element.removeAttribute('tabindex')\n return\n }\n\n const propertyValue = (element as unknown as Record<string, unknown>)[key]\n\n if (typeof propertyValue === 'boolean') {\n ;(element as unknown as Record<string, unknown>)[key] = false\n return\n }\n\n if (typeof propertyValue === 'number') {\n ;(element as unknown as Record<string, unknown>)[key] = 0\n return\n }\n\n ;(element as unknown as Record<string, unknown>)[key] = ''\n}\n\nfunction toStyleValue(styleName: string, value: string | number) {\n if (\n typeof value !== 'number' ||\n value === 0 ||\n styleName.startsWith('--') ||\n UNITLESS_STYLE_PROPERTIES.has(styleName)\n ) {\n return String(value)\n }\n\n return `${value}px`\n}\n\nfunction removeStyleProperty(element: HTMLDivElement, styleName: string) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.removeProperty(toStylePropertyName(styleName))\n}\n\nfunction applyStyleProperty(element: HTMLDivElement, styleName: string, value: string | number) {\n if (PLUGIN_MANAGED_STYLE_PROPERTIES.has(styleName)) {\n return\n }\n\n element.style.setProperty(toStylePropertyName(styleName), toStyleValue(styleName, value))\n}\n\nfunction syncAttributes(\n element: HTMLDivElement,\n prevProps: MenuElementProps,\n nextProps: MenuElementProps,\n) {\n const allKeys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)])\n\n allKeys.forEach(key => {\n if (\n ATTRIBUTE_EXCLUSIONS.has(key) ||\n !isForwardedAttributeKey(key) ||\n isEventProp(key, prevProps[key as keyof MenuElementProps]) ||\n isEventProp(key, nextProps[key as keyof MenuElementProps])\n ) {\n return\n }\n\n const prevValue = prevProps[key as keyof MenuElementProps]\n const nextValue = nextProps[key as keyof MenuElementProps]\n\n if (prevValue === nextValue) {\n return\n }\n\n const attributeName = toAttributeName(key)\n\n if (nextValue == null || nextValue === false) {\n if (isDirectPropertyKey(key)) {\n clearDirectProperty(element, key)\n }\n\n element.removeAttribute(attributeName)\n return\n }\n\n if (nextValue === true) {\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, true)\n }\n\n element.setAttribute(attributeName, '')\n return\n }\n\n if (isDirectPropertyKey(key)) {\n setDirectProperty(element, key, nextValue)\n return\n }\n\n element.setAttribute(attributeName, String(nextValue))\n })\n}\n\nfunction syncClassName(element: HTMLDivElement, prevClassName?: string, nextClassName?: string) {\n if (prevClassName === nextClassName) {\n return\n }\n\n if (nextClassName) {\n element.className = nextClassName\n return\n }\n\n element.removeAttribute('class')\n}\n\nfunction syncStyles(\n element: HTMLDivElement,\n prevStyle: CSSProperties | undefined,\n nextStyle: CSSProperties | undefined,\n) {\n const previousStyle = prevStyle ?? {}\n const currentStyle = nextStyle ?? {}\n const allStyleNames = new Set([...Object.keys(previousStyle), ...Object.keys(currentStyle)])\n\n allStyleNames.forEach(styleName => {\n const prevValue = previousStyle[styleName as keyof CSSProperties]\n const nextValue = currentStyle[styleName as keyof CSSProperties]\n\n if (prevValue === nextValue) {\n return\n }\n\n if (nextValue == null) {\n removeStyleProperty(element, styleName)\n return\n }\n\n applyStyleProperty(element, styleName, nextValue as string | number)\n })\n}\n\nfunction syncEventListeners(\n element: HTMLDivElement,\n prevListeners: EventListenerEntry[],\n nextProps: MenuElementProps,\n) {\n prevListeners.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n\n const nextListeners: EventListenerEntry[] = []\n\n Object.entries(nextProps).forEach(([key, value]) => {\n if (!isEventProp(key, value)) {\n return\n }\n\n const { eventName, options } = toEventConfig(key)\n const listener: MenuNativeListener = event => {\n value(createSyntheticEvent(element, event))\n }\n\n element.addEventListener(eventName, listener, options)\n nextListeners.push({ eventName, listener, options })\n })\n\n return nextListeners\n}\n\nexport function useMenuElementProps(element: HTMLDivElement, props: MenuElementProps) {\n const previousPropsRef = useRef<MenuElementProps>({})\n const listenersRef = useRef<EventListenerEntry[]>([])\n\n useIsomorphicLayoutEffect(() => {\n const previousProps = previousPropsRef.current\n\n syncClassName(element, previousProps.className, props.className)\n syncStyles(element, previousProps.style, props.style)\n syncAttributes(element, previousProps, props)\n listenersRef.current = syncEventListeners(element, listenersRef.current, props)\n previousPropsRef.current = props\n\n return () => {\n listenersRef.current.forEach(({ eventName, listener, options }) => {\n element.removeEventListener(eventName, listener, options)\n })\n listenersRef.current = []\n }\n }, [element, props])\n}\n","import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'\nimport { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'\nimport type { PluginKey } from '@tiptap/pm/state'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getAutoPluginKey } from './getAutoPluginKey.js'\nimport { useMenuElementProps } from './useMenuElementProps.js'\n\ntype Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type FloatingMenuProps = Omit<\n Optional<FloatingMenuPluginProps, 'pluginKey'>,\n 'element' | 'editor'\n> & {\n editor: FloatingMenuPluginProps['editor'] | null\n options?: FloatingMenuPluginProps['options']\n} & React.HTMLAttributes<HTMLDivElement>\n\nexport const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(\n (\n {\n pluginKey,\n editor,\n updateDelay,\n resizeDelay,\n appendTo,\n shouldShow = null,\n options,\n children,\n ...restProps\n },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\n const resolvedPluginKey = useRef<PluginKey | string>(\n getAutoPluginKey(pluginKey, 'floatingMenu'),\n ).current\n\n useMenuElementProps(menuEl.current, restProps)\n\n if (typeof ref === 'function') {\n ref(menuEl.current)\n } else if (ref) {\n ref.current = menuEl.current\n }\n\n const { editor: currentEditor } = useCurrentEditor()\n\n /**\n * The editor instance where the floating menu plugin will be registered.\n */\n const pluginEditor = editor || currentEditor\n\n // Creating a useMemo would be more computationally expensive than just\n // re-creating this object on every render.\n const floatingMenuPluginProps: Omit<FloatingMenuPluginProps, 'editor' | 'element'> = {\n updateDelay,\n resizeDelay,\n appendTo,\n pluginKey: resolvedPluginKey,\n shouldShow,\n options,\n }\n\n /**\n * The props for the floating menu plugin. They are accessed inside a ref to\n * avoid running the useEffect hook and re-registering the plugin when the\n * props change.\n */\n const floatingMenuPluginPropsRef = useRef(floatingMenuPluginProps)\n floatingMenuPluginPropsRef.current = floatingMenuPluginProps\n\n /**\n * Track whether the plugin has been initialized, so we only send updates\n * after the initial registration.\n */\n const [pluginInitialized, setPluginInitialized] = useState(false)\n\n /**\n * Track whether we need to skip the first options update dispatch.\n * This prevents unnecessary updates right after plugin initialization.\n */\n const skipFirstUpdateRef = useRef(true)\n\n useEffect(() => {\n if (pluginEditor?.isDestroyed) {\n return\n }\n\n if (!pluginEditor) {\n console.warn(\n 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',\n )\n return\n }\n\n const floatingMenuElement = menuEl.current\n floatingMenuElement.style.visibility = 'hidden'\n floatingMenuElement.style.position = 'absolute'\n\n const plugin = FloatingMenuPlugin({\n ...floatingMenuPluginPropsRef.current,\n editor: pluginEditor,\n element: floatingMenuElement,\n })\n\n pluginEditor.registerPlugin(plugin)\n\n const createdPluginKey = floatingMenuPluginPropsRef.current.pluginKey\n\n skipFirstUpdateRef.current = true\n setPluginInitialized(true)\n\n return () => {\n setPluginInitialized(false)\n pluginEditor.unregisterPlugin(createdPluginKey)\n window.requestAnimationFrame(() => {\n if (floatingMenuElement.parentNode) {\n floatingMenuElement.parentNode.removeChild(floatingMenuElement)\n }\n })\n }\n }, [pluginEditor])\n\n /**\n * Update the plugin options when props change after the plugin has been initialized.\n * This allows dynamic updates to options like scrollTarget without re-registering the entire plugin.\n */\n useEffect(() => {\n if (!pluginInitialized || !pluginEditor || pluginEditor.isDestroyed) {\n return\n }\n\n // Skip the first update right after initialization since the plugin was just created with these options\n if (skipFirstUpdateRef.current) {\n skipFirstUpdateRef.current = false\n return\n }\n\n pluginEditor.view.dispatch(\n pluginEditor.state.tr.setMeta(resolvedPluginKey, {\n type: 'updateOptions',\n options: floatingMenuPluginPropsRef.current,\n }),\n )\n }, [\n pluginInitialized,\n pluginEditor,\n updateDelay,\n resizeDelay,\n shouldShow,\n options,\n appendTo,\n resolvedPluginKey,\n ])\n\n return createPortal(children, menuEl.current)\n },\n)\n"],"mappings":"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","names":["useEffect","useRef","useRef","useEffect","useCurrentEditor","React","useEffect","useRef","useState","createPortal","React","useRef","useCurrentEditor","useState","useEffect","createPortal"]}
{
"name": "@tiptap/react",
"version": "3.24.0",
"description": "React components for tiptap",
"version": "3.23.6",
"homepage": "https://tiptap.dev",
"keywords": [

@@ -10,3 +9,9 @@ "tiptap",

],
"homepage": "https://tiptap.dev",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/ueberdosis/tiptap",
"directory": "packages/react"
},
"funding": {

@@ -16,2 +21,11 @@ "type": "github",

},
"files": [
"src",
"dist"
],
"type": "module",
"sideEffects": false,
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {

@@ -35,10 +49,2 @@ ".": {

},
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"files": [
"src",
"dist"
],
"dependencies": {

@@ -54,27 +60,20 @@ "@types/use-sync-external-store": "^0.0.6",

"react-dom": "^19.0.0",
"@tiptap/core": "^3.23.6",
"@tiptap/pm": "^3.23.6"
"@tiptap/core": "^3.24.0",
"@tiptap/pm": "^3.24.0"
},
"optionalDependencies": {
"@tiptap/extension-bubble-menu": "^3.23.6",
"@tiptap/extension-floating-menu": "^3.23.6"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@tiptap/core": "3.23.6",
"@tiptap/pm": "3.23.6"
"@tiptap/core": "3.24.0",
"@tiptap/pm": "3.24.0"
},
"repository": {
"type": "git",
"url": "https://github.com/ueberdosis/tiptap",
"directory": "packages/react"
"optionalDependencies": {
"@tiptap/extension-bubble-menu": "^3.24.0",
"@tiptap/extension-floating-menu": "^3.24.0"
},
"sideEffects": false,
"scripts": {
"build": "tsup",
"lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
"build": "tsup"
}
}

@@ -54,3 +54,5 @@ import type { Editor } from '@tiptap/core'

<EditorConsumer>
{({ editor: currentEditor }) => <EditorContent editor={currentEditor} {...editorContainerProps} />}
{({ editor: currentEditor }) => (
<EditorContent editor={currentEditor} {...editorContainerProps} />
)}
</EditorConsumer>

@@ -57,0 +59,0 @@ {children}

@@ -10,3 +10,5 @@ import type { Editor } from '@tiptap/core'

const mergeRefs = <T extends HTMLDivElement>(...refs: Array<MutableRefObject<T> | LegacyRef<T> | undefined>) => {
const mergeRefs = <T extends HTMLDivElement>(
...refs: Array<MutableRefObject<T> | LegacyRef<T> | undefined>
) => {
return (node: T) => {

@@ -187,3 +189,3 @@ refs.forEach(ref => {

return Math.floor(Math.random() * 0xffffffff).toString()
// eslint-disable-next-line react-hooks/exhaustive-deps
// oxlint-disable-next-line react-hooks/exhaustive-deps
}, [props.editor])

@@ -190,0 +192,0 @@

@@ -85,3 +85,5 @@ import { render } from '@testing-library/react'

const [{ element }] = bubbleMenuPluginMock.mock.calls[0] as unknown as [{ element: HTMLDivElement }]
const [{ element }] = bubbleMenuPluginMock.mock.calls[0] as unknown as [
{ element: HTMLDivElement },
]

@@ -160,3 +162,5 @@ expect(element).toBeInstanceOf(HTMLDivElement)

const pluginCalls = bubbleMenuPluginMock.mock.calls as unknown as Array<[{ pluginKey: unknown }]>
const pluginCalls = bubbleMenuPluginMock.mock.calls as unknown as Array<
[{ pluginKey: unknown }]
>
const firstPluginKey = pluginCalls[0][0].pluginKey

@@ -163,0 +167,0 @@ const secondPluginKey = pluginCalls[1][0].pluginKey

@@ -12,3 +12,6 @@ import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'

export type BubbleMenuProps = Optional<Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>, 'editor'> &
export type BubbleMenuProps = Optional<
Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>,
'editor'
> &
React.HTMLAttributes<HTMLDivElement>

@@ -33,3 +36,5 @@

const menuEl = useRef(document.createElement('div'))
const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'bubbleMenu')).current
const resolvedPluginKey = useRef<PluginKey | string>(
getAutoPluginKey(pluginKey, 'bubbleMenu'),
).current

@@ -88,3 +93,5 @@ useMenuElementProps(menuEl.current, restProps)

if (!pluginEditor) {
console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.')
console.warn(
'BubbleMenu component is not rendered inside of an editor component or does not have editor prop.',
)
return

@@ -91,0 +98,0 @@ }

@@ -80,3 +80,5 @@ import { render } from '@testing-library/react'

const [{ element }] = floatingMenuPluginMock.mock.calls[0] as unknown as [{ element: HTMLDivElement }]
const [{ element }] = floatingMenuPluginMock.mock.calls[0] as unknown as [
{ element: HTMLDivElement },
]

@@ -150,3 +152,5 @@ expect(element).toBeInstanceOf(HTMLDivElement)

const pluginCalls = floatingMenuPluginMock.mock.calls as unknown as Array<[{ pluginKey: unknown }]>
const pluginCalls = floatingMenuPluginMock.mock.calls as unknown as Array<
[{ pluginKey: unknown }]
>
const firstPluginKey = pluginCalls[0][0].pluginKey

@@ -153,0 +157,0 @@ const secondPluginKey = pluginCalls[1][0].pluginKey

@@ -13,3 +13,6 @@ import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'

export type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {
export type FloatingMenuProps = Omit<
Optional<FloatingMenuPluginProps, 'pluginKey'>,
'element' | 'editor'
> & {
editor: FloatingMenuPluginProps['editor'] | null

@@ -21,7 +24,19 @@ options?: FloatingMenuPluginProps['options']

(
{ pluginKey, editor, updateDelay, resizeDelay, appendTo, shouldShow = null, options, children, ...restProps },
{
pluginKey,
editor,
updateDelay,
resizeDelay,
appendTo,
shouldShow = null,
options,
children,
...restProps
},
ref,
) => {
const menuEl = useRef(document.createElement('div'))
const resolvedPluginKey = useRef<PluginKey | string>(getAutoPluginKey(pluginKey, 'floatingMenu')).current
const resolvedPluginKey = useRef<PluginKey | string>(
getAutoPluginKey(pluginKey, 'floatingMenu'),
).current

@@ -135,3 +150,12 @@ useMenuElementProps(menuEl.current, restProps)

)
}, [pluginInitialized, pluginEditor, updateDelay, resizeDelay, shouldShow, options, appendTo, resolvedPluginKey])
}, [
pluginInitialized,
pluginEditor,
updateDelay,
resizeDelay,
shouldShow,
options,
appendTo,
resolvedPluginKey,
])

@@ -138,0 +162,0 @@ return createPortal(children, menuEl.current)

@@ -27,3 +27,10 @@ import type { CSSProperties, HTMLAttributes } from 'react'

const PLUGIN_MANAGED_STYLE_PROPERTIES = new Set(['left', 'opacity', 'position', 'top', 'visibility', 'width'])
const PLUGIN_MANAGED_STYLE_PROPERTIES = new Set([
'left',
'opacity',
'position',
'top',
'visibility',
'width',
])
const UNITLESS_STYLE_PROPERTIES = new Set([

@@ -223,3 +230,7 @@ 'animationIterationCount',

function syncAttributes(element: HTMLDivElement, prevProps: MenuElementProps, nextProps: MenuElementProps) {
function syncAttributes(
element: HTMLDivElement,
prevProps: MenuElementProps,
nextProps: MenuElementProps,
) {
const allKeys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)])

@@ -312,3 +323,7 @@

function syncEventListeners(element: HTMLDivElement, prevListeners: EventListenerEntry[], nextProps: MenuElementProps) {
function syncEventListeners(
element: HTMLDivElement,
prevListeners: EventListenerEntry[],
nextProps: MenuElementProps,
) {
prevListeners.forEach(({ eventName, listener, options }) => {

@@ -315,0 +330,0 @@ element.removeEventListener(eventName, listener, options)

@@ -1,2 +0,2 @@

/* eslint-disable @typescript-eslint/no-shadow */
/* oslint-disableno-shadow */
import type { MarkViewProps, MarkViewRenderer, MarkViewRendererOptions } from '@tiptap/core'

@@ -43,3 +43,6 @@ import { MarkView } from '@tiptap/core'

export class ReactMarkView extends MarkView<React.ComponentType<MarkViewProps>, ReactMarkViewRendererOptions> {
export class ReactMarkView extends MarkView<
React.ComponentType<MarkViewProps>,
ReactMarkViewRendererOptions
> {
renderer: ReactRenderer

@@ -56,3 +59,6 @@ contentDOMElement: HTMLElement

const { as = 'span', attrs, className = '' } = options || {}
const componentProps = { ...props, updateAttributes: this.updateAttributes.bind(this) } satisfies MarkViewProps
const componentProps = {
...props,
updateAttributes: this.updateAttributes.bind(this),
} satisfies MarkViewProps

@@ -72,9 +78,11 @@ this.contentDOMElement = document.createElement('span')

// And all of the things it requires are declared outside of the component, so it doesn't need to re-render
const ReactMarkViewProvider: React.FunctionComponent<MarkViewProps> = React.memo(componentProps => {
return (
<ReactMarkViewContext.Provider value={context}>
{React.createElement(component, componentProps)}
</ReactMarkViewContext.Provider>
)
})
const ReactMarkViewProvider: React.FunctionComponent<MarkViewProps> = React.memo(
componentProps => {
return (
<ReactMarkViewContext.Provider value={context}>
{React.createElement(component, componentProps)}
</ReactMarkViewContext.Provider>
)
},
)

@@ -81,0 +89,0 @@ ReactMarkViewProvider.displayName = 'ReactMarkView'

@@ -51,3 +51,6 @@ import type {

| Record<string, string>
| ((props: { node: ProseMirrorNode; HTMLAttributes: Record<string, any> }) => Record<string, string>)
| ((props: {
node: ProseMirrorNode
HTMLAttributes: Record<string, any>
}) => Record<string, string>)
}

@@ -200,9 +203,11 @@

// And all of the things it requires are declared outside of the component, so it doesn't need to re-render
const ReactNodeViewProvider: NamedExoticComponent<ReactNodeViewProps<T>> = memo(componentProps => {
return (
<ReactNodeViewContext.Provider value={context}>
{createElement(Component, componentProps)}
</ReactNodeViewContext.Provider>
)
})
const ReactNodeViewProvider: NamedExoticComponent<ReactNodeViewProps<T>> = memo(
componentProps => {
return (
<ReactNodeViewContext.Provider value={context}>
{createElement(Component, componentProps)}
</ReactNodeViewContext.Provider>
)
},
)

@@ -305,3 +310,7 @@ ReactNodeViewProvider.displayName = 'ReactNodeView'

*/
update(node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource): boolean {
update(
node: Node,
decorations: readonly Decoration[],
innerDecorations: DecorationSource,
): boolean {
const rerenderComponent = (props?: Record<string, any>) => {

@@ -336,3 +345,8 @@ this.renderer.updateProps(props)

updateProps: () =>
rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage }),
rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage,
}),
})

@@ -339,0 +353,0 @@ }

@@ -21,3 +21,7 @@ import type { Editor } from '@tiptap/core'

function isClassComponent(Component: any) {
return !!(typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent)
return !!(
typeof Component === 'function' &&
Component.prototype &&
Component.prototype.isReactComponent
)
}

@@ -48,3 +52,4 @@

Component.$$typeof &&
(Component.$$typeof.toString() === 'Symbol(react.memo)' || Component.$$typeof.description === 'react.memo')
(Component.$$typeof.toString() === 'Symbol(react.memo)' ||
Component.$$typeof.description === 'react.memo')
)

@@ -51,0 +56,0 @@ }

@@ -148,3 +148,6 @@ import type { ReactNode } from 'react'

const tiptapContextValue = useMemo<TiptapContextType>(() => ({ editor: resolvedEditor }), [resolvedEditor])
const tiptapContextValue = useMemo<TiptapContextType>(
() => ({ editor: resolvedEditor }),
[resolvedEditor],
)

@@ -151,0 +154,0 @@ // Provide backwards compatibility with the legacy EditorContext

@@ -101,3 +101,5 @@ import { type EditorOptions, Editor } from '@tiptap/core'

if (immediatelyRender && isDev) {
console.warn('SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches')
console.warn(
'SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches',
)
}

@@ -260,3 +262,4 @@ immediatelyRender = false

const depsAreEqual =
this.previousDeps.length === deps.length && this.previousDeps.every((dep, index) => dep === deps[index])
this.previousDeps.length === deps.length &&
this.previousDeps.every((dep, index) => dep === deps[index])

@@ -332,3 +335,6 @@ if (depsAreEqual) {

export function useEditor(options: UseEditorOptions = {}, deps: DependencyList = []): Editor | null {
export function useEditor(
options: UseEditorOptions = {},
deps: DependencyList = [],
): Editor | null {
const mostRecentOptions = useRef(options)

@@ -349,3 +355,3 @@

// This effect will handle creating/updating the editor instance
// eslint-disable-next-line react-hooks/exhaustive-deps
// oxlint-disable-next-line react-hooks/exhaustive-deps
useEffect(instanceManager.onRender(deps))

@@ -358,3 +364,6 @@

selector: ({ transactionNumber }) => {
if (options.shouldRerenderOnTransaction === false || options.shouldRerenderOnTransaction === undefined) {
if (
options.shouldRerenderOnTransaction === false ||
options.shouldRerenderOnTransaction === undefined
) {
// This will prevent the editor from re-rendering on each transaction

@@ -361,0 +370,0 @@ return null

@@ -13,3 +13,6 @@ import type { Editor } from '@tiptap/core'

export type UseEditorStateOptions<TSelectorResult, TEditor extends Editor | null = Editor | null> = {
export type UseEditorStateOptions<
TSelectorResult,
TEditor extends Editor | null = Editor | null,
> = {
/**

@@ -154,3 +157,5 @@ * The editor instance.

export function useEditorState<TSelectorResult>(
options: UseEditorStateOptions<TSelectorResult, Editor> | UseEditorStateOptions<TSelectorResult, Editor | null>,
options:
| UseEditorStateOptions<TSelectorResult, Editor>
| UseEditorStateOptions<TSelectorResult, Editor | null>,
): TSelectorResult | null {

@@ -157,0 +162,0 @@ const [editorStateManager] = useState(() => new EditorStateManager(options.editor))

@@ -24,6 +24,16 @@ import type { ReactNode } from 'react'

export const ReactNodeViewContentProvider = ({ children, content }: { children: ReactNode; content: ReactNode }) => {
return createElement(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children)
export const ReactNodeViewContentProvider = ({
children,
content,
}: {
children: ReactNode
content: ReactNode
}) => {
return createElement(
ReactNodeViewContext.Provider,
{ value: { nodeViewContentChildren: content } },
children,
)
}
export const useReactNodeView = () => useContext(ReactNodeViewContext)

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display