@handlewithcare/react-prosemirror 3.1.0-tiptap.52 → 3.1.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.
Files changed (75) hide show
  1. package/README.md +3 -0
  2. package/dist/cjs/ReactEditorView.js +18 -1
  3. package/dist/cjs/components/ChildNodeViews.js +4 -4
  4. package/dist/cjs/components/CursorWrapper.js +9 -11
  5. package/dist/cjs/components/ProseMirror.js +13 -3
  6. package/dist/cjs/components/TextNodeView.js +54 -50
  7. package/dist/cjs/components/WidgetView.js +3 -1
  8. package/dist/cjs/components/nodes/NodeView.js +40 -4
  9. package/dist/cjs/contexts/CompositionContext.js +14 -0
  10. package/dist/cjs/decorations/viewDecorations.js +1 -6
  11. package/dist/cjs/hooks/useEditor.js +2 -10
  12. package/dist/cjs/hooks/useMarkViewDescription.js +1 -4
  13. package/dist/cjs/hooks/useNodeViewDescription.js +1 -22
  14. package/dist/cjs/plugins/beforeInputPlugin.js +162 -50
  15. package/dist/cjs/plugins/reactKeys.js +34 -15
  16. package/dist/cjs/tiptap/tiptapNodeView.js +10 -9
  17. package/dist/cjs/viewdesc.js +55 -4
  18. package/dist/esm/ReactEditorView.js +18 -1
  19. package/dist/esm/components/ChildNodeViews.js +5 -5
  20. package/dist/esm/components/CursorWrapper.js +9 -11
  21. package/dist/esm/components/ProseMirror.js +13 -3
  22. package/dist/esm/components/TextNodeView.js +56 -52
  23. package/dist/esm/components/WidgetView.js +3 -1
  24. package/dist/esm/components/nodes/NodeView.js +38 -5
  25. package/dist/esm/contexts/CompositionContext.js +4 -0
  26. package/dist/esm/decorations/viewDecorations.js +1 -6
  27. package/dist/esm/hooks/useEditor.js +2 -10
  28. package/dist/esm/hooks/useIsEditorStatic.js +4 -1
  29. package/dist/esm/hooks/useMarkViewDescription.js +1 -4
  30. package/dist/esm/hooks/useNodeViewDescription.js +2 -23
  31. package/dist/esm/plugins/beforeInputPlugin.js +162 -50
  32. package/dist/esm/plugins/reactKeys.js +34 -15
  33. package/dist/esm/tiptap/ReactProseMirrorNodeView.js +1 -1
  34. package/dist/esm/tiptap/TiptapEditorContent.js +8 -1
  35. package/dist/esm/tiptap/hooks/useIsInReactProseMirror.js +5 -1
  36. package/dist/esm/tiptap/tiptapNodeView.js +13 -14
  37. package/dist/esm/viewdesc.js +54 -4
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/dist/types/ReactEditorView.d.ts +10 -1
  40. package/dist/types/components/ChildNodeViews.d.ts +2 -2
  41. package/dist/types/components/CursorWrapper.d.ts +1 -1
  42. package/dist/types/components/TextNodeView.d.ts +7 -4
  43. package/dist/types/components/__tests__/ProseMirror.composition.test.d.ts +17 -1
  44. package/dist/types/components/marks/DefaultMarkView.d.ts +1 -1
  45. package/dist/types/components/marks/MarkView.d.ts +1 -1
  46. package/dist/types/components/marks/MarkViewConstructorView.d.ts +1 -1
  47. package/dist/types/components/marks/ReactMarkView.d.ts +1 -1
  48. package/dist/types/components/nodes/DefaultNodeView.d.ts +1 -1
  49. package/dist/types/components/nodes/NodeView.d.ts +3 -1
  50. package/dist/types/components/nodes/NodeViewConstructorView.d.ts +1 -1
  51. package/dist/types/components/nodes/ReactNodeView.d.ts +1 -1
  52. package/dist/types/contexts/ChildDescriptionsContext.d.ts +3 -2
  53. package/dist/types/contexts/CompositionContext.d.ts +4 -0
  54. package/dist/types/decorations/viewDecorations.d.ts +2 -2
  55. package/dist/types/hooks/useEditor.d.ts +3 -4
  56. package/dist/types/hooks/useIsEditorStatic.d.ts +4 -0
  57. package/dist/types/hooks/useReactKeys.d.ts +2 -5
  58. package/dist/types/plugins/beforeInputPlugin.d.ts +1 -2
  59. package/dist/types/plugins/reactKeys.d.ts +10 -9
  60. package/dist/types/props.d.ts +225 -225
  61. package/dist/types/tiptap/ReactProseMirrorNodeView.d.ts +1 -1
  62. package/dist/types/tiptap/TiptapEditorContent.d.ts +10 -1
  63. package/dist/types/tiptap/hooks/useIsInReactProseMirror.d.ts +5 -0
  64. package/dist/types/tiptap/tiptapNodeView.d.ts +5 -6
  65. package/dist/types/viewdesc.d.ts +5 -3
  66. package/package.json +22 -6
  67. package/dist/cjs/plugins/componentEventListeners.js +0 -28
  68. package/dist/cjs/plugins/componentEventListenersPlugin.js +0 -35
  69. package/dist/cjs/tiptap/utils/ssrJSDOMPatch.js +0 -59
  70. package/dist/esm/plugins/componentEventListeners.js +0 -18
  71. package/dist/esm/plugins/componentEventListenersPlugin.js +0 -25
  72. package/dist/esm/tiptap/utils/ssrJSDOMPatch.js +0 -56
  73. package/dist/types/plugins/componentEventListeners.d.ts +0 -3
  74. package/dist/types/plugins/componentEventListenersPlugin.d.ts +0 -4
  75. package/dist/types/tiptap/utils/ssrJSDOMPatch.d.ts +0 -1
