@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.
- package/dist/lib/canvas/helpers/getCanvasContainerOrBody.d.ts +1 -0
- package/dist/lib/canvas/helpers/getCanvasWindowValue.d.ts +1 -1
- package/dist/lib/helpers/adjustForZoom.d.ts +1 -0
- package/dist/lib/helpers/createDragHandler.d.ts +69 -0
- package/dist/lib/helpers/getNodeProvider.d.ts +1 -0
- package/dist/lib/helpers/getNodeTools.d.ts +2 -0
- package/dist/lib/helpers/getViewportDimensions.d.ts +4 -0
- package/dist/lib/helpers/index.d.ts +9 -1
- package/dist/lib/helpers/parseTransform.d.ts +8 -0
- package/dist/lib/helpers/toggleClass.d.ts +1 -0
- package/dist/lib/viewport/label/getViewportLabelOverlay.d.ts +1 -0
- package/dist/lib/viewport/label/helpers/selectFirstViewportNode.d.ts +5 -0
- package/dist/lib/viewport/label/index.d.ts +5 -3
- package/dist/lib/viewport/label/isViewportDragging.d.ts +2 -0
- package/dist/lib/viewport/label/refreshViewportLabel.d.ts +8 -0
- package/dist/lib/viewport/label/removeViewportLabel.d.ts +5 -0
- package/dist/lib/viewport/label/setupViewportDrag.d.ts +1 -0
- package/dist/node-edit-utils.cjs.js +342 -280
- package/dist/node-edit-utils.esm.js +342 -280
- package/dist/node-edit-utils.umd.js +342 -280
- package/dist/node-edit-utils.umd.min.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +7 -2
- package/src/lib/canvas/createCanvasObserver.test.ts +242 -0
- package/src/lib/canvas/createCanvasObserver.ts +2 -2
- package/src/lib/canvas/disableCanvasKeyboard.test.ts +53 -0
- package/src/lib/canvas/disableCanvasKeyboard.ts +1 -1
- package/src/lib/canvas/disableCanvasTextMode.test.ts +53 -0
- package/src/lib/canvas/disableCanvasTextMode.ts +1 -1
- package/src/lib/canvas/enableCanvasKeyboard.test.ts +53 -0
- package/src/lib/canvas/enableCanvasKeyboard.ts +1 -1
- package/src/lib/canvas/enableCanvasTextMode.test.ts +53 -0
- package/src/lib/canvas/enableCanvasTextMode.ts +1 -1
- package/src/lib/canvas/helpers/applyCanvasState.test.ts +119 -0
- package/src/lib/canvas/helpers/applyCanvasState.ts +1 -1
- package/src/lib/canvas/helpers/getCanvasContainer.test.ts +62 -0
- package/src/lib/canvas/helpers/getCanvasContainerOrBody.test.ts +51 -0
- package/src/lib/canvas/helpers/getCanvasContainerOrBody.ts +6 -0
- package/src/lib/canvas/helpers/getCanvasWindowValue.test.ts +116 -0
- package/src/lib/canvas/helpers/getCanvasWindowValue.ts +2 -3
- package/src/lib/helpers/adjustForZoom.test.ts +65 -0
- package/src/lib/helpers/adjustForZoom.ts +4 -0
- package/src/lib/helpers/createDragHandler.test.ts +325 -0
- package/src/lib/helpers/createDragHandler.ts +171 -0
- package/src/lib/helpers/getNodeProvider.test.ts +71 -0
- package/src/lib/helpers/getNodeProvider.ts +4 -0
- package/src/lib/helpers/getNodeTools.test.ts +50 -0
- package/src/lib/helpers/getNodeTools.ts +6 -0
- package/src/lib/helpers/getViewportDimensions.test.ts +93 -0
- package/src/lib/helpers/getViewportDimensions.ts +7 -0
- package/src/lib/helpers/index.ts +9 -1
- package/src/lib/helpers/observer/connectMutationObserver.test.ts +127 -0
- package/src/lib/helpers/observer/connectResizeObserver.test.ts +147 -0
- package/src/lib/helpers/parseTransform.test.ts +117 -0
- package/src/lib/helpers/parseTransform.ts +9 -0
- package/src/lib/helpers/toggleClass.test.ts +71 -0
- package/src/lib/helpers/toggleClass.ts +9 -0
- package/src/lib/helpers/withRAF.test.ts +439 -0
- package/src/lib/node-tools/createNodeTools.test.ts +373 -0
- package/src/lib/node-tools/createNodeTools.ts +0 -1
- package/src/lib/node-tools/events/click/handleNodeClick.test.ts +109 -0
- package/src/lib/node-tools/events/setupEventListener.test.ts +136 -0
- package/src/lib/node-tools/highlight/clearHighlightFrame.test.ts +88 -0
- package/src/lib/node-tools/highlight/clearHighlightFrame.ts +2 -3
- package/src/lib/node-tools/highlight/createCornerHandles.test.ts +150 -0
- package/src/lib/node-tools/highlight/createHighlightFrame.test.ts +237 -0
- package/src/lib/node-tools/highlight/createHighlightFrame.ts +5 -9
- package/src/lib/node-tools/highlight/createTagLabel.test.ts +135 -0
- package/src/lib/node-tools/highlight/createToolsContainer.test.ts +97 -0
- package/src/lib/node-tools/highlight/createToolsContainer.ts +3 -6
- package/src/lib/node-tools/highlight/helpers/getElementBounds.test.ts +158 -0
- package/src/lib/node-tools/highlight/helpers/getElementBounds.ts +6 -5
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.test.ts +78 -0
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.ts +2 -3
- package/src/lib/node-tools/highlight/helpers/getScreenBounds.test.ts +133 -0
- package/src/lib/node-tools/highlight/highlightNode.test.ts +213 -0
- package/src/lib/node-tools/highlight/highlightNode.ts +7 -15
- package/src/lib/node-tools/highlight/refreshHighlightFrame.test.ts +323 -0
- package/src/lib/node-tools/highlight/refreshHighlightFrame.ts +12 -42
- package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.test.ts +110 -0
- package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.ts +2 -3
- package/src/lib/node-tools/select/helpers/getElementsFromPoint.test.ts +109 -0
- package/src/lib/node-tools/select/helpers/isInsideComponent.test.ts +81 -0
- package/src/lib/node-tools/select/helpers/isInsideViewport.test.ts +82 -0
- package/src/lib/node-tools/select/helpers/targetSameCandidates.test.ts +81 -0
- package/src/lib/node-tools/select/selectNode.test.ts +238 -0
- package/src/lib/node-tools/text/events/setupKeydownHandler.test.ts +91 -0
- package/src/lib/node-tools/text/events/setupMutationObserver.test.ts +213 -0
- package/src/lib/node-tools/text/events/setupNodeListeners.test.ts +133 -0
- package/src/lib/node-tools/text/helpers/enterTextEditMode.test.ts +50 -0
- package/src/lib/node-tools/text/helpers/handleTextChange.test.ts +201 -0
- package/src/lib/node-tools/text/helpers/hasTextContent.test.ts +101 -0
- package/src/lib/node-tools/text/helpers/insertLineBreak.test.ts +96 -0
- package/src/lib/node-tools/text/helpers/makeNodeEditable.test.ts +56 -0
- package/src/lib/node-tools/text/helpers/makeNodeNonEditable.test.ts +57 -0
- package/src/lib/node-tools/text/helpers/shouldEnterTextEditMode.test.ts +61 -0
- package/src/lib/node-tools/text/nodeText.test.ts +233 -0
- package/src/lib/post-message/processPostMessage.test.ts +218 -0
- package/src/lib/post-message/sendPostMessage.test.ts +120 -0
- package/src/lib/styles/styles.css +3 -3
- package/src/lib/viewport/createViewport.test.ts +267 -0
- package/src/lib/viewport/createViewport.ts +51 -51
- package/src/lib/viewport/events/setupEventListener.test.ts +103 -0
- package/src/lib/viewport/label/getViewportLabelOverlay.test.ts +77 -0
- package/src/lib/viewport/label/{getViewportLabelsOverlay.ts → getViewportLabelOverlay.ts} +6 -6
- package/src/lib/viewport/label/helpers/getLabelPosition.test.ts +51 -0
- package/src/lib/viewport/label/helpers/getLabelPosition.ts +3 -5
- package/src/lib/viewport/label/helpers/getTransformValues.test.ts +59 -0
- package/src/lib/viewport/label/helpers/getTransformValues.ts +3 -5
- package/src/lib/viewport/label/helpers/getZoomValue.test.ts +53 -0
- package/src/lib/viewport/label/helpers/selectFirstViewportNode.test.ts +105 -0
- package/src/lib/viewport/label/helpers/selectFirstViewportNode.ts +26 -0
- package/src/lib/viewport/label/index.ts +5 -3
- package/src/lib/viewport/label/isViewportDragging.test.ts +35 -0
- package/src/lib/viewport/label/isViewportDragging.ts +9 -0
- package/src/lib/viewport/label/refreshViewportLabel.test.ts +105 -0
- package/src/lib/viewport/label/refreshViewportLabel.ts +50 -0
- package/src/lib/viewport/label/refreshViewportLabels.test.ts +107 -0
- package/src/lib/viewport/label/refreshViewportLabels.ts +19 -52
- package/src/lib/viewport/label/removeViewportLabel.test.ts +67 -0
- package/src/lib/viewport/label/removeViewportLabel.ts +20 -0
- package/src/lib/viewport/label/setupViewportDrag.test.ts +249 -0
- package/src/lib/viewport/label/setupViewportDrag.ts +70 -0
- package/src/lib/viewport/resize/createResizeHandle.test.ts +37 -0
- package/src/lib/viewport/resize/createResizePresets.test.ts +75 -0
- package/src/lib/viewport/resize/updateActivePreset.test.ts +92 -0
- package/src/lib/viewport/width/calcConstrainedWidth.test.ts +47 -0
- package/src/lib/viewport/width/calcWidth.test.ts +68 -0
- package/src/lib/viewport/width/updateWidth.test.ts +78 -0
- package/src/lib/window/bindToWindow.test.ts +166 -0
- package/src/lib/window/bindToWindow.ts +1 -2
- package/dist/lib/viewport/label/getViewportLabelsOverlay.d.ts +0 -1
- package/dist/lib/viewport/label/isViewportLabelDragging.d.ts +0 -2
- package/dist/lib/viewport/label/setupViewportLabelDrag.d.ts +0 -1
- package/src/lib/viewport/label/isViewportLabelDragging.ts +0 -9
- 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
|
-
|
|
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 +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
|
-
};
|