@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.
Files changed (149) 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 +58 -29
  5. package/dist/cjs/components/CustomNodeView.js +77 -137
  6. package/dist/cjs/{hooks/useNodePos.js → components/DefaultNodeView.js} +24 -26
  7. package/dist/cjs/components/DocNodeView.js +33 -41
  8. package/dist/cjs/components/MarkView.js +1 -2
  9. package/dist/cjs/components/NativeWidgetView.js +2 -3
  10. package/dist/cjs/components/NodeView.js +31 -21
  11. package/dist/cjs/components/ProseMirror.js +25 -17
  12. package/dist/cjs/components/ProseMirrorDoc.js +7 -27
  13. package/dist/cjs/components/ReactNodeView.js +98 -61
  14. package/dist/cjs/components/SeparatorHackView.js +1 -2
  15. package/dist/cjs/components/TextNodeView.js +4 -5
  16. package/dist/cjs/components/TrailingHackView.js +1 -2
  17. package/dist/cjs/components/WidgetView.js +2 -4
  18. package/dist/cjs/constants.js +33 -0
  19. package/dist/cjs/hooks/useEditor.js +33 -229
  20. package/dist/cjs/hooks/useEditorEffect.js +2 -2
  21. package/dist/cjs/hooks/useEditorEventCallback.js +8 -5
  22. package/dist/cjs/hooks/useIgnoreMutation.js +1 -1
  23. package/dist/cjs/hooks/useNodeViewDescriptor.js +123 -80
  24. package/dist/cjs/hooks/useReactKeys.js +1 -1
  25. package/dist/cjs/hooks/useSelectNode.js +9 -7
  26. package/dist/cjs/hooks/useStopEvent.js +1 -1
  27. package/dist/cjs/plugins/beforeInputPlugin.js +12 -0
  28. package/dist/cjs/testing/editorViewTestHelpers.js +0 -2
  29. package/dist/cjs/viewdesc.js +104 -25
  30. package/dist/esm/AbstractEditorView.js +1 -0
  31. package/dist/esm/ReactEditorView.js +156 -0
  32. package/dist/esm/StaticEditorView.js +76 -0
  33. package/dist/esm/components/ChildNodeViews.js +59 -31
  34. package/dist/esm/components/CustomNodeView.js +78 -138
  35. package/dist/esm/components/DefaultNodeView.js +16 -0
  36. package/dist/esm/components/DocNodeView.js +33 -41
  37. package/dist/esm/components/MarkView.js +1 -2
  38. package/dist/esm/components/NativeWidgetView.js +2 -3
  39. package/dist/esm/components/NodeView.js +32 -22
  40. package/dist/esm/components/ProseMirror.js +25 -17
  41. package/dist/esm/components/ProseMirrorDoc.js +7 -28
  42. package/dist/esm/components/ReactNodeView.js +99 -62
  43. package/dist/esm/components/SeparatorHackView.js +1 -2
  44. package/dist/esm/components/TextNodeView.js +4 -5
  45. package/dist/esm/components/TrailingHackView.js +1 -2
  46. package/dist/esm/components/WidgetView.js +2 -4
  47. package/dist/esm/constants.js +15 -0
  48. package/dist/esm/hooks/useEditor.js +29 -218
  49. package/dist/esm/hooks/useEditorEffect.js +2 -2
  50. package/dist/esm/hooks/useEditorEventCallback.js +8 -5
  51. package/dist/esm/hooks/useIgnoreMutation.js +1 -1
  52. package/dist/esm/hooks/useNodeViewDescriptor.js +125 -82
  53. package/dist/esm/hooks/useReactKeys.js +1 -1
  54. package/dist/esm/hooks/useSelectNode.js +9 -7
  55. package/dist/esm/hooks/useStopEvent.js +1 -1
  56. package/dist/esm/plugins/beforeInputPlugin.js +12 -0
  57. package/dist/esm/testing/editorViewTestHelpers.js +0 -2
  58. package/dist/esm/viewdesc.js +94 -18
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/dist/types/AbstractEditorView.d.ts +27 -0
  61. package/dist/types/ReactEditorView.d.ts +80 -0
  62. package/dist/types/StaticEditorView.d.ts +24 -0
  63. package/dist/types/components/ChildNodeViews.d.ts +2 -2
  64. package/dist/types/components/CustomNodeView.d.ts +3 -3
  65. package/dist/types/components/DefaultNodeView.d.ts +3 -0
  66. package/dist/types/components/DocNodeView.d.ts +9 -17
  67. package/dist/types/components/MarkView.d.ts +2 -2
  68. package/dist/types/components/NativeWidgetView.d.ts +2 -2
  69. package/dist/types/components/NodeView.d.ts +5 -5
  70. package/dist/types/components/NodeViewComponentProps.d.ts +3 -4
  71. package/dist/types/components/ProseMirrorDoc.d.ts +14 -8
  72. package/dist/types/components/ReactNodeView.d.ts +4 -2
  73. package/dist/types/components/SeparatorHackView.d.ts +2 -2
  74. package/dist/types/components/TextNodeView.d.ts +4 -3
  75. package/dist/types/components/TrailingHackView.d.ts +2 -2
  76. package/dist/types/components/WidgetView.d.ts +2 -2
  77. package/dist/types/constants.d.ts +4 -0
  78. package/dist/types/contexts/EditorContext.d.ts +6 -4
  79. package/dist/types/contexts/IgnoreMutationContext.d.ts +2 -1
  80. package/dist/types/contexts/NodeViewContext.d.ts +3 -1
  81. package/dist/types/contexts/SelectNodeContext.d.ts +3 -1
  82. package/dist/types/contexts/StopEventContext.d.ts +2 -1
  83. package/dist/types/decorations/computeDocDeco.d.ts +3 -2
  84. package/dist/types/decorations/viewDecorations.d.ts +3 -2
  85. package/dist/types/hooks/useEditor.d.ts +5 -46
  86. package/dist/types/hooks/useNodeViewDescriptor.d.ts +18 -10
  87. package/dist/types/hooks/useReactKeys.d.ts +1 -1
  88. package/dist/types/hooks/useSelectNode.d.ts +2 -1
  89. package/dist/types/props.d.ts +3 -3
  90. package/dist/types/viewdesc.d.ts +29 -11
  91. package/package.json +7 -3
  92. package/dist/cjs/components/Editor.js +0 -28
  93. package/dist/cjs/components/NodeViews.js +0 -73
  94. package/dist/cjs/components/__tests__/LayoutGroup.test.js +0 -141
  95. package/dist/cjs/components/__tests__/ProseMirror.test.js +0 -255
  96. package/dist/cjs/contexts/NodeViewsContext.js +0 -10
  97. package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -107
  98. package/dist/cjs/hooks/__tests__/useNodeViews.test.js +0 -159
  99. package/dist/cjs/hooks/useClientOnly.js +0 -19
  100. package/dist/cjs/hooks/useEditorView.js +0 -100
  101. package/dist/cjs/hooks/useNodeViews.js +0 -100
  102. package/dist/cjs/nodeViews/createReactNodeViewConstructor.js +0 -244
  103. package/dist/cjs/nodeViews/phrasingContentTags.js +0 -57
  104. package/dist/cjs/plugins/__tests__/react.test.js +0 -139
  105. package/dist/cjs/plugins/react.js +0 -71
  106. package/dist/cjs/selection/SelectionDOMObserver.js +0 -171
  107. package/dist/cjs/selection/hasFocusAndSelection.js +0 -35
  108. package/dist/cjs/selection/selectionFromDOM.js +0 -77
  109. package/dist/cjs/selection/selectionToDOM.js +0 -226
  110. package/dist/cjs/ssr.js +0 -85
  111. package/dist/esm/components/Editor.js +0 -15
  112. package/dist/esm/components/NodeViews.js +0 -26
  113. package/dist/esm/components/__tests__/LayoutGroup.test.js +0 -98
  114. package/dist/esm/components/__tests__/ProseMirror.test.js +0 -207
  115. package/dist/esm/contexts/NodeViewsContext.js +0 -9
  116. package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +0 -98
  117. package/dist/esm/hooks/__tests__/useNodeViews.test.js +0 -116
  118. package/dist/esm/hooks/useClientOnly.js +0 -9
  119. package/dist/esm/hooks/useEditorView.js +0 -99
  120. package/dist/esm/hooks/useNodePos.js +0 -16
  121. package/dist/esm/hooks/useNodeViews.js +0 -53
  122. package/dist/esm/nodeViews/createReactNodeViewConstructor.js +0 -214
  123. package/dist/esm/nodeViews/phrasingContentTags.js +0 -49
  124. package/dist/esm/plugins/__tests__/react.test.js +0 -135
  125. package/dist/esm/plugins/react.js +0 -64
  126. package/dist/esm/selection/SelectionDOMObserver.js +0 -161
  127. package/dist/esm/selection/hasFocusAndSelection.js +0 -17
  128. package/dist/esm/selection/selectionFromDOM.js +0 -59
  129. package/dist/esm/selection/selectionToDOM.js +0 -196
  130. package/dist/esm/ssr.js +0 -82
  131. package/dist/types/components/Editor.d.ts +0 -7
  132. package/dist/types/components/NodeViews.d.ts +0 -6
  133. package/dist/types/components/__tests__/LayoutGroup.test.d.ts +0 -1
  134. package/dist/types/contexts/NodeViewsContext.d.ts +0 -19
  135. package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +0 -1
  136. package/dist/types/hooks/__tests__/useNodeViews.test.d.ts +0 -1
  137. package/dist/types/hooks/useClientOnly.d.ts +0 -1
  138. package/dist/types/hooks/useEditorView.d.ts +0 -23
  139. package/dist/types/hooks/useNodePos.d.ts +0 -9
  140. package/dist/types/hooks/useNodeViews.d.ts +0 -5
  141. package/dist/types/nodeViews/createReactNodeViewConstructor.d.ts +0 -48
  142. package/dist/types/nodeViews/phrasingContentTags.d.ts +0 -1
  143. package/dist/types/plugins/__tests__/react.test.d.ts +0 -1
  144. package/dist/types/plugins/react.d.ts +0 -21
  145. package/dist/types/selection/SelectionDOMObserver.d.ts +0 -33
  146. package/dist/types/selection/hasFocusAndSelection.d.ts +0 -3
  147. package/dist/types/selection/selectionFromDOM.d.ts +0 -4
  148. package/dist/types/selection/selectionToDOM.d.ts +0 -9
  149. package/dist/types/ssr.d.ts +0 -19