package/README.md CHANGED
@@ -99,6 +99,9 @@ import "prosemirror-view/style/prosemirror.css";
99
99
 
100
100
  <!-- tocstop -->
101
101
 
102
+ Already using Tiptap, and interesting in using React ProseMirror as the React
103
+ integration? Check out [the Tiptap integration docs](./src/tiptap/README.md)!
104
+
102
105
  ## The Problem
103
106
 
104
107
  To make updates efficient, React separates updates into phases so that it can
@@ -33,6 +33,7 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
33
33
  nextProps;
34
34
  prevState;
35
35
  _destroyed;
36
+ cursorWrapped;
36
37
  constructor(place, props){
37
38
  // Prevent the base class from destroying the React-managed nodes.
38
39
  // Restore them below after invoking the base class constructor.
@@ -85,6 +86,7 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
85
86
  // @ts-expect-error this violates the typing but class does it, too.
86
87
  this.docView = null;
87
88
  this._destroyed = false;
89
+ this.cursorWrapped = false;
88
90
  }
89
91
  get props() {
90
92
  return this.nextProps;
@@ -185,7 +187,22 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
185
187
  // this ensures that the base class validates the DOM selection and invokes
186
188
  // node view selection callbacks.
187
189
  this.docView.markDirty(-1, -1);
188
- super.update(this.nextProps);
190
+ const selectionChanged = !this.state.selection.eq(this.prevState.selection);
191
+ if (selectionChanged) {
192
+ super.update(this.nextProps);
193
+ } else {
194
+ // If the selection hasn't changed between renders, force prosemirror-view to
195
+ // skip the selectionToDOM call. If a render happens after a DOM selection change
196
+ // but before the "selectionchange" event fired, calling selectionToDOM will cause
197
+ // the selection to be reset its the previous position.
198
+ this.domObserver.setCurSelection();
199
+ this.input.mouseDown = {
200
+ allowDefault: false,
201
+ delayedSelectionSync: false
202
+ };
203
+ super.update(this.nextProps);
204
+ this.input.mouseDown = null;
205
+ }
189
206
  // Store the new previous state.
190
207
  this.prevState = this.state;
191
208
  }
