@neo4j-nvl/react 2.0.0 → 2.1.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 (31) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +8 -0
  3. package/lib/basic-wrapper/BasicNvlWrapper.d.ts +58 -32
  4. package/lib/basic-wrapper/BasicNvlWrapper.js +129 -143
  5. package/lib/index.d.ts +5 -8
  6. package/lib/index.js +3 -3
  7. package/lib/interactive-nvl-wrapper/InteractionHandlers.d.ts +8 -8
  8. package/lib/interactive-nvl-wrapper/InteractionHandlers.js +62 -59
  9. package/lib/interactive-nvl-wrapper/InteractiveNvlWrapper.d.ts +5 -4
  10. package/lib/interactive-nvl-wrapper/InteractiveNvlWrapper.js +55 -42
  11. package/lib/interactive-nvl-wrapper/hooks.d.ts +4 -4
  12. package/lib/interactive-nvl-wrapper/hooks.js +24 -27
  13. package/lib/interactive-nvl-wrapper/types.d.ts +24 -9
  14. package/lib/interactive-nvl-wrapper/types.js +0 -1
  15. package/lib/static-picture-wrapper/StaticPictureWrapper.d.ts +21 -15
  16. package/lib/static-picture-wrapper/StaticPictureWrapper.js +77 -55
  17. package/lib/utils/constants.d.ts +1 -1
  18. package/lib/utils/constants.js +4 -2
  19. package/lib/utils/graph-comparison.d.ts +5 -5
  20. package/lib/utils/graph-comparison.js +53 -68
  21. package/lib/utils/hooks.d.ts +2 -2
  22. package/lib/utils/hooks.js +10 -11
  23. package/package.json +24 -10
  24. package/lib/__tests__/BasicNvlWrapper.test.d.ts +0 -1
  25. package/lib/__tests__/BasicNvlWrapper.test.js +0 -159
  26. package/lib/__tests__/InteractiveNvlWrapper.test.d.ts +0 -1
  27. package/lib/__tests__/InteractiveNvlWrapper.test.js +0 -396
  28. package/lib/__tests__/StaticPictureWrapper.test.d.ts +0 -1
  29. package/lib/__tests__/StaticPictureWrapper.test.js +0 -85
  30. package/lib/__tests__/index.test.d.ts +0 -1
  31. package/lib/__tests__/index.test.js +0 -8
package/CHANGELOG.md CHANGED
@@ -2,7 +2,31 @@
2
2
 
3
3
  All notable changes to NVL will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
4
 
5
- ## [2.0.0] - 2026-09-11
5
+ ## [2.1.0] - 2026-11-10
6
+
7
+ This release adds keyboard actions for moving nodes, ships an agent skill for NVL, and makes all packages loadable as ESM in Node.js without a bundler.
8
+
9
+ ### Added
10
+
11
+ * Keyboard interaction handler actions for moving nodes with the arrow keys, with a new `onNodeMove` callback.
12
+ * Agent skill files for NVL, shipped with `@neo4j-nvl/base`.
13
+
14
+ ### Changed
15
+
16
+ * `@neo4j-nvl/react` and `@neo4j-nvl/interaction-handlers` are now spec-compliant ESM with `"type": "module"` and an `exports` map. Note that deep imports into `lib/` will no longer work.
17
+ * Replaced `lodash` with `lodash-es` in `@neo4j-nvl/react` and `@neo4j-nvl/interaction-handlers` (Jest users transforming `@neo4j-nvl/*` also need to transform `lodash-es`).
18
+ * Type declarations of `@neo4j-nvl/base` now resolve correctly with `moduleResolution: "nodenext"`.
19
+ * Container resizing uses the native `ResizeObserver` instead of the `resizelistener` dependency.
20
+ * Default `height` and `outline` styles of NVL containers can now be overridden by stylesheets.
21
+
22
+ ### Fixed
23
+
24
+ * `fit()` zooms out beyond `minZoom` when `allowDynamicMinZoom` is `true` and the graph does not fit the viewport.
25
+ * `onHover` callback's `element` parameter is now typed as possibly `undefined`, matching the runtime behaviour.
26
+ * Added missing caret for the React 18 peer dependency range in `@neo4j-nvl/react`.
27
+ * Several dependency updates
28
+
29
+ ## [2.0.0] - 2026-09-15
6
30
 
7
31
  This 2.0.0 major release upgrades NVL to WebGL2 for both the renderer and physics engine, unlocking major performance improvements. It also adds new clustering capabilities with visual decorations to the force directed and hierarchical layouts.
8
32
 
package/README.md CHANGED
@@ -78,6 +78,14 @@ const [boxSelect, setBoxSelect] = useState(false)
78
78
 
79
79
  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/).
80
80
 
81
+ ### Agent skills
82
+
83
+ The agent skill for NVL (`neo4j-nvl-skill`) ships with `@neo4j-nvl/base`, which this package depends on. To make it available to your AI coding assistant, run the following with a recent version of the `skills` CLI:
84
+
85
+ ```bash
86
+ npx skills experimental_sync
87
+ ```
88
+
81
89
  ### Product analytics
