@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,53 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { enableCanvasTextMode } from "./enableCanvasTextMode";
3
+ import * as getCanvasWindowValueModule from "./helpers/getCanvasWindowValue";
4
+
5
+ vi.mock("./helpers/getCanvasWindowValue");
6
+
7
+ describe("enableCanvasTextMode", () => {
8
+ beforeEach(() => {
9
+ vi.clearAllMocks();
10
+ });
11
+
12
+ afterEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+
16
+ it("should call enableTextEditMode function from canvas window value", () => {
17
+ const mockEnableTextEditMode = vi.fn();
18
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(mockEnableTextEditMode);
19
+
20
+ enableCanvasTextMode();
21
+
22
+ expect(getCanvasWindowValueModule.getCanvasWindowValue).toHaveBeenCalledWith(["keyboard", "enableTextEditMode"], "canvas");
23
+ expect(mockEnableTextEditMode).toHaveBeenCalledTimes(1);
24
+ });
25
+
26
+ it("should use custom canvas name", () => {
27
+ const mockEnableTextEditMode = vi.fn();
28
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(mockEnableTextEditMode);
29
+
30
+ enableCanvasTextMode("custom-canvas");
31
+
32
+ expect(getCanvasWindowValueModule.getCanvasWindowValue).toHaveBeenCalledWith(["keyboard", "enableTextEditMode"], "custom-canvas");
33
+ expect(mockEnableTextEditMode).toHaveBeenCalledTimes(1);
34
+ });
35
+
36
+ it("should not throw when enableTextEditMode function is undefined", () => {
37
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(undefined);
38
+
39
+ expect(() => enableCanvasTextMode()).not.toThrow();
40
+ });
41
+
42
+ it("should not throw when enableTextEditMode function is null", () => {
43
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(null);
44
+
45
+ expect(() => enableCanvasTextMode()).not.toThrow();
46
+ });
47
+
48
+ it("should throw when getCanvasWindowValue returns non-function", () => {
49
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue("not-a-function");
50
+
51
+ expect(() => enableCanvasTextMode()).toThrow();
52
+ });
53
+ });
@@ -1,7 +1,7 @@
1
1
  import { getCanvasWindowValue } from "@/lib/canvas/helpers/getCanvasWindowValue";
2
2
 
3
3
  export const enableCanvasTextMode = (canvasName: string = "canvas") => {
4
- const enableTextEditMode = getCanvasWindowValue(["keyboard", "enableTextEditMode"], canvasName);
4
+ const enableTextEditMode = getCanvasWindowValue(["keyboard", "enableTextEditMode"], canvasName) as (() => void) | undefined;
5
5
 
6
6
  enableTextEditMode?.();
7
7
  };
