@handlewithcare/react-prosemirror 2.4.12 → 2.5.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.
Files changed (127) hide show
  1. package/dist/cjs/AbstractEditorView.js +4 -0
  2. package/dist/cjs/ReactEditorView.js +156 -0
  3. package/dist/cjs/StaticEditorView.js +86 -0
  4. package/dist/cjs/components/ChildNodeViews.js +59 -30
  5. package/dist/cjs/components/CustomNodeView.js +9 -25
  6. package/dist/cjs/components/DocNodeView.js +6 -15
  7. package/dist/cjs/components/MarkView.js +1 -2
  8. package/dist/cjs/components/NativeWidgetView.js +2 -3
  9. package/dist/cjs/components/NodeView.js +1 -1
  10. package/dist/cjs/components/ProseMirror.js +11 -14
  11. package/dist/cjs/components/ReactNodeView.js +3 -4
  12. package/dist/cjs/components/SeparatorHackView.js +1 -2
  13. package/dist/cjs/components/TextNodeView.js +4 -5
  14. package/dist/cjs/components/TrailingHackView.js +1 -2
  15. package/dist/cjs/components/WidgetView.js +2 -4
  16. package/dist/cjs/constants.js +33 -0
  17. package/dist/cjs/hooks/useEditor.js +32 -228
  18. package/dist/cjs/hooks/useEditorEffect.js +2 -2
  19. package/dist/cjs/hooks/useEditorEventCallback.js +8 -5
  20. package/dist/cjs/hooks/useNodeViewDescriptor.js +10 -10
  21. package/dist/cjs/hooks/useReactKeys.js +1 -1
  22. package/dist/cjs/testing/editorViewTestHelpers.js +0 -2
  23. package/dist/cjs/viewdesc.js +10 -9
  24. package/dist/esm/AbstractEditorView.js +1 -0
  25. package/dist/esm/ReactEditorView.js +156 -0
  26. package/dist/esm/StaticEditorView.js +76 -0
  27. package/dist/esm/components/ChildNodeViews.js +60 -32
  28. package/dist/esm/components/CustomNodeView.js +9 -25
  29. package/dist/esm/components/DocNodeView.js +6 -15
  30. package/dist/esm/components/MarkView.js +1 -2
  31. package/dist/esm/components/NativeWidgetView.js +2 -3
  32. package/dist/esm/components/NodeView.js +1 -1
  33. package/dist/esm/components/ProseMirror.js +11 -14
  34. package/dist/esm/components/ReactNodeView.js +3 -4
  35. package/dist/esm/components/SeparatorHackView.js +1 -2
  36. package/dist/esm/components/TextNodeView.js +4 -5
  37. package/dist/esm/components/TrailingHackView.js +1 -2
  38. package/dist/esm/components/WidgetView.js +2 -4
  39. package/dist/esm/constants.js +15 -0
  40. package/dist/esm/hooks/useEditor.js +28 -217
  41. package/dist/esm/hooks/useEditorEffect.js +2 -2
  42. package/dist/esm/hooks/useEditorEventCallback.js +8 -5
  43. package/dist/esm/hooks/useNodeViewDescriptor.js +10 -10
  44. package/dist/esm/hooks/useReactKeys.js +1 -1
  45. package/dist/esm/testing/editorViewTestHelpers.js +0 -2
  46. package/dist/esm/viewdesc.js +3 -2
  47. package/dist/tsconfig.tsbuildinfo +1 -1
  48. package/dist/types/AbstractEditorView.d.ts +27 -0
  49. package/dist/types/ReactEditorView.d.ts +79 -0
  50. package/dist/types/StaticEditorView.d.ts +24 -0
  51. package/dist/types/components/ChildNodeViews.d.ts +2 -2
  52. package/dist/types/components/CustomNodeView.d.ts +2 -2
  53. package/dist/types/components/DocNodeView.d.ts +2 -5
  54. package/dist/types/components/MarkView.d.ts +2 -2
  55. package/dist/types/components/NativeWidgetView.d.ts +2 -2
  56. package/dist/types/components/NodeView.d.ts +2 -2
  57. package/dist/types/components/ReactNodeView.d.ts +2 -2
  58. package/dist/types/components/SeparatorHackView.d.ts +2 -2
  59. package/dist/types/components/TextNodeView.d.ts +4 -3
  60. package/dist/types/components/TrailingHackView.d.ts +2 -2
  61. package/dist/types/components/WidgetView.d.ts +2 -2
  62. package/dist/types/constants.d.ts +4 -0
  63. package/dist/types/contexts/EditorContext.d.ts +6 -4
  64. package/dist/types/decorations/computeDocDeco.d.ts +3 -2
  65. package/dist/types/decorations/viewDecorations.d.ts +3 -2
  66. package/dist/types/hooks/useEditor.d.ts +5 -46
  67. package/dist/types/hooks/useNodeViewDescriptor.d.ts +1 -1
  68. package/dist/types/hooks/useReactKeys.d.ts +1 -1
  69. package/dist/types/props.d.ts +3 -3
  70. package/dist/types/viewdesc.d.ts +6 -5
  71. package/package.json +6 -2
  72. package/dist/cjs/components/Editor.js +0 -28
  73. package/dist/cjs/components/NodeViews.js +0 -73
  74. package/dist/cjs/components/__tests__/LayoutGroup.test.js +0 -141
  75. package/dist/cjs/components/__tests__/ProseMirror.test.js +0 -255
  76. package/dist/cjs/contexts/NodeViewsContext.js +0 -10
  77. package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -107
  78. package/dist/cjs/hooks/__tests__/useNodeViews.test.js +0 -159
  79. package/dist/cjs/hooks/useEditorView.js +0 -100
  80. package/dist/cjs/hooks/useNodePos.js +0 -69
  81. package/dist/cjs/hooks/useNodeViews.js +0 -100
  82. package/dist/cjs/nodeViews/createReactNodeViewConstructor.js +0 -244
  83. package/dist/cjs/nodeViews/phrasingContentTags.js +0 -57
  84. package/dist/cjs/plugins/__tests__/react.test.js +0 -139
  85. package/dist/cjs/plugins/react.js +0 -71
  86. package/dist/cjs/selection/SelectionDOMObserver.js +0 -171
  87. package/dist/cjs/selection/hasFocusAndSelection.js +0 -35
  88. package/dist/cjs/selection/selectionFromDOM.js +0 -77
  89. package/dist/cjs/selection/selectionToDOM.js +0 -226
  90. package/dist/cjs/ssr.js +0 -85
  91. package/dist/esm/components/Editor.js +0 -15
  92. package/dist/esm/components/NodeViews.js +0 -26
  93. package/dist/esm/components/__tests__/LayoutGroup.test.js +0 -98
  94. package/dist/esm/components/__tests__/ProseMirror.test.js +0 -207
  95. package/dist/esm/contexts/NodeViewsContext.js +0 -9
  96. package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -98
  97. package/dist/esm/hooks/__tests__/useNodeViews.test.js +0 -116
  98. package/dist/esm/hooks/useEditorView.js +0 -99
  99. package/dist/esm/hooks/useNodePos.js +0 -16
  100. package/dist/esm/hooks/useNodeViews.js +0 -53
  101. package/dist/esm/nodeViews/createReactNodeViewConstructor.js +0 -214
  102. package/dist/esm/nodeViews/phrasingContentTags.js +0 -49
  103. package/dist/esm/plugins/__tests__/react.test.js +0 -135
  104. package/dist/esm/plugins/react.js +0 -64
  105. package/dist/esm/selection/SelectionDOMObserver.js +0 -161
  106. package/dist/esm/selection/hasFocusAndSelection.js +0 -17
  107. package/dist/esm/selection/selectionFromDOM.js +0 -59
  108. package/dist/esm/selection/selectionToDOM.js +0 -196
  109. package/dist/esm/ssr.js +0 -82
  110. package/dist/types/components/Editor.d.ts +0 -7
  111. package/dist/types/components/NodeViews.d.ts +0 -6
  112. package/dist/types/components/__tests__/LayoutGroup.test.d.ts +0 -1
  113. package/dist/types/contexts/NodeViewsContext.d.ts +0 -19
  114. package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +0 -1
  115. package/dist/types/hooks/__tests__/useNodeViews.test.d.ts +0 -1
  116. package/dist/types/hooks/useEditorView.d.ts +0 -23
  117. package/dist/types/hooks/useNodePos.d.ts +0 -9
  118. package/dist/types/hooks/useNodeViews.d.ts +0 -5
  119. package/dist/types/nodeViews/createReactNodeViewConstructor.d.ts +0 -48
  120. package/dist/types/nodeViews/phrasingContentTags.d.ts +0 -1
  121. package/dist/types/plugins/__tests__/react.test.d.ts +0 -1
  122. package/dist/types/plugins/react.d.ts +0 -21
  123. package/dist/types/selection/SelectionDOMObserver.d.ts +0 -33
  124. package/dist/types/selection/hasFocusAndSelection.d.ts +0 -3
  125. package/dist/types/selection/selectionFromDOM.d.ts +0 -4
  126. package/dist/types/selection/selectionToDOM.d.ts +0 -9
  127. package/dist/types/ssr.d.ts +0 -19
