@handlewithcare/react-prosemirror 2.6.0-tiptap.0 → 2.6.0-tiptap.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.
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "TiptapEditorContent", {
10
10
  });
11
11
  const _react = require("@tiptap/react");
12
12
  const _react1 = /*#__PURE__*/ _interop_require_wildcard(require("react"));
13
+ const _reactdom = require("react-dom");
13
14
  const _ProseMirrorDoc = require("../components/ProseMirrorDoc.js");
14
15
  const _useEditorEffect = require("../hooks/useEditorEffect.js");
15
16
  function _getRequireWildcardCache(nodeInterop) {
@@ -53,18 +54,62 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
54
  }
54
55
  return newObj;
55
56
  }
57
+ /**
58
+ * This component renders all of the editor's registered "React renderers".
59
+ */ const Portals = (param)=>{
60
+ let { contentComponent } = param;
61
+ const renderers = (0, _react1.useSyncExternalStore)(contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot);
62
+ return /*#__PURE__*/ _react1.default.createElement(_react1.default.Fragment, null, Object.values(renderers));
63
+ };
64
+ function getInstance() {
65
+ const subscribers = new Set();
66
+ let renderers = {};
67
+ return {
68
+ /**
69
+ * Subscribe to the editor instance's changes.
70
+ */ subscribe (callback) {
71
+ subscribers.add(callback);
72
+ return ()=>{
73
+ subscribers.delete(callback);
74
+ };
75
+ },
76
+ getSnapshot () {
77
+ return renderers;
78
+ },
79
+ getServerSnapshot () {
80
+ return renderers;
81
+ },
82
+ /**
83
+ * Adds a new React Renderer to the editor.
84
+ */ setRenderer (id, renderer) {
85
+ renderers = {
86
+ ...renderers,
87
+ [id]: /*#__PURE__*/ (0, _reactdom.createPortal)(renderer.reactElement, renderer.element, id)
88
+ };
89
+ subscribers.forEach((subscriber)=>subscriber());
90
+ },
91
+ /**
92
+ * Removes a React Renderer from the editor.
93
+ */ removeRenderer (id) {
94
+ const nextRenderers = {
95
+ ...renderers
96
+ };
97
+ delete nextRenderers[id];
98
+ renderers = nextRenderers;
99
+ subscribers.forEach((subscriber)=>subscriber());
100
+ }
101
+ };
102
+ }
56
103
  function TiptapEditorContent(param) {
57
- let { editor, ...props } = param;
104
+ let { editor: editorProp, ...props } = param;
105
+ const editor = editorProp;
58
106
  (0, _useEditorEffect.useEditorEffect)((view)=>{
59
107
  if (editor.view === view) {
60
108
  return;
61
109
  }
62
- Object.defineProperty(editor, "editorView", {
63
- value: view,
64
- configurable: true,
65
- enumerable: true,
66
- writable: true
67
- });
110
+ // @ts-expect-error private property
111
+ editor.editorView = view;
112
+ editor.contentComponent = getInstance();
68
113
  // @ts-expect-error private method
69
114
  editor.injectCSS();
70
115
  const dom = view.dom;
@@ -79,6 +124,10 @@ function TiptapEditorContent(param) {
79
124
  });
80
125
  editor.isInitialized = true;
81
126
  });
127
+ return ()=>{
128
+ editor.isInitialized = false;
129
+ editor.contentComponent = null;
130
+ };
82
131
  }, [
83
132
  editor
84
133
  ]);
@@ -89,5 +138,7 @@ function TiptapEditorContent(param) {
89
138
  ]);