@@ -0,0 +1,119 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { applyCanvasState } from "./applyCanvasState";
3
+ import * as getCanvasWindowValueModule from "./getCanvasWindowValue";
4
+
5
+ vi.mock("./getCanvasWindowValue");
6
+
7
+ describe("applyCanvasState", () => {
8
+ beforeEach(() => {
9
+ // Clear body styles and data attributes
10
+ document.body.style.removeProperty("--zoom");
11
+ document.body.style.removeProperty("--stroke-width");
12
+ delete document.body.dataset.zoom;
13
+ delete document.body.dataset.strokeWidth;
14
+ });
15
+
16
+ afterEach(() => {
17
+ vi.clearAllMocks();
18
+ document.body.style.removeProperty("--zoom");
19
+ document.body.style.removeProperty("--stroke-width");
20
+ delete document.body.dataset.zoom;
21
+ delete document.body.dataset.strokeWidth;
22
+ });
23
+
24
+ it("should set zoom and stroke-width CSS variables", () => {
25
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1);
26
+
27
+ applyCanvasState();
28
+
29
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("1.00000");
30
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("2.000");
31
+ });
32
+
33
+ it("should set zoom and stroke-width data attributes", () => {
34
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1);
35
+
36
+ applyCanvasState();
37
+
38
+ expect(document.body.dataset.zoom).toBe("1.00000");
39
+ expect(document.body.dataset.strokeWidth).toBe("2.000");
40
+ });
41
+
42
+ it("should use default zoom of 1 when zoom is undefined", () => {
43
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(undefined);
44
+
45
+ applyCanvasState();
46
+
47
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("1.00000");
48
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("2.000");
49
+ expect(document.body.dataset.zoom).toBe("1.00000");
50
+ expect(document.body.dataset.strokeWidth).toBe("2.000");
51
+ });
52
+
53
+ it("should calculate stroke-width based on zoom", () => {
54
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(2);
55
+
56
+ applyCanvasState();
57
+
58
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("2.00000");
59
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("1.000");
60
+ expect(document.body.dataset.zoom).toBe("2.00000");
61
+ expect(document.body.dataset.strokeWidth).toBe("1.000");
62
+ });
63
+
64
+ it("should handle fractional zoom values", () => {
65
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(0.5);
66
+
67
+ applyCanvasState();
68
+
69
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("0.50000");
70
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("4.000");
71
+ expect(document.body.dataset.zoom).toBe("0.50000");
72
+ expect(document.body.dataset.strokeWidth).toBe("4.000");
73
+ });
74
+
75
+ it("should use custom canvas name", () => {
76
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1.5);
77
+
78
+ applyCanvasState("custom-canvas");
79
+
80
+ expect(getCanvasWindowValueModule.getCanvasWindowValue).toHaveBeenCalledWith(["zoom", "current"], "custom-canvas");
81
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("1.50000");
82
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("1.333");
83
+ });
84
+
85
+ it("should format zoom with 5 decimal places", () => {
86
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1.123456789);
87
+
88
+ applyCanvasState();
89
+
90
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("1.12346");
91
+ expect(document.body.dataset.zoom).toBe("1.12346");
92
+ });
93
+
94
+ it("should format stroke-width with 3 decimal places", () => {
95
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1.333333);
96
+
97
+ applyCanvasState();
98
+
99
+ // 2 / 1.333333 = 1.500000... which rounds to 1.500
100
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("1.500");
101
+ expect(document.body.dataset.strokeWidth).toBe("1.500");
102
+ });
103
+
104
+ it("should update existing values", () => {
105
+ document.body.style.setProperty("--zoom", "0.50000");
106
+ document.body.style.setProperty("--stroke-width", "4.000");
107
+ document.body.dataset.zoom = "0.50000";
108
+ document.body.dataset.strokeWidth = "4.000";
109
+
110
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(2);
111
+
112
+ applyCanvasState();
113
+
114
+ expect(document.body.style.getPropertyValue("--zoom")).toBe("2.00000");
115
+ expect(document.body.style.getPropertyValue("--stroke-width")).toBe("1.000");
116
+ expect(document.body.dataset.zoom).toBe("2.00000");
117
+ expect(document.body.dataset.strokeWidth).toBe("1.000");
118
+ });
119
+ });
@@ -1,7 +1,7 @@
1
1
  import { getCanvasWindowValue } from "./getCanvasWindowValue";
2
2
 