@@ -1,226 +0,0 @@
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
- domIndex: function() {
13
- return domIndex;
14
- },
15
- hasBlockDesc: function() {
16
- return hasBlockDesc;
17
- },
18
- hasSelection: function() {
19
- return hasSelection;
20
- },
21
- isEquivalentPosition: function() {
22
- return isEquivalentPosition;
23
- },
24
- nodeSize: function() {
25
- return nodeSize;
26
- },
27
- selectionToDOM: function() {
28
- return selectionToDOM;
29
- },
30
- syncNodeSelection: function() {
31
- return syncNodeSelection;
32
- }
33
- });
34
- const _prosemirrorstate = require("prosemirror-state");
35
- const _browser = require("../browser.js");
36
- const isEquivalentPosition = function(node, off, targetNode, targetOff) {
37
- return targetNode && (scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1));
38
- };
39
- function hasBlockDesc(dom) {
40
- let desc;
41
- for(let cur = dom; cur; cur = cur.parentNode)if (desc = cur.pmViewDesc) break;
42
- return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom);
43
- }
44
- const atomElements = /^(img|br|input|textarea|hr)$/i;
45
- function scanFor(node, off, targetNode, targetOff, dir) {
46
- for(;;){
47
- if (node == targetNode && off == targetOff) return true;
48
- if (off == (dir < 0 ? 0 : nodeSize(node))) {
49
- const parent = node.parentNode;
50
- if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) || node.contentEditable == "false") return false;
51
- off = domIndex(node) + (dir < 0 ? 0 : 1);
52
- node = parent;
53
- } else if (node.nodeType == 1) {
54
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
55
- node = node.childNodes[off + (dir < 0 ? -1 : 0)];
56
- if (node.contentEditable == "false") return false;
57
- off = dir < 0 ? nodeSize(node) : 0;
58
- } else {
59
- return false;
60
- }
61
- }
62
- }
63
- const domIndex = function(node) {
64
- let n = node;
65
- for(let index = 0;; index++){
66
- n = n.previousSibling;
67
- if (!n) return index;
68
- }
69
- };
70
- function nodeSize(node) {
71
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
72
- return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
73
- }
74
- function syncNodeSelection(view, sel) {
75
- const v = view;
76
- if (sel instanceof _prosemirrorstate.NodeSelection) {
77
- const desc = v.docView.descAt(sel.from);
78
- if (desc != v.lastSelectedViewDesc) {
79
- clearNodeSelection(v);
80
- if (desc) desc.selectNode();
81
- v.lastSelectedViewDesc = desc;
82
- }
83
- } else {
84
- clearNodeSelection(v);
85
- }
86
- }
87
- // Clear all DOM statefulness of the last node selection.
88
- function clearNodeSelection(view) {
89
- const v = view;
90
- if (v.lastSelectedViewDesc) {
91
- if (v.lastSelectedViewDesc.parent) v.lastSelectedViewDesc.deselectNode();
92
- v.lastSelectedViewDesc = undefined;
93
- }
94
- }
95
- function hasSelection(view) {
96
- const v = view;
97
- const sel = v.domSelectionRange();
98
- if (!sel.anchorNode) return false;
99
- try {
100
- // Firefox will raise 'permission denied' errors when accessing
101
- // properties of `sel.anchorNode` when it's in a generated CSS
102
- // element.
103
- return v.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) && (v.editable || v.dom.contains(// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
104
- sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
105
- } catch (_) {
106
- return false;
107
- }
108
- }
109
- function editorOwnsSelection(view) {
110
- return view.editable ? view.hasFocus() : hasSelection(view) && document.activeElement && document.activeElement.contains(view.dom);
111
- }
112
- function selectCursorWrapper(view) {
113
- const v = view;
114
- const domSel = v.domSelection(), range = document.createRange();
115
- if (!domSel) return;
116
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117
- const node = v.cursorWrapper.dom, img = node.nodeName == "IMG";
118
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
119
- if (img) range.setStart(node.parentNode, domIndex(node) + 1);
120
- else range.setStart(node, 0);
121
- range.collapse(true);
122
- domSel.removeAllRanges();
123
- domSel.addRange(range);
124
- // Kludge to kill 'control selection' in IE11 when selecting an
125
- // invisible cursor wrapper, since that would result in those weird
126
- // resize handles and a selection that considers the absolutely
127
- // positioned wrapper, rather than the root editable node, the
128
- // focused element.
129
- if (!img && !v.state.selection.visible && _browser.browser.ie && _browser.browser.ie_version <= 11) {
130
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
- node.disabled = true;
132
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
- node.disabled = false;
134
- }
135
- }
136
- function temporarilyEditableNear(view, pos) {
137
- const v = view;
138
- const { node, offset } = v.docView.domFromPos(pos, 0);
139
- const after = offset < node.childNodes.length ? node.childNodes[offset] : null;
140
- const before = offset ? node.childNodes[offset - 1] : null;
141
- if (_browser.browser.safari && after && after.contentEditable == "false") return setEditable(after);
142
- if ((!after || after.contentEditable == "false") && (!before || before.contentEditable == "false")) {
143
- if (after) return setEditable(after);
144
- else if (before) return setEditable(before);
145
- }
146
- return;
147
- }
148
- function setEditable(element) {
149
- element.contentEditable = "true";
150
- if (_browser.browser.safari && element.draggable) {
151
- element.draggable = false;
152
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
- element.wasDraggable = true;
154
- }
155
- return element;
156
- }
157
- function resetEditable(element) {
158
- element.contentEditable = "false";
159
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
- if (element.wasDraggable) {
161
- element.draggable = true;
162
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
163
- element.wasDraggable = null;
164
- }
165
- }
166
- function removeClassOnSelectionChange(view) {
167
- const v = view;
168
- const doc = v.dom.ownerDocument;
169
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
170
- doc.removeEventListener("selectionchange", v.input.hideSelectionGuard);
171
- const domSel = v.domSelectionRange();
172
- const node = domSel.anchorNode, offset = domSel.anchorOffset;
173
- doc.addEventListener("selectionchange", v.input.hideSelectionGuard = ()=>{
174
- if (domSel.anchorNode != node || domSel.anchorOffset != offset) {
175
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
176
- doc.removeEventListener("selectionchange", v.input.hideSelectionGuard);
177
- setTimeout(()=>{
178
- if (!editorOwnsSelection(v) || v.state.selection.visible) v.dom.classList.remove("ProseMirror-hideselection");
179
- }, 20);
180
- }
181
- });
182
- }
183
- const brokenSelectBetweenUneditable = _browser.browser.safari || _browser.browser.chrome && _browser.browser.chrome_version < 63;
184
- function selectionToDOM(view) {
185
- let force = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
186
- const v = view;
187
- const sel = v.state.selection;
188
- syncNodeSelection(v, sel);
189
- if (!editorOwnsSelection(v)) return;
190
- // The delayed drag selection causes issues with Cell Selections
191
- // in Safari. And the drag selection delay is to workarond issues
192
- // which only present in Chrome.
193
- if (!force && v.input.mouseDown && v.input.mouseDown.allowDefault && _browser.browser.chrome) {
194
- const domSel = v.domSelectionRange(), curSel = v.domObserver.currentSelection;
195
- if (domSel.anchorNode && curSel.anchorNode && isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
196
- v.input.mouseDown.delayedSelectionSync = true;
197
- v.domObserver.setCurSelection();
198
- return;
199
- }
200
- }
201
- v.domObserver.disconnectSelection();
202
- if (v.cursorWrapper) {
203
- selectCursorWrapper(v);
204
- } else {
205
- const { anchor, head } = sel;
206
- let resetEditableFrom;
207
- let resetEditableTo;
208
- if (brokenSelectBetweenUneditable && !(sel instanceof _prosemirrorstate.TextSelection)) {
209
- if (!sel.$from.parent.inlineContent) resetEditableFrom = temporarilyEditableNear(v, sel.from);
210
- if (!sel.empty && !sel.$from.parent.inlineContent) resetEditableTo = temporarilyEditableNear(v, sel.to);
211
- }
212
- v.docView.setSelection(anchor, head, v, force);
213
- if (brokenSelectBetweenUneditable) {
214
- if (resetEditableFrom) resetEditable(resetEditableFrom);
215
- if (resetEditableTo) resetEditable(resetEditableTo);
216
- }
217
- if (sel.visible) {
218
- v.dom.classList.remove("ProseMirror-hideselection");
219
- } else {
220
- v.dom.classList.add("ProseMirror-hideselection");
221
- if ("onselectionchange" in document) removeClassOnSelectionChange(v);
222
- }
223
- }
224
- v.domObserver.setCurSelection();
225
- v.domObserver.connectSelection();
226
- }
package/dist/cjs/ssr.js DELETED
@@ -1,85 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-empty-function */ /**
2
- * @fileoverview
3
- *
4
- * Stubs for ProseMirror View during SSR. These are extremely
5
- * barebones, because they _do not need to actually work_. They
6
- * just need to prevent errors from being thrown when ProseMirror
7
- * View attemps to access these APIs while constructing the
8
- * initial EditorView. None of these APIs are necessary for SSR to
9
- * work properly, so it's fine that they're all no-ops.
10
- */ "use strict";
11
- Object.defineProperty(exports, "__esModule", {
12
- value: true
13
- });
14
- Object.defineProperty(exports, "setSsrStubs", {
15
- enumerable: true,
16
- get: function() {
17
- return setSsrStubs;
18
- }
19
- });
20
- let ClassList = class ClassList {
21
- add() {}
22
- remove() {}
23
- };
24
- let ElementStub = class ElementStub {
25
- get parent() {
26
- return new ElementStub();
27
- }
28
- get parentNode() {
29
- return new ElementStub();
30
- }
31
- nodeName = "div";
32
- appendChild() {
33
- return new ElementStub();
34
- }
35
- setAttribute() {}
36
- hasAttribute() {
37
- return false;
38
- }
39
- insertBefore() {}
40
- get classList() {
41
- return new ClassList();
42
- }
43
- get ownerDocument() {
44
- return new DocumentStub();
45
- }
46
- style = {};
47
- addEventListener() {}
48
- removeEventListener() {}
49
- replaceChildren() {}
50
- };
51
- let DocumentStub = class DocumentStub {
52
- createElement() {
53
- return new ElementStub();
54
- }
55
- addEventListener() {}
56
- removeEventListener() {}
57
- get documentElement() {
58
- return new ElementStub();
59
- }
60
- };
61
- function setSsrStubs() {
62
- const prevWindow = globalThis.window;
63
- // @ts-expect-error HACK - EditorView checks for window.MutationObserver
64
- // in its constructor, which breaks SSR. We temporarily set window
65
- // to an empty object to prevent an error from being thrown, and then
66
- // clean it up so that other isomorphic code doesn't get confused about
67
- // whether there's a functioning global window object
68
- globalThis.window ??= {
69
- visualViewport: null
70
- };
71
- const prevDocument = globalThis.document;
72
- // @ts-expect-error HACK: This is only used during SSR, and only
73
- // to prevent outright errors when ProseMirror View attempts to
74
- // access document properties either on import or when constructing
75
- // the EditorView.
76
- globalThis.document ??= new DocumentStub();
77
- return function cleanupSsrStubs() {
78
- if (globalThis.window !== prevWindow) {
79
- globalThis.window = prevWindow;
80
- }
81
- if (globalThis.document !== prevDocument) {
82
- globalThis.document = prevDocument;
83
- }
84
- };
85
- }
@@ -1,15 +0,0 @@
1
- import React from "react";
2
- import { EditorContext } from "../contexts/EditorContext.js";
3
- import { useEditorView } from "../hooks/useEditorView.js";
4
- import { useNodeViews } from "../hooks/useNodeViews.js";
5
- export function Editor(param) {
6
- let { mount , children , ...options } = param;
7
- const { nodeViews , nodeViewsComponent } = useNodeViews(options.nodeViews);
8
- const value = useEditorView(mount, {
9
- ...options,
10
- nodeViews
11
- });
12
- return /*#__PURE__*/ React.createElement(EditorContext.Provider, {
13
- value: value
14
- }, children, nodeViewsComponent);
15
- }
@@ -1,26 +0,0 @@
1
- import React, { useState } from "react";
2
- import { NodeViewsContext } from "../contexts/NodeViewsContext.js";
3
- import { useEditorEffect } from "../hooks/useEditorEffect.js";
4
- import { ROOT_NODE_KEY } from "../plugins/react.js";
5
- export function NodeViews(param) {
6
- let { portals } = param;
7
- const rootRegisteredPortals = portals[ROOT_NODE_KEY];
8
- const [rootPortals, setRootPortals] = useState(rootRegisteredPortals?.map((param)=>{
9
- let { portal } = param;
10
- return portal;
11
- }) ?? []);
12
- // `getPos` is technically derived from the EditorView
13
- // state, so it's not safe to call until after the EditorView
14
- // has been updated
15
- useEditorEffect(()=>{
16
- setRootPortals(rootRegisteredPortals?.sort((a, b)=>a.getPos() - b.getPos()).map((param)=>{
17
- let { portal } = param;
18
- return portal;
19
- }) ?? []);
20
- }, [
21
- rootRegisteredPortals
22
- ]);
23
- return /*#__PURE__*/ React.createElement(NodeViewsContext.Provider, {
24
- value: portals
25
- }, rootPortals);
26
- }
@@ -1,98 +0,0 @@
1
- import { act, render, screen } from "@testing-library/react";
2
- import React, { useLayoutEffect, useState } from "react";
3
- import { useLayoutGroupEffect } from "../../hooks/useLayoutGroupEffect.js";
4
- import { LayoutGroup } from "../LayoutGroup.js";
5
- describe("LayoutGroup", ()=>{
6
- jest.useFakeTimers("modern");
7
- it("registers multiple effects and runs them", ()=>{
8
- function Parent() {
9
- return /*#__PURE__*/ React.createElement(LayoutGroup, null, /*#__PURE__*/ React.createElement(Child, null));
10
- }
11
- function Child() {
12
- const [double, setDouble] = useState(1);
13
- useLayoutEffect(()=>{
14
- if (double === 2) {
15
- setTimeout(()=>{
16
- setDouble((d)=>d * 2.5);
17
- }, 500);
18
- }
19
- if (double === 20) {
20
- setDouble((d)=>d * 2.5);
21
- }
22
- }, [
23
- double
24
- ]);
25
- useLayoutGroupEffect(()=>{
26
- const timeout = setTimeout(()=>{
27
- setDouble((d)=>d * 2);
28
- }, 1000);
29
- return ()=>{
30
- clearTimeout(timeout);
31
- };
32
- }, [
33
- double
34
- ]);
35
- return /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement("div", {
36
- "data-testid": "double"
37
- }, double));
38
- }
39
- // The component mounts ...
40
- // ... the initial value should be 1
41
- // ... there should be one timeout scheduled by the deferred effect
42
- render(/*#__PURE__*/ React.createElement(Parent, null));
43
- expect(screen.getByTestId("double").innerHTML).toBe("1");
44
- // This block assert that deferred effects run.
45
- // --------------------------------------------
46
- // 1000 milliseconds go by ...
47
- // ... the timeout set by the deferred effect should run
48
- // ... the timeout should double the new value to 2
49
- // ... the immediate effect should set a timeout
50
- // ... the deferred effect should set a timeout
51
- act(()=>{
52
- jest.advanceTimersByTime(1000);
53
- });
54
- expect(screen.getByTestId("double").innerHTML).toBe("2");
55
- // The next three blocks assert that cleanup of deferred effects run.
56
- // ------------------------------------------------------------------
57
- // 500 milliseconds go by ...
58
- // ... the timeout set by the immediate effect should run
59
- // ... the timeout should set the value to 5
60
- // ... the old deferred effect should cancel its timeout
61
- // ... the new deferred effect should set a new timeout
62
- act(()=>{
63
- jest.advanceTimersByTime(500);
64
- });
65
- expect(screen.getByTestId("double").innerHTML).toBe("5");
66
- // ... 500 more milliseconds go by ...
67
- // ... the canceled timeout should not run
68
- // ... the rescheduled timoeut should not yet run
69
- act(()=>{
70
- jest.advanceTimersByTime(500);
71
- });
72
- expect(screen.getByTestId("double").innerHTML).toBe("5");
73
- // ... 500 more milliseconds go by ...
74
- // ... the rescheduled timeout should run
75
- // ... the timeout should double the value to 10
76
- // ... the deferred effect should set a new timeout
77
- act(()=>{
78
- jest.advanceTimersByTime(500);
79
- });
80
- expect(screen.getByTestId("double").innerHTML).toBe("10");
81
- // The next block asserts that cancelation of deferred effects works.
82
- // ------------------------------------------------------------------
83
- // 1000 milliseconds go by ...
84
- // ... the timeout set by the deferred effect should run
85
- // ... the timeout should double the value to 20
86
- // ... the immediate effect should then set the value to 50
87
- // ... the deferred effect from the first render should not run
88
- // ... the deferred effect from the second render should run
89
- // ... the deferred effect that does run should set a new timeout
90
- act(()=>{
91
- jest.advanceTimersByTime(1000);
92
- });
93
- // For this assertion, we need to clear a timer from the React scheduler.
94
- jest.advanceTimersByTime(1);
95
- expect(screen.getByTestId("double").innerHTML).toBe("50");
96
- expect(jest.getTimerCount()).toBe(1);
97
- });
98
- });
@@ -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);