@handlewithcare/react-prosemirror 2.4.12 → 2.5.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/dist/cjs/AbstractEditorView.js +4 -0
- package/dist/cjs/ReactEditorView.js +156 -0
- package/dist/cjs/StaticEditorView.js +86 -0
- package/dist/cjs/components/ChildNodeViews.js +58 -29
- package/dist/cjs/components/CustomNodeView.js +77 -137
- package/dist/cjs/{hooks/useNodePos.js → components/DefaultNodeView.js} +24 -26
- package/dist/cjs/components/DocNodeView.js +33 -41
- package/dist/cjs/components/MarkView.js +1 -2
- package/dist/cjs/components/NativeWidgetView.js +2 -3
- package/dist/cjs/components/NodeView.js +31 -21
- package/dist/cjs/components/ProseMirror.js +25 -17
- package/dist/cjs/components/ProseMirrorDoc.js +7 -27
- package/dist/cjs/components/ReactNodeView.js +98 -61
- package/dist/cjs/components/SeparatorHackView.js +1 -2
- package/dist/cjs/components/TextNodeView.js +4 -5
- package/dist/cjs/components/TrailingHackView.js +1 -2
- package/dist/cjs/components/WidgetView.js +2 -4
- package/dist/cjs/constants.js +33 -0
- package/dist/cjs/hooks/useEditor.js +33 -229
- package/dist/cjs/hooks/useEditorEffect.js +2 -2
- package/dist/cjs/hooks/useEditorEventCallback.js +8 -5
- package/dist/cjs/hooks/useIgnoreMutation.js +1 -1
- package/dist/cjs/hooks/useNodeViewDescriptor.js +123 -80
- package/dist/cjs/hooks/useReactKeys.js +1 -1
- package/dist/cjs/hooks/useSelectNode.js +9 -7
- package/dist/cjs/hooks/useStopEvent.js +1 -1
- package/dist/cjs/plugins/beforeInputPlugin.js +12 -0
- package/dist/cjs/testing/editorViewTestHelpers.js +0 -2
- package/dist/cjs/viewdesc.js +104 -25
- package/dist/esm/AbstractEditorView.js +1 -0
- package/dist/esm/ReactEditorView.js +156 -0
- package/dist/esm/StaticEditorView.js +76 -0
- package/dist/esm/components/ChildNodeViews.js +59 -31
- package/dist/esm/components/CustomNodeView.js +78 -138
- package/dist/esm/components/DefaultNodeView.js +16 -0
- package/dist/esm/components/DocNodeView.js +33 -41
- package/dist/esm/components/MarkView.js +1 -2
- package/dist/esm/components/NativeWidgetView.js +2 -3
- package/dist/esm/components/NodeView.js +32 -22
- package/dist/esm/components/ProseMirror.js +25 -17
- package/dist/esm/components/ProseMirrorDoc.js +7 -28
- package/dist/esm/components/ReactNodeView.js +99 -62
- package/dist/esm/components/SeparatorHackView.js +1 -2
- package/dist/esm/components/TextNodeView.js +4 -5
- package/dist/esm/components/TrailingHackView.js +1 -2
- package/dist/esm/components/WidgetView.js +2 -4
- package/dist/esm/constants.js +15 -0
- package/dist/esm/hooks/useEditor.js +29 -218
- package/dist/esm/hooks/useEditorEffect.js +2 -2
- package/dist/esm/hooks/useEditorEventCallback.js +8 -5
- package/dist/esm/hooks/useIgnoreMutation.js +1 -1
- package/dist/esm/hooks/useNodeViewDescriptor.js +125 -82
- package/dist/esm/hooks/useReactKeys.js +1 -1
- package/dist/esm/hooks/useSelectNode.js +9 -7
- package/dist/esm/hooks/useStopEvent.js +1 -1
- package/dist/esm/plugins/beforeInputPlugin.js +12 -0
- package/dist/esm/testing/editorViewTestHelpers.js +0 -2
- package/dist/esm/viewdesc.js +94 -18
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/AbstractEditorView.d.ts +27 -0
- package/dist/types/ReactEditorView.d.ts +80 -0
- package/dist/types/StaticEditorView.d.ts +24 -0
- package/dist/types/components/ChildNodeViews.d.ts +2 -2
- package/dist/types/components/CustomNodeView.d.ts +3 -3
- package/dist/types/components/DefaultNodeView.d.ts +3 -0
- package/dist/types/components/DocNodeView.d.ts +9 -17
- package/dist/types/components/MarkView.d.ts +2 -2
- package/dist/types/components/NativeWidgetView.d.ts +2 -2
- package/dist/types/components/NodeView.d.ts +5 -5
- package/dist/types/components/NodeViewComponentProps.d.ts +3 -4
- package/dist/types/components/ProseMirrorDoc.d.ts +14 -8
- package/dist/types/components/ReactNodeView.d.ts +4 -2
- package/dist/types/components/SeparatorHackView.d.ts +2 -2
- package/dist/types/components/TextNodeView.d.ts +4 -3
- package/dist/types/components/TrailingHackView.d.ts +2 -2
- package/dist/types/components/WidgetView.d.ts +2 -2
- package/dist/types/constants.d.ts +4 -0
- package/dist/types/contexts/EditorContext.d.ts +6 -4
- package/dist/types/contexts/IgnoreMutationContext.d.ts +2 -1
- package/dist/types/contexts/NodeViewContext.d.ts +3 -1
- package/dist/types/contexts/SelectNodeContext.d.ts +3 -1
- package/dist/types/contexts/StopEventContext.d.ts +2 -1
- package/dist/types/decorations/computeDocDeco.d.ts +3 -2
- package/dist/types/decorations/viewDecorations.d.ts +3 -2
- package/dist/types/hooks/useEditor.d.ts +5 -46
- package/dist/types/hooks/useNodeViewDescriptor.d.ts +18 -10
- package/dist/types/hooks/useReactKeys.d.ts +1 -1
- package/dist/types/hooks/useSelectNode.d.ts +2 -1
- package/dist/types/props.d.ts +3 -3
- package/dist/types/viewdesc.d.ts +29 -11
- package/package.json +7 -3
- package/dist/cjs/components/Editor.js +0 -28
- package/dist/cjs/components/NodeViews.js +0 -73
- package/dist/cjs/components/__tests__/LayoutGroup.test.js +0 -141
- package/dist/cjs/components/__tests__/ProseMirror.test.js +0 -255
- package/dist/cjs/contexts/NodeViewsContext.js +0 -10
- package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -107
- package/dist/cjs/hooks/__tests__/useNodeViews.test.js +0 -159
- package/dist/cjs/hooks/useClientOnly.js +0 -19
- package/dist/cjs/hooks/useEditorView.js +0 -100
- package/dist/cjs/hooks/useNodeViews.js +0 -100
- package/dist/cjs/nodeViews/createReactNodeViewConstructor.js +0 -244
- package/dist/cjs/nodeViews/phrasingContentTags.js +0 -57
- package/dist/cjs/plugins/__tests__/react.test.js +0 -139
- package/dist/cjs/plugins/react.js +0 -71
- package/dist/cjs/selection/SelectionDOMObserver.js +0 -171
- package/dist/cjs/selection/hasFocusAndSelection.js +0 -35
- package/dist/cjs/selection/selectionFromDOM.js +0 -77
- package/dist/cjs/selection/selectionToDOM.js +0 -226
- package/dist/cjs/ssr.js +0 -85
- package/dist/esm/components/Editor.js +0 -15
- package/dist/esm/components/NodeViews.js +0 -26
- package/dist/esm/components/__tests__/LayoutGroup.test.js +0 -98
- package/dist/esm/components/__tests__/ProseMirror.test.js +0 -207
- package/dist/esm/contexts/NodeViewsContext.js +0 -9
- package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -98
- package/dist/esm/hooks/__tests__/useNodeViews.test.js +0 -116
- package/dist/esm/hooks/useClientOnly.js +0 -9
- package/dist/esm/hooks/useEditorView.js +0 -99
- package/dist/esm/hooks/useNodePos.js +0 -16
- package/dist/esm/hooks/useNodeViews.js +0 -53
- package/dist/esm/nodeViews/createReactNodeViewConstructor.js +0 -214
- package/dist/esm/nodeViews/phrasingContentTags.js +0 -49
- package/dist/esm/plugins/__tests__/react.test.js +0 -135
- package/dist/esm/plugins/react.js +0 -64
- package/dist/esm/selection/SelectionDOMObserver.js +0 -161
- package/dist/esm/selection/hasFocusAndSelection.js +0 -17
- package/dist/esm/selection/selectionFromDOM.js +0 -59
- package/dist/esm/selection/selectionToDOM.js +0 -196
- package/dist/esm/ssr.js +0 -82
- package/dist/types/components/Editor.d.ts +0 -7
- package/dist/types/components/NodeViews.d.ts +0 -6
- package/dist/types/components/__tests__/LayoutGroup.test.d.ts +0 -1
- package/dist/types/contexts/NodeViewsContext.d.ts +0 -19
- package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +0 -1
- package/dist/types/hooks/__tests__/useNodeViews.test.d.ts +0 -1
- package/dist/types/hooks/useClientOnly.d.ts +0 -1
- package/dist/types/hooks/useEditorView.d.ts +0 -23
- package/dist/types/hooks/useNodePos.d.ts +0 -9
- package/dist/types/hooks/useNodeViews.d.ts +0 -5
- package/dist/types/nodeViews/createReactNodeViewConstructor.d.ts +0 -48
- package/dist/types/nodeViews/phrasingContentTags.d.ts +0 -1
- package/dist/types/plugins/__tests__/react.test.d.ts +0 -1
- package/dist/types/plugins/react.d.ts +0 -21
- package/dist/types/selection/SelectionDOMObserver.d.ts +0 -33
- package/dist/types/selection/hasFocusAndSelection.d.ts +0 -3
- package/dist/types/selection/selectionFromDOM.d.ts +0 -4
- package/dist/types/selection/selectionToDOM.d.ts +0 -9
- package/dist/types/ssr.d.ts +0 -19
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { act, render, screen } from "@testing-library/react";
|
|
2
|
-
import userEvent from "@testing-library/user-event";
|
|
3
|
-
import { Schema } from "prosemirror-model";
|
|
4
|
-
import { EditorState } from "prosemirror-state";
|
|
5
|
-
import React, { useEffect, useState } from "react";
|
|
6
|
-
import { react } from "../../plugins/react.js";
|
|
7
|
-
import { setupProseMirrorView, teardownProseMirrorView } from "../../testing/setupProseMirrorView.js";
|
|
8
|
-
import { ProseMirror } from "../ProseMirror.js";
|
|
9
|
-
// Mock `ReactDOM.flushSync` to call `act` to flush updates from DOM mutations.
|
|
10
|
-
jest.mock("react-dom", ()=>({
|
|
11
|
-
...jest.requireActual("react-dom"),
|
|
12
|
-
flushSync: (fn)=>act(fn)
|
|
13
|
-
}));
|
|
14
|
-
describe("ProseMirror", ()=>{
|
|
15
|
-
beforeAll(()=>{
|
|
16
|
-
setupProseMirrorView();
|
|
17
|
-
});
|
|
18
|
-
it("renders a contenteditable", async ()=>{
|
|
19
|
-
const schema = new Schema({
|
|
20
|
-
nodes: {
|
|
21
|
-
text: {},
|
|
22
|
-
doc: {
|
|
23
|
-
content: "text*"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
const defaultState = EditorState.create({
|
|
28
|
-
schema
|
|
29
|
-
});
|
|
30
|
-
function TestEditor() {
|
|
31
|
-
const [mount, setMount] = useState(null);
|
|
32
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
33
|
-
mount: mount,
|
|
34
|
-
defaultState: defaultState
|
|
35
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
36
|
-
"data-testid": "editor",
|
|
37
|
-
ref: setMount
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
const user = userEvent.setup();
|
|
41
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
42
|
-
const editor = screen.getByTestId("editor");
|
|
43
|
-
await user.type(editor, "Hello, world!");
|
|
44
|
-
expect(editor.textContent).toBe("Hello, world!");
|
|
45
|
-
});
|
|
46
|
-
it("supports observing transaction dispatch", async ()=>{
|
|
47
|
-
const schema = new Schema({
|
|
48
|
-
nodes: {
|
|
49
|
-
text: {},
|
|
50
|
-
doc: {
|
|
51
|
-
content: "text*"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
const defaultState = EditorState.create({
|
|
56
|
-
schema
|
|
57
|
-
});
|
|
58
|
-
const dispatchTransaction = jest.fn();
|
|
59
|
-
function TestEditor() {
|
|
60
|
-
const [mount, setMount] = useState(null);
|
|
61
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
62
|
-
mount: mount,
|
|
63
|
-
defaultState: defaultState,
|
|
64
|
-
dispatchTransaction: dispatchTransaction
|
|
65
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
66
|
-
"data-testid": "editor",
|
|
67
|
-
ref: setMount
|
|
68
|
-
}));
|
|
69
|
-
}
|
|
70
|
-
const user = userEvent.setup();
|
|
71
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
72
|
-
const editor = screen.getByTestId("editor");
|
|
73
|
-
await user.type(editor, "Hello, world!");
|
|
74
|
-
expect(editor.textContent).toBe("Hello, world!");
|
|
75
|
-
expect(dispatchTransaction).toHaveBeenCalledTimes(13);
|
|
76
|
-
});
|
|
77
|
-
it("supports controlling the editor state", async ()=>{
|
|
78
|
-
const schema = new Schema({
|
|
79
|
-
nodes: {
|
|
80
|
-
text: {},
|
|
81
|
-
doc: {
|
|
82
|
-
content: "text*"
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
let observedState = EditorState.create({
|
|
87
|
-
schema
|
|
88
|
-
});
|
|
89
|
-
function TestEditor() {
|
|
90
|
-
const [state, setState] = useState(observedState);
|
|
91
|
-
const [mount, setMount] = useState(null);
|
|
92
|
-
useEffect(()=>{
|
|
93
|
-
observedState = state;
|
|
94
|
-
}, [
|
|
95
|
-
state
|
|
96
|
-
]);
|
|
97
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
98
|
-
mount: mount,
|
|
99
|
-
state: state,
|
|
100
|
-
dispatchTransaction: (tr)=>{
|
|
101
|
-
setState((s)=>s.apply(tr));
|
|
102
|
-
}
|
|
103
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
104
|
-
"data-testid": "editor",
|
|
105
|
-
ref: setMount
|
|
106
|
-
}));
|
|
107
|
-
}
|
|
108
|
-
const user = userEvent.setup();
|
|
109
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
110
|
-
const editor = screen.getByTestId("editor");
|
|
111
|
-
await user.type(editor, "Hello, world!");
|
|
112
|
-
expect(observedState.doc.textContent).toBe("Hello, world!");
|
|
113
|
-
});
|
|
114
|
-
it("updates props atomically", async ()=>{
|
|
115
|
-
const schema = new Schema({
|
|
116
|
-
nodes: {
|
|
117
|
-
text: {},
|
|
118
|
-
doc: {
|
|
119
|
-
content: "text*"
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
const defaultState = EditorState.create({
|
|
124
|
-
schema
|
|
125
|
-
});
|
|
126
|
-
let allStatesMatched = true;
|
|
127
|
-
function TestEditor() {
|
|
128
|
-
const [state, setState] = useState(defaultState);
|
|
129
|
-
const [mount, setMount] = useState(null);
|
|
130
|
-
// Check that function props get invoked with the latest React state.
|
|
131
|
-
const editable = (viewState)=>{
|
|
132
|
-
allStatesMatched &&= viewState === state;
|
|
133
|
-
return true;
|
|
134
|
-
};
|
|
135
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
136
|
-
mount: mount,
|
|
137
|
-
editable: editable,
|
|
138
|
-
state: state,
|
|
139
|
-
dispatchTransaction: (tr)=>{
|
|
140
|
-
setState((s)=>s.apply(tr));
|
|
141
|
-
}
|
|
142
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
143
|
-
"data-testid": "editor",
|
|
144
|
-
ref: setMount
|
|
145
|
-
}));
|
|
146
|
-
}
|
|
147
|
-
const user = userEvent.setup();
|
|
148
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
149
|
-
const editor = screen.getByTestId("editor");
|
|
150
|
-
await user.type(editor, "Hello, world!");
|
|
151
|
-
expect(allStatesMatched).toBe(true);
|
|
152
|
-
});
|
|
153
|
-
it("supports React NodeViews", async ()=>{
|
|
154
|
-
const schema = new Schema({
|
|
155
|
-
nodes: {
|
|
156
|
-
text: {},
|
|
157
|
-
paragraph: {
|
|
158
|
-
content: "text*"
|
|
159
|
-
},
|
|
160
|
-
doc: {
|
|
161
|
-
content: "paragraph+"
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
const defaultState = EditorState.create({
|
|
166
|
-
schema,
|
|
167
|
-
plugins: [
|
|
168
|
-
react()
|
|
169
|
-
]
|
|
170
|
-
});
|
|
171
|
-
function Paragraph(param) {
|
|
172
|
-
let { children } = param;
|
|
173
|
-
return /*#__PURE__*/ React.createElement("p", {
|
|
174
|
-
"data-testid": "paragraph"
|
|
175
|
-
}, children);
|
|
176
|
-
}
|
|
177
|
-
const nodeViews = {
|
|
178
|
-
paragraph: ()=>({
|
|
179
|
-
component: Paragraph,
|
|
180
|
-
dom: document.createElement("div"),
|
|
181
|
-
contentDOM: document.createElement("span")
|
|
182
|
-
})
|
|
183
|
-
};
|
|
184
|
-
function TestEditor() {
|
|
185
|
-
const [mount, setMount] = useState(null);
|
|
186
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
187
|
-
mount: mount,
|
|
188
|
-
defaultState: defaultState,
|
|
189
|
-
nodeViews: nodeViews
|
|
190
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
191
|
-
"data-testid": "editor",
|
|
192
|
-
ref: setMount
|
|
193
|
-
}));
|
|
194
|
-
}
|
|
195
|
-
const user = userEvent.setup();
|
|
196
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
197
|
-
const editor = screen.getByTestId("editor");
|
|
198
|
-
await user.type(editor, "Hello, world!");
|
|
199
|
-
expect(editor.textContent).toBe("Hello, world!");
|
|
200
|
-
// Ensure that ProseMirror really rendered our Paragraph
|
|
201
|
-
// component, not just any old <p> tag
|
|
202
|
-
expect(screen.getAllByTestId("paragraph").length).toBeGreaterThanOrEqual(1);
|
|
203
|
-
});
|
|
204
|
-
afterAll(()=>{
|
|
205
|
-
teardownProseMirrorView();
|
|
206
|
-
});
|
|
207
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { createContext } from "react";
|
|
2
|
-
/**
|
|
3
|
-
* A context containing a map of node view keys to portals.
|
|
4
|
-
*
|
|
5
|
-
* Each node view registers a portal under its parent's
|
|
6
|
-
* key. Each can then retrieve the list of portals under their
|
|
7
|
-
* key, allowing portals to be rendered with the appropriate
|
|
8
|
-
* hierarchy.
|
|
9
|
-
*/ export const NodeViewsContext = createContext(null);
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-empty-function */ import { render } from "@testing-library/react";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { LayoutGroup } from "../../components/LayoutGroup.js";
|
|
4
|
-
import { EditorContext } from "../../contexts/EditorContext.js";
|
|
5
|
-
import { useEditorEffect } from "../useEditorEffect.js";
|
|
6
|
-
function TestComponent(param) {
|
|
7
|
-
let { effect , dependencies =[] } = param;
|
|
8
|
-
useEditorEffect(effect, [
|
|
9
|
-
effect,
|
|
10
|
-
...dependencies
|
|
11
|
-
]);
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
describe("useEditorViewLayoutEffect", ()=>{
|
|
15
|
-
it("should run the effect", ()=>{
|
|
16
|
-
const effect = jest.fn();
|
|
17
|
-
const editorView = {};
|
|
18
|
-
const editorState = {};
|
|
19
|
-
const registerEventListener = ()=>{};
|
|
20
|
-
const unregisterEventListener = ()=>{};
|
|
21
|
-
render(/*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
22
|
-
value: {
|
|
23
|
-
editorView,
|
|
24
|
-
editorState,
|
|
25
|
-
registerEventListener,
|
|
26
|
-
unregisterEventListener
|
|
27
|
-
}
|
|
28
|
-
}, /*#__PURE__*/ React.createElement(TestComponent, {
|
|
29
|
-
effect: effect
|
|
30
|
-
}))));
|
|
31
|
-
expect(effect).toHaveBeenCalled();
|
|
32
|
-
expect(effect).toHaveBeenCalledWith(editorView);
|
|
33
|
-
});
|
|
34
|
-
it("should not re-run the effect if no dependencies change", ()=>{
|
|
35
|
-
const effect = jest.fn();
|
|
36
|
-
const editorView = {};
|
|
37
|
-
const editorState = {};
|
|
38
|
-
const registerEventListener = ()=>{};
|
|
39
|
-
const unregisterEventListener = ()=>{};
|
|
40
|
-
const { rerender } = render(/*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
41
|
-
value: {
|
|
42
|
-
editorView,
|
|
43
|
-
editorState,
|
|
44
|
-
registerEventListener,
|
|
45
|
-
unregisterEventListener
|
|
46
|
-
}
|
|
47
|
-
}, /*#__PURE__*/ React.createElement(TestComponent, {
|
|
48
|
-
effect: effect,
|
|
49
|
-
dependencies: []
|
|
50
|
-
}))));
|
|
51
|
-
rerender(/*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
52
|
-
value: {
|
|
53
|
-
editorView,
|
|
54
|
-
editorState,
|
|
55
|
-
registerEventListener,
|
|
56
|
-
unregisterEventListener
|
|
57
|
-
}
|
|
58
|
-
}, /*#__PURE__*/ React.createElement(TestComponent, {
|
|
59
|
-
effect: effect,
|
|
60
|
-
dependencies: []
|
|
61
|
-
}))));
|
|
62
|
-
expect(effect).toHaveBeenCalledTimes(1);
|
|
63
|
-
});
|
|
64
|
-
it("should re-run the effect if dependencies change", ()=>{
|
|
65
|
-
const effect = jest.fn();
|
|
66
|
-
const editorView = {};
|
|
67
|
-
const editorState = {};
|
|
68
|
-
const registerEventListener = ()=>{};
|
|
69
|
-
const unregisterEventListener = ()=>{};
|
|
70
|
-
const { rerender } = render(/*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
71
|
-
value: {
|
|
72
|
-
editorView,
|
|
73
|
-
editorState,
|
|
74
|
-
registerEventListener,
|
|
75
|
-
unregisterEventListener
|
|
76
|
-
}
|
|
77
|
-
}, /*#__PURE__*/ React.createElement(TestComponent, {
|
|
78
|
-
effect: effect,
|
|
79
|
-
dependencies: [
|
|
80
|
-
"one"
|
|
81
|
-
]
|
|
82
|
-
}))));
|
|
83
|
-
rerender(/*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(EditorContext.Provider, {
|
|
84
|
-
value: {
|
|
85
|
-
editorView,
|
|
86
|
-
editorState,
|
|
87
|
-
registerEventListener,
|
|
88
|
-
unregisterEventListener
|
|
89
|
-
}
|
|
90
|
-
}, /*#__PURE__*/ React.createElement(TestComponent, {
|
|
91
|
-
effect: effect,
|
|
92
|
-
dependencies: [
|
|
93
|
-
"two"
|
|
94
|
-
]
|
|
95
|
-
}))));
|
|
96
|
-
expect(effect).toHaveBeenCalledTimes(2);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { act, render, screen } from "@testing-library/react";
|
|
2
|
-
import { Schema } from "prosemirror-model";
|
|
3
|
-
import { EditorState } from "prosemirror-state";
|
|
4
|
-
import React, { createContext, useContext, useState } from "react";
|
|
5
|
-
import { ProseMirror } from "../../components/ProseMirror.js";
|
|
6
|
-
import { react } from "../../plugins/react.js";
|
|
7
|
-
// Mock `ReactDOM.flushSync` to call `act` to flush updates from DOM mutations.
|
|
8
|
-
jest.mock("react-dom", ()=>({
|
|
9
|
-
...jest.requireActual("react-dom"),
|
|
10
|
-
flushSync: (fn)=>act(fn)
|
|
11
|
-
}));
|
|
12
|
-
const schema = new Schema({
|
|
13
|
-
nodes: {
|
|
14
|
-
doc: {
|
|
15
|
-
content: "block+"
|
|
16
|
-
},
|
|
17
|
-
list: {
|
|
18
|
-
group: "block",
|
|
19
|
-
content: "list_item+"
|
|
20
|
-
},
|
|
21
|
-
list_item: {
|
|
22
|
-
content: "inline*"
|
|
23
|
-
},
|
|
24
|
-
text: {
|
|
25
|
-
group: "inline"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
const state = EditorState.create({
|
|
30
|
-
doc: schema.topNodeType.create(null, schema.nodes.list.createAndFill()),
|
|
31
|
-
schema,
|
|
32
|
-
plugins: [
|
|
33
|
-
react()
|
|
34
|
-
]
|
|
35
|
-
});
|
|
36
|
-
describe("useNodeViews", ()=>{
|
|
37
|
-
it("should render node views", ()=>{
|
|
38
|
-
function List(param) {
|
|
39
|
-
let { children } = param;
|
|
40
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("span", {
|
|
41
|
-
contentEditable: false
|
|
42
|
-
}, "list"), /*#__PURE__*/ React.createElement("ul", null, children));
|
|
43
|
-
}
|
|
44
|
-
function ListItem(param) {
|
|
45
|
-
let { children } = param;
|
|
46
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("span", {
|
|
47
|
-
contentEditable: false
|
|
48
|
-
}, "list item"), /*#__PURE__*/ React.createElement("li", null, children));
|
|
49
|
-
}
|
|
50
|
-
const nodeViews = {
|
|
51
|
-
list: ()=>({
|
|
52
|
-
component: List,
|
|
53
|
-
dom: document.createElement("div"),
|
|
54
|
-
contentDOM: document.createElement("div")
|
|
55
|
-
}),
|
|
56
|
-
list_item: ()=>({
|
|
57
|
-
component: ListItem,
|
|
58
|
-
dom: document.createElement("div"),
|
|
59
|
-
contentDOM: document.createElement("div")
|
|
60
|
-
})
|
|
61
|
-
};
|
|
62
|
-
function TestEditor() {
|
|
63
|
-
const [mount, setMount] = useState(null);
|
|
64
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
65
|
-
mount: mount,
|
|
66
|
-
nodeViews: nodeViews,
|
|
67
|
-
defaultState: state
|
|
68
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
69
|
-
ref: setMount
|
|
70
|
-
}));
|
|
71
|
-
}
|
|
72
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
73
|
-
expect(screen.getByText("list")).toBeTruthy();
|
|
74
|
-
expect(screen.getByText("list item")).toBeTruthy();
|
|
75
|
-
});
|
|
76
|
-
it("should render child node views as children of their parents", ()=>{
|
|
77
|
-
const TestContext = /*#__PURE__*/ createContext("default");
|
|
78
|
-
function List(param) {
|
|
79
|
-
let { children } = param;
|
|
80
|
-
return /*#__PURE__*/ React.createElement(TestContext.Provider, {
|
|
81
|
-
value: "overriden"
|
|
82
|
-
}, /*#__PURE__*/ React.createElement("ul", null, children));
|
|
83
|
-
}
|
|
84
|
-
function ListItem(param) {
|
|
85
|
-
let { children } = param;
|
|
86
|
-
const testContextValue = useContext(TestContext);
|
|
87
|
-
return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("span", {
|
|
88
|
-
contentEditable: false
|
|
89
|
-
}, testContextValue), /*#__PURE__*/ React.createElement("li", null, children));
|
|
90
|
-
}
|
|
91
|
-
const nodeViews = {
|
|
92
|
-
list: ()=>({
|
|
93
|
-
component: List,
|
|
94
|
-
dom: document.createElement("div"),
|
|
95
|
-
contentDOM: document.createElement("div")
|
|
96
|
-
}),
|
|
97
|
-
list_item: ()=>({
|
|
98
|
-
component: ListItem,
|
|
99
|
-
dom: document.createElement("div"),
|
|
100
|
-
contentDOM: document.createElement("div")
|
|
101
|
-
})
|
|
102
|
-
};
|
|
103
|
-
function TestEditor() {
|
|
104
|
-
const [mount, setMount] = useState(null);
|
|
105
|
-
return /*#__PURE__*/ React.createElement(ProseMirror, {
|
|
106
|
-
mount: mount,
|
|
107
|
-
nodeViews: nodeViews,
|
|
108
|
-
defaultState: state
|
|
109
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
110
|
-
ref: setMount
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
113
|
-
render(/*#__PURE__*/ React.createElement(TestEditor, null));
|
|
114
|
-
expect(screen.getByText("overriden")).toBeTruthy();
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { useSyncExternalStore } from "react";
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3
|
-
function unsubscribe() {}
|
|
4
|
-
function subscribe() {
|
|
5
|
-
return unsubscribe;
|
|
6
|
-
}
|
|
7
|
-
export function useClientOnly() {
|
|
8
|
-
return useSyncExternalStore(subscribe, ()=>true, ()=>false);
|
|
9
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { Schema } from "prosemirror-model";
|
|
2
|
-
import { EditorState } from "prosemirror-state";
|
|
3
|
-
import { EditorView } from "prosemirror-view";
|
|
4
|
-
import { useLayoutEffect, useMemo, useState } from "react";
|
|
5
|
-
import { flushSync } from "react-dom";
|
|
6
|
-
import { useComponentEventListeners } from "./useComponentEventListeners.js";
|
|
7
|
-
const EMPTY_SCHEMA = new Schema({
|
|
8
|
-
nodes: {
|
|
9
|
-
doc: {
|
|
10
|
-
content: "text*"
|
|
11
|
-
},
|
|
12
|
-
text: {
|
|
13
|
-
inline: true
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
const EMPTY_STATE = EditorState.create({
|
|
18
|
-
schema: EMPTY_SCHEMA
|
|
19
|
-
});
|
|
20
|
-
let didWarnValueDefaultValue = false;
|
|
21
|
-
/**
|
|
22
|
-
* Creates, mounts, and manages a ProseMirror `EditorView`.
|
|
23
|
-
*
|
|
24
|
-
* All state and props updates are executed in a layout effect.
|
|
25
|
-
* To ensure that the EditorState and EditorView are never out of
|
|
26
|
-
* sync, it's important that the EditorView produced by this hook
|
|
27
|
-
* is only accessed through the provided hooks.
|
|
28
|
-
*/ export function useEditorView(mount, options) {
|
|
29
|
-
if (process.env.NODE_ENV !== "production") {
|
|
30
|
-
if (options.defaultState !== undefined && options.state !== undefined && !didWarnValueDefaultValue) {
|
|
31
|
-
console.error("A component contains a ProseMirror editor with both value and defaultValue props. " + "ProseMirror editors must be either controlled or uncontrolled " + "(specify either the state prop, or the defaultState prop, but not both). " + "Decide between using a controlled or uncontrolled ProseMirror editor " + "and remove one of these props. More info: " + "https://reactjs.org/link/controlled-components");
|
|
32
|
-
didWarnValueDefaultValue = true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const defaultState = options.defaultState ?? EMPTY_STATE;
|
|
36
|
-
const [_state, setState] = useState(defaultState);
|
|
37
|
-
const state = options.state ?? _state;
|
|
38
|
-
const { componentEventListenersPlugin , registerEventListener , unregisterEventListener } = useComponentEventListeners();
|
|
39
|
-
const plugins = useMemo(()=>[
|
|
40
|
-
...options.plugins ?? [],
|
|
41
|
-
componentEventListenersPlugin
|
|
42
|
-
], [
|
|
43
|
-
options.plugins,
|
|
44
|
-
componentEventListenersPlugin
|
|
45
|
-
]);
|
|
46
|
-
function dispatchTransaction(tr) {
|
|
47
|
-
flushSync(()=>{
|
|
48
|
-
if (!options.state) {
|
|
49
|
-
setState((s)=>s.apply(tr));
|
|
50
|
-
}
|
|
51
|
-
if (options.dispatchTransaction) {
|
|
52
|
-
options.dispatchTransaction.call(this, tr);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
const directEditorProps = {
|
|
57
|
-
...options,
|
|
58
|
-
state,
|
|
59
|
-
plugins,
|
|
60
|
-
dispatchTransaction
|
|
61
|
-
};
|
|
62
|
-
const [_view, setView] = useState(null);
|
|
63
|
-
const view = options.view ?? _view;
|
|
64
|
-
useLayoutEffect(()=>{
|
|
65
|
-
return ()=>{
|
|
66
|
-
if (_view) {
|
|
67
|
-
_view.destroy();
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}, [
|
|
71
|
-
_view
|
|
72
|
-
]);
|
|
73
|
-
// This effect runs on every render and handles the view lifecycle.
|
|
74
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
75
|
-
useLayoutEffect(()=>{
|
|
76
|
-
if (_view) {
|
|
77
|
-
if (_view.dom === mount) {
|
|
78
|
-
_view.setProps(directEditorProps);
|
|
79
|
-
} else {
|
|
80
|
-
setView(null);
|
|
81
|
-
}
|
|
82
|
-
} else if (mount) {
|
|
83
|
-
setView(new EditorView({
|
|
84
|
-
mount
|
|
85
|
-
}, directEditorProps));
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
return useMemo(()=>({
|
|
89
|
-
editorState: state,
|
|
90
|
-
editorView: view,
|
|
91
|
-
registerEventListener,
|
|
92
|
-
unregisterEventListener
|
|
93
|
-
}), [
|
|
94
|
-
state,
|
|
95
|
-
_view,
|
|
96
|
-
registerEventListener,
|
|
97
|
-
unregisterEventListener
|
|
98
|
-
]);
|
|
99
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useContext } from "react";
|
|
2
|
-
import { reactPluginKey } from "../plugins/react.js";
|
|
3
|
-
import { useEditorState } from "./useEditorState.js";
|
|
4
|
-
const NodePosContext = /*#__PURE__*/ createContext(null);
|
|
5
|
-
export function NodePosProvider(param) {
|
|
6
|
-
let { nodeKey , children } = param;
|
|
7
|
-
const editorState = useEditorState();
|
|
8
|
-
const pluginState = reactPluginKey.getState(editorState);
|
|
9
|
-
if (!pluginState) return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
|
|
10
|
-
return /*#__PURE__*/ React.createElement(NodePosContext.Provider, {
|
|
11
|
-
value: pluginState.keyToPos.get(nodeKey) ?? 0
|
|
12
|
-
}, children);
|
|
13
|
-
}
|
|
14
|
-
export function useNodePos() {
|
|
15
|
-
return useContext(NodePosContext);
|
|
16
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useMemo, useState } from "react";
|
|
2
|
-
import { NodeViews } from "../components/NodeViews.js";
|
|
3
|
-
import { createReactNodeViewConstructor, findNodeKeyUp } from "../nodeViews/createReactNodeViewConstructor.js";
|
|
4
|
-
export function useNodeViews(nodeViews) {
|
|
5
|
-
const [portals, setPortals] = useState({});
|
|
6
|
-
const registerPortal = useCallback((view, getPos, portal)=>{
|
|
7
|
-
const nearestAncestorKey = findNodeKeyUp(view, getPos());
|
|
8
|
-
setPortals((oldPortals)=>{
|
|
9
|
-
const oldChildPortals = oldPortals[nearestAncestorKey] ?? [];
|
|
10
|
-
const newChildPortals = oldChildPortals.concat({
|
|
11
|
-
getPos,
|
|
12
|
-
portal
|
|
13
|
-
});
|
|
14
|
-
return {
|
|
15
|
-
...oldPortals,
|
|
16
|
-
[nearestAncestorKey]: newChildPortals
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
|
-
return ()=>{
|
|
20
|
-
setPortals((oldPortals)=>{
|
|
21
|
-
const oldChildPortals = oldPortals[nearestAncestorKey] ?? [];
|
|
22
|
-
const newChildPortals = oldChildPortals.filter((param)=>{
|
|
23
|
-
let { portal: p } = param;
|
|
24
|
-
return p !== portal;
|
|
25
|
-
});
|
|
26
|
-
return {
|
|
27
|
-
...oldPortals,
|
|
28
|
-
[nearestAncestorKey]: newChildPortals
|
|
29
|
-
};
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
}, []);
|
|
33
|
-
const wrappedNodeViews = useMemo(()=>{
|
|
34
|
-
const nodeViewEntries = Object.entries(nodeViews ?? {});
|
|
35
|
-
const wrappedNodeViewEntries = nodeViewEntries.map((param)=>{
|
|
36
|
-
let [name, constructor] = param;
|
|
37
|
-
return [
|
|
38
|
-
name,
|
|
39
|
-
createReactNodeViewConstructor(constructor, registerPortal)
|
|
40
|
-
];
|
|
41
|
-
});
|
|
42
|
-
return Object.fromEntries(wrappedNodeViewEntries);
|
|
43
|
-
}, [
|
|
44
|
-
nodeViews,
|
|
45
|
-
registerPortal
|
|
46
|
-
]);
|
|
47
|
-
return {
|
|
48
|
-
nodeViews: wrappedNodeViews,
|
|
49
|
-
nodeViewsComponent: /*#__PURE__*/ React.createElement(NodeViews, {
|
|
50
|
-
portals: portals
|
|
51
|
-
})
|
|
52
|
-
};
|
|
53
|
-
}
|