@handlewithcare/react-prosemirror 3.1.0-tiptap.53 → 3.1.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.
- package/README.md +3 -0
- package/dist/cjs/ReactEditorView.js +18 -7
- package/dist/cjs/components/ChildNodeViews.js +10 -16
- package/dist/cjs/components/CursorWrapper.js +6 -4
- package/dist/cjs/components/ProseMirror.js +12 -4
- package/dist/cjs/components/TextNodeView.js +7 -216
- package/dist/cjs/components/TrailingHackView.js +0 -70
- package/dist/cjs/components/nodes/NodeView.js +40 -4
- package/dist/cjs/contexts/ChildDescriptionsContext.js +1 -3
- package/dist/cjs/contexts/CompositionContext.js +14 -0
- package/dist/cjs/hooks/useMarkViewDescription.js +2 -63
- package/dist/cjs/hooks/useNodeViewDescription.js +2 -66
- package/dist/cjs/plugins/beforeInputPlugin.js +135 -122
- package/dist/cjs/plugins/reactKeys.js +16 -4
- package/dist/cjs/tiptap/tiptapNodeView.js +10 -9
- package/dist/cjs/viewdesc.js +4 -1
- package/dist/esm/ReactEditorView.js +18 -7
- package/dist/esm/components/ChildNodeViews.js +12 -18
- package/dist/esm/components/CursorWrapper.js +6 -4
- package/dist/esm/components/ProseMirror.js +12 -4
- package/dist/esm/components/TextNodeView.js +5 -165
- package/dist/esm/components/TrailingHackView.js +1 -71
- package/dist/esm/components/nodes/NodeView.js +38 -5
- package/dist/esm/contexts/ChildDescriptionsContext.js +1 -3
- package/dist/esm/contexts/CompositionContext.js +4 -0
- package/dist/esm/hooks/useIsEditorStatic.js +4 -1
- package/dist/esm/hooks/useMarkViewDescription.js +3 -64
- package/dist/esm/hooks/useNodeViewDescription.js +3 -67
- package/dist/esm/plugins/beforeInputPlugin.js +136 -123
- package/dist/esm/plugins/reactKeys.js +16 -4
- package/dist/esm/tiptap/ReactProseMirrorNodeView.js +1 -1
- package/dist/esm/tiptap/TiptapEditorContent.js +8 -1
- package/dist/esm/tiptap/hooks/useIsInReactProseMirror.js +5 -1
- package/dist/esm/tiptap/tiptapNodeView.js +13 -14
- package/dist/esm/viewdesc.js +4 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/ReactEditorView.d.ts +8 -4
- package/dist/types/components/ChildNodeViews.d.ts +2 -2
- package/dist/types/components/CursorWrapper.d.ts +1 -1
- package/dist/types/components/TextNodeView.d.ts +6 -18
- package/dist/types/components/TrailingHackView.d.ts +1 -1
- package/dist/types/components/marks/DefaultMarkView.d.ts +1 -1
- package/dist/types/components/marks/MarkView.d.ts +1 -1
- package/dist/types/components/marks/MarkViewConstructorView.d.ts +1 -1
- package/dist/types/components/marks/ReactMarkView.d.ts +1 -1
- package/dist/types/components/nodes/DefaultNodeView.d.ts +1 -1
- package/dist/types/components/nodes/NodeView.d.ts +3 -1
- package/dist/types/components/nodes/NodeViewConstructorView.d.ts +1 -1
- package/dist/types/components/nodes/ReactNodeView.d.ts +1 -1
- package/dist/types/contexts/ChildDescriptionsContext.d.ts +1 -2
- package/dist/types/contexts/CompositionContext.d.ts +4 -0
- package/dist/types/hooks/useEditor.d.ts +2 -2
- package/dist/types/hooks/useIsEditorStatic.d.ts +4 -0
- package/dist/types/hooks/useMarkViewDescription.d.ts +1 -2
- package/dist/types/hooks/useNodeViewDescription.d.ts +1 -2
- package/dist/types/hooks/useReactKeys.d.ts +2 -5
- package/dist/types/plugins/reactKeys.d.ts +5 -5
- package/dist/types/props.d.ts +225 -225
- package/dist/types/tiptap/ReactProseMirrorNodeView.d.ts +1 -1
- package/dist/types/tiptap/TiptapEditorContent.d.ts +10 -1
- package/dist/types/tiptap/hooks/useIsInReactProseMirror.d.ts +5 -0
- package/dist/types/tiptap/tiptapNodeView.d.ts +5 -6
- package/dist/types/viewdesc.d.ts +2 -1
- package/package.json +20 -6
- package/dist/cjs/plugins/componentEventListeners.js +0 -28
- package/dist/cjs/plugins/componentEventListenersPlugin.js +0 -35
- package/dist/cjs/tiptap/utils/ssrJSDOMPatch.js +0 -59
- package/dist/esm/plugins/componentEventListeners.js +0 -18
- package/dist/esm/plugins/componentEventListenersPlugin.js +0 -25
- package/dist/esm/tiptap/utils/ssrJSDOMPatch.js +0 -56
- package/dist/types/plugins/componentEventListeners.d.ts +0 -3
- package/dist/types/plugins/componentEventListenersPlugin.d.ts +0 -4
- 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,10 +33,7 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
|
|
|
33
33
|
nextProps;
|
|
34
34
|
prevState;
|
|
35
35
|
_destroyed;
|
|
36
|
-
|
|
37
|
-
// whether it was mounted during a compositionstart event handler
|
|
38
|
-
compositionStarting;
|
|
39
|
-
displacedNodes;
|
|
36
|
+
cursorWrapped;
|
|
40
37
|
constructor(place, props){
|
|
41
38
|
// Prevent the base class from destroying the React-managed nodes.
|
|
42
39
|
// Restore them below after invoking the base class constructor.
|
|
@@ -89,8 +86,7 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
|
|
|
89
86
|
// @ts-expect-error this violates the typing but class does it, too.
|
|
90
87
|
this.docView = null;
|
|
91
88
|
this._destroyed = false;
|
|
92
|
-
this.
|
|
93
|
-
this.displacedNodes = [];
|
|
89
|
+
this.cursorWrapped = false;
|
|
94
90
|
}
|
|
95
91
|
get props() {
|
|
96
92
|
return this.nextProps;
|
|
@@ -191,7 +187,22 @@ let ReactEditorView = class ReactEditorView extends _prosemirrorview.EditorView
|
|
|
191
187
|
// this ensures that the base class validates the DOM selection and invokes
|
|
192
188
|
// node view selection callbacks.
|
|
193
189
|
this.docView.markDirty(-1, -1);
|
|
194
|
-
|
|
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
|
+
}
|
|
195
206
|
// Store the new previous state.
|
|
196
207
|
this.prevState = this.state;
|
|
197
208
|
}
|
|
@@ -109,22 +109,16 @@ const ChildView = /*#__PURE__*/ (0, _react.memo)(function ChildView(param) {
|
|
|
109
109
|
}) : child.node.isText ? /*#__PURE__*/ _react.default.createElement(_ChildDescriptionsContext.ChildDescriptionsContext.Consumer, {
|
|
110
110
|
key: child.key
|
|
111
111
|
}, (param)=>{
|
|
112
|
-
let { siblingsRef, parentRef
|
|
113
|
-
return /*#__PURE__*/ _react.default.createElement(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
parentRef: parentRef,
|
|
121
|
-
findCompositionDOM: findCompositionDOM,
|
|
122
|
-
decorations: child.outerDeco,
|
|
123
|
-
registerEventListener: registerEventListener,
|
|
124
|
-
unregisterEventListener: unregisterEventListener
|
|
125
|
-
});
|
|
112
|
+
let { siblingsRef, parentRef } = param;
|
|
113
|
+
return /*#__PURE__*/ _react.default.createElement(_TextNodeView.TextNodeView, {
|
|
114
|
+
view: view,
|
|
115
|
+
node: child.node,
|
|
116
|
+
getPos: getPos,
|
|
117
|
+
siblingsRef: siblingsRef,
|
|
118
|
+
parentRef: parentRef,
|
|
119
|
+
decorations: child.outerDeco
|
|
126
120
|
});
|
|
127
|
-
}) : /*#__PURE__*/ _react.default.createElement(_NodeView.
|
|
121
|
+
}) : /*#__PURE__*/ _react.default.createElement(_NodeView.RemountableNodeView, {
|
|
128
122
|
key: child.key,
|
|
129
123
|
node: child.node,
|
|
130
124
|
getPos: getPos,
|
|
@@ -272,7 +266,7 @@ const ChildElement = /*#__PURE__*/ (0, _react.memo)(function ChildElement(param)
|
|
|
272
266
|
mark: mark,
|
|
273
267
|
getPos: getPos,
|
|
274
268
|
inline: false
|
|
275
|
-
}, element), /*#__PURE__*/ _react.default.createElement(_NodeView.
|
|
269
|
+
}, element), /*#__PURE__*/ _react.default.createElement(_NodeView.RemountableNodeView, {
|
|
276
270
|
key: child.key,
|
|
277
271
|
outerDeco: child.outerDeco,
|
|
278
272
|
node: child.node,
|
|
@@ -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,17 +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();
|
|
67
66
|
if (!domSel.isCollapsed) return;
|
|
68
67
|
const node = innerRef.current;
|
|
69
68
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
70
69
|
domSel.collapse(node.parentNode, (0, _dom.domIndex)(node) + 1);
|
|
71
|
-
|
|
70
|
+
view.cursorWrapped = true;
|
|
72
71
|
view.domObserver.connectSelection();
|
|
72
|
+
return ()=>{
|
|
73
|
+
view.cursorWrapped = false;
|
|
74
|
+
};
|
|
73
75
|
}, []);
|
|
74
76
|
return /*#__PURE__*/ _react.default.createElement("img", {
|
|
75
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) {
|
|
@@ -68,9 +70,7 @@ const rootChildDescriptionsContextValue = {
|
|
|
68
70
|
},
|
|
69
71
|
siblingsRef: {
|
|
70
72
|
current: []
|
|
71
|
-
}
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
73
|
-
findCompositionDOM: ()=>{}
|
|
73
|
+
}
|
|
74
74
|
};
|
|
75
75
|
function ProseMirrorInner(param) {
|
|
76
76
|
let { children, nodeViewComponents, markViewComponents, ...props } = param;
|
|
@@ -104,6 +104,12 @@ function ProseMirrorInner(param) {
|
|
|
104
104
|
decorations,
|
|
105
105
|
innerDecorations
|
|
106
106
|
]);
|
|
107
|
+
const freezeFrom = _reactKeys.reactKeysPluginKey.getState(state)?.freezeFrom ?? null;
|
|
108
|
+
const compositionContextValue = (0, _react.useMemo)(()=>({
|
|
109
|
+
freezeFrom
|
|
110
|
+
}), [
|
|
111
|
+
freezeFrom
|
|
112
|
+
]);
|
|
107
113
|
return /*#__PURE__*/ _react.default.createElement(_EditorContext.EditorContext.Provider, {
|
|
108
114
|
value: editor
|
|
109
115
|
}, /*#__PURE__*/ _react.default.createElement(_EditorStateContext.EditorStateContext.Provider, {
|
|
@@ -112,9 +118,11 @@ function ProseMirrorInner(param) {
|
|
|
112
118
|
value: nodeViewContextValue
|
|
113
119
|
}, /*#__PURE__*/ _react.default.createElement(_ChildDescriptionsContext.ChildDescriptionsContext.Provider, {
|
|
114
120
|
value: rootChildDescriptionsContextValue
|
|
121
|
+
}, /*#__PURE__*/ _react.default.createElement(_CompositionContext.CompositionContext.Provider, {
|
|
122
|
+
value: compositionContextValue
|
|
115
123
|
}, /*#__PURE__*/ _react.default.createElement(_ProseMirrorDoc.DocNodeViewContext.Provider, {
|
|
116
124
|
value: docNodeViewContextValue
|
|
117
|
-
}, children)))));
|
|
125
|
+
}, children))))));
|
|
118
126
|
}
|
|
119
127
|
function ProseMirror(props) {
|
|
120
128
|
return /*#__PURE__*/ _react.default.createElement(_LayoutGroup.LayoutGroup, null, /*#__PURE__*/ _react.default.createElement(ProseMirrorInner, props));
|
|
@@ -2,68 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
get: all[name]
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
_export(exports, {
|
|
12
|
-
RemountableTextNodeView: function() {
|
|
13
|
-
return RemountableTextNodeView;
|
|
14
|
-
},
|
|
15
|
-
TextNodeView: function() {
|
|
5
|
+
Object.defineProperty(exports, "TextNodeView", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
16
8
|
return TextNodeView;
|
|
17
9
|
}
|
|
18
10
|
});
|
|
19
|
-
const _prosemirrorstate = require("prosemirror-state");
|
|
20
11
|
const _prosemirrorview = require("prosemirror-view");
|
|
21
|
-
const _react =
|
|
12
|
+
const _react = require("react");
|
|
22
13
|
const _ReactEditorView = require("../ReactEditorView.js");
|
|
23
14
|
const _findDOMNode = require("../findDOMNode.js");
|
|
24
15
|
const _viewdesc = require("../viewdesc.js");
|
|
25
16
|
const _ChildNodeViews = require("./ChildNodeViews.js");
|
|
26
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
27
|
-
if (typeof WeakMap !== "function") return null;
|
|
28
|
-
var cacheBabelInterop = new WeakMap();
|
|
29
|
-
var cacheNodeInterop = new WeakMap();
|
|
30
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
31
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
32
|
-
})(nodeInterop);
|
|
33
|
-
}
|
|
34
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
35
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
36
|
-
return obj;
|
|
37
|
-
}
|
|
38
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
39
|
-
return {
|
|
40
|
-
default: obj
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
44
|
-
if (cache && cache.has(obj)) {
|
|
45
|
-
return cache.get(obj);
|
|
46
|
-
}
|
|
47
|
-
var newObj = {
|
|
48
|
-
__proto__: null
|
|
49
|
-
};
|
|
50
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
51
|
-
for(var key in obj){
|
|
52
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
53
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
54
|
-
if (desc && (desc.get || desc.set)) {
|
|
55
|
-
Object.defineProperty(newObj, key, desc);
|
|
56
|
-
} else {
|
|
57
|
-
newObj[key] = obj[key];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
newObj.default = obj;
|
|
62
|
-
if (cache) {
|
|
63
|
-
cache.set(obj, newObj);
|
|
64
|
-
}
|
|
65
|
-
return newObj;
|
|
66
|
-
}
|
|
67
17
|
function shallowEqual(objA, objB) {
|
|
68
18
|
if (objA === objB) {
|
|
69
19
|
return true;
|
|
@@ -88,57 +38,6 @@ function shallowEqual(objA, objB) {
|
|
|
88
38
|
}
|
|
89
39
|
let TextNodeView = class TextNodeView extends _react.Component {
|
|
90
40
|
viewDescRef = createMutRef();
|
|
91
|
-
renderRef = createMutRef();
|
|
92
|
-
wasProtecting = createMutRef();
|
|
93
|
-
containsCompositionNodeText = createMutRef();
|
|
94
|
-
// This is basically NodeViewDesc.localCompositionInfo
|
|
95
|
-
// from prosemirror-view. It's been slightly adjusted so that
|
|
96
|
-
// it can be used accurately during render, before we've
|
|
97
|
-
// necessarily found (or even let the browser create)
|
|
98
|
-
// view.input.compositionNode
|
|
99
|
-
shouldProtect(props) {
|
|
100
|
-
const { view, getPos, node } = props;
|
|
101
|
-
if (!(view instanceof _ReactEditorView.ReactEditorView)) return false;
|
|
102
|
-
if (!view.composing) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
const viewDesc = this.viewDescRef.current;
|
|
106
|
-
// If our DOM text node IS the IME's composition node, protect regardless
|
|
107
|
-
// of where the PM selection currently is. The IME may have replaced a
|
|
108
|
-
// selection that included us — moving the PM selection past us — but our
|
|
109
|
-
// DOM is still part of the in-progress composition. Until another
|
|
110
|
-
// TextNodeView's findCompositionDOM displaces us into a comp desc, only
|
|
111
|
-
// our own protect/no-update is preventing React from rewriting the IME's
|
|
112
|
-
// text. (When we *are* displaced, viewDesc is already a CompositionViewDesc
|
|
113
|
-
// and the existing position-based logic doesn't apply anyway.)
|
|
114
|
-
const ownsCompositionNode = viewDesc instanceof _viewdesc.TextViewDesc && viewDesc.nodeDOM === view.input.compositionNode;
|
|
115
|
-
if (!ownsCompositionNode) {
|
|
116
|
-
const pos = getPos();
|
|
117
|
-
const { from, to } = view.state.selection;
|
|
118
|
-
if (!(view.state.selection instanceof _prosemirrorstate.TextSelection) || from <= pos || to > pos + node.nodeSize) {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return !!this.containsCompositionNodeText.current;
|
|
123
|
-
}
|
|
124
|
-
handleCompositionEnd = ()=>{
|
|
125
|
-
if (!this.wasProtecting.current) return;
|
|
126
|
-
const { view } = this.props;
|
|
127
|
-
if (!(view instanceof _ReactEditorView.ReactEditorView)) return;
|
|
128
|
-
// If the IME detached our DOM during composition, React's fiber is now
|
|
129
|
-
// wired to a detached node and will silently send all subsequent updates
|
|
130
|
-
// into the void. Re-attach the orphan (so the upcoming unmount's
|
|
131
|
-
// removeChild has something to remove), then ask our wrapper to mint a
|
|
132
|
-
// new key — that forces React to drop this fiber and mount a fresh one
|
|
133
|
-
// whose stateNode it creates from the current render output.
|
|
134
|
-
const dom = (0, _findDOMNode.findDOMNode)(this);
|
|
135
|
-
if (dom instanceof HTMLElement && !view.dom.contains(dom)) {
|
|
136
|
-
this.reattachAtCorrectPosition(dom);
|
|
137
|
-
this.props.forceRemount();
|
|
138
|
-
} else {
|
|
139
|
-
this.forceUpdate();
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
41
|
create() {
|
|
143
42
|
const { view, decorations, siblingsRef, parentRef, getPos, node } = this.props;
|
|
144
43
|
const dom = (0, _findDOMNode.findDOMNode)(this);
|
|
@@ -150,24 +49,10 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
150
49
|
if (!(textNode instanceof Text)) {
|
|
151
50
|
textNode = null;
|
|
152
51
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
viewDesc = new _viewdesc.CompositionViewDesc(parentRef.current, getPos, // If we can't
|
|
156
|
-
// actually find the correct DOM nodes from here (
|
|
157
|
-
// which is the case in a composition in a newly
|
|
158
|
-
// created text node), we let our parent do it.
|
|
159
|
-
// Passing a valid element here just so that the
|
|
160
|
-
// ViewDesc constructor doesn't blow up.
|
|
161
|
-
dom ?? document.createElement("div"), textNode ?? document.createTextNode(node.text ?? ""), node.text ?? "");
|
|
162
|
-
} else {
|
|
163
|
-
if (!dom || !textNode) return null;
|
|
164
|
-
viewDesc = new _viewdesc.TextViewDesc(parentRef.current, [], getPos, node, decorations, _prosemirrorview.DecorationSet.empty, dom, textNode);
|
|
165
|
-
}
|
|
52
|
+
if (!dom || !textNode) return null;
|
|
53
|
+
const viewDesc = new _viewdesc.TextViewDesc(parentRef.current, [], getPos, node, decorations, _prosemirrorview.DecorationSet.empty, dom, textNode);
|
|
166
54
|
siblingsRef.current.push(viewDesc);
|
|
167
55
|
siblingsRef.current.sort(_viewdesc.sortViewDescs);
|
|
168
|
-
if (viewDesc instanceof _viewdesc.CompositionViewDesc) {
|
|
169
|
-
this.props.findCompositionDOM(viewDesc);
|
|
170
|
-
}
|
|
171
56
|
return viewDesc;
|
|
172
57
|
}
|
|
173
58
|
update() {
|
|
@@ -175,18 +60,6 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
175
60
|
if (!(view instanceof _ReactEditorView.ReactEditorView)) return false;
|
|
176
61
|
const viewDesc = this.viewDescRef.current;
|
|
177
62
|
if (!viewDesc) return false;
|
|
178
|
-
// Don't force destroy/recreate just because we transitioned into protect
|
|
179
|
-
// mode. If our DOM text node is the IME's composition node, we want to
|
|
180
|
-
// keep the TextViewDesc alive so the new composition-text TextNodeView's
|
|
181
|
-
// findCompositionDOM second pass can find us, validate the size mismatch,
|
|
182
|
-
// and displace us into a properly-sized CompositionViewDesc. If we
|
|
183
|
-
// destroyed here, create() would put a wrong-size CompositionViewDesc on
|
|
184
|
-
// T and pre-empt that displacement.
|
|
185
|
-
const ownsCompositionNode = viewDesc instanceof _viewdesc.TextViewDesc && viewDesc.nodeDOM === view.input.compositionNode;
|
|
186
|
-
if (!ownsCompositionNode && this.shouldProtect(this.props) !== viewDesc instanceof _viewdesc.CompositionViewDesc) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
if (viewDesc instanceof _viewdesc.CompositionViewDesc) return false;
|
|
190
63
|
const dom = (0, _findDOMNode.findDOMNode)(this);
|
|
191
64
|
if (!dom || dom !== viewDesc.dom) return false;
|
|
192
65
|
if (!dom.contains(viewDesc.nodeDOM)) return false;
|
|
@@ -207,58 +80,15 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
207
80
|
this.destroy();
|
|
208
81
|
this.viewDescRef.current = this.create();
|
|
209
82
|
}
|
|
210
|
-
const { view } = this.props;
|
|
211
|
-
if (!(view instanceof _ReactEditorView.ReactEditorView)) {
|
|
212
|
-
this.containsCompositionNodeText.current = true;
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
const textNode = view.input.compositionNode;
|
|
216
|
-
if (!textNode) {
|
|
217
|
-
this.containsCompositionNodeText.current = true;
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
// Resolve the parent textblock containing this text node and ask
|
|
221
|
-
// findTextInFragment whether the IME text node's *current* content can be
|
|
222
|
-
// placed somewhere in the textblock's PM content overlapping the
|
|
223
|
-
// selection. If it can, the composition is still consistent with PM state
|
|
224
|
-
// and we should protect. If it can't (e.g. a remote change overwrote the
|
|
225
|
-
// composing region), PM and the DOM have diverged — abandon protection
|
|
226
|
-
// so the re-render can rewrite the DOM and cancel the composition.
|
|
227
|
-
const $pos = view.state.doc.resolve(this.props.getPos());
|
|
228
|
-
const parent = $pos.parent;
|
|
229
|
-
if (!parent.inlineContent) {
|
|
230
|
-
this.containsCompositionNodeText.current = false;
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const parentStart = $pos.start();
|
|
234
|
-
const { from, to } = view.state.selection;
|
|
235
|
-
const textPos = (0, _viewdesc.findTextInFragment)(parent.content, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
236
|
-
textNode.nodeValue, from - parentStart, to - parentStart);
|
|
237
|
-
this.containsCompositionNodeText.current = textPos >= 0;
|
|
238
83
|
}
|
|
239
84
|
shouldComponentUpdate(nextProps) {
|
|
240
|
-
// When leaving the protected state, force a re-render so React's
|
|
241
|
-
// virtual DOM resyncs with whatever the IME wrote into the real DOM
|
|
242
|
-
// while we were returning a stale renderRef.
|
|
243
|
-
if (this.wasProtecting.current && !this.shouldProtect(nextProps)) {
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
85
|
return !shallowEqual(this.props, nextProps);
|
|
247
86
|
}
|
|
248
87
|
constructor(props){
|
|
249
88
|
super(props);
|
|
250
89
|
this.viewDescRef.current = null;
|
|
251
|
-
this.renderRef.current = null;
|
|
252
|
-
this.wasProtecting.current = false;
|
|
253
|
-
this.containsCompositionNodeText.current = true;
|
|
254
90
|
}
|
|
255
91
|
componentDidMount() {
|
|
256
|
-
this.containsCompositionNodeText.current = true;
|
|
257
|
-
// After a composition, force an update so that we re-check whether we need
|
|
258
|
-
// to be protecting our rendered content and allow React to re-sync with the
|
|
259
|
-
// DOM.
|
|
260
|
-
const { registerEventListener } = this.props;
|
|
261
|
-
registerEventListener("compositionend", this.handleCompositionEnd);
|
|
262
92
|
this.viewDescRef.current = this.create();
|
|
263
93
|
this.updateEffect();
|
|
264
94
|
}
|
|
@@ -267,43 +97,12 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
267
97
|
const { view } = this.props;
|
|
268
98
|
if (!(view instanceof _ReactEditorView.ReactEditorView)) return;
|
|
269
99
|
}
|
|
270
|
-
reattachAtCorrectPosition(dom) {
|
|
271
|
-
const viewDesc = this.viewDescRef.current;
|
|
272
|
-
if (!viewDesc) return;
|
|
273
|
-
let host = viewDesc.parent;
|
|
274
|
-
while(host && !host.contentDOM)host = host.parent;
|
|
275
|
-
if (!host?.contentDOM) return;
|
|
276
|
-
const siblings = viewDesc.parent?.children ?? [];
|
|
277
|
-
const idx = siblings.indexOf(viewDesc);
|
|
278
|
-
let nextDom = null;
|
|
279
|
-
for(let i = idx + 1; i < siblings.length; i++){
|
|
280
|
-
const sib = siblings[i];
|
|
281
|
-
if (sib?.dom && sib.dom.parentNode === host.contentDOM) {
|
|
282
|
-
nextDom = sib.dom;
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
host.contentDOM.insertBefore(dom, nextDom);
|
|
287
|
-
}
|
|
288
100
|
componentWillUnmount() {
|
|
289
|
-
const { unregisterEventListener } = this.props;
|
|
290
|
-
unregisterEventListener("compositionend", this.handleCompositionEnd);
|
|
291
101
|
this.destroy();
|
|
292
102
|
}
|
|
293
103
|
render() {
|
|
294
104
|
const { node, decorations } = this.props;
|
|
295
|
-
|
|
296
|
-
// update the DOM that the user is working in. If there's
|
|
297
|
-
// an active composition and the selection is in this node,
|
|
298
|
-
// we freeze the DOM of this element so that it doesn't
|
|
299
|
-
// interrupt the composition
|
|
300
|
-
if (this.shouldProtect(this.props)) {
|
|
301
|
-
this.wasProtecting.current = true;
|
|
302
|
-
return this.renderRef.current;
|
|
303
|
-
}
|
|
304
|
-
this.wasProtecting.current = false;
|
|
305
|
-
this.renderRef.current = decorations.reduce(_ChildNodeViews.wrapInDeco, node.text);
|
|
306
|
-
return this.renderRef.current;
|
|
105
|
+
return decorations.reduce(_ChildNodeViews.wrapInDeco, node.text);
|
|
307
106
|
}
|
|
308
107
|
};
|
|
309
108
|
/**
|
|
@@ -313,11 +112,3 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
313
112
|
*/ function createMutRef() {
|
|
314
113
|
return /*#__PURE__*/ (0, _react.createRef)();
|
|
315
114
|
}
|
|
316
|
-
function RemountableTextNodeView(props) {
|
|
317
|
-
const [key, forceRemount] = (0, _react.useReducer)((x)=>x + 1, 0);
|
|
318
|
-
return /*#__PURE__*/ _react.default.createElement(TextNodeView, {
|
|
319
|
-
key: key,
|
|
320
|
-
forceRemount: forceRemount,
|
|
321
|
-
...props
|
|
322
|
-
});
|
|
323
|
-
}
|
|
@@ -9,11 +9,8 @@ Object.defineProperty(exports, "TrailingHackView", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
|
-
const _ReactEditorView = require("../ReactEditorView.js");
|
|
13
12
|
const _ChildDescriptionsContext = require("../contexts/ChildDescriptionsContext.js");
|
|
14
13
|
const _useClientLayoutEffect = require("../hooks/useClientLayoutEffect.js");
|
|
15
|
-
const _useEditorEffect = require("../hooks/useEditorEffect.js");
|
|
16
|
-
const _useEditorEventListener = require("../hooks/useEditorEventListener.js");
|
|
17
14
|
const _viewdesc = require("../viewdesc.js");
|
|
18
15
|
function _getRequireWildcardCache(nodeInterop) {
|
|
19
16
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -58,15 +55,9 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
58
55
|
}
|
|
59
56
|
function TrailingHackView(param) {
|
|
60
57
|
let { getPos } = param;
|
|
61
|
-
const [shouldRender, setShouldRender] = (0, _react.useState)(true);
|
|
62
|
-
const [shouldReinsert, setShouldReinsert] = (0, _react.useState)(false);
|
|
63
58
|
const { siblingsRef, parentRef } = (0, _react.useContext)(_ChildDescriptionsContext.ChildDescriptionsContext);
|
|
64
59
|
const viewDescRef = (0, _react.useRef)(null);
|
|
65
60
|
const ref = (0, _react.useRef)(null);
|
|
66
|
-
const preservedRef = (0, _react.useRef)(ref.current);
|
|
67
|
-
if (ref.current) {
|
|
68
|
-
preservedRef.current = ref.current;
|
|
69
|
-
}
|
|
70
61
|
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
71
62
|
const siblings = siblingsRef.current;
|
|
72
63
|
return ()=>{
|
|
@@ -92,67 +83,6 @@ function TrailingHackView(param) {
|
|
|
92
83
|
}
|
|
93
84
|
siblingsRef.current.sort(_viewdesc.sortViewDescs);
|
|
94
85
|
});
|
|
95
|
-
// At the start of a composition, the browser will automatically delete
|
|
96
|
-
// the trailing hack br element. We need to unmount ourselves _before_
|
|
97
|
-
// that happens, so that React doesn't try to remove the already-removed
|
|
98
|
-
// br node when this component gets unmounted
|
|
99
|
-
(0, _useEditorEventListener.useEditorEventListener)("compositionstart", (view)=>{
|
|
100
|
-
const { from } = view.state.selection;
|
|
101
|
-
if (from === getPos()) {
|
|
102
|
-
setShouldRender(false);
|
|
103
|
-
setShouldReinsert(true);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
// Chrome and Safari will cancel/mangle the composition if the br element isn't
|
|
107
|
-
// still in the DOM after the compositionstart event. We manually add it
|
|
108
|
-
// back to the DOM, without React managing it, so that it can be removed
|
|
109
|
-
// again by the browser when it starts the composition.
|
|
110
|
-
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
111
|
-
if (!shouldReinsert) return;
|
|
112
|
-
const preservedHack = preservedRef.current;
|
|
113
|
-
if (!preservedHack) return;
|
|
114
|
-
if (!viewDescRef.current) return;
|
|
115
|
-
const { parent } = viewDescRef.current;
|
|
116
|
-
if (!parent) return;
|
|
117
|
-
const dom = parent.contentDOM;
|
|
118
|
-
if (!dom) return;
|
|
119
|
-
preservedHack.pmViewDesc = undefined;
|
|
120
|
-
const index = parent.children.indexOf(viewDescRef.current);
|
|
121
|
-
if (index === 0) {
|
|
122
|
-
dom.appendChild(preservedHack);
|
|
123
|
-
} else {
|
|
124
|
-
dom.insertBefore(preservedHack, dom.childNodes.item(index));
|
|
125
|
-
}
|
|
126
|
-
return ()=>{
|
|
127
|
-
try {
|
|
128
|
-
dom.removeChild(preservedHack);
|
|
129
|
-
} catch {
|
|
130
|
-
// It may have already been removed by the browser during
|
|
131
|
-
// the composition, but if we get unmounted before that happens,
|
|
132
|
-
// we need to remove it ourselves
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
}, [
|
|
136
|
-
shouldReinsert
|
|
137
|
-
]);
|
|
138
|
-
// We need to run the same composition check when we first get mounted,
|
|
139
|
-
// in case we got mounted in the same render batch as the beginning of
|
|
140
|
-
// a composition
|
|
141
|
-
(0, _useEditorEffect.useEditorEffect)((view)=>{
|
|
142
|
-
if (!(view instanceof _ReactEditorView.ReactEditorView)) return;
|
|
143
|
-
if (!view.compositionStarting) return;
|
|
144
|
-
const { from } = view.state.selection;
|
|
145
|
-
if (from === getPos()) {
|
|
146
|
-
setShouldRender(false);
|
|
147
|
-
}
|
|
148
|
-
}, [
|
|
149
|
-
getPos
|
|
150
|
-
]);
|
|
151
|
-
(0, _useEditorEventListener.useEditorEventListener)("compositionend", ()=>{
|
|
152
|
-
setShouldRender(true);
|
|
153
|
-
setShouldReinsert(false);
|
|
154
|
-
});
|
|
155
|
-
if (!shouldRender) return null;
|
|
156
86
|
return /*#__PURE__*/ _react.default.createElement("br", {
|
|
157
87
|
ref: ref,
|
|
158
88
|
className: "ProseMirror-trailingBreak"
|
|
@@ -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(
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
});
|