@tiptap/react 2.14.0 → 2.22.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.
@@ -33,10 +33,56 @@ function isClassComponent(Component: any) {
33
33
  function isForwardRefComponent(Component: any) {
34
34
  return !!(
35
35
  typeof Component === 'object'
36
- && Component.$$typeof?.toString() === 'Symbol(react.forward_ref)'
36
+ && Component.$$typeof
37
+ && (Component.$$typeof.toString() === 'Symbol(react.forward_ref)'
38
+ || Component.$$typeof.description === 'react.forward_ref')
37
39
  )
38
40
  }
39
41
 
42
+ /**
43
+ * Check if a component is a memoized component.
44
+ * @param Component
45
+ * @returns {boolean}
46
+ */
47
+ function isMemoComponent(Component: any) {
48
+ return !!(
49
+ typeof Component === 'object'
50
+ && Component.$$typeof
51
+ && (Component.$$typeof.toString() === 'Symbol(react.memo)' || Component.$$typeof.description === 'react.memo')
52
+ )
53
+ }
54
+
55
+ /**
56
+ * Check if a component can safely receive a ref prop.
57
+ * This includes class components, forwardRef components, and memoized components
58
+ * that wrap forwardRef or class components.
59
+ * @param Component
60
+ * @returns {boolean}
61
+ */
62
+ function canReceiveRef(Component: any) {
63
+ // Check if it's a class component
64
+ if (isClassComponent(Component)) {
65
+ return true
66
+ }
67
+
68
+ // Check if it's a forwardRef component
69
+ if (isForwardRefComponent(Component)) {
70
+ return true
71
+ }
72
+
73
+ // Check if it's a memoized component
74
+ if (isMemoComponent(Component)) {
75
+ // For memoized components, check the wrapped component
76
+ const wrappedComponent = Component.type
77
+
78
+ if (wrappedComponent) {
79
+ return isClassComponent(wrappedComponent) || isForwardRefComponent(wrappedComponent)
80
+ }
81
+ }
82
+
83
+ return false
84
+ }
85
+
40
86
  /**
41
87
  * Check if we're running React 19+ by detecting if function components support ref props
42
88
  * @returns {boolean}
@@ -160,27 +206,21 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
160
206
 
161
207
  // Handle ref forwarding with React 18/19 compatibility
162
208
  const isReact19 = isReact19Plus()
163
- const isClassComp = isClassComponent(Component)
164
- const isForwardRefComp = isForwardRefComponent(Component)
209
+ const componentCanReceiveRef = canReceiveRef(Component)
165
210
 
166
211
  const elementProps = { ...props }
167
212
 
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
- }
213
+ // Always remove ref if the component cannot receive it (unless React 19+)
214
+ if (elementProps.ref && !(isReact19 || componentCanReceiveRef)) {
215
+ delete elementProps.ref
216
+ }
217
+
218
+ // Only assign our own ref if allowed
219
+ if (!elementProps.ref && (isReact19 || componentCanReceiveRef)) {
220
+ // @ts-ignore - Setting ref prop for compatible components
221
+ elementProps.ref = (ref: R) => {
222
+ this.ref = ref
181
223
  }
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
184
224
  }
185
225
 
186
226
  this.reactElement = <Component {...elementProps} />