@neo4j-nvl/react 0.3.9 → 1.0.0-0e1dd35b-alpha
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/CHANGELOG.md +20 -0
- package/package.json +14 -9
- package/lib/__tests__/BasicNvlWrapper.test.d.ts +0 -1
- package/lib/__tests__/BasicNvlWrapper.test.js +0 -39
- package/lib/__tests__/InteractiveNvlWrapper.test.d.ts +0 -1
- package/lib/__tests__/InteractiveNvlWrapper.test.js +0 -135
- package/lib/__tests__/index.test.d.ts +0 -1
- package/lib/__tests__/index.test.js +0 -8
- package/lib/basic-wrapper/BasicNvlWrapper.d.ts +0 -40
- package/lib/basic-wrapper/BasicNvlWrapper.js +0 -132
- package/lib/index.d.ts +0 -6
- package/lib/index.js +0 -3
- package/lib/interactive-nvl-wrapper/InteractionHandlers.d.ts +0 -10
- package/lib/interactive-nvl-wrapper/InteractionHandlers.js +0 -45
- package/lib/interactive-nvl-wrapper/InteractiveNvlWrapper.d.ts +0 -16
- package/lib/interactive-nvl-wrapper/InteractiveNvlWrapper.js +0 -46
- package/lib/interactive-nvl-wrapper/hooks.d.ts +0 -5
- package/lib/interactive-nvl-wrapper/hooks.js +0 -29
- package/lib/interactive-nvl-wrapper/types.d.ts +0 -28
- package/lib/interactive-nvl-wrapper/types.js +0 -1
- package/lib/utils/constants.d.ts +0 -2
- package/lib/utils/constants.js +0 -2
- package/lib/utils/graph-comparison.d.ts +0 -8
- package/lib/utils/graph-comparison.js +0 -72
- package/lib/utils/hooks.d.ts +0 -2
- package/lib/utils/hooks.js +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
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
|
+
## [1.0.0] - 2025-09-30
|
|
6
|
+
This 1.0.0 release is our first major release, with NVL's release strategy fully adopting semantic versioning going forward. Updates in this release include React 19 support for the React wrappers, a UI overhaul of the [examples app](https://neo4j.com/docs/api/nvl/current/examples.html).
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
* support for React 19 in Nvl React wrappers.
|
|
10
|
+
* new prop to the React components to provde zoom and pan values.
|
|
11
|
+
* extend return object of `.getZoomTargetForNodePositions` function to include pan values.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
* updated example application UI.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
* display remaining captions when one of the values in the caption array is null or undefined.
|
|
18
|
+
* ensure the computing state for the d3 layout is set correctly.
|
|
19
|
+
* correctly process Right-to-Left (RTL) text for node captions.
|
|
20
|
+
|
|
21
|
+
### Removed
|
|
22
|
+
* `useWebGL` / `setUseWebGLRenderer`, please use [renderer](https://neo4j.com/docs/api/nvl/current/interfaces/_neo4j_nvl_base.NvlOptions.html#renderer) & [setRenderer](https://neo4j.com/docs/api/nvl/current/classes/_neo4j_nvl_base.NVL.html#setRenderer) instead going forward.
|
|
23
|
+
* `NvlOption.nodeDefaultBorderColor`, `NvlOption.selectedBorderColor`, `NvlOption.disabledItemColor`, `NvlOption.disabledItemFontColor`, please use properties with the same name in [NvlOptions.styling](https://neo4j.com/docs/api/nvl/current/interfaces/_neo4j_nvl_base.NvlOptions.html#styling) object going forward.
|
|
24
|
+
|
|
5
25
|
## [0.3.9] - 2025-07-23
|
|
6
26
|
|
|
7
27
|
The 0.3.9 release contains several fixes for NVL's interaction handler and adds a new method to NVL to directly extract image data from an NVL instance:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-nvl/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-0e1dd35b-alpha",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"homepage": "https://neo4j.com/docs/nvl/current/",
|
|
6
6
|
"license": "SEE LICENSE IN 'LICENSE.txt'",
|
|
@@ -27,17 +27,22 @@
|
|
|
27
27
|
"lib"
|
|
28
28
|
],
|
|
29
29
|
"devDependencies": {
|
|
30
|
+
"@testing-library/dom": "^10.4.0",
|
|
30
31
|
"@testing-library/jest-dom": "^5.16.5",
|
|
31
|
-
"@testing-library/react": "^
|
|
32
|
+
"@testing-library/react": "^16.3.0",
|
|
32
33
|
"@types/lodash": "4.14.202",
|
|
33
34
|
"@types/react": "^18.2.58",
|
|
34
|
-
"
|
|
35
|
+
"react": "^19.1.1",
|
|
36
|
+
"react-dom": "^19.1.1"
|
|
35
37
|
},
|
|
36
38
|
"dependencies": {
|
|
37
|
-
"@neo4j-nvl/base": "0.
|
|
38
|
-
"@neo4j-nvl/interaction-handlers": "0.
|
|
39
|
-
"lodash": "4.17.21"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
"@neo4j-nvl/base": "1.0.0-0e1dd35b-alpha",
|
|
40
|
+
"@neo4j-nvl/interaction-handlers": "1.0.0-0e1dd35b-alpha",
|
|
41
|
+
"lodash": "4.17.21"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
45
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
46
|
+
},
|
|
47
|
+
"stableVersion": "1.0.0"
|
|
43
48
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import NVL, { HierarchicalLayoutType } from '@neo4j-nvl/base';
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
import { render } from '@testing-library/react';
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { BasicNvlWrapper } from '../basic-wrapper/BasicNvlWrapper';
|
|
7
|
-
jest.mock('@neo4j-nvl/base');
|
|
8
|
-
jest.mock('@neo4j-nvl/layout-workers');
|
|
9
|
-
describe('BasicNvlWrapper', () => {
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
jest.clearAllMocks();
|
|
12
|
-
});
|
|
13
|
-
test('initialises NVL expectedly with an empty graph object and no other properties', () => {
|
|
14
|
-
render(_jsx("div", { children: _jsx(BasicNvlWrapper, { nodes: [], rels: [] }) }));
|
|
15
|
-
expect(NVL).toHaveBeenCalledWith(expect.any(HTMLDivElement), [], [], {}, {});
|
|
16
|
-
});
|
|
17
|
-
test('initialises NVL expectedly with a graph object and properties', () => {
|
|
18
|
-
const mockLayoutDoneFunction = jest.fn();
|
|
19
|
-
render(_jsx("div", { children: _jsx(BasicNvlWrapper, { nodes: [{ id: '1' }, { id: '2' }], rels: [{ id: '12', from: '1', to: '2' }], layout: HierarchicalLayoutType, layoutOptions: { enableCytoscape: true }, nvlOptions: { renderer: 'canvas' }, nvlCallbacks: { onLayoutDone: mockLayoutDoneFunction } }) }));
|
|
20
|
-
expect(NVL).toHaveBeenCalledWith(expect.any(HTMLDivElement), [{ id: '1' }, { id: '2' }], [{ id: '12', from: '1', to: '2' }], { renderer: 'canvas', layout: HierarchicalLayoutType, layoutOptions: { enableCytoscape: true } }, {
|
|
21
|
-
onLayoutDone: mockLayoutDoneFunction
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
test('destroys NVL on unmount', () => {
|
|
25
|
-
const destroy = jest.fn();
|
|
26
|
-
jest.spyOn(NVL.prototype, 'destroy').mockImplementation(destroy);
|
|
27
|
-
const { unmount } = render(_jsx("div", { children: _jsx(BasicNvlWrapper, { nodes: [], rels: [] }) }));
|
|
28
|
-
unmount();
|
|
29
|
-
expect(NVL).toHaveBeenCalledTimes(1);
|
|
30
|
-
expect(destroy).toHaveBeenCalledTimes(1);
|
|
31
|
-
});
|
|
32
|
-
test('successfully re-initialises NVL when using React StrictMode', () => {
|
|
33
|
-
const destroy = jest.fn();
|
|
34
|
-
jest.spyOn(NVL.prototype, 'destroy').mockImplementation(destroy);
|
|
35
|
-
render(_jsx(React.StrictMode, { children: _jsx("div", { children: _jsx(BasicNvlWrapper, { nodes: [], rels: [] }) }) }));
|
|
36
|
-
expect(NVL).toHaveBeenCalledTimes(2);
|
|
37
|
-
expect(destroy).toHaveBeenCalledTimes(1);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import NVL, { HierarchicalLayoutType } from '@neo4j-nvl/base';
|
|
3
|
-
import { BoxSelectInteraction, ClickInteraction, DragNodeInteraction, DrawInteraction, HoverInteraction, LassoInteraction, PanInteraction, ZoomInteraction } from '@neo4j-nvl/interaction-handlers';
|
|
4
|
-
import '@testing-library/jest-dom';
|
|
5
|
-
import { act, render } from '@testing-library/react';
|
|
6
|
-
import React, { createRef } from 'react';
|
|
7
|
-
import { InteractiveNvlWrapper } from '../interactive-nvl-wrapper/InteractiveNvlWrapper';
|
|
8
|
-
jest.mock('@neo4j-nvl/base');
|
|
9
|
-
jest.mock('@neo4j-nvl/layout-workers');
|
|
10
|
-
jest.mock('@neo4j-nvl/interaction-handlers');
|
|
11
|
-
let mockOnInitialization;
|
|
12
|
-
HoverInteraction.prototype.callbackMap = new Map();
|
|
13
|
-
PanInteraction.prototype.callbackMap = new Map();
|
|
14
|
-
let mockDestroy;
|
|
15
|
-
let destroyHoverInteraction;
|
|
16
|
-
let destroyPanInteraction;
|
|
17
|
-
describe('InteractiveNvlWrapper', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
jest.spyOn(NVL.prototype, 'getContainer').mockImplementation(() => document.createElement('div'));
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
21
|
-
// @ts-expect-error
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
23
|
-
NVL.mockImplementation((_container, _nodes, _rels, _options, callbacks) => {
|
|
24
|
-
mockOnInitialization = callbacks.onInitialization;
|
|
25
|
-
return {
|
|
26
|
-
getContainer: () => document.createElement('div'),
|
|
27
|
-
destroy: mockDestroy,
|
|
28
|
-
setLayout: jest.fn(),
|
|
29
|
-
setLayoutOptions: jest.fn(),
|
|
30
|
-
setRenderer: jest.fn()
|
|
31
|
-
};
|
|
32
|
-
});
|
|
33
|
-
mockDestroy = jest.fn();
|
|
34
|
-
destroyHoverInteraction = jest.fn();
|
|
35
|
-
destroyPanInteraction = jest.fn();
|
|
36
|
-
jest.spyOn(NVL.prototype, 'destroy').mockImplementation(mockDestroy);
|
|
37
|
-
jest.spyOn(HoverInteraction.prototype, 'destroy').mockImplementation(destroyHoverInteraction);
|
|
38
|
-
jest.spyOn(PanInteraction.prototype, 'destroy').mockImplementation(destroyPanInteraction);
|
|
39
|
-
});
|
|
40
|
-
afterEach(() => {
|
|
41
|
-
jest.clearAllMocks();
|
|
42
|
-
});
|
|
43
|
-
test('initialises NVL expectedly with an empty graph object and no other properties', () => {
|
|
44
|
-
render(_jsx("div", { children: _jsx(InteractiveNvlWrapper, { nodes: [], rels: [] }) }));
|
|
45
|
-
expect(NVL).toHaveBeenCalledWith(expect.any(HTMLDivElement), [], [], {}, { onInitialization: expect.any(Function) });
|
|
46
|
-
});
|
|
47
|
-
test('initialises NVL expectedly with a graph object and properties', () => {
|
|
48
|
-
const mockLayoutDoneFunction = jest.fn();
|
|
49
|
-
render(_jsx(InteractiveNvlWrapper, { nodes: [{ id: '1' }, { id: '2' }], rels: [{ id: '12', from: '1', to: '2' }], layout: HierarchicalLayoutType, layoutOptions: { enableCytoscape: true }, nvlOptions: { renderer: 'canvas' }, nvlCallbacks: { onLayoutDone: mockLayoutDoneFunction } }));
|
|
50
|
-
act(() => {
|
|
51
|
-
mockOnInitialization?.();
|
|
52
|
-
});
|
|
53
|
-
expect(NVL).toHaveBeenCalledWith(expect.any(HTMLDivElement), [{ id: '1' }, { id: '2' }], [{ id: '12', from: '1', to: '2' }], { renderer: 'canvas', layout: HierarchicalLayoutType, layoutOptions: { enableCytoscape: true } }, {
|
|
54
|
-
onLayoutDone: mockLayoutDoneFunction,
|
|
55
|
-
onInitialization: expect.any(Function)
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
test('initialises expected interaction handlers with correct options', () => {
|
|
59
|
-
const myNvlRef = createRef();
|
|
60
|
-
render(_jsx(InteractiveNvlWrapper, { nodes: [], rels: [], ref: myNvlRef, mouseEventCallbacks: {
|
|
61
|
-
onHover: true,
|
|
62
|
-
onPan: true
|
|
63
|
-
}, interactionOptions: {
|
|
64
|
-
drawShadowOnHover: true
|
|
65
|
-
} }));
|
|
66
|
-
act(() => {
|
|
67
|
-
mockOnInitialization?.();
|
|
68
|
-
});
|
|
69
|
-
expect(HoverInteraction).toHaveBeenCalledWith(myNvlRef.current, { drawShadowOnHover: true });
|
|
70
|
-
expect(PanInteraction).toHaveBeenCalledWith(myNvlRef.current, { drawShadowOnHover: true });
|
|
71
|
-
expect(HoverInteraction).toHaveBeenCalledTimes(1);
|
|
72
|
-
expect(PanInteraction).toHaveBeenCalledTimes(1);
|
|
73
|
-
expect(ClickInteraction).not.toHaveBeenCalled();
|
|
74
|
-
expect(DragNodeInteraction).not.toHaveBeenCalled();
|
|
75
|
-
expect(DrawInteraction).not.toHaveBeenCalled();
|
|
76
|
-
expect(ZoomInteraction).not.toHaveBeenCalled();
|
|
77
|
-
expect(BoxSelectInteraction).not.toHaveBeenCalled();
|
|
78
|
-
expect(LassoInteraction).not.toHaveBeenCalled();
|
|
79
|
-
});
|
|
80
|
-
test('does not attempt to initialize interaction handlers if NVL container is not available', () => {
|
|
81
|
-
const myNvlRef = createRef();
|
|
82
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
83
|
-
// @ts-expect-error
|
|
84
|
-
jest.spyOn(NVL.prototype, 'getContainer').mockImplementation(() => null);
|
|
85
|
-
render(_jsx(InteractiveNvlWrapper, { nodes: [], rels: [], ref: myNvlRef, mouseEventCallbacks: {
|
|
86
|
-
onHover: true
|
|
87
|
-
}, interactionOptions: {
|
|
88
|
-
drawShadowOnHover: true
|
|
89
|
-
} }));
|
|
90
|
-
expect(HoverInteraction).not.toHaveBeenCalled();
|
|
91
|
-
expect(NVL).toHaveBeenCalledTimes(1);
|
|
92
|
-
});
|
|
93
|
-
test('destroys NVL and active interaction handlers on unmount', () => {
|
|
94
|
-
const { unmount } = render(_jsx(InteractiveNvlWrapper, { nodes: [], rels: [], mouseEventCallbacks: {
|
|
95
|
-
onHover: true
|
|
96
|
-
} }));
|
|
97
|
-
act(() => {
|
|
98
|
-
mockOnInitialization?.();
|
|
99
|
-
});
|
|
100
|
-
unmount();
|
|
101
|
-
expect(mockDestroy).toHaveBeenCalledTimes(1);
|
|
102
|
-
expect(destroyHoverInteraction).toHaveBeenCalledTimes(1);
|
|
103
|
-
expect(destroyPanInteraction).not.toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
test('successfully re-initialises NVL and active interaction handlers when using React StrictMode', () => {
|
|
106
|
-
const myNvlRef = createRef();
|
|
107
|
-
render(_jsx(React.StrictMode, { children: _jsx(InteractiveNvlWrapper, { nodes: [], rels: [], ref: myNvlRef, mouseEventCallbacks: {
|
|
108
|
-
onHover: true
|
|
109
|
-
}, interactionOptions: {
|
|
110
|
-
drawShadowOnHover: true
|
|
111
|
-
} }) }));
|
|
112
|
-
act(() => {
|
|
113
|
-
mockOnInitialization?.();
|
|
114
|
-
});
|
|
115
|
-
expect(NVL).toHaveBeenCalledTimes(2);
|
|
116
|
-
expect(HoverInteraction).toHaveBeenCalledTimes(2);
|
|
117
|
-
expect(HoverInteraction).toHaveBeenCalledWith(myNvlRef.current, { drawShadowOnHover: true });
|
|
118
|
-
expect(mockDestroy).toHaveBeenCalledTimes(1);
|
|
119
|
-
expect(destroyHoverInteraction).toHaveBeenCalledTimes(1);
|
|
120
|
-
expect(destroyPanInteraction).not.toHaveBeenCalled();
|
|
121
|
-
expect(DragNodeInteraction).not.toHaveBeenCalled();
|
|
122
|
-
expect(DrawInteraction).not.toHaveBeenCalled();
|
|
123
|
-
expect(ZoomInteraction).not.toHaveBeenCalled();
|
|
124
|
-
expect(BoxSelectInteraction).not.toHaveBeenCalled();
|
|
125
|
-
expect(LassoInteraction).not.toHaveBeenCalled();
|
|
126
|
-
});
|
|
127
|
-
test('also calls custom callbacks on initialization', () => {
|
|
128
|
-
const customOnInitializationCallback = jest.fn();
|
|
129
|
-
render(_jsx(InteractiveNvlWrapper, { nodes: [], rels: [], nvlCallbacks: { onInitialization: customOnInitializationCallback } }));
|
|
130
|
-
act(() => {
|
|
131
|
-
mockOnInitialization?.();
|
|
132
|
-
});
|
|
133
|
-
expect(customOnInitializationCallback).toHaveBeenCalledTimes(1);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as exportedModules from '../index';
|
|
2
|
-
jest.mock('@neo4j-nvl/layout-workers');
|
|
3
|
-
describe('index', () => {
|
|
4
|
-
test('provides the expected components', () => {
|
|
5
|
-
const modules = Object.keys(exportedModules);
|
|
6
|
-
expect(modules).toContain('BasicNvlWrapper');
|
|
7
|
-
});
|
|
8
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ExternalCallbacks, Layout, LayoutOptions, Node, NvlOptions, Relationship } from '@neo4j-nvl/base';
|
|
2
|
-
import NVL from '@neo4j-nvl/base';
|
|
3
|
-
import { type HTMLProps } from 'react';
|
|
4
|
-
/**
|
|
5
|
-
* @hidden
|
|
6
|
-
*/
|
|
7
|
-
type IncludeMethods<T> = Pick<T, {
|
|
8
|
-
[K in keyof T]: T[K] extends (_: unknown) => unknown ? K : never;
|
|
9
|
-
}[keyof T]>;
|
|
10
|
-
/**
|
|
11
|
-
* The properties that can be passed to the {@link BasicNvlWrapper} component.
|
|
12
|
-
*/
|
|
13
|
-
export interface BasicReactWrapperProps {
|
|
14
|
-
/** The nodes of the graph of type Node[] */
|
|
15
|
-
nodes: Node[];
|
|
16
|
-
/** The rels of the graph of type Relationship[] */
|
|
17
|
-
rels: Relationship[];
|
|
18
|
-
/** The layout, can be 'forceDirected' or 'hierarchical' */
|
|
19
|
-
layout?: Layout;
|
|
20
|
-
/** Options for the current layout */
|
|
21
|
-
layoutOptions?: LayoutOptions;
|
|
22
|
-
/** an Object containing functions for callbacks on certain actions */
|
|
23
|
-
nvlCallbacks?: ExternalCallbacks;
|
|
24
|
-
/** An object containing options for the Nvl instance */
|
|
25
|
-
nvlOptions?: NvlOptions;
|
|
26
|
-
/** Sets the positions of the nodes in the graph using the {@link NVL.setNodePositions} method. */
|
|
27
|
-
positions?: Node[];
|
|
28
|
-
/** A callback to handle any errors that happen during NVL initialization */
|
|
29
|
-
onInitializationError?: (error: unknown) => void;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
* A basic React wrapper that wraps the base {@link NVL} library within a React component.
|
|
34
|
-
* It takes the class' arguments as properties, which are passed to the NVL constructor.
|
|
35
|
-
* Any changes in properties will be reflected in the NVL instance by calling the corresponding methods.
|
|
36
|
-
*
|
|
37
|
-
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_basic_react_wrapper Basic React wrapper documentation page}.
|
|
38
|
-
*/
|
|
39
|
-
export declare const BasicNvlWrapper: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<Omit<BasicReactWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & import("react").RefAttributes<IncludeMethods<NVL>>>>;
|
|
40
|
-
export {};
|
|
@@ -1,132 +0,0 @@
|
|
|
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';
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* A basic React wrapper that wraps the base {@link NVL} 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, layout, layoutOptions, nvlCallbacks = {}, nvlOptions = {}, positions = [], onInitializationError, ...nvlEvents }, ref) => {
|
|
16
|
-
const nvlRef = useRef(null);
|
|
17
|
-
useImperativeHandle(ref, () => {
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
19
|
-
const nvlMethods = Object.getOwnPropertyNames(NVL.prototype);
|
|
20
|
-
return nvlMethods.reduce((current, method) => ({
|
|
21
|
-
...current,
|
|
22
|
-
[method]: (...args) => {
|
|
23
|
-
if (nvlRef.current === null) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
// @ts-ignore suppress the type casting error on spreading
|
|
27
|
-
return nvlRef.current[method](...args);
|
|
28
|
-
}
|
|
29
|
-
}),
|
|
30
|
-
// eslint-disable-next-line max-len
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter, @typescript-eslint/consistent-type-assertions
|
|
32
|
-
{});
|
|
33
|
-
});
|
|
34
|
-
const containerRef = useRef(null);
|
|
35
|
-
const [currentNodes, setCurrentNodes] = useState(nodes);
|
|
36
|
-
const [currentRels, setCurrentRels] = useState(rels);
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
let newNvl = null;
|
|
39
|
-
if (containerRef.current !== null) {
|
|
40
|
-
if (nvlRef.current === null) {
|
|
41
|
-
const combinedOptions = { ...nvlOptions, layoutOptions };
|
|
42
|
-
if (layout !== undefined) {
|
|
43
|
-
combinedOptions.layout = layout;
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
newNvl = new NVL(containerRef.current, currentNodes, currentRels, combinedOptions, nvlCallbacks);
|
|
47
|
-
nvlRef.current = newNvl;
|
|
48
|
-
setCurrentRels(rels);
|
|
49
|
-
setCurrentNodes(nodes);
|
|
50
|
-
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
if (typeof onInitializationError === 'function') {
|
|
53
|
-
onInitializationError(e);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
throw e;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return () => {
|
|
62
|
-
newNvl?.destroy();
|
|
63
|
-
nvlRef.current = null;
|
|
64
|
-
};
|
|
65
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
-
}, []);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (nvlRef.current === null) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const nodeChanges = getMapDifferences(currentNodes, nodes);
|
|
72
|
-
const nodeDiff = getNodeAttributeDifferences(currentNodes, nodes);
|
|
73
|
-
const relChanges = getMapDifferences(currentRels, rels);
|
|
74
|
-
const graphIsUnchanged = nodeChanges.added.length === 0 &&
|
|
75
|
-
nodeChanges.removed.length === 0 &&
|
|
76
|
-
nodeDiff.length === 0 &&
|
|
77
|
-
relChanges.added.length === 0 &&
|
|
78
|
-
relChanges.removed.length === 0 &&
|
|
79
|
-
relChanges.updated.length === 0;
|
|
80
|
-
if (graphIsUnchanged) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
setCurrentRels(rels);
|
|
84
|
-
setCurrentNodes(nodes);
|
|
85
|
-
const nodesToAddAndUpdate = [...nodeChanges.added, ...nodeDiff];
|
|
86
|
-
const relsToAddAndUpdate = [...relChanges.added, ...relChanges.updated];
|
|
87
|
-
nvlRef.current.addAndUpdateElementsInGraph(nodesToAddAndUpdate, relsToAddAndUpdate);
|
|
88
|
-
const relationshipsToRemove = relChanges.removed.map((r) => r.id);
|
|
89
|
-
const nodesToRemove = nodeChanges.removed.map((n) => n.id);
|
|
90
|
-
nvlRef.current.removeRelationshipsWithIds(relationshipsToRemove);
|
|
91
|
-
nvlRef.current.removeNodesWithIds(nodesToRemove);
|
|
92
|
-
}, [currentNodes, currentRels, nodes, rels]);
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
const updatedLayout = layout ?? nvlOptions.layout;
|
|
95
|
-
if (nvlRef.current === null || updatedLayout === undefined) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
nvlRef.current.setLayout(updatedLayout);
|
|
99
|
-
}, [layout, nvlOptions.layout]);
|
|
100
|
-
useDeepCompareEffect(() => {
|
|
101
|
-
const updatedLayoutOptions = layoutOptions ?? nvlOptions?.layoutOptions;
|
|
102
|
-
if (nvlRef.current === null || updatedLayoutOptions === undefined) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
nvlRef.current.setLayoutOptions(updatedLayoutOptions);
|
|
106
|
-
}, [layoutOptions, nvlOptions.layoutOptions]);
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (nvlRef.current === null || nvlOptions.useWebGL === undefined) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
nvlRef.current.setUseWebGLRenderer(nvlOptions.useWebGL);
|
|
112
|
-
}, [nvlOptions.useWebGL]);
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
if (nvlRef.current === null || nvlOptions.renderer === undefined) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
nvlRef.current.setRenderer(nvlOptions.renderer);
|
|
118
|
-
});
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
if (nvlRef.current === null || nvlOptions.disableWebGL === undefined) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
nvlRef.current.setDisableWebGL(nvlOptions.disableWebGL);
|
|
124
|
-
}, [nvlOptions.disableWebGL]);
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
if (nvlRef.current === null || positions.length === 0) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
nvlRef.current.setNodePositions(positions);
|
|
130
|
-
}, [positions]);
|
|
131
|
-
return _jsx("div", { id: BASIC_WRAPPER_ID, ref: containerRef, style: { height: '100%', outline: '0' }, ...nvlEvents });
|
|
132
|
-
}));
|
package/lib/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
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, MouseEvent, MouseEventCallbacks } from './interactive-nvl-wrapper/types';
|
|
5
|
-
export { BasicNvlWrapper, InteractiveNvlWrapper };
|
|
6
|
-
export type { MouseEventCallbacks, MouseEvent, BasicReactWrapperProps, InteractionOptions, InteractiveNvlWrapperProps };
|
package/lib/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type NVL from '@neo4j-nvl/base';
|
|
2
|
-
import type { MutableRefObject } from 'react';
|
|
3
|
-
import type { InteractionOptions, MouseEventCallbacks } from './types';
|
|
4
|
-
interface InteractionHandlersProps {
|
|
5
|
-
nvlRef: MutableRefObject<NVL | null>;
|
|
6
|
-
mouseEventCallbacks: MouseEventCallbacks;
|
|
7
|
-
interactionOptions: InteractionOptions;
|
|
8
|
-
}
|
|
9
|
-
export declare const InteractionHandlers: React.FC<InteractionHandlersProps>;
|
|
10
|
-
export {};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { BoxSelectInteraction, ClickInteraction, DragNodeInteraction, DrawInteraction, HoverInteraction, 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, 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
|
-
useInteraction(HoverInteraction, hoverInteraction, mouseEventCallbacks.onHover, 'onHover', nvlRef, interactionOptions);
|
|
14
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeClick, 'onNodeClick', nvlRef, interactionOptions);
|
|
15
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeDoubleClick, 'onNodeDoubleClick', nvlRef, interactionOptions);
|
|
16
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onNodeRightClick, 'onNodeRightClick', nvlRef, interactionOptions);
|
|
17
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipClick, 'onRelationshipClick', nvlRef, interactionOptions);
|
|
18
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipDoubleClick, 'onRelationshipDoubleClick', nvlRef, interactionOptions);
|
|
19
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onRelationshipRightClick, 'onRelationshipRightClick', nvlRef, interactionOptions);
|
|
20
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasClick, 'onCanvasClick', nvlRef, interactionOptions);
|
|
21
|
-
useInteraction(ClickInteraction, clickInteraction, mouseEventCallbacks.onCanvasRightClick, 'onCanvasRightClick', nvlRef, interactionOptions);
|
|
22
|
-
useInteraction(PanInteraction, panInteraction, mouseEventCallbacks.onPan, 'onPan', nvlRef, interactionOptions);
|
|
23
|
-
useInteraction(ZoomInteraction, zoomInteraction, mouseEventCallbacks.onZoom, 'onZoom', nvlRef, interactionOptions);
|
|
24
|
-
useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDrag, 'onDrag', nvlRef, interactionOptions);
|
|
25
|
-
useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragStart, 'onDragStart', nvlRef, interactionOptions);
|
|
26
|
-
useInteraction(DragNodeInteraction, dragNodeInteraction, mouseEventCallbacks.onDragEnd, 'onDragEnd', nvlRef, interactionOptions);
|
|
27
|
-
useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onHoverNodeMargin, 'onHoverNodeMargin', nvlRef, interactionOptions);
|
|
28
|
-
useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawStarted, 'onDrawStarted', nvlRef, interactionOptions);
|
|
29
|
-
useInteraction(DrawInteraction, drawInteraction, mouseEventCallbacks.onDrawEnded, 'onDrawEnded', nvlRef, interactionOptions);
|
|
30
|
-
useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxStarted, 'onBoxStarted', nvlRef, interactionOptions);
|
|
31
|
-
useInteraction(BoxSelectInteraction, multiSelectInteraction, mouseEventCallbacks.onBoxSelect, 'onBoxSelect', nvlRef, interactionOptions);
|
|
32
|
-
useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoStarted, 'onLassoStarted', nvlRef, interactionOptions);
|
|
33
|
-
useInteraction(LassoInteraction, lassoInteraction, mouseEventCallbacks.onLassoSelect, 'onLassoSelect', nvlRef, interactionOptions);
|
|
34
|
-
useEffect(() => () => {
|
|
35
|
-
destroyInteraction(hoverInteraction);
|
|
36
|
-
destroyInteraction(clickInteraction);
|
|
37
|
-
destroyInteraction(panInteraction);
|
|
38
|
-
destroyInteraction(zoomInteraction);
|
|
39
|
-
destroyInteraction(dragNodeInteraction);
|
|
40
|
-
destroyInteraction(drawInteraction);
|
|
41
|
-
destroyInteraction(multiSelectInteraction);
|
|
42
|
-
destroyInteraction(lassoInteraction);
|
|
43
|
-
}, []);
|
|
44
|
-
return null;
|
|
45
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type NVL from '@neo4j-nvl/base';
|
|
2
|
-
import type { HTMLProps } from 'react';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import type { InteractiveNvlWrapperProps } from './types';
|
|
5
|
-
/**
|
|
6
|
-
* The interactive React wrapper component contains a collection of interaction handlers by default
|
|
7
|
-
* and provides a variety of common functionality and callbacks.
|
|
8
|
-
* It is an extension of the {@link BasicNvlWrapper} component and incorporates the
|
|
9
|
-
* @neo4j-nvl/interaction-handlers module's decorators to provide a set of interaction events.
|
|
10
|
-
*
|
|
11
|
-
* The mouseEventCallbacks property takes an object where various callbacks can be defined
|
|
12
|
-
* and behavior can be toggled on and off.
|
|
13
|
-
*
|
|
14
|
-
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_interactive_reactive_wrapperr Interactive React wrapper documentation page}.
|
|
15
|
-
*/
|
|
16
|
-
export declare const InteractiveNvlWrapper: React.MemoExoticComponent<React.ForwardRefExoticComponent<Omit<InteractiveNvlWrapperProps & HTMLProps<HTMLDivElement>, "ref"> & React.RefAttributes<NVL>>>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef, memo, useCallback, useRef, useState } from 'react';
|
|
3
|
-
import { BasicNvlWrapper } from '../basic-wrapper/BasicNvlWrapper';
|
|
4
|
-
import { INTERACTIVE_WRAPPER_ID } from '../utils/constants';
|
|
5
|
-
import { InteractionHandlers } from './InteractionHandlers';
|
|
6
|
-
const options = {
|
|
7
|
-
selectOnClick: false,
|
|
8
|
-
drawShadowOnHover: true,
|
|
9
|
-
selectOnRelease: false,
|
|
10
|
-
excludeNodeMargin: true
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* The interactive React wrapper component contains a collection of interaction handlers by default
|
|
14
|
-
* and provides a variety of common functionality and callbacks.
|
|
15
|
-
* It is an extension of the {@link BasicNvlWrapper} component and incorporates the
|
|
16
|
-
* @neo4j-nvl/interaction-handlers module's decorators to provide a set of interaction events.
|
|
17
|
-
*
|
|
18
|
-
* The mouseEventCallbacks property takes an object where various callbacks can be defined
|
|
19
|
-
* and behavior can be toggled on and off.
|
|
20
|
-
*
|
|
21
|
-
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/react-wrappers/#_interactive_reactive_wrapperr Interactive React wrapper documentation page}.
|
|
22
|
-
*/
|
|
23
|
-
export const InteractiveNvlWrapper = memo(forwardRef(({ nodes, rels, layout, layoutOptions, onInitializationError, mouseEventCallbacks = {}, nvlCallbacks = {}, nvlOptions = {}, interactionOptions = options, ...nvlEvents }, nvlRef) => {
|
|
24
|
-
const newNvlRef = useRef(null);
|
|
25
|
-
const myNvlRef = nvlRef ?? newNvlRef;
|
|
26
|
-
const [isNvlInitialized, setIsNvlInitialized] = useState(false);
|
|
27
|
-
const handleInitialization = useCallback(() => {
|
|
28
|
-
setIsNvlInitialized(true);
|
|
29
|
-
}, []);
|
|
30
|
-
const handleInitializationError = useCallback((error) => {
|
|
31
|
-
setIsNvlInitialized(false);
|
|
32
|
-
if (onInitializationError) {
|
|
33
|
-
onInitializationError(error);
|
|
34
|
-
}
|
|
35
|
-
}, [onInitializationError]);
|
|
36
|
-
const setupInteractions = isNvlInitialized && myNvlRef.current !== null;
|
|
37
|
-
return (_jsxs(_Fragment, { children: [_jsx(BasicNvlWrapper, { ref: myNvlRef, nodes: nodes, id: INTERACTIVE_WRAPPER_ID, rels: rels, nvlOptions: nvlOptions, nvlCallbacks: {
|
|
38
|
-
...nvlCallbacks,
|
|
39
|
-
onInitialization: () => {
|
|
40
|
-
if (nvlCallbacks.onInitialization !== undefined) {
|
|
41
|
-
nvlCallbacks.onInitialization();
|
|
42
|
-
}
|
|
43
|
-
handleInitialization();
|
|
44
|
-
}
|
|
45
|
-
}, layout: layout, layoutOptions: layoutOptions, onInitializationError: handleInitializationError, ...nvlEvents }), setupInteractions && (_jsx(InteractionHandlers, { nvlRef: myNvlRef, mouseEventCallbacks: mouseEventCallbacks, interactionOptions: interactionOptions }))] }));
|
|
46
|
-
}));
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type NVL from '@neo4j-nvl/base';
|
|
2
|
-
import type { MutableRefObject } from 'react';
|
|
3
|
-
import type { InteractionOptions, MouseEvent, MouseInteraction, MouseInteractionModule } from './types';
|
|
4
|
-
export declare const destroyInteraction: (interactionRef: MutableRefObject<MouseInteraction | null>) => void;
|
|
5
|
-
export declare const useInteraction: (Interaction: MouseInteractionModule, interactionRef: MutableRefObject<MouseInteraction | null>, callback: boolean | ((...args: unknown[]) => void) | undefined, eventName: MouseEvent, nvlRef: MutableRefObject<NVL | null>, interactionOptions: InteractionOptions) => void;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { isNil } from 'lodash';
|
|
2
|
-
import { useEffect } from 'react';
|
|
3
|
-
export const destroyInteraction = (interactionRef) => {
|
|
4
|
-
interactionRef.current?.destroy();
|
|
5
|
-
interactionRef.current = null;
|
|
6
|
-
};
|
|
7
|
-
export const useInteraction = (Interaction, interactionRef, callback, eventName, nvlRef, interactionOptions) => {
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
const nvl = nvlRef.current;
|
|
10
|
-
// Make sure we are not mounting interaction handlers when there is NVL setup
|
|
11
|
-
if (isNil(nvl) || isNil(nvl.getContainer())) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
if (callback === true || typeof callback === 'function') {
|
|
15
|
-
if (isNil(interactionRef.current)) {
|
|
16
|
-
interactionRef.current = new Interaction(nvl, interactionOptions);
|
|
17
|
-
}
|
|
18
|
-
if (typeof callback === 'function') {
|
|
19
|
-
interactionRef.current.updateCallback(eventName, callback);
|
|
20
|
-
}
|
|
21
|
-
else if (!isNil(interactionRef.current.callbackMap[eventName])) {
|
|
22
|
-
interactionRef.current.removeCallback(eventName);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
else if (callback === false) {
|
|
26
|
-
destroyInteraction(interactionRef);
|
|
27
|
-
}
|
|
28
|
-
}, [Interaction, callback, eventName, interactionOptions, interactionRef, nvlRef]);
|
|
29
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { BoxSelectInteraction, BoxSelectInteractionCallbacks, BoxSelectInteractionOptions, ClickInteraction, ClickInteractionCallbacks, ClickInteractionOptions, DragNodeInteraction, DragNodeInteractionCallbacks, DrawInteraction, DrawInteractionCallbacks, DrawInteractionOptions, HoverInteraction, HoverInteractionCallbacks, HoverInteractionOptions, LassoInteraction, LassoInteractionCallbacks, LassoInteractionOptions, PanInteraction, PanInteractionCallbacks, PanInteractionOptions, ZoomInteraction, ZoomInteractionCallbacks } from '@neo4j-nvl/interaction-handlers';
|
|
2
|
-
import type { BasicReactWrapperProps } from '../basic-wrapper/BasicNvlWrapper';
|
|
3
|
-
export type MouseInteractionModule = typeof HoverInteraction | typeof ClickInteraction | typeof PanInteraction | typeof ZoomInteraction | typeof DragNodeInteraction | typeof DrawInteraction | typeof BoxSelectInteraction | typeof LassoInteraction;
|
|
4
|
-
export type MouseInteraction = HoverInteraction | ClickInteraction | PanInteraction | ZoomInteraction | DragNodeInteraction | DrawInteraction | BoxSelectInteraction | LassoInteraction;
|
|
5
|
-
/**
|
|
6
|
-
* Collection of mouse event callbacks that can be used with
|
|
7
|
-
* the {@link InteractiveNvlWrapper} component.
|
|
8
|
-
*/
|
|
9
|
-
export type MouseEventCallbacks = ClickInteractionCallbacks & DragNodeInteractionCallbacks & HoverInteractionCallbacks & PanInteractionCallbacks & ZoomInteractionCallbacks & BoxSelectInteractionCallbacks & DrawInteractionCallbacks & LassoInteractionCallbacks;
|
|
10
|
-
/**
|
|
11
|
-
* Collection of interaction options that can be used with
|
|
12
|
-
* the {@link InteractiveNvlWrapper} component.
|
|
13
|
-
*/
|
|
14
|
-
export type InteractionOptions = ClickInteractionOptions & BoxSelectInteractionOptions & HoverInteractionOptions & PanInteractionOptions & LassoInteractionOptions & DrawInteractionOptions;
|
|
15
|
-
/**
|
|
16
|
-
* The events that can be passed to the {@link MouseEventCallbacks} object
|
|
17
|
-
* to turn on/off certain events for the {@link InteractiveNvlWrapper} component.
|
|
18
|
-
*/
|
|
19
|
-
export type MouseEvent = keyof MouseEventCallbacks;
|
|
20
|
-
/**
|
|
21
|
-
* The properties that can be passed to the {@link InteractiveNvlWrapper} component.
|
|
22
|
-
*/
|
|
23
|
-
export interface InteractiveNvlWrapperProps extends BasicReactWrapperProps {
|
|
24
|
-
/** {@link MouseEventCallbacks} containing functions for callbacks on certain actions */
|
|
25
|
-
mouseEventCallbacks?: MouseEventCallbacks;
|
|
26
|
-
/** {@link InteractionOptions} for the underlying interaction handlers */
|
|
27
|
-
interactionOptions?: InteractionOptions;
|
|
28
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib/utils/constants.d.ts
DELETED
package/lib/utils/constants.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Node, Relationship } from '@neo4j-nvl/base';
|
|
2
|
-
declare const getMapDifferences: <T extends Node | Relationship>(prevGraphElements: T[], newGraphElements: T[]) => {
|
|
3
|
-
added: T[];
|
|
4
|
-
removed: T[];
|
|
5
|
-
updated: T[];
|
|
6
|
-
};
|
|
7
|
-
declare const getNodeAttributeDifferences: (prevNodes: Node[], newNodes: Node[]) => Node[];
|
|
8
|
-
export { getNodeAttributeDifferences, getMapDifferences };
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { isEqual, isNil, keyBy, keys, sortBy, transform } from 'lodash';
|
|
2
|
-
const getMapDifferences = (prevGraphElements, newGraphElements) => {
|
|
3
|
-
const prevMap = keyBy(prevGraphElements, 'id');
|
|
4
|
-
const currentMap = keyBy(newGraphElements, 'id');
|
|
5
|
-
const prevIds = sortBy(keys(prevMap));
|
|
6
|
-
const currentIds = sortBy(keys(currentMap));
|
|
7
|
-
const added = [];
|
|
8
|
-
const removed = [];
|
|
9
|
-
const updated = [];
|
|
10
|
-
let i = 0;
|
|
11
|
-
let j = 0;
|
|
12
|
-
while (i < prevIds.length && j < currentIds.length) {
|
|
13
|
-
const prevId = prevIds[i];
|
|
14
|
-
const currId = currentIds[j];
|
|
15
|
-
if (prevId === undefined || currId === undefined) {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
if (prevId === currId) {
|
|
19
|
-
if (!isEqual(prevMap[prevId], currentMap[currId])) {
|
|
20
|
-
updated.push(currId);
|
|
21
|
-
}
|
|
22
|
-
i += 1;
|
|
23
|
-
j += 1;
|
|
24
|
-
}
|
|
25
|
-
else if (prevId < currId) {
|
|
26
|
-
removed.push(prevId);
|
|
27
|
-
i += 1;
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
added.push(currId);
|
|
31
|
-
j += 1;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
while (i < prevIds.length) {
|
|
35
|
-
const prevId = prevIds[i];
|
|
36
|
-
if (prevId === undefined) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
removed.push(prevId);
|
|
40
|
-
i += 1;
|
|
41
|
-
}
|
|
42
|
-
while (j < currentIds.length) {
|
|
43
|
-
const currId = currentIds[j];
|
|
44
|
-
if (currId === undefined) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
added.push(currId);
|
|
48
|
-
j += 1;
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
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))
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
const getNodeAttributeDifferences = (prevNodes, newNodes) => {
|
|
57
|
-
const prevNodeMap = keyBy(prevNodes, 'id');
|
|
58
|
-
return newNodes
|
|
59
|
-
.map((nodeToUpdate) => {
|
|
60
|
-
const previousNode = prevNodeMap[nodeToUpdate.id];
|
|
61
|
-
if (previousNode === undefined) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
return transform(nodeToUpdate, (result, value, key) => {
|
|
65
|
-
if (key === 'id' || value !== previousNode[key]) {
|
|
66
|
-
Object.assign(result, { [key]: value });
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
})
|
|
70
|
-
.filter((n) => n !== null && Object.keys(n).length > 1);
|
|
71
|
-
};
|
|
72
|
-
export { getNodeAttributeDifferences, getMapDifferences };
|
package/lib/utils/hooks.d.ts
DELETED
package/lib/utils/hooks.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { isEqual } from 'lodash';
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
-
function deepCompareEquals(a, b) {
|
|
4
|
-
return isEqual(a, b);
|
|
5
|
-
}
|
|
6
|
-
function useDeepCompareMemoize(value) {
|
|
7
|
-
const ref = useRef();
|
|
8
|
-
if (!deepCompareEquals(value, ref.current)) {
|
|
9
|
-
ref.current = value;
|
|
10
|
-
}
|
|
11
|
-
return ref.current;
|
|
12
|
-
}
|
|
13
|
-
export const useDeepCompareEffect = (callback, dependencies) => {
|
|
14
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15
|
-
useEffect(callback, dependencies.map(useDeepCompareMemoize));
|
|
16
|
-
};
|