@handlewithcare/react-prosemirror 2.1.0 → 2.2.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 (34) hide show
  1. package/README.md +22 -3
  2. package/dist/cjs/components/CustomNodeView.js +80 -4
  3. package/dist/cjs/components/NodeView.js +13 -133
  4. package/dist/cjs/components/OutputSpec.js +1 -1
  5. package/dist/cjs/components/ReactNodeView.js +136 -0
  6. package/dist/cjs/components/TextNodeView.js +2 -2
  7. package/dist/cjs/findDOMNode.js +46 -0
  8. package/dist/cjs/hooks/useEditor.js +14 -3
  9. package/dist/cjs/hooks/useEditorEffect.js +5 -2
  10. package/dist/cjs/hooks/useIsNodeSelected.js +21 -0
  11. package/dist/cjs/index.js +4 -0
  12. package/dist/cjs/plugins/componentEventListeners.js +1 -1
  13. package/dist/cjs/plugins/reactKeys.js +1 -1
  14. package/dist/esm/components/CustomNodeView.js +82 -6
  15. package/dist/esm/components/NodeView.js +14 -134
  16. package/dist/esm/components/OutputSpec.js +1 -1
  17. package/dist/esm/components/ReactNodeView.js +85 -0
  18. package/dist/esm/components/TextNodeView.js +1 -1
  19. package/dist/esm/findDOMNode.js +31 -0
  20. package/dist/esm/hooks/useEditor.js +14 -3
  21. package/dist/esm/hooks/useEditorEffect.js +5 -2
  22. package/dist/esm/hooks/useIsNodeSelected.js +11 -0
  23. package/dist/esm/index.js +1 -0
  24. package/dist/esm/plugins/componentEventListeners.js +1 -1
  25. package/dist/esm/plugins/reactKeys.js +1 -1
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/dist/types/components/CustomNodeView.d.ts +3 -12
  28. package/dist/types/components/ReactNodeView.d.ts +11 -0
  29. package/dist/types/contexts/EditorContext.d.ts +2 -0
  30. package/dist/types/findDOMNode.d.ts +3 -0
  31. package/dist/types/hooks/useEditor.d.ts +1 -0
  32. package/dist/types/hooks/useIsNodeSelected.d.ts +1 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/package.json +17 -4
@@ -1,12 +1,79 @@
1
- import React, { createElement, useContext } from "react";
1
+ import React, { cloneElement, createElement, memo, useContext, useLayoutEffect, useMemo, useRef } from "react";
2
2
  import { createPortal } from "react-dom";
3
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
4
  import { EditorContext } from "../contexts/EditorContext.js";
4
5
  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;
