@neo4j-nvl/interaction-handlers 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 (49) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +8 -0
  3. package/lib/constants.d.ts +1 -1
  4. package/lib/constants.js +4 -2
  5. package/lib/index.d.ts +10 -20
  6. package/lib/index.js +10 -10
  7. package/lib/interaction-handlers/base.d.ts +67 -67
  8. package/lib/interaction-handlers/base.js +98 -104
  9. package/lib/interaction-handlers/box-select-interaction.d.ts +44 -44
  10. package/lib/interaction-handlers/box-select-interaction.js +133 -127
  11. package/lib/interaction-handlers/click-interaction.d.ts +111 -111
  12. package/lib/interaction-handlers/click-interaction.js +116 -131
  13. package/lib/interaction-handlers/drag-node-interaction.d.ts +40 -40
  14. package/lib/interaction-handlers/drag-node-interaction.js +102 -111
  15. package/lib/interaction-handlers/draw-interaction.d.ts +37 -37
  16. package/lib/interaction-handlers/draw-interaction.js +245 -278
  17. package/lib/interaction-handlers/hover-interaction.d.ts +34 -30
  18. package/lib/interaction-handlers/hover-interaction.js +83 -89
  19. package/lib/interaction-handlers/keyboard-interaction.d.ts +149 -97
  20. package/lib/interaction-handlers/keyboard-interaction.js +255 -201
  21. package/lib/interaction-handlers/lasso-interaction.d.ts +45 -45
  22. package/lib/interaction-handlers/lasso-interaction.js +174 -196
  23. package/lib/interaction-handlers/pan-interaction.d.ts +62 -61
  24. package/lib/interaction-handlers/pan-interaction.js +111 -100
  25. package/lib/interaction-handlers/utils.d.ts +2 -2
  26. package/lib/interaction-handlers/utils.js +39 -38
  27. package/lib/interaction-handlers/zoom-interaction.d.ts +52 -48
  28. package/lib/interaction-handlers/zoom-interaction.js +73 -71
  29. package/lib/overlay-renderer/overlay-renderer.d.ts +13 -13
  30. package/lib/overlay-renderer/overlay-renderer.js +96 -111
  31. package/package.json +19 -6
  32. package/lib/__tests__/box-select-interaction.test.d.ts +0 -1
  33. package/lib/__tests__/box-select-interaction.test.js +0 -149
  34. package/lib/__tests__/click-interaction.test.d.ts +0 -1
  35. package/lib/__tests__/click-interaction.test.js +0 -505
  36. package/lib/__tests__/drag-node-interaction.test.d.ts +0 -1
  37. package/lib/__tests__/drag-node-interaction.test.js +0 -247
  38. package/lib/__tests__/hover-interaction.test.d.ts +0 -1
  39. package/lib/__tests__/hover-interaction.test.js +0 -374
  40. package/lib/__tests__/keyboard-interaction.test.d.ts +0 -1
  41. package/lib/__tests__/keyboard-interaction.test.js +0 -322
  42. package/lib/__tests__/lasso-interaction.test.d.ts +0 -1
  43. package/lib/__tests__/lasso-interaction.test.js +0 -219
  44. package/lib/__tests__/pan-interaction.test.d.ts +0 -1
  45. package/lib/__tests__/pan-interaction.test.js +0 -223
  46. package/lib/__tests__/utils.test.d.ts +0 -1
  47. package/lib/__tests__/utils.test.js +0 -19
  48. package/lib/__tests__/zoom-interaction.test.d.ts +0 -1
  49. package/lib/__tests__/zoom-interaction.test.js +0 -185
@@ -1,207 +1,261 @@
1
- import { BaseInteraction } from './base';
1
+ import { BaseInteraction } from "./base.js";
2
+ // src/interaction-handlers/keyboard-interaction.ts
2
3
  const DEFAULT_OPTIONS = {
3
- enterGraphKey: ['Enter'],
4
- navigateForwardKey: ['Tab'],
5
- navigateBackwardKey: ['Shift', 'Tab'],
6
- exitGraphKey: ['Escape'],
7
- contextMenuKey: ['Shift', 'F10'],
8
- canvasOutlineColor: '#30839D'
4
+ enterGraphKey: ["Enter"],
5
+ navigateForwardKey: ["Tab"],
6
+ navigateBackwardKey: ["Shift", "Tab"],
7
+ exitGraphKey: ["Escape"],
8
+ contextMenuKey: ["Shift", "F10"],
9
+ moveUpKey: ["ArrowUp"],
10
+ moveDownKey: ["ArrowDown"],
11
+ moveLeftKey: ["ArrowLeft"],
12
+ moveRightKey: ["ArrowRight"],
13
+ moveStep: 5,
14
+ largeMoveStep: 50,
15
+ largeMoveStepModifier: "Shift",
16
+ canvasOutlineColor: "#30839D"
9
17
  };