82
90
 
83
91
  In order to improve the library we are collecting some information about the usage of NVL. If you prefer to disable this behavior setting `disableTelemetry` to `true` in the `nvlOptions` property.
@@ -1,44 +1,70 @@
1
- import type { ExternalCallbacks, Node, NvlOptions, Relationship } from '@neo4j-nvl/base';
2
- import NVL from '@neo4j-nvl/base';
3
- import { type HTMLProps } from 'react';
1
+ import NVL, { ExternalCallbacks, Node, NvlOptions, Relationship } from "@neo4j-nvl/base";
2
+ import { HTMLProps } from "react";
4
3
  /**
5
4
  * The properties that can be passed to the {@link BasicNvlWrapper} component.
6
5
  */
7
6
  export interface BasicReactWrapperProps {
8
- /** The nodes of the graph of type Node[] */
9
- nodes: Node[];
10
- /** The rels of the graph of type Relationship[] */
11
- rels: Relationship[];
12
- /** an Object containing functions for callbacks on certain actions */
13
- nvlCallbacks?: ExternalCallbacks;
14
- /** An object containing options for the Nvl instance */
15
- nvlOptions?: NvlOptions;
16
- /** Sets the positions of the nodes in the graph using the setNodePositions method. */
17
- positions?: Node[];
18
- /**
19
- * Sets the zoom level of the viewport using the setZoom method.
20
- * @remarks If both zoom and pan are provided, the setZoomAndPan method will be used.
21
- */
22
- zoom?: number;
23
- /**
24
- * Sets the pan coordinates of the viewport using the setPan method.
25
- * @remarks If both zoom and pan are provided, the setZoomAndPan method will be used.
26
- */
27
- pan?: {
28
- /** The x coordinate of the pan. */
29
- x: number;
30
- /** The y coordinate of the pan. */
31
- y: number;
32
- };
33
- /** A callback to handle any errors that happen during NVL initialization */
34
- onInitializationError?: (error: unknown) => void;
7
+ /** The nodes of the graph of type Node[] */
8
+ nodes: Node[];
9
+ /** The rels of the graph of type Relationship[] */
10
+ rels: Relationship[];
11
+ /**
12
+ * An object containing functions for callbacks on certain actions.
13
+ * @remarks Passed to the NVL constructor once; later changes to this prop are ignored.
14
+ * Read changing state through a ref inside the callbacks instead of redefining them.
15
+ */
16
+ nvlCallbacks?: ExternalCallbacks;
17
+ /**
18
+ * An object containing options for the Nvl instance.
19
+ * @remarks
20
+ * If `minimapContainer` is present it must be a non-null element before NVL is created, otherwise
21
+ * creation is deferred until it is.
22
+ */
23
+ nvlOptions?: NvlOptions;
24
+ /**
25
+ * Sets the positions of the nodes in the graph using the setNodePositions method.
26
+ * @remarks Applied whenever the array reference changes and is non-empty. This is the way to
27
+ * position nodes.
28
+ * Do not set `x` and `y` on `nodes` directly.
29
+ */
30
+ positions?: Node[];
31
+ /**
32
+ * Sets the zoom level of the viewport using the setZoom method.
33
+ * @remarks If both zoom and pan are provided, the setZoomAndPan method will be used.
34
+ */
35
+ zoom?: number;
36
+ /**
37
+ * Sets the pan coordinates of the viewport using the setPan method.
38
+ * @remarks If both zoom and pan are provided, the setZoomAndPan method will be used.
39
+ */
40
+ pan?: {
41
+ /** The x coordinate of the pan. */
42
+ x: number;
43
+ /** The y coordinate of the pan. */
44
+ y: number;
45
+ };
46
+ /** A callback to handle any errors that happen during NVL initialization */
47
+ onInitializationError?: (error: unknown) => void;
35
48
  }
36
49
  /**
37
50
  *
38
51
  * A basic React wrapper that wraps the NVL base library within a React component.
39
52
  * It takes the class' arguments as properties, which are passed to the NVL constructor.
40
- * Any changes in properties will be reflected in the NVL instance by calling the corresponding methods.
53
+ *
54
+ * The `ref` exposes every NVL method. Calls made before the instance exists return `null`.
41
55
  *
42
56
  * For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_basic_react_wrapper Basic React wrapper documentation page}.
57
+ * @example
58
+ * ```tsx
59
+ * const Graph = () => {
60
+ * const nvlRef = useRef<NVL>(null)
61
+ * return (
62
+ * <>
63
+ * <BasicNvlWrapper ref={nvlRef} nodes={nodes} rels={relationships} />
64
+ * <button onClick={() => nvlRef.current?.fit(nodes.map((node) => node.id))}>Fit</button>
65
+ * </>
66
+ * )
67
+ * }
68
+ * ```
43
69
  */
