@handlewithcare/react-prosemirror 2.2.4 → 2.3.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 +13 -2
- package/dist/cjs/components/CustomNodeView.js +68 -29
- package/dist/cjs/components/ReactNodeView.js +5 -2
- package/dist/cjs/contexts/IgnoreMutationContext.js +12 -0
- package/dist/cjs/hooks/useClientOnly.js +6 -5
- package/dist/cjs/hooks/useEditor.js +1 -1
- package/dist/cjs/hooks/useEditorEventCallback.js +6 -4
- package/dist/cjs/hooks/useIgnoreMutation.js +24 -0
- package/dist/cjs/hooks/useNodeViewDescriptor.js +7 -2
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/props.js +36 -25
- package/dist/cjs/viewdesc.js +6 -6
- package/dist/esm/components/CustomNodeView.js +68 -29
- package/dist/esm/components/ReactNodeView.js +5 -2
- package/dist/esm/contexts/IgnoreMutationContext.js +2 -0
- package/dist/esm/hooks/useClientOnly.js +7 -6
- package/dist/esm/hooks/useEditor.js +1 -1
- package/dist/esm/hooks/useEditorEventCallback.js +6 -4
- package/dist/esm/hooks/useIgnoreMutation.js +14 -0
- package/dist/esm/hooks/useNodeViewDescriptor.js +7 -2
- package/dist/esm/index.js +1 -0
- package/dist/esm/props.js +36 -23
- package/dist/esm/viewdesc.js +6 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/components/NodeViewComponentProps.d.ts +2 -1
- package/dist/types/components/ProseMirror.d.ts +2 -2
- package/dist/types/contexts/IgnoreMutationContext.d.ts +4 -0
- package/dist/types/contexts/NodeViewContext.d.ts +2 -2
- package/dist/types/hooks/useEditorEventCallback.d.ts +1 -1
- package/dist/types/hooks/useIgnoreMutation.d.ts +2 -0
- package/dist/types/hooks/useNodeViewDescriptor.d.ts +2 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/props.d.ts +1 -7
- package/dist/types/viewdesc.d.ts +2 -2
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@ yarn add @handlewithcare/react-prosemirror prosemirror-view@1.37.1 prosemirror-s
|
|
|
59
59
|
- [`useEditorEffect`](#useeditoreffect-1)
|
|
60
60
|
- [`NodeViewComponentProps`](#nodeviewcomponentprops)
|
|
61
61
|
- [`useStopEvent`](#usestopevent)
|
|
62
|
+
- [`useIgnoreMutation`](#useignoremutation)
|
|
62
63
|
- [`useSelectNode`](#useselectnode)
|
|
63
64
|
- [`useIsNodeSelected`](#useisnodeselected)
|
|
64
65
|
- [`widget`](#widget)
|
|
@@ -362,7 +363,7 @@ const Paragraph = forwardRef<HTMLParagraphElement, NodeViewComponentProps>(
|
|
|
362
363
|
});
|
|
363
364
|
|
|
364
365
|
return (
|
|
365
|
-
<p ref={ref}
|
|
366
|
+
<p {...props} ref={ref}>
|
|
366
367
|
{children}
|
|
367
368
|
</p>
|
|
368
369
|
);
|
|
@@ -402,7 +403,7 @@ const Paragraph = forwardRef<HTMLParagraphElement, NodeViewComponentProps>(
|
|
|
402
403
|
);
|
|
403
404
|
|
|
404
405
|
return (
|
|
405
|
-
<p ref={ref}
|
|
406
|
+
<p {...props} ref={ref} onClick={onClick}>
|
|
406
407
|
{children}
|
|
407
408
|
</p>
|
|
408
409
|
);
|
|
@@ -685,6 +686,16 @@ This hook can be used within a node view component to register a
|
|
|
685
686
|
[stopEvent handler](https://prosemirror.net/docs/ref/#view.NodeView.stopEvent).
|
|
686
687
|
Events for which this returns true are not handled by the editor.
|
|
687
688
|
|
|
689
|
+
### `useIgnoreMutation`
|
|
690
|
+
|
|
691
|
+
```tsx
|
|
692
|
+
type useIgnoreMutation = (stopEvent: (view: EditorView, mutation: ViewMutationRecord) => boolean): void
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
This hook can be used within a node view component to register an
|
|
696
|
+
[ignoreMutation handler](https://prosemirror.net/docs/ref/#view.NodeView.ignoreMutation).
|
|
697
|
+
Mutations for which this returns true are not handled by the editor.
|
|
698
|
+
|
|
688
699
|
### `useSelectNode`
|
|
689
700
|
|
|
690
701
|
```tsx
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "CustomNodeView", {
|
|
|
8
8
|
return CustomNodeView;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _prosemirrorstate = require("prosemirror-state");
|
|
11
12
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
13
|
const _reactdom = require("react-dom");
|
|
13
14
|
const _ChildDescriptorsContext = require("../contexts/ChildDescriptorsContext.js");
|
|
@@ -64,41 +65,72 @@ const CustomNodeView = /*#__PURE__*/ (0, _react.memo)(function CustomNodeView(pa
|
|
|
64
65
|
const nodeDomRef = (0, _react.useRef)(null);
|
|
65
66
|
const contentDomRef = (0, _react.useRef)(null);
|
|
66
67
|
const getPosFunc = (0, _react.useRef)(()=>getPos.current()).current;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
68
|
+
const nodeRef = (0, _react.useRef)(node);
|
|
69
|
+
nodeRef.current = node;
|
|
70
|
+
const outerDecoRef = (0, _react.useRef)(outerDeco);
|
|
71
|
+
outerDecoRef.current = outerDeco;
|
|
72
|
+
const innerDecoRef = (0, _react.useRef)(innerDeco);
|
|
73
|
+
innerDecoRef.current = innerDeco;
|
|
71
74
|
const customNodeViewRootRef = (0, _react.useRef)(null);
|
|
72
75
|
const customNodeViewRef = (0, _react.useRef)(null);
|
|
73
76
|
const shouldRender = (0, _useClientOnly.useClientOnly)();
|
|
77
|
+
// In Strict/Concurrent mode, layout effects can be destroyed/re-run
|
|
78
|
+
// independently of renders. We need to ensure that if the
|
|
79
|
+
// destructor that destroys the node view is called, we then recreate
|
|
80
|
+
// the node view when the layout effect is re-run.
|
|
74
81
|
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
75
|
-
if (!customNodeViewRef.current || !
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
if (!customNodeViewRef.current || !shouldRender) {
|
|
83
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
84
|
+
// this line if customNodeView is set
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
86
|
+
view, getPosFunc, outerDecoRef.current, innerDecoRef.current);
|
|
87
|
+
if (customNodeViewRef.current.stopEvent) {
|
|
88
|
+
setStopEvent(customNodeViewRef.current.stopEvent.bind(customNodeViewRef.current));
|
|
89
|
+
}
|
|
90
|
+
if (customNodeViewRef.current.selectNode) {
|
|
91
|
+
setSelectNode(customNodeViewRef.current.selectNode.bind(customNodeViewRef.current), customNodeViewRef.current.deselectNode?.bind(customNodeViewRef.current) ?? (()=>{}));
|
|
92
|
+
}
|
|
93
|
+
if (customNodeViewRef.current.ignoreMutation) {
|
|
94
|
+
setIgnoreMutation(customNodeViewRef.current.ignoreMutation.bind(customNodeViewRef.current));
|
|
95
|
+
}
|
|
96
|
+
if (!customNodeViewRootRef.current) return;
|
|
97
|
+
const { dom } = customNodeViewRef.current;
|
|
98
|
+
nodeDomRef.current = customNodeViewRootRef.current;
|
|
99
|
+
customNodeViewRootRef.current.appendChild(dom);
|
|
100
|
+
// Layout effects can run multiple times — if this effect
|
|
101
|
+
// destroyed and recreated this node view, then we need to
|
|
102
|
+
// resync the selectNode state
|
|
103
|
+
if (view?.state.selection instanceof _prosemirrorstate.NodeSelection && view.state.selection.node === nodeRef.current) {
|
|
104
|
+
customNodeViewRef.current.selectNode?.();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const nodeView = customNodeViewRef.current;
|
|
79
108
|
return ()=>{
|
|
80
|
-
|
|
109
|
+
nodeView.destroy?.();
|
|
110
|
+
customNodeViewRef.current = null;
|
|
81
111
|
};
|
|
112
|
+
// setStopEvent, setSelectNodee, and setIgnoreMutation are all stable
|
|
113
|
+
// functions and don't need to be added to the dependencies. They also
|
|
114
|
+
// can't be, because they come from useNodeViewDescriptor, which
|
|
115
|
+
// _has_ to be called after this hook, so that the effects run
|
|
116
|
+
// in the correct order
|
|
117
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
82
118
|
}, [
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
shouldRender
|
|
119
|
+
customNodeView,
|
|
120
|
+
getPosFunc,
|
|
121
|
+
view
|
|
87
122
|
]);
|
|
88
123
|
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
89
|
-
if (!customNodeView || !customNodeViewRef.current
|
|
124
|
+
if (!customNodeView || !customNodeViewRef.current) return;
|
|
90
125
|
const { destroy, update } = customNodeViewRef.current;
|
|
91
126
|
const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
|
|
92
127
|
if (updated) return;
|
|
93
128
|
destroy?.call(customNodeViewRef.current);
|
|
94
129
|
if (!customNodeViewRootRef.current) return;
|
|
95
|
-
|
|
96
|
-
initialOuterDeco.current = outerDeco;
|
|
97
|
-
initialInnerDeco.current = innerDeco;
|
|
98
|
-
customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
|
|
130
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
99
131
|
// this line if customNodeView is set
|
|
100
132
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
101
|
-
view, getPosFunc,
|
|
133
|
+
view, getPosFunc, outerDecoRef.current, innerDecoRef.current);
|
|
102
134
|
const { dom } = customNodeViewRef.current;
|
|
103
135
|
nodeDomRef.current = customNodeViewRootRef.current;
|
|
104
136
|
customNodeViewRootRef.current.appendChild(dom);
|
|
@@ -109,16 +141,9 @@ const CustomNodeView = /*#__PURE__*/ (0, _react.memo)(function CustomNodeView(pa
|
|
|
109
141
|
node,
|
|
110
142
|
outerDeco,
|
|
111
143
|
getPos,
|
|
112
|
-
customNodeViewRef,
|
|
113
|
-
customNodeViewRootRef,
|
|
114
|
-
initialNode,
|
|
115
|
-
initialOuterDeco,
|
|
116
|
-
initialInnerDeco,
|
|
117
|
-
nodeDomRef,
|
|
118
|
-
shouldRender,
|
|
119
144
|
getPosFunc
|
|
120
145
|
]);
|
|
121
|
-
const { childDescriptors, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node,
|
|
146
|
+
const { childDescriptors, nodeViewDescRef, setStopEvent, setSelectNode, setIgnoreMutation } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, getPosFunc, domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
122
147
|
const childContextValue = (0, _react.useMemo)(()=>({
|
|
123
148
|
parentRef: nodeViewDescRef,
|
|
124
149
|
siblingsRef: childDescriptors
|
|
@@ -127,11 +152,25 @@ const CustomNodeView = /*#__PURE__*/ (0, _react.memo)(function CustomNodeView(pa
|
|
|
127
152
|
nodeViewDescRef
|
|
128
153
|
]);
|
|
129
154
|
if (!shouldRender) return null;
|
|
155
|
+
// In order to render the correct element with the correct
|
|
156
|
+
// props below, we have to call the customNodeView in the
|
|
157
|
+
// render function here. We only do this once, and the
|
|
158
|
+
// results are stored in a ref but not actually appended
|
|
159
|
+
// to the DOM until a client effect
|
|
130
160
|
if (!customNodeViewRef.current) {
|
|
131
|
-
customNodeViewRef.current = customNodeView(
|
|
161
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
132
162
|
// this line if customNodeView is set
|
|
133
163
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
134
|
-
view, ()=>getPos.current(),
|
|
164
|
+
view, ()=>getPos.current(), outerDecoRef.current, innerDecoRef.current);
|
|
165
|
+
if (customNodeViewRef.current.stopEvent) {
|
|
166
|
+
setStopEvent(customNodeViewRef.current.stopEvent.bind(customNodeViewRef.current));
|
|
167
|
+
}
|
|
168
|
+
if (customNodeViewRef.current.selectNode) {
|
|
169
|
+
setSelectNode(customNodeViewRef.current.selectNode.bind(customNodeViewRef.current), customNodeViewRef.current.deselectNode?.bind(customNodeViewRef.current) ?? (()=>{}));
|
|
170
|
+
}
|
|
171
|
+
if (customNodeViewRef.current.ignoreMutation) {
|
|
172
|
+
setIgnoreMutation(customNodeViewRef.current.ignoreMutation.bind(customNodeViewRef.current));
|
|
173
|
+
}
|
|
135
174
|
}
|
|
136
175
|
const { contentDOM } = customNodeViewRef.current;
|
|
137
176
|
contentDomRef.current = contentDOM ?? null;
|
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "ReactNodeView", {
|
|
|
10
10
|
});
|
|
11
11
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
12
|
const _ChildDescriptorsContext = require("../contexts/ChildDescriptorsContext.js");
|
|
13
|
+
const _IgnoreMutationContext = require("../contexts/IgnoreMutationContext.js");
|
|
13
14
|
const _NodeViewContext = require("../contexts/NodeViewContext.js");
|
|
14
15
|
const _SelectNodeContext = require("../contexts/SelectNodeContext.js");
|
|
15
16
|
const _StopEventContext = require("../contexts/StopEventContext.js");
|
|
@@ -69,7 +70,7 @@ const ReactNodeView = /*#__PURE__*/ (0, _react.memo)(function ReactNodeView(para
|
|
|
69
70
|
const outputSpec = (0, _react.useMemo)(()=>node.type.spec.toDOM?.(node), [
|
|
70
71
|
node
|
|
71
72
|
]);
|
|
72
|
-
const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
73
|
+
const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, setIgnoreMutation, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
73
74
|
const finalProps = {
|
|
74
75
|
...props,
|
|
75
76
|
...!hasContentDOM && {
|
|
@@ -130,7 +131,9 @@ const ReactNodeView = /*#__PURE__*/ (0, _react.memo)(function ReactNodeView(para
|
|
|
130
131
|
value: setSelectNode
|
|
131
132
|
}, /*#__PURE__*/ _react.default.createElement(_StopEventContext.StopEventContext.Provider, {
|
|
132
133
|
value: setStopEvent
|
|
134
|
+
}, /*#__PURE__*/ _react.default.createElement(_IgnoreMutationContext.IgnoreMutationContext.Provider, {
|
|
135
|
+
value: setIgnoreMutation
|
|
133
136
|
}, /*#__PURE__*/ _react.default.createElement(_ChildDescriptorsContext.ChildDescriptorsContext.Provider, {
|
|
134
137
|
value: childContextValue
|
|
135
|
-
}, decoratedElement)));
|
|
138
|
+
}, decoratedElement))));
|
|
136
139
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "IgnoreMutationContext", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return IgnoreMutationContext;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = require("react");
|
|
12
|
+
const IgnoreMutationContext = (0, _react.createContext)(null);
|
|
@@ -9,10 +9,11 @@ Object.defineProperty(exports, "useClientOnly", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _react = require("react");
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
13
|
+
function unsubscribe() {}
|
|
14
|
+
function subscribe() {
|
|
15
|
+
return unsubscribe;
|
|
16
|
+
}
|
|
12
17
|
function useClientOnly() {
|
|
13
|
-
|
|
14
|
-
(0, _react.useEffect)(()=>{
|
|
15
|
-
setRender(true);
|
|
16
|
-
}, []);
|
|
17
|
-
return render;
|
|
18
|
+
return (0, _react.useSyncExternalStore)(subscribe, ()=>true, ()=>false);
|
|
18
19
|
}
|
|
@@ -229,7 +229,7 @@ function useEditor(mount, options) {
|
|
|
229
229
|
cleanup();
|
|
230
230
|
const docViewDescRef = (0, _react.useRef)(new _viewdesc.NodeViewDesc(undefined, [], ()=>-1, state.doc, [], _prosemirrorview.DecorationSet.empty, tempDom, null, tempDom, ()=>false, ()=>{
|
|
231
231
|
/* The doc node can't have a node selection*/ }, ()=>{
|
|
232
|
-
/* The doc node can't have a node selection*/ }));
|
|
232
|
+
/* The doc node can't have a node selection*/ }, ()=>false));
|
|
233
233
|
const directEditorProps = {
|
|
234
234
|
...options,
|
|
235
235
|
state,
|
|
@@ -23,10 +23,12 @@ function useEditorEventCallback(callback) {
|
|
|
23
23
|
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
24
24
|
args[_key] = arguments[_key];
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// It's not actually possible for an event handler to run
|
|
27
|
+
// while view is null, since view is only ever set to
|
|
28
|
+
// null in a layout effect that then immediately triggers
|
|
29
|
+
// a re-render which sets view to a new EditorView
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
31
|
+
return ref.current(view, ...args);
|
|
30
32
|
}, [
|
|
31
33
|
view
|
|
32
34
|
]);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "useIgnoreMutation", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return useIgnoreMutation;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = require("react");
|
|
12
|
+
const _IgnoreMutationContext = require("../contexts/IgnoreMutationContext.js");
|
|
13
|
+
const _useEditorEffect = require("./useEditorEffect.js");
|
|
14
|
+
const _useEditorEventCallback = require("./useEditorEventCallback.js");
|
|
15
|
+
function useIgnoreMutation(ignoreMutation) {
|
|
16
|
+
const register = (0, _react.useContext)(_IgnoreMutationContext.IgnoreMutationContext);
|
|
17
|
+
const ignoreMutationMemo = (0, _useEditorEventCallback.useEditorEventCallback)(ignoreMutation);
|
|
18
|
+
(0, _useEditorEffect.useEditorEffect)(()=>{
|
|
19
|
+
register(ignoreMutationMemo);
|
|
20
|
+
}, [
|
|
21
|
+
register,
|
|
22
|
+
ignoreMutationMemo
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
@@ -21,6 +21,10 @@ function useNodeViewDescriptor(node, getPos, domRef, nodeDomRef, innerDecoration
|
|
|
21
21
|
const setStopEvent = (0, _react.useCallback)((newStopEvent)=>{
|
|
22
22
|
stopEvent.current = newStopEvent;
|
|
23
23
|
}, []);
|
|
24
|
+
const ignoreMutation = (0, _react.useRef)(()=>false);
|
|
25
|
+
const setIgnoreMutation = (0, _react.useCallback)((newIgnoreMutation)=>{
|
|
26
|
+
ignoreMutation.current = newIgnoreMutation;
|
|
27
|
+
}, []);
|
|
24
28
|
const selectNode = (0, _react.useRef)(()=>{
|
|
25
29
|
if (!nodeDomRef.current || !node) return;
|
|
26
30
|
if (nodeDomRef.current.nodeType == 1) nodeDomRef.current.classList.add("ProseMirror-selectednode");
|
|
@@ -56,7 +60,7 @@ function useNodeViewDescriptor(node, getPos, domRef, nodeDomRef, innerDecoration
|
|
|
56
60
|
if (!node || !nodeDomRef.current) return;
|
|
57
61
|
const firstChildDesc = childDescriptors.current[0];
|
|
58
62
|
if (!nodeViewDescRef.current) {
|
|
59
|
-
nodeViewDescRef.current = new _viewdesc.NodeViewDesc(parentRef.current, childDescriptors.current, getPos, node, outerDecorations, innerDecorations, domRef?.current ?? nodeDomRef.current, firstChildDesc?.dom.parentElement ?? null, nodeDomRef.current, (event)=>!!stopEvent.current(event), ()=>selectNode.current(), ()=>deselectNode.current());
|
|
63
|
+
nodeViewDescRef.current = new _viewdesc.NodeViewDesc(parentRef.current, childDescriptors.current, getPos, node, outerDecorations, innerDecorations, domRef?.current ?? nodeDomRef.current, firstChildDesc?.dom.parentElement ?? null, nodeDomRef.current, (event)=>!!stopEvent.current(event), ()=>selectNode.current(), ()=>deselectNode.current(), (mutation)=>ignoreMutation.current(mutation));
|
|
60
64
|
} else {
|
|
61
65
|
nodeViewDescRef.current.parent = parentRef.current;
|
|
62
66
|
nodeViewDescRef.current.children = childDescriptors.current;
|
|
@@ -111,6 +115,7 @@ function useNodeViewDescriptor(node, getPos, domRef, nodeDomRef, innerDecoration
|
|
|
111
115
|
childDescriptors,
|
|
112
116
|
nodeViewDescRef,
|
|
113
117
|
setStopEvent,
|
|
114
|
-
setSelectNode
|
|
118
|
+
setSelectNode,
|
|
119
|
+
setIgnoreMutation
|
|
115
120
|
};
|
|
116
121
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -31,6 +31,9 @@ _export(exports, {
|
|
|
31
31
|
useEditorState: function() {
|
|
32
32
|
return _useEditorState.useEditorState;
|
|
33
33
|
},
|
|
34
|
+
useIgnoreMutation: function() {
|
|
35
|
+
return _useIgnoreMutation.useIgnoreMutation;
|
|
36
|
+
},
|
|
34
37
|
useIsNodeSelected: function() {
|
|
35
38
|
return _useIsNodeSelected.useIsNodeSelected;
|
|
36
39
|
},
|
|
@@ -52,6 +55,7 @@ const _useEditorEventListener = require("./hooks/useEditorEventListener.js");
|
|
|
52
55
|
const _useEditorState = require("./hooks/useEditorState.js");
|
|
53
56
|
const _useStopEvent = require("./hooks/useStopEvent.js");
|
|
54
57
|
const _useSelectNode = require("./hooks/useSelectNode.js");
|
|
58
|
+
const _useIgnoreMutation = require("./hooks/useIgnoreMutation.js");
|
|
55
59
|
const _useIsNodeSelected = require("./hooks/useIsNodeSelected.js");
|
|
56
60
|
const _reactKeys = require("./plugins/reactKeys.js");
|
|
57
61
|
const _ReactWidgetType = require("./decorations/ReactWidgetType.js");
|
package/dist/cjs/props.js
CHANGED
|
@@ -9,50 +9,53 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
-
cssToStyles: function() {
|
|
13
|
-
return cssToStyles;
|
|
14
|
-
},
|
|
15
12
|
htmlAttrsToReactProps: function() {
|
|
16
13
|
return htmlAttrsToReactProps;
|
|
17
14
|
},
|
|
18
|
-
kebabCaseToCamelCase: function() {
|
|
19
|
-
return kebabCaseToCamelCase;
|
|
20
|
-
},
|
|
21
15
|
mergeReactProps: function() {
|
|
22
16
|
return mergeReactProps;
|
|
23
17
|
}
|
|
24
18
|
});
|
|
25
19
|
const _classnames = /*#__PURE__*/ _interop_require_default(require("classnames"));
|
|
26
|
-
const _csstree = require("css-tree");
|
|
27
20
|
function _interop_require_default(obj) {
|
|
28
21
|
return obj && obj.__esModule ? obj : {
|
|
29
22
|
default: obj
|
|
30
23
|
};
|
|
31
24
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
let patched = false;
|
|
26
|
+
function patchConsoleError() {
|
|
27
|
+
if (patched) return;
|
|
28
|
+
/* eslint-disable no-console */ const consoleError = console.error;
|
|
29
|
+
console.error = function() {
|
|
30
|
+
for(var _len = arguments.length, data = new Array(_len), _key = 0; _key < _len; _key++){
|
|
31
|
+
data[_key] = arguments[_key];
|
|
32
|
+
}
|
|
33
|
+
const [message, prop, correction] = data;
|
|
34
|
+
if (typeof message === "string" && message.startsWith("Warning: Invalid DOM property `%s`. Did you mean `%s`?") && prop === "STYLE" && correction === "style") {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
consoleError(...data);
|
|
38
|
+
};
|
|
39
|
+
patched = true;
|
|
40
|
+
/* eslint-enable no-console */ }
|
|
41
|
+
function mergeStyleProps(a, b) {
|
|
42
|
+
if (!("STYLE" in a)) {
|
|
43
|
+
if (!("STYLE" in b)) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return b.STYLE;
|
|
47
|
+
}
|
|
48
|
+
if (!("STYLE" in b)) {
|
|
49
|
+
return a.STYLE;
|
|
48
50
|
}
|
|
49
|
-
return
|
|
51
|
+
return `${a.STYLE.match(/;\s*$/) ? a.STYLE : `${a.STYLE}`} ${b.STYLE}`;
|
|
50
52
|
}
|
|
51
53
|
function mergeReactProps(a, b) {
|
|
52
54
|
return {
|
|
53
55
|
...a,
|
|
54
56
|
...b,
|
|
55
57
|
className: (0, _classnames.default)(a.className, b.className),
|
|
58
|
+
STYLE: mergeStyleProps(a, b),
|
|
56
59
|
style: {
|
|
57
60
|
...a.style,
|
|
58
61
|
...b.style
|
|
@@ -60,6 +63,7 @@ function mergeReactProps(a, b) {
|
|
|
60
63
|
};
|
|
61
64
|
}
|
|
62
65
|
function htmlAttrsToReactProps(attrs) {
|
|
66
|
+
patchConsoleError();
|
|
63
67
|
const props = {};
|
|
64
68
|
for (const [attrName, attrValue] of Object.entries(attrs)){
|
|
65
69
|
switch(attrName.toLowerCase()){
|
|
@@ -70,7 +74,14 @@ function htmlAttrsToReactProps(attrs) {
|
|
|
70
74
|
}
|
|
71
75
|
case "style":
|
|
72
76
|
{
|
|
73
|
-
|
|
77
|
+
// HACK: React expects the `style` prop to be an
|
|
78
|
+
// object mapping from CSS property name to value.
|
|
79
|
+
// However, it will pass un-recognized props through
|
|
80
|
+
// to the underlying DOM element, and HTML attributes
|
|
81
|
+
// are case insensitive. So we use `STYLE` instead,
|
|
82
|
+
// which React doesn't intercept, but the DOM treats
|
|
83
|
+
// as `style`
|
|
84
|
+
props.STYLE = attrValue;
|
|
74
85
|
break;
|
|
75
86
|
}
|
|
76
87
|
case "autocapitalize":
|
package/dist/cjs/viewdesc.js
CHANGED
|
@@ -551,8 +551,9 @@ let NodeViewDesc = class NodeViewDesc extends ViewDesc {
|
|
|
551
551
|
stopEvent;
|
|
552
552
|
selectNode;
|
|
553
553
|
deselectNode;
|
|
554
|
-
|
|
555
|
-
|
|
554
|
+
ignoreMutation;
|
|
555
|
+
constructor(parent, children, getPos, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, stopEvent, selectNode, deselectNode, ignoreMutation){
|
|
556
|
+
super(parent, children, getPos, dom, contentDOM), this.node = node, this.outerDeco = outerDeco, this.innerDeco = innerDeco, this.nodeDOM = nodeDOM, this.stopEvent = stopEvent, this.selectNode = selectNode, this.deselectNode = deselectNode, this.ignoreMutation = ignoreMutation;
|
|
556
557
|
}
|
|
557
558
|
updateOuterDeco() {
|
|
558
559
|
// pass
|
|
@@ -612,7 +613,9 @@ let TextViewDesc = class TextViewDesc extends NodeViewDesc {
|
|
|
612
613
|
constructor(parent, children, getPos, node, outerDeco, innerDeco, dom, nodeDOM){
|
|
613
614
|
super(parent, children, getPos, node, outerDeco, innerDeco, dom, null, nodeDOM, ()=>false, ()=>{
|
|
614
615
|
/* Text nodes can't have node selections */ }, ()=>{
|
|
615
|
-
/* Text nodes can't have node selections */ })
|
|
616
|
+
/* Text nodes can't have node selections */ }, (mutation)=>{
|
|
617
|
+
return mutation.type != "characterData" && mutation.type != "selection";
|
|
618
|
+
});
|
|
616
619
|
}
|
|
617
620
|
parseRule() {
|
|
618
621
|
let skip = this.nodeDOM.parentNode;
|
|
@@ -639,9 +642,6 @@ let TextViewDesc = class TextViewDesc extends NodeViewDesc {
|
|
|
639
642
|
if (dom == this.nodeDOM) return this.posAtStart + Math.min(offset, this.node.text.length);
|
|
640
643
|
return super.localPosFromDOM(dom, offset, bias);
|
|
641
644
|
}
|
|
642
|
-
ignoreMutation(mutation) {
|
|
643
|
-
return mutation.type != "characterData" && mutation.type != "selection";
|
|
644
|
-
}
|
|
645
645
|
markDirty(from, to) {
|
|
646
646
|
super.markDirty(from, to);
|
|
647
647
|
if (this.dom != this.nodeDOM && (from == 0 || to == this.nodeDOM.nodeValue.length)) this.dirty = NODE_DIRTY;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NodeSelection } from "prosemirror-state";
|
|
1
2
|
import React, { cloneElement, createElement, memo, useContext, useMemo, useRef } from "react";
|
|
2
3
|
import { createPortal } from "react-dom";
|
|
3
4
|
import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
|
|
@@ -13,41 +14,72 @@ export const CustomNodeView = /*#__PURE__*/ memo(function CustomNodeView(param)
|
|
|
13
14
|
const nodeDomRef = useRef(null);
|
|
14
15
|
const contentDomRef = useRef(null);
|
|
15
16
|
const getPosFunc = useRef(()=>getPos.current()).current;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
17
|
+
const nodeRef = useRef(node);
|
|
18
|
+
nodeRef.current = node;
|
|
19
|
+
const outerDecoRef = useRef(outerDeco);
|
|
20
|
+
outerDecoRef.current = outerDeco;
|
|
21
|
+
const innerDecoRef = useRef(innerDeco);
|
|
22
|
+
innerDecoRef.current = innerDeco;
|
|
20
23
|
const customNodeViewRootRef = useRef(null);
|
|
21
24
|
const customNodeViewRef = useRef(null);
|
|
22
25
|
const shouldRender = useClientOnly();
|
|
26
|
+
// In Strict/Concurrent mode, layout effects can be destroyed/re-run
|
|
27
|
+
// independently of renders. We need to ensure that if the
|
|
28
|
+
// destructor that destroys the node view is called, we then recreate
|
|
29
|
+
// the node view when the layout effect is re-run.
|
|
23
30
|
useClientLayoutEffect(()=>{
|
|
24
|
-
if (!customNodeViewRef.current || !
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
if (!customNodeViewRef.current || !shouldRender) {
|
|
32
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
33
|
+
// this line if customNodeView is set
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
35
|
+
view, getPosFunc, outerDecoRef.current, innerDecoRef.current);
|
|
36
|
+
if (customNodeViewRef.current.stopEvent) {
|
|
37
|
+
setStopEvent(customNodeViewRef.current.stopEvent.bind(customNodeViewRef.current));
|
|
38
|
+
}
|
|
39
|
+
if (customNodeViewRef.current.selectNode) {
|
|
40
|
+
setSelectNode(customNodeViewRef.current.selectNode.bind(customNodeViewRef.current), customNodeViewRef.current.deselectNode?.bind(customNodeViewRef.current) ?? (()=>{}));
|
|
41
|
+
}
|
|
42
|
+
if (customNodeViewRef.current.ignoreMutation) {
|
|
43
|
+
setIgnoreMutation(customNodeViewRef.current.ignoreMutation.bind(customNodeViewRef.current));
|
|
44
|
+
}
|
|
45
|
+
if (!customNodeViewRootRef.current) return;
|
|
46
|
+
const { dom } = customNodeViewRef.current;
|
|
47
|
+
nodeDomRef.current = customNodeViewRootRef.current;
|
|
48
|
+
customNodeViewRootRef.current.appendChild(dom);
|
|
49
|
+
// Layout effects can run multiple times — if this effect
|
|
50
|
+
// destroyed and recreated this node view, then we need to
|
|
51
|
+
// resync the selectNode state
|
|
52
|
+
if (view?.state.selection instanceof NodeSelection && view.state.selection.node === nodeRef.current) {
|
|
53
|
+
customNodeViewRef.current.selectNode?.();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const nodeView = customNodeViewRef.current;
|
|
28
57
|
return ()=>{
|
|
29
|
-
|
|
58
|
+
nodeView.destroy?.();
|
|
59
|
+
customNodeViewRef.current = null;
|
|
30
60
|
};
|
|
61
|
+
// setStopEvent, setSelectNodee, and setIgnoreMutation are all stable
|
|
62
|
+
// functions and don't need to be added to the dependencies. They also
|
|
63
|
+
// can't be, because they come from useNodeViewDescriptor, which
|
|
64
|
+
// _has_ to be called after this hook, so that the effects run
|
|
65
|
+
// in the correct order
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
67
|
}, [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
shouldRender
|
|
68
|
+
customNodeView,
|
|
69
|
+
getPosFunc,
|
|
70
|
+
view
|
|
36
71
|
]);
|
|
37
72
|
useClientLayoutEffect(()=>{
|
|
38
|
-
if (!customNodeView || !customNodeViewRef.current
|
|
73
|
+
if (!customNodeView || !customNodeViewRef.current) return;
|
|
39
74
|
const { destroy, update } = customNodeViewRef.current;
|
|
40
75
|
const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
|
|
41
76
|
if (updated) return;
|
|
42
77
|
destroy?.call(customNodeViewRef.current);
|
|
43
78
|
if (!customNodeViewRootRef.current) return;
|
|
44
|
-
|
|
45
|
-
initialOuterDeco.current = outerDeco;
|
|
46
|
-
initialInnerDeco.current = innerDeco;
|
|
47
|
-
customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
|
|
79
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
48
80
|
// this line if customNodeView is set
|
|
49
81
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
50
|
-
view, getPosFunc,
|
|
82
|
+
view, getPosFunc, outerDecoRef.current, innerDecoRef.current);
|
|
51
83
|
const { dom } = customNodeViewRef.current;
|
|
52
84
|
nodeDomRef.current = customNodeViewRootRef.current;
|
|
53
85
|
customNodeViewRootRef.current.appendChild(dom);
|
|
@@ -58,16 +90,9 @@ export const CustomNodeView = /*#__PURE__*/ memo(function CustomNodeView(param)
|
|
|
58
90
|
node,
|
|
59
91
|
outerDeco,
|
|
60
92
|
getPos,
|
|
61
|
-
customNodeViewRef,
|
|
62
|
-
customNodeViewRootRef,
|
|
63
|
-
initialNode,
|
|
64
|
-
initialOuterDeco,
|
|
65
|
-
initialInnerDeco,
|
|
66
|
-
nodeDomRef,
|
|
67
|
-
shouldRender,
|
|
68
93
|
getPosFunc
|
|
69
94
|
]);
|
|
70
|
-
const { childDescriptors, nodeViewDescRef } = useNodeViewDescriptor(node,
|
|
95
|
+
const { childDescriptors, nodeViewDescRef, setStopEvent, setSelectNode, setIgnoreMutation } = useNodeViewDescriptor(node, getPosFunc, domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
71
96
|
const childContextValue = useMemo(()=>({
|
|
72
97
|
parentRef: nodeViewDescRef,
|
|
73
98
|
siblingsRef: childDescriptors
|
|
@@ -76,11 +101,25 @@ export const CustomNodeView = /*#__PURE__*/ memo(function CustomNodeView(param)
|
|
|
76
101
|
nodeViewDescRef
|
|
77
102
|
]);
|
|
78
103
|
if (!shouldRender) return null;
|
|
104
|
+
// In order to render the correct element with the correct
|
|
105
|
+
// props below, we have to call the customNodeView in the
|
|
106
|
+
// render function here. We only do this once, and the
|
|
107
|
+
// results are stored in a ref but not actually appended
|
|
108
|
+
// to the DOM until a client effect
|
|
79
109
|
if (!customNodeViewRef.current) {
|
|
80
|
-
customNodeViewRef.current = customNodeView(
|
|
110
|
+
customNodeViewRef.current = customNodeView(nodeRef.current, // customNodeView will only be set if view is set, and we can only reach
|
|
81
111
|
// this line if customNodeView is set
|
|
82
112
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
83
|
-
view, ()=>getPos.current(),
|
|
113
|
+
view, ()=>getPos.current(), outerDecoRef.current, innerDecoRef.current);
|
|
114
|
+
if (customNodeViewRef.current.stopEvent) {
|
|
115
|
+
setStopEvent(customNodeViewRef.current.stopEvent.bind(customNodeViewRef.current));
|
|
116
|
+
}
|
|
117
|
+
if (customNodeViewRef.current.selectNode) {
|
|
118
|
+
setSelectNode(customNodeViewRef.current.selectNode.bind(customNodeViewRef.current), customNodeViewRef.current.deselectNode?.bind(customNodeViewRef.current) ?? (()=>{}));
|
|
119
|
+
}
|
|
120
|
+
if (customNodeViewRef.current.ignoreMutation) {
|
|
121
|
+
setIgnoreMutation(customNodeViewRef.current.ignoreMutation.bind(customNodeViewRef.current));
|
|
122
|
+
}
|
|
84
123
|
}
|
|
85
124
|
const { contentDOM } = customNodeViewRef.current;
|
|
86
125
|
contentDomRef.current = contentDOM ?? null;
|