@tiptap/react 3.0.0-next.0 → 3.0.0-next.2
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/dist/index.cjs +996 -1126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +334 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +960 -1098
- package/dist/index.js.map +1 -1
- package/package.json +14 -15
- package/src/BubbleMenu.tsx +70 -50
- package/src/Context.tsx +15 -7
- package/src/Editor.ts +7 -8
- package/src/EditorContent.tsx +98 -50
- package/src/FloatingMenu.tsx +51 -45
- package/src/NodeViewContent.tsx +1 -0
- package/src/NodeViewWrapper.tsx +1 -0
- package/src/ReactNodeViewRenderer.tsx +163 -53
- package/src/ReactRenderer.tsx +42 -23
- package/src/index.ts +0 -1
- package/src/useEditor.ts +253 -92
- package/src/useEditorState.ts +122 -69
- package/dist/index.umd.js +0 -1176
- 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 -159
- 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 -8
- 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 -253
- 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 -99
- 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 -81
- 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 -13
- 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 -11
- 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
|
@@ -1,54 +1,90 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DecorationWithType,
|
|
3
|
+
Editor,
|
|
4
|
+
getRenderedAttributes,
|
|
3
5
|
NodeView,
|
|
4
6
|
NodeViewProps,
|
|
5
7
|
NodeViewRenderer,
|
|
6
8
|
NodeViewRendererOptions,
|
|
7
|
-
NodeViewRendererProps,
|
|
8
9
|
} from '@tiptap/core'
|
|
9
|
-
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
10
|
-
import { Decoration, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
|
|
11
|
-
import React from 'react'
|
|
10
|
+
import { Node, Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
11
|
+
import { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
|
|
12
|
+
import React, { ComponentType } from 'react'
|
|
12
13
|
|
|
13
|
-
import {
|
|
14
|
+
import { EditorWithContentComponent } from './Editor.js'
|
|
14
15
|
import { ReactRenderer } from './ReactRenderer.js'
|
|
15
16
|
import { ReactNodeViewContext, ReactNodeViewContextProps } from './useReactNodeView.js'
|
|
16
17
|
|
|
17
18
|
export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
|
|
19
|
+
/**
|
|
20
|
+
* This function is called when the node view is updated.
|
|
21
|
+
* It allows you to compare the old node with the new node and decide if the component should update.
|
|
22
|
+
*/
|
|
18
23
|
update:
|
|
19
24
|
| ((props: {
|
|
20
|
-
oldNode: ProseMirrorNode
|
|
21
|
-
oldDecorations: Decoration[]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
oldNode: ProseMirrorNode;
|
|
26
|
+
oldDecorations: readonly Decoration[];
|
|
27
|
+
oldInnerDecorations: DecorationSource;
|
|
28
|
+
newNode: ProseMirrorNode;
|
|
29
|
+
newDecorations: readonly Decoration[];
|
|
30
|
+
innerDecorations: DecorationSource;
|
|
31
|
+
updateProps: () => void;
|
|
25
32
|
}) => boolean)
|
|
26
|
-
| null
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
| null;
|
|
34
|
+
/**
|
|
35
|
+
* The tag name of the element wrapping the React component.
|
|
36
|
+
*/
|
|
37
|
+
as?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The class name of the element wrapping the React component.
|
|
40
|
+
*/
|
|
41
|
+
className?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Attributes that should be applied to the element wrapping the React component.
|
|
44
|
+
* If this is a function, it will be called each time the node view is updated.
|
|
45
|
+
* If this is an object, it will be applied once when the node view is mounted.
|
|
46
|
+
*/
|
|
47
|
+
attrs?:
|
|
48
|
+
| Record<string, string>
|
|
49
|
+
| ((props: {
|
|
50
|
+
node: ProseMirrorNode;
|
|
51
|
+
HTMLAttributes: Record<string, any>;
|
|
52
|
+
}) => Record<string, string>);
|
|
30
53
|
}
|
|
31
54
|
|
|
32
|
-
class ReactNodeView
|
|
33
|
-
|
|
34
|
-
Editor,
|
|
35
|
-
ReactNodeViewRendererOptions
|
|
36
|
-
> {
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
export class ReactNodeView<
|
|
56
|
+
Component extends ComponentType<NodeViewProps> = ComponentType<NodeViewProps>,
|
|
57
|
+
NodeEditor extends Editor = Editor,
|
|
58
|
+
Options extends ReactNodeViewRendererOptions = ReactNodeViewRendererOptions,
|
|
59
|
+
> extends NodeView<Component, NodeEditor, Options> {
|
|
60
|
+
/**
|
|
61
|
+
* The renderer instance.
|
|
62
|
+
*/
|
|
63
|
+
renderer!: ReactRenderer<unknown, NodeViewProps>
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The element that holds the rich-text content of the node.
|
|
67
|
+
*/
|
|
39
68
|
contentDOMElement!: HTMLElement | null
|
|
40
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Setup the React component.
|
|
72
|
+
* Called on initialization.
|
|
73
|
+
*/
|
|
41
74
|
mount() {
|
|
42
|
-
const props
|
|
75
|
+
const props = {
|
|
43
76
|
editor: this.editor,
|
|
44
77
|
node: this.node,
|
|
45
|
-
decorations: this.decorations,
|
|
78
|
+
decorations: this.decorations as DecorationWithType[],
|
|
79
|
+
innerDecorations: this.innerDecorations,
|
|
80
|
+
view: this.view,
|
|
46
81
|
selected: false,
|
|
47
82
|
extension: this.extension,
|
|
83
|
+
HTMLAttributes: this.HTMLAttributes,
|
|
48
84
|
getPos: () => this.getPos(),
|
|
49
85
|
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
|
50
86
|
deleteNode: () => this.deleteNode(),
|
|
51
|
-
}
|
|
87
|
+
} satisfies NodeViewProps
|
|
52
88
|
|
|
53
89
|
if (!(this.component as any).displayName) {
|
|
54
90
|
const capitalizeFirstChar = (string: string): string => {
|
|
@@ -58,25 +94,25 @@ class ReactNodeView extends NodeView<
|
|
|
58
94
|
this.component.displayName = capitalizeFirstChar(this.extension.name)
|
|
59
95
|
}
|
|
60
96
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
|
|
66
|
-
element.appendChild(this.contentDOMElement)
|
|
67
|
-
}
|
|
97
|
+
const onDragStart = this.onDragStart.bind(this)
|
|
98
|
+
const nodeViewContentRef: ReactNodeViewContextProps['nodeViewContentRef'] = element => {
|
|
99
|
+
if (element && this.contentDOMElement && element.firstChild !== this.contentDOMElement) {
|
|
100
|
+
element.appendChild(this.contentDOMElement)
|
|
68
101
|
}
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<>
|
|
72
|
-
{/* @ts-ignore */}
|
|
73
|
-
<ReactNodeViewContext.Provider value={{ onDragStart, nodeViewContentRef }}>
|
|
74
|
-
{/* @ts-ignore */}
|
|
75
|
-
<Component {...componentProps} />
|
|
76
|
-
</ReactNodeViewContext.Provider>
|
|
77
|
-
</>
|
|
78
|
-
)
|
|
79
102
|
}
|
|
103
|
+
const context = { onDragStart, nodeViewContentRef }
|
|
104
|
+
const Component = this.component
|
|
105
|
+
// For performance reasons, we memoize the provider component
|
|
106
|
+
// And all of the things it requires are declared outside of the component, so it doesn't need to re-render
|
|
107
|
+
const ReactNodeViewProvider: React.FunctionComponent<NodeViewProps> = React.memo(
|
|
108
|
+
componentProps => {
|
|
109
|
+
return (
|
|
110
|
+
<ReactNodeViewContext.Provider value={context}>
|
|
111
|
+
{React.createElement(Component, componentProps)}
|
|
112
|
+
</ReactNodeViewContext.Provider>
|
|
113
|
+
)
|
|
114
|
+
},
|
|
115
|
+
)
|
|
80
116
|
|
|
81
117
|
ReactNodeViewProvider.displayName = 'ReactNodeView'
|
|
82
118
|
|
|
@@ -89,6 +125,7 @@ class ReactNodeView extends NodeView<
|
|
|
89
125
|
}
|
|
90
126
|
|
|
91
127
|
if (this.contentDOMElement) {
|
|
128
|
+
this.contentDOMElement.dataset.nodeViewContentReact = ''
|
|
92
129
|
// For some reason the whiteSpace prop is not inherited properly in Chrome and Safari
|
|
93
130
|
// With this fix it seems to work fine
|
|
94
131
|
// See: https://github.com/ueberdosis/tiptap/issues/1197
|
|
@@ -111,10 +148,15 @@ class ReactNodeView extends NodeView<
|
|
|
111
148
|
props,
|
|
112
149
|
as,
|
|
113
150
|
className: `node-${this.node.type.name} ${className}`.trim(),
|
|
114
|
-
attrs: this.options.attrs,
|
|
115
151
|
})
|
|
152
|
+
|
|
153
|
+
this.updateElementAttributes()
|
|
116
154
|
}
|
|
117
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Return the DOM element.
|
|
158
|
+
* This is the element that will be used to display the node view.
|
|
159
|
+
*/
|
|
118
160
|
get dom() {
|
|
119
161
|
if (
|
|
120
162
|
this.renderer.element.firstElementChild
|
|
@@ -126,6 +168,10 @@ class ReactNodeView extends NodeView<
|
|
|
126
168
|
return this.renderer.element as HTMLElement
|
|
127
169
|
}
|
|
128
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Return the content DOM element.
|
|
173
|
+
* This is the element that will be used to display the rich-text content of the node.
|
|
174
|
+
*/
|
|
129
175
|
get contentDOM() {
|
|
130
176
|
if (this.node.isLeaf) {
|
|
131
177
|
return null
|
|
@@ -134,10 +180,19 @@ class ReactNodeView extends NodeView<
|
|
|
134
180
|
return this.contentDOMElement
|
|
135
181
|
}
|
|
136
182
|
|
|
183
|
+
/**
|
|
184
|
+
* On editor selection update, check if the node is selected.
|
|
185
|
+
* If it is, call `selectNode`, otherwise call `deselectNode`.
|
|
186
|
+
*/
|
|
137
187
|
handleSelectionUpdate() {
|
|
138
188
|
const { from, to } = this.editor.state.selection
|
|
189
|
+
const pos = this.getPos()
|
|
139
190
|
|
|
140
|
-
if (
|
|
191
|
+
if (typeof pos !== 'number') {
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (from <= pos && to >= pos + this.node.nodeSize) {
|
|
141
196
|
if (this.renderer.props.selected) {
|
|
142
197
|
return
|
|
143
198
|
}
|
|
@@ -152,9 +207,20 @@ class ReactNodeView extends NodeView<
|
|
|
152
207
|
}
|
|
153
208
|
}
|
|
154
209
|
|
|
155
|
-
|
|
156
|
-
|
|
210
|
+
/**
|
|
211
|
+
* On update, update the React component.
|
|
212
|
+
* To prevent unnecessary updates, the `update` option can be used.
|
|
213
|
+
*/
|
|
214
|
+
update(
|
|
215
|
+
node: Node,
|
|
216
|
+
decorations: readonly Decoration[],
|
|
217
|
+
innerDecorations: DecorationSource,
|
|
218
|
+
): boolean {
|
|
219
|
+
const rerenderComponent = (props?: Record<string, any>) => {
|
|
157
220
|
this.renderer.updateProps(props)
|
|
221
|
+
if (typeof this.options.attrs === 'function') {
|
|
222
|
+
this.updateElementAttributes()
|
|
223
|
+
}
|
|
158
224
|
}
|
|
159
225
|
|
|
160
226
|
if (node.type !== this.node.type) {
|
|
@@ -164,31 +230,44 @@ class ReactNodeView extends NodeView<
|
|
|
164
230
|
if (typeof this.options.update === 'function') {
|
|
165
231
|
const oldNode = this.node
|
|
166
232
|
const oldDecorations = this.decorations
|
|
233
|
+
const oldInnerDecorations = this.innerDecorations
|
|
167
234
|
|
|
168
235
|
this.node = node
|
|
169
236
|
this.decorations = decorations
|
|
237
|
+
this.innerDecorations = innerDecorations
|
|
170
238
|
|
|
171
239
|
return this.options.update({
|
|
172
240
|
oldNode,
|
|
173
241
|
oldDecorations,
|
|
174
242
|
newNode: node,
|
|
175
243
|
newDecorations: decorations,
|
|
176
|
-
|
|
244
|
+
oldInnerDecorations,
|
|
245
|
+
innerDecorations,
|
|
246
|
+
updateProps: () => rerenderComponent({ node, decorations, innerDecorations }),
|
|
177
247
|
})
|
|
178
248
|
}
|
|
179
249
|
|
|
180
|
-
if (
|
|
250
|
+
if (
|
|
251
|
+
node === this.node
|
|
252
|
+
&& this.decorations === decorations
|
|
253
|
+
&& this.innerDecorations === innerDecorations
|
|
254
|
+
) {
|
|
181
255
|
return true
|
|
182
256
|
}
|
|
183
257
|
|
|
184
258
|
this.node = node
|
|
185
259
|
this.decorations = decorations
|
|
260
|
+
this.innerDecorations = innerDecorations
|
|
186
261
|
|
|
187
|
-
|
|
262
|
+
rerenderComponent({ node, decorations, innerDecorations })
|
|
188
263
|
|
|
189
264
|
return true
|
|
190
265
|
}
|
|
191
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Select the node.
|
|
269
|
+
* Add the `selected` prop and the `ProseMirror-selectednode` class.
|
|
270
|
+
*/
|
|
192
271
|
selectNode() {
|
|
193
272
|
this.renderer.updateProps({
|
|
194
273
|
selected: true,
|
|
@@ -196,6 +275,10 @@ class ReactNodeView extends NodeView<
|
|
|
196
275
|
this.renderer.element.classList.add('ProseMirror-selectednode')
|
|
197
276
|
}
|
|
198
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Deselect the node.
|
|
280
|
+
* Remove the `selected` prop and the `ProseMirror-selectednode` class.
|
|
281
|
+
*/
|
|
199
282
|
deselectNode() {
|
|
200
283
|
this.renderer.updateProps({
|
|
201
284
|
selected: false,
|
|
@@ -203,25 +286,52 @@ class ReactNodeView extends NodeView<
|
|
|
203
286
|
this.renderer.element.classList.remove('ProseMirror-selectednode')
|
|
204
287
|
}
|
|
205
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Destroy the React component instance.
|
|
291
|
+
*/
|
|
206
292
|
destroy() {
|
|
207
293
|
this.renderer.destroy()
|
|
208
294
|
this.editor.off('selectionUpdate', this.handleSelectionUpdate)
|
|
209
295
|
this.contentDOMElement = null
|
|
210
296
|
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Update the attributes of the top-level element that holds the React component.
|
|
300
|
+
* Applying the attributes defined in the `attrs` option.
|
|
301
|
+
*/
|
|
302
|
+
updateElementAttributes() {
|
|
303
|
+
if (this.options.attrs) {
|
|
304
|
+
let attrsObj: Record<string, string> = {}
|
|
305
|
+
|
|
306
|
+
if (typeof this.options.attrs === 'function') {
|
|
307
|
+
const extensionAttributes = this.editor.extensionManager.attributes
|
|
308
|
+
const HTMLAttributes = getRenderedAttributes(this.node, extensionAttributes)
|
|
309
|
+
|
|
310
|
+
attrsObj = this.options.attrs({ node: this.node, HTMLAttributes })
|
|
311
|
+
} else {
|
|
312
|
+
attrsObj = this.options.attrs
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.renderer.updateAttributes(attrsObj)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
211
318
|
}
|
|
212
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Create a React node view renderer.
|
|
322
|
+
*/
|
|
213
323
|
export function ReactNodeViewRenderer(
|
|
214
|
-
component:
|
|
324
|
+
component: ComponentType<NodeViewProps>,
|
|
215
325
|
options?: Partial<ReactNodeViewRendererOptions>,
|
|
216
326
|
): NodeViewRenderer {
|
|
217
|
-
return
|
|
327
|
+
return props => {
|
|
218
328
|
// try to get the parent component
|
|
219
329
|
// this is important for vue devtools to show the component hierarchy correctly
|
|
220
330
|
// maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
|
221
|
-
if (!(props.editor as
|
|
222
|
-
return {}
|
|
331
|
+
if (!(props.editor as EditorWithContentComponent).contentComponent) {
|
|
332
|
+
return {} as unknown as ProseMirrorNodeView
|
|
223
333
|
}
|
|
224
334
|
|
|
225
|
-
return new ReactNodeView(component, props, options)
|
|
335
|
+
return new ReactNodeView(component, props, options)
|
|
226
336
|
}
|
|
227
337
|
}
|
package/src/ReactRenderer.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Editor } from '@tiptap/core'
|
|
2
2
|
import React from 'react'
|
|
3
|
+
import { flushSync } from 'react-dom'
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { EditorWithContentComponent } from './Editor.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Check if a component is a class component.
|
|
@@ -56,14 +57,6 @@ export interface ReactRendererOptions {
|
|
|
56
57
|
* @example 'foo bar'
|
|
57
58
|
*/
|
|
58
59
|
className?: string,
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The attributes of the element.
|
|
62
|
-
* @type {Record<string, string>}
|
|
63
|
-
* @default {}
|
|
64
|
-
* @example { 'data-foo': 'bar' }
|
|
65
|
-
*/
|
|
66
|
-
attrs?: Record<string, string>,
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
type ComponentType<R, P> =
|
|
@@ -82,32 +75,34 @@ type ComponentType<R, P> =
|
|
|
82
75
|
* as: 'span',
|
|
83
76
|
* })
|
|
84
77
|
*/
|
|
85
|
-
export class ReactRenderer<R = unknown, P =
|
|
78
|
+
export class ReactRenderer<R = unknown, P extends Record<string, any> = {}> {
|
|
86
79
|
id: string
|
|
87
80
|
|
|
88
|
-
editor:
|
|
81
|
+
editor: Editor
|
|
89
82
|
|
|
90
83
|
component: any
|
|
91
84
|
|
|
92
85
|
element: Element
|
|
93
86
|
|
|
94
|
-
props:
|
|
87
|
+
props: P
|
|
95
88
|
|
|
96
89
|
reactElement: React.ReactNode
|
|
97
90
|
|
|
98
91
|
ref: R | null = null
|
|
99
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Immediately creates element and renders the provided React component.
|
|
95
|
+
*/
|
|
100
96
|
constructor(component: ComponentType<R, P>, {
|
|
101
97
|
editor,
|
|
102
98
|
props = {},
|
|
103
99
|
as = 'div',
|
|
104
100
|
className = '',
|
|
105
|
-
attrs,
|
|
106
101
|
}: ReactRendererOptions) {
|
|
107
102
|
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
|
108
103
|
this.component = component
|
|
109
|
-
this.editor = editor as
|
|
110
|
-
this.props = props
|
|
104
|
+
this.editor = editor as EditorWithContentComponent
|
|
105
|
+
this.props = props as P
|
|
111
106
|
this.element = document.createElement(as)
|
|
112
107
|
this.element.classList.add('react-renderer')
|
|
113
108
|
|
|
@@ -115,30 +110,40 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
115
110
|
this.element.classList.add(...className.split(' '))
|
|
116
111
|
}
|
|
117
112
|
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
if (this.editor.isInitialized) {
|
|
114
|
+
// On first render, we need to flush the render synchronously
|
|
115
|
+
// Renders afterwards can be async, but this fixes a cursor positioning issue
|
|
116
|
+
flushSync(() => {
|
|
117
|
+
this.render()
|
|
121
118
|
})
|
|
119
|
+
} else {
|
|
120
|
+
this.render()
|
|
122
121
|
}
|
|
123
|
-
|
|
124
|
-
this.render()
|
|
125
122
|
}
|
|
126
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Render the React component.
|
|
126
|
+
*/
|
|
127
127
|
render(): void {
|
|
128
128
|
const Component = this.component
|
|
129
129
|
const props = this.props
|
|
130
|
+
const editor = this.editor as EditorWithContentComponent
|
|
130
131
|
|
|
131
132
|
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
|
|
133
|
+
// @ts-ignore This is a hack to make the ref work
|
|
132
134
|
props.ref = (ref: R) => {
|
|
133
135
|
this.ref = ref
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
this.reactElement = <Component {...props
|
|
139
|
+
this.reactElement = <Component {...props} />
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
editor?.contentComponent?.setRenderer(this.id, this)
|
|
140
142
|
}
|
|
141
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Re-renders the React component with new props.
|
|
146
|
+
*/
|
|
142
147
|
updateProps(props: Record<string, any> = {}): void {
|
|
143
148
|
this.props = {
|
|
144
149
|
...this.props,
|
|
@@ -148,7 +153,21 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
148
153
|
this.render()
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Destroy the React component.
|
|
158
|
+
*/
|
|
151
159
|
destroy(): void {
|
|
152
|
-
this.editor
|
|
160
|
+
const editor = this.editor as EditorWithContentComponent
|
|
161
|
+
|
|
162
|
+
editor?.contentComponent?.removeRenderer(this.id)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Update the attributes of the element that holds the React component.
|
|
167
|
+
*/
|
|
168
|
+
updateAttributes(attributes: Record<string, string>): void {
|
|
169
|
+
Object.keys(attributes).forEach(key => {
|
|
170
|
+
this.element.setAttribute(key, attributes[key])
|
|
171
|
+
})
|
|
153
172
|
}
|
|
154
173
|
}
|