90
139
  return /*#__PURE__*/ _react1.default.createElement(_react.EditorContext.Provider, {
91
140
  value: contextValue
92
- }, /*#__PURE__*/ _react1.default.createElement(_ProseMirrorDoc.ProseMirrorDoc, props));
141
+ }, /*#__PURE__*/ _react1.default.createElement(_react1.default.Fragment, null, /*#__PURE__*/ _react1.default.createElement(_ProseMirrorDoc.ProseMirrorDoc, props), editor?.contentComponent && /*#__PURE__*/ _react1.default.createElement(Portals, {
142
+ contentComponent: editor.contentComponent
143
+ })));
93
144
  }
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "TiptapEditorView", {
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
12
  const _ProseMirror = require("../components/ProseMirror.js");
13
+ const _useForceUpdate = require("../hooks/useForceUpdate.js");
13
14
  function _getRequireWildcardCache(nodeInterop) {
14
15
  if (typeof WeakMap !== "function") return null;
15
16
  var cacheBabelInterop = new WeakMap();
@@ -53,11 +54,17 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
54
  }
54
55
  function TiptapEditorView(param) {
55
56
  let { editor, nodeViews, children } = param;
57
+ const forceUpdate = (0, _useForceUpdate.useForceUpdate)();
56
58
  const dispatchTransaction = (0, _react.useCallback)((tr)=>{
57
59
  // @ts-expect-error calling private method
58
60
  editor.dispatchTransaction(tr);
61
+ // Tiptap's dispatchTransaction doesn't trigger
62
+ // a re-render, so we need to manually force
63
+ // one to ensure that React stays in sync.
64
+ forceUpdate();
59
65
  }, [
60
- editor
66
+ editor,
67
+ forceUpdate
61
68
  ]);
62
69
  const initialEditorProps = {
63
70
  ...editor.options.editorProps,
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "useTiptapEditor", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return useTiptapEditor;
9
+ }
10
+ });
11
+ const _react = require("@tiptap/react");
12
+ function useTiptapEditor(options, deps) {
13
+ return (0, _react.useEditor)({
14
+ ...options,
15
+ element: null
16
+ }, deps);
17
+ }
@@ -18,6 +18,9 @@ _export(exports, {
18
18
  tiptapNodeView: function() {
19
19
  return _tiptapNodeView.tiptapNodeView;
20
20
  },
21
+ useTiptapEditor: function() {
22
+ return _useTiptapEditor.useTiptapEditor;
23
+ },
21
24
  useTiptapEditorEffect: function() {
22
25
  return _useTiptapEditorEffect.useTiptapEditorEffect;
23
26
  },
@@ -30,3 +33,4 @@ const _TiptapEditorView = require("./TiptapEditorView.js");
30
33
  const _TiptapEditorContent = require("./TiptapEditorContent.js");
31
34
  const _useTiptapEditorEffect = require("./hooks/useTiptapEditorEffect.js");
32
35
  const _useTiptapEditorEventCallback = require("./hooks/useTiptapEditorEventCallback.js");
36
+ const _useTiptapEditor = require("./hooks/useTiptapEditor.js");
@@ -64,10 +64,11 @@ function _interop_require_wildcard(obj, nodeInterop) {
64
64
  return newObj;
65
65
  }
66
66
  function tiptapNodeView(param) {
67
- let { component: WrappedComponent, extension, as: OuterTag = "div", className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
67
+ let { component: WrappedComponent, extension, as, className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
68
68
  const TiptapNodeView = /*#__PURE__*/ (0, _react1.memo)(/*#__PURE__*/ (0, _react1.forwardRef)(function TiptapNodeView(param, ref) {
69
69
  let { children, nodeProps, ...props } = param;
70
70
  const { node, getPos, decorations, innerDecorations } = nodeProps;
71
+ const OuterTag = as ?? node.type.isInline ? "span" : "div";
71
72
  const { editor } = (0, _react.useCurrentEditor)();
72
73
  const extensionManager = editor?.extensionManager ?? null;
73
74
  const extensions = extensionManager?.extensions ?? null;
@@ -142,20 +143,18 @@ function tiptapNodeView(param) {
142
143
  to
143
144
  });
144
145
  });
145
- const nodeViewContext = (0, _react1.useMemo)(()=>({
146
- nodeViewContentChildren: /*#__PURE__*/ _react1.default.createElement(InnerTag, {
147
- "data-node-view-content-inner": node.type.name,
148
- style: {
149
- whitespace: "inherit"
150
- }
151
- }, children)
152
- }), [
146
+ const nodeViewContent = (0, _react1.useMemo)(()=>/*#__PURE__*/ _react1.default.createElement(InnerTag, {
147
+ "data-node-view-content-inner": node.type.name,
148
+ style: {
149
+ whitespace: "inherit"
150
+ }
151
+ }, children), [
153
152
  children,
154
153
  node.type.name
155
154
  ]);
156
155
  if (!editor) return null;
157
- return /*#__PURE__*/ _react1.default.createElement(_react.ReactNodeViewContext.Provider, {
158
- value: nodeViewContext
156
+ return /*#__PURE__*/ _react1.default.createElement(_react.ReactNodeViewContentProvider, {
157
+ content: nodeViewContent
159
158
  }, /*#__PURE__*/ _react1.default.createElement(OuterTag, {
160
159
  ref: ref,
161
160
  className: finalClassName,
@@ -1,19 +1,64 @@
1
1
  import { EditorContext } from "@tiptap/react";
2
- import React, { useMemo } from "react";
2
+ import React, { useMemo, useSyncExternalStore } from "react";
3
+ import { createPortal } from "react-dom";
3
4
  import { ProseMirrorDoc } from "../components/ProseMirrorDoc.js";
4
5
  import { useEditorEffect } from "../hooks/useEditorEffect.js";
6
+ /**
7
+ * This component renders all of the editor's registered "React renderers".
8
+ */ const Portals = (param)=>{
9
+ let { contentComponent } = param;
10
+ const renderers = useSyncExternalStore(contentComponent.subscribe, contentComponent.getSnapshot, contentComponent.getServerSnapshot);
11
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, Object.values(renderers));
12
+ };
13
+ function getInstance() {
14
+ const subscribers = new Set();
15
+ let renderers = {};
16
+ return {
17
+ /**
18
+ * Subscribe to the editor instance's changes.
19
+ */ subscribe (callback) {
20
+ subscribers.add(callback);
21
+ return ()=>{
22
+ subscribers.delete(callback);
23
+ };
24
+ },
25
+ getSnapshot () {
26
+ return renderers;
27
+ },
28
+ getServerSnapshot () {
29
+ return renderers;
30
+ },
31
+ /**
32
+ * Adds a new React Renderer to the editor.
33
+ */ setRenderer (id, renderer) {
34
+ renderers = {
35
+ ...renderers,
36
+ [id]: /*#__PURE__*/ createPortal(renderer.reactElement, renderer.element, id)
37
+ };
38
+ subscribers.forEach((subscriber)=>subscriber());
39
+ },
40
+ /**
41
+ * Removes a React Renderer from the editor.
42
+ */ removeRenderer (id) {
43
+ const nextRenderers = {
44
+ ...renderers
45
+ };
46
+ delete nextRenderers[id];
47
+ renderers = nextRenderers;
48
+ subscribers.forEach((subscriber)=>subscriber());
49
+ }
50
+ };
51
+ }
5
52
  export function TiptapEditorContent(param) {
6
- let { editor, ...props } = param;
53
+ let { editor: editorProp, ...props } = param;
54
+ const editor = editorProp;
7
55
  useEditorEffect((view)=>{
8
56
  if (editor.view === view) {
9
57
  return;
10
58
  }
11
- Object.defineProperty(editor, "editorView", {
12
- value: view,
13
- configurable: true,
14
- enumerable: true,
15
- writable: true
16
- });
59
+ // @ts-expect-error private property
60
+ editor.editorView = view;
61
+ editor.contentComponent = getInstance();
17
62
  // @ts-expect-error private method
18
63
  editor.injectCSS();
19
64
  const dom = view.dom;
@@ -28,6 +73,10 @@ export function TiptapEditorContent(param) {
28
73
  });
29
74
  editor.isInitialized = true;
30
75
  });
76
+ return ()=>{
77
+ editor.isInitialized = false;
78
+ editor.contentComponent = null;
79
+ };
31
80
  }, [
32
81
  editor
33
82
  ]);
@@ -38,5 +87,7 @@ export function TiptapEditorContent(param) {
38
87
  ]);
39
88
  return /*#__PURE__*/ React.createElement(EditorContext.Provider, {
40
89
  value: contextValue
41
- }, /*#__PURE__*/ React.createElement(ProseMirrorDoc, props));
90
+ }, /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(ProseMirrorDoc, props), editor?.contentComponent && /*#__PURE__*/ React.createElement(Portals, {
91
+ contentComponent: editor.contentComponent
92
+ })));
42
93
  }
@@ -1,14 +1,21 @@
1
1
  import React, { useCallback } from "react";
2
2
  import { ProseMirror } from "../components/ProseMirror.js";
3
+ import { useForceUpdate } from "../hooks/useForceUpdate.js";
3
4
  /**
4
5
  * Render a Tiptap-compatible React ProseMirror editor.
5
6
  */ export function TiptapEditorView(param) {
6
7
  let { editor, nodeViews, children } = param;
8
+ const forceUpdate = useForceUpdate();
7
9
  const dispatchTransaction = useCallback((tr)=>{
8
10
  // @ts-expect-error calling private method
9
11
  editor.dispatchTransaction(tr);
12
+ // Tiptap's dispatchTransaction doesn't trigger
13
+ // a re-render, so we need to manually force
14
+ // one to ensure that React stays in sync.
15
+ forceUpdate();
10
16
  }, [
11
- editor
17
+ editor,
18
+ forceUpdate
12
19
  ]);
13
20
  const initialEditorProps = {
14
21
  ...editor.options.editorProps,
@@ -0,0 +1,7 @@
1
+ import { useEditor } from "@tiptap/react";
2
+ export function useTiptapEditor(options, deps) {
3
+ return useEditor({
4
+ ...options,
5
+ element: null
6
+ }, deps);
7
+ }
@@ -3,3 +3,4 @@ export { TiptapEditorView } from "./TiptapEditorView.js";
3
3
  export { TiptapEditorContent } from "./TiptapEditorContent.js";
4
4
  export { useTiptapEditorEffect } from "./hooks/useTiptapEditorEffect.js";
5
5
  export { useTiptapEditorEventCallback } from "./hooks/useTiptapEditorEventCallback.js";
6
+ export { useTiptapEditor } from "./hooks/useTiptapEditor.js";
@@ -1,5 +1,5 @@
1
1
  import { getAttributesFromExtensions, getRenderedAttributes } from "@tiptap/core";
2
- import { ReactNodeViewContext, useCurrentEditor } from "@tiptap/react";
2
+ import { ReactNodeViewContentProvider, useCurrentEditor } from "@tiptap/react";
3
3
  import cx from "classnames";
4
4
  import React, { forwardRef, memo, useMemo, useRef } from "react";
5
5
  import { useEditorEventCallback } from "../hooks/useEditorEventCallback.js";
@@ -32,10 +32,11 @@ import { htmlAttrsToReactProps } from "../props.js";
32
32
  * }
33
33
  * ```
34
34
  */ export function tiptapNodeView(param) {
35
- let { component: WrappedComponent, extension, as: OuterTag = "div", className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
35
+ let { component: WrappedComponent, extension, as, className = "", attrs, contentDOMElementTag: InnerTag = "div", stopEvent, ignoreMutation } = param;
36
36
  const TiptapNodeView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function TiptapNodeView(param, ref) {
37
37
  let { children, nodeProps, ...props } = param;
38
38
  const { node, getPos, decorations, innerDecorations } = nodeProps;
39
+ const OuterTag = as ?? node.type.isInline ? "span" : "div";
39
40
  const { editor } = useCurrentEditor();
40
41
  const extensionManager = editor?.extensionManager ?? null;
41
42
  const extensions = extensionManager?.extensions ?? null;
@@ -110,20 +111,18 @@ import { htmlAttrsToReactProps } from "../props.js";
110
111
  to
111
112
  });
112
113
  });
113
- const nodeViewContext = useMemo(()=>({
114
- nodeViewContentChildren: /*#__PURE__*/ React.createElement(InnerTag, {
115
- "data-node-view-content-inner": node.type.name,
116
- style: {
117
- whitespace: "inherit"
118
- }
119
- }, children)
120
- }), [
114
+ const nodeViewContent = useMemo(()=>/*#__PURE__*/ React.createElement(InnerTag, {
115
+ "data-node-view-content-inner": node.type.name,
116
+ style: {
117
+ whitespace: "inherit"
118
+ }
119
+ }, children), [
121
120
  children,
122
121
  node.type.name
123
122
  ]);
124
123
  if (!editor) return null;
125
- return /*#__PURE__*/ React.createElement(ReactNodeViewContext.Provider, {
126
- value: nodeViewContext
124
+ return /*#__PURE__*/ React.createElement(ReactNodeViewContentProvider, {
125
+ content: nodeViewContent
127
126
  }, /*#__PURE__*/ React.createElement(OuterTag, {
128
127
  ref: ref,
129
128
  className: finalClassName,