@handlewithcare/react-prosemirror 2.0.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 (209) hide show
  1. package/LICENSE.txt +12 -0
  2. package/README.md +705 -0
  3. package/dist/cjs/browser.js +53 -0
  4. package/dist/cjs/components/ChildNodeViews.js +376 -0
  5. package/dist/cjs/components/CursorWrapper.js +91 -0
  6. package/dist/cjs/components/CustomNodeView.js +79 -0
  7. package/dist/cjs/components/DocNodeView.js +104 -0
  8. package/dist/cjs/components/LayoutGroup.js +111 -0
  9. package/dist/cjs/components/MarkView.js +115 -0
  10. package/dist/cjs/components/NativeWidgetView.js +109 -0
  11. package/dist/cjs/components/NodeView.js +196 -0
  12. package/dist/cjs/components/NodeViewComponentProps.js +4 -0
  13. package/dist/cjs/components/OutputSpec.js +88 -0
  14. package/dist/cjs/components/ProseMirror.js +103 -0
  15. package/dist/cjs/components/ProseMirrorDoc.js +92 -0
  16. package/dist/cjs/components/SeparatorHackView.js +100 -0
  17. package/dist/cjs/components/TextNodeView.js +112 -0
  18. package/dist/cjs/components/TrailingHackView.js +90 -0
  19. package/dist/cjs/components/WidgetView.js +95 -0
  20. package/dist/cjs/components/WidgetViewComponentProps.js +4 -0
  21. package/dist/cjs/components/__tests__/ProseMirror.composition.test.js +398 -0
  22. package/dist/cjs/components/__tests__/ProseMirror.domchange.test.js +270 -0
  23. package/dist/cjs/components/__tests__/ProseMirror.draw-decoration.test.js +1010 -0
  24. package/dist/cjs/components/__tests__/ProseMirror.draw.test.js +337 -0
  25. package/dist/cjs/components/__tests__/ProseMirror.node-view.test.js +315 -0
  26. package/dist/cjs/components/__tests__/ProseMirror.selection.test.js +444 -0
  27. package/dist/cjs/components/__tests__/ProseMirror.test.js +382 -0
  28. package/dist/cjs/contexts/ChildDescriptorsContext.js +19 -0
  29. package/dist/cjs/contexts/EditorContext.js +12 -0
  30. package/dist/cjs/contexts/EditorStateContext.js +12 -0
  31. package/dist/cjs/contexts/LayoutGroupContext.js +12 -0
  32. package/dist/cjs/contexts/NodeViewContext.js +12 -0
  33. package/dist/cjs/contexts/SelectNodeContext.js +12 -0
  34. package/dist/cjs/contexts/StopEventContext.js +12 -0
  35. package/dist/cjs/contexts/__tests__/DeferredLayoutEffects.test.js +141 -0
  36. package/dist/cjs/decorations/ReactWidgetType.js +58 -0
  37. package/dist/cjs/decorations/computeDocDeco.js +44 -0
  38. package/dist/cjs/decorations/internalTypes.js +4 -0
  39. package/dist/cjs/decorations/iterDeco.js +79 -0
  40. package/dist/cjs/decorations/viewDecorations.js +163 -0
  41. package/dist/cjs/dom.js +142 -0
  42. package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +108 -0
  43. package/dist/cjs/hooks/useClientOnly.js +18 -0
  44. package/dist/cjs/hooks/useComponentEventListeners.js +39 -0
  45. package/dist/cjs/hooks/useEditor.js +287 -0
  46. package/dist/cjs/hooks/useEditorEffect.js +35 -0
  47. package/dist/cjs/hooks/useEditorEventCallback.js +33 -0
  48. package/dist/cjs/hooks/useEditorEventListener.js +34 -0
  49. package/dist/cjs/hooks/useEditorState.js +16 -0
  50. package/dist/cjs/hooks/useForceUpdate.js +15 -0
  51. package/dist/cjs/hooks/useLayoutGroupEffect.js +19 -0
  52. package/dist/cjs/hooks/useNodeViewDescriptor.js +115 -0
  53. package/dist/cjs/hooks/useReactKeys.js +17 -0
  54. package/dist/cjs/hooks/useSelectNode.js +28 -0
  55. package/dist/cjs/hooks/useStopEvent.js +24 -0
  56. package/dist/cjs/index.js +53 -0
  57. package/dist/cjs/package.json +3 -0
  58. package/dist/cjs/plugins/__tests__/reactKeys.test.js +81 -0
  59. package/dist/cjs/plugins/beforeInputPlugin.js +143 -0
  60. package/dist/cjs/plugins/componentEventListeners.js +35 -0
  61. package/dist/cjs/plugins/componentEventListenersPlugin.js +35 -0
  62. package/dist/cjs/plugins/reactKeys.js +96 -0
  63. package/dist/cjs/props.js +269 -0
  64. package/dist/cjs/selection/SelectionDOMObserver.js +174 -0
  65. package/dist/cjs/selection/hasFocusAndSelection.js +35 -0
  66. package/dist/cjs/selection/selectionFromDOM.js +77 -0
  67. package/dist/cjs/selection/selectionToDOM.js +226 -0
  68. package/dist/cjs/ssr.js +85 -0
  69. package/dist/cjs/testing/editorViewTestHelpers.js +111 -0
  70. package/dist/cjs/testing/setupProseMirrorView.js +94 -0
  71. package/dist/cjs/viewdesc.js +664 -0
  72. package/dist/esm/browser.js +43 -0
  73. package/dist/esm/components/ChildNodeViews.js +318 -0
  74. package/dist/esm/components/CursorWrapper.js +40 -0
  75. package/dist/esm/components/CustomNodeView.js +28 -0
  76. package/dist/esm/components/DocNodeView.js +53 -0
  77. package/dist/esm/components/LayoutGroup.js +66 -0
  78. package/dist/esm/components/MarkView.js +64 -0
  79. package/dist/esm/components/NativeWidgetView.js +58 -0
  80. package/dist/esm/components/NodeView.js +145 -0
  81. package/dist/esm/components/NodeViewComponentProps.js +1 -0
  82. package/dist/esm/components/OutputSpec.js +38 -0
  83. package/dist/esm/components/ProseMirror.js +52 -0
  84. package/dist/esm/components/ProseMirrorDoc.js +34 -0
  85. package/dist/esm/components/SeparatorHackView.js +49 -0
  86. package/dist/esm/components/TextNodeView.js +102 -0
  87. package/dist/esm/components/TrailingHackView.js +39 -0
  88. package/dist/esm/components/WidgetView.js +44 -0
  89. package/dist/esm/components/WidgetViewComponentProps.js +1 -0
  90. package/dist/esm/components/__tests__/ProseMirror.composition.test.js +395 -0
  91. package/dist/esm/components/__tests__/ProseMirror.domchange.test.js +266 -0
  92. package/dist/esm/components/__tests__/ProseMirror.draw-decoration.test.js +967 -0
  93. package/dist/esm/components/__tests__/ProseMirror.draw.test.js +294 -0
  94. package/dist/esm/components/__tests__/ProseMirror.node-view.test.js +272 -0
  95. package/dist/esm/components/__tests__/ProseMirror.selection.test.js +440 -0
  96. package/dist/esm/components/__tests__/ProseMirror.test.js +339 -0
  97. package/dist/esm/contexts/ChildDescriptorsContext.js +9 -0
  98. package/dist/esm/contexts/EditorContext.js +7 -0
  99. package/dist/esm/contexts/EditorStateContext.js +2 -0
  100. package/dist/esm/contexts/LayoutGroupContext.js +2 -0
  101. package/dist/esm/contexts/NodeViewContext.js +2 -0
  102. package/dist/esm/contexts/SelectNodeContext.js +2 -0
  103. package/dist/esm/contexts/StopEventContext.js +2 -0
  104. package/dist/esm/contexts/__tests__/DeferredLayoutEffects.test.js +98 -0
  105. package/dist/esm/decorations/ReactWidgetType.js +40 -0
  106. package/dist/esm/decorations/computeDocDeco.js +44 -0
  107. package/dist/esm/decorations/internalTypes.js +1 -0
  108. package/dist/esm/decorations/iterDeco.js +73 -0
  109. package/dist/esm/decorations/viewDecorations.js +163 -0
  110. package/dist/esm/dom.js +105 -0
  111. package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +99 -0
  112. package/dist/esm/hooks/useClientOnly.js +8 -0
  113. package/dist/esm/hooks/useComponentEventListeners.js +54 -0
  114. package/dist/esm/hooks/useEditor.js +278 -0
  115. package/dist/esm/hooks/useEditorEffect.js +38 -0
  116. package/dist/esm/hooks/useEditorEventCallback.js +35 -0
  117. package/dist/esm/hooks/useEditorEventListener.js +28 -0
  118. package/dist/esm/hooks/useEditorState.js +8 -0
  119. package/dist/esm/hooks/useForceUpdate.js +8 -0
  120. package/dist/esm/hooks/useLayoutGroupEffect.js +9 -0
  121. package/dist/esm/hooks/useNodeViewDescriptor.js +105 -0
  122. package/dist/esm/hooks/useReactKeys.js +7 -0
  123. package/dist/esm/hooks/useSelectNode.js +18 -0
  124. package/dist/esm/hooks/useStopEvent.js +14 -0
  125. package/dist/esm/index.js +11 -0
  126. package/dist/esm/plugins/__tests__/reactKeys.test.js +77 -0
  127. package/dist/esm/plugins/beforeInputPlugin.js +133 -0
  128. package/dist/esm/plugins/componentEventListeners.js +25 -0
  129. package/dist/esm/plugins/componentEventListenersPlugin.js +25 -0
  130. package/dist/esm/plugins/reactKeys.js +81 -0
  131. package/dist/esm/props.js +251 -0
  132. package/dist/esm/selection/SelectionDOMObserver.js +164 -0
  133. package/dist/esm/selection/hasFocusAndSelection.js +17 -0
  134. package/dist/esm/selection/selectionFromDOM.js +59 -0
  135. package/dist/esm/selection/selectionToDOM.js +196 -0
  136. package/dist/esm/ssr.js +82 -0
  137. package/dist/esm/testing/editorViewTestHelpers.js +88 -0
  138. package/dist/esm/testing/setupProseMirrorView.js +76 -0
  139. package/dist/esm/viewdesc.js +654 -0
  140. package/dist/tsconfig.tsbuildinfo +1 -0
  141. package/dist/types/browser.d.ts +15 -0
  142. package/dist/types/components/ChildNodeViews.d.ts +9 -0
  143. package/dist/types/components/CursorWrapper.d.ts +5 -0
  144. package/dist/types/components/CustomNodeView.d.ts +21 -0
  145. package/dist/types/components/DocNodeView.d.ts +20 -0
  146. package/dist/types/components/LayoutGroup.d.ts +12 -0
  147. package/dist/types/components/MarkView.d.ts +9 -0
  148. package/dist/types/components/NativeWidgetView.d.ts +8 -0
  149. package/dist/types/components/NodeView.d.ts +11 -0
  150. package/dist/types/components/NodeViewComponentProps.d.ts +12 -0
  151. package/dist/types/components/OutputSpec.d.ts +8 -0
  152. package/dist/types/components/ProseMirror.d.ts +15 -0
  153. package/dist/types/components/ProseMirrorDoc.d.ts +10 -0
  154. package/dist/types/components/SeparatorHackView.d.ts +6 -0
  155. package/dist/types/components/TextNodeView.d.ts +23 -0
  156. package/dist/types/components/TrailingHackView.d.ts +6 -0
  157. package/dist/types/components/WidgetView.d.ts +8 -0
  158. package/dist/types/components/WidgetViewComponentProps.d.ts +6 -0
  159. package/dist/types/components/__tests__/ProseMirror.composition.test.d.ts +1 -0
  160. package/dist/types/components/__tests__/ProseMirror.domchange.test.d.ts +1 -0
  161. package/dist/types/components/__tests__/ProseMirror.draw-decoration.test.d.ts +1 -0
  162. package/dist/types/components/__tests__/ProseMirror.draw.test.d.ts +1 -0
  163. package/dist/types/components/__tests__/ProseMirror.node-view.test.d.ts +1 -0
  164. package/dist/types/components/__tests__/ProseMirror.selection.test.d.ts +1 -0
  165. package/dist/types/components/__tests__/ProseMirror.test.d.ts +1 -0
  166. package/dist/types/contexts/ChildDescriptorsContext.d.ts +6 -0
  167. package/dist/types/contexts/EditorContext.d.ts +14 -0
  168. package/dist/types/contexts/EditorStateContext.d.ts +2 -0
  169. package/dist/types/contexts/LayoutGroupContext.d.ts +5 -0
  170. package/dist/types/contexts/NodeViewContext.d.ts +6 -0
  171. package/dist/types/contexts/SelectNodeContext.d.ts +3 -0
  172. package/dist/types/contexts/StopEventContext.d.ts +3 -0
  173. package/dist/types/contexts/__tests__/DeferredLayoutEffects.test.d.ts +1 -0
  174. package/dist/types/decorations/ReactWidgetType.d.ts +39 -0
  175. package/dist/types/decorations/computeDocDeco.d.ts +13 -0
  176. package/dist/types/decorations/internalTypes.d.ts +16 -0
  177. package/dist/types/decorations/iterDeco.d.ts +3 -0
  178. package/dist/types/decorations/viewDecorations.d.ts +13 -0
  179. package/dist/types/dom.d.ts +22 -0
  180. package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +1 -0
  181. package/dist/types/hooks/useClientOnly.d.ts +1 -0
  182. package/dist/types/hooks/useComponentEventListeners.d.ts +33 -0
  183. package/dist/types/hooks/useEditor.d.ts +66 -0
  184. package/dist/types/hooks/useEditorEffect.d.ts +17 -0
  185. package/dist/types/hooks/useEditorEventCallback.d.ts +15 -0
  186. package/dist/types/hooks/useEditorEventListener.d.ts +8 -0
  187. package/dist/types/hooks/useEditorState.d.ts +5 -0
  188. package/dist/types/hooks/useForceUpdate.d.ts +5 -0
  189. package/dist/types/hooks/useLayoutGroupEffect.d.ts +3 -0
  190. package/dist/types/hooks/useNodeViewDescriptor.d.ts +11 -0
  191. package/dist/types/hooks/useReactKeys.d.ts +5 -0
  192. package/dist/types/hooks/useSelectNode.d.ts +1 -0
  193. package/dist/types/hooks/useStopEvent.d.ts +2 -0
  194. package/dist/types/index.d.ts +12 -0
  195. package/dist/types/plugins/__tests__/reactKeys.test.d.ts +1 -0
  196. package/dist/types/plugins/beforeInputPlugin.d.ts +3 -0
  197. package/dist/types/plugins/componentEventListeners.d.ts +4 -0
  198. package/dist/types/plugins/componentEventListenersPlugin.d.ts +4 -0
  199. package/dist/types/plugins/reactKeys.d.ts +19 -0
  200. package/dist/types/props.d.ts +1174 -0
  201. package/dist/types/selection/SelectionDOMObserver.d.ts +34 -0
  202. package/dist/types/selection/hasFocusAndSelection.d.ts +3 -0
  203. package/dist/types/selection/selectionFromDOM.d.ts +4 -0
  204. package/dist/types/selection/selectionToDOM.d.ts +9 -0
  205. package/dist/types/ssr.d.ts +19 -0
  206. package/dist/types/testing/editorViewTestHelpers.d.ts +23 -0
  207. package/dist/types/testing/setupProseMirrorView.d.ts +2 -0
  208. package/dist/types/viewdesc.d.ts +131 -0
  209. package/package.json +113 -0