10
18
  /**
11
- * Checks whether a keyboard event matches a key combo array.
12
- * The last element is the primary key (`event.key`), preceding elements are modifiers.
13
- * Examples: `['Tab']`, `['Shift', 'Tab']`, `['Shift', 'F10']`
14
- */
19
+ * Checks whether a keyboard event matches a key combo array.
20
+ * The last element is the primary key (`event.key`), preceding elements are modifiers.
21
+ * Examples: `['Tab']`, `['Shift', 'Tab']`, `['Shift', 'F10']`
22
+ */
15
23
  const matchesKeyCombo = (event, keyCombo) => {
16
- const key = keyCombo[keyCombo.length - 1];
17
- const requireShift = keyCombo.includes('Shift');
18
- const requireCtrl = keyCombo.includes('Ctrl');
19
- const requireAlt = keyCombo.includes('Alt');
20
- const requireMeta = keyCombo.includes('Meta');
21
- return (event.key === key &&
22
- event.shiftKey === requireShift &&
23
- event.ctrlKey === requireCtrl &&
24
- event.altKey === requireAlt &&
25
- event.metaKey === requireMeta);
24
+ const key = keyCombo[keyCombo.length - 1];
25
+ const requireShift = keyCombo.includes("Shift");
26
+ const requireCtrl = keyCombo.includes("Ctrl");
27
+ const requireAlt = keyCombo.includes("Alt");
28
+ const requireMeta = keyCombo.includes("Meta");
29
+ return event.key === key && event.shiftKey === requireShift && event.ctrlKey === requireCtrl && event.altKey === requireAlt && event.metaKey === requireMeta;
26
30
  };