44
- export declare const BasicNvlWrapper: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<Omit<BasicReactWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & import("react").RefAttributes<Partial<Pick<NVL, "restart" | "destroy" | "addAndUpdateElementsInGraph" | "getSelectedNodes" | "getSelectedRelationships" | "removeNodesWithIds" | "removeRelationshipsWithIds" | "getNodes" | "getRelationships" | "getNodeById" | "getRelationshipById" | "getPositionById" | "getCurrentOptions" | "deselectAll" | "fit" | "resetZoom" | "setRenderer" | "setDisableWebGL" | "pinNode" | "unPinNode" | "setLayout" | "setLayoutOptions" | "getNodesOnScreen" | "getNodePositions" | "setNodePositions" | "isLayoutMoving" | "saveToFile" | "saveToSvg" | "getImageDataUrl" | "getSvgDataUrl" | "saveFullGraphToLargeFile" | "getZoomLimits" | "setZoom" | "getScale" | "getPan" | "getHits" | "getContainer">>>>>;
70
+ export declare const BasicNvlWrapper: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<Omit<BasicReactWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & import("react").RefAttributes<Partial<Pick<NVL, "restart" | "addAndUpdateElementsInGraph" | "getSelectedNodes" | "getSelectedRelationships" | "removeNodesWithIds" | "removeRelationshipsWithIds" | "getNodes" | "getRelationships" | "getNodeById" | "getRelationshipById" | "getPositionById" | "getCurrentOptions" | "destroy" | "deselectAll" | "fit" | "resetZoom" | "setRenderer" | "setDisableWebGL" | "pinNode" | "unPinNode" | "setLayout" | "setLayoutOptions" | "getNodesOnScreen" | "getNodePositions" | "setNodePositions" | "isLayoutMoving" | "saveToFile" | "saveToSvg" | "getImageDataUrl" | "getSvgDataUrl" | "saveFullGraphToLargeFile" | "getZoomLimits" | "setZoom" | "getScale" | "getPan" | "getHits" | "getContainer">>>>>;
@@ -1,145 +1,131 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import NVL from '@neo4j-nvl/base';
3
- import { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react';
4
- import { BASIC_WRAPPER_ID } from '../utils/constants';
5
- import { getMapDifferences, getNodeAttributeDifferences } from '../utils/graph-comparison';
6
- import { useDeepCompareEffect } from '../utils/hooks';
1
+ import { BASIC_WRAPPER_ID } from "../utils/constants.js";
2
+ import { getMapDifferences, getNodeAttributeDifferences } from "../utils/graph-comparison.js";
3
+ import { useDeepCompareEffect } from "../utils/hooks.js";
4
+ import NVL from "@neo4j-nvl/base";
5
+ import { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ // src/basic-wrapper/BasicNvlWrapper.tsx
7
8
  /**
8
- *
9
- * A basic React wrapper that wraps the NVL base library within a React component.
10
- * It takes the class' arguments as properties, which are passed to the NVL constructor.
11
- * Any changes in properties will be reflected in the NVL instance by calling the corresponding methods.
12
- *
13
- * For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_basic_react_wrapper Basic React wrapper documentation page}.
14
- */
15
- export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, nvlCallbacks = {}, nvlOptions = {}, positions = [], zoom, pan, onInitializationError, ...nvlEvents }, ref) => {
16
- const nvlRef = useRef(null);
17
- const prevZoomRef = useRef(undefined);
18
- const prevPanRef = useRef(undefined);
19
- useImperativeHandle(ref, () => {
20
- const nvlMethods = Object.getOwnPropertyNames(NVL.prototype);
21
- return nvlMethods.reduce((current, method) => ({
22
- ...current,
23
- [method]: (...args) => {
24
- if (nvlRef.current === null) {
25
- return null;
26
- }
27
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
28
- return nvlRef.current[method](...args);
29
- }
30
- }), {});
31
- });
32
- const containerRef = useRef(null);
33
- const [currentNodes, setCurrentNodes] = useState(nodes);
34
- const [currentRels, setCurrentRels] = useState(rels);
35
- useEffect(() => {
36
- return () => {
37
- nvlRef.current?.destroy();
38
- nvlRef.current = null;
39
- prevZoomRef.current = undefined;
40
- prevPanRef.current = undefined;
41
- };
42
- }, []);
43
- useEffect(() => {
44
- let newNvl = null;
45
- const hasMinimap = 'minimapContainer' in nvlOptions;
46
- const minimapContainerIsReady = hasMinimap ? nvlOptions.minimapContainer !== null : true;
47
- const mainContainerIsReady = containerRef.current !== null;
48
- if (mainContainerIsReady && minimapContainerIsReady) {
49
- if (nvlRef.current === null) {
50
- try {
51
- newNvl = new NVL(containerRef.current, currentNodes, currentRels, nvlOptions, nvlCallbacks);
52
- nvlRef.current = newNvl;
53
- setCurrentRels(rels);
54
- setCurrentNodes(nodes);
55
- }
56
- catch (e) {
57
- if (typeof onInitializationError === 'function') {
58
- onInitializationError(e);
59
- }
60
- else {
61
- throw e;
62
- }
63
- }
64
- }
65
- }
66
- // eslint-disable-next-line react-hooks/exhaustive-deps
67
- }, [containerRef.current, nvlOptions.minimapContainer]);
68
- useEffect(() => {
69
- if (nvlRef.current === null) {
70
- return;
71
- }
72
- const nodeChanges = getMapDifferences(currentNodes, nodes);
73
- const nodeDiff = getNodeAttributeDifferences(currentNodes, nodes);
74
- const relChanges = getMapDifferences(currentRels, rels);
75
- const graphIsUnchanged = nodeChanges.added.length === 0 &&
76
- nodeChanges.removed.length === 0 &&
77
- nodeDiff.length === 0 &&
78
- relChanges.added.length === 0 &&
79
- relChanges.removed.length === 0 &&
80
- relChanges.updated.length === 0;
81
- if (graphIsUnchanged) {
82
- return;
83
- }
84
- setCurrentRels(rels);
85
- setCurrentNodes(nodes);
86
- const nodesToAddAndUpdate = [...nodeChanges.added, ...nodeDiff];
87
- const relsToAddAndUpdate = [...relChanges.added, ...relChanges.updated];
88
- nvlRef.current.addAndUpdateElementsInGraph(nodesToAddAndUpdate, relsToAddAndUpdate);
89
- const relationshipsToRemove = relChanges.removed.map((r) => r.id);
90
- const nodesToRemove = nodeChanges.removed.map((n) => n.id);
91
- nvlRef.current.removeRelationshipsWithIds(relationshipsToRemove);
92
- nvlRef.current.removeNodesWithIds(nodesToRemove);
93
- }, [currentNodes, currentRels, nodes, rels]);
94
- useEffect(() => {
95
- if (nvlRef.current === null || nvlOptions.layout === undefined) {
96
- return;
97
- }
98
- nvlRef.current.setLayout(nvlOptions.layout);
99
- }, [nvlOptions.layout]);
100
- useDeepCompareEffect(() => {
101
- if (nvlRef.current === null || nvlOptions.layoutOptions === undefined) {
102
- return;
103
- }
104
- nvlRef.current.setLayoutOptions(nvlOptions.layoutOptions);
105
- }, [nvlOptions.layoutOptions]);
106
- useEffect(() => {
107
- if (nvlRef.current === null || nvlOptions.renderer === undefined) {
108
- return;
109
- }
110
- nvlRef.current.setRenderer(nvlOptions.renderer);
111
- }, [nvlOptions.renderer]);
112
- useEffect(() => {
113
- if (nvlRef.current === null || nvlOptions.disableWebGL === undefined) {
114
- return;
115
- }
116
- nvlRef.current.setDisableWebGL(nvlOptions.disableWebGL);
117
- }, [nvlOptions.disableWebGL]);
118
- useEffect(() => {
119
- if (nvlRef.current === null || positions.length === 0) {
120
- return;
121
- }
122
- nvlRef.current.setNodePositions(positions);
123
- }, [positions]);
124
- useEffect(() => {
125
- if (nvlRef.current === null) {
126
- return;
127
- }
128
- const currentZoom = prevZoomRef.current;
129
- const currentPan = prevPanRef.current;
130
- const zoomHasChanged = zoom !== undefined && zoom !== currentZoom;
131
- const panHasChanged = pan !== undefined && (pan.x !== currentPan?.x || pan.y !== currentPan.y);
132
- if (zoomHasChanged && panHasChanged) {
133
- nvlRef.current.setZoomAndPan(zoom, pan.x, pan.y);
134
- }
135
- else if (zoomHasChanged) {
136
- nvlRef.current.setZoom(zoom);
137
- }
138
- else if (panHasChanged) {
139
- nvlRef.current.setPan(pan.x, pan.y);
140
- }
141
- prevZoomRef.current = zoom;
142
- prevPanRef.current = pan;
143
- }, [zoom, pan]);
144
- return _jsx("div", { id: BASIC_WRAPPER_ID, ref: containerRef, style: { height: '100%', outline: '0' }, ...nvlEvents });
9
+ *
10
+ * A basic React wrapper that wraps the NVL base library within a React component.
11
+ * It takes the class' arguments as properties, which are passed to the NVL constructor.
12
+ *
13
+ * The `ref` exposes every NVL method. Calls made before the instance exists return `null`.
14
+ *
15
+ * For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_basic_react_wrapper Basic React wrapper documentation page}.
16
+ * @example
17
+ * ```tsx
18
+ * const Graph = () => {
19
+ * const nvlRef = useRef<NVL>(null)
20
+ * return (
21
+ * <>
22
+ * <BasicNvlWrapper ref={nvlRef} nodes={nodes} rels={relationships} />
23
+ * <button onClick={() => nvlRef.current?.fit(nodes.map((node) => node.id))}>Fit</button>
24
+ * </>
25
+ * )
26
+ * }
27
+ * ```
28
+ */
29
+ const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, nvlCallbacks = {}, nvlOptions = {}, positions = [], zoom, pan, onInitializationError, ...nvlEvents }, ref) => {
30
+ const nvlRef = useRef(null);
31
+ const prevZoomRef = useRef(void 0);
32
+ const prevPanRef = useRef(void 0);
33
+ useImperativeHandle(ref, () => {
34
+ return Object.getOwnPropertyNames(NVL.prototype).reduce((current, method) => ({
35
+ ...current,
36
+ [method]: (...args) => {
37
+ if (nvlRef.current === null) return null;
38
+ return nvlRef.current[method](...args);
39
+ }
40
+ }), {});
41
+ });
42
+ const containerRef = useRef(null);
43
+ const [currentNodes, setCurrentNodes] = useState(nodes);
44
+ const [currentRels, setCurrentRels] = useState(rels);
45
+ useEffect(() => {
46
+ return () => {
47
+ nvlRef.current?.destroy();
48
+ nvlRef.current = null;
49
+ prevZoomRef.current = void 0;
50
+ prevPanRef.current = void 0;
51
+ };
52
+ }, []);
53
+ useEffect(() => {
54
+ let newNvl = null;
55
+ const minimapContainerIsReady = "minimapContainer" in nvlOptions ? nvlOptions.minimapContainer !== null : true;
56
+ if (containerRef.current !== null && minimapContainerIsReady) {
57
+ if (nvlRef.current === null) try {
58
+ newNvl = new NVL(containerRef.current, currentNodes, currentRels, nvlOptions, nvlCallbacks);
59
+ nvlRef.current = newNvl;
60
+ setCurrentRels(rels);
61
+ setCurrentNodes(nodes);
62
+ } catch (e) {
63
+ if (typeof onInitializationError === "function") onInitializationError(e);
64
+ else throw e;
65
+ }
66
+ }
67
+ }, [containerRef.current, nvlOptions.minimapContainer]);
68
+ useEffect(() => {
69
+ if (nvlRef.current === null) return;
70
+ const nodeChanges = getMapDifferences(currentNodes, nodes);
71
+ const nodeDiff = getNodeAttributeDifferences(currentNodes, nodes);
72
+ const relChanges = getMapDifferences(currentRels, rels);
73
+ if (nodeChanges.added.length === 0 && nodeChanges.removed.length === 0 && nodeDiff.length === 0 && relChanges.added.length === 0 && relChanges.removed.length === 0 && relChanges.updated.length === 0) return;
74
+ setCurrentRels(rels);
75
+ setCurrentNodes(nodes);
76
+ const nodesToAddAndUpdate = [...nodeChanges.added, ...nodeDiff];
77
+ const relsToAddAndUpdate = [...relChanges.added, ...relChanges.updated];
78
+ nvlRef.current.addAndUpdateElementsInGraph(nodesToAddAndUpdate, relsToAddAndUpdate);
79
+ const relationshipsToRemove = relChanges.removed.map((r) => r.id);
80
+ const nodesToRemove = nodeChanges.removed.map((n) => n.id);
81
+ nvlRef.current.removeRelationshipsWithIds(relationshipsToRemove);
82
+ nvlRef.current.removeNodesWithIds(nodesToRemove);
83
+ }, [
84
+ currentNodes,
85
+ currentRels,
86
+ nodes,
87
+ rels
88
+ ]);
89
+ useEffect(() => {
90
+ if (nvlRef.current === null || nvlOptions.layout === void 0) return;
91
+ nvlRef.current.setLayout(nvlOptions.layout);
92
+ }, [nvlOptions.layout]);
93
+ useDeepCompareEffect(() => {
94
+ if (nvlRef.current === null || nvlOptions.layoutOptions === void 0) return;
95
+ nvlRef.current.setLayoutOptions(nvlOptions.layoutOptions);
96
+ }, [nvlOptions.layoutOptions]);
97
+ useEffect(() => {
98
+ if (nvlRef.current === null || nvlOptions.renderer === void 0) return;
99
+ nvlRef.current.setRenderer(nvlOptions.renderer);
100
+ }, [nvlOptions.renderer]);
101
+ useEffect(() => {
102
+ if (nvlRef.current === null || nvlOptions.disableWebGL === void 0) return;
103
+ nvlRef.current.setDisableWebGL(nvlOptions.disableWebGL);
104
+ }, [nvlOptions.disableWebGL]);
105
+ useEffect(() => {
106
+ if (nvlRef.current === null || positions.length === 0) return;
107
+ nvlRef.current.setNodePositions(positions);
108
+ }, [positions]);
109
+ useEffect(() => {
110
+ if (nvlRef.current === null) return;
111
+ const currentZoom = prevZoomRef.current;
112
+ const currentPan = prevPanRef.current;
113
+ const zoomHasChanged = zoom !== void 0 && zoom !== currentZoom;
114
+ const panHasChanged = pan !== void 0 && (pan.x !== currentPan?.x || pan.y !== currentPan.y);
115
+ if (zoomHasChanged && panHasChanged) nvlRef.current.setZoomAndPan(zoom, pan.x, pan.y);
116
+ else if (zoomHasChanged) nvlRef.current.setZoom(zoom);
117
+ else if (panHasChanged) nvlRef.current.setPan(pan.x, pan.y);
118
+ prevZoomRef.current = zoom;
119
+ prevPanRef.current = pan;
120
+ }, [zoom, pan]);
121
+ return /* @__PURE__ */ jsx("div", {
122
+ id: BASIC_WRAPPER_ID,
123
+ ref: containerRef,
124
+ style: {
125
+ height: "100%",
126
+ outline: "0"
127
+ },
128
+ ...nvlEvents
129
+ });
145
130
  }));