6
+ import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
7
+ import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
8
+ export const CustomNodeView = /*#__PURE__*/ memo(function CustomNodeView(param) {
9
+ let { customNodeView, node, getPos, innerDeco, outerDeco } = param;
8
10
  const { view } = useContext(EditorContext);
11
+ const domRef = useRef(null);
12
+ const nodeDomRef = useRef(null);
13
+ const contentDomRef = useRef(null);
14
+ const getPosFunc = useRef(()=>getPos.current()).current;
15
+ // this is ill-conceived; should revisit
16
+ const initialNode = useRef(node);
17
+ const initialOuterDeco = useRef(outerDeco);
18
+ const initialInnerDeco = useRef(innerDeco);
19
+ const customNodeViewRootRef = useRef(null);
20
+ const customNodeViewRef = useRef(null);
9
21
  const shouldRender = useClientOnly();
22
+ useLayoutEffect(()=>{
23
+ if (!customNodeViewRef.current || !customNodeViewRootRef.current || !shouldRender) return;
24
+ const { dom } = customNodeViewRef.current;
25
+ nodeDomRef.current = customNodeViewRootRef.current;
26
+ customNodeViewRootRef.current.appendChild(dom);
27
+ return ()=>{
28
+ customNodeViewRef.current?.destroy?.();
29
+ };
30
+ }, [
31
+ customNodeViewRef,
32
+ customNodeViewRootRef,
33
+ nodeDomRef,
34
+ shouldRender
35
+ ]);
36
+ useLayoutEffect(()=>{
37
+ if (!customNodeView || !customNodeViewRef.current || !shouldRender) return;
38
+ const { destroy, update } = customNodeViewRef.current;
39
+ const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
40
+ if (updated) return;
41
+ destroy?.call(customNodeViewRef.current);
42
+ if (!customNodeViewRootRef.current) return;
43
+ initialNode.current = node;
44
+ initialOuterDeco.current = outerDeco;
45
+ initialInnerDeco.current = innerDeco;
46
+ customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
47
+ // this line if customNodeView is set
48
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
49
+ view, getPosFunc, initialOuterDeco.current, initialInnerDeco.current);
50
+ const { dom } = customNodeViewRef.current;
51
+ nodeDomRef.current = customNodeViewRootRef.current;
52
+ customNodeViewRootRef.current.appendChild(dom);
53
+ }, [
54
+ customNodeView,
55
+ view,
56
+ innerDeco,
57
+ node,
58
+ outerDeco,
59
+ getPos,
60
+ customNodeViewRef,
61
+ customNodeViewRootRef,
62
+ initialNode,
63
+ initialOuterDeco,
64
+ initialInnerDeco,
65
+ nodeDomRef,
66
+ shouldRender,
67
+ getPosFunc
68
+ ]);
69
+ const { childDescriptors, nodeViewDescRef } = useNodeViewDescriptor(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
70
+ const childContextValue = useMemo(()=>({
71
+ parentRef: nodeViewDescRef,
72
+ siblingsRef: childDescriptors
73
+ }), [
74
+ childDescriptors,
75
+ nodeViewDescRef
76
+ ]);
10
77
  if (!shouldRender) return null;
11
78
  if (!customNodeViewRef.current) {
12
79
  customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
@@ -16,7 +83,7 @@ export function CustomNodeView(param) {
16
83
  }
17
84
  const { contentDOM } = customNodeViewRef.current;
18
85
  contentDomRef.current = contentDOM ?? null;
19
- return /*#__PURE__*/ createElement(node.isInline ? "span" : "div", {
86
+ const element = /*#__PURE__*/ createElement(node.isInline ? "span" : "div", {
20
87
  ref: customNodeViewRootRef,
21
88
  contentEditable: !!contentDOM,
22
89
  suppressContentEditableWarning: true
@@ -25,4 +92,13 @@ export function CustomNodeView(param) {
25
92
  node: node,
26
93
  innerDecorations: innerDeco
27
94
  }), contentDOM));
28
- }
95
+ const decoratedElement = /*#__PURE__*/ cloneElement(outerDeco.reduce(wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ outerDeco.some((d)=>d.type.attrs.nodeName) ? {
97
+ ref: domRef
98
+ } : // we've already passed the domRef to the NodeView component
99
+ // as a prop
100
+ undefined);
101
+ return /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
102
+ value: childContextValue
103
+ }, decoratedElement);
104
+ });
@@ -1,145 +1,25 @@
1
- import React, { cloneElement, memo, useContext, useLayoutEffect, useMemo, useRef } from "react";
2
- import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
1
+ import React, { memo, useContext } from "react";
3
2
  import { EditorContext } from "../contexts/EditorContext.js";
4
- import { NodeViewContext } from "../contexts/NodeViewContext.js";
5
- import { SelectNodeContext } from "../contexts/SelectNodeContext.js";
6
- import { StopEventContext } from "../contexts/StopEventContext.js";
7
- import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
8
- import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
9
3
  import { CustomNodeView } from "./CustomNodeView.js";