27
31
  /**
28
- * Opinionated interaction handler for keyboard-driven focus navigation
29
- * through graph elements (nodes and relationships).
30
- *
31
- * By default, Tab / Shift+Tab cycle focus through elements, Escape exits the
32
- * graph, and Shift+F10 call the `onContextMenu` callback with the focused element.
33
- * All keys can be reconfigured via {@link KeyboardInteractionOptions}.
34
- *
35
- * Callbacks are fired for focus/blur transitions and context-menu activation,
36
- * following the same one-way data-flow pattern as the other interaction handlers.
37
- */
38
- export class KeyboardInteraction extends BaseInteraction {
39
- focusedElementId = undefined;
40
- focusedElementIsNode = undefined;
41
- focusableElements = [];
42
- addedTabindex = false;
43
- resolvedOptions;
44
- /**
45
- * Creates a new keyboard interaction handler.
46
- * @param nvl - The NVL instance to attach the interaction handler to.
47
- * @param options - Options for the keyboard interaction handler.
48
- */
49
- constructor(nvl, options = {}) {
50
- super(nvl, options);
51
- this.resolvedOptions = { ...DEFAULT_OPTIONS, ...options };
52
- // Ensure the container is focusable for keyboard events
53
- const tabindex = this.containerInstance.getAttribute('tabindex');
54
- if (tabindex === null || tabindex === '') {
55
- this.containerInstance.setAttribute('tabindex', '0');
56
- this.addedTabindex = true;
57
- }
58
- this.addEventListener('keydown', this.handleKeyDown);
59
- this.addEventListener('keyup', this.handleKeyUp);
60
- this.addEventListener('focusin', this.handleFocusIn);
61
- this.addEventListener('focusout', this.handleFocusOut);
62
- }
63
- buildFocusableElements() {
64
- const nodes = this.nvlInstance.getNodes();
65
- const relationships = this.nvlInstance.getRelationships();
66
- this.focusableElements = [
67
- ...nodes.map((node) => ({ id: node.id, isNode: true })),
68
- ...relationships.map((rel) => ({ id: rel.id, isNode: false }))
69
- ];
70
- }
71
- /**
72
- * Returns the currently focused element, if any.
73
- */
74
- getFocused() {
75
- if (this.focusedElementId === undefined) {
76
- return undefined;
77
- }
78
- if (this.focusedElementIsNode === true) {
79
- return this.nvlInstance.getNodes().find((n) => n.id === this.focusedElementId);
80
- }
81
- return this.nvlInstance.getRelationships().find((r) => r.id === this.focusedElementId);
82
- }
83
- setCanvasOutline() {
84
- const container = this.containerInstance;
85
- if (container.matches(':focus-visible')) {
86
- container.style.outline = `2px solid ${this.resolvedOptions.canvasOutlineColor}`;
87
- container.style.outlineOffset = '-2px';
88
- }
89
- }
90
- clearCanvasOutline() {
91
- const container = this.containerInstance;
92
- container.style.outline = 'none';
93
- container.style.outlineOffset = '';
94
- }
95
- handleFocusIn = (event) => {
96
- this.setCanvasOutline();
97
- this.callCallbackIfRegistered('onCanvasFocus', event);
98
- };
99
- handleFocusOut = (event) => {
100
- this.callCallbackIfRegistered('onCanvasBlur', event);
101
- this.clearCanvasOutline();
102
- };
103
- handleKeyDown = (event) => {
104
- const focusedElement = this.getFocused();
105
- this.callCallbackIfRegistered('onKeyDown', event, focusedElement);
106
- const { enterGraphKey, navigateForwardKey, navigateBackwardKey, exitGraphKey, contextMenuKey } = this.resolvedOptions;
107
- if (matchesKeyCombo(event, enterGraphKey)) {
108
- if (focusedElement === undefined) {
109
- event.preventDefault();
110
- this.navigateFocus(1, event);
111
- }
112
- }
113
- else if (matchesKeyCombo(event, navigateForwardKey)) {
114
- if (focusedElement !== undefined) {
115
- event.preventDefault();
116
- this.navigateFocus(1, event);
117
- }
118
- }
119
- else if (matchesKeyCombo(event, navigateBackwardKey)) {
120
- if (focusedElement !== undefined) {
121
- event.preventDefault();
122
- this.navigateFocus(-1, event);
123
- }
124
- }
125
- else if (matchesKeyCombo(event, exitGraphKey)) {
126
- this.setCanvasOutline();
127
- if (focusedElement !== undefined) {
128
- event.preventDefault();
129
- this.clearFocus(event);
130
- }
131
- }
132
- else if (matchesKeyCombo(event, contextMenuKey)) {
133
- event.preventDefault();
134
- this.callCallbackIfRegistered('onContextMenu', focusedElement, event);
135
- }
136
- };
137
- handleKeyUp = (event) => {
138
- const focusedElement = this.getFocused();
139
- this.callCallbackIfRegistered('onKeyUp', event, focusedElement);
140
- };
141
- navigateFocus(direction, event) {
142
- this.buildFocusableElements();
143
- if (this.focusableElements.length === 0) {
144
- return;
145
- }
146
- const currentIndex = this.focusedElementId !== undefined
147
- ? this.focusableElements.findIndex((el) => el.id === this.focusedElementId && el.isNode === this.focusedElementIsNode)
148
- : -1;
149
- let nextIndex;
150
- if (currentIndex === -1) {
151
- nextIndex = direction === 1 ? 0 : this.focusableElements.length - 1;
152
- }
153
- else {
154
- nextIndex = (currentIndex + direction + this.focusableElements.length) % this.focusableElements.length;
155
- }
156
- const nextElement = this.focusableElements[nextIndex];
157
- if (nextElement) {
158
- this.setFocus(nextElement.id, nextElement.isNode, event);
159
- }
160
- }
161
- setFocus(elementId, isNode, event) {
162
- this.clearFocus(event);
163
- // Update focus state
164
- this.focusedElementId = elementId;
165
- this.focusedElementIsNode = isNode;
166
- // Notify about the newly focused element
167
- const newElement = this.getFocused();
168
- if (newElement !== undefined) {
169
- this.clearCanvasOutline();
170
- if (isNode) {
171
- this.callCallbackIfRegistered('onNodeFocus', newElement, event);
172
- }
173
- else {
174
- this.callCallbackIfRegistered('onRelationshipFocus', newElement, event);
175
- }
176
- }
177
- }
178
- clearFocus(event) {
179
- const previousElement = this.getFocused();
180
- if (previousElement !== undefined) {
181
- if (this.focusedElementIsNode === true) {
182
- this.callCallbackIfRegistered('onNodeBlur', previousElement, event);
183
- }
184
- else {
185
- this.callCallbackIfRegistered('onRelationshipBlur', previousElement, event);
186
- }
187
- }
188
- this.focusedElementId = undefined;
189
- this.focusedElementIsNode = undefined;
190
- }
191
- /**
192
- * Removes all related event listeners from the container.
193
- */
194
- destroy() {
195
- this.removeEventListener('keydown', this.handleKeyDown);
196
- this.removeEventListener('keyup', this.handleKeyUp);
197
- this.removeEventListener('focusin', this.handleFocusIn);
198
- this.removeEventListener('focusout', this.handleFocusOut);
199
- this.clearCanvasOutline();
200
- if (this.addedTabindex) {
201
- this.containerInstance.removeAttribute('tabindex');
202
- }
203
- this.focusedElementId = undefined;
204
- this.focusedElementIsNode = undefined;
205
- this.focusableElements = [];
206
- }
207
- }
32
+ * Nodes without layout coordinates cannot be moved by a relative offset.
33
+ */
34
+ const hasPosition = (node) => node.x !== void 0 && node.y !== void 0;
35
+ /**
36
+ * Opinionated interaction handler for keyboard-driven focus navigation
37
+ * through graph elements (nodes and relationships).
38
+ *
39
+ * By default, Tab / Shift+Tab cycle focus through elements, Escape exits the
40
+ * graph, and Shift+F10 call the `onContextMenu` callback with the focused element.
41
+ * While a node is focused, the arrow keys move the selected node(s), or the focused
42
+ * node when nothing is selected, by `moveStep` screen pixels - or by `largeMoveStep`
43
+ * while the large step modifier (Shift by default) is held.
44
+ * All keys can be reconfigured via {@link KeyboardInteractionOptions}.
45
+ *
46
+ * Callbacks are fired for focus/blur transitions and context-menu activation,
47
+ * following the same one-way data-flow pattern as the other interaction handlers.
48
+ */
49
+ var KeyboardInteraction = class extends BaseInteraction {
50
+ focusedElementId = void 0;
51
+ focusedElementIsNode = void 0;
52
+ focusableElements = [];
53
+ addedTabindex = false;
54
+ resolvedOptions;
55
+ /**
56
+ * Creates a new keyboard interaction handler.
57
+ * @param nvl - The NVL instance to attach the interaction handler to.
58
+ * @param options - Options for the keyboard interaction handler.
59
+ */
60
+ constructor(nvl, options = {}) {
61
+ super(nvl, options);
62
+ this.resolvedOptions = {
63
+ ...DEFAULT_OPTIONS,
64
+ ...options
65
+ };
66
+ const tabindex = this.containerInstance.getAttribute("tabindex");
67
+ if (tabindex === null || tabindex === "") {
68
+ this.containerInstance.setAttribute("tabindex", "0");
69
+ this.addedTabindex = true;
70
+ }
71
+ this.addEventListener("keydown", this.handleKeyDown);
72
+ this.addEventListener("keyup", this.handleKeyUp);
73
+ this.addEventListener("focusin", this.handleFocusIn);
74
+ this.addEventListener("focusout", this.handleFocusOut);
75
+ }
76
+ buildFocusableElements() {
77
+ const nodes = this.nvlInstance.getNodes();
78
+ const relationships = this.nvlInstance.getRelationships();
79
+ this.focusableElements = [...nodes.map((node) => ({
80
+ id: node.id,
81
+ isNode: true
82
+ })), ...relationships.map((rel) => ({
83
+ id: rel.id,
84
+ isNode: false
85
+ }))];
86
+ }
87
+ /**
88
+ * Returns the currently focused element, if any.
89
+ */
90
+ getFocused() {
91
+ if (this.focusedElementId === void 0) return;
92
+ if (this.focusedElementIsNode === true) return this.nvlInstance.getNodes().find((n) => n.id === this.focusedElementId);
93
+ return this.nvlInstance.getRelationships().find((r) => r.id === this.focusedElementId);
94
+ }
95
+ setCanvasOutline() {
96
+ const container = this.containerInstance;
97
+ if (container.matches(":focus-visible")) {
98
+ container.style.outline = `2px solid ${this.resolvedOptions.canvasOutlineColor}`;
99
+ container.style.outlineOffset = "-2px";
100
+ }
101
+ }
102
+ clearCanvasOutline() {
103
+ const container = this.containerInstance;
104
+ container.style.outline = "none";
105
+ container.style.outlineOffset = "";
106
+ }
107
+ handleFocusIn = (event) => {
108
+ this.setCanvasOutline();
109
+ this.callCallbackIfRegistered("onCanvasFocus", event);
110
+ };
111
+ handleFocusOut = (event) => {
112
+ this.callCallbackIfRegistered("onCanvasBlur", event);
113
+ this.clearCanvasOutline();
114
+ };
115
+ handleKeyDown = (event) => {
116
+ const focusedElement = this.getFocused();
117
+ this.callCallbackIfRegistered("onKeyDown", event, focusedElement);
118
+ const { enterGraphKey, navigateForwardKey, navigateBackwardKey, exitGraphKey, contextMenuKey } = this.resolvedOptions;
119
+ if (matchesKeyCombo(event, enterGraphKey)) {
120
+ if (focusedElement === void 0) {
121
+ event.preventDefault();
122
+ this.navigateFocus(1, event);
123
+ }
124
+ } else if (matchesKeyCombo(event, navigateForwardKey)) {
125
+ if (focusedElement !== void 0) {
126
+ event.preventDefault();
127
+ this.navigateFocus(1, event);
128
+ }
129
+ } else if (matchesKeyCombo(event, navigateBackwardKey)) {
130
+ if (focusedElement !== void 0) {
131
+ event.preventDefault();
132
+ this.navigateFocus(-1, event);
133
+ }
134
+ } else if (matchesKeyCombo(event, exitGraphKey)) {
135
+ this.setCanvasOutline();
136
+ if (focusedElement !== void 0) {
137
+ event.preventDefault();
138
+ this.clearFocus(event);
139
+ }
140
+ } else if (matchesKeyCombo(event, contextMenuKey)) {
141
+ event.preventDefault();
142
+ this.callCallbackIfRegistered("onContextMenu", focusedElement, event);
143
+ } else this.handleMoveKeys(event);
144
+ };
145
+ /**
146
+ * Moves the nodes to be moved when the event matches one of the move key combos,
147
+ * either by `moveStep` or, with the large step modifier held, by `largeMoveStep`.
148
+ *
149
+ * The step is given in screen pixels and converted to graph coordinates using the
150
+ * current zoom level, the same way the drag interaction converts pointer
151
+ * movement, so keyboard and pointer moves cover the same visible distance.
152
+ */
153
+ handleMoveKeys(event) {
154
+ const { moveUpKey, moveDownKey, moveLeftKey, moveRightKey, moveStep, largeMoveStep, largeMoveStepModifier } = this.resolvedOptions;
155
+ const direction = [
156
+ {
157
+ keyCombo: moveUpKey,
158
+ x: 0,
159
+ y: -1
160
+ },
161
+ {
162
+ keyCombo: moveDownKey,
163
+ x: 0,
164
+ y: 1
165
+ },
166
+ {
167
+ keyCombo: moveLeftKey,
168
+ x: -1,
169
+ y: 0
170
+ },
171
+ {
172
+ keyCombo: moveRightKey,
173
+ x: 1,
174
+ y: 0
175
+ }
176
+ ].find(({ keyCombo }) => matchesKeyCombo(event, keyCombo) || matchesKeyCombo(event, [largeMoveStepModifier, ...keyCombo]));
177
+ if (direction === void 0) return;
178
+ const graphStep = (matchesKeyCombo(event, direction.keyCombo) ? moveStep : largeMoveStep) / this.nvlInstance.getScale() * window.devicePixelRatio;
179
+ this.moveNodes(direction.x * graphStep, direction.y * graphStep, event);
180
+ }
181
+ /**
182
+ * Returns the nodes a move key applies to: the selected nodes, or the focused
183
+ * node when nothing is selected.
184
+ *
185
+ * A node must be focused for any of them to move, so move keys are inert until
186
+ * the graph has been entered, and a focused relationship blocks moving entirely.
187
+ */
188
+ getNodesToMove() {
189
+ if (this.focusedElementId === void 0 || this.focusedElementIsNode !== true) return [];
190
+ const selectedNodes = this.nvlInstance.getSelectedNodes();
191
+ if (selectedNodes.length > 0) return selectedNodes.filter(hasPosition);
192
+ return this.nvlInstance.getNodes().filter((node) => node.id === this.focusedElementId).filter(hasPosition);
193
+ }
194
+ moveNodes(dx, dy, event) {
195
+ const nodesToMove = this.getNodesToMove();
196
+ if (nodesToMove.length === 0) return;
197
+ event.preventDefault();
198
+ const movedNodes = nodesToMove.map((node) => ({
199
+ ...node,
200
+ x: node.x + dx,
201
+ y: node.y + dy,
202
+ pinned: true
203
+ }));
204
+ this.nvlInstance.setNodePositions(movedNodes.map(({ id, x, y, pinned }) => ({
205
+ id,
206
+ x,
207
+ y,
208
+ pinned
209
+ })), true);
210
+ this.callCallbackIfRegistered("onNodeMove", movedNodes, event);
211
+ }
212
+ handleKeyUp = (event) => {
213
+ const focusedElement = this.getFocused();
214
+ this.callCallbackIfRegistered("onKeyUp", event, focusedElement);
215
+ };
216
+ navigateFocus(direction, event) {
217
+ this.buildFocusableElements();
218
+ if (this.focusableElements.length === 0) return;
219
+ const currentIndex = this.focusedElementId !== void 0 ? this.focusableElements.findIndex((el) => el.id === this.focusedElementId && el.isNode === this.focusedElementIsNode) : -1;
220
+ let nextIndex;
221
+ if (currentIndex === -1) nextIndex = direction === 1 ? 0 : this.focusableElements.length - 1;
222
+ else nextIndex = (currentIndex + direction + this.focusableElements.length) % this.focusableElements.length;
223
+ const nextElement = this.focusableElements[nextIndex];
224
+ if (nextElement) this.setFocus(nextElement.id, nextElement.isNode, event);
225
+ }
226
+ setFocus(elementId, isNode, event) {
227
+ this.clearFocus(event);
228
+ this.focusedElementId = elementId;
229
+ this.focusedElementIsNode = isNode;
230
+ const newElement = this.getFocused();
231
+ if (newElement !== void 0) {
232
+ this.clearCanvasOutline();
233
+ if (isNode) this.callCallbackIfRegistered("onNodeFocus", newElement, event);
234
+ else this.callCallbackIfRegistered("onRelationshipFocus", newElement, event);
235
+ }
236
+ }
237
+ clearFocus(event) {
238
+ const previousElement = this.getFocused();
239
+ if (previousElement !== void 0) {
240
+ if (this.focusedElementIsNode === true) this.callCallbackIfRegistered("onNodeBlur", previousElement, event);
241
+ else this.callCallbackIfRegistered("onRelationshipBlur", previousElement, event);
242
+ }
243
+ this.focusedElementId = void 0;
244
+ this.focusedElementIsNode = void 0;
245
+ }
246
+ /**
247
+ * Removes all related event listeners from the container.
248
+ */
249
+ destroy() {
250
+ this.removeEventListener("keydown", this.handleKeyDown);
251
+ this.removeEventListener("keyup", this.handleKeyUp);
252
+ this.removeEventListener("focusin", this.handleFocusIn);
253
+ this.removeEventListener("focusout", this.handleFocusOut);
254
+ this.clearCanvasOutline();
255
+ if (this.addedTabindex) this.containerInstance.removeAttribute("tabindex");
256
+ this.focusedElementId = void 0;
257
+ this.focusedElementIsNode = void 0;
258
+ this.focusableElements = [];
259
+ }
260
+ };
261
+ export { KeyboardInteraction };
@@ -1,33 +1,33 @@
1
- import type { NVL, Node, Point, Relationship } from '@neo4j-nvl/base';
2
- import { BaseInteraction } from './base';
1
+ import { BaseInteraction } from "./base.js";
2
+ import { NVL, Node, Point, Relationship } from "@neo4j-nvl/base";
3
3
  /**
4
4
  * Options for the lasso interaction handler to customize its behavior.
5
5
  */