@@ -118,7 +118,7 @@ const ChildView = /*#__PURE__*/ (0, _react.memo)(function ChildView(param) {
118
118
  parentRef: parentRef,
119
119
  decorations: child.outerDeco
120
120
  });
121
- }) : /*#__PURE__*/ _react.default.createElement(_NodeView.NodeView, {
121
+ }) : /*#__PURE__*/ _react.default.createElement(_NodeView.RemountableNodeView, {
122
122
  key: child.key,
123
123
  node: child.node,
124
124
  getPos: getPos,
@@ -266,7 +266,7 @@ const ChildElement = /*#__PURE__*/ (0, _react.memo)(function ChildElement(param)
266
266
  mark: mark,
267
267
  getPos: getPos,
268
268
  inline: false
269
- }, element), /*#__PURE__*/ _react.default.createElement(_NodeView.NodeView, {
269
+ }, element), /*#__PURE__*/ _react.default.createElement(_NodeView.RemountableNodeView, {
270
270
  key: child.key,
271
271
  outerDeco: child.outerDeco,
272
272
  node: child.node,
@@ -399,14 +399,14 @@ const ChildNodeViews = /*#__PURE__*/ (0, _react.memo)(function ChildNodeViews(pa
399
399
  component: _SeparatorHackView.SeparatorHackView,
400
400
  marks: [],
401
401
  offset: lastChild?.offset ?? 0,
402
- index: (lastChild?.index ?? 0) + 2,
402
+ index: (lastChild?.index ?? 0) + 1,
403
403
  key: "trailing-hack-img"
404
404
  }, {
405
405
  type: "hack",
406
406
  component: _TrailingHackView.TrailingHackView,
407
407
  marks: [],
408
408
  offset: lastChild?.offset ?? 0,
409
- index: (lastChild?.index ?? 0) + 1,
409
+ index: (lastChild?.index ?? 0) + 2,
410
410
  key: "trailing-hack-br"
411
411
  });
412
412
  }
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "CursorWrapper", {
9
9
  }
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
+ const _ReactEditorView = require("../ReactEditorView.js");
12
13
  const _dom = require("../dom.js");
13
14
  const _useEditorEffect = require("../hooks/useEditorEffect.js");
14
15
  function _getRequireWildcardCache(nodeInterop) {
@@ -59,21 +60,18 @@ const CursorWrapper = /*#__PURE__*/ (0, _react.forwardRef)(function CursorWrappe
59
60
  return innerRef.current;
60
61
  }, []);
61
62
  (0, _useEditorEffect.useEditorEffect)((view)=>{
62
- if (!view || !innerRef.current) return;
63
- // @ts-expect-error Internal property - domObserver
63
+ if (!(view instanceof _ReactEditorView.ReactEditorView) || !innerRef.current) return;
64
64
  view.domObserver.disconnectSelection();
65
- // @ts-expect-error Internal property - domSelection
66
65
  const domSel = view.domSelection();
66
+ if (!domSel.isCollapsed) return;
67
67
  const node = innerRef.current;
68
- const img = node.nodeName == "IMG";
69
- if (img) {
70
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
71
- domSel.collapse(node.parentNode, (0, _dom.domIndex)(node) + 1);
72
- } else {
73
- domSel.collapse(node, 0);
74
- }
75
- // @ts-expect-error Internal property - domObserver
68
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
69
+ domSel.collapse(node.parentNode, (0, _dom.domIndex)(node) + 1);
70
+ view.cursorWrapped = true;
76
71
  view.domObserver.connectSelection();
72
+ return ()=>{
73
+ view.cursorWrapped = false;
74
+ };
77
75
  }, []);
78
76
  return /*#__PURE__*/ _react.default.createElement("img", {
79
77
  ref: innerRef,
@@ -10,12 +10,14 @@ Object.defineProperty(exports, "ProseMirror", {
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
12
  const _ChildDescriptionsContext = require("../contexts/ChildDescriptionsContext.js");
13
+ const _CompositionContext = require("../contexts/CompositionContext.js");
13
14
  const _EditorContext = require("../contexts/EditorContext.js");
14
15
  const _EditorStateContext = require("../contexts/EditorStateContext.js");
15
16
  const _NodeViewContext = require("../contexts/NodeViewContext.js");
16
17
  const _computeDocDeco = require("../decorations/computeDocDeco.js");
17
18
  const _viewDecorations = require("../decorations/viewDecorations.js");
18
19
  const _useEditor = require("../hooks/useEditor.js");
20
+ const _reactKeys = require("../plugins/reactKeys.js");
19
21
  const _LayoutGroup = require("./LayoutGroup.js");
20
22
  const _ProseMirrorDoc = require("./ProseMirrorDoc.js");
21
23
  function _getRequireWildcardCache(nodeInterop) {
@@ -73,7 +75,7 @@ const rootChildDescriptionsContextValue = {
73
75
  function ProseMirrorInner(param) {
74
76
  let { children, nodeViewComponents, markViewComponents, ...props } = param;
75
77
  const [mount, setMount] = (0, _react.useState)(null);
76
- const { editor, cursorWrapper, state } = (0, _useEditor.useEditor)(mount, props);
78
+ const { editor, state } = (0, _useEditor.useEditor)(mount, props);
77
79
  const nodeViewConstructors = editor.view.nodeViews;
78
80
  const nodeViewContextValue = (0, _react.useMemo)(()=>{
79
81
  return {
@@ -90,7 +92,7 @@ function ProseMirrorInner(param) {
90
92
  ]);
91
93
  const node = state.doc;
92
94
  const decorations = (0, _computeDocDeco.computeDocDeco)(editor.view);
93
- const innerDecorations = (0, _viewDecorations.viewDecorations)(editor.view, cursorWrapper);
95
+ const innerDecorations = (0, _viewDecorations.viewDecorations)(editor.view);
94
96
  const docNodeViewContextValue = (0, _react.useMemo)(()=>({
95
97
  setMount,
96
98
  node,
@@ -102,6 +104,12 @@ function ProseMirrorInner(param) {
102
104
  decorations,
103
105
  innerDecorations
104
106
  ]);
107
+ const freezeFrom = _reactKeys.reactKeysPluginKey.getState(state)?.freezeFrom ?? null;
108
+ const compositionContextValue = (0, _react.useMemo)(()=>({
109
+ freezeFrom
110
+ }), [
111
+ freezeFrom
112
+ ]);
105
113
  return /*#__PURE__*/ _react.default.createElement(_EditorContext.EditorContext.Provider, {
106
114
  value: editor
107
115
  }, /*#__PURE__*/ _react.default.createElement(_EditorStateContext.EditorStateContext.Provider, {
@@ -110,9 +118,11 @@ function ProseMirrorInner(param) {
110
118
  value: nodeViewContextValue
111
119
  }, /*#__PURE__*/ _react.default.createElement(_ChildDescriptionsContext.ChildDescriptionsContext.Provider, {
112
120
  value: rootChildDescriptionsContextValue
121
+ }, /*#__PURE__*/ _react.default.createElement(_CompositionContext.CompositionContext.Provider, {
122
+ value: compositionContextValue
113
123
  }, /*#__PURE__*/ _react.default.createElement(_ProseMirrorDoc.DocNodeViewContext.Provider, {
114
124
  value: docNodeViewContextValue
115
- }, children)))));
125
+ }, children))))));
116
126
  }
117
127
  function ProseMirror(props) {
118
128
  return /*#__PURE__*/ _react.default.createElement(_LayoutGroup.LayoutGroup, null, /*#__PURE__*/ _react.default.createElement(ProseMirrorInner, props));
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "TextNodeView", {
10
10
  });
11
11
  const _prosemirrorview = require("prosemirror-view");
12
12
  const _react = require("react");
13
+ const _ReactEditorView = require("../ReactEditorView.js");
13
14
  const _findDOMNode = require("../findDOMNode.js");
14
15
  const _viewdesc = require("../viewdesc.js");
15
16
  const _ChildNodeViews = require("./ChildNodeViews.js");
@@ -36,75 +37,78 @@ function shallowEqual(objA, objB) {
36
37
  return true;
37
38
  }
38
39
  let TextNodeView = class TextNodeView extends _react.Component {
39
- viewDescRef = null;
40
- renderRef = null;
41
- updateEffect() {
40
+ viewDescRef = createMutRef();
41
+ create() {
42
42
  const { view, decorations, siblingsRef, parentRef, getPos, node } = this.props;
43
- // There simply is no other way to ref a text node
44
- // eslint-disable-next-line react/no-find-dom-node
45
43
  const dom = (0, _findDOMNode.findDOMNode)(this);
46
- // We only need to explicitly create a CompositionViewDesc
47
- // when a composition was started that produces a new text node.
48
- // Otherwise we just rely on re-rendering the renderRef
49
- if (!dom) {
50
- if (!view.composing) return;
51
- this.viewDescRef = new _viewdesc.CompositionViewDesc(parentRef.current, getPos, // These are just placeholders/dummies. We can't
52
- // actually find the correct DOM nodes from here,
53
- // so we let our parent do it.
54
- // Passing a valid element here just so that the
55
- // ViewDesc constructor doesn't blow up.
56
- document.createElement("div"), document.createTextNode(node.text ?? ""), node.text ?? "");
57
- return;
58
- }
44
+ if (!dom && !view.composing) return null;
59
45
  let textNode = dom;
60
- while(textNode.firstChild){
46
+ while(textNode?.firstChild){
61
47
  textNode = textNode.firstChild;
62
48
  }
63
- if (!this.viewDescRef || this.viewDescRef instanceof _viewdesc.CompositionViewDesc) {
64
- this.viewDescRef = new _viewdesc.TextViewDesc(undefined, [], getPos, node, decorations, _prosemirrorview.DecorationSet.empty, dom, textNode);
65
- } else {
66
- this.viewDescRef.parent = parentRef.current;
67
- this.viewDescRef.children = [];
68
- this.viewDescRef.node = node;
69
- this.viewDescRef.outerDeco = decorations;
70
- this.viewDescRef.innerDeco = _prosemirrorview.DecorationSet.empty;
71
- this.viewDescRef.dom = dom;
72
- this.viewDescRef.dom.pmViewDesc = this.viewDescRef;
73
- this.viewDescRef.nodeDOM = textNode;
74
- }
75
- if (!siblingsRef.current.includes(this.viewDescRef)) {
76
- siblingsRef.current.push(this.viewDescRef);
49
+ if (!(textNode instanceof Text)) {
50
+ textNode = null;
77
51
  }
52
+ if (!dom || !textNode) return null;
53
+ const viewDesc = new _viewdesc.TextViewDesc(parentRef.current, [], getPos, node, decorations, _prosemirrorview.DecorationSet.empty, dom, textNode);
54
+ siblingsRef.current.push(viewDesc);
78
55
  siblingsRef.current.sort(_viewdesc.sortViewDescs);
56
+ return viewDesc;
57
+ }
58
+ update() {
59
+ const { view, node, decorations } = this.props;
60
+ if (!(view instanceof _ReactEditorView.ReactEditorView)) return false;
61
+ const viewDesc = this.viewDescRef.current;
62
+ if (!viewDesc) return false;
63
+ const dom = (0, _findDOMNode.findDOMNode)(this);
64
+ if (!dom || dom !== viewDesc.dom) return false;
65
+ if (!dom.contains(viewDesc.nodeDOM)) return false;
66
+ return viewDesc.matchesNode(node, decorations, _prosemirrorview.DecorationSet.empty) || viewDesc.update(node, decorations, _prosemirrorview.DecorationSet.empty, view);
67
+ }
68
+ destroy() {
69
+ const viewDesc = this.viewDescRef.current;
70
+ if (!viewDesc) return;
71
+ viewDesc.destroy();
72
+ const siblings = this.props.siblingsRef.current;
73
+ if (siblings.includes(viewDesc)) {
74
+ const index = siblings.indexOf(viewDesc);
75
+ siblings.splice(index, 1);
76
+ }
77
+ }
78
+ updateEffect() {
79
+ if (!this.update()) {
80
+ this.destroy();
81
+ this.viewDescRef.current = this.create();
82
+ }
79
83
  }
80
84
  shouldComponentUpdate(nextProps) {
81
85
  return !shallowEqual(this.props, nextProps);
82
86
  }
87
+ constructor(props){
88
+ super(props);
89
+ this.viewDescRef.current = null;
90
+ }
83
91
  componentDidMount() {
92
+ this.viewDescRef.current = this.create();
84
93
  this.updateEffect();
85
94
  }
86
95
  componentDidUpdate() {
87
96
  this.updateEffect();
97
+ const { view } = this.props;
98
+ if (!(view instanceof _ReactEditorView.ReactEditorView)) return;
88
99
  }
89
100
  componentWillUnmount() {
90
- const { siblingsRef } = this.props;
91
- if (!this.viewDescRef) return;
92
- if (siblingsRef.current.includes(this.viewDescRef)) {
93
- const index = siblingsRef.current.indexOf(this.viewDescRef);
94
- siblingsRef.current.splice(index, 1);
95
- }
101
+ this.destroy();
96
102
  }
97
103
  render() {
98
- const { view, getPos, node, decorations } = this.props;
99
- // During a composition, it's crucial that we don't try to
100
- // update the DOM that the user is working in. If there's
101
- // an active composition and the selection is in this node,
102
- // we freeze the DOM of this element so that it doesn't
103
- // interrupt the composition
104
- if (view.composing && view.state.selection.from >= getPos() && view.state.selection.from <= getPos() + node.nodeSize) {
105
- return this.renderRef;
106
- }
107
- this.renderRef = decorations.reduce(_ChildNodeViews.wrapInDeco, node.text);
108
- return this.renderRef;
104
+ const { node, decorations } = this.props;
105
+ return decorations.reduce(_ChildNodeViews.wrapInDeco, node.text);
109
106
  }
110
107
  };
108
+ /**
109
+ * createRef returns a RefObject, even though the docs
110
+ * say that it's acceptible to manage the ref's value
111
+ * yourself.
112
+ */ function createMutRef() {
113
+ return /*#__PURE__*/ (0, _react.createRef)();
114
+ }
@@ -90,6 +90,8 @@ function WidgetView(param) {
90
90
  ref: domRef,
91
91
  widget: widget,
92
92
  getPos: getPos,
93
- contentEditable: false
93
+ ...!widget.type.spec.raw && {
94
+ contentEditable: false
95
+ }
94
96
  });
95
97
  }
@@ -14,9 +14,13 @@ _export(exports, {
14
14
  },
15
15
  NodeView: function() {
16
16
  return NodeView;
17
+ },
18
+ RemountableNodeView: function() {
19
+ return RemountableNodeView;
17
20
  }
18
21
  });
19
22
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
23
+ const _CompositionContext = require("../../contexts/CompositionContext.js");
20
24
  const _NodeViewContext = require("../../contexts/NodeViewContext.js");
21
25
  const _DefaultNodeView = require("./DefaultNodeView.js");
22
26
  const _NodeViewConstructorView = require("./NodeViewConstructorView.js");
@@ -62,8 +66,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
62
66
  }
63
67
  return newObj;
64
68
  }
65
- const NodeView = /*#__PURE__*/ (0, _react.memo)(function NodeView(props) {
69
+ const NodeView = /*#__PURE__*/ (0, _react.memo)(function NodeView(param) {
70
+ let { forceRemount, ...props } = param;
71
+ const renderRef = (0, _react.useRef)(null);
72
+ const { freezeFrom } = (0, _react.useContext)(_CompositionContext.CompositionContext);
66
73
  const { components, constructors } = (0, _react.useContext)(_NodeViewContext.NodeViewContext);
74
+ const committedFrozenRef = (0, _react.useRef)(false);
67
75
  const component = components[props.node.type.name] ?? _DefaultNodeView.DefaultNodeView;
68
76
  const constructor = constructors[props.node.type.name];
69
77
  // Construct a wrapper component so that the node view remounts when either
@@ -90,8 +98,36 @@ const NodeView = /*#__PURE__*/ (0, _react.memo)(function NodeView(props) {
90
98
  constructor,
91
99
  component
92
100
  ]);
93
- return /*#__PURE__*/ _react.default.createElement(GetPosContext.Provider, {
94
- value: props.getPos
95
- }, /*#__PURE__*/ _react.default.createElement(Component, props));
101
+ // It's not generally safe to access getPos during render, because the
102
+ // component may not re-render when its return value would change. Here it's
103
+ // safe because we only use it to _suppress_ commits that would otherwise
104
+ // have happened.
105
+ const frozen = props.getPos() === freezeFrom;
106
+ // Protect content while frozen, and also through the single render where we
107
+ // leave the frozen state: `committedFrozenRef` still reflects the previous
108
+ // commit, so we keep returning the exact same cached element reference.
109
+ const protecting = (frozen || committedFrozenRef.current) && renderRef.current != null;
110
+ if (!protecting) {
111
+ renderRef.current = /*#__PURE__*/ _react.default.createElement(GetPosContext.Provider, {
112
+ value: props.getPos
113
+ }, /*#__PURE__*/ _react.default.createElement(Component, props));
114
+ }
115
+ (0, _react.useLayoutEffect)(()=>{
116
+ const wasFrozen = committedFrozenRef.current;
117
+ committedFrozenRef.current = frozen;
118
+ if (wasFrozen && !frozen) forceRemount();
119
+ }, [
120
+ frozen,
121
+ forceRemount
122
+ ]);
123
+ return renderRef.current;
96
124
  });
97
125
  const GetPosContext = /*#__PURE__*/ (0, _react.createContext)(null);
126
+ function RemountableNodeView(props) {
127
+ const [key, forceRemount] = (0, _react.useReducer)((x)=>x + 1, 0);
128
+ return /*#__PURE__*/ _react.default.createElement(NodeView, {
129
+ key: key.toString(),
130
+ ...props,
131
+ forceRemount: forceRemount
132
+ });
133
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "CompositionContext", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return CompositionContext;
9
+ }
10
+ });
11
+ const _react = require("react");
12
+ const CompositionContext = (0, _react.createContext)({
13
+ freezeFrom: null
14
+ });
@@ -123,17 +123,12 @@ function insertAhead(array, i, deco) {
123
123
  array.splice(i, 0, deco);
124
124
  }
125
125
  const ViewDecorationsCache = new WeakMap();
126
- function viewDecorations(view, cursorWrapper) {
126
+ function viewDecorations(view) {
127
127
  const found = [];
128
128
  view.someProp("decorations", (f)=>{
129
129
  const result = f(view.state);
130
130
  if (result && result != empty) found.push(result);
131
131
  });
132
- if (cursorWrapper) {
133
- found.push(_prosemirrorview.DecorationSet.create(view.state.doc, [
134
- cursorWrapper
135
- ]));
136
- }
137
132
  const previous = ViewDecorationsCache.get(view);
138
133
  if (!previous) {
139
134
  const result = DecorationGroup.from(found);
@@ -27,23 +27,16 @@ function useEditor(mount, options) {
27
27
  }
28
28
  }
29
29
  const flushSyncRef = (0, _react.useRef)(true);
30
- const [cursorWrapper, _setCursorWrapper] = (0, _react.useState)(null);
31
30
  const forceUpdate = (0, _useForceUpdate.useForceUpdate)();
32
31
  const defaultState = options.defaultState ?? _constants.EMPTY_STATE;
33
32
  const [_state, setState] = (0, _react.useState)(defaultState);
34
33
  const state = options.state ?? _state;
35
34
  const { handleDOMEvents, registerEventListener, unregisterEventListener } = (0, _useComponentEventListeners.useComponentEventListeners)(options.handleDOMEvents);
36
- const setCursorWrapper = (0, _react.useCallback)((deco)=>{
37
- (0, _reactdom.flushSync)(()=>{
38
- _setCursorWrapper(deco);
39
- });
40
- }, []);
41
35
  const plugins = (0, _react.useMemo)(()=>[
42
36
  ...options.plugins ?? [],
43
- (0, _beforeInputPlugin.beforeInputPlugin)(setCursorWrapper)
37
+ (0, _beforeInputPlugin.beforeInputPlugin)()
44
38
  ], [
45
- options.plugins,
46
- setCursorWrapper
39
+ options.plugins
47
40
  ]);
48
41
  const dispatchTransaction = (0, _react.useCallback)(function dispatchTransaction(tr) {
49
42
  if (flushSyncRef.current) {
@@ -122,7 +115,6 @@ function useEditor(mount, options) {
122
115
  ]);
123
116
  return {
124
117
  editor,
125
- cursorWrapper,
126
118
  state
127
119
  };
128
120
  }
@@ -123,10 +123,7 @@ function useMarkViewDescription(getDOM, getContentDOM, constructor, props) {
123
123
  const childContextValue = (0, _react.useMemo)(()=>({
124
124
  parentRef: viewDescRef,
125
125
  siblingsRef: childrenRef
126
- }), [
127
- childrenRef,
128
- viewDescRef
129
- ]);
126
+ }), []);
130
127
  return {
131
128
  childContextValue,
132
129
  contentDOM: contentDOMRef.current ?? viewDescRef.current?.dom,
@@ -141,33 +141,12 @@ function useNodeViewDescription(getDOM, getContentDOM, constructor, props) {
141
141
  children.sort(_viewdesc.sortViewDescs);
142
142
  for (const child of children){
143
143
  child.parent = viewDesc;
144
- // Because TextNodeViews can't locate the DOM nodes
145
- // for compositions, we need to override them here
146
- if (child instanceof _viewdesc.CompositionViewDesc) {
147
- const compositionTopDOM = viewDesc?.contentDOM?.firstChild;
148
- if (!compositionTopDOM) throw new Error(`Started a composition but couldn't find the text node it belongs to.`);
149
- let textDOM = compositionTopDOM;
150
- while(textDOM.firstChild){
151
- textDOM = textDOM.firstChild;
152
- }
153
- if (!textDOM || !(textDOM instanceof Text)) throw new Error(`Started a composition but couldn't find the text node it belongs to.`);
154
- child.dom = compositionTopDOM;
155
- child.textDOM = textDOM;
156
- child.text = textDOM.data;
157
- child.textDOM.pmViewDesc = child;
158
- // It should not be possible to be in a composition because one could
159
- // not start between the renders that switch the view type.
160
- view.input.compositionNodes.push(child);
161
- }
162
144
  }
163
145
  });
164
146
  const childContextValue = (0, _react.useMemo)(()=>({
165
147
  parentRef: viewDescRef,
166
148
  siblingsRef: childrenRef
167
- }), [
168
- childrenRef,
169
- viewDescRef
170
- ]);
149
+ }), []);
171
150
  return {
172
151
  childContextValue,
173
152
  contentDOM: contentDOMRef.current,