10
- import { OutputSpec } from "./OutputSpec.js";
4
+ import { ReactNodeView } from "./ReactNodeView.js";
11
5
  export const NodeView = /*#__PURE__*/ memo(function NodeView(param) {
12
6
  let { outerDeco, getPos, node, innerDeco, ...props } = param;
13
- const domRef = useRef(null);
14
- const nodeDomRef = useRef(null);
15
- const contentDomRef = useRef(null);
16
- const getPosFunc = useRef(()=>getPos.current()).current;
17
- // this is ill-conceived; should revisit
18
- const initialNode = useRef(node);
19
- const initialOuterDeco = useRef(outerDeco);
20
- const initialInnerDeco = useRef(innerDeco);
21
- const customNodeViewRootRef = useRef(null);
22
- const customNodeViewRef = useRef(null);
23
- // const state = useEditorState();
24
- const { nodeViews } = useContext(NodeViewContext);
25
7
  const { view } = useContext(EditorContext);
26
- let element = null;
27
- const Component = nodeViews[node.type.name];
28
- const outputSpec = useMemo(()=>node.type.spec.toDOM?.(node), [
29
- node
30
- ]);
31
- // TODO: Would be great to pull all of the custom node view stuff into
32
- // a hook
33
8
  const customNodeView = view?.someProp("nodeViews", (nodeViews)=>nodeViews?.[node.type.name]);
34
- useLayoutEffect(()=>{
35
- if (!customNodeViewRef.current || !customNodeViewRootRef.current) return;
36
- const { dom } = customNodeViewRef.current;
37
- nodeDomRef.current = customNodeViewRootRef.current;
38
- customNodeViewRootRef.current.appendChild(dom);
39
- return ()=>{
40
- customNodeViewRef.current?.destroy?.();
41
- };
42
- }, []);
43
- useLayoutEffect(()=>{
44
- if (!customNodeView || !customNodeViewRef.current) return;
45
- const { destroy, update } = customNodeViewRef.current;
46
- const updated = update?.call(customNodeViewRef.current, node, outerDeco, innerDeco) ?? true;
47
- if (updated) return;
48
- destroy?.call(customNodeViewRef.current);
49
- if (!customNodeViewRootRef.current) return;
50
- initialNode.current = node;
51
- initialOuterDeco.current = outerDeco;
52
- initialInnerDeco.current = innerDeco;
53
- customNodeViewRef.current = customNodeView(initialNode.current, // customNodeView will only be set if view is set, and we can only reach
54
- // this line if customNodeView is set
55
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
56
- view, ()=>getPos.current(), initialOuterDeco.current, initialInnerDeco.current);
57
- const { dom } = customNodeViewRef.current;
58
- nodeDomRef.current = customNodeViewRootRef.current;
59
- customNodeViewRootRef.current.appendChild(dom);
60
- }, [
61
- customNodeView,
62
- view,
63
- innerDeco,
64
- node,
65
- outerDeco,
66
- getPos
67
- ]);
68
- const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, nodeViewDescRef } = useNodeViewDescriptor(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
69
- const finalProps = {
70
- ...props,
71
- ...!hasContentDOM && {
72
- contentEditable: false
73
- }
74
- };
75
- const nodeProps = useMemo(()=>({
76
- node: node,
77
- getPos: getPosFunc,
78
- decorations: outerDeco,
79
- innerDecorations: innerDeco
80
- }), [
81
- getPosFunc,
82
- innerDeco,
83
- node,
84
- outerDeco
85
- ]);
86
- if (Component) {
87
- element = /*#__PURE__*/ React.createElement(Component, {
88
- ...finalProps,
89
- ref: nodeDomRef,
90
- nodeProps: nodeProps
91
- }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
92
- getPos: getPos,
93
- node: node,
94
- innerDecorations: innerDeco
95
- }));
96
- } else if (customNodeView) {
97
- element = /*#__PURE__*/ React.createElement(CustomNodeView, {
98
- contentDomRef: contentDomRef,
9
+ if (customNodeView) {
10
+ return /*#__PURE__*/ React.createElement(CustomNodeView, {
99
11
  customNodeView: customNodeView,
100
- customNodeViewRef: customNodeViewRef,
101
- customNodeViewRootRef: customNodeViewRootRef,
102
- initialInnerDeco: initialInnerDeco,
103
- initialNode: initialNode,
104
- initialOuterDeco: initialOuterDeco,
105
12
  node: node,
106
- getPos: getPos,
107
- innerDeco: innerDeco
13
+ innerDeco: innerDeco,
14
+ outerDeco: outerDeco,
15
+ getPos: getPos
108
16
  });
109
- } else {
110
- if (outputSpec) {
111
- element = /*#__PURE__*/ React.createElement(OutputSpec, {
112
- ...finalProps,
113
- ref: nodeDomRef,
114
- outputSpec: outputSpec
115
- }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
116
- getPos: getPos,
117
- node: node,
118
- innerDecorations: innerDeco
119
- }));
120
- }
121
- }
122
- if (!element) {
123
- throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
124
17
  }
125
- const decoratedElement = /*#__PURE__*/ cloneElement(outerDeco.reduce(wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
126
- outerDeco.some((d)=>d.type.attrs.nodeName) ? {
127
- ref: domRef
128
- } : // we've already passed the domRef to the NodeView component
129
- // as a prop
130
- undefined);
131
- const childContextValue = useMemo(()=>({
132
- parentRef: nodeViewDescRef,
133
- siblingsRef: childDescriptors
134
- }), [
135
- childDescriptors,
136
- nodeViewDescRef
137
- ]);
138
- return /*#__PURE__*/ React.createElement(SelectNodeContext.Provider, {
139
- value: setSelectNode
140
- }, /*#__PURE__*/ React.createElement(StopEventContext.Provider, {
141
- value: setStopEvent
142
- }, /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
143
- value: childContextValue
144
- }, decoratedElement)));
18
+ return /*#__PURE__*/ React.createElement(ReactNodeView, {
19
+ node: node,
20
+ innerDeco: innerDeco,
21
+ outerDeco: outerDeco,
22
+ getPos: getPos,
23
+ ...props
24
+ });
145
25
  });
