@tiptap/react 2.12.0 → 2.13.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/EditorContent.d.ts +1 -1
- package/dist/EditorContent.d.ts.map +1 -1
- package/dist/ReactNodeViewRenderer.d.ts +9 -7
- package/dist/ReactNodeViewRenderer.d.ts.map +1 -1
- package/dist/ReactRenderer.d.ts +4 -4
- package/dist/ReactRenderer.d.ts.map +1 -1
- package/dist/index.cjs +46 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -9
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +44 -6
- package/dist/index.umd.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +9 -9
- package/src/ReactNodeViewRenderer.tsx +25 -27
- package/src/ReactRenderer.tsx +58 -11
- package/src/index.ts +1 -0
- package/src/types.ts +6 -0
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DecorationWithType,
|
|
3
|
-
Editor,
|
|
4
|
-
getRenderedAttributes,
|
|
5
|
-
NodeView,
|
|
6
|
-
NodeViewProps,
|
|
7
|
-
NodeViewRenderer,
|
|
8
|
-
NodeViewRendererOptions,
|
|
1
|
+
import type {
|
|
2
|
+
DecorationWithType, Editor, NodeViewRenderer, NodeViewRendererOptions,
|
|
9
3
|
} from '@tiptap/core'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
4
|
+
import { getRenderedAttributes, NodeView } from '@tiptap/core'
|
|
5
|
+
import type { Node, Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
6
|
+
import type { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
|
|
7
|
+
import type { ComponentType, NamedExoticComponent } from 'react'
|
|
8
|
+
import React, { createElement, createRef, memo } from 'react'
|
|
13
9
|
|
|
14
10
|
import { EditorWithContentComponent } from './Editor.js'
|
|
15
11
|
import { ReactRenderer } from './ReactRenderer.js'
|
|
16
|
-
import {
|
|
12
|
+
import type { ReactNodeViewProps } from './types.js'
|
|
13
|
+
import type { ReactNodeViewContextProps } from './useReactNodeView.js'
|
|
14
|
+
import { ReactNodeViewContext } from './useReactNodeView.js'
|
|
17
15
|
|
|
18
16
|
export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
|
|
19
17
|
/**
|
|
@@ -53,14 +51,15 @@ export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
|
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
export class ReactNodeView<
|
|
56
|
-
|
|
54
|
+
T = HTMLElement,
|
|
55
|
+
Component extends ComponentType<ReactNodeViewProps<T>> = ComponentType<ReactNodeViewProps<T>>,
|
|
57
56
|
NodeEditor extends Editor = Editor,
|
|
58
57
|
Options extends ReactNodeViewRendererOptions = ReactNodeViewRendererOptions,
|
|
59
58
|
> extends NodeView<Component, NodeEditor, Options> {
|
|
60
59
|
/**
|
|
61
60
|
* The renderer instance.
|
|
62
61
|
*/
|
|
63
|
-
renderer!: ReactRenderer<unknown,
|
|
62
|
+
renderer!: ReactRenderer<unknown, ReactNodeViewProps<T>>
|
|
64
63
|
|
|
65
64
|
/**
|
|
66
65
|
* The element that holds the rich-text content of the node.
|
|
@@ -84,7 +83,8 @@ export class ReactNodeView<
|
|
|
84
83
|
getPos: () => this.getPos(),
|
|
85
84
|
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
|
86
85
|
deleteNode: () => this.deleteNode(),
|
|
87
|
-
|
|
86
|
+
ref: createRef<T>(),
|
|
87
|
+
} satisfies ReactNodeViewProps<T>
|
|
88
88
|
|
|
89
89
|
if (!(this.component as any).displayName) {
|
|
90
90
|
const capitalizeFirstChar = (string: string): string => {
|
|
@@ -104,15 +104,13 @@ export class ReactNodeView<
|
|
|
104
104
|
const Component = this.component
|
|
105
105
|
// For performance reasons, we memoize the provider component
|
|
106
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:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
},
|
|
115
|
-
)
|
|
107
|
+
const ReactNodeViewProvider: NamedExoticComponent<ReactNodeViewProps<T>> = memo(componentProps => {
|
|
108
|
+
return (
|
|
109
|
+
<ReactNodeViewContext.Provider value={context}>
|
|
110
|
+
{createElement(Component, componentProps)}
|
|
111
|
+
</ReactNodeViewContext.Provider>
|
|
112
|
+
)
|
|
113
|
+
})
|
|
116
114
|
|
|
117
115
|
ReactNodeViewProvider.displayName = 'ReactNodeView'
|
|
118
116
|
|
|
@@ -320,8 +318,8 @@ export class ReactNodeView<
|
|
|
320
318
|
/**
|
|
321
319
|
* Create a React node view renderer.
|
|
322
320
|
*/
|
|
323
|
-
export function ReactNodeViewRenderer(
|
|
324
|
-
component: ComponentType<
|
|
321
|
+
export function ReactNodeViewRenderer<T = HTMLElement>(
|
|
322
|
+
component: ComponentType<ReactNodeViewProps<T>>,
|
|
325
323
|
options?: Partial<ReactNodeViewRendererOptions>,
|
|
326
324
|
): NodeViewRenderer {
|
|
327
325
|
return props => {
|
|
@@ -332,6 +330,6 @@ export function ReactNodeViewRenderer(
|
|
|
332
330
|
return {} as unknown as ProseMirrorNodeView
|
|
333
331
|
}
|
|
334
332
|
|
|
335
|
-
return new ReactNodeView(component, props, options)
|
|
333
|
+
return new ReactNodeView<T>(component, props, options)
|
|
336
334
|
}
|
|
337
335
|
}
|
package/src/ReactRenderer.tsx
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { Editor } from '@tiptap/core'
|
|
2
|
-
import
|
|
1
|
+
import type { Editor } from '@tiptap/core'
|
|
2
|
+
import type {
|
|
3
|
+
ComponentClass,
|
|
4
|
+
ForwardRefExoticComponent,
|
|
5
|
+
FunctionComponent,
|
|
6
|
+
PropsWithoutRef,
|
|
7
|
+
ReactNode,
|
|
8
|
+
RefAttributes,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import React, { version as reactVersion } from 'react'
|
|
3
11
|
import { flushSync } from 'react-dom'
|
|
4
12
|
|
|
5
13
|
import { EditorWithContentComponent } from './Editor.js'
|
|
@@ -29,6 +37,27 @@ function isForwardRefComponent(Component: any) {
|
|
|
29
37
|
)
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Check if we're running React 19+ by detecting if function components support ref props
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
function isReact19Plus(): boolean {
|
|
45
|
+
// React 19 is detected by checking React version if available
|
|
46
|
+
// In practice, we'll use a more conservative approach and assume React 18 behavior
|
|
47
|
+
// unless we can definitively detect React 19
|
|
48
|
+
try {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
if (reactVersion) {
|
|
51
|
+
const majorVersion = parseInt(reactVersion.split('.')[0], 10)
|
|
52
|
+
|
|
53
|
+
return majorVersion >= 19
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
// Fallback to React 18 behavior if we can't determine version
|
|
57
|
+
}
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
|
|
32
61
|
export interface ReactRendererOptions {
|
|
33
62
|
/**
|
|
34
63
|
* The editor instance.
|
|
@@ -60,9 +89,9 @@ export interface ReactRendererOptions {
|
|
|
60
89
|
}
|
|
61
90
|
|
|
62
91
|
type ComponentType<R, P> =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
92
|
+
| ComponentClass<P>
|
|
93
|
+
| FunctionComponent<P>
|
|
94
|
+
| ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<R>>
|
|
66
95
|
|
|
67
96
|
/**
|
|
68
97
|
* The ReactRenderer class. It's responsible for rendering React components inside the editor.
|
|
@@ -86,7 +115,7 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
|
|
|
86
115
|
|
|
87
116
|
props: P
|
|
88
117
|
|
|
89
|
-
reactElement:
|
|
118
|
+
reactElement: ReactNode
|
|
90
119
|
|
|
91
120
|
ref: R | null = null
|
|
92
121
|
|
|
@@ -129,14 +158,32 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
|
|
|
129
158
|
const props = this.props
|
|
130
159
|
const editor = this.editor as EditorWithContentComponent
|
|
131
160
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
161
|
+
// Handle ref forwarding with React 18/19 compatibility
|
|
162
|
+
const isReact19 = isReact19Plus()
|
|
163
|
+
const isClassComp = isClassComponent(Component)
|
|
164
|
+
const isForwardRefComp = isForwardRefComponent(Component)
|
|
165
|
+
|
|
166
|
+
const elementProps = { ...props }
|
|
167
|
+
|
|
168
|
+
if (!elementProps.ref) {
|
|
169
|
+
if (isReact19) {
|
|
170
|
+
// React 19: ref is a standard prop for all components
|
|
171
|
+
// @ts-ignore - Setting ref prop for React 19 compatibility
|
|
172
|
+
elementProps.ref = (ref: R) => {
|
|
173
|
+
this.ref = ref
|
|
174
|
+
}
|
|
175
|
+
} else if (isClassComp || isForwardRefComp) {
|
|
176
|
+
// React 18 and prior: only set ref for class components and forwardRef components
|
|
177
|
+
// @ts-ignore - Setting ref prop for React 18 class/forwardRef components
|
|
178
|
+
elementProps.ref = (ref: R) => {
|
|
179
|
+
this.ref = ref
|
|
180
|
+
}
|
|
136
181
|
}
|
|
182
|
+
// For function components in React 18, we can't use ref - the component won't receive it
|
|
183
|
+
// This is a limitation we have to accept for React 18 function components without forwardRef
|
|
137
184
|
}
|
|
138
185
|
|
|
139
|
-
this.reactElement = <Component {...
|
|
186
|
+
this.reactElement = <Component {...elementProps} />
|
|
140
187
|
|
|
141
188
|
editor?.contentComponent?.setRenderer(this.id, this)
|
|
142
189
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './NodeViewContent.js'
|
|
|
6
6
|
export * from './NodeViewWrapper.js'
|
|
7
7
|
export * from './ReactNodeViewRenderer.js'
|
|
8
8
|
export * from './ReactRenderer.js'
|
|
9
|
+
export * from './types.js'
|
|
9
10
|
export * from './useEditor.js'
|
|
10
11
|
export * from './useEditorState.js'
|
|
11
12
|
export * from './useReactNodeView.js'
|