@@ -0,0 +1,16 @@
1
+ import React, { forwardRef, useMemo } from "react";
2
+ import { OutputSpec } from "./OutputSpec.js";
3
+ export const DefaultNodeView = /*#__PURE__*/ forwardRef(function DefaultNodeView(param, ref) {
4
+ let { nodeProps: { node }, children, ...props } = param;
5
+ const spec = useMemo(()=>node.type.spec.toDOM?.(node), [
6
+ node
7
+ ]);
8
+ if (!spec) {
9
+ throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
10
+ }
11
+ return /*#__PURE__*/ React.createElement(OutputSpec, {
12
+ ...props,
13
+ outputSpec: spec,
14
+ ref: ref
15
+ }, children);
16
+ });
@@ -1,53 +1,45 @@
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";
1
+ import React, { cloneElement, createElement, forwardRef, memo, useImperativeHandle, useMemo, useRef } from "react";
4
2
  import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
5
3
  import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
6
4
  import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
7
- const getPos = {
8
- current () {
9
- return -1;
10
- }
11
- };
12
5
  export const DocNodeView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function DocNodeView(param, ref) {
13
- let { className, node, innerDeco, outerDeco, as, viewDesc, ...elementProps } = param;
6
+ let { as, node, getPos, decorations, innerDecorations, setMount, ...elementProps } = param;
14
7
  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
8
+ useImperativeHandle(ref, ()=>innerRef.current);
9
+ useImperativeHandle(setMount, ()=>innerRef.current);
10
+ const nodeProps = useMemo(()=>({
11
+ node,
12
+ getPos,
13
+ decorations,
14
+ innerDecorations
22
15
  }), [
23
- childDescriptors,
24
- nodeViewDescRef
16
+ node,
17
+ getPos,
18
+ decorations,
19
+ innerDecorations
25
20
  ]);
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, {
21
+ const { childContextValue } = useNodeViewDescriptor(innerRef, ()=>{
22
+ const dom = innerRef.current;
23
+ return {
24
+ dom,
25
+ contentDOM: dom,
26
+ update () {
27
+ return true;
28
+ }
29
+ };
30
+ }, nodeProps);
31
+ const children = /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
39
32
  value: childContextValue
40
33
  }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
41
34
  getPos: getPos,
42
35
  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;
36
+ innerDecorations: innerDecorations
37
+ }));
38
+ const props = {
39
+ ...elementProps,
40
+ suppressContentEditableWarning: true,
41
+ ref: innerRef
42
+ };
43
+ const element = as ? /*#__PURE__*/ cloneElement(as, props, children) : /*#__PURE__*/ createElement("div", props, children);
44
+ return nodeProps.decorations.reduce(wrapInDeco, element);
53
45
  }));