@@ -6,7 +6,7 @@ const ForwardedOutputSpec = /*#__PURE__*/ memo(/*#__PURE__*/ forwardRef(function
6
6
  return /*#__PURE__*/ React.createElement(React.Fragment, null, outputSpec);
7
7
  }
8
8
  if (!Array.isArray(outputSpec)) {
9
- throw new Error("@nytimes/react-prosemirror only supports strings and arrays in toDOM");
9
+ throw new Error("@handlewithcare/react-prosemirror only supports strings and arrays in toDOM");
10
10
  }
11
11
  const tagSpec = outputSpec[0];
12
12
  const tagName = tagSpec.replace(" ", ":");
@@ -0,0 +1,85 @@
1
+ import React, { cloneElement, memo, useContext, useMemo, useRef } from "react";
2
+ import { ChildDescriptorsContext } from "../contexts/ChildDescriptorsContext.js";
3
+ import { NodeViewContext } from "../contexts/NodeViewContext.js";
4
+ import { SelectNodeContext } from "../contexts/SelectNodeContext.js";
5
+ import { StopEventContext } from "../contexts/StopEventContext.js";
6
+ import { useNodeViewDescriptor } from "../hooks/useNodeViewDescriptor.js";
7
+ import { ChildNodeViews, wrapInDeco } from "./ChildNodeViews.js";
8
+ import { OutputSpec } from "./OutputSpec.js";
9
+ export const ReactNodeView = /*#__PURE__*/ memo(function ReactNodeView(param) {
10
+ let { outerDeco, getPos, node, innerDeco, ...props } = param;
11
+ const domRef = useRef(null);
12
+ const nodeDomRef = useRef(null);
13
+ const contentDomRef = useRef(null);
14
+ const getPosFunc = useRef(()=>getPos.current()).current;
15
+ const { nodeViews } = useContext(NodeViewContext);
16
+ let element = null;
17
+ const Component = nodeViews[node.type.name];
18
+ const outputSpec = useMemo(()=>node.type.spec.toDOM?.(node), [
19
+ node
20
+ ]);
21
+ const { hasContentDOM, childDescriptors, setStopEvent, setSelectNode, nodeViewDescRef } = useNodeViewDescriptor(node, ()=>getPos.current(), domRef, nodeDomRef, innerDeco, outerDeco, undefined, contentDomRef);
22
+ const finalProps = {
23
+ ...props,
24
+ ...!hasContentDOM && {
25
+ contentEditable: false
26
+ }
27
+ };
28
+ const nodeProps = useMemo(()=>({
29
+ node: node,
30
+ getPos: getPosFunc,
31
+ decorations: outerDeco,
32
+ innerDecorations: innerDeco
33
+ }), [
34
+ getPosFunc,
35
+ innerDeco,
36
+ node,
37
+ outerDeco
38
+ ]);
39
+ if (Component) {
40
+ element = /*#__PURE__*/ React.createElement(Component, {
41
+ ...finalProps,
42
+ ref: nodeDomRef,
43
+ nodeProps: nodeProps
44
+ }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
45
+ getPos: getPos,
46
+ node: node,
47
+ innerDecorations: innerDeco
48
+ }));
49
+ } else {
50
+ if (outputSpec) {
51
+ element = /*#__PURE__*/ React.createElement(OutputSpec, {
52
+ ...finalProps,
53
+ ref: nodeDomRef,
54
+ outputSpec: outputSpec
55
+ }, /*#__PURE__*/ React.createElement(ChildNodeViews, {
56
+ getPos: getPos,
57
+ node: node,
58
+ innerDecorations: innerDeco
59
+ }));
60
+ }
61
+ }
62
+ if (!element) {
63
+ throw new Error(`Node spec for ${node.type.name} is missing toDOM`);
64
+ }
65
+ const decoratedElement = /*#__PURE__*/ cloneElement(outerDeco.reduce(wrapInDeco, element), // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ outerDeco.some((d)=>d.type.attrs.nodeName) ? {
67
+ ref: domRef
68
+ } : // we've already passed the domRef to the NodeView component
69
+ // as a prop
70
+ undefined);
71
+ const childContextValue = useMemo(()=>({
72
+ parentRef: nodeViewDescRef,
73
+ siblingsRef: childDescriptors
74
+ }), [
75
+ childDescriptors,
76
+ nodeViewDescRef
77
+ ]);
78
+ return /*#__PURE__*/ React.createElement(SelectNodeContext.Provider, {
79
+ value: setSelectNode
80
+ }, /*#__PURE__*/ React.createElement(StopEventContext.Provider, {
81
+ value: setStopEvent
82
+ }, /*#__PURE__*/ React.createElement(ChildDescriptorsContext.Provider, {
83
+ value: childContextValue
84
+ }, decoratedElement)));
85
+ });
@@ -1,6 +1,6 @@
1
1
  import { DecorationSet } from "prosemirror-view";
