@tiptap/react 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +5 -1
- package/dist/index.cjs +1030 -1163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +350 -0
- package/dist/index.d.ts +350 -0
- package/dist/index.js +970 -1138
- package/dist/index.js.map +1 -1
- package/dist/menus/index.cjs +142 -0
- package/dist/menus/index.cjs.map +1 -0
- package/dist/menus/index.d.cts +19 -0
- package/dist/menus/index.d.ts +19 -0
- package/dist/menus/index.js +104 -0
- package/dist/menus/index.js.map +1 -0
- package/package.json +34 -21
- package/src/Context.tsx +18 -12
- package/src/Editor.ts +10 -11
- package/src/EditorContent.tsx +104 -64
- package/src/NodeViewContent.tsx +13 -8
- package/src/NodeViewWrapper.tsx +3 -2
- package/src/ReactMarkViewRenderer.tsx +111 -0
- package/src/ReactNodeViewRenderer.tsx +184 -67
- package/src/ReactRenderer.tsx +152 -51
- package/src/index.ts +2 -3
- package/src/menus/BubbleMenu.tsx +68 -0
- package/src/menus/FloatingMenu.tsx +68 -0
- package/src/menus/index.ts +2 -0
- package/src/types.ts +6 -0
- package/src/useEditor.ts +286 -166
- package/src/useEditorState.ts +133 -85
- package/src/useReactNodeView.ts +21 -5
- package/dist/index.umd.js +0 -1219
- package/dist/index.umd.js.map +0 -1
- package/dist/packages/core/src/CommandManager.d.ts +0 -20
- package/dist/packages/core/src/Editor.d.ts +0 -161
- package/dist/packages/core/src/EventEmitter.d.ts +0 -11
- package/dist/packages/core/src/Extension.d.ts +0 -343
- package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
- package/dist/packages/core/src/InputRule.d.ts +0 -42
- package/dist/packages/core/src/Mark.d.ts +0 -451
- package/dist/packages/core/src/Node.d.ts +0 -611
- package/dist/packages/core/src/NodePos.d.ts +0 -44
- package/dist/packages/core/src/NodeView.d.ts +0 -31
- package/dist/packages/core/src/PasteRule.d.ts +0 -50
- package/dist/packages/core/src/Tracker.d.ts +0 -11
- package/dist/packages/core/src/commands/blur.d.ts +0 -13
- package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
- package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
- package/dist/packages/core/src/commands/command.d.ts +0 -18
- package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
- package/dist/packages/core/src/commands/cut.d.ts +0 -20
- package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
- package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
- package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
- package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
- package/dist/packages/core/src/commands/enter.d.ts +0 -13
- package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
- package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
- package/dist/packages/core/src/commands/first.d.ts +0 -14
- package/dist/packages/core/src/commands/focus.d.ts +0 -27
- package/dist/packages/core/src/commands/forEach.d.ts +0 -14
- package/dist/packages/core/src/commands/index.d.ts +0 -55
- package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
- package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
- package/dist/packages/core/src/commands/join.d.ts +0 -41
- package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
- package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
- package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
- package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
- package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
- package/dist/packages/core/src/commands/lift.d.ts +0 -17
- package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
- package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
- package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
- package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
- package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
- package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
- package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
- package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
- package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
- package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
- package/dist/packages/core/src/commands/setContent.d.ts +0 -40
- package/dist/packages/core/src/commands/setMark.d.ts +0 -15
- package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
- package/dist/packages/core/src/commands/setNode.d.ts +0 -16
- package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
- package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
- package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
- package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
- package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
- package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
- package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
- package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
- package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
- package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
- package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
- package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
- package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
- package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
- package/dist/packages/core/src/extensions/commands.d.ts +0 -3
- package/dist/packages/core/src/extensions/editable.d.ts +0 -2
- package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
- package/dist/packages/core/src/extensions/index.d.ts +0 -6
- package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
- package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
- package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
- package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
- package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
- package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
- package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
- package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
- package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
- package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
- package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
- package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
- package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
- package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
- package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
- package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
- package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
- package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
- package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
- package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
- package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
- package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
- package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
- package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
- package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
- package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
- package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
- package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
- package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
- package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
- package/dist/packages/core/src/helpers/getText.d.ts +0 -15
- package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
- package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
- package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
- package/dist/packages/core/src/helpers/index.d.ts +0 -50
- package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
- package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
- package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
- package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
- package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
- package/dist/packages/core/src/helpers/isList.d.ts +0 -2
- package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
- package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
- package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
- package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
- package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
- package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
- package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
- package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
- package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
- package/dist/packages/core/src/index.d.ts +0 -24
- package/dist/packages/core/src/inputRules/index.d.ts +0 -5
- package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
- package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
- package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
- package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
- package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
- package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
- package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
- package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
- package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
- package/dist/packages/core/src/style.d.ts +0 -1
- package/dist/packages/core/src/types.d.ts +0 -255
- package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
- package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
- package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
- package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
- package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
- package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
- package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
- package/dist/packages/core/src/utilities/index.d.ts +0 -20
- package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
- package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
- package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
- package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
- package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
- package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
- package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
- package/dist/packages/core/src/utilities/isString.d.ts +0 -1
- package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
- package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
- package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
- package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
- package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
- package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
- package/dist/packages/extension-bubble-menu/src/bubble-menu-plugin.d.ts +0 -76
- package/dist/packages/extension-bubble-menu/src/bubble-menu.d.ts +0 -15
- package/dist/packages/extension-bubble-menu/src/index.d.ts +0 -4
- package/dist/packages/extension-floating-menu/src/floating-menu-plugin.d.ts +0 -66
- package/dist/packages/extension-floating-menu/src/floating-menu.d.ts +0 -15
- package/dist/packages/extension-floating-menu/src/index.d.ts +0 -4
- package/dist/packages/react/src/BubbleMenu.d.ts +0 -11
- package/dist/packages/react/src/Context.d.ts +0 -23
- package/dist/packages/react/src/Editor.d.ts +0 -12
- package/dist/packages/react/src/EditorContent.d.ts +0 -24
- package/dist/packages/react/src/FloatingMenu.d.ts +0 -10
- package/dist/packages/react/src/NodeViewContent.d.ts +0 -6
- package/dist/packages/react/src/NodeViewWrapper.d.ts +0 -6
- package/dist/packages/react/src/ReactNodeViewRenderer.d.ts +0 -16
- package/dist/packages/react/src/ReactRenderer.d.ts +0 -62
- package/dist/packages/react/src/index.d.ts +0 -13
- package/dist/packages/react/src/useEditor.d.ts +0 -39
- package/dist/packages/react/src/useEditorState.d.ts +0 -22
- package/dist/packages/react/src/useReactNodeView.d.ts +0 -6
- package/src/BubbleMenu.tsx +0 -57
- package/src/FloatingMenu.tsx +0 -64
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/menus/BubbleMenu.tsx
|
|
2
|
+
import { BubbleMenuPlugin } from "@tiptap/extension-bubble-menu";
|
|
3
|
+
import { useCurrentEditor } from "@tiptap/react";
|
|
4
|
+
import React, { useEffect, useRef } from "react";
|
|
5
|
+
import { createPortal } from "react-dom";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
var BubbleMenu = React.forwardRef(
|
|
8
|
+
({ pluginKey = "bubbleMenu", editor, updateDelay, resizeDelay, shouldShow = null, options, children, ...restProps }, ref) => {
|
|
9
|
+
const menuEl = useRef(document.createElement("div"));
|
|
10
|
+
if (typeof ref === "function") {
|
|
11
|
+
ref(menuEl.current);
|
|
12
|
+
} else if (ref) {
|
|
13
|
+
ref.current = menuEl.current;
|
|
14
|
+
}
|
|
15
|
+
const { editor: currentEditor } = useCurrentEditor();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const bubbleMenuElement = menuEl.current;
|
|
18
|
+
bubbleMenuElement.style.visibility = "hidden";
|
|
19
|
+
bubbleMenuElement.style.position = "absolute";
|
|
20
|
+
if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const attachToEditor = editor || currentEditor;
|
|
24
|
+
if (!attachToEditor) {
|
|
25
|
+
console.warn("BubbleMenu component is not rendered inside of an editor component or does not have editor prop.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const plugin = BubbleMenuPlugin({
|
|
29
|
+
updateDelay,
|
|
30
|
+
resizeDelay,
|
|
31
|
+
editor: attachToEditor,
|
|
32
|
+
element: bubbleMenuElement,
|
|
33
|
+
pluginKey,
|
|
34
|
+
shouldShow,
|
|
35
|
+
options
|
|
36
|
+
});
|
|
37
|
+
attachToEditor.registerPlugin(plugin);
|
|
38
|
+
return () => {
|
|
39
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
40
|
+
window.requestAnimationFrame(() => {
|
|
41
|
+
if (bubbleMenuElement.parentNode) {
|
|
42
|
+
bubbleMenuElement.parentNode.removeChild(bubbleMenuElement);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
}, [editor, currentEditor]);
|
|
47
|
+
return createPortal(/* @__PURE__ */ jsx("div", { ...restProps, children }), menuEl.current);
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// src/menus/FloatingMenu.tsx
|
|
52
|
+
import { FloatingMenuPlugin } from "@tiptap/extension-floating-menu";
|
|
53
|
+
import { useCurrentEditor as useCurrentEditor2 } from "@tiptap/react";
|
|
54
|
+
import React2, { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
55
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
56
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
57
|
+
var FloatingMenu = React2.forwardRef(
|
|
58
|
+
({ pluginKey = "floatingMenu", editor, shouldShow = null, options, children, ...restProps }, ref) => {
|
|
59
|
+
const menuEl = useRef2(document.createElement("div"));
|
|
60
|
+
if (typeof ref === "function") {
|
|
61
|
+
ref(menuEl.current);
|
|
62
|
+
} else if (ref) {
|
|
63
|
+
ref.current = menuEl.current;
|
|
64
|
+
}
|
|
65
|
+
const { editor: currentEditor } = useCurrentEditor2();
|
|
66
|
+
useEffect2(() => {
|
|
67
|
+
const floatingMenuElement = menuEl.current;
|
|
68
|
+
floatingMenuElement.style.visibility = "hidden";
|
|
69
|
+
floatingMenuElement.style.position = "absolute";
|
|
70
|
+
if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const attachToEditor = editor || currentEditor;
|
|
74
|
+
if (!attachToEditor) {
|
|
75
|
+
console.warn(
|
|
76
|
+
"FloatingMenu component is not rendered inside of an editor component or does not have editor prop."
|
|
77
|
+
);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const plugin = FloatingMenuPlugin({
|
|
81
|
+
editor: attachToEditor,
|
|
82
|
+
element: floatingMenuElement,
|
|
83
|
+
pluginKey,
|
|
84
|
+
shouldShow,
|
|
85
|
+
options
|
|
86
|
+
});
|
|
87
|
+
attachToEditor.registerPlugin(plugin);
|
|
88
|
+
return () => {
|
|
89
|
+
attachToEditor.unregisterPlugin(pluginKey);
|
|
90
|
+
window.requestAnimationFrame(() => {
|
|
91
|
+
if (floatingMenuElement.parentNode) {
|
|
92
|
+
floatingMenuElement.parentNode.removeChild(floatingMenuElement);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
}, [editor, currentEditor]);
|
|
97
|
+
return createPortal2(/* @__PURE__ */ jsx2("div", { ...restProps, children }), menuEl.current);
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
export {
|
|
101
|
+
BubbleMenu,
|
|
102
|
+
FloatingMenu
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/menus/BubbleMenu.tsx","../../src/menus/FloatingMenu.tsx"],"sourcesContent":["import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef } from 'react'\nimport { createPortal } from 'react-dom'\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 { pluginKey = 'bubbleMenu', editor, updateDelay, resizeDelay, shouldShow = null, options, children, ...restProps },\n ref,\n ) => {\n const menuEl = useRef(document.createElement('div'))\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 useEffect(() => {\n const bubbleMenuElement = menuEl.current\n\n bubbleMenuElement.style.visibility = 'hidden'\n bubbleMenuElement.style.position = 'absolute'\n\n if (editor?.isDestroyed || (currentEditor as any)?.isDestroyed) {\n return\n }\n\n const attachToEditor = editor || currentEditor\n\n if (!attachToEditor) {\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 plugin = BubbleMenuPlugin({\n updateDelay,\n resizeDelay,\n editor: attachToEditor,\n element: bubbleMenuElement,\n pluginKey,\n shouldShow,\n options,\n })\n\n attachToEditor.registerPlugin(plugin)\n\n return () => {\n attachToEditor.unregisterPlugin(pluginKey)\n window.requestAnimationFrame(() => {\n if (bubbleMenuElement.parentNode) {\n bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)\n }\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor, currentEditor])\n\n return createPortal(<div {...restProps}>{children}</div>, menuEl.current)\n },\n)\n","import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'\nimport { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'\nimport { useCurrentEditor } from '@tiptap/react'\nimport React, { useEffect, useRef } from 'react'\nimport { createPortal } from 'react-dom'\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 ({ pluginKey = 'floatingMenu', editor, shouldShow = null, options, children, ...restProps }, ref) => {\n const menuEl = useRef(document.createElement('div'))\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 useEffect(() => {\n const floatingMenuElement = menuEl.current\n\n floatingMenuElement.style.visibility = 'hidden'\n floatingMenuElement.style.position = 'absolute'\n\n if (editor?.isDestroyed || (currentEditor as any)?.isDestroyed) {\n return\n }\n\n const attachToEditor = editor || currentEditor\n\n if (!attachToEditor) {\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 plugin = FloatingMenuPlugin({\n editor: attachToEditor,\n element: floatingMenuElement,\n pluginKey,\n shouldShow,\n options,\n })\n\n attachToEditor.registerPlugin(plugin)\n\n return () => {\n attachToEditor.unregisterPlugin(pluginKey)\n window.requestAnimationFrame(() => {\n if (floatingMenuElement.parentNode) {\n floatingMenuElement.parentNode.removeChild(floatingMenuElement)\n }\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor, currentEditor])\n\n return createPortal(<div {...restProps}>{children}</div>, menuEl.current)\n },\n)\n"],"mappings":";AAAA,SAAqC,wBAAwB;AAC7D,SAAS,wBAAwB;AACjC,OAAO,SAAS,WAAW,cAAc;AACzC,SAAS,oBAAoB;AA8DL;AAvDjB,IAAM,aAAa,MAAM;AAAA,EAC9B,CACE,EAAE,YAAY,cAAc,QAAQ,aAAa,aAAa,aAAa,MAAM,SAAS,UAAU,GAAG,UAAU,GACjH,QACG;AACH,UAAM,SAAS,OAAO,SAAS,cAAc,KAAK,CAAC;AAEnD,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;AAEnD,cAAU,MAAM;AACd,YAAM,oBAAoB,OAAO;AAEjC,wBAAkB,MAAM,aAAa;AACrC,wBAAkB,MAAM,WAAW;AAEnC,WAAI,iCAAQ,iBAAgB,+CAAuB,cAAa;AAC9D;AAAA,MACF;AAEA,YAAM,iBAAiB,UAAU;AAEjC,UAAI,CAAC,gBAAgB;AACnB,gBAAQ,KAAK,kGAAkG;AAC/G;AAAA,MACF;AAEA,YAAM,SAAS,iBAAiB;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,qBAAe,eAAe,MAAM;AAEpC,aAAO,MAAM;AACX,uBAAe,iBAAiB,SAAS;AACzC,eAAO,sBAAsB,MAAM;AACjC,cAAI,kBAAkB,YAAY;AAChC,8BAAkB,WAAW,YAAY,iBAAiB;AAAA,UAC5D;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IAEF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,WAAO,aAAa,oBAAC,SAAK,GAAG,WAAY,UAAS,GAAQ,OAAO,OAAO;AAAA,EAC1E;AACF;;;AClEA,SAAS,0BAA0B;AACnC,SAAS,oBAAAA,yBAAwB;AACjC,OAAOC,UAAS,aAAAC,YAAW,UAAAC,eAAc;AACzC,SAAS,gBAAAC,qBAAoB;AA6DL,gBAAAC,YAAA;AApDjB,IAAM,eAAeJ,OAAM;AAAA,EAChC,CAAC,EAAE,YAAY,gBAAgB,QAAQ,aAAa,MAAM,SAAS,UAAU,GAAG,UAAU,GAAG,QAAQ;AACnG,UAAM,SAASE,QAAO,SAAS,cAAc,KAAK,CAAC;AAEnD,QAAI,OAAO,QAAQ,YAAY;AAC7B,UAAI,OAAO,OAAO;AAAA,IACpB,WAAW,KAAK;AACd,UAAI,UAAU,OAAO;AAAA,IACvB;AAEA,UAAM,EAAE,QAAQ,cAAc,IAAIH,kBAAiB;AAEnD,IAAAE,WAAU,MAAM;AACd,YAAM,sBAAsB,OAAO;AAEnC,0BAAoB,MAAM,aAAa;AACvC,0BAAoB,MAAM,WAAW;AAErC,WAAI,iCAAQ,iBAAgB,+CAAuB,cAAa;AAC9D;AAAA,MACF;AAEA,YAAM,iBAAiB,UAAU;AAEjC,UAAI,CAAC,gBAAgB;AACnB,gBAAQ;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,SAAS,mBAAmB;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,qBAAe,eAAe,MAAM;AAEpC,aAAO,MAAM;AACX,uBAAe,iBAAiB,SAAS;AACzC,eAAO,sBAAsB,MAAM;AACjC,cAAI,oBAAoB,YAAY;AAClC,gCAAoB,WAAW,YAAY,mBAAmB;AAAA,UAChE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IAEF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,WAAOE,cAAa,gBAAAC,KAAC,SAAK,GAAG,WAAY,UAAS,GAAQ,OAAO,OAAO;AAAA,EAC1E;AACF;","names":["useCurrentEditor","React","useEffect","useRef","createPortal","jsx"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/react",
|
|
3
3
|
"description": "React components for tiptap",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.1",
|
|
5
5
|
"homepage": "https://tiptap.dev",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -14,39 +14,52 @@
|
|
|
14
14
|
},
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
17
|
-
"types":
|
|
17
|
+
"types": {
|
|
18
|
+
"import": "./dist/index.d.ts",
|
|
19
|
+
"require": "./dist/index.d.cts"
|
|
20
|
+
},
|
|
18
21
|
"import": "./dist/index.js",
|
|
19
22
|
"require": "./dist/index.cjs"
|
|
23
|
+
},
|
|
24
|
+
"./menus": {
|
|
25
|
+
"types": {
|
|
26
|
+
"import": "./dist/menus/index.d.ts",
|
|
27
|
+
"require": "./dist/menus/index.d.cts"
|
|
28
|
+
},
|
|
29
|
+
"import": "./dist/menus/index.js",
|
|
30
|
+
"require": "./dist/menus/index.cjs"
|
|
20
31
|
}
|
|
21
32
|
},
|
|
22
33
|
"main": "dist/index.cjs",
|
|
23
34
|
"module": "dist/index.js",
|
|
24
|
-
"
|
|
25
|
-
"types": "dist/packages/react/src/index.d.ts",
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
26
36
|
"type": "module",
|
|
27
37
|
"files": [
|
|
28
38
|
"src",
|
|
29
39
|
"dist"
|
|
30
40
|
],
|
|
31
41
|
"dependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"
|
|
34
|
-
"use-sync-external-store": "^1.
|
|
35
|
-
"@types/use-sync-external-store": "^0.0.6"
|
|
42
|
+
"@types/use-sync-external-store": "^0.0.6",
|
|
43
|
+
"fast-deep-equal": "^3.1.3",
|
|
44
|
+
"use-sync-external-store": "^1.4.0"
|
|
36
45
|
},
|
|
37
46
|
"devDependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
47
|
+
"@types/react": "^18.3.18",
|
|
48
|
+
"@types/react-dom": "^18.3.5",
|
|
49
|
+
"react": "^19.0.0",
|
|
50
|
+
"react-dom": "^19.0.0",
|
|
51
|
+
"@tiptap/core": "^3.0.1",
|
|
52
|
+
"@tiptap/pm": "^3.0.1"
|
|
53
|
+
},
|
|
54
|
+
"optionalDependencies": {
|
|
55
|
+
"@tiptap/extension-bubble-menu": "^3.0.1",
|
|
56
|
+
"@tiptap/extension-floating-menu": "^3.0.1"
|
|
44
57
|
},
|
|
45
58
|
"peerDependencies": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
59
|
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
60
|
+
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
61
|
+
"@tiptap/core": "^3.0.1",
|
|
62
|
+
"@tiptap/pm": "^3.0.1"
|
|
50
63
|
},
|
|
51
64
|
"repository": {
|
|
52
65
|
"type": "git",
|
|
@@ -55,7 +68,7 @@
|
|
|
55
68
|
},
|
|
56
69
|
"sideEffects": false,
|
|
57
70
|
"scripts": {
|
|
58
|
-
"
|
|
59
|
-
"
|
|
71
|
+
"build": "tsup",
|
|
72
|
+
"lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
|
|
60
73
|
}
|
|
61
|
-
}
|
|
74
|
+
}
|
package/src/Context.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { Editor } from '@tiptap/core'
|
|
2
|
+
import type { HTMLAttributes, ReactNode } from 'react'
|
|
3
|
+
import React, { createContext, useContext, useMemo } from 'react'
|
|
2
4
|
|
|
3
|
-
import { Editor } from './Editor.js'
|
|
4
5
|
import { EditorContent } from './EditorContent.js'
|
|
5
|
-
import {
|
|
6
|
+
import type { UseEditorOptions } from './useEditor.js'
|
|
7
|
+
import { useEditor } from './useEditor.js'
|
|
6
8
|
|
|
7
9
|
export type EditorContextValue = {
|
|
8
|
-
editor: Editor | null
|
|
10
|
+
editor: Editor | null
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export const EditorContext = createContext<EditorContextValue>({
|
|
@@ -20,9 +22,10 @@ export const EditorConsumer = EditorContext.Consumer
|
|
|
20
22
|
export const useCurrentEditor = () => useContext(EditorContext)
|
|
21
23
|
|
|
22
24
|
export type EditorProviderProps = {
|
|
23
|
-
children?: ReactNode
|
|
24
|
-
slotBefore?: ReactNode
|
|
25
|
-
slotAfter?: ReactNode
|
|
25
|
+
children?: ReactNode
|
|
26
|
+
slotBefore?: ReactNode
|
|
27
|
+
slotAfter?: ReactNode
|
|
28
|
+
editorContainerProps?: HTMLAttributes<HTMLDivElement>
|
|
26
29
|
} & UseEditorOptions
|
|
27
30
|
|
|
28
31
|
/**
|
|
@@ -31,21 +34,24 @@ export type EditorProviderProps = {
|
|
|
31
34
|
* with `useCurrentEditor`.
|
|
32
35
|
*/
|
|
33
36
|
export function EditorProvider({
|
|
34
|
-
children,
|
|
37
|
+
children,
|
|
38
|
+
slotAfter,
|
|
39
|
+
slotBefore,
|
|
40
|
+
editorContainerProps = {},
|
|
41
|
+
...editorOptions
|
|
35
42
|
}: EditorProviderProps) {
|
|
36
43
|
const editor = useEditor(editorOptions)
|
|
44
|
+
const contextValue = useMemo(() => ({ editor }), [editor])
|
|
37
45
|
|
|
38
46
|
if (!editor) {
|
|
39
47
|
return null
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
return (
|
|
43
|
-
<EditorContext.Provider value={
|
|
51
|
+
<EditorContext.Provider value={contextValue}>
|
|
44
52
|
{slotBefore}
|
|
45
53
|
<EditorConsumer>
|
|
46
|
-
{({ editor: currentEditor }) =>
|
|
47
|
-
<EditorContent editor={currentEditor} />
|
|
48
|
-
)}
|
|
54
|
+
{({ editor: currentEditor }) => <EditorContent editor={currentEditor} {...editorContainerProps} />}
|
|
49
55
|
</EditorConsumer>
|
|
50
56
|
{children}
|
|
51
57
|
{slotAfter}
|
package/src/Editor.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { Editor
|
|
2
|
-
import
|
|
1
|
+
import type { Editor } from '@tiptap/core'
|
|
2
|
+
import type { ReactPortal } from 'react'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { ReactRenderer } from './ReactRenderer.js'
|
|
4
|
+
import type { ReactRenderer } from './ReactRenderer.js'
|
|
6
5
|
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
export type EditorWithContentComponent = Editor & { contentComponent?: ContentComponent | null }
|
|
7
|
+
export type ContentComponent = {
|
|
8
|
+
setRenderer(id: string, renderer: ReactRenderer): void
|
|
9
|
+
removeRenderer(id: string): void
|
|
10
|
+
subscribe: (callback: () => void) => () => void
|
|
11
|
+
getSnapshot: () => Record<string, ReactPortal>
|
|
12
|
+
getServerSnapshot: () => Record<string, ReactPortal>
|
|
14
13
|
}
|
package/src/EditorContent.tsx
CHANGED
|
@@ -1,56 +1,105 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
} from 'react'
|
|
4
|
-
import ReactDOM
|
|
1
|
+
import type { Editor } from '@tiptap/core'
|
|
2
|
+
import type { ForwardedRef, HTMLProps, LegacyRef, MutableRefObject } from 'react'
|
|
3
|
+
import React, { forwardRef } from 'react'
|
|
4
|
+
import ReactDOM from 'react-dom'
|
|
5
|
+
import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
-
import { ReactRenderer } from './ReactRenderer.js'
|
|
7
|
+
import type { ContentComponent, EditorWithContentComponent } from './Editor.js'
|
|
8
|
+
import type { ReactRenderer } from './ReactRenderer.js'
|
|
8
9
|
|
|
9
|
-
const mergeRefs = <T extends HTMLDivElement>(
|
|
10
|
-
...refs: Array<MutableRefObject<T> | LegacyRef<T> | undefined>
|
|
11
|
-
) => {
|
|
10
|
+
const mergeRefs = <T extends HTMLDivElement>(...refs: Array<MutableRefObject<T> | LegacyRef<T> | undefined>) => {
|
|
12
11
|
return (node: T) => {
|
|
13
12
|
refs.forEach(ref => {
|
|
14
13
|
if (typeof ref === 'function') {
|
|
15
14
|
ref(node)
|
|
16
15
|
} else if (ref) {
|
|
17
|
-
(ref as MutableRefObject<T | null>).current = node
|
|
16
|
+
;(ref as MutableRefObject<T | null>).current = node
|
|
18
17
|
}
|
|
19
18
|
})
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
/**
|
|
23
|
+
* This component renders all of the editor's node views.
|
|
24
|
+
*/
|
|
25
|
+
const Portals: React.FC<{ contentComponent: ContentComponent }> = ({ contentComponent }) => {
|
|
26
|
+
// For performance reasons, we render the node view portals on state changes only
|
|
27
|
+
const renderers = useSyncExternalStore(
|
|
28
|
+
contentComponent.subscribe,
|
|
29
|
+
contentComponent.getSnapshot,
|
|
30
|
+
contentComponent.getServerSnapshot,
|
|
30
31
|
)
|
|
32
|
+
|
|
33
|
+
// This allows us to directly render the portals without any additional wrapper
|
|
34
|
+
return <>{Object.values(renderers)}</>
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface EditorContentProps extends HTMLProps<HTMLDivElement> {
|
|
34
|
-
editor: Editor | null
|
|
35
|
-
innerRef?: ForwardedRef<HTMLDivElement | null
|
|
38
|
+
editor: Editor | null
|
|
39
|
+
innerRef?: ForwardedRef<HTMLDivElement | null>
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
function getInstance(): ContentComponent {
|
|
43
|
+
const subscribers = new Set<() => void>()
|
|
44
|
+
let renderers: Record<string, React.ReactPortal> = {}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
/**
|
|
48
|
+
* Subscribe to the editor instance's changes.
|
|
49
|
+
*/
|
|
50
|
+
subscribe(callback: () => void) {
|
|
51
|
+
subscribers.add(callback)
|
|
52
|
+
return () => {
|
|
53
|
+
subscribers.delete(callback)
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
getSnapshot() {
|
|
57
|
+
return renderers
|
|
58
|
+
},
|
|
59
|
+
getServerSnapshot() {
|
|
60
|
+
return renderers
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Adds a new NodeView Renderer to the editor.
|
|
64
|
+
*/
|
|
65
|
+
setRenderer(id: string, renderer: ReactRenderer) {
|
|
66
|
+
renderers = {
|
|
67
|
+
...renderers,
|
|
68
|
+
[id]: ReactDOM.createPortal(renderer.reactElement, renderer.element, id),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
subscribers.forEach(subscriber => subscriber())
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* Removes a NodeView Renderer from the editor.
|
|
75
|
+
*/
|
|
76
|
+
removeRenderer(id: string) {
|
|
77
|
+
const nextRenderers = { ...renderers }
|
|
78
|
+
|
|
79
|
+
delete nextRenderers[id]
|
|
80
|
+
renderers = nextRenderers
|
|
81
|
+
subscribers.forEach(subscriber => subscriber())
|
|
82
|
+
},
|
|
83
|
+
}
|
|
40
84
|
}
|
|
41
85
|
|
|
42
|
-
export class PureEditorContent extends React.Component<
|
|
86
|
+
export class PureEditorContent extends React.Component<
|
|
87
|
+
EditorContentProps,
|
|
88
|
+
{ hasContentComponentInitialized: boolean }
|
|
89
|
+
> {
|
|
43
90
|
editorContentRef: React.RefObject<any>
|
|
44
91
|
|
|
45
92
|
initialized: boolean
|
|
46
93
|
|
|
94
|
+
unsubscribeToContentComponent?: () => void
|
|
95
|
+
|
|
47
96
|
constructor(props: EditorContentProps) {
|
|
48
97
|
super(props)
|
|
49
98
|
this.editorContentRef = React.createRef()
|
|
50
99
|
this.initialized = false
|
|
51
100
|
|
|
52
101
|
this.state = {
|
|
53
|
-
|
|
102
|
+
hasContentComponentInitialized: Boolean((props.editor as EditorWithContentComponent | null)?.contentComponent),
|
|
54
103
|
}
|
|
55
104
|
}
|
|
56
105
|
|
|
@@ -63,7 +112,7 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
63
112
|
}
|
|
64
113
|
|
|
65
114
|
init() {
|
|
66
|
-
const
|
|
115
|
+
const editor = this.props.editor as EditorWithContentComponent | null
|
|
67
116
|
|
|
68
117
|
if (editor && !editor.isDestroyed && editor.options.element) {
|
|
69
118
|
if (editor.contentComponent) {
|
|
@@ -78,7 +127,27 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
78
127
|
element,
|
|
79
128
|
})
|
|
80
129
|
|
|
81
|
-
editor.contentComponent =
|
|
130
|
+
editor.contentComponent = getInstance()
|
|
131
|
+
|
|
132
|
+
// Has the content component been initialized?
|
|
133
|
+
if (!this.state.hasContentComponentInitialized) {
|
|
134
|
+
// Subscribe to the content component
|
|
135
|
+
this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
|
|
136
|
+
this.setState(prevState => {
|
|
137
|
+
if (!prevState.hasContentComponentInitialized) {
|
|
138
|
+
return {
|
|
139
|
+
hasContentComponentInitialized: true,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return prevState
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// Unsubscribe to previous content component
|
|
146
|
+
if (this.unsubscribeToContentComponent) {
|
|
147
|
+
this.unsubscribeToContentComponent()
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
}
|
|
82
151
|
|
|
83
152
|
editor.createNodeViews()
|
|
84
153
|
|
|
@@ -86,43 +155,8 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
86
155
|
}
|
|
87
156
|
}
|
|
88
157
|
|
|
89
|
-
maybeFlushSync(fn: () => void) {
|
|
90
|
-
// Avoid calling flushSync until the editor is initialized.
|
|
91
|
-
// Initialization happens during the componentDidMount or componentDidUpdate
|
|
92
|
-
// lifecycle methods, and React doesn't allow calling flushSync from inside
|
|
93
|
-
// a lifecycle method.
|
|
94
|
-
if (this.initialized) {
|
|
95
|
-
flushSync(fn)
|
|
96
|
-
} else {
|
|
97
|
-
fn()
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
setRenderer(id: string, renderer: ReactRenderer) {
|
|
102
|
-
this.maybeFlushSync(() => {
|
|
103
|
-
this.setState(({ renderers }) => ({
|
|
104
|
-
renderers: {
|
|
105
|
-
...renderers,
|
|
106
|
-
[id]: renderer,
|
|
107
|
-
},
|
|
108
|
-
}))
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
removeRenderer(id: string) {
|
|
113
|
-
this.maybeFlushSync(() => {
|
|
114
|
-
this.setState(({ renderers }) => {
|
|
115
|
-
const nextRenderers = { ...renderers }
|
|
116
|
-
|
|
117
|
-
delete nextRenderers[id]
|
|
118
|
-
|
|
119
|
-
return { renderers: nextRenderers }
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
|
|
124
158
|
componentWillUnmount() {
|
|
125
|
-
const
|
|
159
|
+
const editor = this.props.editor as EditorWithContentComponent | null
|
|
126
160
|
|
|
127
161
|
if (!editor) {
|
|
128
162
|
return
|
|
@@ -136,12 +170,17 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
136
170
|
})
|
|
137
171
|
}
|
|
138
172
|
|
|
173
|
+
if (this.unsubscribeToContentComponent) {
|
|
174
|
+
this.unsubscribeToContentComponent()
|
|
175
|
+
}
|
|
176
|
+
|
|
139
177
|
editor.contentComponent = null
|
|
140
178
|
|
|
141
|
-
if (!editor.options.element
|
|
179
|
+
if (!editor.options.element?.firstChild) {
|
|
142
180
|
return
|
|
143
181
|
}
|
|
144
182
|
|
|
183
|
+
// TODO using the new editor.mount method might allow us to remove this
|
|
145
184
|
const newElement = document.createElement('div')
|
|
146
185
|
|
|
147
186
|
newElement.append(...editor.options.element.childNodes)
|
|
@@ -158,7 +197,7 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
158
197
|
<>
|
|
159
198
|
<div ref={mergeRefs(innerRef, this.editorContentRef)} {...rest} />
|
|
160
199
|
{/* @ts-ignore */}
|
|
161
|
-
<Portals
|
|
200
|
+
{editor?.contentComponent && <Portals contentComponent={editor.contentComponent} />}
|
|
162
201
|
</>
|
|
163
202
|
)
|
|
164
203
|
}
|
|
@@ -168,7 +207,8 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
|
|
168
207
|
const EditorContentWithKey = forwardRef<HTMLDivElement, EditorContentProps>(
|
|
169
208
|
(props: Omit<EditorContentProps, 'innerRef'>, ref) => {
|
|
170
209
|
const key = React.useMemo(() => {
|
|
171
|
-
return Math.floor(Math.random() *
|
|
210
|
+
return Math.floor(Math.random() * 0xffffffff).toString()
|
|
211
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
172
212
|
}, [props.editor])
|
|
173
213
|
|
|
174
214
|
// Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
|
package/src/NodeViewContent.tsx
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react'
|
|
1
2
|
import React from 'react'
|
|
2
3
|
|
|
3
4
|
import { useReactNodeView } from './useReactNodeView.js'
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
6
|
+
export type NodeViewContentProps<T extends keyof React.JSX.IntrinsicElements = 'div'> = {
|
|
7
|
+
as?: NoInfer<T>
|
|
8
|
+
} & ComponentProps<T>
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
export function NodeViewContent<T extends keyof React.JSX.IntrinsicElements = 'div'>({
|
|
11
|
+
as: Tag = 'div' as T,
|
|
12
|
+
...props
|
|
13
|
+
}: NodeViewContentProps<T>) {
|
|
14
|
+
const { nodeViewContentRef, nodeViewContentChildren } = useReactNodeView()
|
|
13
15
|
|
|
14
16
|
return (
|
|
17
|
+
// @ts-ignore
|
|
15
18
|
<Tag
|
|
16
19
|
{...props}
|
|
17
20
|
ref={nodeViewContentRef}
|
|
@@ -20,6 +23,8 @@ export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
|
|
|
20
23
|
whiteSpace: 'pre-wrap',
|
|
21
24
|
...props.style,
|
|
22
25
|
}}
|
|
23
|
-
|
|
26
|
+
>
|
|
27
|
+
{nodeViewContentChildren}
|
|
28
|
+
</Tag>
|
|
24
29
|
)
|
|
25
30
|
}
|
package/src/NodeViewWrapper.tsx
CHANGED
|
@@ -3,8 +3,8 @@ import React from 'react'
|
|
|
3
3
|
import { useReactNodeView } from './useReactNodeView.js'
|
|
4
4
|
|
|
5
5
|
export interface NodeViewWrapperProps {
|
|
6
|
-
[key: string]: any
|
|
7
|
-
as?: React.ElementType
|
|
6
|
+
[key: string]: any
|
|
7
|
+
as?: React.ElementType
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const NodeViewWrapper: React.FC<NodeViewWrapperProps> = React.forwardRef((props, ref) => {
|
|
@@ -12,6 +12,7 @@ export const NodeViewWrapper: React.FC<NodeViewWrapperProps> = React.forwardRef(
|
|
|
12
12
|
const Tag = props.as || 'div'
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
|
+
// @ts-ignore
|
|
15
16
|
<Tag
|
|
16
17
|
{...props}
|
|
17
18
|
ref={ref}
|