@neo4j-nvl/react 0.3.1-6201a90a → 0.3.1-6fbcfb2a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -82,4 +82,4 @@ const [multiSelect, setMultiSelect] = useState(false)
82
82
  ```
83
83
 
84
84
 
85
- You can also find more instructions and examples on how to use NVL in the docs.
85
+ You can also find more instructions and examples on how to use the NVL React wrappers in the [docs](https://neo4j.com/docs/nvl/current/react-wrappers/).
@@ -22,8 +22,6 @@ export interface BasicReactWrapperProps {
22
22
  nvlOptions?: NvlOptions;
23
23
  /** A callback to handle any errors that happen during NVL initialization */
24
24
  onInitializationError?: (error: unknown) => void;
25
- /** Any events that should be passed to the NVL instance */
26
- nvlEvents?: Record<string, (event: unknown) => void>;
27
25
  }
28
26
  /**
29
27
  * A basic React wrapper for the {@link NVL} class.
@@ -50,25 +48,31 @@ export interface BasicReactWrapperProps {
50
48
  * When nodes and/or relationships are updated in the React wrapper, the NVL instance will be updated accordingly:
51
49
  *
52
50
  * ```tsx
53
- * const [nodes, setNodes] = useState<Node[]>([{ id: '0' }, { id: '1' }])
51
+ * const NvlComponent = () => {
52
+ * const [nodes, setNodes] = useState<Node[]>([{ id: '0' }, { id: '1' }])
54
53
  *
55
- * const addElements = () => {
56
- * const newNodes = [...nodes, { id: nodes.length }]
54
+ * const addElements = () => {
55
+ * const newNodes = [...nodes, { id: nodes.length.toString() }]
57
56
  * setNodes(newNodes)
58
57
  * }
59
58
  *
60
- * <div>
61
- * <BasicNvlWrapper nodes={nodes} />
59
+ * return <div>
60
+ * <BasicNvlWrapper nodes={nodes} rels={[]} />
62
61
  * <button onClick={addElements}>Add Graph Elements</button>
63
62
  * </div>
63
+ * }
64
64
  * ```
65
65
  *
66
66
  * would be equivalent to
67
67
  *
68
68
  * ```tsx
69
+ * const container = document.createElement('div')
70
+ * const myButton = document.createElement('button')
71
+ * const nodes = [{ id: '0' }, { id: '1' }]
69
72
  * const myNvl = new NVL(container, nodes, [])
70
73
  * myButton.addEventListener('click', () => {
71
- * myNvl.addAndUpdateElementsInGraph(newNodes, [])
74
+ * const newNodes = [...nodes, { id: nodes.length.toString() }]
75
+ * myNvl.addAndUpdateElementsInGraph(newNodes, [])
72
76
  * })
73
77
  * ```
74
78
  *
@@ -76,16 +80,18 @@ export interface BasicReactWrapperProps {
76
80
  * If you want to access the NVL class outside of the React wrapper you can use a
77
81
  * reference of NVL to call its methods:
78
82
  * ```tsx
79
- * const nvlRef = useRef<NVL>()
80
- *
81
- * <div>
82
- * <BasicNvlWrapper
83
- * nodes={[{ id: '0' }, { id: '1' }]}
84
- * rels={[{ from: '0', to: '1', id: '10' }]}
85
- * ref={nvlRef}
86
- * />
87
- * <button onClick={() => nvlRef.current?.zoomToNodes([0, 1])}>Zoom to Nodes</button>
88
- * </div>
83
+ * const NvlComponent = () => {
84
+ * const nvlRef = useRef<NVL>()
85
+ *
86
+ * return <div>
87
+ * <BasicNvlWrapper
88
+ * nodes={[{ id: '0' }, { id: '1' }]}
89
+ * rels={[{ from: '0', to: '1', id: '10' }]}
90
+ * ref={nvlRef}
91
+ * />
92
+ * <button onClick={() => nvlRef.current?.fit([0, 1])}>Zoom to Nodes</button>
93
+ * </div>
94
+ * }
89
95
  * ```
90
96
  *
91
97
  * @example
@@ -102,7 +108,9 @@ export interface BasicReactWrapperProps {
102
108
  * would be equivalent to
103
109
  *
104
110
  * ```tsx
105
- * const myNvl = new NVL(container, nodes, relationships)
111
+ * const container = document.createElement('div')
112
+ * const nodes = [{ id: '0' }, { id: '1' }]
113
+ * const myNvl = new NVL(container, nodes, [])
106
114
  * container.addEventListener('click', (event) => console.log(event))
107
115
  * ```
108
116
  *
@@ -28,25 +28,31 @@ import { useDeepCompareEffect } from '../utils/hooks';
28
28
  * When nodes and/or relationships are updated in the React wrapper, the NVL instance will be updated accordingly:
29
29
  *
30
30
  * ```tsx
31
- * const [nodes, setNodes] = useState<Node[]>([{ id: '0' }, { id: '1' }])
31
+ * const NvlComponent = () => {
32
+ * const [nodes, setNodes] = useState<Node[]>([{ id: '0' }, { id: '1' }])
32
33
  *
33
- * const addElements = () => {
34
- * const newNodes = [...nodes, { id: nodes.length }]
34
+ * const addElements = () => {
35
+ * const newNodes = [...nodes, { id: nodes.length.toString() }]
35
36
  * setNodes(newNodes)
36
37
  * }
37
38
  *
38
- * <div>
39
- * <BasicNvlWrapper nodes={nodes} />
39
+ * return <div>
40
+ * <BasicNvlWrapper nodes={nodes} rels={[]} />
40
41
  * <button onClick={addElements}>Add Graph Elements</button>
41
42
  * </div>
43
+ * }
42
44
  * ```
43
45
  *
44
46
  * would be equivalent to
45
47
  *
46
48
  * ```tsx
49
+ * const container = document.createElement('div')
50
+ * const myButton = document.createElement('button')
51
+ * const nodes = [{ id: '0' }, { id: '1' }]
47
52
  * const myNvl = new NVL(container, nodes, [])
48
53
  * myButton.addEventListener('click', () => {
49
- * myNvl.addAndUpdateElementsInGraph(newNodes, [])
54
+ * const newNodes = [...nodes, { id: nodes.length.toString() }]
55
+ * myNvl.addAndUpdateElementsInGraph(newNodes, [])
50
56
  * })
51
57
  * ```
52
58
  *
@@ -54,16 +60,18 @@ import { useDeepCompareEffect } from '../utils/hooks';
54
60
  * If you want to access the NVL class outside of the React wrapper you can use a
55
61
  * reference of NVL to call its methods:
56
62
  * ```tsx
57
- * const nvlRef = useRef<NVL>()
58
- *
59
- * <div>
60
- * <BasicNvlWrapper
61
- * nodes={[{ id: '0' }, { id: '1' }]}
62
- * rels={[{ from: '0', to: '1', id: '10' }]}
63
- * ref={nvlRef}
64
- * />
65
- * <button onClick={() => nvlRef.current?.zoomToNodes([0, 1])}>Zoom to Nodes</button>
66
- * </div>
63
+ * const NvlComponent = () => {
64
+ * const nvlRef = useRef<NVL>()
65
+ *
66
+ * return <div>
67
+ * <BasicNvlWrapper
68
+ * nodes={[{ id: '0' }, { id: '1' }]}
69
+ * rels={[{ from: '0', to: '1', id: '10' }]}
70
+ * ref={nvlRef}
71
+ * />
72
+ * <button onClick={() => nvlRef.current?.fit([0, 1])}>Zoom to Nodes</button>
73
+ * </div>
74
+ * }
67
75
  * ```
68
76
  *
69
77
  * @example
@@ -80,7 +88,9 @@ import { useDeepCompareEffect } from '../utils/hooks';
80
88
  * would be equivalent to
81
89
  *
82
90
  * ```tsx
83
- * const myNvl = new NVL(container, nodes, relationships)
91
+ * const container = document.createElement('div')
92
+ * const nodes = [{ id: '0' }, { id: '1' }]
93
+ * const myNvl = new NVL(container, nodes, [])
84
94
  * container.addEventListener('click', (event) => console.log(event))
85
95
  * ```
86
96
  *
@@ -94,9 +104,13 @@ export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOpt
94
104
  const nvlMethods = Object.getOwnPropertyNames(NVL.prototype);
95
105
  return nvlMethods.reduce((current, method) => ({
96
106
  ...current,
97
- [method]: (...args) =>
98
- // @ts-ignore suppress the type casting error on spreading
99
- nvlRef.current !== null && nvlRef.current[method](...args)
107
+ [method]: (...args) => {
108
+ if (nvlRef.current === null) {
109
+ return null;
110
+ }
111
+ // @ts-ignore suppress the type casting error on spreading
112
+ return nvlRef.current[method](...args);
113
+ }
100
114
  }),
101
115
  // eslint-disable-next-line max-len
102
116
  // eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter, @typescript-eslint/consistent-type-assertions
@@ -1,4 +1,5 @@
1
1
  import type NVL from '@neo4j-nvl/base';
2
+ import type { HTMLProps } from 'react';
2
3
  import React from 'react';
3
4
  import type { InteractiveNvlWrapperProps } from './types';
4
5
  /**
@@ -13,21 +14,23 @@ import type { InteractiveNvlWrapperProps } from './types';
13
14
  *
14
15
  * @example
15
16
  * ```tsx
16
- * const [multiSelect, setMultiSelect] = useState(false)
17
- * <>
18
- * <button onClick={() => setMultiSelect(!multiSelect)}>
19
- * {multiSelect ? 'Disable' : 'Enable'} multi-select
20
- * </button>
21
- * <InteractiveNvlWrapper
22
- * nodes={nodes}
23
- * rels={relationships}
24
- * mouseEventCallbacks={{
25
- * onHover: (element) => console.log(element),
26
- * onNodeClick: (node) => console.log(node),
27
- * onMultiSelect: multiSelect
28
- * }}
29
- * />
30
- * </>
17
+ * const InteractiveNvlComponent = () => {
18
+ * const [boxSelect, setBoxSelect] = useState(false)
19
+ * return <>
20
+ * <button onClick={() => setBoxSelect(!boxSelect)}>
21
+ * {boxSelect ? 'Disable' : 'Enable'} box-select
22
+ * </button>
23
+ * <InteractiveNvlWrapper
24
+ * nodes={nodes}
25
+ * rels={relationships}
26
+ * mouseEventCallbacks={{
27
+ * onHover: (element) => console.log(element),
28
+ * onNodeClick: (node) => console.log(node),
29
+ * onBoxSelect: boxSelect
30
+ * }}
31
+ * />
32
+ * </>
33
+ * }
31
34
  * ```
32
35
  */
33
- export declare const InteractiveNvlWrapper: React.MemoExoticComponent<React.ForwardRefExoticComponent<InteractiveNvlWrapperProps & React.RefAttributes<NVL>>>;
36
+ export declare const InteractiveNvlWrapper: React.MemoExoticComponent<React.ForwardRefExoticComponent<Omit<InteractiveNvlWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & React.RefAttributes<NVL>>>;
@@ -21,24 +21,26 @@ const options = {
21
21
  *
22
22
  * @example
23
23
  * ```tsx
24
- * const [multiSelect, setMultiSelect] = useState(false)
25
- * <>
26
- * <button onClick={() => setMultiSelect(!multiSelect)}>
27
- * {multiSelect ? 'Disable' : 'Enable'} multi-select
28
- * </button>
29
- * <InteractiveNvlWrapper
30
- * nodes={nodes}
31
- * rels={relationships}
32
- * mouseEventCallbacks={{
33
- * onHover: (element) => console.log(element),
34
- * onNodeClick: (node) => console.log(node),
35
- * onMultiSelect: multiSelect
36
- * }}
37
- * />
38
- * </>
24
+ * const InteractiveNvlComponent = () => {
25
+ * const [boxSelect, setBoxSelect] = useState(false)
26
+ * return <>
27
+ * <button onClick={() => setBoxSelect(!boxSelect)}>
28
+ * {boxSelect ? 'Disable' : 'Enable'} box-select
29
+ * </button>
30
+ * <InteractiveNvlWrapper
31
+ * nodes={nodes}
32
+ * rels={relationships}
33
+ * mouseEventCallbacks={{
34
+ * onHover: (element) => console.log(element),
35
+ * onNodeClick: (node) => console.log(node),
36
+ * onBoxSelect: boxSelect
37
+ * }}
38
+ * />
39
+ * </>
40
+ * }
39
41
  * ```
40
42
  */
41
- export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOptions, mouseEventCallbacks = {}, nvlCallbacks = {}, nvlOptions = {}, interactionOptions = options }, nvlRef) => {
43
+ export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOptions, mouseEventCallbacks = {}, nvlCallbacks = {}, nvlOptions = {}, interactionOptions = options, onInitializationError = null, ...nvlEvents }, nvlRef) => {
42
44
  const newNvlRef = useRef(null);
43
45
  const myNvlRef = nvlRef ?? newNvlRef;
44
46
  const { onHover, onNodeClick, onNodeDoubleClick, onNodeRightClick, onRelationshipClick, onRelationshipDoubleClick, onRelationshipRightClick, onCanvasClick, onCanvasRightClick, onPan, onZoom, onDrag, onDragStart, onDragEnd, onDrawEnd, onHoverNodeMargin, onBoxStarted, onBoxSelect, onLassoStarted, onLassoSelect } = mouseEventCallbacks;
@@ -80,5 +82,5 @@ export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, lay
80
82
  destroyInteraction(multiSelectInteraction);
81
83
  destroyInteraction(lassoInteraction);
82
84
  }, []);
83
- return (_jsx(BasicNvlWrapper, { ref: myNvlRef, nodes: nodes, rels: rels, nvlOptions: nvlOptions, nvlCallbacks: nvlCallbacks, layout: layout, layoutOptions: layoutOptions }));
85
+ return (_jsx(BasicNvlWrapper, { ref: myNvlRef, nodes: nodes, rels: rels, nvlOptions: nvlOptions, nvlCallbacks: nvlCallbacks, layout: layout, layoutOptions: layoutOptions, onInitializationError: onInitializationError, ...nvlEvents }));
84
86
  }));
@@ -6,6 +6,11 @@ export const destroyInteraction = (interactionRef) => {
6
6
  };
7
7
  export const useInteraction = (Interaction, interactionRef, callback, eventName, nvlRef, interactionOptions) => {
8
8
  useEffect(() => {
9
+ const container = nvlRef.current?.getContainer();
10
+ // Make sure we are not mounting interaction handlers when there is NVL setup
11
+ if (isNil(container)) {
12
+ return;
13
+ }
9
14
  if ((callback === true || typeof callback === 'function') && !isNil(nvlRef.current)) {
10
15
  if (isNil(interactionRef.current)) {
11
16
  interactionRef.current = new Interaction(nvlRef.current, interactionOptions);
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@neo4j-nvl/react",
3
- "version": "0.3.1-6201a90a",
3
+ "version": "0.3.1-6fbcfb2a",
4
4
  "main": "lib/index.js",
5
+ "homepage": "https://neo4j.com/docs/nvl/current/",
5
6
  "license": "SEE LICENSE IN 'LICENSE.txt'",
6
7
  "description": "React wrappers for the Neo4j Visualization Library",
7
8
  "keywords": [
@@ -15,6 +16,7 @@
15
16
  },
16
17
  "scripts": {
17
18
  "build": "tsc",
19
+ "watch": "tsc -w",
18
20
  "test": "jest",
19
21
  "prepack": "cp ../../LICENSE.txt ./",
20
22
  "postpack": "rm LICENSE.txt"
@@ -39,8 +41,8 @@
39
41
  "typescript": "^5.4.5"
40
42
  },
41
43
  "dependencies": {
42
- "@neo4j-nvl/base": "^0.3.1-6201a90a",
43
- "@neo4j-nvl/interaction-handlers": "^0.3.1-6201a90a",
44
+ "@neo4j-nvl/base": "^0.3.1-6fbcfb2a",
45
+ "@neo4j-nvl/interaction-handlers": "^0.3.1-6fbcfb2a",
44
46
  "lodash": "4.17.21",
45
47
  "react": "^18.2.0",
46
48
  "react-dom": "^18.2.0"