6
6
  export type LassoInteractionOptions = {
7
- /**
8
- * If true, the selected items will be automatically selected when the gesture is finished.
9
- * @default false
10
- */
11
- selectOnRelease?: boolean;
7
+ /**
8
+ * If true, the selected items will be automatically selected when the gesture is finished.
9
+ * @default false
10
+ */
11
+ selectOnRelease?: boolean;
12
12
  };
13
13
  /**
14
14
  * Callbacks for the lasso interaction handler.
15
15
  */
16
16
  export type LassoInteractionCallbacks = {
17
- /**
18
- * Called once when the user presses the mouse on the canvas, starting the lasso.
19
- * @param event - The original mouse event.
20
- */
21
- onLassoStarted?: ((event: MouseEvent) => void) | boolean;
22
- /**
23
- * Called once when the user releases the mouse after lasso selecting.
24
- * @param selectionObject - The selected nodes and relationships.
25
- * @param event - The original mouse event.
26
- */
27
- onLassoSelect?: (({ nodes, rels }: {
28
- nodes: Node[];
29
- rels: Relationship[];
30
- }, event: MouseEvent) => void) | boolean;
17
+ /**
18
+ * Called once when the user presses the mouse on the canvas, starting the lasso.
19
+ * @param event - The original mouse event.
20
+ */
21
+ onLassoStarted?: ((event: MouseEvent) => void) | boolean;
22
+ /**
23
+ * Called once when the user releases the mouse after lasso selecting.
24
+ * @param selectionObject - The selected nodes and relationships.
25
+ * @param event - The original mouse event.
26
+ */
27
+ onLassoSelect?: (({ nodes, rels }: {
28
+ nodes: Node[];
29
+ rels: Relationship[];
30
+ }, event: MouseEvent) => void) | boolean;
31
31
  };
