@tiptap/react 2.11.7 → 3.0.0-beta.1

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 (59) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +967 -1473
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +345 -0
  6. package/dist/index.d.ts +344 -12
  7. package/dist/index.js +916 -1452
  8. package/dist/index.js.map +1 -1
  9. package/dist/menus/index.cjs +142 -0
  10. package/dist/menus/index.cjs.map +1 -0
  11. package/dist/menus/index.d.cts +19 -0
  12. package/dist/menus/index.d.ts +19 -0
  13. package/dist/menus/index.js +104 -0
  14. package/dist/menus/index.js.map +1 -0
  15. package/package.json +30 -18
  16. package/src/Context.tsx +18 -15
  17. package/src/Editor.ts +8 -8
  18. package/src/EditorContent.tsx +14 -22
  19. package/src/NodeViewContent.tsx +12 -8
  20. package/src/NodeViewWrapper.tsx +2 -2
  21. package/src/ReactMarkViewRenderer.tsx +109 -0
  22. package/src/ReactNodeViewRenderer.tsx +32 -50
  23. package/src/ReactRenderer.tsx +17 -26
  24. package/src/index.ts +1 -2
  25. package/src/menus/BubbleMenu.tsx +68 -0
  26. package/src/menus/FloatingMenu.tsx +68 -0
  27. package/src/menus/index.ts +2 -0
  28. package/src/useEditor.ts +32 -26
  29. package/src/useEditorState.ts +14 -19
  30. package/src/useReactNodeView.ts +21 -5
  31. package/dist/BubbleMenu.d.ts +0 -12
  32. package/dist/BubbleMenu.d.ts.map +0 -1
  33. package/dist/Context.d.ts +0 -25
  34. package/dist/Context.d.ts.map +0 -1
  35. package/dist/Editor.d.ts +0 -14
  36. package/dist/Editor.d.ts.map +0 -1
  37. package/dist/EditorContent.d.ts +0 -21
  38. package/dist/EditorContent.d.ts.map +0 -1
  39. package/dist/FloatingMenu.d.ts +0 -11
  40. package/dist/FloatingMenu.d.ts.map +0 -1
  41. package/dist/NodeViewContent.d.ts +0 -7
  42. package/dist/NodeViewContent.d.ts.map +0 -1
  43. package/dist/NodeViewWrapper.d.ts +0 -7
  44. package/dist/NodeViewWrapper.d.ts.map +0 -1
  45. package/dist/ReactNodeViewRenderer.d.ts +0 -96
  46. package/dist/ReactNodeViewRenderer.d.ts.map +0 -1
  47. package/dist/ReactRenderer.d.ts +0 -71
  48. package/dist/ReactRenderer.d.ts.map +0 -1
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/index.umd.js +0 -1540
  51. package/dist/index.umd.js.map +0 -1
  52. package/dist/useEditor.d.ts +0 -39
  53. package/dist/useEditor.d.ts.map +0 -1
  54. package/dist/useEditorState.d.ts +0 -45
  55. package/dist/useEditorState.d.ts.map +0 -1
  56. package/dist/useReactNodeView.d.ts +0 -7
  57. package/dist/useReactNodeView.d.ts.map +0 -1
  58. package/src/BubbleMenu.tsx +0 -57
  59. package/src/FloatingMenu.tsx +0 -64
