@node-edit-utils/core 2.3.2 → 2.3.4

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 (136) hide show
  1. package/dist/lib/canvas/helpers/getCanvasContainerOrBody.d.ts +1 -0
  2. package/dist/lib/canvas/helpers/getCanvasWindowValue.d.ts +1 -1
  3. package/dist/lib/helpers/adjustForZoom.d.ts +1 -0
  4. package/dist/lib/helpers/createDragHandler.d.ts +69 -0
  5. package/dist/lib/helpers/getNodeProvider.d.ts +1 -0
  6. package/dist/lib/helpers/getNodeTools.d.ts +2 -0
  7. package/dist/lib/helpers/getViewportDimensions.d.ts +4 -0
  8. package/dist/lib/helpers/index.d.ts +9 -1
  9. package/dist/lib/helpers/parseTransform.d.ts +8 -0
  10. package/dist/lib/helpers/toggleClass.d.ts +1 -0
  11. package/dist/lib/viewport/label/getViewportLabelOverlay.d.ts +1 -0
  12. package/dist/lib/viewport/label/helpers/selectFirstViewportNode.d.ts +5 -0
  13. package/dist/lib/viewport/label/index.d.ts +5 -3
  14. package/dist/lib/viewport/label/isViewportDragging.d.ts +2 -0
  15. package/dist/lib/viewport/label/refreshViewportLabel.d.ts +8 -0
  16. package/dist/lib/viewport/label/removeViewportLabel.d.ts +5 -0
  17. package/dist/lib/viewport/label/setupViewportDrag.d.ts +1 -0
  18. package/dist/node-edit-utils.cjs.js +342 -280
  19. package/dist/node-edit-utils.esm.js +342 -280
  20. package/dist/node-edit-utils.umd.js +342 -280
  21. package/dist/node-edit-utils.umd.min.js +1 -1
  22. package/dist/styles.css +1 -1
  23. package/package.json +7 -2
  24. package/src/lib/canvas/createCanvasObserver.test.ts +242 -0
  25. package/src/lib/canvas/createCanvasObserver.ts +2 -2
  26. package/src/lib/canvas/disableCanvasKeyboard.test.ts +53 -0
  27. package/src/lib/canvas/disableCanvasKeyboard.ts +1 -1
  28. package/src/lib/canvas/disableCanvasTextMode.test.ts +53 -0
  29. package/src/lib/canvas/disableCanvasTextMode.ts +1 -1
  30. package/src/lib/canvas/enableCanvasKeyboard.test.ts +53 -0
  31. package/src/lib/canvas/enableCanvasKeyboard.ts +1 -1
  32. package/src/lib/canvas/enableCanvasTextMode.test.ts +53 -0
  33. package/src/lib/canvas/enableCanvasTextMode.ts +1 -1
  34. package/src/lib/canvas/helpers/applyCanvasState.test.ts +119 -0
  35. package/src/lib/canvas/helpers/applyCanvasState.ts +1 -1
  36. package/src/lib/canvas/helpers/getCanvasContainer.test.ts +62 -0
  37. package/src/lib/canvas/helpers/getCanvasContainerOrBody.test.ts +51 -0
  38. package/src/lib/canvas/helpers/getCanvasContainerOrBody.ts +6 -0
  39. package/src/lib/canvas/helpers/getCanvasWindowValue.test.ts +116 -0
  40. package/src/lib/canvas/helpers/getCanvasWindowValue.ts +2 -3
  41. package/src/lib/helpers/adjustForZoom.test.ts +65 -0
  42. package/src/lib/helpers/adjustForZoom.ts +4 -0
  43. package/src/lib/helpers/createDragHandler.test.ts +325 -0
  44. package/src/lib/helpers/createDragHandler.ts +171 -0
  45. package/src/lib/helpers/getNodeProvider.test.ts +71 -0
  46. package/src/lib/helpers/getNodeProvider.ts +4 -0
  47. package/src/lib/helpers/getNodeTools.test.ts +50 -0
  48. package/src/lib/helpers/getNodeTools.ts +6 -0
  49. package/src/lib/helpers/getViewportDimensions.test.ts +93 -0
  50. package/src/lib/helpers/getViewportDimensions.ts +7 -0
  51. package/src/lib/helpers/index.ts +9 -1
  52. package/src/lib/helpers/observer/connectMutationObserver.test.ts +127 -0
  53. package/src/lib/helpers/observer/connectResizeObserver.test.ts +147 -0
  54. package/src/lib/helpers/parseTransform.test.ts +117 -0
  55. package/src/lib/helpers/parseTransform.ts +9 -0
  56. package/src/lib/helpers/toggleClass.test.ts +71 -0
  57. package/src/lib/helpers/toggleClass.ts +9 -0
  58. package/src/lib/helpers/withRAF.test.ts +439 -0
  59. package/src/lib/node-tools/createNodeTools.test.ts +373 -0
  60. package/src/lib/node-tools/createNodeTools.ts +0 -1
  61. package/src/lib/node-tools/events/click/handleNodeClick.test.ts +109 -0
  62. package/src/lib/node-tools/events/setupEventListener.test.ts +136 -0
  63. package/src/lib/node-tools/highlight/clearHighlightFrame.test.ts +88 -0
  64. package/src/lib/node-tools/highlight/clearHighlightFrame.ts +2 -3
  65. package/src/lib/node-tools/highlight/createCornerHandles.test.ts +150 -0
  66. package/src/lib/node-tools/highlight/createHighlightFrame.test.ts +237 -0
  67. package/src/lib/node-tools/highlight/createHighlightFrame.ts +5 -9
  68. package/src/lib/node-tools/highlight/createTagLabel.test.ts +135 -0
  69. package/src/lib/node-tools/highlight/createToolsContainer.test.ts +97 -0
  70. package/src/lib/node-tools/highlight/createToolsContainer.ts +3 -6
  71. package/src/lib/node-tools/highlight/helpers/getElementBounds.test.ts +158 -0
  72. package/src/lib/node-tools/highlight/helpers/getElementBounds.ts +6 -5
  73. package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.test.ts +78 -0
  74. package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +2 -3
  75. package/src/lib/node-tools/highlight/helpers/getScreenBounds.test.ts +133 -0
  76. package/src/lib/node-tools/highlight/highlightNode.test.ts +213 -0
  77. package/src/lib/node-tools/highlight/highlightNode.ts +7 -15
  78. package/src/lib/node-tools/highlight/refreshHighlightFrame.test.ts +323 -0
  79. package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +12 -42
  80. package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.test.ts +110 -0
  81. package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.ts +2 -3
  82. package/src/lib/node-tools/select/helpers/getElementsFromPoint.test.ts +109 -0
  83. package/src/lib/node-tools/select/helpers/isInsideComponent.test.ts +81 -0
  84. package/src/lib/node-tools/select/helpers/isInsideViewport.test.ts +82 -0
  85. package/src/lib/node-tools/select/helpers/targetSameCandidates.test.ts +81 -0
  86. package/src/lib/node-tools/select/selectNode.test.ts +238 -0
  87. package/src/lib/node-tools/text/events/setupKeydownHandler.test.ts +91 -0
  88. package/src/lib/node-tools/text/events/setupMutationObserver.test.ts +213 -0
  89. package/src/lib/node-tools/text/events/setupNodeListeners.test.ts +133 -0
  90. package/src/lib/node-tools/text/helpers/enterTextEditMode.test.ts +50 -0
  91. package/src/lib/node-tools/text/helpers/handleTextChange.test.ts +201 -0
  92. package/src/lib/node-tools/text/helpers/hasTextContent.test.ts +101 -0
  93. package/src/lib/node-tools/text/helpers/insertLineBreak.test.ts +96 -0
  94. package/src/lib/node-tools/text/helpers/makeNodeEditable.test.ts +56 -0
  95. package/src/lib/node-tools/text/helpers/makeNodeNonEditable.test.ts +57 -0
  96. package/src/lib/node-tools/text/helpers/shouldEnterTextEditMode.test.ts +61 -0
  97. package/src/lib/node-tools/text/nodeText.test.ts +233 -0
  98. package/src/lib/post-message/processPostMessage.test.ts +218 -0
  99. package/src/lib/post-message/sendPostMessage.test.ts +120 -0
  100. package/src/lib/styles/styles.css +3 -3
  101. package/src/lib/viewport/createViewport.test.ts +267 -0
  102. package/src/lib/viewport/createViewport.ts +51 -51
  103. package/src/lib/viewport/events/setupEventListener.test.ts +103 -0
  104. package/src/lib/viewport/label/getViewportLabelOverlay.test.ts +77 -0
  105. package/src/lib/viewport/label/{getViewportLabelsOverlay.ts → getViewportLabelOverlay.ts} +6 -6
  106. package/src/lib/viewport/label/helpers/getLabelPosition.test.ts +51 -0
  107. package/src/lib/viewport/label/helpers/getLabelPosition.ts +3 -5
  108. package/src/lib/viewport/label/helpers/getTransformValues.test.ts +59 -0
  109. package/src/lib/viewport/label/helpers/getTransformValues.ts +3 -5
  110. package/src/lib/viewport/label/helpers/getZoomValue.test.ts +53 -0
  111. package/src/lib/viewport/label/helpers/selectFirstViewportNode.test.ts +105 -0
  112. package/src/lib/viewport/label/helpers/selectFirstViewportNode.ts +26 -0
  113. package/src/lib/viewport/label/index.ts +5 -3
  114. package/src/lib/viewport/label/isViewportDragging.test.ts +35 -0
  115. package/src/lib/viewport/label/isViewportDragging.ts +9 -0
  116. package/src/lib/viewport/label/refreshViewportLabel.test.ts +105 -0
  117. package/src/lib/viewport/label/refreshViewportLabel.ts +50 -0
  118. package/src/lib/viewport/label/refreshViewportLabels.test.ts +107 -0
  119. package/src/lib/viewport/label/refreshViewportLabels.ts +19 -52
  120. package/src/lib/viewport/label/removeViewportLabel.test.ts +67 -0
  121. package/src/lib/viewport/label/removeViewportLabel.ts +20 -0
  122. package/src/lib/viewport/label/setupViewportDrag.test.ts +249 -0
  123. package/src/lib/viewport/label/setupViewportDrag.ts +70 -0
  124. package/src/lib/viewport/resize/createResizeHandle.test.ts +37 -0
  125. package/src/lib/viewport/resize/createResizePresets.test.ts +75 -0
  126. package/src/lib/viewport/resize/updateActivePreset.test.ts +92 -0
  127. package/src/lib/viewport/width/calcConstrainedWidth.test.ts +47 -0
  128. package/src/lib/viewport/width/calcWidth.test.ts +68 -0
  129. package/src/lib/viewport/width/updateWidth.test.ts +78 -0
  130. package/src/lib/window/bindToWindow.test.ts +166 -0
  131. package/src/lib/window/bindToWindow.ts +1 -2
  132. package/dist/lib/viewport/label/getViewportLabelsOverlay.d.ts +0 -1
  133. package/dist/lib/viewport/label/isViewportLabelDragging.d.ts +0 -2
  134. package/dist/lib/viewport/label/setupViewportLabelDrag.d.ts +0 -1
  135. package/src/lib/viewport/label/isViewportLabelDragging.ts +0 -9
  136. package/src/lib/viewport/label/setupViewportLabelDrag.ts +0 -98