@@ -32,7 +32,7 @@ export const MarkView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function Mar
32
32
  if (!domRef.current) return;
33
33
  const firstChildDesc = childDescriptors.current[0];
34
34
  if (!viewDescRef.current) {
35
- viewDescRef.current = new MarkViewDesc(parentRef.current, childDescriptors.current, ()=>getPos.current(), mark, domRef.current, firstChildDesc?.dom.parentElement ?? domRef.current, {
35
+ viewDescRef.current = new MarkViewDesc(parentRef.current, childDescriptors.current, getPos, mark, domRef.current, firstChildDesc?.dom.parentElement ?? domRef.current, {
36
36
  dom: domRef.current,
37
37
  contentDOM: firstChildDesc?.dom.parentElement ?? domRef.current
38
38
  });
@@ -42,7 +42,6 @@ export const MarkView = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function Mar
42
42
  viewDescRef.current.children = childDescriptors.current;
43
43
  viewDescRef.current.spec.contentDOM = viewDescRef.current.contentDOM = firstChildDesc?.dom.parentElement ?? domRef.current;
44
44
  viewDescRef.current.mark = mark;
45
- viewDescRef.current.getPos = ()=>getPos.current();
46
45
  }
47
46
  if (!siblingsRef.current.includes(viewDescRef.current)) {
48
47
  siblingsRef.current.push(viewDescRef.current);
@@ -24,7 +24,7 @@ export function NativeWidgetView(param) {
24
24
  if (!rootDomRef.current) return;
25
25
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
26
  const toDOM = widget.type.toDOM;
27
- let dom = typeof toDOM === "function" ? toDOM(view, ()=>getPos.current()) : toDOM;
27
+ let dom = typeof toDOM === "function" ? toDOM(view, getPos) : toDOM;
28
28
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
29
  if (!widget.type.spec.raw) {
30
30
  if (dom.nodeType != 1) {
@@ -41,11 +41,10 @@ export function NativeWidgetView(param) {
41
41
  useClientLayoutEffect(()=>{
42
42
  if (!rootDomRef.current) return;
43
43
  if (!viewDescRef.current) {
44
- viewDescRef.current = new WidgetViewDesc(parentRef.current, ()=>getPos.current(), widget, rootDomRef.current);
44
+ viewDescRef.current = new WidgetViewDesc(parentRef.current, getPos, widget, rootDomRef.current);
45
45
  } else {
46
46
  viewDescRef.current.parent = parentRef.current;
47
47
  viewDescRef.current.widget = widget;
48
- viewDescRef.current.getPos = ()=>getPos.current();
49
48
  viewDescRef.current.dom = rootDomRef.current;
50
49
  }
51
50
  if (!siblingsRef.current.includes(viewDescRef.current)) {
@@ -1,25 +1,35 @@
1
- import React, { memo, useContext } from "react";
2
- import { EditorContext } from "../contexts/EditorContext.js";
1
+ import React, { memo, useContext, useMemo } from "react";
2
+ import { NodeViewContext } from "../contexts/NodeViewContext.js";
3
3
  import { CustomNodeView } from "./CustomNodeView.js";
4
+ import { DefaultNodeView } from "./DefaultNodeView.js";
4
5
  import { ReactNodeView } from "./ReactNodeView.js";
5
- export const NodeView = /*#__PURE__*/ memo(function NodeView(param) {
6
- let { outerDeco, getPos, node, innerDeco, ...props } = param;
7
- const { view } = useContext(EditorContext);
8
- const customNodeView = view?.someProp("nodeViews", (nodeViews)=>nodeViews?.[node.type.name]);
9
- if (customNodeView) {
10
- return /*#__PURE__*/ React.createElement(CustomNodeView, {
11
- customNodeView: customNodeView,
12
- node: node,
13
- innerDeco: innerDeco,
14
- outerDeco: outerDeco,
15
- getPos: getPos
16
- });
17
- }
18
- return /*#__PURE__*/ React.createElement(ReactNodeView, {
19
- node: node,
20
- innerDeco: innerDeco,
21
- outerDeco: outerDeco,
22
- getPos: getPos,
23
- ...props
24
- });
6
+ export const NodeView = /*#__PURE__*/ memo(function NodeView(props) {
7
+ const { components, constructors } = useContext(NodeViewContext);
8
+ const component = components[props.node.type.name] ?? DefaultNodeView;
9
+ const constructor = constructors[props.node.type.name];
10
+ // Construct a wrapper component so that the node view remounts when either
11
+ // its component or constructor changes. A React node view would remount if
12
+ // its underlying component changed without this wrapper, but a custom node
13
+ // view otherwise uses the same React components for all custom node views.
14
+ const Component = useMemo(()=>{
15
+ if (constructor) {
16
+ return function NodeView(props) {
17
+ return /*#__PURE__*/ React.createElement(CustomNodeView, {
18
+ constructor: constructor,
19
+ ...props
20
+ });
21
+ };
22
+ } else {
23
+ return function NodeView(props) {
24
+ return /*#__PURE__*/ React.createElement(ReactNodeView, {
25
+ component: component,
26
+ ...props
27
+ });
28
+ };
29
+ }
30
+ }, [
31
+ constructor,
32
+ component
33
+ ]);
34
+ return /*#__PURE__*/ React.createElement(Component, props);
25
35
  });
@@ -1,4 +1,3 @@
1
- import { DecorationSet } from "prosemirror-view";
2
1
  import React, { useMemo, useState } from "react";
3
2
  import { EditorContext } from "../contexts/EditorContext.js";
4
3
  import { EditorStateContext } from "../contexts/EditorStateContext.js";
@@ -8,7 +7,9 @@ import { viewDecorations } from "../decorations/viewDecorations.js";
8
7
  import { useEditor } from "../hooks/useEditor.js";
9
8
  import { LayoutGroup } from "./LayoutGroup.js";
10
9
  import { DocNodeViewContext } from "./ProseMirrorDoc.js";
11
- const EMPTY_OUTER_DECOS = [];
10
+ function getPos() {
11
+ return -1;
12
+ }
12
13
  function ProseMirrorInner(param) {
13
14
  let { className, children, nodeViews, customNodeViews, ...props } = param;
14
15
  const [mount, setMount] = useState(null);
@@ -16,26 +17,33 @@ function ProseMirrorInner(param) {
16
17
  ...props,
17
18
  nodeViews: customNodeViews
18
19
  });
19
- const innerDecos = editor.view ? viewDecorations(editor.view, editor.cursorWrapper) : DecorationSet.empty;
20
- const outerDecos = editor.view ? computeDocDeco(editor.view) : EMPTY_OUTER_DECOS;
21
- const nodeViewContextValue = useMemo(()=>({
22
- nodeViews: nodeViews ?? {}
23
- }), [
20
+ const nodeViewConstructors = editor.view.nodeViews;
21
+ const nodeViewContextValue = useMemo(()=>{
22
+ return {
23
+ components: {
24
+ ...nodeViews
25
+ },
26
+ constructors: nodeViewConstructors
27
+ };
28
+ }, [
29
+ nodeViewConstructors,
24
30
  nodeViews
25
31
  ]);
32
+ const node = state.doc;
33
+ const decorations = computeDocDeco(editor.view);
34
+ const innerDecorations = viewDecorations(editor.view, editor.cursorWrapper);
26
35
  const docNodeViewContextValue = useMemo(()=>({
27
- className: className,
28
- setMount: setMount,
29
- node: editor.view?.state.doc,
30
- innerDeco: innerDecos,
31
- outerDeco: outerDecos,
32
- viewDesc: editor.docViewDescRef.current
36
+ className,
37
+ setMount,
38
+ node,
39
+ getPos,
40
+ decorations,
41
+ innerDecorations
33
42
  }), [
34
43
  className,
35
- editor.docViewDescRef,
36
- editor.view?.state.doc,
37
- innerDecos,
38
- outerDecos
44
+ node,
45
+ decorations,
46
+ innerDecorations
39
47
  ]);
40
48
  return /*#__PURE__*/ React.createElement(EditorContext.Provider, {
41
49
  value: editor
@@ -1,34 +1,13 @@
1
- import React, { createContext, forwardRef, useContext, useImperativeHandle, useMemo, useRef } from "react";
2
- import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
1
+ import React, { createContext, forwardRef, useContext } from "react";
3
2
  import { DocNodeView } from "./DocNodeView.js";
4
3
  export const DocNodeViewContext = /*#__PURE__*/ createContext(null);
5
- function ProseMirrorDoc(param, ref) {
4
+ export const ProseMirrorDoc = /*#__PURE__*/ forwardRef(function ProseMirrorDoc(param, ref) {
6
5
  let { as, ...props } = param;
7
- const childDescriptors = useRef([]);
8
- const innerRef = useRef(null);
9
- const { setMount, ...docProps } = useContext(DocNodeViewContext);
10
- const viewDescRef = useRef(undefined);
11
- useImperativeHandle(ref, ()=>{
12
- return innerRef.current;
13
- }, []);
14
- const childContextValue = useMemo(()=>({
15
- parentRef: viewDescRef,
16
- siblingsRef: childDescriptors
17
- }), [
18
- childDescriptors,
19
- viewDescRef
20
- ]);
21
- return /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
22
- value: childContextValue
23
- }, /*#__PURE__*/ React.createElement(DocNodeView, {
24
- ref: (el)=>{
25
- innerRef.current = el;
26
- setMount(el);
27
- },
6
+ const docProps = useContext(DocNodeViewContext);
7
+ return /*#__PURE__*/ React.createElement(DocNodeView, {
8
+ ref: ref,
28
9
  ...props,
29
10
  ...docProps,
30
11
  as: as
31
- }));
32
- }
33
- const ForwardedProseMirrorDoc = /*#__PURE__*/ forwardRef(ProseMirrorDoc);
34
- export { ForwardedProseMirrorDoc as ProseMirrorDoc };
12
+ });
13
+ });
@@ -1,81 +1,118 @@
1
- import React, { cloneElement, memo, useContext, useMemo, useRef } from "react";
1
+ import React, { cloneElement, memo, useCallback, useMemo, useRef, useState } from "react";
2
2
  import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
3
  import { IgnoreMutationContext } from "../contexts/IgnoreMutationContext.js";
4
- import { NodeViewContext } from "../contexts/NodeViewContext.js";
5
4
  import { SelectNodeContext } from "../contexts/SelectNodeContext.js";
6
5
  import { StopEventContext } from "../contexts/StopEventContext.js";
7
6
  import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
8
7
  import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
9
- import { OutputSpec } from "./OutputSpec.js";
10
8
  export const ReactNodeView = /*#__PURE__*/ memo(function ReactNodeView(param) {
11
- let { outerDeco, getPos, node, innerDeco, ...props } = param;
12
- const domRef = useRef(null);
13
- const nodeDomRef = useRef(null);
14
- const contentDomRef = useRef(null);
15
- const getPosFunc = useRef(()=>getPos.current()).current;
16
- const { nodeViews } = useContext(NodeViewContext);
17
- let element = null;
18
- const Component = nodeViews[node.type.name];
19
- const outputSpec = useMemo(()=>node.type.spec.toDOM?.(node), [
20
- node
21
- ]);
22
- const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, setIgnoreMutation, nodeViewDescRef } = useNodeViewDescriptor(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
23
- const finalProps = {
24
- ...props,
25
- ...!hasContentDOM && nodeDomRef.current?.tagName !== "BR" && {
26
- contentEditable: false
27
- }
28
- };
9
+ let { component: Component, outerDeco, getPos, node, innerDeco } = param;
10
+ const [controlSelected, setControlSelected] = useState(false);
11
+ const [selected, setSelected] = useState(false);
12
+ const ref = useRef(null);
13
+ const innerRef = useRef(null);
14
+ const selectNodeRef = useRef(null);
15
+ const deselectNodeRef = useRef(null);
16
+ const stopEventRef = useRef(null);
17
+ const ignoreMutationRef = useRef(null);
18
+ const setSelectNode = useCallback((selectHandler, deselectHandler)=>{
19
+ selectNodeRef.current = selectHandler;
20
+ deselectNodeRef.current = deselectHandler;
21
+ setControlSelected(true);
22
+ return ()=>{
23
+ selectNodeRef.current = null;
24
+ deselectNodeRef.current = null;
25
+ setControlSelected(false);
26
+ };
27
+ }, []);
28
+ const setStopEvent = useCallback((handler)=>{
29
+ stopEventRef.current = handler;
30
+ return ()=>{
31
+ stopEventRef.current = null;
32
+ };
33
+ }, []);
34
+ const setIgnoreMutation = useCallback((handler)=>{
35
+ ignoreMutationRef.current = handler;
36
+ return ()=>{
37
+ ignoreMutationRef.current = null;
38
+ return ()=>{
39
+ ignoreMutationRef.current = null;
40
+ };
41
+ };
42
+ }, []);
29
43
  const nodeProps = useMemo(()=>({
30
44
  node: node,
31
- getPos: getPosFunc,
45
+ getPos: getPos,
32
46
  decorations: outerDeco,
33
47
  innerDecorations: innerDeco
34
48
  }), [
35
- getPosFunc,
49
+ getPos,
36
50
  innerDeco,
37
51
  node,
38
52
  outerDeco
39
53
  ]);
40
- if (Component) {
41
- element = /*#__PURE__*/ React.createElement(Component, {
42
- ...finalProps,
43
- ref: nodeDomRef,
44
- nodeProps: nodeProps
45
- }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
46
- getPos: getPos,
47
- node: node,
48
- innerDecorations: innerDeco
49
- }));
50
- } else {
51
- if (outputSpec) {
52
- element = /*#__PURE__*/ React.createElement(OutputSpec, {
53
- ...finalProps,
54
- ref: nodeDomRef,
55
- outputSpec: outputSpec
56
- }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
57
- getPos: getPos,
58
- node: node,
59
- innerDecorations: innerDeco
60
- }));
61
- }
62
- }
63
- if (!element) {
64
- throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
65
- }
66
- const decoratedElement = /*#__PURE__*/ cloneElement(outerDeco.reduce(wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- outerDeco.some((d)=>d.type.attrs.nodeName) ? {
68
- ref: domRef
69
- } : // we've already passed the domRef to the NodeView component
70
- // as a prop
71
- undefined);
72
- const childContextValue = useMemo(()=>({
73
- parentRef: nodeViewDescRef,
74
- siblingsRef: childDescriptors
75
- }), [
76
- childDescriptors,
77
- nodeViewDescRef
78
- ]);
54
+ const { childContextValue, contentDOM, nodeDOM } = useNodeViewDescriptor(ref, ()=>{
55
+ setSelected(false);
56
+ return {
57
+ dom: innerRef.current ?? ref.current,
58
+ update () {
59
+ return true;
60
+ },
61
+ multiType: true,
62
+ selectNode () {
63
+ const selectNode = selectNodeRef.current;
64
+ if (selectNode) {
65
+ selectNode();
66
+ }
67
+ setSelected(true);
68
+ },
69
+ deselectNode () {
70
+ const deselectNode = deselectNodeRef.current;
71
+ if (deselectNode) {
72
+ deselectNode();
73
+ }
74
+ setSelected(false);
75
+ },
76
+ stopEvent (event) {
77
+ const stopEvent = stopEventRef.current;
78
+ if (stopEvent) {
79
+ return stopEvent(event);
80
+ }
81
+ return false;
82
+ },
83
+ ignoreMutation (mutation) {
84
+ const ignoreMutation = ignoreMutationRef.current;
85
+ if (ignoreMutation) {
86
+ return ignoreMutation(mutation);
87
+ }
88
+ return false;
89
+ }
90
+ };
91
+ }, nodeProps);
92
+ const children = !node.isLeaf ? /*#__PURE__*/ React.createElement(ChildNodeViews, {
93
+ getPos: getPos,
94
+ node: node,
95
+ innerDecorations: innerDeco
96
+ }) : null;
97
+ const innerProps = {
98
+ nodeProps,
99
+ ...!contentDOM && !nodeProps.node.isText && nodeDOM?.nodeName !== "BR" ? {
100
+ contentEditable: false,
101
+ suppressContentEditableWarning: true
102
+ } : null,
103
+ ...controlSelected && selected ? {
104
+ className: "ProseMirror-selectednode"
105
+ } : null,
106
+ ref: innerRef
107
+ };
108
+ const innerElement = /*#__PURE__*/ React.createElement(Component, innerProps, children);
109
+ const props = {
110
+ ...controlSelected && selected || node.type.spec.draggable ? {
111
+ draggable: true
112
+ } : null,
113
+ ref
114
+ };
115
+ const decoratedElement = /*#__PURE__*/ cloneElement(outerDeco.reduce(wrapInDeco, innerElement), props);
79
116
  return /*#__PURE__*/ React.createElement(SelectNodeContext.Provider, {
80
117
  value: setSelectNode
81
118
  }, /*#__PURE__*/ React.createElement(StopEventContext.Provider, {
@@ -32,11 +32,10 @@ export function SeparatorHackView(param) {
32
32
  }
33
33
  if (!ref.current) return;
34
34
  if (!viewDescRef.current) {
35
- viewDescRef.current = new TrailingHackViewDesc(parentRef.current, [], ()=>getPos.current(), ref.current, null);
35
+ viewDescRef.current = new TrailingHackViewDesc(parentRef.current, [], getPos, ref.current, null);
36
36
  } else {
37
37
  viewDescRef.current.parent = parentRef.current;
38
38
  viewDescRef.current.dom = ref.current;
39
- viewDescRef.current.getPos = ()=>getPos.current();
40
39
  }
41
40
  if (!siblingsRef.current.includes(viewDescRef.current)) {
42
41
  siblingsRef.current.push(viewDescRef.current);
@@ -37,8 +37,8 @@ export class TextNodeView extends Component {
37
37
  // when a composition was started that produces a new text node.
38
38
  // Otherwise we just rely on re-rendering the renderRef
39
39
  if (!dom) {
40
- if (!view?.composing) return;
41
- this.viewDescRef = new CompositionViewDesc(parentRef.current, ()=>getPos.current(), // These are just placeholders/dummies. We can't
40
+ if (!view.composing) return;
41
+ this.viewDescRef = new CompositionViewDesc(parentRef.current, getPos, // These are just placeholders/dummies. We can't
42
42
  // actually find the correct DOM nodes from here,
43
43
  // so we let our parent do it.
44
44
  // Passing a valid element here just so that the
@@ -51,12 +51,11 @@ export class TextNodeView extends Component {
51
51
  textNode = textNode.firstChild;
52
52
  }
53
53
  if (!this.viewDescRef || this.viewDescRef instanceof CompositionViewDesc) {
54
- this.viewDescRef = new TextViewDesc(undefined, [], ()=>getPos.current(), node, decorations, DecorationSet.empty, dom, textNode);
54
+ this.viewDescRef = new TextViewDesc(undefined, [], getPos, node, decorations, DecorationSet.empty, dom, textNode);
55
55
  } else {
56
56
  this.viewDescRef.parent = parentRef.current;
57
57
  this.viewDescRef.children = [];
58
58
  this.viewDescRef.node = node;
59
- this.viewDescRef.getPos = ()=>getPos.current();
60
59
  this.viewDescRef.outerDeco = decorations;
61
60
  this.viewDescRef.innerDeco = DecorationSet.empty;
62
61
  this.viewDescRef.dom = dom;
@@ -92,7 +91,7 @@ export class TextNodeView extends Component {
92
91
  // an active composition and the selection is in this node,
93
92
  // we freeze the DOM of this element so that it doesn't
94
93
  // interrupt the composition
95
- if (view?.composing && view.state.selection.from >= getPos.current() && view.state.selection.from <= getPos.current() + node.nodeSize) {
94
+ if (view.composing && view.state.selection.from >= getPos() && view.state.selection.from <= getPos() + node.nodeSize) {
96
95
  return this.renderRef;
97
96
  }
98
97
  this.renderRef = decorations.reduce(wrapInDeco, node.text);
@@ -22,11 +22,10 @@ export function TrailingHackView(param) {
22
22
  useClientLayoutEffect(()=>{
23
23
  if (!ref.current) return;
24
24
  if (!viewDescRef.current) {
25
- viewDescRef.current = new TrailingHackViewDesc(parentRef.current, [], ()=>getPos.current(), ref.current, null);
25
+ viewDescRef.current = new TrailingHackViewDesc(parentRef.current, [], getPos, ref.current, null);
26
26
  } else {
27
27
  viewDescRef.current.parent = parentRef.current;
28
28
  viewDescRef.current.dom = ref.current;
29
- viewDescRef.current.getPos = ()=>getPos.current();
30
29
  }
31
30
  if (!siblingsRef.current.includes(viewDescRef.current)) {
32
31
  siblingsRef.current.push(viewDescRef.current);
@@ -6,7 +6,6 @@ export function WidgetView(param) {
6
6
  let { widget, getPos } = param;
7
7
  const { siblingsRef, parentRef } = useContext(ChildDescriptorsContext);
8
8
  const viewDescRef = useRef(null);
9
- const getPosFunc = useRef(()=>getPos.current()).current;
10
9
  const domRef = useRef(null);
11
10
  useClientLayoutEffect(()=>{
12
11
  const siblings = siblingsRef.current;
@@ -23,11 +22,10 @@ export function WidgetView(param) {
23
22
  useClientLayoutEffect(()=>{
24
23
  if (!domRef.current) return;
25
24
  if (!viewDescRef.current) {
26
- viewDescRef.current = new WidgetViewDesc(parentRef.current, ()=>getPos.current(), widget, domRef.current);
25
+ viewDescRef.current = new WidgetViewDesc(parentRef.current, getPos, widget, domRef.current);
27
26
  } else {
28
27
  viewDescRef.current.parent = parentRef.current;
29
28
  viewDescRef.current.widget = widget;
30
- viewDescRef.current.getPos = ()=>getPos.current();
31
29
  viewDescRef.current.dom = domRef.current;
32
30
  }
33
31
  if (!siblingsRef.current.includes(viewDescRef.current)) {
@@ -39,7 +37,7 @@ export function WidgetView(param) {
39
37
  return Component && /*#__PURE__*/ React.createElement(Component, {
40
38
  ref: domRef,
41
39
  widget: widget,
42
- getPos: getPosFunc,
40
+ getPos: getPos,
43
41
  contentEditable: false
44
42
  });
45
43
  }
@@ -0,0 +1,15 @@
1
+ import { Schema } from "prosemirror-model";
2
+ import { EditorState } from "prosemirror-state";
3
+ export const EMPTY_SCHEMA = new Schema({
4
+ nodes: {
5
+ doc: {
6
+ content: "text*"
7
+ },
8
+ text: {
9
+ inline: true
10
+ }
11
+ }
12
+ });
13
+ export const EMPTY_STATE = EditorState.create({
14
+ schema: EMPTY_SCHEMA
15
+ });