3
3
  export const applyCanvasState = (canvasName: string = "canvas") => {
4
- const zoom: number = getCanvasWindowValue(["zoom", "current"], canvasName) ?? 1;
4
+ const zoom: number = (getCanvasWindowValue(["zoom", "current"], canvasName) as number | undefined) ?? 1;
5
5
 
6
6
  document.body.style.setProperty("--zoom", zoom.toFixed(5));
7
7
  document.body.style.setProperty("--stroke-width", (2 / zoom).toFixed(3));
@@ -0,0 +1,62 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { getCanvasContainer } from "./getCanvasContainer";
3
+
4
+ describe("getCanvasContainer", () => {
5
+ let canvasContainer: HTMLElement;
6
+
7
+ beforeEach(() => {
8
+ canvasContainer = document.createElement("div");
9
+ canvasContainer.classList.add("canvas-container");
10
+ });
11
+
12
+ afterEach(() => {
13
+ if (document.body.contains(canvasContainer)) {
14
+ document.body.removeChild(canvasContainer);
15
+ }
16
+ // Remove any other canvas containers that might exist
17
+ const existingContainers = document.querySelectorAll(".canvas-container");
18
+ existingContainers.forEach((container) => {
19
+ if (document.body.contains(container)) {
20
+ document.body.removeChild(container);
21
+ }
22
+ });
23
+ });
24
+
25
+ it("should return canvas container element when it exists", () => {
26
+ document.body.appendChild(canvasContainer);
27
+
28
+ const result = getCanvasContainer();
29
+
30
+ expect(result).toBe(canvasContainer);
31
+ });
32
+
33
+ it("should return null when canvas container does not exist", () => {
34
+ const result = getCanvasContainer();
35
+
36
+ expect(result).toBeNull();
37
+ });
38
+
39
+ it("should return first canvas container when multiple exist", () => {
40
+ const firstContainer = document.createElement("div");
41
+ firstContainer.classList.add("canvas-container");
42
+ const secondContainer = document.createElement("div");
43
+ secondContainer.classList.add("canvas-container");
44
+
45
+ document.body.appendChild(firstContainer);
46
+ document.body.appendChild(secondContainer);
47
+
48
+ const result = getCanvasContainer();
49
+
50
+ expect(result).toBe(firstContainer);
51
+ });
52
+
53
+ it("should return null after container is removed", () => {
54
+ document.body.appendChild(canvasContainer);
55
+ const result1 = getCanvasContainer();
56
+ expect(result1).toBe(canvasContainer);
57
+
58
+ document.body.removeChild(canvasContainer);
59
+ const result2 = getCanvasContainer();
60
+ expect(result2).toBeNull();
61
+ });
62
+ });
@@ -0,0 +1,51 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import * as getCanvasContainerModule from "./getCanvasContainer";
3
+ import { getCanvasContainerOrBody } from "./getCanvasContainerOrBody";
4
+
5
+ vi.mock("./getCanvasContainer");
6
+
7
+ describe("getCanvasContainerOrBody", () => {
8
+ let canvasContainer: HTMLElement;
9
+
10
+ beforeEach(() => {
11
+ canvasContainer = document.createElement("div");
12
+ canvasContainer.classList.add("canvas-container");
13
+ });
14
+
15
+ afterEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+
19
+ it("should return canvas container when it exists", () => {
20
+ vi.mocked(getCanvasContainerModule.getCanvasContainer).mockReturnValue(canvasContainer);
21
+
22
+ const result = getCanvasContainerOrBody();
23
+
24
+ expect(result).toBe(canvasContainer);
25
+ });
26
+
27
+ it("should return document.body when canvas container does not exist", () => {
28
+ vi.mocked(getCanvasContainerModule.getCanvasContainer).mockReturnValue(null);
29
+
30
+ const result = getCanvasContainerOrBody();
31
+
32
+ expect(result).toBe(document.body);
33
+ });
34
+
35
+ it("should always return an HTMLElement", () => {
36
+ vi.mocked(getCanvasContainerModule.getCanvasContainer).mockReturnValue(canvasContainer);
37
+
38
+ const result = getCanvasContainerOrBody();
39
+
40
+ expect(result).toBeInstanceOf(HTMLElement);
41
+ });
42
+
43
+ it("should return document.body when canvas container is null", () => {
44
+ vi.mocked(getCanvasContainerModule.getCanvasContainer).mockReturnValue(null);
45
+
46
+ const result = getCanvasContainerOrBody();
47
+
48
+ expect(result).toBe(document.body);
49
+ expect(result).toBeInstanceOf(HTMLElement);
50
+ });
51
+ });
@@ -0,0 +1,6 @@
1
+ import { getCanvasContainer } from "./getCanvasContainer";
2
+
3
+ export const getCanvasContainerOrBody = (): HTMLElement => {
4
+ return getCanvasContainer() || document.body;
5
+ };
6
+
@@ -0,0 +1,116 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { getCanvasWindowValue } from "./getCanvasWindowValue";
3
+
4
+ describe("getCanvasWindowValue", () => {
5
+ beforeEach(() => {
6
+ // Clear any existing canvas properties
7
+ delete (window as unknown as Record<string, unknown>).canvas;
8
+ delete (window as unknown as Record<string, unknown>).customCanvas;
9
+ });
10
+
11
+ afterEach(() => {
12
+ // Clean up
13
+ delete (window as unknown as Record<string, unknown>).canvas;
14
+ delete (window as unknown as Record<string, unknown>).customCanvas;
15
+ });
16
+
17
+ it("should return value from nested path", () => {
18
+ const mockValue = { keyboard: { enable: vi.fn() } };
19
+ (window as unknown as Record<string, unknown>).canvas = mockValue;
20
+
21
+ const result = getCanvasWindowValue(["keyboard", "enable"], "canvas");
22
+
23
+ expect(result).toBe(mockValue.keyboard.enable);
24
+ });
25
+
26
+ it("should return undefined when canvas does not exist", () => {
27
+ const result = getCanvasWindowValue(["keyboard", "enable"], "nonExistentCanvas");
28
+
29
+ expect(result).toBeUndefined();
30
+ });
31
+
32
+ it("should return undefined when path does not exist", () => {
33
+ (window as unknown as Record<string, unknown>).canvas = {};
34
+
35
+ const result = getCanvasWindowValue(["nonExistent", "path"], "canvas");
36
+
37
+ expect(result).toBeUndefined();
38
+ });
39
+
40
+ it("should return undefined when intermediate path is null", () => {
41
+ (window as unknown as Record<string, unknown>).canvas = { keyboard: null };
42
+
43
+ const result = getCanvasWindowValue(["keyboard", "enable"], "canvas");
44
+
45
+ expect(result).toBeUndefined();
46
+ });
47
+
48
+ it("should return undefined when intermediate path is undefined", () => {
49
+ (window as unknown as Record<string, unknown>).canvas = { keyboard: undefined };
50
+
51
+ const result = getCanvasWindowValue(["keyboard", "enable"], "canvas");
52
+
53
+ expect(result).toBeUndefined();
54
+ });
55
+
56
+ it("should use default canvas name when not provided", () => {
57
+ const mockValue = { keyboard: { enable: vi.fn() } };
58
+ (window as unknown as Record<string, unknown>).canvas = mockValue;
59
+
60
+ const result = getCanvasWindowValue(["keyboard", "enable"]);
61
+
62
+ expect(result).toBe(mockValue.keyboard.enable);
63
+ });
64
+
65
+ it("should handle custom canvas name", () => {
66
+ const mockValue = { keyboard: { enable: vi.fn() } };
67
+ (window as unknown as Record<string, unknown>).customCanvas = mockValue;
68
+
69
+ const result = getCanvasWindowValue(["keyboard", "enable"], "customCanvas");
70
+
71
+ expect(result).toBe(mockValue.keyboard.enable);
72
+ });
73
+
74
+ it("should handle single level path", () => {
75
+ const mockValue = { property: "value" };
76
+ (window as unknown as Record<string, unknown>).canvas = mockValue;
77
+
78
+ const result = getCanvasWindowValue(["property"], "canvas");
79
+
80
+ expect(result).toBe("value");
81
+ });
82
+
83
+ it("should handle deep nested path", () => {
84
+ const mockValue = {
85
+ level1: {
86
+ level2: {
87
+ level3: {
88
+ level4: "deep-value",
89
+ },
90
+ },
91
+ },
92
+ };
93
+ (window as unknown as Record<string, unknown>).canvas = mockValue;
94
+
95
+ const result = getCanvasWindowValue(["level1", "level2", "level3", "level4"], "canvas");
96
+
97
+ expect(result).toBe("deep-value");
98
+ });
99
+
100
+ it("should handle empty path array", () => {
101
+ const mockValue = { property: "value" };
102
+ (window as unknown as Record<string, unknown>).canvas = mockValue;
103
+
104
+ const result = getCanvasWindowValue([], "canvas");
105
+
106
+ expect(result).toBe(mockValue);
107
+ });
108
+
109
+ it("should handle when canvas is not an object", () => {
110
+ (window as unknown as Record<string, unknown>).canvas = "not-an-object";
111
+
112
+ const result = getCanvasWindowValue(["keyboard", "enable"], "canvas");
113
+
114
+ expect(result).toBeUndefined();
115
+ });
116
+ });
@@ -1,5 +1,4 @@
1
1
  export const getCanvasWindowValue = (path: string[], canvasName: string = "canvas") => {
2
- // biome-ignore lint/suspicious/noExplicitAny: global window extension
3
- const canvas = (window as any)[canvasName];
4
- return path.reduce((obj, prop) => obj?.[prop], canvas);
2
+ const canvas = (window as unknown as Record<string, unknown>)[canvasName];
3
+ return path.reduce((obj: unknown, prop: string) => (obj as Record<string, unknown>)?.[prop], canvas);
5
4
  };
@@ -0,0 +1,65 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { adjustForZoom } from "./adjustForZoom";
3
+
4
+ describe("adjustForZoom", () => {
5
+ it("should divide value by zoom", () => {
6
+ const result = adjustForZoom(100, 2);
7
+
8
+ expect(result).toBe(50);
9
+ });
10
+
11
+ it("should handle zoom of 1", () => {
12
+ const result = adjustForZoom(100, 1);
13
+
14
+ expect(result).toBe(100);
15
+ });
16
+
17
+ it("should handle fractional zoom", () => {
18
+ const result = adjustForZoom(100, 0.5);
19
+
20
+ expect(result).toBe(200);
21
+ });
22
+
23
+ it("should handle decimal values", () => {
24
+ const result = adjustForZoom(123.456, 2.5);
25
+
26
+ expect(result).toBe(49.3824);
27
+ });
28
+
29
+ it("should use default precision of 5", () => {
30
+ const result = adjustForZoom(100, 3);
31
+
32
+ expect(result).toBe(33.33333);
33
+ });
34
+
35
+ it("should use custom precision", () => {
36
+ const result = adjustForZoom(100, 3, 2);
37
+
38
+ expect(result).toBe(33.33);
39
+ });
40
+
41
+ it("should handle zero value", () => {
42
+ const result = adjustForZoom(0, 2);
43
+
44
+ expect(result).toBe(0);
45
+ });
46
+
47
+ it("should handle negative values", () => {
48
+ const result = adjustForZoom(-100, 2);
49
+
50
+ expect(result).toBe(-50);
51
+ });
52
+
53
+ it("should handle precision of 0", () => {
54
+ const result = adjustForZoom(100, 3, 0);
55
+
56
+ expect(result).toBe(33);
57
+ });
58
+
59
+ it("should handle very small zoom values", () => {
60
+ const result = adjustForZoom(100, 0.1);
61
+
62
+ expect(result).toBe(1000);
63
+ });
64
+ });
65
+
@@ -0,0 +1,4 @@
1
+ export const adjustForZoom = (value: number, zoom: number, precision: number = 5): number => {
2
+ return parseFloat((value / zoom).toFixed(precision));
3
+ };
4
+