@neo4j-nvl/react 0.2.53 → 0.2.55
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/lib/basic-wrapper/BasicNvlWrapper.d.ts +2 -2
- package/lib/basic-wrapper/BasicNvlWrapper.js +40 -33
- package/lib/interactive-nvl-wrapper/InteractiveNvlWrapper.js +5 -3
- package/lib/interactive-nvl-wrapper/hooks.d.ts +2 -2
- package/lib/interactive-nvl-wrapper/hooks.js +13 -15
- package/lib/utils/{graphComparison.js → graph-comparison.js} +17 -6
- package/package.json +2 -2
- /package/lib/utils/{graphComparison.d.ts → graph-comparison.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExternalCallbacks, Layout, LayoutOptions, Node, NvlOptions, Relationship } from '@neo4j-nvl/core';
|
|
2
2
|
import NVL from '@neo4j-nvl/core';
|
|
3
|
-
import
|
|
3
|
+
import { type HTMLProps } from 'react';
|
|
4
4
|
type IncludeMethods<T> = Pick<T, {
|
|
5
5
|
[K in keyof T]: T[K] extends (_: unknown) => unknown ? K : never;
|
|
6
6
|
}[keyof T]>;
|
|
@@ -109,5 +109,5 @@ export interface BasicReactWrapperProps {
|
|
|
109
109
|
* For more about interactivity, check out the {@link NVL}.hittest method,
|
|
110
110
|
* the Interaction Handlers module module and the {@link InteractiveNvlWrapper}.
|
|
111
111
|
*/
|
|
112
|
-
export declare const BasicNvlWrapper:
|
|
112
|
+
export declare const BasicNvlWrapper: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<Omit<BasicReactWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & import("react").RefAttributes<IncludeMethods<NVL>>>>;
|
|
113
113
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import NVL from '@neo4j-nvl/core';
|
|
2
|
-
import
|
|
3
|
-
import { getMapDifferences, getNodeAttributeDifferences } from '../utils/
|
|
3
|
+
import { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
4
|
+
import { getMapDifferences, getNodeAttributeDifferences } from '../utils/graph-comparison';
|
|
4
5
|
import { useDeepCompareEffect } from '../utils/hooks';
|
|
5
6
|
/**
|
|
6
7
|
* A basic React wrapper for the {@link NVL} class.
|
|
@@ -91,43 +92,49 @@ export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOpt
|
|
|
91
92
|
useImperativeHandle(ref, () => {
|
|
92
93
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
93
94
|
const nvlMethods = Object.getOwnPropertyNames(NVL.prototype);
|
|
94
|
-
// @ts-ignore revisit better typing for reduce function
|
|
95
95
|
return nvlMethods.reduce((current, method) => ({
|
|
96
96
|
...current,
|
|
97
97
|
[method]: (...args) =>
|
|
98
98
|
// @ts-ignore suppress the type casting error on spreading
|
|
99
|
-
nvlRef
|
|
100
|
-
}),
|
|
99
|
+
nvlRef.current !== null && nvlRef.current[method](...args)
|
|
100
|
+
}),
|
|
101
|
+
// eslint-disable-next-line max-len
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter, @typescript-eslint/consistent-type-assertions
|
|
103
|
+
{});
|
|
101
104
|
});
|
|
102
|
-
const containerRef = useRef();
|
|
105
|
+
const containerRef = useRef(null);
|
|
103
106
|
const [currentNodes, setCurrentNodes] = useState(nodes);
|
|
104
107
|
const [currentRels, setCurrentRels] = useState(rels);
|
|
105
108
|
useEffect(() => {
|
|
106
|
-
let newNvl;
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
catch (e) {
|
|
119
|
-
if (typeof onInitializationError === 'function') {
|
|
120
|
-
onInitializationError(e);
|
|
109
|
+
let newNvl = null;
|
|
110
|
+
if (containerRef.current !== null) {
|
|
111
|
+
if (nvlRef.current === null) {
|
|
112
|
+
const combinedOptions = { ...nvlOptions, layoutOptions };
|
|
113
|
+
if (layout !== undefined) {
|
|
114
|
+
combinedOptions.layout = layout;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
newNvl = new NVL(containerRef.current, currentNodes, currentRels, combinedOptions, nvlCallbacks);
|
|
118
|
+
nvlRef.current = newNvl;
|
|
119
|
+
setCurrentRels(rels);
|
|
120
|
+
setCurrentNodes(nodes);
|
|
121
121
|
}
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
catch (e) {
|
|
123
|
+
if (typeof onInitializationError === 'function') {
|
|
124
|
+
onInitializationError(e);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
throw e;
|
|
128
|
+
}
|
|
124
129
|
}
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
return () => {
|
|
128
133
|
newNvl?.destroy();
|
|
134
|
+
nvlRef.current = null;
|
|
129
135
|
};
|
|
130
|
-
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
137
|
+
}, [containerRef.current]);
|
|
131
138
|
useEffect(() => {
|
|
132
139
|
if (nvlRef.current === null) {
|
|
133
140
|
return;
|
|
@@ -137,33 +144,33 @@ export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOpt
|
|
|
137
144
|
const relChanges = getMapDifferences(currentRels, rels);
|
|
138
145
|
setCurrentRels(rels);
|
|
139
146
|
setCurrentNodes(nodes);
|
|
140
|
-
nvlRef.current
|
|
141
|
-
nvlRef.current
|
|
142
|
-
nvlRef.current
|
|
143
|
-
}, [nodes, rels]);
|
|
147
|
+
nvlRef.current.addAndUpdateElementsInGraph([...nodeChanges.added, ...nodeDiff], [...relChanges.added, ...relChanges.updated]);
|
|
148
|
+
nvlRef.current.removeRelationshipsWithIds(relChanges.removed.map((r) => r.id));
|
|
149
|
+
nvlRef.current.removeNodesWithIds(nodeChanges.removed.map((n) => n.id));
|
|
150
|
+
}, [currentNodes, currentRels, nodes, rels]);
|
|
144
151
|
useEffect(() => {
|
|
145
152
|
if (nvlRef.current === null || layout === undefined) {
|
|
146
153
|
return;
|
|
147
154
|
}
|
|
148
|
-
nvlRef.current
|
|
155
|
+
nvlRef.current.setLayout(layout);
|
|
149
156
|
}, [layout]);
|
|
150
157
|
useDeepCompareEffect(() => {
|
|
151
158
|
if (nvlRef.current === null || layoutOptions === undefined) {
|
|
152
159
|
return;
|
|
153
160
|
}
|
|
154
|
-
nvlRef.current
|
|
161
|
+
nvlRef.current.setLayoutOptions(layoutOptions);
|
|
155
162
|
}, [layoutOptions]);
|
|
156
163
|
useEffect(() => {
|
|
157
164
|
if (nvlRef.current === null || nvlOptions.useWebGL === undefined) {
|
|
158
165
|
return;
|
|
159
166
|
}
|
|
160
|
-
nvlRef.current
|
|
167
|
+
nvlRef.current.setUseWebGLRenderer(nvlOptions.useWebGL);
|
|
161
168
|
}, [nvlOptions.useWebGL]);
|
|
162
169
|
useEffect(() => {
|
|
163
170
|
if (nvlRef.current === null || nvlOptions.disableWebGL === undefined) {
|
|
164
171
|
return;
|
|
165
172
|
}
|
|
166
|
-
nvlRef.current
|
|
173
|
+
nvlRef.current.setDisableWebGL(nvlOptions.disableWebGL);
|
|
167
174
|
}, [nvlOptions.disableWebGL]);
|
|
168
|
-
return
|
|
175
|
+
return _jsx("div", { ref: containerRef, style: { height: '100%', outline: '0' }, ...nvlEvents });
|
|
169
176
|
}));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { BoxSelectInteraction, ClickInteraction, DragNodeInteraction, DrawInteraction, HoverInteraction, LassoInteraction, PanInteraction, ZoomInteraction } from '@neo4j-nvl/interaction-handlers';
|
|
2
|
-
import
|
|
3
|
+
import { forwardRef, memo, useEffect, useRef } from 'react';
|
|
3
4
|
import { BasicNvlWrapper } from '../basic-wrapper/BasicNvlWrapper';
|
|
4
5
|
import { destroyInteraction, useInteraction } from './hooks';
|
|
5
6
|
const options = {
|
|
@@ -38,7 +39,8 @@ const options = {
|
|
|
38
39
|
* ```
|
|
39
40
|
*/
|
|
40
41
|
export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOptions, mouseEventCallbacks = {}, nvlCallbacks = {}, nvlOptions = {}, interactionOptions = options }, nvlRef) => {
|
|
41
|
-
const
|
|
42
|
+
const newNvlRef = useRef(null);
|
|
43
|
+
const myNvlRef = nvlRef ?? newNvlRef;
|
|
42
44
|
const { onHover, onNodeClick, onNodeDoubleClick, onNodeRightClick, onRelationshipClick, onRelationshipDoubleClick, onRelationshipRightClick, onCanvasClick, onCanvasRightClick, onPan, onZoom, onDrag, onDragStart, onDragEnd, onDrawEnd, onHoverNodeMargin, onBoxStarted, onBoxSelect, onLassoStarted, onLassoSelect } = mouseEventCallbacks;
|
|
43
45
|
const hoverInteraction = useRef();
|
|
44
46
|
const clickInteraction = useRef();
|
|
@@ -78,5 +80,5 @@ export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, lay
|
|
|
78
80
|
destroyInteraction(multiSelectInteraction);
|
|
79
81
|
destroyInteraction(lassoInteraction);
|
|
80
82
|
}, []);
|
|
81
|
-
return (
|
|
83
|
+
return (_jsx(BasicNvlWrapper, { ref: myNvlRef, nodes: nodes, rels: rels, nvlOptions: nvlOptions, nvlCallbacks: nvlCallbacks, layout: layout, layoutOptions: layoutOptions }));
|
|
82
84
|
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type NVL from '@neo4j-nvl/core';
|
|
2
2
|
import type { MutableRefObject } from 'react';
|
|
3
3
|
import type { InteractionOptions, MouseEvent, MouseInteraction, MouseInteractionModule } from './types';
|
|
4
|
-
export declare const destroyInteraction: (interactionRef: MutableRefObject<MouseInteraction>) => void;
|
|
5
|
-
export declare const useInteraction: (Interaction: MouseInteractionModule, interactionRef: MutableRefObject<MouseInteraction>, callback: boolean | ((...args: unknown[]) => void), eventName: MouseEvent, nvlRef: MutableRefObject<NVL>, interactionOptions: InteractionOptions) => void;
|
|
4
|
+
export declare const destroyInteraction: (interactionRef: MutableRefObject<MouseInteraction | null>) => void;
|
|
5
|
+
export declare const useInteraction: (Interaction: MouseInteractionModule, interactionRef: MutableRefObject<MouseInteraction>, callback: boolean | ((...args: unknown[]) => void), eventName: MouseEvent, nvlRef: MutableRefObject<NVL | null>, interactionOptions: InteractionOptions) => void;
|
|
@@ -6,21 +6,19 @@ export const destroyInteraction = (interactionRef) => {
|
|
|
6
6
|
};
|
|
7
7
|
export const useInteraction = (Interaction, interactionRef, callback, eventName, nvlRef, interactionOptions) => {
|
|
8
8
|
useEffect(() => {
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
interactionRef.current = new Interaction(nvlRef.current, interactionOptions);
|
|
13
|
-
}
|
|
14
|
-
if (typeof callback === 'function') {
|
|
15
|
-
interactionRef.current.updateCallback(eventName, callback);
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
interactionRef.current.removeCallback(eventName);
|
|
19
|
-
}
|
|
9
|
+
if ((callback === true || typeof callback === 'function') && !isNil(nvlRef.current)) {
|
|
10
|
+
if (isNil(interactionRef.current)) {
|
|
11
|
+
interactionRef.current = new Interaction(nvlRef.current, interactionOptions);
|
|
20
12
|
}
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
if (typeof callback === 'function') {
|
|
14
|
+
interactionRef.current.updateCallback(eventName, callback);
|
|
23
15
|
}
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
else if (!isNil(interactionRef.current.callbackMap[eventName])) {
|
|
17
|
+
interactionRef.current.removeCallback(eventName);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else if (callback === false) {
|
|
21
|
+
destroyInteraction(interactionRef);
|
|
22
|
+
}
|
|
23
|
+
}, [Interaction, callback, eventName, interactionOptions, interactionRef, nvlRef]);
|
|
26
24
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isEqual, keyBy, keys, sortBy, transform } from 'lodash';
|
|
1
|
+
import { isEqual, isNil, keyBy, keys, sortBy, transform } from 'lodash';
|
|
2
2
|
const getMapDifferences = (prevGraphElements, newGraphElements) => {
|
|
3
3
|
const prevMap = keyBy(prevGraphElements, 'id');
|
|
4
4
|
const currentMap = keyBy(newGraphElements, 'id');
|
|
@@ -12,6 +12,9 @@ const getMapDifferences = (prevGraphElements, newGraphElements) => {
|
|
|
12
12
|
while (i < prevIds.length && j < currentIds.length) {
|
|
13
13
|
const prevId = prevIds[i];
|
|
14
14
|
const currId = currentIds[j];
|
|
15
|
+
if (prevId === undefined || currId === undefined) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
15
18
|
if (prevId === currId) {
|
|
16
19
|
if (!isEqual(prevMap[prevId], currentMap[currId])) {
|
|
17
20
|
updated.push(currId);
|
|
@@ -29,17 +32,25 @@ const getMapDifferences = (prevGraphElements, newGraphElements) => {
|
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
while (i < prevIds.length) {
|
|
32
|
-
|
|
35
|
+
const prevId = prevIds[i];
|
|
36
|
+
if (prevId === undefined) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
removed.push(prevId);
|
|
33
40
|
i += 1;
|
|
34
41
|
}
|
|
35
42
|
while (j < currentIds.length) {
|
|
36
|
-
|
|
43
|
+
const currId = currentIds[j];
|
|
44
|
+
if (currId === undefined) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
added.push(currId);
|
|
37
48
|
j += 1;
|
|
38
49
|
}
|
|
39
50
|
return {
|
|
40
|
-
added: added.map((id) => currentMap[id]),
|
|
41
|
-
removed: removed.map((id) => prevMap[id]),
|
|
42
|
-
updated: updated.map((id) => currentMap[id])
|
|
51
|
+
added: added.map((id) => currentMap[id]).filter((n) => !isNil(n)),
|
|
52
|
+
removed: removed.map((id) => prevMap[id]).filter((n) => !isNil(n)),
|
|
53
|
+
updated: updated.map((id) => currentMap[id]).filter((n) => !isNil(n))
|
|
43
54
|
};
|
|
44
55
|
};
|
|
45
56
|
const getNodeAttributeDifferences = (prevNodes, newNodes) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-nvl/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.55",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"license": "SEE LICENSE IN 'Neo4j Early Access Agreement - Visualization Library.pdf'",
|
|
6
6
|
"scripts": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@testing-library/jest-dom": "^5.16.5",
|
|
28
28
|
"@testing-library/react": "^13.4.0",
|
|
29
29
|
"@types/lodash": "4.14.202",
|
|
30
|
-
"@types/react": "
|
|
30
|
+
"@types/react": "18.2.58",
|
|
31
31
|
"babel-eslint": "^10.1.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
File without changes
|