131
+ export { BasicNvlWrapper };
package/lib/index.d.ts CHANGED
@@ -1,8 +1,5 @@
1
- import { BasicNvlWrapper } from './basic-wrapper/BasicNvlWrapper';
2
- import type { BasicReactWrapperProps } from './basic-wrapper/BasicNvlWrapper';
3
- import { InteractiveNvlWrapper } from './interactive-nvl-wrapper/InteractiveNvlWrapper';
4
- import type { InteractionOptions, InteractiveNvlWrapperProps, KeyboardEvent, KeyboardEventCallbacks, MouseEvent, MouseEventCallbacks } from './interactive-nvl-wrapper/types';
5
- import type { StaticPictureWrapperProps } from './static-picture-wrapper/StaticPictureWrapper';
6
- import { StaticPictureWrapper } from './static-picture-wrapper/StaticPictureWrapper';
7
- export { BasicNvlWrapper, InteractiveNvlWrapper, StaticPictureWrapper };
8
- export type { MouseEventCallbacks, KeyboardEventCallbacks, MouseEvent, KeyboardEvent, BasicReactWrapperProps, InteractionOptions, InteractiveNvlWrapperProps, StaticPictureWrapperProps };
1
+ import { BasicNvlWrapper, BasicReactWrapperProps } from "./basic-wrapper/BasicNvlWrapper.js";
2
+ import { InteractionOptions, InteractiveNvlWrapperProps, KeyboardEvent, KeyboardEventCallbacks, MouseEvent, MouseEventCallbacks } from "./interactive-nvl-wrapper/types.js";
3
+ import { InteractiveNvlWrapper } from "./interactive-nvl-wrapper/InteractiveNvlWrapper.js";
4
+ import { StaticPictureWrapper, StaticPictureWrapperProps } from "./static-picture-wrapper/StaticPictureWrapper.js";
5
+ export { BasicNvlWrapper, type BasicReactWrapperProps, type InteractionOptions, InteractiveNvlWrapper, type InteractiveNvlWrapperProps, type KeyboardEvent, type KeyboardEventCallbacks, type MouseEvent, type MouseEventCallbacks, StaticPictureWrapper, type StaticPictureWrapperProps };
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BasicNvlWrapper } from './basic-wrapper/BasicNvlWrapper';
2
- import { InteractiveNvlWrapper } from './interactive-nvl-wrapper/InteractiveNvlWrapper';
3
- import { StaticPictureWrapper } from './static-picture-wrapper/StaticPictureWrapper';
1
+ import { BasicNvlWrapper } from "./basic-wrapper/BasicNvlWrapper.js";
2
+ import { InteractiveNvlWrapper } from "./interactive-nvl-wrapper/InteractiveNvlWrapper.js";
3
+ import { StaticPictureWrapper } from "./static-picture-wrapper/StaticPictureWrapper.js";
4
4
  export { BasicNvlWrapper, InteractiveNvlWrapper, StaticPictureWrapper };