@@ -0,0 +1,43 @@
1
+ const nav = typeof navigator != "undefined" ? navigator : null;
2
+ const doc = typeof document != "undefined" ? document : null;
3
+ const agent = nav && nav.userAgent || "";
4
+ const ie_edge = /Edge\/(\d+)/.exec(agent);
5
+ const ie_upto10 = /MSIE \d/.exec(agent);
6
+ const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent);
7
+ const ie = !!(ie_upto10 || ie_11up || ie_edge);
8
+ const ie_version = ie_upto10 ? document.documentMode : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0;
9
+ const gecko = !ie && /gecko\/(\d+)/i.test(agent);
10
+ const gecko_version = gecko && +(/Firefox\/(\d+)/.exec(agent) || [
11
+ 0,
12
+ 0
13
+ ])[1];
14
+ const _chrome = !ie && /Chrome\/(\d+)/.exec(agent);
15
+ const chrome = !!_chrome;
16
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17
+ const chrome_version = _chrome ? +_chrome[1] : 0;
18
+ const safari = !ie && !!nav && /Apple Computer/.test(nav.vendor);
19
+ // Is true for both iOS and iPadOS for convenience
20
+ const ios = safari && (/Mobile\/\w+/.test(agent) || !!nav && nav.maxTouchPoints > 2);
21
+ const mac = ios || (nav ? /Mac/.test(nav.platform) : false);
22
+ const windows = nav ? /Win/.test(nav.platform) : false;
23
+ const android = /Android \d/.test(agent);
24
+ const webkit = !!doc && "webkitFontSmoothing" in doc.documentElement.style;
25
+ const webkit_version = webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [
26
+ 0,
27
+ 0
28
+ ])[1] : 0;
29
+ export const browser = {
30
+ ie,
31
+ ie_version,
32
+ gecko,
33
+ gecko_version,
34
+ chrome,
35
+ chrome_version,
36
+ safari,
37
+ ios,
38
+ mac,
39
+ windows,
40
+ android,
41
+ webkit,
42
+ webkit_version
43
+ };
@@ -0,0 +1,318 @@
1
+ import React, { cloneElement, createElement, memo, useContext, useRef } from "react";
2
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
+ import { EditorContext } from "../contexts/EditorContext.js";
4
+ import { iterDeco } from "../decorations/iterDeco.js";
5
+ // import { useEditorState } from "../hooks/useEditorState.js";
6
+ import { useReactKeys } from "../hooks/useReactKeys.js";
7
+ import { htmlAttrsToReactProps, mergeReactProps } from "../props.js";
8
+ import { MarkView } from "./MarkView.js";
9
+ import { NativeWidgetView } from "./NativeWidgetView.js";
10
+ import { NodeView } from "./NodeView.js";
11
+ import { SeparatorHackView } from "./SeparatorHackView.js";
12
+ import { TextNodeView } from "./TextNodeView.js";
13
+ import { TrailingHackView } from "./TrailingHackView.js";
14
+ import { WidgetView } from "./WidgetView.js";
15
+ export function wrapInDeco(reactNode, deco) {
16
+ const { nodeName, ...attrs } = deco.type.attrs;
17
+ const props = htmlAttrsToReactProps(attrs);
18
+ // We auto-wrap text nodes in spans so that we can apply attributes
19
+ // and styles, but we want to avoid double-wrapping the same
20
+ // text node
21
+ if (nodeName || typeof reactNode === "string") {
22
+ return /*#__PURE__*/ createElement(nodeName ?? "span", props, reactNode);
23
+ }
24
+ return /*#__PURE__*/ cloneElement(reactNode, mergeReactProps(reactNode.props, props));
25
+ }
26
+ function areChildrenEqual(a, b) {
27
+ return a.type === b.type && a.marks.every((mark)=>mark.isInSet(b.marks)) && b.marks.every((mark)=>mark.isInSet(a.marks)) && a.key === b.key && (a.type === "node" ? a.outerDeco?.length === b.outerDeco?.length && a.outerDeco?.every((prevDeco)=>b.outerDeco?.some((nextDeco)=>prevDeco.from === nextDeco.from && prevDeco.to && nextDeco.to && prevDeco.type.eq(nextDeco.type))) && a.innerDeco.eq(b.innerDeco) : true) && a.node === b.node && a.widget === b.widget;
28
+ }
29
+ const ChildView = /*#__PURE__*/ memo(function ChildView(param) {
30
+ let { child, getInnerPos } = param;
31
+ const { view } = useContext(EditorContext);
32
+ const getChildPos = useRef(()=>getInnerPos.current() + child.offset);
33
+ getChildPos.current = ()=>getInnerPos.current() + child.offset;
34
+ return child.type === "widget" ? /*#__PURE__*/ React.createElement(WidgetView, {
35
+ key: child.key,
36
+ widget: child.widget,
37
+ getPos: getChildPos
38
+ }) : child.type === "native-widget" ? /*#__PURE__*/ React.createElement(NativeWidgetView, {
39
+ key: child.key,
40
+ widget: child.widget,
41
+ getPos: getChildPos
42
+ }) : child.node.isText ? /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Consumer, {
43
+ key: child.key
44
+ }, (param)=>{
45
+ let { siblingsRef, parentRef } = param;
46
+ return /*#__PURE__*/ React.createElement(TextNodeView, {
47
+ view: view,
48
+ node: child.node,
49
+ getPos: getChildPos,
50
+ siblingsRef: siblingsRef,
51
+ parentRef: parentRef,
52
+ decorations: child.outerDeco
53
+ });
54
+ }) : /*#__PURE__*/ React.createElement(NodeView, {
55
+ key: child.key,
56
+ node: child.node,
57
+ getPos: getChildPos,
58
+ outerDeco: child.outerDeco,
59
+ innerDeco: child.innerDeco
60
+ });
61
+ });
62
+ const InlinePartition = /*#__PURE__*/ memo(function InlinePartition(param) {
63
+ let { childViews, getInnerPos } = param;
64
+ const firstChild = childViews[0];
65
+ const getFirstChildPos = useRef(()=>getInnerPos.current() + firstChild.offset);
66
+ getFirstChildPos.current = ()=>getInnerPos.current() + firstChild.offset;
67
+ const firstMark = firstChild.marks[0];
68
+ if (!firstMark) {
69
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, childViews.map((child)=>{
70
+ return /*#__PURE__*/ React.createElement(ChildView, {
71
+ key: child.key,
72
+ child: child,
73
+ getInnerPos: getInnerPos
74
+ });
75
+ }));
76
+ }
77
+ return /*#__PURE__*/ React.createElement(MarkView, {
78
+ getPos: getFirstChildPos,
79
+ key: firstChild.key,
80
+ mark: firstMark
81
+ }, /*#__PURE__*/ React.createElement(InlineView, {
82
+ key: firstChild.key,
83
+ getInnerPos: getInnerPos,
84
+ childViews: childViews.map((child)=>({
85
+ ...child,
86
+ marks: child.marks.slice(1)
87
+ }))
88
+ }));
89
+ });
90
+ const InlineView = /*#__PURE__*/ memo(function InlineView(param) {
91
+ let { getInnerPos, childViews } = param;
92
+ // const editorState = useEditorState();
93
+ const partitioned = childViews.reduce((acc, child)=>{
94
+ const lastPartition = acc[acc.length - 1];
95
+ if (!lastPartition) {
96
+ return [
97
+ [
98
+ child
99
+ ]
100
+ ];
101
+ }
102
+ const lastChild = lastPartition[lastPartition.length - 1];
103
+ if (!lastChild) {
104
+ return [
105
+ ...acc.slice(0, acc.length),
106
+ [
107
+ child
108
+ ]
109
+ ];
110
+ }
111
+ if (!child.marks.length && !lastChild.marks.length || child.marks.length && lastChild.marks.length && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ child.marks[0]?.eq(lastChild.marks[0])) {
113
+ return [
114
+ ...acc.slice(0, acc.length - 1),
115
+ [
116
+ ...lastPartition.slice(0, lastPartition.length),
117
+ child
118
+ ]
119
+ ];
120
+ }
121
+ return [
122
+ ...acc,
123
+ [
124
+ child
125
+ ]
126
+ ];
127
+ }, []);
128
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, partitioned.map((childViews)=>{
129
+ const firstChild = childViews[0];
130
+ if (!firstChild) return null;
131
+ return /*#__PURE__*/ React.createElement(InlinePartition, {
132
+ key: firstChild.key,
133
+ childViews: childViews,
134
+ getInnerPos: getInnerPos
135
+ });
136
+ }));
137
+ });
138
+ function createKey(innerPos, offset, type, posToKey, widget, index) {
139
+ const pos = innerPos + offset;
140
+ const key = posToKey?.get(pos);
141
+ if (type === "widget" || type === "native-widget") {
142
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
143
+ if (widget.type.spec.key) // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
+ return widget.type.spec.key;
145
+ // eslint-disable-next-line no-console
146
+ console.warn(`Widget at position ${pos} doesn't have a key specified. This may cause issues.`);
147
+ return `${key}-${index}`;
148
+ }
149
+ if (key) return key;
150
+ // if (!doc) return pos;
151
+ const parentPos = innerPos - 1;
152
+ const parentKey = posToKey?.get(parentPos);
153
+ if (parentKey) return `${parentKey}-${offset}`;
154
+ return pos;
155
+ }
156
+ function adjustWidgetMarksForward(lastNodeChild, widgetChild) {
157
+ if (!widgetChild || // Using internal Decoration property, "type"
158
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
159
+ widgetChild.widget.type.side >= 0) return;
160
+ if (!lastNodeChild || !lastNodeChild.node.isInline) return;
161
+ const marksToSpread = lastNodeChild.marks;
162
+ widgetChild.marks = widgetChild.marks.reduce((acc, mark)=>mark.addToSet(acc), marksToSpread);
163
+ }
164
+ function adjustWidgetMarksBack(widgetChildren, nodeChild) {
165
+ if (!nodeChild.node.isInline) return;
166
+ const marksToSpread = nodeChild.marks;
167
+ for(let i = widgetChildren.length - 1; i >= 0; i--){
168
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
169
+ const child = widgetChildren[i];
170
+ if (// Using internal Decoration property, "type"
171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ child.widget.type.side < 0) {
173
+ continue;
174
+ }
175
+ child.marks = child.marks.reduce((acc, mark)=>mark.addToSet(acc), marksToSpread);
176
+ }
177
+ }
178
+ const ChildElement = /*#__PURE__*/ memo(function ChildElement(param) {
179
+ let { child, getInnerPos } = param;
180
+ const getNodePos = useRef(()=>getInnerPos.current() + child.offset);
181
+ getNodePos.current = ()=>getInnerPos.current() + child.offset;
182
+ if (child.type === "node") {
183
+ return child.marks.reduce((element, mark)=>/*#__PURE__*/ React.createElement(MarkView, {
184
+ getPos: getNodePos,
185
+ mark: mark
186
+ }, element), /*#__PURE__*/ React.createElement(NodeView, {
187
+ key: child.key,
188
+ outerDeco: child.outerDeco,
189
+ node: child.node,
190
+ innerDeco: child.innerDeco,
191
+ getPos: getNodePos
192
+ }));
193
+ } else {
194
+ return /*#__PURE__*/ React.createElement(InlineView, {
195
+ key: child.key,
196
+ childViews: [
197
+ child
198
+ ],
199
+ getInnerPos: getInnerPos
200
+ });
201
+ }
202
+ });
203
+ function createChildElements(children, getInnerPos) {
204
+ if (!children.length) return [];
205
+ if (children.every((child)=>child.type !== "node" || child.node.isInline)) {
206
+ return [
207
+ /*#__PURE__*/ React.createElement(InlineView, {
208
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
209
+ key: children[0].key,
210
+ childViews: children,
211
+ getInnerPos: getInnerPos
212
+ })
213
+ ];
214
+ }
215
+ return children.map((child)=>{
216
+ return /*#__PURE__*/ React.createElement(ChildElement, {
217
+ key: child.key,
218
+ child: child,
219
+ getInnerPos: getInnerPos
220
+ });
221
+ });
222
+ }
223
+ export const ChildNodeViews = /*#__PURE__*/ memo(function ChildNodeViews(param) {
224
+ let { getPos, node, innerDecorations } = param;
225
+ // const editorState = useEditorState();
226
+ const reactKeys = useReactKeys();
227
+ const getInnerPos = useRef(()=>getPos.current() + 1);
228
+ const childMap = useRef(new Map()).current;
229
+ if (!node) return null;
230
+ const keysSeen = new Set();
231
+ let widgetChildren = [];
232
+ let lastNodeChild = null;
233
+ iterDeco(node, innerDecorations, (widget, isNative, offset, index)=>{
234
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
+ const widgetMarks = widget.type.spec.marks ?? [];
236
+ let key;
237
+ if (isNative) {
238
+ key = createKey(getInnerPos.current(), offset, "native-widget", reactKeys?.posToKey, widget, index);
239
+ const child = {
240
+ type: "native-widget",
241
+ widget,
242
+ marks: widgetMarks,
243
+ offset,
244
+ index,
245
+ key
246
+ };
247
+ const prevChild = childMap.get(key);
248
+ if (prevChild && areChildrenEqual(prevChild, child)) {
249
+ prevChild.offset = offset;
250
+ } else {
251
+ childMap.set(key, child);
252
+ }
253
+ keysSeen.add(key);
254
+ } else {
255
+ key = createKey(getInnerPos.current(), offset, "widget", reactKeys?.posToKey, widget, index);
256
+ const child = {
257
+ type: "widget",
258
+ widget: widget,
259
+ marks: widgetMarks,
260
+ offset,
261
+ index,
262
+ key
263
+ };
264
+ const prevChild = childMap.get(key);
265
+ if (prevChild && areChildrenEqual(prevChild, child)) {
266
+ prevChild.offset = offset;
267
+ } else {
268
+ childMap.set(key, child);
269
+ }
270
+ keysSeen.add(key);
271
+ }
272
+ const child = childMap.get(key);
273
+ widgetChildren.push(child);
274
+ adjustWidgetMarksForward(lastNodeChild, childMap.get(key));
275
+ }, (childNode, outerDeco, innerDeco, offset)=>{
276
+ const key = createKey(getInnerPos.current(), offset, "node", reactKeys?.posToKey);
277
+ const child = {
278
+ type: "node",
279
+ node: childNode,
280
+ marks: childNode.marks,
281
+ innerDeco,
282
+ outerDeco,
283
+ offset,
284
+ key
285
+ };
286
+ const prevChild = childMap.get(key);
287
+ if (prevChild && areChildrenEqual(prevChild, child)) {
288
+ prevChild.offset = offset;
289
+ lastNodeChild = prevChild;
290
+ } else {
291
+ childMap.set(key, child);
292
+ lastNodeChild = child;
293
+ }
294
+ keysSeen.add(key);
295
+ adjustWidgetMarksBack(widgetChildren, lastNodeChild);
296
+ widgetChildren = [];
297
+ });
298
+ for (const key of childMap.keys()){
299
+ if (!keysSeen.has(key)) {
300
+ childMap.delete(key);
301
+ }
302
+ }
303
+ const children = Array.from(childMap.values()).sort((a, b)=>a.offset - b.offset);
304
+ const childElements = createChildElements(children, getInnerPos);
305
+ const lastChild = children[children.length - 1];
306
+ if (!lastChild || lastChild.type !== "node" || lastChild.node.isInline && !lastChild.node.isText || // RegExp.test actually handles undefined just fine
307
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
308
+ /\n$/.test(lastChild.node.text)) {
309
+ childElements.push(/*#__PURE__*/ React.createElement(SeparatorHackView, {
310
+ getPos: getInnerPos,
311
+ key: "trailing-hack-img"
312
+ }), /*#__PURE__*/ React.createElement(TrailingHackView, {
313
+ getPos: getInnerPos,
314
+ key: "trailing-hack-br"
315
+ }));
316
+ }
317
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, childElements);
318
+ });
@@ -0,0 +1,40 @@
1
+ import React, { forwardRef, useImperativeHandle, useRef, useState } from "react";
2
+ import { domIndex } from "../dom.js";
3
+ import { useEditorEffect } from "../hooks/useEditorEffect.js";
4
+ export const CursorWrapper = /*#__PURE__*/ forwardRef(function CursorWrapper(param, ref) {
5
+ let { widget, getPos, ...props } = param;
6
+ const [shouldRender, setShouldRender] = useState(true);
7
+ const innerRef = useRef(null);
8
+ useImperativeHandle(ref, ()=>{
9
+ return innerRef.current;
10
+ }, []);
11
+ useEditorEffect((view)=>{
12
+ if (!view || !innerRef.current) return;
13
+ // @ts-expect-error Internal property - domObserver
14
+ view.domObserver.disconnectSelection();
15
+ // @ts-expect-error Internal property - domSelection
16
+ const domSel = view.domSelection();
17
+ const range = document.createRange();
18
+ const node = innerRef.current;
19
+ const img = node.nodeName == "IMG";
20
+ if (img && node.parentNode) {
21
+ range.setEnd(node.parentNode, domIndex(node) + 1);
22
+ } else {
23
+ range.setEnd(node, 0);
24
+ }
25
+ range.collapse(false);
26
+ domSel.removeAllRanges();
27
+ domSel.addRange(range);
28
+ setShouldRender(false);
29
+ // @ts-expect-error Internal property - domObserver
30
+ view.domObserver.connectSelection();
31
+ }, []);
32
+ return shouldRender ? /*#__PURE__*/ React.createElement("img", {
33
+ ref: innerRef,
34
+ className: "ProseMirror-separator",
35
+ // eslint-disable-next-line react/no-unknown-property
36
+ "mark-placeholder": "true",
37
+ alt: "",
38
+ ...props
39
+ }) : null;
40
+ });
@@ -0,0 +1,28 @@
1
+ import React, { createElement, useContext } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { EditorContext } from "../contexts/EditorContext.js";
4
+ import { useClientOnly } from "../hooks/useClientOnly.js";
5
+ import { ChildNodeViews } from "./ChildNodeViews.js";
6
+ export function CustomNodeView(param) {
7
+ let { contentDomRef, customNodeViewRef, customNodeViewRootRef, customNodeView, initialNode, node, getPos, initialOuterDeco, initialInnerDeco, innerDeco } = param;
8
+ const { view } = useContext(EditorContext);
9
+ const shouldRender = useClientOnly();
10
+ if (!shouldRender) return null;
11
+ if (!customNodeViewRef.current) {
12
+ customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
13
+ // this line if customNodeView is set
14
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15
+ view, ()=>getPos.current(), initialOuterDeco.current, initialInnerDeco.current);
16
+ }
17
+ const { contentDOM } = customNodeViewRef.current;
18
+ contentDomRef.current = contentDOM ?? null;
19
+ return /*#__PURE__*/ createElement(node.isInline ? "span" : "div", {
20
+ ref: customNodeViewRootRef,
21
+ contentEditable: !!contentDOM,
22
+ suppressContentEditableWarning: true
23
+ }, contentDOM && /*#__PURE__*/ createPortal(/*#__PURE__*/ React.createElement(ChildNodeViews, {
24
+ getPos: getPos,
25
+ node: node,
26
+ innerDecorations: innerDeco
27
+ }), contentDOM));
28
+ }
@@ -0,0 +1,53 @@
1
+ // TODO: I must be missing something, but I do not know why
2
+ // this linting rule is only broken in this file
3
+ /* eslint-disable react/prop-types */ import React, { cloneElement, createElement, forwardRef, memo, useImperativeHandle, useMemo, useRef } from "react";
4
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
5
+ import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
6
+ import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
7
+ const getPos = {
8
+ current () {
9
+ return -1;
10
+ }
11
+ };
12
+ export const DocNodeView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function DocNodeView(param, ref) {
13
+ let { className, node, innerDeco, outerDeco, as, viewDesc, ...elementProps } = param;
14
+ const innerRef = useRef(null);
15
+ useImperativeHandle(ref, ()=>{
16
+ return innerRef.current;
17
+ }, []);
18
+ const { childDescriptors, nodeViewDescRef } = useNodeViewDescriptor(node, ()=>getPos.current(), innerRef, innerRef, innerDeco, outerDeco, viewDesc);
19
+ const childContextValue = useMemo(()=>({
20
+ parentRef: nodeViewDescRef,
21
+ siblingsRef: childDescriptors
22
+ }), [
23
+ childDescriptors,
24
+ nodeViewDescRef
25
+ ]);
26
+ const props = {
27
+ ...elementProps,
28
+ ref: innerRef,
29
+ className,
30
+ suppressContentEditableWarning: true
31
+ };
32
+ const element = as ? /*#__PURE__*/ cloneElement(as, props, /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
33
+ value: childContextValue
34
+ }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
35
+ getPos: getPos,
36
+ node: node,
37
+ innerDecorations: innerDeco
38
+ }))) : /*#__PURE__*/ createElement("div", props, /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
39
+ value: childContextValue
40
+ }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
41
+ getPos: getPos,
42
+ node: node,
43
+ innerDecorations: innerDeco
44
+ })));
45
+ if (!node) return element;
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ const nodeDecorations = outerDeco.filter((deco)=>!deco.inline);
48
+ if (!nodeDecorations.length) {
49
+ return element;
50
+ }
51
+ const wrapped = nodeDecorations.reduce(wrapInDeco, element);
52
+ return wrapped;
53
+ }));
@@ -0,0 +1,66 @@
1
+ /* Copyright (c) The New York Times Company */ import React, { useCallback, useLayoutEffect, useRef } from "react";
2
+ import { LayoutGroupContext } from "../contexts/LayoutGroupContext.js";
3
+ import { useForceUpdate } from "../hooks/useForceUpdate.js";
4
+ /**
5
+ * Provides a boundary for grouping layout effects.
6
+ *
7
+ * Descendant components can invoke the `useLayoutGroupEffect` hook to register
8
+ * effects that run after all descendants within the group have processed their
9
+ * regular layout effects.
10
+ */ export function LayoutGroup(param) {
11
+ let { children } = param;
12
+ const createQueue = useRef(new Set()).current;
13
+ const destroyQueue = useRef(new Set()).current;
14
+ const isMounted = useRef(false);
15
+ const forceUpdate = useForceUpdate();
16
+ const isUpdatePending = useRef(true);
17
+ const ensureFlush = useCallback(()=>{
18
+ if (!isUpdatePending.current) {
19
+ forceUpdate();
20
+ isUpdatePending.current = true;
21
+ }
22
+ }, [
23
+ forceUpdate
24
+ ]);
25
+ const register = useCallback((effect)=>{
26
+ let destroy;
27
+ const create = ()=>{
28
+ destroy = effect();
29
+ };
30
+ createQueue.add(create);
31
+ ensureFlush();
32
+ return ()=>{
33
+ createQueue.delete(create);
34
+ if (destroy) {
35
+ if (isMounted.current) {
36
+ destroyQueue.add(destroy);
37
+ ensureFlush();
38
+ } else {
39
+ destroy();
40
+ }
41
+ }
42
+ };
43
+ }, [
44
+ createQueue,
45
+ destroyQueue,
46
+ ensureFlush
47
+ ]);
48
+ useLayoutEffect(()=>{
49
+ isUpdatePending.current = false;
50
+ createQueue.forEach((create)=>create());
51
+ createQueue.clear();
52
+ return ()=>{
53
+ destroyQueue.forEach((destroy)=>destroy());
54
+ destroyQueue.clear();
55
+ };
56
+ });
57
+ useLayoutEffect(()=>{
58
+ isMounted.current = true;
59
+ return ()=>{
60
+ isMounted.current = false;
61
+ };
62
+ }, []);
63
+ return /*#__PURE__*/ React.createElement(LayoutGroupContext.Provider, {
64
+ value: register
65
+ }, children);
66
+ }
@@ -0,0 +1,64 @@
1
+ import React, { forwardRef, memo, useContext, useImperativeHandle, useLayoutEffect, useMemo, useRef } from "react";
2
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
+ import { MarkViewDesc, sortViewDescs } from "../viewdesc.js";
4
+ import { OutputSpec } from "./OutputSpec.js";
5
+ export const MarkView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function MarkView(param, ref) {
6
+ let { mark, getPos, children } = param;
7
+ const { siblingsRef, parentRef } = useContext(ChildDescriptorsContext);
8
+ const viewDescRef = useRef(undefined);
9
+ const childDescriptors = useRef([]);
10
+ const domRef = useRef(null);
11
+ useImperativeHandle(ref, ()=>{
12
+ return domRef.current;
13
+ }, []);
14
+ const outputSpec = useMemo(()=>mark.type.spec.toDOM?.(mark, true), [
15
+ mark
16
+ ]);
17
+ if (!outputSpec) throw new Error(`Mark spec for ${mark.type.name} is missing toDOM`);
18
+ useLayoutEffect(()=>{
19
+ const siblings = siblingsRef.current;
20
+ return ()=>{
21
+ if (!viewDescRef.current) return;
22
+ if (siblings.includes(viewDescRef.current)) {
23
+ const index = siblings.indexOf(viewDescRef.current);
24
+ siblings.splice(index, 1);
25
+ }
26
+ };
27
+ }, [
28
+ siblingsRef
29
+ ]);
30
+ useLayoutEffect(()=>{
31
+ if (!domRef.current) return;
32
+ const firstChildDesc = childDescriptors.current[0];
33
+ if (!viewDescRef.current) {
34
+ viewDescRef.current = new MarkViewDesc(parentRef.current, childDescriptors.current, ()=>getPos.current(), mark, domRef.current, firstChildDesc?.dom.parentElement ?? domRef.current);
35
+ } else {
36
+ viewDescRef.current.parent = parentRef.current;
37
+ viewDescRef.current.dom = domRef.current;
38
+ viewDescRef.current.children = childDescriptors.current;
39
+ viewDescRef.current.contentDOM = firstChildDesc?.dom.parentElement ?? domRef.current;
40
+ viewDescRef.current.mark = mark;
41
+ viewDescRef.current.getPos = ()=>getPos.current();
42
+ }
43
+ if (!siblingsRef.current.includes(viewDescRef.current)) {
44
+ siblingsRef.current.push(viewDescRef.current);
45
+ }
46
+ siblingsRef.current.sort(sortViewDescs);
47
+ for (const childDesc of childDescriptors.current){
48
+ childDesc.parent = viewDescRef.current;
49
+ }
50
+ });
51
+ const childContextValue = useMemo(()=>({
52
+ parentRef: viewDescRef,
53
+ siblingsRef: childDescriptors
54
+ }), [
55
+ childDescriptors,
56
+ viewDescRef
57
+ ]);
58
+ return /*#__PURE__*/ React.createElement(OutputSpec, {
59
+ ref: domRef,
60
+ outputSpec: outputSpec
61
+ }, /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
62
+ value: childContextValue
63
+ }, children));
64
+ }));
@@ -0,0 +1,58 @@
1
+ import React, { useContext, useLayoutEffect, useRef } from "react";
2
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
+ import { useEditorEffect } from "../hooks/useEditorEffect.js";
4
+ import { WidgetViewDesc, sortViewDescs } from "../viewdesc.js";
5
+ export function NativeWidgetView(param) {
6
+ let { widget, getPos } = param;
7
+ const { siblingsRef, parentRef } = useContext(ChildDescriptorsContext);
8
+ const viewDescRef = useRef(null);
9
+ const rootDomRef = useRef(null);
10
+ useLayoutEffect(()=>{
11
+ const siblings = siblingsRef.current;
12
+ return ()=>{
13
+ if (!viewDescRef.current) return;
14
+ if (siblings.includes(viewDescRef.current)) {
15
+ const index = siblings.indexOf(viewDescRef.current);
16
+ siblings.splice(index, 1);
17
+ }
18
+ };
19
+ }, [
20
+ siblingsRef
21
+ ]);
22
+ useEditorEffect((view)=>{
23
+ if (!rootDomRef.current) return;
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ const toDOM = widget.type.toDOM;
26
+ let dom = typeof toDOM === "function" ? toDOM(view, ()=>getPos.current()) : toDOM;
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ if (!widget.type.spec.raw) {
29
+ if (dom.nodeType != 1) {
30
+ const wrap = document.createElement("span");
31
+ wrap.appendChild(dom);
32
+ dom = wrap;
33
+ }
34
+ dom.contentEditable = "false";
35
+ dom.classList.add("ProseMirror-widget");
36
+ }
37
+ if (rootDomRef.current.firstElementChild === dom) return;
38
+ rootDomRef.current.replaceChildren(dom);
39
+ });
40
+ useLayoutEffect(()=>{
41
+ if (!rootDomRef.current) return;
42
+ if (!viewDescRef.current) {
43
+ viewDescRef.current = new WidgetViewDesc(parentRef.current, ()=>getPos.current(), widget, rootDomRef.current);
44
+ } else {
45
+ viewDescRef.current.parent = parentRef.current;
46
+ viewDescRef.current.widget = widget;
47
+ viewDescRef.current.getPos = ()=>getPos.current();
48
+ viewDescRef.current.dom = rootDomRef.current;
49
+ }
50
+ if (!siblingsRef.current.includes(viewDescRef.current)) {
51
+ siblingsRef.current.push(viewDescRef.current);
52
+ }
53
+ siblingsRef.current.sort(sortViewDescs);
54
+ });
55
+ return /*#__PURE__*/ React.createElement("span", {
56
+ ref: rootDomRef
57
+ });
58
+ }