@handlewithcare/react-prosemirror 2.1.0 → 2.2.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.
- package/README.md +22 -3
- package/dist/cjs/components/CustomNodeView.js +80 -4
- package/dist/cjs/components/NodeView.js +13 -133
- package/dist/cjs/components/OutputSpec.js +1 -1
- package/dist/cjs/components/ReactNodeView.js +136 -0
- package/dist/cjs/components/TextNodeView.js +2 -2
- package/dist/cjs/findDOMNode.js +46 -0
- package/dist/cjs/hooks/useEditor.js +14 -3
- package/dist/cjs/hooks/useEditorEffect.js +5 -2
- package/dist/cjs/hooks/useIsNodeSelected.js +21 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/plugins/componentEventListeners.js +1 -1
- package/dist/cjs/plugins/reactKeys.js +1 -1
- package/dist/esm/components/CustomNodeView.js +82 -6
- package/dist/esm/components/NodeView.js +14 -134
- package/dist/esm/components/OutputSpec.js +1 -1
- package/dist/esm/components/ReactNodeView.js +85 -0
- package/dist/esm/components/TextNodeView.js +1 -1
- package/dist/esm/findDOMNode.js +31 -0
- package/dist/esm/hooks/useEditor.js +14 -3
- package/dist/esm/hooks/useEditorEffect.js +5 -2
- package/dist/esm/hooks/useIsNodeSelected.js +11 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/plugins/componentEventListeners.js +1 -1
- package/dist/esm/plugins/reactKeys.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/components/CustomNodeView.d.ts +3 -12
- package/dist/types/components/ReactNodeView.d.ts +11 -0
- package/dist/types/contexts/EditorContext.d.ts +2 -0
- package/dist/types/findDOMNode.d.ts +3 -0
- package/dist/types/hooks/useEditor.d.ts +1 -0
- package/dist/types/hooks/useIsNodeSelected.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +17 -4
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ yarn add @handlewithcare/react-prosemirror prosemirror-view@1.37.1 prosemirror-s
|
|
|
48
48
|
- [`useEditorEventCallback`](#useeditoreventcallback)
|
|
49
49
|
- [`useEditorEventListener`](#useeditoreventlistener)
|
|
50
50
|
- [Building node views with React](#building-node-views-with-react)
|
|
51
|
-
- [What's
|
|
51
|
+
- [What's new in v2?](#whats-new-in-v2)
|
|
52
52
|
- [API changes](#api-changes)
|
|
53
53
|
- [API](#api)
|
|
54
54
|
- [`ProseMirror`](#prosemirror)
|
|
@@ -60,7 +60,9 @@ yarn add @handlewithcare/react-prosemirror prosemirror-view@1.37.1 prosemirror-s
|
|
|
60
60
|
- [`NodeViewComponentProps`](#nodeviewcomponentprops)
|
|
61
61
|
- [`useStopEvent`](#usestopevent)
|
|
62
62
|
- [`useSelectNode`](#useselectnode)
|
|
63
|
+
- [`useIsNodeSelected`](#useisnodeselected)
|
|
63
64
|
- [`widget`](#widget)
|
|
65
|
+
- [Looking for someone to collaborate with?](#looking-for-someone-to-collaborate-with)
|
|
64
66
|
|
|
65
67
|
<!-- tocstop -->
|
|
66
68
|
|
|
@@ -421,9 +423,9 @@ function ProseMirrorEditor() {
|
|
|
421
423
|
}
|
|
422
424
|
```
|
|
423
425
|
|
|
424
|
-
## What's
|
|
426
|
+
## What's new in v2?
|
|
425
427
|
|
|
426
|
-
The
|
|
428
|
+
The v2 release constitutes a significant re-write of the library.
|
|
427
429
|
|
|
428
430
|
Previously, React ProseMirror relied on ProseMirror's EditorView to manage the
|
|
429
431
|
DOM for the editor. To integrate it with React, we used React
|
|
@@ -694,6 +696,16 @@ This hook can be used within a node view component to register
|
|
|
694
696
|
The selectNode handler will only be called when a NodeSelection is created whose
|
|
695
697
|
node is this one.
|
|
696
698
|
|
|
699
|
+
### `useIsNodeSelected`
|
|
700
|
+
|
|
701
|
+
```tsx
|
|
702
|
+
type useIsNodeSelected = (): boolean
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
This hook can be used within a node view component to subscribe to a boolean
|
|
706
|
+
value determining whether this node is selected. The hook will return true when
|
|
707
|
+
a NodeSelection is created whose node is this one.
|
|
708
|
+
|
|
697
709
|
### `widget`
|
|
698
710
|
|
|
699
711
|
```tsx
|
|
@@ -708,3 +720,10 @@ type widget = (
|
|
|
708
720
|
|
|
709
721
|
Like ProseMirror View's `Decoration.widget`, but with support for React
|
|
710
722
|
components.
|
|
723
|
+
|
|
724
|
+
## Looking for someone to collaborate with?
|
|
725
|
+
|
|
726
|
+
Reach out to [Handle with Care](https://handlewithcare.dev/#get-in-touch)! We're
|
|
727
|
+
a product development collective with years of experience bringing excellent
|
|
728
|
+
ideas to life. We love React and ProseMirror, and we're always looking for new
|
|
729
|
+
folks to work with!
|
|
@@ -10,8 +10,10 @@ Object.defineProperty(exports, "CustomNodeView", {
|
|
|
10
10
|
});
|
|
11
11
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
12
|
const _reactdom = require("react-dom");
|
|
13
|
+
const _ChildDescriptorsContext = require("../contexts/ChildDescriptorsContext.js");
|
|
13
14
|
const _EditorContext = require("../contexts/EditorContext.js");
|
|
14
15
|
const _useClientOnly = require("../hooks/useClientOnly.js");
|
|
16
|
+
const _useNodeViewDescriptor = require("../hooks/useNodeViewDescriptor.js");
|
|
15
17
|
const _ChildNodeViews = require("./ChildNodeViews.js");
|
|
16
18
|
function _getRequireWildcardCache(nodeInterop) {
|
|
17
19
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -54,10 +56,75 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
54
56
|
}
|
|
55
57
|
return newObj;
|
|
56
58
|
}
|
|
57
|
-
function CustomNodeView(param) {
|
|
58
|
-
let {
|
|
59
|
+
const CustomNodeView = /*#__PURE__*/ (0, _react.memo)(function CustomNodeView(param) {
|
|
60
|
+
let { customNodeView, node, getPos, innerDeco, outerDeco } = param;
|
|
59
61
|
const { view } = (0, _react.useContext)(_EditorContext.EditorContext);
|
|
62
|
+
const domRef = (0, _react.useRef)(null);
|
|
63
|
+
const nodeDomRef = (0, _react.useRef)(null);
|
|
64
|
+
const contentDomRef = (0, _react.useRef)(null);
|
|
65
|
+
const getPosFunc = (0, _react.useRef)(()=>getPos.current()).current;
|
|
66
|
+
// this is ill-conceived; should revisit
|
|
67
|
+
const initialNode = (0, _react.useRef)(node);
|
|
68
|
+
const initialOuterDeco = (0, _react.useRef)(outerDeco);
|
|
69
|
+
const initialInnerDeco = (0, _react.useRef)(innerDeco);
|
|
70
|
+
const customNodeViewRootRef = (0, _react.useRef)(null);
|
|
71
|
+
const customNodeViewRef = (0, _react.useRef)(null);
|
|
60
72
|
const shouldRender = (0, _useClientOnly.useClientOnly)();
|
|
73
|
+
(0, _react.useLayoutEffect)(()=>{
|
|
74
|
+
if (!customNodeViewRef.current || !customNodeViewRootRef.current || !shouldRender) return;
|
|
75
|
+
const { dom } = customNodeViewRef.current;
|
|
76
|
+
nodeDomRef.current = customNodeViewRootRef.current;
|
|
77
|
+
customNodeViewRootRef.current.appendChild(dom);
|
|
78
|
+
return ()=>{
|
|
79
|
+
customNodeViewRef.current?.destroy?.();
|
|
80
|
+
};
|
|
81
|
+
}, [
|
|
82
|
+
customNodeViewRef,
|
|
83
|
+
customNodeViewRootRef,
|
|
84
|
+
nodeDomRef,
|
|
85
|
+
shouldRender
|
|
86
|
+
]);
|
|
87
|
+
(0, _react.useLayoutEffect)(()=>{
|
|
88
|
+
if (!customNodeView || !customNodeViewRef.current || !shouldRender) return;
|
|
89
|
+
const { destroy, update } = customNodeViewRef.current;
|
|
90
|
+
const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
|
|
91
|
+
if (updated) return;
|
|
92
|
+
destroy?.call(customNodeViewRef.current);
|
|
93
|
+
if (!customNodeViewRootRef.current) return;
|
|
94
|
+
initialNode.current = node;
|
|
95
|
+
initialOuterDeco.current = outerDeco;
|
|
96
|
+
initialInnerDeco.current = innerDeco;
|
|
97
|
+
customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
|
|
98
|
+
// this line if customNodeView is set
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
100
|
+
view, getPosFunc, initialOuterDeco.current, initialInnerDeco.current);
|
|
101
|
+
const { dom } = customNodeViewRef.current;
|
|
102
|
+
nodeDomRef.current = customNodeViewRootRef.current;
|
|
103
|
+
customNodeViewRootRef.current.appendChild(dom);
|
|
104
|
+
}, [
|
|
105
|
+
customNodeView,
|
|
106
|
+
view,
|
|
107
|
+
innerDeco,
|
|
108
|
+
node,
|
|
109
|
+
outerDeco,
|
|
110
|
+
getPos,
|
|
111
|
+
customNodeViewRef,
|
|
112
|
+
customNodeViewRootRef,
|
|
113
|
+
initialNode,
|
|
114
|
+
initialOuterDeco,
|
|
115
|
+
initialInnerDeco,
|
|
116
|
+
nodeDomRef,
|
|
117
|
+
shouldRender,
|
|
118
|
+
getPosFunc
|
|
119
|
+
]);
|
|
120
|
+
const { childDescriptors, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
121
|
+
const childContextValue = (0, _react.useMemo)(()=>({
|
|
122
|
+
parentRef: nodeViewDescRef,
|
|
123
|
+
siblingsRef: childDescriptors
|
|
124
|
+
}), [
|
|
125
|
+
childDescriptors,
|
|
126
|
+
nodeViewDescRef
|
|
127
|
+
]);
|
|
61
128
|
if (!shouldRender) return null;
|
|
62
129
|
if (!customNodeViewRef.current) {
|
|
63
130
|
customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
|
|
@@ -67,7 +134,7 @@ function CustomNodeView(param) {
|
|
|
67
134
|
}
|
|
68
135
|
const { contentDOM } = customNodeViewRef.current;
|
|
69
136
|
contentDomRef.current = contentDOM ?? null;
|
|
70
|
-
|
|
137
|
+
const element = /*#__PURE__*/ (0, _react.createElement)(node.isInline ? "span" : "div", {
|
|
71
138
|
ref: customNodeViewRootRef,
|
|
72
139
|
contentEditable: !!contentDOM,
|
|
73
140
|
suppressContentEditableWarning: true
|
|
@@ -76,4 +143,13 @@ function CustomNodeView(param) {
|
|
|
76
143
|
node: node,
|
|
77
144
|
innerDecorations: innerDeco
|
|
78
145
|
}), contentDOM));
|
|
79
|
-
|
|
146
|
+
const decoratedElement = /*#__PURE__*/ (0, _react.cloneElement)(outerDeco.reduce(_ChildNodeViews.wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
|
+
outerDeco.some((d)=>d.type.attrs.nodeName) ? {
|
|
148
|
+
ref: domRef
|
|
149
|
+
} : // we've already passed the domRef to the NodeView component
|
|
150
|
+
// as a prop
|
|
151
|
+
undefined);
|
|
152
|
+
return /*#__PURE__*/ _react.default.createElement(_ChildDescriptorsContext.ChildDescriptorsContext.Provider, {
|
|
153
|
+
value: childContextValue
|
|
154
|
+
}, decoratedElement);
|
|
155
|
+
});
|
|
@@ -9,15 +9,9 @@ Object.defineProperty(exports, "NodeView", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
|
-
const _ChildDescriptorsContext = require("../contexts/ChildDescriptorsContext.js");
|
|
13
12
|
const _EditorContext = require("../contexts/EditorContext.js");
|
|
14
|
-
const _NodeViewContext = require("../contexts/NodeViewContext.js");
|
|
15
|
-
const _SelectNodeContext = require("../contexts/SelectNodeContext.js");
|
|
16
|
-
const _StopEventContext = require("../contexts/StopEventContext.js");
|
|
17
|
-
const _useNodeViewDescriptor = require("../hooks/useNodeViewDescriptor.js");
|
|
18
|
-
const _ChildNodeViews = require("./ChildNodeViews.js");
|
|
19
13
|
const _CustomNodeView = require("./CustomNodeView.js");
|
|
20
|
-
const
|
|
14
|
+
const _ReactNodeView = require("./ReactNodeView.js");
|
|
21
15
|
function _getRequireWildcardCache(nodeInterop) {
|
|
22
16
|
if (typeof WeakMap !== "function") return null;
|
|
23
17
|
var cacheBabelInterop = new WeakMap();
|
|
@@ -61,136 +55,22 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
61
55
|
}
|
|
62
56
|
const NodeView = /*#__PURE__*/ (0, _react.memo)(function NodeView(param) {
|
|
63
57
|
let { outerDeco, getPos, node, innerDeco, ...props } = param;
|
|
64
|
-
const domRef = (0, _react.useRef)(null);
|
|
65
|
-
const nodeDomRef = (0, _react.useRef)(null);
|
|
66
|
-
const contentDomRef = (0, _react.useRef)(null);
|
|
67
|
-
const getPosFunc = (0, _react.useRef)(()=>getPos.current()).current;
|
|
68
|
-
// this is ill-conceived; should revisit
|
|
69
|
-
const initialNode = (0, _react.useRef)(node);
|
|
70
|
-
const initialOuterDeco = (0, _react.useRef)(outerDeco);
|
|
71
|
-
const initialInnerDeco = (0, _react.useRef)(innerDeco);
|
|
72
|
-
const customNodeViewRootRef = (0, _react.useRef)(null);
|
|
73
|
-
const customNodeViewRef = (0, _react.useRef)(null);
|
|
74
|
-
// const state = useEditorState();
|
|
75
|
-
const { nodeViews } = (0, _react.useContext)(_NodeViewContext.NodeViewContext);
|
|
76
58
|
const { view } = (0, _react.useContext)(_EditorContext.EditorContext);
|
|
77
|
-
let element = null;
|
|
78
|
-
const Component = nodeViews[node.type.name];
|
|
79
|
-
const outputSpec = (0, _react.useMemo)(()=>node.type.spec.toDOM?.(node), [
|
|
80
|
-
node
|
|
81
|
-
]);
|
|
82
|
-
// TODO: Would be great to pull all of the custom node view stuff into
|
|
83
|
-
// a hook
|
|
84
59
|
const customNodeView = view?.someProp("nodeViews", (nodeViews)=>nodeViews?.[node.type.name]);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const { dom } = customNodeViewRef.current;
|
|
88
|
-
nodeDomRef.current = customNodeViewRootRef.current;
|
|
89
|
-
customNodeViewRootRef.current.appendChild(dom);
|
|
90
|
-
return ()=>{
|
|
91
|
-
customNodeViewRef.current?.destroy?.();
|
|
92
|
-
};
|
|
93
|
-
}, []);
|
|
94
|
-
(0, _react.useLayoutEffect)(()=>{
|
|
95
|
-
if (!customNodeView || !customNodeViewRef.current) return;
|
|
96
|
-
const { destroy, update } = customNodeViewRef.current;
|
|
97
|
-
const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
|
|
98
|
-
if (updated) return;
|
|
99
|
-
destroy?.call(customNodeViewRef.current);
|
|
100
|
-
if (!customNodeViewRootRef.current) return;
|
|
101
|
-
initialNode.current = node;
|
|
102
|
-
initialOuterDeco.current = outerDeco;
|
|
103
|
-
initialInnerDeco.current = innerDeco;
|
|
104
|
-
customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
|
|
105
|
-
// this line if customNodeView is set
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
107
|
-
view, ()=>getPos.current(), initialOuterDeco.current, initialInnerDeco.current);
|
|
108
|
-
const { dom } = customNodeViewRef.current;
|
|
109
|
-
nodeDomRef.current = customNodeViewRootRef.current;
|
|
110
|
-
customNodeViewRootRef.current.appendChild(dom);
|
|
111
|
-
}, [
|
|
112
|
-
customNodeView,
|
|
113
|
-
view,
|
|
114
|
-
innerDeco,
|
|
115
|
-
node,
|
|
116
|
-
outerDeco,
|
|
117
|
-
getPos
|
|
118
|
-
]);
|
|
119
|
-
const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
120
|
-
const finalProps = {
|
|
121
|
-
...props,
|
|
122
|
-
...!hasContentDOM && {
|
|
123
|
-
contentEditable: false
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const nodeProps = (0, _react.useMemo)(()=>({
|
|
127
|
-
node: node,
|
|
128
|
-
getPos: getPosFunc,
|
|
129
|
-
decorations: outerDeco,
|
|
130
|
-
innerDecorations: innerDeco
|
|
131
|
-
}), [
|
|
132
|
-
getPosFunc,
|
|
133
|
-
innerDeco,
|
|
134
|
-
node,
|
|
135
|
-
outerDeco
|
|
136
|
-
]);
|
|
137
|
-
if (Component) {
|
|
138
|
-
element = /*#__PURE__*/ _react.default.createElement(Component, {
|
|
139
|
-
...finalProps,
|
|
140
|
-
ref: nodeDomRef,
|
|
141
|
-
nodeProps: nodeProps
|
|
142
|
-
}, /*#__PURE__*/ _react.default.createElement(_ChildNodeViews.ChildNodeViews, {
|
|
143
|
-
getPos: getPos,
|
|
144
|
-
node: node,
|
|
145
|
-
innerDecorations: innerDeco
|
|
146
|
-
}));
|
|
147
|
-
} else if (customNodeView) {
|
|
148
|
-
element = /*#__PURE__*/ _react.default.createElement(_CustomNodeView.CustomNodeView, {
|
|
149
|
-
contentDomRef: contentDomRef,
|
|
60
|
+
if (customNodeView) {
|
|
61
|
+
return /*#__PURE__*/ _react.default.createElement(_CustomNodeView.CustomNodeView, {
|
|
150
62
|
customNodeView: customNodeView,
|
|
151
|
-
customNodeViewRef: customNodeViewRef,
|
|
152
|
-
customNodeViewRootRef: customNodeViewRootRef,
|
|
153
|
-
initialInnerDeco: initialInnerDeco,
|
|
154
|
-
initialNode: initialNode,
|
|
155
|
-
initialOuterDeco: initialOuterDeco,
|
|
156
63
|
node: node,
|
|
157
|
-
|
|
158
|
-
|
|
64
|
+
innerDeco: innerDeco,
|
|
65
|
+
outerDeco: outerDeco,
|
|
66
|
+
getPos: getPos
|
|
159
67
|
});
|
|
160
|
-
} else {
|
|
161
|
-
if (outputSpec) {
|
|
162
|
-
element = /*#__PURE__*/ _react.default.createElement(_OutputSpec.OutputSpec, {
|
|
163
|
-
...finalProps,
|
|
164
|
-
ref: nodeDomRef,
|
|
165
|
-
outputSpec: outputSpec
|
|
166
|
-
}, /*#__PURE__*/ _react.default.createElement(_ChildNodeViews.ChildNodeViews, {
|
|
167
|
-
getPos: getPos,
|
|
168
|
-
node: node,
|
|
169
|
-
innerDecorations: innerDeco
|
|
170
|
-
}));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (!element) {
|
|
174
|
-
throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
|
|
175
68
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
parentRef: nodeViewDescRef,
|
|
184
|
-
siblingsRef: childDescriptors
|
|
185
|
-
}), [
|
|
186
|
-
childDescriptors,
|
|
187
|
-
nodeViewDescRef
|
|
188
|
-
]);
|
|
189
|
-
return /*#__PURE__*/ _react.default.createElement(_SelectNodeContext.SelectNodeContext.Provider, {
|
|
190
|
-
value: setSelectNode
|
|
191
|
-
}, /*#__PURE__*/ _react.default.createElement(_StopEventContext.StopEventContext.Provider, {
|
|
192
|
-
value: setStopEvent
|
|
193
|
-
}, /*#__PURE__*/ _react.default.createElement(_ChildDescriptorsContext.ChildDescriptorsContext.Provider, {
|
|
194
|
-
value: childContextValue
|
|
195
|
-
}, decoratedElement)));
|
|
69
|
+
return /*#__PURE__*/ _react.default.createElement(_ReactNodeView.ReactNodeView, {
|
|
70
|
+
node: node,
|
|
71
|
+
innerDeco: innerDeco,
|
|
72
|
+
outerDeco: outerDeco,
|
|
73
|
+
getPos: getPos,
|
|
74
|
+
...props
|
|
75
|
+
});
|
|
196
76
|
});
|
|
@@ -57,7 +57,7 @@ const ForwardedOutputSpec = /*#__PURE__*/ (0, _react.memo)(/*#__PURE__*/ (0, _re
|
|
|
57
57
|
return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, outputSpec);
|
|
58
58
|
}
|
|
59
59
|
if (!Array.isArray(outputSpec)) {
|
|
60
|
-
throw new Error("@
|
|
60
|
+
throw new Error("@handlewithcare/react-prosemirror only supports strings and arrays in toDOM");
|
|
61
61
|
}
|
|
62
62
|
const tagSpec = outputSpec[0];
|
|
63
63
|
const tagName = tagSpec.replace(" ", ":");
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "ReactNodeView", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return ReactNodeView;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
12
|
+
const _ChildDescriptorsContext = require("../contexts/ChildDescriptorsContext.js");
|
|
13
|
+
const _NodeViewContext = require("../contexts/NodeViewContext.js");
|
|
14
|
+
const _SelectNodeContext = require("../contexts/SelectNodeContext.js");
|
|
15
|
+
const _StopEventContext = require("../contexts/StopEventContext.js");
|
|
16
|
+
const _useNodeViewDescriptor = require("../hooks/useNodeViewDescriptor.js");
|
|
17
|
+
const _ChildNodeViews = require("./ChildNodeViews.js");
|
|
18
|
+
const _OutputSpec = require("./OutputSpec.js");
|
|
19
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
20
|
+
if (typeof WeakMap !== "function") return null;
|
|
21
|
+
var cacheBabelInterop = new WeakMap();
|
|
22
|
+
var cacheNodeInterop = new WeakMap();
|
|
23
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
24
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
25
|
+
})(nodeInterop);
|
|
26
|
+
}
|
|
27
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
28
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
32
|
+
return {
|
|
33
|
+
default: obj
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
37
|
+
if (cache && cache.has(obj)) {
|
|
38
|
+
return cache.get(obj);
|
|
39
|
+
}
|
|
40
|
+
var newObj = {
|
|
41
|
+
__proto__: null
|
|
42
|
+
};
|
|
43
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
44
|
+
for(var key in obj){
|
|
45
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
46
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
47
|
+
if (desc && (desc.get || desc.set)) {
|
|
48
|
+
Object.defineProperty(newObj, key, desc);
|
|
49
|
+
} else {
|
|
50
|
+
newObj[key] = obj[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
newObj.default = obj;
|
|
55
|
+
if (cache) {
|
|
56
|
+
cache.set(obj, newObj);
|
|
57
|
+
}
|
|
58
|
+
return newObj;
|
|
59
|
+
}
|
|
60
|
+
const ReactNodeView = /*#__PURE__*/ (0, _react.memo)(function ReactNodeView(param) {
|
|
61
|
+
let { outerDeco, getPos, node, innerDeco, ...props } = param;
|
|
62
|
+
const domRef = (0, _react.useRef)(null);
|
|
63
|
+
const nodeDomRef = (0, _react.useRef)(null);
|
|
64
|
+
const contentDomRef = (0, _react.useRef)(null);
|
|
65
|
+
const getPosFunc = (0, _react.useRef)(()=>getPos.current()).current;
|
|
66
|
+
const { nodeViews } = (0, _react.useContext)(_NodeViewContext.NodeViewContext);
|
|
67
|
+
let element = null;
|
|
68
|
+
const Component = nodeViews[node.type.name];
|
|
69
|
+
const outputSpec = (0, _react.useMemo)(()=>node.type.spec.toDOM?.(node), [
|
|
70
|
+
node
|
|
71
|
+
]);
|
|
72
|
+
const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, nodeViewDescRef } = (0, _useNodeViewDescriptor.useNodeViewDescriptor)(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
|
|
73
|
+
const finalProps = {
|
|
74
|
+
...props,
|
|
75
|
+
...!hasContentDOM && {
|
|
76
|
+
contentEditable: false
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const nodeProps = (0, _react.useMemo)(()=>({
|
|
80
|
+
node: node,
|
|
81
|
+
getPos: getPosFunc,
|
|
82
|
+
decorations: outerDeco,
|
|
83
|
+
innerDecorations: innerDeco
|
|
84
|
+
}), [
|
|
85
|
+
getPosFunc,
|
|
86
|
+
innerDeco,
|
|
87
|
+
node,
|
|
88
|
+
outerDeco
|
|
89
|
+
]);
|
|
90
|
+
if (Component) {
|
|
91
|
+
element = /*#__PURE__*/ _react.default.createElement(Component, {
|
|
92
|
+
...finalProps,
|
|
93
|
+
ref: nodeDomRef,
|
|
94
|
+
nodeProps: nodeProps
|
|
95
|
+
}, /*#__PURE__*/ _react.default.createElement(_ChildNodeViews.ChildNodeViews, {
|
|
96
|
+
getPos: getPos,
|
|
97
|
+
node: node,
|
|
98
|
+
innerDecorations: innerDeco
|
|
99
|
+
}));
|
|
100
|
+
} else {
|
|
101
|
+
if (outputSpec) {
|
|
102
|
+
element = /*#__PURE__*/ _react.default.createElement(_OutputSpec.OutputSpec, {
|
|
103
|
+
...finalProps,
|
|
104
|
+
ref: nodeDomRef,
|
|
105
|
+
outputSpec: outputSpec
|
|
106
|
+
}, /*#__PURE__*/ _react.default.createElement(_ChildNodeViews.ChildNodeViews, {
|
|
107
|
+
getPos: getPos,
|
|
108
|
+
node: node,
|
|
109
|
+
innerDecorations: innerDeco
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!element) {
|
|
114
|
+
throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
|
|
115
|
+
}
|
|
116
|
+
const decoratedElement = /*#__PURE__*/ (0, _react.cloneElement)(outerDeco.reduce(_ChildNodeViews.wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
|
+
outerDeco.some((d)=>d.type.attrs.nodeName) ? {
|
|
118
|
+
ref: domRef
|
|
119
|
+
} : // we've already passed the domRef to the NodeView component
|
|
120
|
+
// as a prop
|
|
121
|
+
undefined);
|
|
122
|
+
const childContextValue = (0, _react.useMemo)(()=>({
|
|
123
|
+
parentRef: nodeViewDescRef,
|
|
124
|
+
siblingsRef: childDescriptors
|
|
125
|
+
}), [
|
|
126
|
+
childDescriptors,
|
|
127
|
+
nodeViewDescRef
|
|
128
|
+
]);
|
|
129
|
+
return /*#__PURE__*/ _react.default.createElement(_SelectNodeContext.SelectNodeContext.Provider, {
|
|
130
|
+
value: setSelectNode
|
|
131
|
+
}, /*#__PURE__*/ _react.default.createElement(_StopEventContext.StopEventContext.Provider, {
|
|
132
|
+
value: setStopEvent
|
|
133
|
+
}, /*#__PURE__*/ _react.default.createElement(_ChildDescriptorsContext.ChildDescriptorsContext.Provider, {
|
|
134
|
+
value: childContextValue
|
|
135
|
+
}, decoratedElement)));
|
|
136
|
+
});
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "TextNodeView", {
|
|
|
10
10
|
});
|
|
11
11
|
const _prosemirrorview = require("prosemirror-view");
|
|
12
12
|
const _react = require("react");
|
|
13
|
-
const
|
|
13
|
+
const _findDOMNode = require("../findDOMNode.js");
|
|
14
14
|
const _viewdesc = require("../viewdesc.js");
|
|
15
15
|
const _ChildNodeViews = require("./ChildNodeViews.js");
|
|
16
16
|
function shallowEqual(objA, objB) {
|
|
@@ -42,7 +42,7 @@ let TextNodeView = class TextNodeView extends _react.Component {
|
|
|
42
42
|
const { view, decorations, siblingsRef, parentRef, getPos, node } = this.props;
|
|
43
43
|
// There simply is no other way to ref a text node
|
|
44
44
|
// eslint-disable-next-line react/no-find-dom-node
|
|
45
|
-
const dom = (0,
|
|
45
|
+
const dom = (0, _findDOMNode.findDOMNode)(this);
|
|
46
46
|
// We only need to explicitly create a CompositionViewDesc
|
|
47
47
|
// when a composition was started that produces a new text node.
|
|
48
48
|
// Otherwise we just rely on re-rendering the renderRef
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
findDOMNode: function() {
|
|
13
|
+
return findDOMNode;
|
|
14
|
+
},
|
|
15
|
+
getInstance: function() {
|
|
16
|
+
return getInstance;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const _reflection = require("react-reconciler/reflection");
|
|
20
|
+
function getInstance(key) {
|
|
21
|
+
return key._reactInternals;
|
|
22
|
+
}
|
|
23
|
+
// https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js#L322
|
|
24
|
+
function getPublicInstance(instance) {
|
|
25
|
+
return instance;
|
|
26
|
+
}
|
|
27
|
+
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberReconciler.js#L153
|
|
28
|
+
function findHostInstance(component) {
|
|
29
|
+
const fiber = getInstance(component);
|
|
30
|
+
if (fiber === undefined) {
|
|
31
|
+
if (typeof component.render === "function") {
|
|
32
|
+
throw new Error("Unable to find node on an unmounted component.");
|
|
33
|
+
} else {
|
|
34
|
+
const keys = Object.keys(component).join(",");
|
|
35
|
+
throw new Error(`Argument appears to not be a ReactComponent. Keys: ${keys}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const hostFiber = (0, _reflection.findCurrentHostFiber)(fiber);
|
|
39
|
+
if (hostFiber === null) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return getPublicInstance(hostFiber.stateNode);
|
|
43
|
+
}
|
|
44
|
+
function findDOMNode(componentOrElement) {
|
|
45
|
+
return findHostInstance(componentOrElement);
|
|
46
|
+
}
|
|
@@ -180,6 +180,7 @@ function useEditor(mount, options) {
|
|
|
180
180
|
didWarnValueDefaultValue = true;
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
+
const flushSyncRef = (0, _react.useRef)(true);
|
|
183
184
|
const [cursorWrapper, _setCursorWrapper] = (0, _react.useState)(null);
|
|
184
185
|
const forceUpdate = (0, _useForceUpdate.useForceUpdate)();
|
|
185
186
|
const defaultState = options.defaultState ?? EMPTY_STATE;
|
|
@@ -201,14 +202,23 @@ function useEditor(mount, options) {
|
|
|
201
202
|
setCursorWrapper
|
|
202
203
|
]);
|
|
203
204
|
const dispatchTransaction = (0, _react.useCallback)(function dispatchTransaction(tr) {
|
|
204
|
-
(
|
|
205
|
+
if (flushSyncRef.current) {
|
|
206
|
+
(0, _reactdom.flushSync)(()=>{
|
|
207
|
+
if (!options.state) {
|
|
208
|
+
setState((s)=>s.apply(tr));
|
|
209
|
+
}
|
|
210
|
+
if (options.dispatchTransaction) {
|
|
211
|
+
options.dispatchTransaction.call(this, tr);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
205
215
|
if (!options.state) {
|
|
206
216
|
setState((s)=>s.apply(tr));
|
|
207
217
|
}
|
|
208
218
|
if (options.dispatchTransaction) {
|
|
209
219
|
options.dispatchTransaction.call(this, tr);
|
|
210
220
|
}
|
|
211
|
-
}
|
|
221
|
+
}
|
|
212
222
|
}, [
|
|
213
223
|
options.dispatchTransaction,
|
|
214
224
|
options.state
|
|
@@ -273,7 +283,8 @@ function useEditor(mount, options) {
|
|
|
273
283
|
registerEventListener,
|
|
274
284
|
unregisterEventListener,
|
|
275
285
|
cursorWrapper,
|
|
276
|
-
docViewDescRef
|
|
286
|
+
docViewDescRef,
|
|
287
|
+
flushSyncRef
|
|
277
288
|
}), [
|
|
278
289
|
view,
|
|
279
290
|
registerEventListener,
|
|
@@ -12,7 +12,7 @@ const _react = require("react");
|
|
|
12
12
|
const _EditorContext = require("../contexts/EditorContext.js");
|
|
13
13
|
const _useLayoutGroupEffect = require("./useLayoutGroupEffect.js");
|
|
14
14
|
function useEditorEffect(effect, dependencies) {
|
|
15
|
-
const { view } = (0, _react.useContext)(_EditorContext.EditorContext);
|
|
15
|
+
const { view, flushSyncRef } = (0, _react.useContext)(_EditorContext.EditorContext);
|
|
16
16
|
// The rules of hooks want `effect` to be included in the
|
|
17
17
|
// dependency list, but dependency issues for `effect` will
|
|
18
18
|
// be caught by the linter at the call-site for
|
|
@@ -22,7 +22,10 @@ function useEditorEffect(effect, dependencies) {
|
|
|
22
22
|
// be defined inline and run on every re-render.
|
|
23
23
|
(0, _useLayoutGroupEffect.useLayoutGroupEffect)(()=>{
|
|
24
24
|
if (view) {
|
|
25
|
-
|
|
25
|
+
flushSyncRef.current = false;
|
|
26
|
+
const result = effect(view);
|
|
27
|
+
flushSyncRef.current = true;
|
|
28
|
+
return result;
|
|
26
29
|
}
|
|
27
30
|
}, // The rules of hooks want to be able to statically
|
|
28
31
|
// verify the dependencies for the effect, but this will
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "useIsNodeSelected", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return useIsNodeSelected;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = require("react");
|
|
12
|
+
const _useSelectNode = require("./useSelectNode.js");
|
|
13
|
+
function useIsNodeSelected() {
|
|
14
|
+
const [isSelected, setIsSelected] = (0, _react.useState)(false);
|
|
15
|
+
(0, _useSelectNode.useSelectNode)(()=>{
|
|
16
|
+
setIsSelected(true);
|
|
17
|
+
}, ()=>{
|
|
18
|
+
setIsSelected(false);
|
|
19
|
+
});
|
|
20
|
+
return isSelected;
|
|
21
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -31,6 +31,9 @@ _export(exports, {
|
|
|
31
31
|
useEditorState: function() {
|
|
32
32
|
return _useEditorState.useEditorState;
|
|
33
33
|
},
|
|
34
|
+
useIsNodeSelected: function() {
|
|
35
|
+
return _useIsNodeSelected.useIsNodeSelected;
|
|
36
|
+
},
|
|
34
37
|
useSelectNode: function() {
|
|
35
38
|
return _useSelectNode.useSelectNode;
|
|
36
39
|
},
|
|
@@ -49,5 +52,6 @@ const _useEditorEventListener = require("./hooks/useEditorEventListener.js");
|
|
|
49
52
|
const _useEditorState = require("./hooks/useEditorState.js");
|
|
50
53
|
const _useStopEvent = require("./hooks/useStopEvent.js");
|
|
51
54
|
const _useSelectNode = require("./hooks/useSelectNode.js");
|
|
55
|
+
const _useIsNodeSelected = require("./hooks/useIsNodeSelected.js");
|
|
52
56
|
const _reactKeys = require("./plugins/reactKeys.js");
|
|
53
57
|
const _ReactWidgetType = require("./decorations/ReactWidgetType.js");
|
|
@@ -26,7 +26,7 @@ function componentEventListeners(eventHandlerRegistry) {
|
|
|
26
26
|
domEventHandlers[eventType] = handleEvent;
|
|
27
27
|
}
|
|
28
28
|
const plugin = new _prosemirrorstate.Plugin({
|
|
29
|
-
key: new _prosemirrorstate.PluginKey("@
|
|
29
|
+
key: new _prosemirrorstate.PluginKey("@handlewithcare/react-prosemirror/componentEventListeners"),
|
|
30
30
|
props: {
|
|
31
31
|
handleDOMEvents: domEventHandlers
|
|
32
32
|
}
|
|
@@ -24,7 +24,7 @@ function createNodeKey() {
|
|
|
24
24
|
const key = Math.floor(Math.random() * 0xffffffffffff).toString(16);
|
|
25
25
|
return key;
|
|
26
26
|
}
|
|
27
|
-
const reactKeysPluginKey = new _prosemirrorstate.PluginKey("@
|
|
27
|
+
const reactKeysPluginKey = new _prosemirrorstate.PluginKey("@handlewithcare/react-prosemirror/reactKeys");
|
|
28
28
|
function reactKeys() {
|
|
29
29
|
let composing = false;
|
|
30
30
|
return new _prosemirrorstate.Plugin({
|