2
2
  import { Component } from "react";
3
- import { findDOMNode } from "react-dom";
3
+ import { findDOMNode } from "../findDOMNode.js";
4
4
  import { CompositionViewDesc, TextViewDesc, sortViewDescs } from "../viewdesc.js";
5
5
  import { wrapInDeco } from "./ChildNodeViews.js";
6
6
  function shallowEqual(objA, objB) {
@@ -0,0 +1,31 @@
1
+ //@ts-expect-error This module isn't typed
2
+ import { findCurrentHostFiber } from "react-reconciler/reflection";
3
+ // https://github.com/facebook/react/blob/main/packages/shared/ReactInstanceMap.js#L18
4
+ export function getInstance(key) {
5
+ return key._reactInternals;
6
+ }
7
+ // https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js#L322
8
+ function getPublicInstance(instance) {
9
+ return instance;
10
+ }
11
+ // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberReconciler.js#L153
12
+ function findHostInstance(component) {
13
+ const fiber = getInstance(component);
14
+ if (fiber === undefined) {
15
+ if (typeof component.render === "function") {
16
+ throw new Error("Unable to find node on an unmounted component.");
17
+ } else {
18
+ const keys = Object.keys(component).join(",");
19
+ throw new Error(`Argument appears to not be a ReactComponent. Keys: ${keys}`);
20
+ }
21
+ }
22
+ const hostFiber = findCurrentHostFiber(fiber);
23
+ if (hostFiber === null) {
24
+ return null;
25
+ }
26
+ return getPublicInstance(hostFiber.stateNode);
27
+ }
28
+ // https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOMClient.js#L43
29
+ export function findDOMNode(componentOrElement) {
30
+ return findHostInstance(componentOrElement);
31
+ }
@@ -171,6 +171,7 @@ let didWarnValueDefaultValue = false;
171
171
  didWarnValueDefaultValue = true;
172
172
  }
173
173
  }
174
+ const flushSyncRef = useRef(true);
174
175
  const [cursorWrapper, _setCursorWrapper] = useState(null);
175
176
  const forceUpdate = useForceUpdate();
176
177
  const defaultState = options.defaultState ?? EMPTY_STATE;
@@ -192,14 +193,23 @@ let didWarnValueDefaultValue = false;
192
193
  setCursorWrapper
193
194
  ]);
