@neo4j-nvl/react 0.2.54 → 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 +38 -32
- 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 +1 -1
- package/lib/utils/{graphComparison.js → graph-comparison.js} +17 -6
- package/package.json +1 -1
- /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,36 +92,40 @@ 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
|
}
|
|
@@ -128,6 +133,7 @@ export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOpt
|
|
|
128
133
|
newNvl?.destroy();
|
|
129
134
|
nvlRef.current = null;
|
|
130
135
|
};
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
131
137
|
}, [containerRef.current]);
|
|
132
138
|
useEffect(() => {
|
|
133
139
|
if (nvlRef.current === null) {
|
|
@@ -138,33 +144,33 @@ export const BasicNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOpt
|
|
|
138
144
|
const relChanges = getMapDifferences(currentRels, rels);
|
|
139
145
|
setCurrentRels(rels);
|
|
140
146
|
setCurrentNodes(nodes);
|
|
141
|
-
nvlRef.current
|
|
142
|
-
nvlRef.current
|
|
143
|
-
nvlRef.current
|
|
144
|
-
}, [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]);
|
|
145
151
|
useEffect(() => {
|
|
146
152
|
if (nvlRef.current === null || layout === undefined) {
|
|
147
153
|
return;
|
|
148
154
|
}
|
|
149
|
-
nvlRef.current
|
|
155
|
+
nvlRef.current.setLayout(layout);
|
|
150
156
|
}, [layout]);
|
|
151
157
|
useDeepCompareEffect(() => {
|
|
152
158
|
if (nvlRef.current === null || layoutOptions === undefined) {
|
|
153
159
|
return;
|
|
154
160
|
}
|
|
155
|
-
nvlRef.current
|
|
161
|
+
nvlRef.current.setLayoutOptions(layoutOptions);
|
|
156
162
|
}, [layoutOptions]);
|
|
157
163
|
useEffect(() => {
|
|
158
164
|
if (nvlRef.current === null || nvlOptions.useWebGL === undefined) {
|
|
159
165
|
return;
|
|
160
166
|
}
|
|
161
|
-
nvlRef.current
|
|
167
|
+
nvlRef.current.setUseWebGLRenderer(nvlOptions.useWebGL);
|
|
162
168
|
}, [nvlOptions.useWebGL]);
|
|
163
169
|
useEffect(() => {
|
|
164
170
|
if (nvlRef.current === null || nvlOptions.disableWebGL === undefined) {
|
|
165
171
|
return;
|
|
166
172
|
}
|
|
167
|
-
nvlRef.current
|
|
173
|
+
nvlRef.current.setDisableWebGL(nvlOptions.disableWebGL);
|
|
168
174
|
}, [nvlOptions.disableWebGL]);
|
|
169
|
-
return
|
|
175
|
+
return _jsx("div", { ref: containerRef, style: { height: '100%', outline: '0' }, ...nvlEvents });
|
|
170
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;
|
|
@@ -20,5 +20,5 @@ export const useInteraction = (Interaction, interactionRef, callback, eventName,
|
|
|
20
20
|
else if (callback === false) {
|
|
21
21
|
destroyInteraction(interactionRef);
|
|
22
22
|
}
|
|
23
|
-
}, [callback]);
|
|
23
|
+
}, [Interaction, callback, eventName, interactionOptions, interactionRef, nvlRef]);
|
|
24
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
|
File without changes
|