@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.
Files changed (201) hide show
  1. package/dist/index.cjs +996 -1126
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +334 -0
  4. package/dist/index.d.ts +334 -0
  5. package/dist/index.js +960 -1098
  6. package/dist/index.js.map +1 -1
  7. package/package.json +14 -15
  8. package/src/BubbleMenu.tsx +70 -50
  9. package/src/Context.tsx +15 -7
  10. package/src/Editor.ts +7 -8
  11. package/src/EditorContent.tsx +98 -50
  12. package/src/FloatingMenu.tsx +51 -45
  13. package/src/NodeViewContent.tsx +1 -0
  14. package/src/NodeViewWrapper.tsx +1 -0
  15. package/src/ReactNodeViewRenderer.tsx +163 -53
  16. package/src/ReactRenderer.tsx +42 -23
  17. package/src/index.ts +0 -1
  18. package/src/useEditor.ts +253 -92
  19. package/src/useEditorState.ts +122 -69
  20. package/dist/index.umd.js +0 -1176
  21. package/dist/index.umd.js.map +0 -1
  22. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  23. package/dist/packages/core/src/Editor.d.ts +0 -159
  24. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  25. package/dist/packages/core/src/Extension.d.ts +0 -343
  26. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  27. package/dist/packages/core/src/InputRule.d.ts +0 -42
  28. package/dist/packages/core/src/Mark.d.ts +0 -451
  29. package/dist/packages/core/src/Node.d.ts +0 -611
  30. package/dist/packages/core/src/NodePos.d.ts +0 -44
  31. package/dist/packages/core/src/NodeView.d.ts +0 -31
  32. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  33. package/dist/packages/core/src/Tracker.d.ts +0 -11
  34. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  35. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  36. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  37. package/dist/packages/core/src/commands/command.d.ts +0 -18
  38. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  39. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  40. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  41. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  42. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  43. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  44. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  45. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  46. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  47. package/dist/packages/core/src/commands/first.d.ts +0 -14
  48. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  49. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  50. package/dist/packages/core/src/commands/index.d.ts +0 -55
  51. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  52. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  53. package/dist/packages/core/src/commands/join.d.ts +0 -41
  54. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  55. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  56. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  57. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  58. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  59. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  60. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  61. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  62. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  63. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  64. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  65. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  66. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  67. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  68. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  69. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  70. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  71. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  72. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  73. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  74. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  75. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  76. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  77. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  78. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  79. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  80. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  81. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  82. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  83. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  84. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  85. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  86. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  87. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  88. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  89. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  90. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  91. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  92. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  93. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  94. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  95. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  96. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  97. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  98. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  99. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  100. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  101. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  102. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  103. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  104. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  105. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  106. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  107. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  108. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  109. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  110. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  111. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  112. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  113. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  114. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  115. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  116. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  117. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  118. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  119. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  120. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  121. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  122. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  123. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  124. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  125. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  126. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  127. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  128. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  129. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  130. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  131. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  132. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  133. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  134. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  135. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  136. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  137. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  138. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  139. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  140. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  141. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -8
  142. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  143. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  144. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  145. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  146. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  147. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  148. package/dist/packages/core/src/index.d.ts +0 -24
  149. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  150. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  151. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  152. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  153. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  154. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  155. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  156. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  157. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  158. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  159. package/dist/packages/core/src/style.d.ts +0 -1
  160. package/dist/packages/core/src/types.d.ts +0 -253
  161. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  162. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  163. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  164. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  165. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  166. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  167. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  168. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  169. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  170. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  171. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  172. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  173. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  174. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  175. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  176. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  177. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  178. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  179. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  180. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  181. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  182. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
  183. package/dist/packages/extension-bubble-menu/src/bubble-menu-plugin.d.ts +0 -99
  184. package/dist/packages/extension-bubble-menu/src/bubble-menu.d.ts +0 -15
  185. package/dist/packages/extension-bubble-menu/src/index.d.ts +0 -4
  186. package/dist/packages/extension-floating-menu/src/floating-menu-plugin.d.ts +0 -81
  187. package/dist/packages/extension-floating-menu/src/floating-menu.d.ts +0 -15
  188. package/dist/packages/extension-floating-menu/src/index.d.ts +0 -4
  189. package/dist/packages/react/src/BubbleMenu.d.ts +0 -13
  190. package/dist/packages/react/src/Context.d.ts +0 -23
  191. package/dist/packages/react/src/Editor.d.ts +0 -12
  192. package/dist/packages/react/src/EditorContent.d.ts +0 -24
  193. package/dist/packages/react/src/FloatingMenu.d.ts +0 -11
  194. package/dist/packages/react/src/NodeViewContent.d.ts +0 -6
  195. package/dist/packages/react/src/NodeViewWrapper.d.ts +0 -6
  196. package/dist/packages/react/src/ReactNodeViewRenderer.d.ts +0 -16
  197. package/dist/packages/react/src/ReactRenderer.d.ts +0 -62
  198. package/dist/packages/react/src/index.d.ts +0 -13
  199. package/dist/packages/react/src/useEditor.d.ts +0 -39
  200. package/dist/packages/react/src/useEditorState.d.ts +0 -22
  201. package/dist/packages/react/src/useReactNodeView.d.ts +0 -6
