@handlewithcare/react-prosemirror 2.4.10 → 2.4.12
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 +16 -0
- package/dist/cjs/components/Editor.js +28 -0
- package/dist/cjs/components/NodeViews.js +73 -0
- package/dist/cjs/{contexts/__tests__/DeferredLayoutEffects.test.js → components/__tests__/LayoutGroup.test.js} +2 -2
- package/dist/cjs/components/__tests__/ProseMirror.test.js +136 -263
- package/dist/cjs/contexts/NodeViewsContext.js +10 -0
- package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +27 -28
- package/dist/cjs/hooks/__tests__/useNodeViews.test.js +159 -0
- package/dist/cjs/hooks/useEditor.js +2 -4
- package/dist/cjs/hooks/useEditorView.js +100 -0
- package/dist/cjs/hooks/useNodePos.js +69 -0
- package/dist/cjs/hooks/useNodeViews.js +100 -0
- package/dist/cjs/nodeViews/createReactNodeViewConstructor.js +244 -0
- package/dist/cjs/nodeViews/phrasingContentTags.js +57 -0
- package/dist/cjs/plugins/__tests__/react.test.js +139 -0
- package/dist/cjs/plugins/react.js +71 -0
- package/dist/esm/components/Editor.js +15 -0
- package/dist/esm/components/NodeViews.js +26 -0
- package/dist/esm/{contexts/__tests__/DeferredLayoutEffects.test.js → components/__tests__/LayoutGroup.test.js} +2 -2
- package/dist/esm/components/__tests__/ProseMirror.test.js +135 -267
- package/dist/esm/contexts/NodeViewsContext.js +9 -0
- package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +27 -28
- package/dist/esm/hooks/__tests__/useNodeViews.test.js +116 -0
- package/dist/esm/hooks/useEditor.js +2 -4
- package/dist/esm/hooks/useEditorView.js +99 -0
- package/dist/esm/hooks/useNodePos.js +16 -0
- package/dist/esm/hooks/useNodeViews.js +53 -0
- package/dist/esm/nodeViews/createReactNodeViewConstructor.js +214 -0
- package/dist/esm/nodeViews/phrasingContentTags.js +49 -0
- package/dist/esm/plugins/__tests__/react.test.js +135 -0
- package/dist/esm/plugins/react.js +64 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/components/Editor.d.ts +7 -0
- package/dist/types/components/NodeViews.d.ts +6 -0
- package/dist/types/components/__tests__/LayoutGroup.test.d.ts +1 -0
- package/dist/types/contexts/NodeViewsContext.d.ts +19 -0
- package/dist/types/decorations/ReactWidgetType.d.ts +1 -0
- package/dist/types/hooks/__tests__/useNodeViews.test.d.ts +1 -0
- package/dist/types/hooks/useEditorView.d.ts +23 -0
- package/dist/types/hooks/useNodePos.d.ts +9 -0
- package/dist/types/hooks/useNodeViews.d.ts +5 -0
- package/dist/types/nodeViews/createReactNodeViewConstructor.d.ts +48 -0
- package/dist/types/nodeViews/phrasingContentTags.d.ts +1 -0
- package/dist/types/plugins/__tests__/react.test.d.ts +1 -0
- package/dist/types/plugins/react.d.ts +21 -0
- package/dist/types/props.d.ts +27 -27
- package/package.json +1 -1
- package/dist/cjs/components/__tests__/ProseMirror.composition.test.js +0 -398
- package/dist/cjs/components/__tests__/ProseMirror.domchange.test.js +0 -270
- package/dist/cjs/components/__tests__/ProseMirror.draw-decoration.test.js +0 -1010
- package/dist/cjs/components/__tests__/ProseMirror.draw.test.js +0 -337
- package/dist/cjs/components/__tests__/ProseMirror.node-view.test.js +0 -315
- package/dist/cjs/components/__tests__/ProseMirror.selection.test.js +0 -444
- package/dist/cjs/plugins/__tests__/reactKeys.test.js +0 -81
- package/dist/esm/components/__tests__/ProseMirror.composition.test.js +0 -395
- package/dist/esm/components/__tests__/ProseMirror.domchange.test.js +0 -266
- package/dist/esm/components/__tests__/ProseMirror.draw-decoration.test.js +0 -967
- package/dist/esm/components/__tests__/ProseMirror.draw.test.js +0 -294
- package/dist/esm/components/__tests__/ProseMirror.node-view.test.js +0 -272
- package/dist/esm/components/__tests__/ProseMirror.selection.test.js +0 -440
- package/dist/esm/plugins/__tests__/reactKeys.test.js +0 -77
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */ function _extends() {
|
|
2
|
-
_extends = Object.assign || function(target) {
|
|
3
|
-
for(var i = 1; i < arguments.length; i++){
|
|
4
|
-
var source = arguments[i];
|
|
5
|
-
for(var key in source){
|
|
6
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
7
|
-
target[key] = source[key];
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
return target;
|
|
12
|
-
};
|
|
13
|
-
return _extends.apply(this, arguments);
|
|
14
|
-
}
|
|
15
|
-
import { Schema } from "prosemirror-model";
|
|
16
|
-
import { Plugin } from "prosemirror-state";
|
|
17
|
-
import { doc, h1, hr, img, p, pre, schema, strong } from "prosemirror-test-builder";
|
|
18
|
-
import React, { forwardRef } from "react";
|
|
19
|
-
import { tempEditor } from "../../testing/editorViewTestHelpers.js";
|
|
20
|
-
describe("EditorView draw", ()=>{
|
|
21
|
-
it("updates the DOM", async ()=>{
|
|
22
|
-
const { view } = tempEditor({
|
|
23
|
-
doc: doc(p("foo"))
|
|
24
|
-
});
|
|
25
|
-
view.dispatch(view.state.tr.insertText("bar"));
|
|
26
|
-
expect(view.dom.textContent).toBe("barfoo");
|
|
27
|
-
});
|
|
28
|
-
it("doesn't redraw nodes after changes", async ()=>{
|
|
29
|
-
const { view } = tempEditor({
|
|
30
|
-
doc: doc(h1("foo<a>"), p("bar"))
|
|
31
|
-
});
|
|
32
|
-
const oldP = view.dom.querySelector("p");
|
|
33
|
-
view.dispatch(view.state.tr.insertText("!"));
|
|
34
|
-
expect(view.dom.querySelector("p")).toBe(oldP);
|
|
35
|
-
});
|
|
36
|
-
it("doesn't redraw nodes before changes", async ()=>{
|
|
37
|
-
const { view } = tempEditor({
|
|
38
|
-
doc: doc(p("foo"), h1("bar"))
|
|
39
|
-
});
|
|
40
|
-
const oldP = view.dom.querySelector("p");
|
|
41
|
-
view.dispatch(view.state.tr.insertText("!", 2));
|
|
42
|
-
expect(view.dom.querySelector("p")).toBe(oldP);
|
|
43
|
-
});
|
|
44
|
-
it("doesn't redraw nodes between changes", async ()=>{
|
|
45
|
-
const { view } = tempEditor({
|
|
46
|
-
doc: doc(p("foo"), h1("bar"), pre("baz"))
|
|
47
|
-
});
|
|
48
|
-
const oldP = view.dom.querySelector("p");
|
|
49
|
-
const oldPre = view.dom.querySelector("pre");
|
|
50
|
-
view.dispatch(view.state.tr.insertText("!", 2));
|
|
51
|
-
expect(view.dom.querySelector("p")).toBe(oldP);
|
|
52
|
-
expect(view.dom.querySelector("pre")).toBe(oldPre);
|
|
53
|
-
});
|
|
54
|
-
it("doesn't redraw siblings of a split node", async ()=>{
|
|
55
|
-
const { view } = tempEditor({
|
|
56
|
-
doc: doc(p("foo"), h1("bar"), pre("baz"))
|
|
57
|
-
});
|
|
58
|
-
const oldP = view.dom.querySelector("p");
|
|
59
|
-
const oldPre = view.dom.querySelector("pre");
|
|
60
|
-
view.dispatch(view.state.tr.split(8));
|
|
61
|
-
expect(view.dom.querySelector("p")).toBe(oldP);
|
|
62
|
-
expect(view.dom.querySelector("pre")).toBe(oldPre);
|
|
63
|
-
});
|
|
64
|
-
it("doesn't redraw siblings of a joined node", async ()=>{
|
|
65
|
-
const { view } = tempEditor({
|
|
66
|
-
doc: doc(p("foo"), h1("bar"), h1("x"), pre("baz"))
|
|
67
|
-
});
|
|
68
|
-
const oldP = view.dom.querySelector("p");
|
|
69
|
-
const oldPre = view.dom.querySelector("pre");
|
|
70
|
-
view.dispatch(view.state.tr.join(10));
|
|
71
|
-
expect(view.dom.querySelector("p")).toBe(oldP);
|
|
72
|
-
expect(view.dom.querySelector("pre")).toBe(oldPre);
|
|
73
|
-
});
|
|
74
|
-
it("doesn't redraw after a big deletion", async ()=>{
|
|
75
|
-
const { view } = tempEditor({
|
|
76
|
-
doc: doc(p(), p(), p(), p(), p(), p(), p(), p(), h1("!"), p(), p())
|
|
77
|
-
});
|
|
78
|
-
const oldH = view.dom.querySelector("h1");
|
|
79
|
-
view.dispatch(view.state.tr.delete(2, 14));
|
|
80
|
-
expect(view.dom.querySelector("h1")).toBe(oldH);
|
|
81
|
-
});
|
|
82
|
-
it("adds classes from the attributes prop", async ()=>{
|
|
83
|
-
const { view , rerender } = tempEditor({
|
|
84
|
-
doc: doc(p()),
|
|
85
|
-
attributes: {
|
|
86
|
-
class: "foo bar"
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
expect(view.dom.classList.contains("foo")).toBeTruthy();
|
|
90
|
-
expect(view.dom.classList.contains("bar")).toBeTruthy();
|
|
91
|
-
expect(view.dom.classList.contains("ProseMirror")).toBeTruthy();
|
|
92
|
-
rerender({
|
|
93
|
-
attributes: {
|
|
94
|
-
class: "baz"
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
expect(!view.dom.classList.contains("foo")).toBeTruthy();
|
|
98
|
-
expect(view.dom.classList.contains("baz")).toBeTruthy();
|
|
99
|
-
});
|
|
100
|
-
it("adds style from the attributes prop", async ()=>{
|
|
101
|
-
const { view } = tempEditor({
|
|
102
|
-
doc: doc(p()),
|
|
103
|
-
attributes: {
|
|
104
|
-
style: "border: 1px solid red;"
|
|
105
|
-
},
|
|
106
|
-
plugins: [
|
|
107
|
-
new Plugin({
|
|
108
|
-
props: {
|
|
109
|
-
attributes: {
|
|
110
|
-
style: "background: red;"
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}),
|
|
114
|
-
new Plugin({
|
|
115
|
-
props: {
|
|
116
|
-
attributes: {
|
|
117
|
-
style: "color: red;"
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
]
|
|
122
|
-
});
|
|
123
|
-
expect(view.dom.style.border).toBe("1px solid red");
|
|
124
|
-
expect(view.dom.style.backgroundColor).toBe("red");
|
|
125
|
-
expect(view.dom.style.color).toBe("red");
|
|
126
|
-
});
|
|
127
|
-
it("can set other attributes", async ()=>{
|
|
128
|
-
const { view , rerender } = tempEditor({
|
|
129
|
-
doc: doc(p()),
|
|
130
|
-
attributes: {
|
|
131
|
-
spellcheck: "false",
|
|
132
|
-
"aria-label": "hello"
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
expect(view.dom.spellcheck).toBe(false);
|
|
136
|
-
expect(view.dom.getAttribute("aria-label")).toBe("hello");
|
|
137
|
-
rerender({
|
|
138
|
-
attributes: {
|
|
139
|
-
style: "background-color: yellow"
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
expect(view.dom.hasAttribute("aria-label")).toBe(false);
|
|
143
|
-
expect(view.dom.style.backgroundColor).toBe("yellow");
|
|
144
|
-
});
|
|
145
|
-
it("can't set the contenteditable attribute", async ()=>{
|
|
146
|
-
const { view } = tempEditor({
|
|
147
|
-
doc: doc(p()),
|
|
148
|
-
attributes: {
|
|
149
|
-
contenteditable: "false"
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
expect(view.dom.contentEditable).toBe("true");
|
|
153
|
-
});
|
|
154
|
-
it("understands the editable prop", async ()=>{
|
|
155
|
-
const { view , rerender } = tempEditor({
|
|
156
|
-
doc: doc(p()),
|
|
157
|
-
editable: ()=>false
|
|
158
|
-
});
|
|
159
|
-
expect(view.dom.contentEditable).toBe("false");
|
|
160
|
-
rerender({
|
|
161
|
-
editable: ()=>true
|
|
162
|
-
});
|
|
163
|
-
expect(view.dom.contentEditable).toBe("true");
|
|
164
|
-
});
|
|
165
|
-
it("doesn't redraw following paragraphs when a paragraph is split", async ()=>{
|
|
166
|
-
const { view } = tempEditor({
|
|
167
|
-
doc: doc(p("abcde"), p("fg"))
|
|
168
|
-
});
|
|
169
|
-
const lastPara = view.dom.lastChild;
|
|
170
|
-
view.dispatch(view.state.tr.split(3));
|
|
171
|
-
expect(view.dom.lastChild).toBe(lastPara);
|
|
172
|
-
});
|
|
173
|
-
it("doesn't greedily match nodes that have another match", async ()=>{
|
|
174
|
-
const { view } = tempEditor({
|
|
175
|
-
doc: doc(p("a"), p("b"), p())
|
|
176
|
-
});
|
|
177
|
-
const secondPara = view.dom.querySelectorAll("p")[1];
|
|
178
|
-
view.dispatch(view.state.tr.split(2));
|
|
179
|
-
expect(view.dom.querySelectorAll("p")[2]).toBe(secondPara);
|
|
180
|
-
});
|
|
181
|
-
it("creates and destroys plugin views", async ()=>{
|
|
182
|
-
const events = [];
|
|
183
|
-
let PluginView = class PluginView {
|
|
184
|
-
update() {
|
|
185
|
-
events.push("update");
|
|
186
|
-
}
|
|
187
|
-
destroy() {
|
|
188
|
-
events.push("destroy");
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
const plugin = new Plugin({
|
|
192
|
-
view () {
|
|
193
|
-
events.push("create");
|
|
194
|
-
return new PluginView();
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
const { view , unmount } = tempEditor({
|
|
198
|
-
plugins: [
|
|
199
|
-
plugin
|
|
200
|
-
]
|
|
201
|
-
});
|
|
202
|
-
view.dispatch(view.state.tr.insertText("u"));
|
|
203
|
-
unmount();
|
|
204
|
-
expect(events.join(" ")).toBe("create update destroy");
|
|
205
|
-
});
|
|
206
|
-
it("redraws changed node views", async ()=>{
|
|
207
|
-
const { view , rerender } = tempEditor({
|
|
208
|
-
doc: doc(p("foo"), hr())
|
|
209
|
-
});
|
|
210
|
-
expect(view.dom.querySelector("hr")).toBeTruthy();
|
|
211
|
-
rerender({
|
|
212
|
-
nodeViews: {
|
|
213
|
-
horizontal_rule: /*#__PURE__*/ forwardRef(function HorizontalRule(param, ref) {
|
|
214
|
-
let { nodeProps , ...props } = param;
|
|
215
|
-
return /*#__PURE__*/ React.createElement("var", _extends({
|
|
216
|
-
ref: ref
|
|
217
|
-
}, props));
|
|
218
|
-
})
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
expect(!view.dom.querySelector("hr")).toBeTruthy();
|
|
222
|
-
expect(view.dom.querySelector("var")).toBeTruthy();
|
|
223
|
-
});
|
|
224
|
-
it("doesn't get confused by merged nodes", async ()=>{
|
|
225
|
-
const { view } = tempEditor({
|
|
226
|
-
doc: doc(p(strong("one"), " two ", strong("three")))
|
|
227
|
-
});
|
|
228
|
-
view.dispatch(view.state.tr.removeMark(1, 4, schema.marks.strong));
|
|
229
|
-
expect(view.dom.querySelectorAll("strong")).toHaveLength(1);
|
|
230
|
-
});
|
|
231
|
-
it("doesn't redraw too much when marks are present", async ()=>{
|
|
232
|
-
const s = new Schema({
|
|
233
|
-
nodes: {
|
|
234
|
-
doc: {
|
|
235
|
-
content: "paragraph+",
|
|
236
|
-
marks: "m"
|
|
237
|
-
},
|
|
238
|
-
text: {
|
|
239
|
-
group: "inline"
|
|
240
|
-
},
|
|
241
|
-
paragraph: schema.spec.nodes.get("paragraph")
|
|
242
|
-
},
|
|
243
|
-
marks: {
|
|
244
|
-
m: {
|
|
245
|
-
toDOM: ()=>[
|
|
246
|
-
"div",
|
|
247
|
-
{
|
|
248
|
-
class: "m"
|
|
249
|
-
},
|
|
250
|
-
0
|
|
251
|
-
],
|
|
252
|
-
parseDOM: [
|
|
253
|
-
{
|
|
254
|
-
tag: "div.m"
|
|
255
|
-
}
|
|
256
|
-
]
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
const paragraphs = [];
|
|
261
|
-
for(let i = 1; i <= 10; i++)paragraphs.push(s.node("paragraph", null, [
|
|
262
|
-
s.text("para " + i)
|
|
263
|
-
], [
|
|
264
|
-
s.mark("m")
|
|
265
|
-
]));
|
|
266
|
-
const { view } = tempEditor({
|
|
267
|
-
// @ts-expect-error this is fine
|
|
268
|
-
doc: s.node("doc", null, paragraphs)
|
|
269
|
-
});
|
|
270
|
-
const initialChildren = Array.from(view.dom.querySelectorAll("p"));
|
|
271
|
-
const newParagraphs = [];
|
|
272
|
-
for(let i = -6; i < 0; i++)newParagraphs.push(s.node("paragraph", null, [
|
|
273
|
-
s.text("para " + i)
|
|
274
|
-
], [
|
|
275
|
-
s.mark("m")
|
|
276
|
-
]));
|
|
277
|
-
view.dispatch(view.state.tr.replaceWith(0, 8, newParagraphs));
|
|
278
|
-
const currentChildren = Array.from(view.dom.querySelectorAll("p"));
|
|
279
|
-
let sameAtEnd = 0;
|
|
280
|
-
while(sameAtEnd < currentChildren.length && sameAtEnd < initialChildren.length && currentChildren[currentChildren.length - sameAtEnd - 1] == initialChildren[initialChildren.length - sameAtEnd - 1])sameAtEnd++;
|
|
281
|
-
expect(sameAtEnd).toBe(9);
|
|
282
|
-
});
|
|
283
|
-
it("correctly wraps inline nodes with marks", async ()=>{
|
|
284
|
-
const { view } = tempEditor({
|
|
285
|
-
doc: doc(p(strong(img(), " two")))
|
|
286
|
-
});
|
|
287
|
-
const docDom = view.dom;
|
|
288
|
-
const paragraphDom = docDom.firstElementChild;
|
|
289
|
-
const strongDom = paragraphDom.firstElementChild;
|
|
290
|
-
expect(strongDom?.tagName).toBe("STRONG");
|
|
291
|
-
expect(strongDom?.firstElementChild?.tagName).toBe("IMG");
|
|
292
|
-
expect(strongDom?.childNodes.item(1).textContent).toBe(" two");
|
|
293
|
-
});
|
|
294
|
-
});
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ function _extends() {
|
|
2
|
-
_extends = Object.assign || function(target) {
|
|
3
|
-
for(var i = 1; i < arguments.length; i++){
|
|
4
|
-
var source = arguments[i];
|
|
5
|
-
for(var key in source){
|
|
6
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
7
|
-
target[key] = source[key];
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
return target;
|
|
12
|
-
};
|
|
13
|
-
return _extends.apply(this, arguments);
|
|
14
|
-
}
|
|
15
|
-
import { screen } from "@testing-library/react";
|
|
16
|
-
import { Plugin } from "prosemirror-state";
|
|
17
|
-
import { blockquote, br, doc, p } from "prosemirror-test-builder";
|
|
18
|
-
import { Decoration, DecorationSet } from "prosemirror-view";
|
|
19
|
-
import React, { forwardRef, useEffect } from "react";
|
|
20
|
-
import { useEditorState } from "../../hooks/useEditorState.js";
|
|
21
|
-
import { useStopEvent } from "../../hooks/useStopEvent.js";
|
|
22
|
-
import { tempEditor } from "../../testing/editorViewTestHelpers.js";
|
|
23
|
-
describe("nodeViews prop", ()=>{
|
|
24
|
-
it("can replace a node's representation", async ()=>{
|
|
25
|
-
const { view } = tempEditor({
|
|
26
|
-
doc: doc(p("foo", br())),
|
|
27
|
-
nodeViews: {
|
|
28
|
-
hard_break: /*#__PURE__*/ forwardRef(function Var(props, ref) {
|
|
29
|
-
return /*#__PURE__*/ React.createElement("var", {
|
|
30
|
-
ref: ref
|
|
31
|
-
}, props.children);
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
expect(view.dom.querySelector("var")).not.toBeNull();
|
|
36
|
-
});
|
|
37
|
-
it("can override drawing of a node's content", async ()=>{
|
|
38
|
-
const { view } = tempEditor({
|
|
39
|
-
doc: doc(p("foo")),
|
|
40
|
-
nodeViews: {
|
|
41
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
|
|
42
|
-
return /*#__PURE__*/ React.createElement("p", {
|
|
43
|
-
ref: ref
|
|
44
|
-
}, props.nodeProps.node.textContent.toUpperCase());
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
expect(view.dom.querySelector("p").textContent).toBe("FOO");
|
|
49
|
-
view.dispatch(view.state.tr.insertText("a"));
|
|
50
|
-
expect(view.dom.querySelector("p").textContent).toBe("AFOO");
|
|
51
|
-
});
|
|
52
|
-
// React makes this more or less trivial; the render
|
|
53
|
-
// method of the component _is_ the update (and create)
|
|
54
|
-
// method
|
|
55
|
-
// eslint-disable-next-line jest/no-disabled-tests
|
|
56
|
-
it.skip("can register its own update method", async ()=>{
|
|
57
|
-
const { view } = tempEditor({
|
|
58
|
-
doc: doc(p("foo")),
|
|
59
|
-
nodeViews: {
|
|
60
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
|
|
61
|
-
return /*#__PURE__*/ React.createElement("p", {
|
|
62
|
-
ref: ref
|
|
63
|
-
}, props.nodeProps.node.textContent.toUpperCase());
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
const para = view.dom.querySelector("p");
|
|
68
|
-
view.dispatch(view.state.tr.insertText("a"));
|
|
69
|
-
expect(view.dom.querySelector("p")).toBe(para);
|
|
70
|
-
expect(para.textContent).toBe("AFOO");
|
|
71
|
-
});
|
|
72
|
-
it("allows decoration updates for node views with an update method", async ()=>{
|
|
73
|
-
const { view , rerender } = tempEditor({
|
|
74
|
-
doc: doc(p("foo")),
|
|
75
|
-
nodeViews: {
|
|
76
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(param, ref) {
|
|
77
|
-
let { children , nodeProps , ...props } = param;
|
|
78
|
-
return /*#__PURE__*/ React.createElement("p", _extends({
|
|
79
|
-
ref: ref
|
|
80
|
-
}, props), children);
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
rerender({
|
|
85
|
-
decorations (state) {
|
|
86
|
-
return DecorationSet.create(state.doc, [
|
|
87
|
-
Decoration.inline(2, 3, {
|
|
88
|
-
someattr: "ok"
|
|
89
|
-
}),
|
|
90
|
-
Decoration.node(0, 5, {
|
|
91
|
-
otherattr: "ok"
|
|
92
|
-
})
|
|
93
|
-
]);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
expect(view.dom.querySelector("[someattr]")).not.toBeNull();
|
|
97
|
-
expect(view.dom.querySelector("[otherattr]")).not.toBeNull();
|
|
98
|
-
});
|
|
99
|
-
it("can provide a contentDOM property", async ()=>{
|
|
100
|
-
const { view } = tempEditor({
|
|
101
|
-
doc: doc(p("foo")),
|
|
102
|
-
nodeViews: {
|
|
103
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
|
|
104
|
-
return(// ContentDOM is inferred from where props.children is rendered
|
|
105
|
-
/*#__PURE__*/ React.createElement("p", {
|
|
106
|
-
ref: ref
|
|
107
|
-
}, props.children));
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
const para = view.dom.querySelector("p");
|
|
112
|
-
view.dispatch(view.state.tr.insertText("a"));
|
|
113
|
-
expect(view.dom.querySelector("p")).toBe(para);
|
|
114
|
-
expect(para.textContent).toBe("afoo");
|
|
115
|
-
});
|
|
116
|
-
it("has its destroy method called", async ()=>{
|
|
117
|
-
let destroyed = false;
|
|
118
|
-
const { view } = tempEditor({
|
|
119
|
-
doc: doc(p("foo", br())),
|
|
120
|
-
nodeViews: {
|
|
121
|
-
hard_break: /*#__PURE__*/ forwardRef(function BR(_props, ref) {
|
|
122
|
-
// React implements "destroy methods" with effect
|
|
123
|
-
// hooks
|
|
124
|
-
useEffect(()=>{
|
|
125
|
-
return ()=>{
|
|
126
|
-
destroyed = true;
|
|
127
|
-
};
|
|
128
|
-
}, []);
|
|
129
|
-
return /*#__PURE__*/ React.createElement("br", {
|
|
130
|
-
ref: ref
|
|
131
|
-
});
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
expect(destroyed).toBeFalsy();
|
|
136
|
-
view.dispatch(view.state.tr.delete(3, 5));
|
|
137
|
-
expect(destroyed).toBeTruthy();
|
|
138
|
-
});
|
|
139
|
-
it("can query its own position", async ()=>{
|
|
140
|
-
let pos;
|
|
141
|
-
const { view } = tempEditor({
|
|
142
|
-
doc: doc(blockquote(p("abc"), p("foo", br()))),
|
|
143
|
-
nodeViews: {
|
|
144
|
-
hard_break: /*#__PURE__*/ forwardRef(function BR(param, ref) {
|
|
145
|
-
let { nodeProps , children , ...props } = param;
|
|
146
|
-
// trigger a re-render on every updated, otherwise we won't
|
|
147
|
-
// re-render when an updated doesn't directly affect us
|
|
148
|
-
useEditorState();
|
|
149
|
-
pos = nodeProps.getPos();
|
|
150
|
-
return /*#__PURE__*/ React.createElement("br", _extends({
|
|
151
|
-
ref: ref
|
|
152
|
-
}, props));
|
|
153
|
-
})
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
expect(pos).toBe(10);
|
|
157
|
-
view.dispatch(view.state.tr.insertText("a"));
|
|
158
|
-
expect(pos).toBe(11);
|
|
159
|
-
});
|
|
160
|
-
it("has access to outer decorations", async ()=>{
|
|
161
|
-
const plugin = new Plugin({
|
|
162
|
-
state: {
|
|
163
|
-
init () {
|
|
164
|
-
return null;
|
|
165
|
-
},
|
|
166
|
-
apply (tr, prev) {
|
|
167
|
-
return tr.getMeta("setDeco") || prev;
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
props: {
|
|
171
|
-
decorations (state) {
|
|
172
|
-
const deco = this.getState(state);
|
|
173
|
-
return deco && DecorationSet.create(state.doc, [
|
|
174
|
-
Decoration.inline(0, state.doc.content.size, {}, {
|
|
175
|
-
name: deco
|
|
176
|
-
})
|
|
177
|
-
]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
const { view } = tempEditor({
|
|
182
|
-
doc: doc(p("foo", br())),
|
|
183
|
-
plugins: [
|
|
184
|
-
plugin
|
|
185
|
-
],
|
|
186
|
-
nodeViews: {
|
|
187
|
-
hard_break: /*#__PURE__*/ forwardRef(function Var(props, ref) {
|
|
188
|
-
return /*#__PURE__*/ React.createElement("var", {
|
|
189
|
-
ref: ref
|
|
190
|
-
}, props.nodeProps.decorations.length ? props.nodeProps.decorations[0].spec.name : "[]");
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
expect(view.dom.querySelector("var").textContent).toBe("[]");
|
|
195
|
-
view.dispatch(view.state.tr.setMeta("setDeco", "foo"));
|
|
196
|
-
expect(view.dom.querySelector("var").textContent).toBe("foo");
|
|
197
|
-
view.dispatch(view.state.tr.setMeta("setDeco", "bar"));
|
|
198
|
-
expect(view.dom.querySelector("var").textContent).toBe("bar");
|
|
199
|
-
});
|
|
200
|
-
it("provides access to inner decorations in the constructor", async ()=>{
|
|
201
|
-
tempEditor({
|
|
202
|
-
doc: doc(p("foo")),
|
|
203
|
-
nodeViews: {
|
|
204
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
|
|
205
|
-
expect(props.nodeProps.innerDecorations.find().map((d)=>`${d.from}-${d.to}`).join()).toBe("1-2");
|
|
206
|
-
return /*#__PURE__*/ React.createElement("p", {
|
|
207
|
-
ref: ref
|
|
208
|
-
}, props.children);
|
|
209
|
-
})
|
|
210
|
-
},
|
|
211
|
-
decorations (state) {
|
|
212
|
-
return DecorationSet.create(state.doc, [
|
|
213
|
-
Decoration.inline(2, 3, {
|
|
214
|
-
someattr: "ok"
|
|
215
|
-
}),
|
|
216
|
-
Decoration.node(0, 5, {
|
|
217
|
-
otherattr: "ok"
|
|
218
|
-
})
|
|
219
|
-
]);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
it("provides access to inner decorations in the update method", async ()=>{
|
|
224
|
-
let innerDecos = [];
|
|
225
|
-
const { rerender } = tempEditor({
|
|
226
|
-
doc: doc(p("foo")),
|
|
227
|
-
nodeViews: {
|
|
228
|
-
paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
|
|
229
|
-
innerDecos = props.nodeProps.innerDecorations.find().map((d)=>`${d.from}-${d.to}`);
|
|
230
|
-
return /*#__PURE__*/ React.createElement("p", {
|
|
231
|
-
ref: ref
|
|
232
|
-
}, props.children);
|
|
233
|
-
})
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
rerender({
|
|
237
|
-
decorations (state) {
|
|
238
|
-
return DecorationSet.create(state.doc, [
|
|
239
|
-
Decoration.inline(2, 3, {
|
|
240
|
-
someattr: "ok"
|
|
241
|
-
}),
|
|
242
|
-
Decoration.node(0, 5, {
|
|
243
|
-
otherattr: "ok"
|
|
244
|
-
})
|
|
245
|
-
]);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
expect(innerDecos.join()).toBe("1-2");
|
|
249
|
-
});
|
|
250
|
-
it("can provide a stopEvent hook", async ()=>{
|
|
251
|
-
tempEditor({
|
|
252
|
-
doc: doc(p("input value")),
|
|
253
|
-
nodeViews: {
|
|
254
|
-
paragraph: /*#__PURE__*/ forwardRef(function ParagraphInput(param, ref) {
|
|
255
|
-
let { nodeProps , children , ...props } = param;
|
|
256
|
-
useStopEvent(()=>{
|
|
257
|
-
return true;
|
|
258
|
-
});
|
|
259
|
-
return /*#__PURE__*/ React.createElement("input", _extends({
|
|
260
|
-
ref: ref,
|
|
261
|
-
type: "text",
|
|
262
|
-
defaultValue: nodeProps.node.textContent
|
|
263
|
-
}, props));
|
|
264
|
-
})
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
const input = screen.getByDisplayValue("input value");
|
|
268
|
-
input.focus();
|
|
269
|
-
await browser.keys("z");
|
|
270
|
-
expect(await $(input).getValue()).toBe("input valuez");
|
|
271
|
-
});
|
|
272
|
-
});
|