@@ -1,11 +1,11 @@
1
- import type NVL from '@neo4j-nvl/base';
2
- import type { MutableRefObject } from 'react';
3
- import type { InteractionOptions, KeyboardEventCallbacks, MouseEventCallbacks } from './types';
1
+ import { InteractionOptions, KeyboardEventCallbacks, MouseEventCallbacks } from "./types.js";
2
+ import NVL from "@neo4j-nvl/base";
3
+ import { MutableRefObject } from "react";
4
4
  interface InteractionHandlersProps {
5
- nvlRef: MutableRefObject<NVL | null>;
6
- mouseEventCallbacks: MouseEventCallbacks;
7
- keyboardEventCallbacks: KeyboardEventCallbacks;
8
- interactionOptions: InteractionOptions;
5
+ nvlRef: MutableRefObject<NVL | null>;
6
+ mouseEventCallbacks: MouseEventCallbacks;
7
+ keyboardEventCallbacks: KeyboardEventCallbacks;
8
+ interactionOptions: InteractionOptions;
9
9
  }
10
10
  export declare const InteractionHandlers: React.FC<InteractionHandlersProps>;
11
- export {};
11
+ export {};
@@ -1,60 +1,63 @@
1
- import { BoxSelectInteraction, ClickInteraction, DragNodeInteraction, DrawInteraction, HoverInteraction, KeyboardInteraction, LassoInteraction, PanInteraction, ZoomInteraction } from '@neo4j-nvl/interaction-handlers';
2
- import { useEffect, useRef } from 'react';
3
- import { destroyInteraction, useInteraction } from './hooks';
4
- export const InteractionHandlers = ({ nvlRef, mouseEventCallbacks, keyboardEventCallbacks, interactionOptions }) => {
5
- const hoverInteraction = useRef(null);
6
- const clickInteraction = useRef(null);
7
- const panInteraction = useRef(null);
8
- const zoomInteraction = useRef(null);
9
- const dragNodeInteraction = useRef(null);
10
- const drawInteraction = useRef(null);
11
- const multiSelectInteraction = useRef(null);
12
- const lassoInteraction = useRef(null);
13
- const keyboardInteraction = useRef(null);
14
- useInteraction(HoverInteraction, hoverInteraction, mouseEventCallbacks.onHover, 'onHover', nvlRef, interactionOptions);
15
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeClick, 'onNodeClick', nvlRef, interactionOptions);
16
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeDoubleClick, 'onNodeDoubleClick', nvlRef, interactionOptions);
17
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeRightClick, 'onNodeRightClick', nvlRef, interactionOptions);
18
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipClick, 'onRelationshipClick', nvlRef, interactionOptions);
19
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipDoubleClick, 'onRelationshipDoubleClick', nvlRef, interactionOptions);
20
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipRightClick, 'onRelationshipRightClick', nvlRef, interactionOptions);
21
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasClick, 'onCanvasClick', nvlRef, interactionOptions);
22
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasDoubleClick, 'onCanvasDoubleClick', nvlRef, interactionOptions);
23
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasRightClick, 'onCanvasRightClick', nvlRef, interactionOptions);
24
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterClick, 'onClusterClick', nvlRef, interactionOptions);
25
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterDoubleClick, 'onClusterDoubleClick', nvlRef, interactionOptions);
26
- useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterRightClick, 'onClusterRightClick', nvlRef, interactionOptions);
27
- useInteraction(PanInteraction, panInteraction, mouseEventCallbacks.onPan, 'onPan', nvlRef, interactionOptions);
28
- useInteraction(ZoomInteraction, zoomInteraction, mouseEventCallbacks.onZoomAndPan, 'onZoomAndPan', nvlRef, interactionOptions);
29
- useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDrag, 'onDrag', nvlRef, interactionOptions);
30
- useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragStart, 'onDragStart', nvlRef, interactionOptions);
31
- useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragEnd, 'onDragEnd', nvlRef, interactionOptions);
32
- useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onHoverNodeMargin, 'onHoverNodeMargin', nvlRef, interactionOptions);
33
- useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawStarted, 'onDrawStarted', nvlRef, interactionOptions);
34
- useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawEnded, 'onDrawEnded', nvlRef, interactionOptions);
35
- useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxStarted, 'onBoxStarted', nvlRef, interactionOptions);
36
- useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxSelect, 'onBoxSelect', nvlRef, interactionOptions);
37
- useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoStarted, 'onLassoStarted', nvlRef, interactionOptions);
38
- useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoSelect, 'onLassoSelect', nvlRef, interactionOptions);
39
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onKeyDown, 'onKeyDown', nvlRef, interactionOptions);
40
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onKeyUp, 'onKeyUp', nvlRef, interactionOptions);
41
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onNodeFocus, 'onNodeFocus', nvlRef, interactionOptions);
42
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onNodeBlur, 'onNodeBlur', nvlRef, interactionOptions);
43
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onRelationshipFocus, 'onRelationshipFocus', nvlRef, interactionOptions);
44
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onRelationshipBlur, 'onRelationshipBlur', nvlRef, interactionOptions);
45
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onCanvasFocus, 'onCanvasFocus', nvlRef, interactionOptions);
46
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onCanvasBlur, 'onCanvasBlur', nvlRef, interactionOptions);
47
- useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onContextMenu, 'onContextMenu', nvlRef, interactionOptions);
48
- useEffect(() => () => {
49
- destroyInteraction(hoverInteraction);
50
- destroyInteraction(clickInteraction);
51
- destroyInteraction(panInteraction);
52
- destroyInteraction(zoomInteraction);
53
- destroyInteraction(dragNodeInteraction);
54
- destroyInteraction(drawInteraction);
55
- destroyInteraction(multiSelectInteraction);
56
- destroyInteraction(lassoInteraction);
57
- destroyInteraction(keyboardInteraction);
58
- }, []);
59
- return null;
1
+ import { destroyInteraction, useInteraction } from "./hooks.js";
2
+ import { useEffect, useRef } from "react";
3
+ import { BoxSelectInteraction, ClickInteraction, DragNodeInteraction, DrawInteraction, HoverInteraction, KeyboardInteraction, LassoInteraction, PanInteraction, ZoomInteraction } from "@neo4j-nvl/interaction-handlers";
4
+ // src/interactive-nvl-wrapper/InteractionHandlers.tsx
5
+ const InteractionHandlers = ({ nvlRef, mouseEventCallbacks, keyboardEventCallbacks, interactionOptions }) => {
6
+ const hoverInteraction = useRef(null);
7
+ const clickInteraction = useRef(null);
8
+ const panInteraction = useRef(null);
9
+ const zoomInteraction = useRef(null);
10
+ const dragNodeInteraction = useRef(null);
11
+ const drawInteraction = useRef(null);
12
+ const multiSelectInteraction = useRef(null);
13
+ const lassoInteraction = useRef(null);
14
+ const keyboardInteraction = useRef(null);
15
+ useInteraction(HoverInteraction, hoverInteraction, mouseEventCallbacks.onHover, "onHover", nvlRef, interactionOptions);
16
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeClick, "onNodeClick", nvlRef, interactionOptions);
17
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeDoubleClick, "onNodeDoubleClick", nvlRef, interactionOptions);
18
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeRightClick, "onNodeRightClick", nvlRef, interactionOptions);
19
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipClick, "onRelationshipClick", nvlRef, interactionOptions);
20
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipDoubleClick, "onRelationshipDoubleClick", nvlRef, interactionOptions);
21
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipRightClick, "onRelationshipRightClick", nvlRef, interactionOptions);
22
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasClick, "onCanvasClick", nvlRef, interactionOptions);
23
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasDoubleClick, "onCanvasDoubleClick", nvlRef, interactionOptions);
24
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasRightClick, "onCanvasRightClick", nvlRef, interactionOptions);
25
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterClick, "onClusterClick", nvlRef, interactionOptions);
26
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterDoubleClick, "onClusterDoubleClick", nvlRef, interactionOptions);
27
+ useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onClusterRightClick, "onClusterRightClick", nvlRef, interactionOptions);
28
+ useInteraction(PanInteraction, panInteraction, mouseEventCallbacks.onPan, "onPan", nvlRef, interactionOptions);
29
+ useInteraction(ZoomInteraction, zoomInteraction, mouseEventCallbacks.onZoomAndPan, "onZoomAndPan", nvlRef, interactionOptions);
30
+ useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDrag, "onDrag", nvlRef, interactionOptions);
31
+ useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragStart, "onDragStart", nvlRef, interactionOptions);
32
+ useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragEnd, "onDragEnd", nvlRef, interactionOptions);
33
+ useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onHoverNodeMargin, "onHoverNodeMargin", nvlRef, interactionOptions);
34
+ useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawStarted, "onDrawStarted", nvlRef, interactionOptions);
35
+ useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawEnded, "onDrawEnded", nvlRef, interactionOptions);
36
+ useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxStarted, "onBoxStarted", nvlRef, interactionOptions);
37
+ useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxSelect, "onBoxSelect", nvlRef, interactionOptions);
38
+ useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoStarted, "onLassoStarted", nvlRef, interactionOptions);
39
+ useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoSelect, "onLassoSelect", nvlRef, interactionOptions);
40
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onKeyDown, "onKeyDown", nvlRef, interactionOptions);
41
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onKeyUp, "onKeyUp", nvlRef, interactionOptions);
42
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onNodeFocus, "onNodeFocus", nvlRef, interactionOptions);
43
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onNodeBlur, "onNodeBlur", nvlRef, interactionOptions);
44
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onRelationshipFocus, "onRelationshipFocus", nvlRef, interactionOptions);
45
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onRelationshipBlur, "onRelationshipBlur", nvlRef, interactionOptions);
46
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onCanvasFocus, "onCanvasFocus", nvlRef, interactionOptions);
47
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onCanvasBlur, "onCanvasBlur", nvlRef, interactionOptions);
48
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onContextMenu, "onContextMenu", nvlRef, interactionOptions);
49
+ useInteraction(KeyboardInteraction, keyboardInteraction, keyboardEventCallbacks.onNodeMove, "onNodeMove", nvlRef, interactionOptions);
50
+ useEffect(() => () => {
51
+ destroyInteraction(hoverInteraction);
52
+ destroyInteraction(clickInteraction);
53
+ destroyInteraction(panInteraction);
54
+ destroyInteraction(zoomInteraction);
55
+ destroyInteraction(dragNodeInteraction);
56
+ destroyInteraction(drawInteraction);
57
+ destroyInteraction(multiSelectInteraction);
58
+ destroyInteraction(lassoInteraction);
59
+ destroyInteraction(keyboardInteraction);
60
+ }, []);
61
+ return null;
60
62
  };
63
+ export { InteractionHandlers };