package/src/Context.tsx CHANGED
@@ -1,12 +1,14 @@
1
- import React, { createContext, ReactNode, useContext } from 'react'
1
+ import { Editor } from '@tiptap/core'
2
+ import React, {
3
+ createContext, HTMLAttributes, ReactNode, useContext, useMemo,
4
+ } from 'react'
2
5
 
3
- import { Editor } from './Editor.js'
4
6
  import { EditorContent } from './EditorContent.js'
5
7
  import { useEditor, UseEditorOptions } from './useEditor.js'
6
8
 
7
9
  export type EditorContextValue = {
8
10
  editor: Editor | null;
9
- }
11
+ };
10
12
 
11
13
  export const EditorContext = createContext<EditorContextValue>({
12
14
  editor: null,
@@ -23,7 +25,8 @@ export type EditorProviderProps = {
23
25
  children?: ReactNode;
24
26
  slotBefore?: ReactNode;
25
27
  slotAfter?: ReactNode;
26
- } & UseEditorOptions
28
+ editorContainerProps?: HTMLAttributes<HTMLDivElement>;
29
+ } & UseEditorOptions;
27
30
 
28
31
  /**
29
32
  * This is the provider component for the editor.
@@ -31,20 +34,25 @@ export type EditorProviderProps = {
31
34
  * with `useCurrentEditor`.
32
35
  */
33
36
  export function EditorProvider({
34
- children, slotAfter, slotBefore, ...editorOptions
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={{ editor }}>
51
+ <EditorContext.Provider value={contextValue}>
44
52
  {slotBefore}
45
53
  <EditorConsumer>
46
54
  {({ editor: currentEditor }) => (
47
- <EditorContent editor={currentEditor} />
55
+ <EditorContent editor={currentEditor} {...editorContainerProps} />
48
56
  )}
49
57
  </EditorConsumer>
50
58
  {children}
package/src/Editor.ts CHANGED
@@ -1,14 +1,13 @@
1
- import { Editor as CoreEditor } from '@tiptap/core'
2
- import React from 'react'
1
+ import { Editor } from '@tiptap/core'
2
+ import { ReactPortal } from 'react'
3
3
 
4
- import { EditorContentProps, EditorContentState } from './EditorContent.js'
5
4
  import { ReactRenderer } from './ReactRenderer.js'
6
5
 
7
- type ContentComponent = React.Component<EditorContentProps, EditorContentState> & {
6
+ export type EditorWithContentComponent = Editor & { contentComponent?: ContentComponent | null }
7
+ export type ContentComponent = {
8
8
  setRenderer(id: string, renderer: ReactRenderer): void;
9
9
  removeRenderer(id: string): void;
10
- }
11
-
12
- export class Editor extends CoreEditor {
13
- public contentComponent: ContentComponent | null = null
10
+ subscribe: (callback: () => void) => () => void;
11
+ getSnapshot: () => Record<string, ReactPortal>;
12
+ getServerSnapshot: () => Record<string, ReactPortal>;
14
13
  }
@@ -1,9 +1,11 @@
1
+ import { Editor } from '@tiptap/core'
1
2
  import React, {
2
3
  ForwardedRef, forwardRef, HTMLProps, LegacyRef, MutableRefObject,
3
4
  } from 'react'
4
- import ReactDOM, { flushSync } from 'react-dom'
5
+ import ReactDOM from 'react-dom'
6
+ import { useSyncExternalStore } from 'use-sync-external-store/shim'
5
7
 
6
- import { Editor } from './Editor.js'
8
+ import { ContentComponent, EditorWithContentComponent } from './Editor.js'
7
9
  import { ReactRenderer } from './ReactRenderer.js'
8
10
 
9
11
  const mergeRefs = <T extends HTMLDivElement>(
@@ -20,12 +22,23 @@ const mergeRefs = <T extends HTMLDivElement>(
20
22
  }
21
23
  }
22
24
 
23
- const Portals: React.FC<{ renderers: Record<string, ReactRenderer> }> = ({ renderers }) => {
25
+ /**
26
+ * This component renders all of the editor's node views.
27
+ */
28
+ const Portals: React.FC<{ contentComponent: ContentComponent }> = ({
29
+ contentComponent,
30
+ }) => {
31
+ // For performance reasons, we render the node view portals on state changes only
32
+ const renderers = useSyncExternalStore(
33
+ contentComponent.subscribe,
34
+ contentComponent.getSnapshot,
35
+ contentComponent.getServerSnapshot,
36
+ )
37
+
38
+ // This allows us to directly render the portals without any additional wrapper
24
39
  return (
25
40
  <>
26
- {Object.entries(renderers).map(([key, renderer]) => {
27
- return ReactDOM.createPortal(renderer.reactElement, renderer.element, key)
28
- })}
41
+ {Object.values(renderers)}
29
42
  </>
30
43
  )
31
44
  }
@@ -35,22 +48,67 @@ export interface EditorContentProps extends HTMLProps<HTMLDivElement> {
35
48
  innerRef?: ForwardedRef<HTMLDivElement | null>;
36
49
  }
37
50
 
38
- export interface EditorContentState {
39
- renderers: Record<string, ReactRenderer>;
51
+ function getInstance(): ContentComponent {
52
+ const subscribers = new Set<() => void>()
53
+ let renderers: Record<string, React.ReactPortal> = {}
54
+
55
+ return {
56
+ /**
57
+ * Subscribe to the editor instance's changes.
58
+ */
59
+ subscribe(callback: () => void) {
60
+ subscribers.add(callback)
61
+ return () => {
62
+ subscribers.delete(callback)
63
+ }
64
+ },
65
+ getSnapshot() {
66
+ return renderers
67
+ },
68
+ getServerSnapshot() {
69
+ return renderers
70
+ },
71
+ /**
72
+ * Adds a new NodeView Renderer to the editor.
73
+ */
74
+ setRenderer(id: string, renderer: ReactRenderer) {
75
+ renderers = {
76
+ ...renderers,
77
+ [id]: ReactDOM.createPortal(renderer.reactElement, renderer.element, id),
78
+ }
79
+
80
+ subscribers.forEach(subscriber => subscriber())
81
+ },
82
+ /**
83
+ * Removes a NodeView Renderer from the editor.
84
+ */
85
+ removeRenderer(id: string) {
86
+ const nextRenderers = { ...renderers }
87
+
88
+ delete nextRenderers[id]
89
+ renderers = nextRenderers
90
+ subscribers.forEach(subscriber => subscriber())
91
+ },
92
+ }
40
93
  }
41
94
 
42
- export class PureEditorContent extends React.Component<EditorContentProps, EditorContentState> {
95
+ export class PureEditorContent extends React.Component<
96
+ EditorContentProps,
97
+ { hasContentComponentInitialized: boolean }
98
+ > {
43
99
  editorContentRef: React.RefObject<any>
44
100
 
45
101
  initialized: boolean
46
102
 
103
+ unsubscribeToContentComponent?: () => void
104
+
47
105
  constructor(props: EditorContentProps) {
48
106
  super(props)
49
107
  this.editorContentRef = React.createRef()
50
108
  this.initialized = false
51
109
 
52
110
  this.state = {
53
- renderers: {},
111
+ hasContentComponentInitialized: Boolean((props.editor as EditorWithContentComponent | null)?.contentComponent),
54
112
  }
55
113
  }
56
114
 
@@ -63,7 +121,7 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
63
121
  }
64
122
 
65
123
  init() {
66
- const { editor } = this.props
124
+ const editor = this.props.editor as EditorWithContentComponent | null
67
125
 
68
126
  if (editor && !editor.isDestroyed && editor.options.element) {
69
127
  if (editor.contentComponent) {
@@ -78,7 +136,27 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
78
136
  element,
79
137
  })
80
138
 
81
- editor.contentComponent = this
139
+ editor.contentComponent = getInstance()
140
+
141
+ // Has the content component been initialized?
142
+ if (!this.state.hasContentComponentInitialized) {
143
+ // Subscribe to the content component
144
+ this.unsubscribeToContentComponent = editor.contentComponent.subscribe(() => {
145
+ this.setState(prevState => {
146
+ if (!prevState.hasContentComponentInitialized) {
147
+ return {
148
+ hasContentComponentInitialized: true,
149
+ }
150
+ }
151
+ return prevState
152
+ })
153
+
154
+ // Unsubscribe to previous content component
155
+ if (this.unsubscribeToContentComponent) {
156
+ this.unsubscribeToContentComponent()
157
+ }
158
+ })
159
+ }
82
160
 
83
161
  editor.createNodeViews()
84
162
 
@@ -86,43 +164,8 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
86
164
  }
87
165
  }
88
166
 
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
167
  componentWillUnmount() {
125
- const { editor } = this.props
168
+ const editor = this.props.editor as EditorWithContentComponent | null
126
169
 
127
170
  if (!editor) {
128
171
  return
@@ -136,6 +179,10 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
136
179
  })
137
180
  }
138
181
 
182
+ if (this.unsubscribeToContentComponent) {
183
+ this.unsubscribeToContentComponent()
184
+ }
185
+
139
186
  editor.contentComponent = null
140
187
 
141
188
  if (!editor.options.element.firstChild) {
@@ -158,7 +205,7 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
158
205
  <>
159
206
  <div ref={mergeRefs(innerRef, this.editorContentRef)} {...rest} />
160
207
  {/* @ts-ignore */}
161
- <Portals renderers={this.state.renderers} />
208
+ {editor?.contentComponent && <Portals contentComponent={editor.contentComponent} />}
162
209
  </>
163
210
  )
164
211
  }
@@ -168,7 +215,8 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
168
215
  const EditorContentWithKey = forwardRef<HTMLDivElement, EditorContentProps>(
169
216
  (props: Omit<EditorContentProps, 'innerRef'>, ref) => {
170
217
  const key = React.useMemo(() => {
171
- return Math.floor(Math.random() * 0xFFFFFFFF).toString()
218
+ return Math.floor(Math.random() * 0xffffffff).toString()
219
+ // eslint-disable-next-line react-hooks/exhaustive-deps
172
220
  }, [props.editor])
173
221
 
174
222
  // Can't use JSX here because it conflicts with the type definition of Vue's JSX, so use createElement
@@ -1,77 +1,83 @@
1
1
  import { FloatingMenuPlugin, FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'
2
- import React, {
3
- useEffect, useRef,
4
- } from 'react'
2
+ import React, { useEffect, useRef } from 'react'
5
3
  import { createPortal } from 'react-dom'
6
4
 
7
5
  import { useCurrentEditor } from './Context.js'
8
6
 
9
- type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
7
+ type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
10
8
 
11
- export type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {
9
+ export type FloatingMenuProps = Omit<
10
+ Optional<FloatingMenuPluginProps, 'pluginKey'>,
11
+ 'element' | 'editor'
12
+ > & {
12
13
  editor: FloatingMenuPluginProps['editor'] | null;
13
- className?: string,
14
- children: React.ReactNode
15
- options?: FloatingMenuPluginProps['options']
16
- }
14
+ options?: FloatingMenuPluginProps['options'];
15
+ } & React.HTMLAttributes<HTMLDivElement>;
17
16
 
18
- export const FloatingMenu = (props: FloatingMenuProps) => {
17
+ export const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(({
18
+ pluginKey = 'floatingMenu',
19
+ editor,
20
+ shouldShow = null,
21
+ options,
22
+ children,
23
+ ...restProps
24
+ }, ref) => {
19
25
  const menuEl = useRef(document.createElement('div'))
26
+
27
+ if (typeof ref === 'function') {
28
+ ref(menuEl.current)
29
+ } else if (ref) {
30
+ ref.current = menuEl.current
31
+ }
32
+
20
33
  const { editor: currentEditor } = useCurrentEditor()
21
34
 
22
35
  useEffect(() => {
23
- menuEl.current.style.visibility = 'hidden'
24
- menuEl.current.style.position = 'absolute'
36
+ const floatingMenuElement = menuEl.current
37
+
38
+ floatingMenuElement.style.visibility = 'hidden'
39
+ floatingMenuElement.style.position = 'absolute'
25
40
 
26
- if (props.editor?.isDestroyed || currentEditor?.isDestroyed) {
41
+ if (editor?.isDestroyed || currentEditor?.isDestroyed) {
27
42
  return
28
43
  }
29
44
 
30
- const {
31
- pluginKey = 'floatingMenu',
32
- editor,
33
- options,
34
- shouldShow = null,
35
- } = props
36
-
37
- const menuEditor = editor || currentEditor
45
+ const attachToEditor = editor || currentEditor
38
46
 
39
- if (!menuEditor) {
40
- console.warn('FloatingMenu component is not rendered inside of an editor component or does not have editor prop.')
47
+ if (!attachToEditor) {
48
+ console.warn(
49
+ 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',
50
+ )
41
51
  return
42
52
  }
43
53
 
44
54
  const plugin = FloatingMenuPlugin({
55
+ editor: attachToEditor,
56
+ element: floatingMenuElement,
45
57
  pluginKey,
46
- editor: menuEditor,
47
- element: menuEl.current,
48
- options,
49
58
  shouldShow,
59
+ options,
50
60
  })
51
61
 
52
- menuEditor.registerPlugin(plugin)
62
+ attachToEditor.registerPlugin(plugin)
63
+
53
64
  return () => {
54
- menuEditor.unregisterPlugin(pluginKey)
65
+ attachToEditor.unregisterPlugin(pluginKey)
55
66
  window.requestAnimationFrame(() => {
56
- if (menuEl.current.parentNode) {
57
- menuEl.current.parentNode.removeChild(menuEl.current)
67
+ if (floatingMenuElement.parentNode) {
68
+ floatingMenuElement.parentNode.removeChild(floatingMenuElement)
58
69
  }
59
70
  })
60
71
  }
61
- }, [
62
- props.editor,
63
- currentEditor,
64
- ])
65
-
66
- const portal = createPortal(
67
- (
68
- <div className={props.className}>
69
- {props.children}
70
- </div>
71
- ), menuEl.current,
72
- )
72
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
+ }, [editor, currentEditor])
73
74
 
74
- return (
75
- <>{portal}</>
75
+ return createPortal(
76
+ <div
77
+ {...restProps}
78
+ >
79
+ {children}
80
+ </div>,
81
+ menuEl.current,
76
82
  )
77
- }
83
+ })
@@ -12,6 +12,7 @@ export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
12
12
  const { nodeViewContentRef } = useReactNodeView()
13
13
 
14
14
  return (
15
+ // @ts-ignore
15
16
  <Tag
16
17
  {...props}
17
18
  ref={nodeViewContentRef}
@@ -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}