194
195
  const dispatchTransaction = useCallback(function dispatchTransaction(tr) {
195
- flushSync(()=>{
196
+ if (flushSyncRef.current) {
197
+ flushSync(()=>{
198
+ if (!options.state) {
199
+ setState((s)=>s.apply(tr));
200
+ }
201
+ if (options.dispatchTransaction) {
202
+ options.dispatchTransaction.call(this, tr);
203
+ }
204
+ });
205
+ } else {
196
206
  if (!options.state) {
197
207
  setState((s)=>s.apply(tr));
198
208
  }
199
209
  if (options.dispatchTransaction) {
200
210
  options.dispatchTransaction.call(this, tr);
201
211
  }
202
- });
212
+ }
203
213
  }, [
204
214
  options.dispatchTransaction,
205
215
  options.state
@@ -264,7 +274,8 @@ let didWarnValueDefaultValue = false;
264
274
  registerEventListener,
265
275
  unregisterEventListener,
266
276
  cursorWrapper,
267
- docViewDescRef
277
+ docViewDescRef,
278
+ flushSyncRef
268
279
  }), [
269
280
  view,
270
281
  registerEventListener,
@@ -15,7 +15,7 @@ import { useLayoutGroupEffect } from "./useLayoutGroupEffect.js";
15
15
  * _after_ the EditorView has been updated, even when the
16
16
  * EditorView lives in an ancestor component.
17
17
  */ export function useEditorEffect(effect, dependencies) {
18
- const { view } = useContext(EditorContext);
18
+ const { view, flushSyncRef } = useContext(EditorContext);
19
19
  // The rules of hooks want `effect` to be included in the
20
20
  // dependency list, but dependency issues for `effect` will
21
21
  // be caught by the linter at the call-site for
@@ -25,7 +25,10 @@ import { useLayoutGroupEffect } from "./useLayoutGroupEffect.js";
25
25
  // be defined inline and run on every re-render.
26
26
  useLayoutGroupEffect(()=>{
27
27
  if (view) {
28
- return effect(view);
28
+ flushSyncRef.current = false;
29
+ const result = effect(view);
30
+ flushSyncRef.current = true;
31
+ return result;
29
32
  }
30
33
  }, // The rules of hooks want to be able to statically
31
34
  // verify the dependencies for the effect, but this will
@@ -0,0 +1,11 @@
1
+ import { useState } from "react";
2
+ import { useSelectNode } from "./useSelectNode.js";
3
+ export function useIsNodeSelected() {
4
+ const [isSelected, setIsSelected] = useState(false);
5
+ useSelectNode(()=>{
6
+ setIsSelected(true);
7
+ }, ()=>{
8
+ setIsSelected(false);
9
+ });
10
+ return isSelected;
11
+ }
package/dist/esm/index.js CHANGED
@@ -7,5 +7,6 @@ export { useEditorEventListener } from "./hooks/useEditorEventListener.js";
7
7
  export { useEditorState } from "./hooks/useEditorState.js";
8
8
  export { useStopEvent } from "./hooks/useStopEvent.js";
9
9
  export { useSelectNode } from "./hooks/useSelectNode.js";
10
+ export { useIsNodeSelected } from "./hooks/useIsNodeSelected.js";
10
11
  export { reactKeys } from "./plugins/reactKeys.js";
11
12
  export { widget } from "./decorations/ReactWidgetType.js";
@@ -16,7 +16,7 @@ export function componentEventListeners(eventHandlerRegistry) {
16
16
  domEventHandlers[eventType] = handleEvent;
17
17
  }
18
18
  const plugin = new Plugin({
19
- key: new PluginKey("@nytimes/react-prosemirror/componentEventListeners"),
19
+ key: new PluginKey("@handlewithcare/react-prosemirror/componentEventListeners"),
20
20
  props: {
21
21
  handleDOMEvents: domEventHandlers
22
22
  }
@@ -3,7 +3,7 @@ export function createNodeKey() {
3
3
  const key = Math.floor(Math.random() * 0xffffffffffff).toString(16);
4
4
  return key;
5
5
  }
6
- export const reactKeysPluginKey = new PluginKey("@nytimes/react-prosemirror/reactKeys");
6
+ export const reactKeysPluginKey = new PluginKey("@handlewithcare/react-prosemirror/reactKeys");
7
7
  /**
8
8
  * Tracks a unique key for each (non-text) node in the
9
9
  * document, identified by its current position. Keys are