@@ -0,0 +1,68 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+ import { calcWidth } from "./calcWidth";
3
+
4
+ describe("calcWidth", () => {
5
+ beforeEach(() => {
6
+ // Reset zoom data attribute
7
+ document.body.dataset.zoom = "1";
8
+ });
9
+
10
+ it("should calculate width based on mouse event and start position", () => {
11
+ const startX = 100;
12
+ const startWidth = 200;
13
+ const event = {
14
+ clientX: 150,
15
+ } as MouseEvent;
16
+
17
+ const result = calcWidth(event, startX, startWidth);
18
+ expect(result).toBe(250);
19
+ });
20
+
21
+ it("should account for zoom level", () => {
22
+ document.body.dataset.zoom = "2";
23
+ const startX = 100;
24
+ const startWidth = 200;
25
+ const event = {
26
+ clientX: 150,
27
+ } as MouseEvent;
28
+
29
+ const result = calcWidth(event, startX, startWidth);
30
+ // deltaX = (150 - 100) / 2 = 25
31
+ expect(result).toBe(225);
32
+ });
33
+
34
+ it("should handle negative deltaX", () => {
35
+ const startX = 150;
36
+ const startWidth = 200;
37
+ const event = {
38
+ clientX: 100,
39
+ } as MouseEvent;
40
+
41
+ const result = calcWidth(event, startX, startWidth);
42
+ expect(result).toBe(150);
43
+ });
44
+
45
+ it("should default to zoom 1 if dataset.zoom is not set", () => {
46
+ delete document.body.dataset.zoom;
47
+ const startX = 100;
48
+ const startWidth = 200;
49
+ const event = {
50
+ clientX: 150,
51
+ } as MouseEvent;
52
+
53
+ const result = calcWidth(event, startX, startWidth);
54
+ expect(result).toBe(250);
55
+ });
56
+
57
+ it("should respect min and max width constraints", () => {
58
+ const startX = 100;
59
+ const startWidth = 10;
60
+ const event = {
61
+ clientX: 50,
62
+ } as MouseEvent;
63
+
64
+ const result = calcWidth(event, startX, startWidth);
65
+ // Should be clamped to minWidth (4)
66
+ expect(result).toBe(4);
67
+ });
68
+ });
@@ -0,0 +1,78 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { RESIZE_PRESETS } from "../constants";
3
+ import { updateWidth } from "./updateWidth";
4
+
5
+ describe("updateWidth", () => {
6
+ let container: HTMLElement;
7
+
8
+ beforeEach(() => {
9
+ container = document.createElement("div");
10
+ document.body.appendChild(container);
11
+ });
12
+
13
+ afterEach(() => {
14
+ document.body.removeChild(container);
15
+ });
16
+
17
+ it("should set --container-width CSS variable", () => {
18
+ updateWidth(container, 500);
19
+ expect(container.style.getPropertyValue("--container-width")).toBe("500px");
20
+ });
21
+
22
+ it("should update active preset when width matches a preset", () => {
23
+ // Create preset buttons
24
+ const presets = document.createElement("div");
25
+ presets.className = "resize-presets";
26
+ RESIZE_PRESETS.forEach(() => {
27
+ const button = document.createElement("button");
28
+ button.className = "resize-preset-button";
29
+ presets.appendChild(button);
30
+ });
31
+ container.appendChild(presets);
32
+
33
+ const mobilePreset = RESIZE_PRESETS[0];
34
+ updateWidth(container, mobilePreset.rawValue);
35
+
36
+ const buttons = container.querySelectorAll<HTMLButtonElement>(".resize-preset-button");
37
+ expect(buttons[0].classList.contains("is-active")).toBe(true);
38
+ expect(buttons[1].classList.contains("is-active")).toBe(false);
39
+ });
40
+
41
+ it("should remove active class from other presets when setting new width", () => {
42
+ const presets = document.createElement("div");
43
+ presets.className = "resize-presets";
44
+ RESIZE_PRESETS.forEach(() => {
45
+ const button = document.createElement("button");
46
+ button.className = "resize-preset-button";
47
+ presets.appendChild(button);
48
+ });
49
+ container.appendChild(presets);
50
+
51
+ const buttons = container.querySelectorAll<HTMLButtonElement>(".resize-preset-button");
52
+ buttons[0].classList.add("is-active");
53
+
54
+ const tabletPreset = RESIZE_PRESETS[1];
55
+ updateWidth(container, tabletPreset.rawValue);
56
+
57
+ expect(buttons[0].classList.contains("is-active")).toBe(false);
58
+ expect(buttons[1].classList.contains("is-active")).toBe(true);
59
+ });
60
+
61
+ it("should handle width that doesn't match any preset", () => {
62
+ const presets = document.createElement("div");
63
+ presets.className = "resize-presets";
64
+ RESIZE_PRESETS.forEach(() => {
65
+ const button = document.createElement("button");
66
+ button.className = "resize-preset-button";
67
+ presets.appendChild(button);
68
+ });
69
+ container.appendChild(presets);
70
+
71
+ updateWidth(container, 999);
72
+
73
+ const buttons = container.querySelectorAll<HTMLButtonElement>(".resize-preset-button");
74
+ buttons.forEach((button) => {
75
+ expect(button.classList.contains("is-active")).toBe(false);
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,166 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { bindToWindow } from "./bindToWindow";
3
+
4
+ describe("bindToWindow", () => {
5
+ let originalWindow: typeof window;
6
+
7
+ beforeEach(() => {
8
+ originalWindow = global.window;
9
+ });
10
+
11
+ afterEach(() => {
12
+ // Restore original window
13
+ global.window = originalWindow;
14
+ // Clean up any properties we added
15
+ if (typeof window !== "undefined") {
16
+ delete (window as unknown as Record<string, unknown>).testKey;
17
+ delete (window as unknown as Record<string, unknown>).nodeTools;
18
+ delete (window as unknown as Record<string, unknown>).customProperty;
19
+ }
20
+ });
21
+
22
+ it("should bind value to window object", () => {
23
+ const testValue = { test: "value" };
24
+ bindToWindow("testKey", testValue);
25
+
26
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(testValue);
27
+ });
28
+
29
+ it("should bind string value", () => {
30
+ bindToWindow("testKey", "test string");
31
+
32
+ expect((window as unknown as Record<string, unknown>).testKey).toBe("test string");
33
+ });
34
+
35
+ it("should bind number value", () => {
36
+ bindToWindow("testKey", 42);
37
+
38
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(42);
39
+ });
40
+
41
+ it("should bind boolean value", () => {
42
+ bindToWindow("testKey", true);
43
+
44
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(true);
45
+ });
46
+
47
+ it("should bind object value", () => {
48
+ const obj = { prop1: "value1", prop2: 123 };
49
+ bindToWindow("testKey", obj);
50
+
51
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(obj);
52
+ });
53
+
54
+ it("should bind array value", () => {
55
+ const arr = [1, 2, 3];
56
+ bindToWindow("testKey", arr);
57
+
58
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(arr);
59
+ });
60
+
61
+ it("should bind null value", () => {
62
+ bindToWindow("testKey", null);
63
+
64
+ expect((window as unknown as Record<string, unknown>).testKey).toBeNull();
65
+ });
66
+
67
+ it("should bind undefined value", () => {
68
+ bindToWindow("testKey", undefined);
69
+
70
+ expect((window as unknown as Record<string, unknown>).testKey).toBeUndefined();
71
+ });
72
+
73
+ it("should overwrite existing property", () => {
74
+ (window as unknown as Record<string, unknown>).testKey = "old value";
75
+ bindToWindow("testKey", "new value");
76
+
77
+ expect((window as unknown as Record<string, unknown>).testKey).toBe("new value");
78
+ });
79
+
80
+ it("should bind function value", () => {
81
+ const fn = vi.fn();
82
+ bindToWindow("testKey", fn);
83
+
84
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(fn);
85
+ });
86
+
87
+ it("should work with custom property names", () => {
88
+ const value = { custom: "data" };
89
+ bindToWindow("customProperty", value);
90
+
91
+ expect((window as unknown as Record<string, unknown>).customProperty).toBe(value);
92
+ });
93
+
94
+ it("should work with nodeTools property name", () => {
95
+ const nodeTools = { selectNode: vi.fn() };
96
+ bindToWindow("nodeTools", nodeTools);
97
+
98
+ expect((window as unknown as Record<string, unknown>).nodeTools).toBe(nodeTools);
99
+ });
100
+
101
+ it("should handle multiple bindings", () => {
102
+ bindToWindow("key1", "value1");
103
+ bindToWindow("key2", "value2");
104
+ bindToWindow("key3", "value3");
105
+
106
+ expect((window as unknown as Record<string, unknown>).key1).toBe("value1");
107
+ expect((window as unknown as Record<string, unknown>).key2).toBe("value2");
108
+ expect((window as unknown as Record<string, unknown>).key3).toBe("value3");
109
+ });
110
+
111
+ it("should not throw when window is undefined (SSR safety)", () => {
112
+ // Temporarily remove window
113
+ const windowBackup = global.window;
114
+ // @ts-ignore
115
+ delete global.window;
116
+
117
+ expect(() => {
118
+ bindToWindow("testKey", "value");
119
+ }).not.toThrow();
120
+
121
+ // Restore window
122
+ global.window = windowBackup;
123
+ });
124
+
125
+ it("should not bind when window is undefined (SSR safety)", () => {
126
+ // Temporarily remove window
127
+ const windowBackup = global.window;
128
+ // @ts-ignore
129
+ delete global.window;
130
+
131
+ bindToWindow("testKey", "value");
132
+
133
+ // Restore window and verify it wasn't set
134
+ global.window = windowBackup;
135
+ expect((window as unknown as Record<string, unknown>).testKey).toBeUndefined();
136
+ });
137
+
138
+ it("should handle complex nested objects", () => {
139
+ const complexObject = {
140
+ level1: {
141
+ level2: {
142
+ level3: {
143
+ value: "deep",
144
+ },
145
+ },
146
+ },
147
+ array: [1, { nested: "object" }],
148
+ };
149
+ bindToWindow("testKey", complexObject);
150
+
151
+ expect((window as unknown as Record<string, unknown>).testKey).toBe(complexObject);
152
+ });
153
+
154
+ it("should handle empty string key", () => {
155
+ bindToWindow("", "empty key value");
156
+
157
+ expect((window as unknown as Record<string, unknown>)[""]).toBe("empty key value");
158
+ });
159
+
160
+ it("should handle special characters in key", () => {
161
+ bindToWindow("test-key_123", "special chars");
162
+
163
+ expect((window as unknown as Record<string, unknown>)["test-key_123"]).toBe("special chars");
164
+ });
165
+ });
166
+
@@ -1,6 +1,5 @@
1
1
  export const bindToWindow = <T>(key: string, value: T): void => {
2
2
  if (typeof window !== "undefined") {
3
- // biome-ignore lint/suspicious/noExplicitAny: global window extension requires flexibility
4
- (window as any)[key] = value;
3
+ (window as unknown as Record<string, unknown>)[key] = value;
5
4
  }
6
5
  };
@@ -1 +0,0 @@
1
- export declare const getViewportLabelsOverlay: () => SVGSVGElement;
@@ -1,2 +0,0 @@
1
- export declare const isViewportLabelDragging: () => boolean;
2
- export declare const setViewportLabelDragging: (isDragging: boolean) => void;
@@ -1 +0,0 @@
1
- export declare const setupViewportLabelDrag: (labelElement: SVGTextElement, viewportElement: HTMLElement, viewportName: string) => (() => void);
@@ -1,9 +0,0 @@
1
- // Global flag to prevent refreshViewportLabels during drag
2
- let globalIsDragging = false;
3
-
4
- export const isViewportLabelDragging = (): boolean => globalIsDragging;
5
-
6
- export const setViewportLabelDragging = (isDragging: boolean): void => {
7
- globalIsDragging = isDragging;
8
- };
9
-
@@ -1,98 +0,0 @@
1
- import { sendPostMessage } from "../../post-message/sendPostMessage";
2
- import { getLabelPosition } from "./helpers/getLabelPosition";
3
- import { getTransformValues } from "./helpers/getTransformValues";
4
- import { getZoomValue } from "./helpers/getZoomValue";
5
- import { setViewportLabelDragging } from "./isViewportLabelDragging";
6
-
7
- export const setupViewportLabelDrag = (labelElement: SVGTextElement, viewportElement: HTMLElement, viewportName: string): (() => void) => {
8
- let isDragging = false;
9
- let startX = 0;
10
- let startY = 0;
11
- let initialTransform = { x: 0, y: 0 };
12
- let initialLabelPosition = { x: 0, y: 0 };
13
-
14
- // Get the parent group element that contains the label
15
- const labelGroup = labelElement.parentElement as unknown as SVGGElement;
16
-
17
- const startDrag = (event: MouseEvent): void => {
18
- event.preventDefault();
19
- event.stopPropagation();
20
-
21
- isDragging = true;
22
- setViewportLabelDragging(true);
23
- startX = event.clientX;
24
- startY = event.clientY;
25
- initialTransform = getTransformValues(viewportElement);
26
- initialLabelPosition = getLabelPosition(labelGroup);
27
- };
28
-
29
- const handleDrag = (event: MouseEvent): void => {
30
- if (!isDragging) return;
31
-
32
- const zoom = getZoomValue();
33
-
34
- // Calculate mouse delta
35
- const rawDeltaX = event.clientX - startX;
36
- const rawDeltaY = event.clientY - startY;
37
-
38
- // Adjust delta for zoom level
39
- const deltaX = rawDeltaX / zoom;
40
- const deltaY = rawDeltaY / zoom;
41
-
42
- const newX = initialTransform.x + deltaX;
43
- const newY = initialTransform.y + deltaY;
44
-
45
- // Update label position with raw delta (labels are in screen space)
46
- const newLabelX = initialLabelPosition.x + rawDeltaX;
47
- const newLabelY = initialLabelPosition.y + rawDeltaY;
48
- labelGroup.setAttribute("transform", `translate(${newLabelX}, ${newLabelY})`);
49
-
50
- // Update viewport position with zoom-adjusted delta
51
- viewportElement.style.transform = `translate3d(${newX}px, ${newY}px, 0)`;
52
- };
53
-
54
- const stopDrag = (event: MouseEvent): void => {
55
- if (!isDragging) return;
56
-
57
- event.preventDefault();
58
- event.stopPropagation();
59
-
60
- isDragging = false;
61
- setViewportLabelDragging(false);
62
-
63
- const finalTransform = getTransformValues(viewportElement);
64
-
65
- // Trigger refresh after drag completes to update highlight frame and labels
66
- // biome-ignore lint/suspicious/noExplicitAny: global window extension
67
- const nodeTools = (window as any).nodeTools;
68
- if (nodeTools?.refreshHighlightFrame) {
69
- nodeTools.refreshHighlightFrame();
70
- }
71
-
72
- // Notify parent about the new position
73
- sendPostMessage("viewport-position-changed", {
74
- viewportName,
75
- x: finalTransform.x,
76
- y: finalTransform.y,
77
- });
78
- };
79
-
80
- const cancelDrag = (): void => {
81
- isDragging = false;
82
- setViewportLabelDragging(false);
83
- };
84
-
85
- // Attach event listeners
86
- labelElement.addEventListener("mousedown", startDrag);
87
- document.addEventListener("mousemove", handleDrag);
88
- document.addEventListener("mouseup", stopDrag);
89
- window.addEventListener("blur", cancelDrag);
90
-
91
- // Return cleanup function
92
- return () => {
93
- labelElement.removeEventListener("mousedown", startDrag);
94
- document.removeEventListener("mousemove", handleDrag);
95
- document.removeEventListener("mouseup", stopDrag);
96
- window.removeEventListener("blur", cancelDrag);
97
- };
98
- };