@handlewithcare/react-prosemirror 3.1.0-tiptap.29 → 3.1.0-tiptap.31
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/dist/cjs/components/marks/MarkViewConstructorView.js +8 -2
- package/dist/cjs/components/marks/ReactMarkView.js +24 -6
- package/dist/cjs/hooks/useMarkViewDescription.js +19 -13
- package/dist/cjs/tiptap/extensions/ReactProseMirrorCommands.js +21 -0
- package/dist/cjs/tiptap/extensions/commands/updateAttributes.js +104 -0
- package/dist/cjs/tiptap/hooks/useTiptapEditor.js +18 -0
- package/dist/cjs/viewdesc.js +10 -0
- package/dist/esm/components/marks/MarkViewConstructorView.js +8 -2
- package/dist/esm/components/marks/ReactMarkView.js +24 -6
- package/dist/esm/hooks/useMarkViewDescription.js +21 -15
- package/dist/esm/tiptap/extensions/ReactProseMirrorCommands.js +11 -0
- package/dist/esm/tiptap/extensions/commands/updateAttributes.js +96 -0
- package/dist/esm/tiptap/hooks/useTiptapEditor.js +18 -0
- package/dist/esm/viewdesc.js +7 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/hooks/useMarkViewDescription.d.ts +5 -10
- package/dist/types/tiptap/extensions/ReactProseMirrorCommands.d.ts +2 -0
- package/dist/types/tiptap/extensions/commands/updateAttributes.d.ts +24 -0
- package/dist/types/viewdesc.d.ts +3 -0
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ const _prosemirrormodel = require("prosemirror-model");
|
|
|
12
12
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
13
13
|
const _reactdom = require("react-dom");
|
|
14
14
|
const _ChildDescriptionsContext = require("../../contexts/ChildDescriptionsContext.js");
|
|
15
|
+
const _useForceUpdate = require("../../hooks/useForceUpdate.js");
|
|
15
16
|
const _useMarkViewDescription = require("../../hooks/useMarkViewDescription.js");
|
|
16
17
|
function _getRequireWildcardCache(nodeInterop) {
|
|
17
18
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -58,6 +59,7 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
|
|
|
58
59
|
let { constructor, mark, inline, getPos, children } = param;
|
|
59
60
|
const ref = (0, _react.useRef)(null);
|
|
60
61
|
const innerRef = (0, _react.useRef)(null);
|
|
62
|
+
const forceUpdate = (0, _useForceUpdate.useForceUpdate)();
|
|
61
63
|
const markProps = (0, _react.useMemo)(()=>({
|
|
62
64
|
mark,
|
|
63
65
|
inline,
|
|
@@ -84,13 +86,17 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
|
|
|
84
86
|
}
|
|
85
87
|
return markView;
|
|
86
88
|
};
|
|
87
|
-
const { childContextValue, contentDOM } = (0, _useMarkViewDescription.useMarkViewDescription)(ref, function() {
|
|
89
|
+
const { childContextValue, contentDOM } = (0, _useMarkViewDescription.useMarkViewDescription)(()=>ref.current, (markView)=>markView?.contentDOM ?? null, function() {
|
|
88
90
|
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
89
91
|
args[_key] = arguments[_key];
|
|
90
92
|
}
|
|
91
93
|
const markView = createMarkView(...args);
|
|
92
94
|
const dom = markView.dom;
|
|
93
95
|
const wrapperDOM = innerRef.current ?? ref.current;
|
|
96
|
+
wrapperDOM.appendChild(dom);
|
|
97
|
+
// Force a re-render so that we properly create
|
|
98
|
+
// a portal into the contentDOM/dom
|
|
99
|
+
forceUpdate();
|
|
94
100
|
return {
|
|
95
101
|
...markView,
|
|
96
102
|
destroy () {
|
|
@@ -99,7 +105,7 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
|
|
|
99
105
|
},
|
|
100
106
|
ignoreMutation: markView.ignoreMutation
|
|
101
107
|
};
|
|
102
|
-
},
|
|
108
|
+
}, markProps);
|
|
103
109
|
const Component = inline ? "span" : "div";
|
|
104
110
|
const props = {
|
|
105
111
|
ref: innerRef
|
|
@@ -67,17 +67,16 @@ const ReactMarkView = /*#__PURE__*/ (0, _react.memo)(function ReactMarkView(para
|
|
|
67
67
|
};
|
|
68
68
|
};
|
|
69
69
|
}, []);
|
|
70
|
-
const
|
|
70
|
+
const markViewDescProps = (0, _react.useMemo)(()=>({
|
|
71
71
|
mark,
|
|
72
72
|
getPos,
|
|
73
|
-
inline
|
|
74
|
-
contentDOMRef
|
|
73
|
+
inline
|
|
75
74
|
}), [
|
|
76
75
|
getPos,
|
|
77
76
|
inline,
|
|
78
77
|
mark
|
|
79
78
|
]);
|
|
80
|
-
const { childContextValue } = (0, _useMarkViewDescription.useMarkViewDescription)(ref, ()=>({
|
|
79
|
+
const { childContextValue, refUpdated } = (0, _useMarkViewDescription.useMarkViewDescription)(()=>ref.current, ()=>contentDOMRef.current ?? ref.current, ()=>({
|
|
81
80
|
dom: ref.current,
|
|
82
81
|
ignoreMutation (mutation) {
|
|
83
82
|
const ignoreMutation = ignoreMutationRef.current;
|
|
@@ -86,10 +85,29 @@ const ReactMarkView = /*#__PURE__*/ (0, _react.memo)(function ReactMarkView(para
|
|
|
86
85
|
}
|
|
87
86
|
return false;
|
|
88
87
|
}
|
|
89
|
-
}),
|
|
88
|
+
}), markViewDescProps);
|
|
89
|
+
const setDOM = (0, _react.useCallback)((el)=>{
|
|
90
|
+
ref.current = el;
|
|
91
|
+
refUpdated();
|
|
92
|
+
}, [
|
|
93
|
+
refUpdated
|
|
94
|
+
]);
|
|
95
|
+
const setContentDOM = (0, _react.useCallback)((el)=>{
|
|
96
|
+
contentDOMRef.current = el;
|
|
97
|
+
refUpdated();
|
|
98
|
+
}, [
|
|
99
|
+
refUpdated
|
|
100
|
+
]);
|
|
101
|
+
const markProps = (0, _react.useMemo)(()=>({
|
|
102
|
+
...markViewDescProps,
|
|
103
|
+
contentDOMRef: setContentDOM
|
|
104
|
+
}), [
|
|
105
|
+
markViewDescProps,
|
|
106
|
+
setContentDOM
|
|
107
|
+
]);
|
|
90
108
|
const props = {
|
|
91
109
|
markProps,
|
|
92
|
-
ref
|
|
110
|
+
ref: setDOM
|
|
93
111
|
};
|
|
94
112
|
return /*#__PURE__*/ _react.default.createElement(_IgnoreMutationContext.IgnoreMutationContext.Provider, {
|
|
95
113
|
value: setIgnoreMutation
|
|
@@ -15,18 +15,17 @@ const _EditorContext = require("../contexts/EditorContext.js");
|
|
|
15
15
|
const _viewdesc = require("../viewdesc.js");
|
|
16
16
|
const _useClientLayoutEffect = require("./useClientLayoutEffect.js");
|
|
17
17
|
const _useEffectEvent = require("./useEffectEvent.js");
|
|
18
|
-
function useMarkViewDescription(
|
|
18
|
+
function useMarkViewDescription(getDOM, getContentDOM, constructor, props) {
|
|
19
19
|
const { view } = (0, _react.useContext)(_EditorContext.EditorContext);
|
|
20
20
|
const { parentRef, siblingsRef } = (0, _react.useContext)(_ChildDescriptionsContext.ChildDescriptionsContext);
|
|
21
|
-
const
|
|
22
|
-
const [contentDOM, setContentDOM] = (0, _react.useState)(null);
|
|
21
|
+
const contentDOMRef = (0, _react.useRef)(null);
|
|
23
22
|
const viewDescRef = (0, _react.useRef)();
|
|
24
23
|
const childrenRef = (0, _react.useRef)([]);
|
|
25
24
|
const create = (0, _useEffectEvent.useEffectEvent)(()=>{
|
|
26
25
|
if (!(view instanceof _ReactEditorView.ReactEditorView)) {
|
|
27
26
|
return;
|
|
28
27
|
}
|
|
29
|
-
const dom =
|
|
28
|
+
const dom = getDOM();
|
|
30
29
|
if (!dom) {
|
|
31
30
|
return;
|
|
32
31
|
}
|
|
@@ -38,9 +37,8 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
38
37
|
const parent = parentRef.current;
|
|
39
38
|
const children = childrenRef.current;
|
|
40
39
|
const contentDOM = getContentDOM(markView);
|
|
41
|
-
const viewDesc = new _viewdesc.
|
|
42
|
-
|
|
43
|
-
setContentDOM(contentDOM);
|
|
40
|
+
const viewDesc = new _viewdesc.ReactMarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? markView.dom, markView);
|
|
41
|
+
contentDOMRef.current = contentDOM;
|
|
44
42
|
return viewDesc;
|
|
45
43
|
});
|
|
46
44
|
const update = (0, _useEffectEvent.useEffectEvent)(()=>{
|
|
@@ -51,7 +49,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
51
49
|
if (!viewDesc) {
|
|
52
50
|
return false;
|
|
53
51
|
}
|
|
54
|
-
const dom =
|
|
52
|
+
const dom = getDOM();
|
|
55
53
|
if (!dom || dom !== viewDesc.dom) {
|
|
56
54
|
return false;
|
|
57
55
|
}
|
|
@@ -73,8 +71,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
73
71
|
const index = siblings.indexOf(viewDesc);
|
|
74
72
|
siblings.splice(index, 1);
|
|
75
73
|
}
|
|
76
|
-
|
|
77
|
-
setContentDOM(null);
|
|
74
|
+
contentDOMRef.current = null;
|
|
78
75
|
});
|
|
79
76
|
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
80
77
|
viewDescRef.current = create();
|
|
@@ -85,6 +82,16 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
85
82
|
create,
|
|
86
83
|
destroy
|
|
87
84
|
]);
|
|
85
|
+
const refUpdated = (0, _react.useCallback)(()=>{
|
|
86
|
+
if (!update()) {
|
|
87
|
+
destroy();
|
|
88
|
+
viewDescRef.current = create();
|
|
89
|
+
}
|
|
90
|
+
}, [
|
|
91
|
+
create,
|
|
92
|
+
destroy,
|
|
93
|
+
update
|
|
94
|
+
]);
|
|
88
95
|
(0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
|
|
89
96
|
if (!update()) {
|
|
90
97
|
destroy();
|
|
@@ -115,8 +122,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
115
122
|
]);
|
|
116
123
|
return {
|
|
117
124
|
childContextValue,
|
|
118
|
-
dom,
|
|
119
|
-
|
|
120
|
-
ref
|
|
125
|
+
contentDOM: contentDOMRef.current ?? viewDescRef.current?.dom,
|
|
126
|
+
refUpdated
|
|
121
127
|
};
|
|
122
128
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "ReactProseMirrorCommands", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return ReactProseMirrorCommands;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _core = require("@tiptap/core");
|
|
12
|
+
const _updateAttributes = require("./commands/updateAttributes.js");
|
|
13
|
+
const ReactProseMirrorCommands = _core.Extension.create({
|
|
14
|
+
name: "reactProseMirrorCommands",
|
|
15
|
+
addCommands () {
|
|
16
|
+
return {
|
|
17
|
+
..._core.commands,
|
|
18
|
+
updateAttributes: _updateAttributes.updateAttributes
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "updateAttributes", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return updateAttributes;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _core = require("@tiptap/core");
|
|
12
|
+
const updateAttributes = function(typeOrName) {
|
|
13
|
+
let attributes = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
14
|
+
return (param)=>{
|
|
15
|
+
let { tr, state, dispatch } = param;
|
|
16
|
+
let nodeType = null;
|
|
17
|
+
let markType = null;
|
|
18
|
+
const schemaType = (0, _core.getSchemaTypeNameByName)(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
|
|
19
|
+
if (!schemaType) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (schemaType === "node") {
|
|
23
|
+
nodeType = (0, _core.getNodeType)(typeOrName, state.schema);
|
|
24
|
+
}
|
|
25
|
+
if (schemaType === "mark") {
|
|
26
|
+
markType = (0, _core.getMarkType)(typeOrName, state.schema);
|
|
27
|
+
}
|
|
28
|
+
let canUpdate = false;
|
|
29
|
+
tr.selection.ranges.forEach((range)=>{
|
|
30
|
+
const from = range.$from.pos;
|
|
31
|
+
const to = range.$to.pos;
|
|
32
|
+
let lastPos;
|
|
33
|
+
let lastNode;
|
|
34
|
+
let trimmedFrom;
|
|
35
|
+
let trimmedTo;
|
|
36
|
+
if (tr.selection.empty) {
|
|
37
|
+
state.doc.nodesBetween(from, to, (node, pos)=>{
|
|
38
|
+
if (nodeType && nodeType === node.type) {
|
|
39
|
+
canUpdate = true;
|
|
40
|
+
trimmedFrom = Math.max(pos, from);
|
|
41
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
42
|
+
lastPos = pos;
|
|
43
|
+
lastNode = node;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
state.doc.nodesBetween(from, to, (node, pos)=>{
|
|
48
|
+
if (pos < from && nodeType && nodeType === node.type) {
|
|
49
|
+
canUpdate = true;
|
|
50
|
+
trimmedFrom = Math.max(pos, from);
|
|
51
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
52
|
+
lastPos = pos;
|
|
53
|
+
lastNode = node;
|
|
54
|
+
}
|
|
55
|
+
if (pos >= from && pos <= to) {
|
|
56
|
+
if (nodeType && nodeType === node.type) {
|
|
57
|
+
canUpdate = true;
|
|
58
|
+
if (dispatch) {
|
|
59
|
+
Object.entries(attributes).forEach((param)=>{
|
|
60
|
+
let [key, value] = param;
|
|
61
|
+
tr.setNodeAttribute(pos, key, value);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (markType && node.marks.length) {
|
|
66
|
+
node.marks.forEach((mark)=>{
|
|
67
|
+
if (markType === mark.type) {
|
|
68
|
+
canUpdate = true;
|
|
69
|
+
if (dispatch) {
|
|
70
|
+
const trimmedFrom2 = Math.max(pos, from);
|
|
71
|
+
const trimmedTo2 = Math.min(pos + node.nodeSize, to);
|
|
72
|
+
tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
|
|
73
|
+
...mark.attrs,
|
|
74
|
+
...attributes
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (lastNode) {
|
|
84
|
+
if (dispatch) {
|
|
85
|
+
Object.entries(attributes).forEach((param)=>{
|
|
86
|
+
let [key, value] = param;
|
|
87
|
+
if (lastPos !== undefined) tr.setNodeAttribute(lastPos, key, value);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (markType && lastNode.marks.length) {
|
|
91
|
+
lastNode.marks.forEach((mark)=>{
|
|
92
|
+
if (markType === mark.type && dispatch) {
|
|
93
|
+
tr.addMark(trimmedFrom, trimmedTo, markType.create({
|
|
94
|
+
...mark.attrs,
|
|
95
|
+
...attributes
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return canUpdate;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
@@ -10,9 +10,27 @@ Object.defineProperty(exports, "useTiptapEditor", {
|
|
|
10
10
|
});
|
|
11
11
|
const _react = require("@tiptap/react");
|
|
12
12
|
const _StaticEditorView = require("../../StaticEditorView.js");
|
|
13
|
+
const _ReactProseMirror = require("../extensions/ReactProseMirror.js");
|
|
14
|
+
const _ReactProseMirrorCommands = require("../extensions/ReactProseMirrorCommands.js");
|
|
13
15
|
function useTiptapEditor(options, deps) {
|
|
16
|
+
const extensions = [
|
|
17
|
+
_ReactProseMirror.ReactProseMirror,
|
|
18
|
+
...options.extensions ?? []
|
|
19
|
+
];
|
|
20
|
+
// If a consumer explicitly disables core extensions (or the Commands core extension)
|
|
21
|
+
// do not re-add our custom Commands
|
|
22
|
+
if (options.enableCoreExtensions === false || typeof options.enableCoreExtensions === "object" && options?.enableCoreExtensions?.commands === false) {
|
|
23
|
+
// Do nothing
|
|
24
|
+
} else {
|
|
25
|
+
options.enableCoreExtensions = {
|
|
26
|
+
...typeof options.enableCoreExtensions === "object" ? options.enableCoreExtensions : {},
|
|
27
|
+
commands: false
|
|
28
|
+
};
|
|
29
|
+
extensions.push(_ReactProseMirrorCommands.ReactProseMirrorCommands);
|
|
30
|
+
}
|
|
14
31
|
const editor = (0, _react.useEditor)({
|
|
15
32
|
...options,
|
|
33
|
+
extensions,
|
|
16
34
|
element: null
|
|
17
35
|
}, deps);
|
|
18
36
|
// @ts-expect-error private property
|
package/dist/cjs/viewdesc.js
CHANGED
|
@@ -18,6 +18,9 @@ _export(exports, {
|
|
|
18
18
|
NodeViewDesc: function() {
|
|
19
19
|
return NodeViewDesc;
|
|
20
20
|
},
|
|
21
|
+
ReactMarkViewDesc: function() {
|
|
22
|
+
return ReactMarkViewDesc;
|
|
23
|
+
},
|
|
21
24
|
ReactNodeViewDesc: function() {
|
|
22
25
|
return ReactNodeViewDesc;
|
|
23
26
|
},
|
|
@@ -743,6 +746,13 @@ let CustomNodeViewDesc = class CustomNodeViewDesc extends NodeViewDesc {
|
|
|
743
746
|
return this.spec.ignoreMutation ? this.spec.ignoreMutation.call(this, mutation) : super.ignoreMutation(mutation);
|
|
744
747
|
}
|
|
745
748
|
};
|
|
749
|
+
let ReactMarkViewDesc = class ReactMarkViewDesc extends MarkViewDesc {
|
|
750
|
+
destroy() {
|
|
751
|
+
// React has already destroyed the children (if needed).
|
|
752
|
+
this.children = [];
|
|
753
|
+
super.destroy();
|
|
754
|
+
}
|
|
755
|
+
};
|
|
746
756
|
let ReactNodeViewDesc = class ReactNodeViewDesc extends CustomNodeViewDesc {
|
|
747
757
|
updateChildren(_view, _pos) {
|
|
748
758
|
// React has already updated the children.
|
|
@@ -2,11 +2,13 @@ import { DOMSerializer } from "prosemirror-model";
|
|
|
2
2
|
import React, { memo, useMemo, useRef } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { ChildDescriptionsContext } from "../../contexts/ChildDescriptionsContext.js";
|
|
5
|
+
import { useForceUpdate } from "../../hooks/useForceUpdate.js";
|
|
5
6
|
import { useMarkViewDescription } from "../../hooks/useMarkViewDescription.js";
|
|
6
7
|
export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConstructorView(param) {
|
|
7
8
|
let { constructor, mark, inline, getPos, children } = param;
|
|
8
9
|
const ref = useRef(null);
|
|
9
10
|
const innerRef = useRef(null);
|
|
11
|
+
const forceUpdate = useForceUpdate();
|
|
10
12
|
const markProps = useMemo(()=>({
|
|
11
13
|
mark,
|
|
12
14
|
inline,
|
|
@@ -33,13 +35,17 @@ export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConst
|
|
|
33
35
|
}
|
|
34
36
|
return markView;
|
|
35
37
|
};
|
|
36
|
-
const { childContextValue, contentDOM } = useMarkViewDescription(ref, function() {
|
|
38
|
+
const { childContextValue, contentDOM } = useMarkViewDescription(()=>ref.current, (markView)=>markView?.contentDOM ?? null, function() {
|
|
37
39
|
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
|
|
38
40
|
args[_key] = arguments[_key];
|
|
39
41
|
}
|
|
40
42
|
const markView = createMarkView(...args);
|
|
41
43
|
const dom = markView.dom;
|
|
42
44
|
const wrapperDOM = innerRef.current ?? ref.current;
|
|
45
|
+
wrapperDOM.appendChild(dom);
|
|
46
|
+
// Force a re-render so that we properly create
|
|
47
|
+
// a portal into the contentDOM/dom
|
|
48
|
+
forceUpdate();
|
|
43
49
|
return {
|
|
44
50
|
...markView,
|
|
45
51
|
destroy () {
|
|
@@ -48,7 +54,7 @@ export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConst
|
|
|
48
54
|
},
|
|
49
55
|
ignoreMutation: markView.ignoreMutation
|
|
50
56
|
};
|
|
51
|
-
},
|
|
57
|
+
}, markProps);
|
|
52
58
|
const Component = inline ? "span" : "div";
|
|
53
59
|
const props = {
|
|
54
60
|
ref: innerRef
|
|
@@ -16,17 +16,16 @@ export const ReactMarkView = /*#__PURE__*/ memo(function ReactMarkView(param) {
|
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
18
|
}, []);
|
|
19
|
-
const
|
|
19
|
+
const markViewDescProps = useMemo(()=>({
|
|
20
20
|
mark,
|
|
21
21
|
getPos,
|
|
22
|
-
inline
|
|
23
|
-
contentDOMRef
|
|
22
|
+
inline
|
|
24
23
|
}), [
|
|
25
24
|
getPos,
|
|
26
25
|
inline,
|
|
27
26
|
mark
|
|
28
27
|
]);
|
|
29
|
-
const { childContextValue } = useMarkViewDescription(ref, ()=>({
|
|
28
|
+
const { childContextValue, refUpdated } = useMarkViewDescription(()=>ref.current, ()=>contentDOMRef.current ?? ref.current, ()=>({
|
|
30
29
|
dom: ref.current,
|
|
31
30
|
ignoreMutation (mutation) {
|
|
32
31
|
const ignoreMutation = ignoreMutationRef.current;
|
|
@@ -35,10 +34,29 @@ export const ReactMarkView = /*#__PURE__*/ memo(function ReactMarkView(param) {
|
|
|
35
34
|
}
|
|
36
35
|
return false;
|
|
37
36
|
}
|
|
38
|
-
}),
|
|
37
|
+
}), markViewDescProps);
|
|
38
|
+
const setDOM = useCallback((el)=>{
|
|
39
|
+
ref.current = el;
|
|
40
|
+
refUpdated();
|
|
41
|
+
}, [
|
|
42
|
+
refUpdated
|
|
43
|
+
]);
|
|
44
|
+
const setContentDOM = useCallback((el)=>{
|
|
45
|
+
contentDOMRef.current = el;
|
|
46
|
+
refUpdated();
|
|
47
|
+
}, [
|
|
48
|
+
refUpdated
|
|
49
|
+
]);
|
|
50
|
+
const markProps = useMemo(()=>({
|
|
51
|
+
...markViewDescProps,
|
|
52
|
+
contentDOMRef: setContentDOM
|
|
53
|
+
}), [
|
|
54
|
+
markViewDescProps,
|
|
55
|
+
setContentDOM
|
|
56
|
+
]);
|
|
39
57
|
const props = {
|
|
40
58
|
markProps,
|
|
41
|
-
ref
|
|
59
|
+
ref: setDOM
|
|
42
60
|
};
|
|
43
61
|
return /*#__PURE__*/ React.createElement(IgnoreMutationContext.Provider, {
|
|
44
62
|
value: setIgnoreMutation
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import { useContext, useMemo, useRef
|
|
1
|
+
import { useCallback, useContext, useMemo, useRef } from "react";
|
|
2
2
|
import { ReactEditorView } from "../ReactEditorView.js";
|
|
3
3
|
import { ChildDescriptionsContext } from "../contexts/ChildDescriptionsContext.js";
|
|
4
4
|
import { EditorContext } from "../contexts/EditorContext.js";
|
|
5
|
-
import {
|
|
5
|
+
import { ReactMarkViewDesc, sortViewDescs } from "../viewdesc.js";
|
|
6
6
|
import { useClientLayoutEffect } from "./useClientLayoutEffect.js";
|
|
7
7
|
import { useEffectEvent } from "./useEffectEvent.js";
|
|
8
|
-
export function useMarkViewDescription(
|
|
8
|
+
export function useMarkViewDescription(getDOM, getContentDOM, constructor, props) {
|
|
9
9
|
const { view } = useContext(EditorContext);
|
|
10
10
|
const { parentRef, siblingsRef } = useContext(ChildDescriptionsContext);
|
|
11
|
-
const
|
|
12
|
-
const [contentDOM, setContentDOM] = useState(null);
|
|
11
|
+
const contentDOMRef = useRef(null);
|
|
13
12
|
const viewDescRef = useRef();
|
|
14
13
|
const childrenRef = useRef([]);
|
|
15
14
|
const create = useEffectEvent(()=>{
|
|
16
15
|
if (!(view instanceof ReactEditorView)) {
|
|
17
16
|
return;
|
|
18
17
|
}
|
|
19
|
-
const dom =
|
|
18
|
+
const dom = getDOM();
|
|
20
19
|
if (!dom) {
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
@@ -28,9 +27,8 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
28
27
|
const parent = parentRef.current;
|
|
29
28
|
const children = childrenRef.current;
|
|
30
29
|
const contentDOM = getContentDOM(markView);
|
|
31
|
-
const viewDesc = new
|
|
32
|
-
|
|
33
|
-
setContentDOM(contentDOM);
|
|
30
|
+
const viewDesc = new ReactMarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? markView.dom, markView);
|
|
31
|
+
contentDOMRef.current = contentDOM;
|
|
34
32
|
return viewDesc;
|
|
35
33
|
});
|
|
36
34
|
const update = useEffectEvent(()=>{
|
|
@@ -41,7 +39,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
41
39
|
if (!viewDesc) {
|
|
42
40
|
return false;
|
|
43
41
|
}
|
|
44
|
-
const dom =
|
|
42
|
+
const dom = getDOM();
|
|
45
43
|
if (!dom || dom !== viewDesc.dom) {
|
|
46
44
|
return false;
|
|
47
45
|
}
|
|
@@ -63,8 +61,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
63
61
|
const index = siblings.indexOf(viewDesc);
|
|
64
62
|
siblings.splice(index, 1);
|
|
65
63
|
}
|
|
66
|
-
|
|
67
|
-
setContentDOM(null);
|
|
64
|
+
contentDOMRef.current = null;
|
|
68
65
|
});
|
|
69
66
|
useClientLayoutEffect(()=>{
|
|
70
67
|
viewDescRef.current = create();
|
|
@@ -75,6 +72,16 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
75
72
|
create,
|
|
76
73
|
destroy
|
|
77
74
|
]);
|
|
75
|
+
const refUpdated = useCallback(()=>{
|
|
76
|
+
if (!update()) {
|
|
77
|
+
destroy();
|
|
78
|
+
viewDescRef.current = create();
|
|
79
|
+
}
|
|
80
|
+
}, [
|
|
81
|
+
create,
|
|
82
|
+
destroy,
|
|
83
|
+
update
|
|
84
|
+
]);
|
|
78
85
|
useClientLayoutEffect(()=>{
|
|
79
86
|
if (!update()) {
|
|
80
87
|
destroy();
|
|
@@ -105,8 +112,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
|
|
|
105
112
|
]);
|
|
106
113
|
return {
|
|
107
114
|
childContextValue,
|
|
108
|
-
dom,
|
|
109
|
-
|
|
110
|
-
ref
|
|
115
|
+
contentDOM: contentDOMRef.current ?? viewDescRef.current?.dom,
|
|
116
|
+
refUpdated
|
|
111
117
|
};
|
|
112
118
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Extension, commands as coreCommands } from "@tiptap/core";
|
|
2
|
+
import { updateAttributes } from "./commands/updateAttributes.js";
|
|
3
|
+
export const ReactProseMirrorCommands = Extension.create({
|
|
4
|
+
name: "reactProseMirrorCommands",
|
|
5
|
+
addCommands () {
|
|
6
|
+
return {
|
|
7
|
+
...coreCommands,
|
|
8
|
+
updateAttributes
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getMarkType, getNodeType, getSchemaTypeNameByName } from "@tiptap/core";
|
|
2
|
+
// Tiptap's updateAttributes command, but using setNodeAttribute instead of
|
|
3
|
+
// setNodeMarkup to avoid replacing entire leaf nodes
|
|
4
|
+
export const updateAttributes = function(typeOrName) {
|
|
5
|
+
let attributes = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
6
|
+
return (param)=>{
|
|
7
|
+
let { tr, state, dispatch } = param;
|
|
8
|
+
let nodeType = null;
|
|
9
|
+
let markType = null;
|
|
10
|
+
const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
|
|
11
|
+
if (!schemaType) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (schemaType === "node") {
|
|
15
|
+
nodeType = getNodeType(typeOrName, state.schema);
|
|
16
|
+
}
|
|
17
|
+
if (schemaType === "mark") {
|
|
18
|
+
markType = getMarkType(typeOrName, state.schema);
|
|
19
|
+
}
|
|
20
|
+
let canUpdate = false;
|
|
21
|
+
tr.selection.ranges.forEach((range)=>{
|
|
22
|
+
const from = range.$from.pos;
|
|
23
|
+
const to = range.$to.pos;
|
|
24
|
+
let lastPos;
|
|
25
|
+
let lastNode;
|
|
26
|
+
let trimmedFrom;
|
|
27
|
+
let trimmedTo;
|
|
28
|
+
if (tr.selection.empty) {
|
|
29
|
+
state.doc.nodesBetween(from, to, (node, pos)=>{
|
|
30
|
+
if (nodeType && nodeType === node.type) {
|
|
31
|
+
canUpdate = true;
|
|
32
|
+
trimmedFrom = Math.max(pos, from);
|
|
33
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
34
|
+
lastPos = pos;
|
|
35
|
+
lastNode = node;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
state.doc.nodesBetween(from, to, (node, pos)=>{
|
|
40
|
+
if (pos < from && nodeType && nodeType === node.type) {
|
|
41
|
+
canUpdate = true;
|
|
42
|
+
trimmedFrom = Math.max(pos, from);
|
|
43
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
44
|
+
lastPos = pos;
|
|
45
|
+
lastNode = node;
|
|
46
|
+
}
|
|
47
|
+
if (pos >= from && pos <= to) {
|
|
48
|
+
if (nodeType && nodeType === node.type) {
|
|
49
|
+
canUpdate = true;
|
|
50
|
+
if (dispatch) {
|
|
51
|
+
Object.entries(attributes).forEach((param)=>{
|
|
52
|
+
let [key, value] = param;
|
|
53
|
+
tr.setNodeAttribute(pos, key, value);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (markType && node.marks.length) {
|
|
58
|
+
node.marks.forEach((mark)=>{
|
|
59
|
+
if (markType === mark.type) {
|
|
60
|
+
canUpdate = true;
|
|
61
|
+
if (dispatch) {
|
|
62
|
+
const trimmedFrom2 = Math.max(pos, from);
|
|
63
|
+
const trimmedTo2 = Math.min(pos + node.nodeSize, to);
|
|
64
|
+
tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
|
|
65
|
+
...mark.attrs,
|
|
66
|
+
...attributes
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (lastNode) {
|
|
76
|
+
if (dispatch) {
|
|
77
|
+
Object.entries(attributes).forEach((param)=>{
|
|
78
|
+
let [key, value] = param;
|
|
79
|
+
if (lastPos !== undefined) tr.setNodeAttribute(lastPos, key, value);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (markType && lastNode.marks.length) {
|
|
83
|
+
lastNode.marks.forEach((mark)=>{
|
|
84
|
+
if (markType === mark.type && dispatch) {
|
|
85
|
+
tr.addMark(trimmedFrom, trimmedTo, markType.create({
|
|
86
|
+
...mark.attrs,
|
|
87
|
+
...attributes
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return canUpdate;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import { useEditor } from "@tiptap/react";
|
|
2
2
|
import { StaticEditorView } from "../../StaticEditorView.js";
|
|
3
|
+
import { ReactProseMirror } from "../extensions/ReactProseMirror.js";
|
|
4
|
+
import { ReactProseMirrorCommands } from "../extensions/ReactProseMirrorCommands.js";
|
|
3
5
|
export function useTiptapEditor(options, deps) {
|
|
6
|
+
const extensions = [
|
|
7
|
+
ReactProseMirror,
|
|
8
|
+
...options.extensions ?? []
|
|
9
|
+
];
|
|
10
|
+
// If a consumer explicitly disables core extensions (or the Commands core extension)
|
|
11
|
+
// do not re-add our custom Commands
|
|
12
|
+
if (options.enableCoreExtensions === false || typeof options.enableCoreExtensions === "object" && options?.enableCoreExtensions?.commands === false) {
|
|
13
|
+
// Do nothing
|
|
14
|
+
} else {
|
|
15
|
+
options.enableCoreExtensions = {
|
|
16
|
+
...typeof options.enableCoreExtensions === "object" ? options.enableCoreExtensions : {},
|
|
17
|
+
commands: false
|
|
18
|
+
};
|
|
19
|
+
extensions.push(ReactProseMirrorCommands);
|
|
20
|
+
}
|
|
4
21
|
const editor = useEditor({
|
|
5
22
|
...options,
|
|
23
|
+
extensions,
|
|
6
24
|
element: null
|
|
7
25
|
}, deps);
|
|
8
26
|
// @ts-expect-error private property
|