@@ -1,19 +1,14 @@
1
- import {
2
- DecorationWithType,
3
- Editor,
4
- getRenderedAttributes,
5
- NodeView,
6
- NodeViewProps,
7
- NodeViewRenderer,
8
- NodeViewRendererOptions,
9
- } from '@tiptap/core'
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'
13
-
14
- import { EditorWithContentComponent } from './Editor.js'
1
+ import type { DecorationWithType, Editor, NodeViewProps, NodeViewRenderer, NodeViewRendererOptions } from '@tiptap/core'
2
+ import { getRenderedAttributes, NodeView } from '@tiptap/core'
3
+ import type { Node, Node as ProseMirrorNode } from '@tiptap/pm/model'
4
+ import type { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
5
+ import type { ComponentType } from 'react'
6
+ import React from 'react'
7
+
8
+ import type { EditorWithContentComponent } from './Editor.js'
15
9
  import { ReactRenderer } from './ReactRenderer.js'
16
- import { ReactNodeViewContext, ReactNodeViewContextProps } from './useReactNodeView.js'
10
+ import type { ReactNodeViewContextProps } from './useReactNodeView.js'
11
+ import { ReactNodeViewContext } from './useReactNodeView.js'
17
12
 
18
13
  export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
19
14
  /**
@@ -22,23 +17,23 @@ export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
22
17
  */
23
18
  update:
24
19
  | ((props: {
25
- oldNode: ProseMirrorNode;
26
- oldDecorations: readonly Decoration[];
27
- oldInnerDecorations: DecorationSource;
28
- newNode: ProseMirrorNode;
29
- newDecorations: readonly Decoration[];
30
- innerDecorations: DecorationSource;
31
- updateProps: () => void;
20
+ oldNode: ProseMirrorNode
21
+ oldDecorations: readonly Decoration[]
22
+ oldInnerDecorations: DecorationSource
23
+ newNode: ProseMirrorNode
24
+ newDecorations: readonly Decoration[]
25
+ innerDecorations: DecorationSource
26
+ updateProps: () => void
32
27
  }) => boolean)
33
- | null;
28
+ | null
34
29
  /**
35
30
  * The tag name of the element wrapping the React component.
36
31
  */
37
- as?: string;
32
+ as?: string
38
33
  /**
39
34
  * The class name of the element wrapping the React component.
40
35
  */
41
- className?: string;
36
+ className?: string
42
37
  /**
43
38
  * Attributes that should be applied to the element wrapping the React component.
44
39
  * If this is a function, it will be called each time the node view is updated.
@@ -46,10 +41,7 @@ export interface ReactNodeViewRendererOptions extends NodeViewRendererOptions {
46
41
  */
47
42
  attrs?:
48
43
  | Record<string, string>
49
- | ((props: {
50
- node: ProseMirrorNode;
51
- HTMLAttributes: Record<string, any>;
52
- }) => Record<string, string>);
44
+ | ((props: { node: ProseMirrorNode; HTMLAttributes: Record<string, any> }) => Record<string, string>)
53
45
  }
54
46
 
55
47
  export class ReactNodeView<
@@ -104,15 +96,13 @@ export class ReactNodeView<
104
96
  const Component = this.component
105
97
  // For performance reasons, we memoize the provider component
106
98
  // 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
- )
99
+ const ReactNodeViewProvider: React.FunctionComponent<NodeViewProps> = React.memo(componentProps => {
100
+ return (
101
+ <ReactNodeViewContext.Provider value={context}>
102
+ {React.createElement(Component, componentProps)}
103
+ </ReactNodeViewContext.Provider>
104
+ )
105
+ })
116
106
 
117
107
  ReactNodeViewProvider.displayName = 'ReactNodeView'
118
108
 
@@ -159,8 +149,8 @@ export class ReactNodeView<
159
149
  */
