@tiptap/react 2.6.6 → 2.7.0-pre.0
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 +201 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +198 -20
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1501 -1322
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/NodeView.d.ts +20 -8
- package/dist/packages/core/src/index.d.ts +2 -0
- package/dist/packages/core/src/plugins/DropPlugin.d.ts +3 -0
- package/dist/packages/core/src/plugins/PastePlugin.d.ts +3 -0
- package/dist/packages/core/src/types.d.ts +35 -15
- package/dist/packages/react/src/ReactNodeViewRenderer.d.ts +86 -7
- package/dist/packages/react/src/ReactRenderer.d.ts +19 -10
- package/dist/packages/react/src/useEditorState.d.ts +23 -1
- package/package.json +8 -7
- package/src/ReactNodeViewRenderer.tsx +152 -41
- package/src/ReactRenderer.tsx +25 -18
- package/src/useEditor.ts +2 -0
- package/src/useEditorState.ts +43 -8
package/src/ReactRenderer.tsx
CHANGED
|
@@ -57,14 +57,6 @@ export interface ReactRendererOptions {
|
|
|
57
57
|
* @example 'foo bar'
|
|
58
58
|
*/
|
|
59
59
|
className?: string,
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The attributes of the element.
|
|
63
|
-
* @type {Record<string, string>}
|
|
64
|
-
* @default {}
|
|
65
|
-
* @example { 'data-foo': 'bar' }
|
|
66
|
-
*/
|
|
67
|
-
attrs?: Record<string, string>,
|
|
68
60
|
}
|
|
69
61
|
|
|
70
62
|
type ComponentType<R, P> =
|
|
@@ -83,7 +75,7 @@ type ComponentType<R, P> =
|
|
|
83
75
|
* as: 'span',
|
|
84
76
|
* })
|
|
85
77
|
*/
|
|
86
|
-
export class ReactRenderer<R = unknown, P =
|
|
78
|
+
export class ReactRenderer<R = unknown, P extends Record<string, any> = {}> {
|
|
87
79
|
id: string
|
|
88
80
|
|
|
89
81
|
editor: Editor
|
|
@@ -92,23 +84,25 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
92
84
|
|
|
93
85
|
element: Element
|
|
94
86
|
|
|
95
|
-
props:
|
|
87
|
+
props: P
|
|
96
88
|
|
|
97
89
|
reactElement: React.ReactNode
|
|
98
90
|
|
|
99
91
|
ref: R | null = null
|
|
100
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Immediately creates element and renders the provided React component.
|
|
95
|
+
*/
|
|
101
96
|
constructor(component: ComponentType<R, P>, {
|
|
102
97
|
editor,
|
|
103
98
|
props = {},
|
|
104
99
|
as = 'div',
|
|
105
100
|
className = '',
|
|
106
|
-
attrs,
|
|
107
101
|
}: ReactRendererOptions) {
|
|
108
102
|
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
|
109
103
|
this.component = component
|
|
110
104
|
this.editor = editor as EditorWithContentComponent
|
|
111
|
-
this.props = props
|
|
105
|
+
this.props = props as P
|
|
112
106
|
this.element = document.createElement(as)
|
|
113
107
|
this.element.classList.add('react-renderer')
|
|
114
108
|
|
|
@@ -116,12 +110,6 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
116
110
|
this.element.classList.add(...className.split(' '))
|
|
117
111
|
}
|
|
118
112
|
|
|
119
|
-
if (attrs) {
|
|
120
|
-
Object.keys(attrs).forEach(key => {
|
|
121
|
-
this.element.setAttribute(key, attrs[key])
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
113
|
if (this.editor.isInitialized) {
|
|
126
114
|
// On first render, we need to flush the render synchronously
|
|
127
115
|
// Renders afterwards can be async, but this fixes a cursor positioning issue
|
|
@@ -133,12 +121,16 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
133
121
|
}
|
|
134
122
|
}
|
|
135
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Render the React component.
|
|
126
|
+
*/
|
|
136
127
|
render(): void {
|
|
137
128
|
const Component = this.component
|
|
138
129
|
const props = this.props
|
|
139
130
|
const editor = this.editor as EditorWithContentComponent
|
|
140
131
|
|
|
141
132
|
if (isClassComponent(Component) || isForwardRefComponent(Component)) {
|
|
133
|
+
// @ts-ignore This is a hack to make the ref work
|
|
142
134
|
props.ref = (ref: R) => {
|
|
143
135
|
this.ref = ref
|
|
144
136
|
}
|
|
@@ -149,6 +141,9 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
149
141
|
editor?.contentComponent?.setRenderer(this.id, this)
|
|
150
142
|
}
|
|
151
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Re-renders the React component with new props.
|
|
146
|
+
*/
|
|
152
147
|
updateProps(props: Record<string, any> = {}): void {
|
|
153
148
|
this.props = {
|
|
154
149
|
...this.props,
|
|
@@ -158,9 +153,21 @@ export class ReactRenderer<R = unknown, P = unknown> {
|
|
|
158
153
|
this.render()
|
|
159
154
|
}
|
|
160
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Destroy the React component.
|
|
158
|
+
*/
|
|
161
159
|
destroy(): void {
|
|
162
160
|
const editor = this.editor as EditorWithContentComponent
|
|
163
161
|
|
|
164
162
|
editor?.contentComponent?.removeRenderer(this.id)
|
|
165
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
|
+
})
|
|
172
|
+
}
|
|
166
173
|
}
|
package/src/useEditor.ts
CHANGED
|
@@ -149,6 +149,8 @@ class EditorInstanceManager {
|
|
|
149
149
|
onTransaction: (...args) => this.options.current.onTransaction?.(...args),
|
|
150
150
|
onUpdate: (...args) => this.options.current.onUpdate?.(...args),
|
|
151
151
|
onContentError: (...args) => this.options.current.onContentError?.(...args),
|
|
152
|
+
onDrop: (...args) => this.options.current.onDrop?.(...args),
|
|
153
|
+
onPaste: (...args) => this.options.current.onPaste?.(...args),
|
|
152
154
|
}
|
|
153
155
|
const editor = new Editor(optionsToApply)
|
|
154
156
|
|
package/src/useEditorState.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Editor } from '@tiptap/core'
|
|
2
|
+
import deepEqual from 'fast-deep-equal/es6/react'
|
|
2
3
|
import { useDebugValue, useEffect, useState } from 'react'
|
|
3
4
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
|
|
4
5
|
|
|
@@ -6,6 +7,7 @@ export type EditorStateSnapshot<TEditor extends Editor | null = Editor | null> =
|
|
|
6
7
|
editor: TEditor;
|
|
7
8
|
transactionNumber: number;
|
|
8
9
|
};
|
|
10
|
+
|
|
9
11
|
export type UseEditorStateOptions<
|
|
10
12
|
TSelectorResult,
|
|
11
13
|
TEditor extends Editor | null = Editor | null,
|
|
@@ -20,7 +22,7 @@ export type UseEditorStateOptions<
|
|
|
20
22
|
selector: (context: EditorStateSnapshot<TEditor>) => TSelectorResult;
|
|
21
23
|
/**
|
|
22
24
|
* A custom equality function to determine if the editor should re-render.
|
|
23
|
-
* @default `
|
|
25
|
+
* @default `deepEqual` from `fast-deep-equal`
|
|
24
26
|
*/
|
|
25
27
|
equalityFn?: (a: TSelectorResult, b: TSelectorResult | null) => boolean;
|
|
26
28
|
};
|
|
@@ -108,30 +110,63 @@ class EditorStateManager<TEditor extends Editor | null = Editor | null> {
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
113
|
+
/**
|
|
114
|
+
* This hook allows you to watch for changes on the editor instance.
|
|
115
|
+
* It will allow you to select a part of the editor state and re-render the component when it changes.
|
|
116
|
+
* @example
|
|
117
|
+
* ```tsx
|
|
118
|
+
* const editor = useEditor({...options})
|
|
119
|
+
* const { currentSelection } = useEditorState({
|
|
120
|
+
* editor,
|
|
121
|
+
* selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
|
|
122
|
+
* })
|
|
123
|
+
*/
|
|
111
124
|
export function useEditorState<TSelectorResult>(
|
|
112
125
|
options: UseEditorStateOptions<TSelectorResult, Editor>
|
|
113
126
|
): TSelectorResult;
|
|
127
|
+
/**
|
|
128
|
+
* This hook allows you to watch for changes on the editor instance.
|
|
129
|
+
* It will allow you to select a part of the editor state and re-render the component when it changes.
|
|
130
|
+
* @example
|
|
131
|
+
* ```tsx
|
|
132
|
+
* const editor = useEditor({...options})
|
|
133
|
+
* const { currentSelection } = useEditorState({
|
|
134
|
+
* editor,
|
|
135
|
+
* selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
|
|
136
|
+
* })
|
|
137
|
+
*/
|
|
114
138
|
export function useEditorState<TSelectorResult>(
|
|
115
139
|
options: UseEditorStateOptions<TSelectorResult, Editor | null>
|
|
116
140
|
): TSelectorResult | null;
|
|
117
141
|
|
|
142
|
+
/**
|
|
143
|
+
* This hook allows you to watch for changes on the editor instance.
|
|
144
|
+
* It will allow you to select a part of the editor state and re-render the component when it changes.
|
|
145
|
+
* @example
|
|
146
|
+
* ```tsx
|
|
147
|
+
* const editor = useEditor({...options})
|
|
148
|
+
* const { currentSelection } = useEditorState({
|
|
149
|
+
* editor,
|
|
150
|
+
* selector: snapshot => ({ currentSelection: snapshot.editor.state.selection }),
|
|
151
|
+
* })
|
|
152
|
+
*/
|
|
118
153
|
export function useEditorState<TSelectorResult>(
|
|
119
154
|
options: UseEditorStateOptions<TSelectorResult, Editor> | UseEditorStateOptions<TSelectorResult, Editor | null>,
|
|
120
155
|
): TSelectorResult | null {
|
|
121
|
-
const [
|
|
156
|
+
const [editorStateManager] = useState(() => new EditorStateManager(options.editor))
|
|
122
157
|
|
|
123
158
|
// Using the `useSyncExternalStore` hook to sync the editor instance with the component state
|
|
124
159
|
const selectedState = useSyncExternalStoreWithSelector(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
160
|
+
editorStateManager.subscribe,
|
|
161
|
+
editorStateManager.getSnapshot,
|
|
162
|
+
editorStateManager.getServerSnapshot,
|
|
128
163
|
options.selector as UseEditorStateOptions<TSelectorResult, Editor | null>['selector'],
|
|
129
|
-
options.equalityFn,
|
|
164
|
+
options.equalityFn ?? deepEqual,
|
|
130
165
|
)
|
|
131
166
|
|
|
132
167
|
useEffect(() => {
|
|
133
|
-
return
|
|
134
|
-
}, [options.editor,
|
|
168
|
+
return editorStateManager.watch(options.editor)
|
|
169
|
+
}, [options.editor, editorStateManager])
|
|
135
170
|
|
|
136
171
|
useDebugValue(selectedState)
|
|
137
172
|
|