32
32
  /**
33
33
  * @internal
@@ -59,27 +59,27 @@ export declare const checkPointInside: (x: number, y: number, vs: Point[]) => bo
59
59
  * For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_lassointeraction Lasso Interaction documentation page}.
60
60
  */
61
61
  export declare class LassoInteraction extends BaseInteraction<LassoInteractionOptions> {
62
- private active;
63
- private lassoPending;
64
- private startClientPosition;
65
- private pendingPointerCanvas;
66
- private points;
67
- private overlayRenderer;
68
- /**
69
- * Creates a new instance of the lasso interaction handler.
70
- * @param nvl - The NVL instance to attach the interaction handler to.
71
- * @param options - Options for the lasso interaction handler to customize its behavior.
72
- */
73
- constructor(nvl: NVL, options?: LassoInteractionOptions);
74
- private startLasso;
75
- private handleMouseDown;
76
- private handleDrag;
77
- private activateLasso;
78
- private handleMouseUp;
79
- private getLassoItems;
80
- private endLasso;
81
- /**
82
- * Removes all related event listeners and the overlay renderer for the box.
83
- */
84
- destroy(): void;
85
- }
62
+ private active;
63
+ private lassoPending;
64
+ private startClientPosition;
65
+ private pendingPointerCanvas;
66
+ private points;
67
+ private overlayRenderer;
68
+ /**
69
+ * Creates a new instance of the lasso interaction handler.
70
+ * @param nvl - The NVL instance to attach the interaction handler to.
71
+ * @param options - Options for the lasso interaction handler to customize its behavior.
72
+ */
73
+ constructor(nvl: NVL, options?: LassoInteractionOptions);
74
+ private startLasso;
75
+ private handleMouseDown;
76
+ private handleDrag;
77
+ private activateLasso;
78
+ private handleMouseUp;
79
+ private getLassoItems;
80
+ private endLasso;
81
+ /**
82
+ * Removes all related event listeners and the overlay renderer for the box.
83
+ */
84
+ destroy(): void;
85
+ }