160
150
  get dom() {
161
151
  if (
162
- this.renderer.element.firstElementChild
163
- && !this.renderer.element.firstElementChild?.hasAttribute('data-node-view-wrapper')
152
+ this.renderer.element.firstElementChild &&
153
+ !this.renderer.element.firstElementChild?.hasAttribute('data-node-view-wrapper')
164
154
  ) {
165
155
  throw Error('Please use the NodeViewWrapper component for your node view.')
166
156
  }
@@ -211,11 +201,7 @@ export class ReactNodeView<
211
201
  * On update, update the React component.
212
202
  * To prevent unnecessary updates, the `update` option can be used.
213
203
  */
214
- update(
215
- node: Node,
216
- decorations: readonly Decoration[],
217
- innerDecorations: DecorationSource,
218
- ): boolean {
204
+ update(node: Node, decorations: readonly Decoration[], innerDecorations: DecorationSource): boolean {
219
205
  const rerenderComponent = (props?: Record<string, any>) => {
220
206
  this.renderer.updateProps(props)
221
207
  if (typeof this.options.attrs === 'function') {
@@ -247,11 +233,7 @@ export class ReactNodeView<
247
233
  })
248
234
  }
249
235
 
250
- if (
251
- node === this.node
252
- && this.decorations === decorations
253
- && this.innerDecorations === innerDecorations
254
- ) {
236
+ if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
255
237
  return true
256
238
  }
257
239
 
@@ -1,8 +1,8 @@
1
- import { Editor } from '@tiptap/core'
1
+ import type { Editor } from '@tiptap/core'
2
2
  import React from 'react'
3
3
  import { flushSync } from 'react-dom'
4
4
 
5
- import { EditorWithContentComponent } from './Editor.js'
5
+ import type { EditorWithContentComponent } from './Editor.js'
6
6
 
7
7
  /**
8
8
  * Check if a component is a class component.
@@ -10,11 +10,7 @@ import { EditorWithContentComponent } from './Editor.js'
10
10
  * @returns {boolean}
11
11
  */
12
12
  function isClassComponent(Component: any) {
13
- return !!(
14
- typeof Component === 'function'
15
- && Component.prototype
16
- && Component.prototype.isReactComponent
17
- )
13
+ return !!(typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent)
18
14
  }
19
15
 
20
16
  /**
@@ -23,10 +19,7 @@ function isClassComponent(Component: any) {
23
19
  * @returns {boolean}
24
20
  */
25
21
  function isForwardRefComponent(Component: any) {
26
- return !!(
27
- typeof Component === 'object'
28
- && Component.$$typeof?.toString() === 'Symbol(react.forward_ref)'
29
- )
22
+ return !!(typeof Component === 'object' && Component.$$typeof?.toString() === 'Symbol(react.forward_ref)')
30
23
  }
31
24
 
32
25
  export interface ReactRendererOptions {
@@ -34,21 +27,21 @@ export interface ReactRendererOptions {
34
27
  * The editor instance.
35
28
  * @type {Editor}
36
29
  */
37
- editor: Editor,
30
+ editor: Editor
38
31
 
39
32
  /**
40
33
  * The props for the component.
41
34
  * @type {Record<string, any>}
42
35
  * @default {}
43
36
  */
44
- props?: Record<string, any>,
37
+ props?: Record<string, any>
45
38
 
46
39
  /**
47
40
  * The tag name of the element.
48
41
  * @type {string}
49
42
  * @default 'div'
50
43
  */
51
- as?: string,
44
+ as?: string
52
45
 
53
46
  /**
54
47
  * The class name of the element.
@@ -56,13 +49,13 @@ export interface ReactRendererOptions {
56
49
  * @default ''
57
50
  * @example 'foo bar'
58
51
  */
59
- className?: string,
52
+ className?: string
60
53
  }
61
54
 
62
55
  type ComponentType<R, P> =
63
- React.ComponentClass<P> |
64
- React.FunctionComponent<P> |
65
- React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<R>>;
56
+ | React.ComponentClass<P>
57
+ | React.FunctionComponent<P>
58
+ | React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<R>>
66
59
 
67
60
  /**
68
61
  * The ReactRenderer class. It's responsible for rendering React components inside the editor.
@@ -74,7 +67,7 @@ type ComponentType<R, P> =
74
67
  * },
75
68
  * as: 'span',
76
69
  * })
77
- */
70
+ */
78
71
  export class ReactRenderer<R = unknown, P extends Record<string, any> = object> {
79
72
  id: string
80
73
 
@@ -93,13 +86,11 @@ export class ReactRenderer<R = unknown, P extends Record<string, any> = object>
93
86
  /**
94
87
  * Immediately creates element and renders the provided React component.
95
88
  */
96
- constructor(component: ComponentType<R, P>, {
97
- editor,
98
- props = {},
99
- as = 'div',
100
- className = '',
101
- }: ReactRendererOptions) {
102
- this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
89
+ constructor(
90
+ component: ComponentType<R, P>,
91
+ { editor, props = {}, as = 'div', className = '' }: ReactRendererOptions,
92
+ ) {
93
+ this.id = Math.floor(Math.random() * 0xffffffff).toString()
103
94
  this.component = component
104
95
  this.editor = editor as EditorWithContentComponent
105
96
  this.props = props as P
package/src/index.ts CHANGED
@@ -1,9 +1,8 @@
1
- export * from './BubbleMenu.js'
2
1
  export * from './Context.js'
3
2
  export * from './EditorContent.js'
4
- export * from './FloatingMenu.js'
5
3
  export * from './NodeViewContent.js'
6
4
  export * from './NodeViewWrapper.js'
5
+ export * from './ReactMarkViewRenderer.js'
7
6
  export * from './ReactNodeViewRenderer.js'
8
7
  export * from './ReactRenderer.js'
9
8
  export * from './useEditor.js'
@@ -0,0 +1,68 @@
1
+ import { type BubbleMenuPluginProps, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'
2
+ import { useCurrentEditor } from '@tiptap/react'
3
+ import React, { useEffect, useRef } from 'react'
4
+ import { createPortal } from 'react-dom'
5
+
6
+ type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
7
+
8
+ export type BubbleMenuProps = Optional<Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element'>, 'editor'> &
9
+ React.HTMLAttributes<HTMLDivElement>
10
+
11
+ export const BubbleMenu = React.forwardRef<HTMLDivElement, BubbleMenuProps>(
12
+ (
13
+ { pluginKey = 'bubbleMenu', editor, updateDelay, resizeDelay, shouldShow = null, options, children, ...restProps },
14
+ ref,
15
+ ) => {
16
+ const menuEl = useRef(document.createElement('div'))
17
+
18
+ if (typeof ref === 'function') {
19
+ ref(menuEl.current)
20
+ } else if (ref) {
21
+ ref.current = menuEl.current
22
+ }
23
+
24
+ const { editor: currentEditor } = useCurrentEditor()
25
+
26
+ useEffect(() => {
27
+ const bubbleMenuElement = menuEl.current
28
+
29
+ bubbleMenuElement.style.visibility = 'hidden'
30
+ bubbleMenuElement.style.position = 'absolute'
31
+
32
+ if (editor?.isDestroyed || (currentEditor as any)?.isDestroyed) {
33
+ return
34
+ }
35
+
36
+ const attachToEditor = editor || currentEditor
37
+
38
+ if (!attachToEditor) {
39
+ console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.')
40
+ return
41
+ }
42
+
43
+ const plugin = BubbleMenuPlugin({
44
+ updateDelay,
45
+ resizeDelay,
46
+ editor: attachToEditor,
47
+ element: bubbleMenuElement,
48
+ pluginKey,
49
+ shouldShow,
50
+ options,
51
+ })
52
+
53
+ attachToEditor.registerPlugin(plugin)
54
+
55
+ return () => {
56
+ attachToEditor.unregisterPlugin(pluginKey)
57
+ window.requestAnimationFrame(() => {
58
+ if (bubbleMenuElement.parentNode) {
59
+ bubbleMenuElement.parentNode.removeChild(bubbleMenuElement)
60
+ }
61
+ })
62
+ }
63
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
+ }, [editor, currentEditor])
65
+
66
+ return createPortal(<div {...restProps}>{children}</div>, menuEl.current)
67
+ },
68
+ )
@@ -0,0 +1,68 @@
1
+ import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'
2
+ import { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'
3
+ import { useCurrentEditor } from '@tiptap/react'
4
+ import React, { useEffect, useRef } from 'react'
5
+ import { createPortal } from 'react-dom'
6
+
7
+ type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>
8
+
9
+ export type FloatingMenuProps = Omit<Optional<FloatingMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {
10
+ editor: FloatingMenuPluginProps['editor'] | null
11
+ options?: FloatingMenuPluginProps['options']
12
+ } & React.HTMLAttributes<HTMLDivElement>
13
+
14
+ export const FloatingMenu = React.forwardRef<HTMLDivElement, FloatingMenuProps>(
15
+ ({ pluginKey = 'floatingMenu', editor, shouldShow = null, options, children, ...restProps }, ref) => {
16
+ const menuEl = useRef(document.createElement('div'))
17
+
18
+ if (typeof ref === 'function') {
19
+ ref(menuEl.current)
20
+ } else if (ref) {
21
+ ref.current = menuEl.current
22
+ }
23
+
24
+ const { editor: currentEditor } = useCurrentEditor()
25
+
26
+ useEffect(() => {
27
+ const floatingMenuElement = menuEl.current
28
+
29
+ floatingMenuElement.style.visibility = 'hidden'
30
+ floatingMenuElement.style.position = 'absolute'
31
+
32
+ if (editor?.isDestroyed || (currentEditor as any)?.isDestroyed) {
33
+ return
34
+ }
35
+
36
+ const attachToEditor = editor || currentEditor
37
+
38
+ if (!attachToEditor) {
39
+ console.warn(
40
+ 'FloatingMenu component is not rendered inside of an editor component or does not have editor prop.',
41
+ )
42
+ return
43
+ }
44
+
45
+ const plugin = FloatingMenuPlugin({
46
+ editor: attachToEditor,
47
+ element: floatingMenuElement,
48
+ pluginKey,
49
+ shouldShow,
50
+ options,
51
+ })
52
+
53
+ attachToEditor.registerPlugin(plugin)
54
+
55
+ return () => {
56
+ attachToEditor.unregisterPlugin(pluginKey)
57
+ window.requestAnimationFrame(() => {
58
+ if (floatingMenuElement.parentNode) {
59
+ floatingMenuElement.parentNode.removeChild(floatingMenuElement)
60
+ }
61
+ })
62
+ }
63
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
+ }, [editor, currentEditor])
65
+
66
+ return createPortal(<div {...restProps}>{children}</div>, menuEl.current)
67
+ },
68
+ )
@@ -0,0 +1,2 @@
1
+ export * from './BubbleMenu.js'
2
+ export * from './FloatingMenu.js'
package/src/useEditor.ts CHANGED
@@ -1,16 +1,11 @@
1
1
  import { type EditorOptions, Editor } from '@tiptap/core'
2
- import {
3
- DependencyList,
4
- MutableRefObject,
5
- useDebugValue,
6
- useEffect,
7
- useRef,
8
- useState,
9
- } from 'react'
2
+ import type { DependencyList, MutableRefObject } from 'react'
3
+ import { useDebugValue, useEffect, useRef, useState } from 'react'
10
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim'
11
5
 
12
6
  import { useEditorState } from './useEditorState.js'
13
7
 
8
+ // @ts-ignore
14
9
  const isDev = process.env.NODE_ENV !== 'production'
15
10
  const isSSR = typeof window === 'undefined'
16
11
  const isNext = isSSR || Boolean(typeof window !== 'undefined' && (window as any).next)
@@ -25,14 +20,14 @@ export type UseEditorOptions = Partial<EditorOptions> & {
25
20
  * If server-side rendering, set this to `false`.
26
21
  * @default true
27
22
  */
28
- immediatelyRender?: boolean;
23
+ immediatelyRender?: boolean
29
24
  /**
30
25
  * Whether to re-render the editor on each transaction.
31
26
  * This is legacy behavior that will be removed in future versions.
32
- * @default true
27
+ * @default false
33
28
  */
34
- shouldRerenderOnTransaction?: boolean;
35
- };
29
+ shouldRerenderOnTransaction?: boolean
30
+ }
36
31
 
37
32
  /**
38
33
  * This class handles the creation, destruction, and re-creation of the editor instance.
@@ -100,13 +95,12 @@ class EditorInstanceManager {
100
95
  private getInitialEditor() {
101
96
  if (this.options.current.immediatelyRender === undefined) {
102
97
  if (isSSR || isNext) {
103
- // TODO in the next major release, we should throw an error here
104
98
  if (isDev) {
105
99
  /**
106
100
  * Throw an error in development, to make sure the developer is aware that tiptap cannot be SSR'd
107
101
  * and that they need to set `immediatelyRender` to `false` to avoid hydration mismatches.
108
102
  */
109
- console.warn(
103
+ throw new Error(
110
104
  'Tiptap Error: SSR has been detected, please set `immediatelyRender` explicitly to `false` to avoid hydration mismatches.',
111
105
  )
112
106
  }
@@ -151,6 +145,7 @@ class EditorInstanceManager {
151
145
  onContentError: (...args) => this.options.current.onContentError?.(...args),
152
146
  onDrop: (...args) => this.options.current.onDrop?.(...args),
153
147
  onPaste: (...args) => this.options.current.onPaste?.(...args),
148
+ onDelete: (...args) => this.options.current.onDelete?.(...args),
154
149
  }
155
150
  const editor = new Editor(optionsToApply)
156
151
 
@@ -186,7 +181,21 @@ class EditorInstanceManager {
186
181
 
187
182
  static compareOptions(a: UseEditorOptions, b: UseEditorOptions) {
188
183
  return (Object.keys(a) as (keyof UseEditorOptions)[]).every(key => {
189
- if (['onCreate', 'onBeforeCreate', 'onDestroy', 'onUpdate', 'onTransaction', 'onFocus', 'onBlur', 'onSelectionUpdate', 'onContentError', 'onDrop', 'onPaste'].includes(key)) {
184
+ if (
185
+ [
186
+ 'onCreate',
187
+ 'onBeforeCreate',
188
+ 'onDestroy',
189
+ 'onUpdate',
190
+ 'onTransaction',
191
+ 'onFocus',
192
+ 'onBlur',
193
+ 'onSelectionUpdate',
194
+ 'onContentError',
195
+ 'onDrop',
196
+ 'onPaste',
197
+ ].includes(key)
198
+ ) {
190
199
  // we don't want to compare callbacks, they are always different and only registered once
191
200
  return true
192
201
  }
@@ -260,8 +269,8 @@ class EditorInstanceManager {
260
269
  this.previousDeps = deps
261
270
  return
262
271
  }
263
- const depsAreEqual = this.previousDeps.length === deps.length
264
- && this.previousDeps.every((dep, index) => dep === deps[index])
272
+ const depsAreEqual =
273
+ this.previousDeps.length === deps.length && this.previousDeps.every((dep, index) => dep === deps[index])
265
274
 
266
275
  if (depsAreEqual) {
267
276
  // deps exist and are equal, no need to recreate
@@ -319,9 +328,9 @@ class EditorInstanceManager {
319
328
  * @example const editor = useEditor({ extensions: [...] })
320
329
  */
321
330
  export function useEditor(
322
- options: UseEditorOptions & { immediatelyRender: true },
323
- deps?: DependencyList
324
- ): Editor;
331
+ options: UseEditorOptions & { immediatelyRender: false },
332
+ deps?: DependencyList,
333
+ ): Editor | null
325
334
 
326
335
  /**
327
336
  * This hook allows you to create an editor instance.
@@ -330,12 +339,9 @@ export function useEditor(
330
339
  * @returns The editor instance
331
340
  * @example const editor = useEditor({ extensions: [...] })
332
341
  */
333
- export function useEditor(options?: UseEditorOptions, deps?: DependencyList): Editor | null;
342
+ export function useEditor(options: UseEditorOptions, deps?: DependencyList): Editor
334
343
 
335
- export function useEditor(
336
- options: UseEditorOptions = {},
337
- deps: DependencyList = [],
338
- ): Editor | null {
344
+ export function useEditor(options: UseEditorOptions = {}, deps: DependencyList = []): Editor | null {
339
345
  const mostRecentOptions = useRef(options)
340
346
 
341
347
  mostRecentOptions.current = options
@@ -359,7 +365,7 @@ export function useEditor(
359
365
  useEditorState({
360
366
  editor,
361
367
  selector: ({ transactionNumber }) => {
362
- if (options.shouldRerenderOnTransaction === false) {
368
+ if (options.shouldRerenderOnTransaction === false || options.shouldRerenderOnTransaction === undefined) {
363
369
  // This will prevent the editor from re-rendering on each transaction
364
370
  return null
365
371
  }
@@ -1,35 +1,30 @@
1
1
  import type { Editor } from '@tiptap/core'
2
2
  import deepEqual from 'fast-deep-equal/es6/react'
3
- import {
4
- useDebugValue, useEffect, useLayoutEffect, useState,
5
- } from 'react'
3
+ import { useDebugValue, useEffect, useLayoutEffect, useState } from 'react'
6
4
  import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
7
5
 
8
6
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect
9
7
 
10
8
  export type EditorStateSnapshot<TEditor extends Editor | null = Editor | null> = {
11
- editor: TEditor;
12
- transactionNumber: number;
13
- };
14
-
15
- export type UseEditorStateOptions<
16
- TSelectorResult,
17
- TEditor extends Editor | null = Editor | null,
18
- > = {
9
+ editor: TEditor
10
+ transactionNumber: number
11
+ }
12
+
13
+ export type UseEditorStateOptions<TSelectorResult, TEditor extends Editor | null = Editor | null> = {
19
14
  /**
20
15
  * The editor instance.
21
16
  */
22
- editor: TEditor;
17
+ editor: TEditor
23
18
  /**
24
19
  * A selector function to determine the value to compare for re-rendering.
25
20
  */
26
- selector: (context: EditorStateSnapshot<TEditor>) => TSelectorResult;
21
+ selector: (context: EditorStateSnapshot<TEditor>) => TSelectorResult
27
22
  /**
28
23
  * A custom equality function to determine if the editor should re-render.
29
24
  * @default `deepEqual` from `fast-deep-equal`
30
25
  */
31
- equalityFn?: (a: TSelectorResult, b: TSelectorResult | null) => boolean;
32
- };
26
+ equalityFn?: (a: TSelectorResult, b: TSelectorResult | null) => boolean
27
+ }
33
28
 
34
29
  /**
35
30
  * To synchronize the editor instance with the component state,
@@ -126,8 +121,8 @@ class EditorStateManager<TEditor extends Editor | null = Editor | null> {
126
121
  * })
127
122
  */
128
123
  export function useEditorState<TSelectorResult>(
129
- options: UseEditorStateOptions<TSelectorResult, Editor>
130
- ): TSelectorResult;
124
+ options: UseEditorStateOptions<TSelectorResult, Editor>,
125
+ ): TSelectorResult
131
126
  /**
132
127
  * This hook allows you to watch for changes on the editor instance.
133
128
  * It will allow you to select a part of the editor state and re-render the component when it changes.
@@ -140,8 +135,8 @@ export function useEditorState<TSelectorResult>(
140
135
  * })
141
136
  */
142
137
  export function useEditorState<TSelectorResult>(
143
- options: UseEditorStateOptions<TSelectorResult, Editor | null>
144
- ): TSelectorResult | null;
138
+ options: UseEditorStateOptions<TSelectorResult, Editor | null>,
139
+ ): TSelectorResult | null
145
140
 
146
141
  /**
147
142
  * This hook allows you to watch for changes on the editor instance.
@@ -1,12 +1,28 @@
1
- import { createContext, useContext } from 'react'
1
+ import type { ReactNode } from 'react'
2
+ import { createContext, createElement, useContext } from 'react'
2
3
 
3
4
  export interface ReactNodeViewContextProps {
4
- onDragStart: (event: DragEvent) => void,
5
- nodeViewContentRef: (element: HTMLElement | null) => void,
5
+ onDragStart?: (event: DragEvent) => void
6
+ nodeViewContentRef?: (element: HTMLElement | null) => void
7
+ /**
8
+ * This allows you to add children into the NodeViewContent component.
9
+ * This is useful when statically rendering the content of a node view.
10
+ */
11
+ nodeViewContentChildren?: ReactNode
6
12
  }
7
13
 
8
- export const ReactNodeViewContext = createContext<Partial<ReactNodeViewContextProps>>({
9
- onDragStart: undefined,
14
+ export const ReactNodeViewContext = createContext<ReactNodeViewContextProps>({
15
+ onDragStart: () => {
16
+ // no-op
17
+ },
18
+ nodeViewContentChildren: undefined,
19
+ nodeViewContentRef: () => {
20
+ // no-op
21
+ },
10
22
  })
11
23
 
24
+ export const ReactNodeViewContentProvider = ({ children, content }: { children: ReactNode; content: ReactNode }) => {
25
+ return createElement(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children)
26
+ }
27
+
12
28
  export const useReactNodeView = () => useContext(ReactNodeViewContext)
@@ -1,12 +0,0 @@
1
- import { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu';
2
- import React from 'react';
3
- type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
4
- export type BubbleMenuProps = Omit<Optional<BubbleMenuPluginProps, 'pluginKey'>, 'element' | 'editor'> & {
5
- editor: BubbleMenuPluginProps['editor'] | null;
6
- className?: string;
7
- children: React.ReactNode;
8
- updateDelay?: number;
9
- };
10
- export declare const BubbleMenu: (props: BubbleMenuProps) => React.JSX.Element;
11
- export {};
12
- //# sourceMappingURL=BubbleMenu.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BubbleMenu.d.ts","sourceRoot":"","sources":["../src/BubbleMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AACvF,OAAO,KAA8B,MAAM,OAAO,CAAA;AAIlD,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEvE,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,qBAAqB,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC,GAAG;IACvG,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,UAAU,UAAW,eAAe,sBA0ChD,CAAA"}
package/dist/Context.d.ts DELETED
@@ -1,25 +0,0 @@
1
- import { Editor } from '@tiptap/core';
2
- import React, { HTMLAttributes, ReactNode } from 'react';
3
- import { UseEditorOptions } from './useEditor.js';
4
- export type EditorContextValue = {
5
- editor: Editor | null;
6
- };
7
- export declare const EditorContext: React.Context<EditorContextValue>;
8
- export declare const EditorConsumer: React.Consumer<EditorContextValue>;
9
- /**
10
- * A hook to get the current editor instance.
11
- */
12
- export declare const useCurrentEditor: () => EditorContextValue;
13
- export type EditorProviderProps = {
14
- children?: ReactNode;
15
- slotBefore?: ReactNode;
16
- slotAfter?: ReactNode;
17
- editorContainerProps?: HTMLAttributes<HTMLDivElement>;
18
- } & UseEditorOptions;
19
- /**
20
- * This is the provider component for the editor.
21
- * It allows the editor to be accessible across the entire component tree
22
- * with `useCurrentEditor`.
23
- */
24
- export declare function EditorProvider({ children, slotAfter, slotBefore, editorContainerProps, ...editorOptions }: EditorProviderProps): React.JSX.Element | null;
25
- //# sourceMappingURL=Context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Context.d.ts","sourceRoot":"","sources":["../src/Context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,EACG,cAAc,EAAE,SAAS,EACzC,MAAM,OAAO,CAAA;AAGd,OAAO,EAAa,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE5D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAA;AAED,eAAO,MAAM,aAAa,mCAExB,CAAA;AAEF,eAAO,MAAM,cAAc,oCAAyB,CAAA;AAEpD;;GAEG;AACH,eAAO,MAAM,gBAAgB,0BAAkC,CAAA;AAE/D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,oBAAoB,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CACvD,GAAG,gBAAgB,CAAA;AAEpB;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,oBAAyB,EAAE,GAAG,aAAa,EAC7E,EAAE,mBAAmB,4BAmBrB"}