@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,97 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import * as toggleClassModule from "@/lib/helpers/toggleClass";
3
+ import * as createTagLabelModule from "./createTagLabel";
4
+ import { createToolsContainer } from "./createToolsContainer";
5
+
6
+ vi.mock("@/lib/helpers/toggleClass");
7
+ vi.mock("./createTagLabel");
8
+
9
+ describe("createToolsContainer", () => {
10
+ let node: HTMLElement;
11
+ let highlightFrame: HTMLElement;
12
+
13
+ beforeEach(() => {
14
+ node = document.createElement("div");
15
+ node.setAttribute("data-node-id", "test-node");
16
+ highlightFrame = document.createElement("div");
17
+
18
+ vi.mocked(toggleClassModule.toggleClass).mockImplementation(() => {});
19
+ vi.mocked(createTagLabelModule.createTagLabel).mockImplementation(() => {});
20
+ });
21
+
22
+ afterEach(() => {
23
+ vi.clearAllMocks();
24
+ });
25
+
26
+ it("should create node-tools element", () => {
27
+ createToolsContainer(node, highlightFrame);
28
+
29
+ const nodeTools = highlightFrame.querySelector(".node-tools");
30
+ expect(nodeTools).not.toBeNull();
31
+ expect(nodeTools?.className).toBe("node-tools");
32
+ });
33
+
34
+ it("should append node-tools to highlight frame", () => {
35
+ createToolsContainer(node, highlightFrame);
36
+
37
+ const nodeTools = highlightFrame.querySelector(".node-tools");
38
+ expect(nodeTools?.parentNode).toBe(highlightFrame);
39
+ });
40
+
41
+ it("should toggle is-instance class when isInstance is true", () => {
42
+ createToolsContainer(node, highlightFrame, true, false);
43
+
44
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(
45
+ expect.any(HTMLElement),
46
+ "is-instance",
47
+ true
48
+ );
49
+ });
50
+
51
+ it("should toggle is-text-edit class when isTextEdit is true", () => {
52
+ createToolsContainer(node, highlightFrame, false, true);
53
+
54
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(
55
+ expect.any(HTMLElement),
56
+ "is-text-edit",
57
+ true
58
+ );
59
+ });
60
+
61
+ it("should toggle both classes when both flags are true", () => {
62
+ createToolsContainer(node, highlightFrame, true, true);
63
+
64
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledTimes(2);
65
+ });
66
+
67
+ it("should not toggle classes when both flags are false", () => {
68
+ createToolsContainer(node, highlightFrame, false, false);
69
+
70
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledTimes(2);
71
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(
72
+ expect.any(HTMLElement),
73
+ "is-instance",
74
+ false
75
+ );
76
+ expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(
77
+ expect.any(HTMLElement),
78
+ "is-text-edit",
79
+ false
80
+ );
81
+ });
82
+
83
+ it("should create tag label", () => {
84
+ createToolsContainer(node, highlightFrame);
85
+
86
+ const nodeTools = highlightFrame.querySelector(".node-tools");
87
+ expect(createTagLabelModule.createTagLabel).toHaveBeenCalledWith(node, nodeTools as HTMLElement);
88
+ });
89
+
90
+ it("should pass correct nodeTools element to createTagLabel", () => {
91
+ createToolsContainer(node, highlightFrame);
92
+
93
+ const nodeTools = highlightFrame.querySelector(".node-tools");
94
+ expect(createTagLabelModule.createTagLabel).toHaveBeenCalledWith(node, nodeTools as HTMLElement);
95
+ });
96
+ });
97
+
@@ -1,15 +1,12 @@
1
+ import { toggleClass } from "@/lib/helpers/toggleClass";
1
2
  import { createTagLabel } from "./createTagLabel";
2
3
 
3
4
  export const createToolsContainer = (node: HTMLElement, highlightFrame: HTMLElement, isInstance: boolean = false, isTextEdit: boolean = false): void => {
4
5
  const nodeTools = document.createElement("div");
5
6
 
6
7
  nodeTools.className = "node-tools";
7
- if (isInstance) {
8
- nodeTools.classList.add("is-instance");
9
- }
10
- if (isTextEdit) {
11
- nodeTools.classList.add("is-text-edit");
12
- }
8
+ toggleClass(nodeTools, "is-instance", isInstance);
9
+ toggleClass(nodeTools, "is-text-edit", isTextEdit);
13
10
  highlightFrame.appendChild(nodeTools);
14
11
 
15
12
  createTagLabel(node, nodeTools);
@@ -0,0 +1,158 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import * as adjustForZoomModule from "@/lib/helpers/adjustForZoom";
3
+ import * as getCanvasWindowValueModule from "@/lib/canvas/helpers/getCanvasWindowValue";
4
+ import { getElementBounds } from "./getElementBounds";
5
+
6
+ vi.mock("@/lib/helpers/adjustForZoom");
7
+ vi.mock("@/lib/canvas/helpers/getCanvasWindowValue");
8
+
9
+ describe("getElementBounds", () => {
10
+ let element: HTMLElement;
11
+ let nodeProvider: HTMLElement;
12
+
13
+ beforeEach(() => {
14
+ nodeProvider = document.createElement("div");
15
+ nodeProvider.style.position = "relative";
16
+ nodeProvider.style.left = "100px";
17
+ nodeProvider.style.top = "200px";
18
+ document.body.appendChild(nodeProvider);
19
+
20
+ element = document.createElement("div");
21
+ element.style.position = "absolute";
22
+ element.style.left = "50px";
23
+ element.style.top = "75px";
24
+ element.style.width = "200px";
25
+ element.style.height = "150px";
26
+ nodeProvider.appendChild(element);
27
+
28
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1);
29
+ vi.mocked(adjustForZoomModule.adjustForZoom).mockImplementation((value) => value);
30
+ });
31
+
32
+ afterEach(() => {
33
+ if (document.body.contains(nodeProvider)) {
34
+ document.body.removeChild(nodeProvider);
35
+ }
36
+ vi.clearAllMocks();
37
+ });
38
+
39
+ it("should calculate relative bounds", () => {
40
+ const result = getElementBounds(element, nodeProvider);
41
+
42
+ expect(result).toHaveProperty("top");
43
+ expect(result).toHaveProperty("left");
44
+ expect(result).toHaveProperty("width");
45
+ expect(result).toHaveProperty("height");
46
+ expect(typeof result.top).toBe("number");
47
+ expect(typeof result.left).toBe("number");
48
+ expect(typeof result.width).toBe("number");
49
+ expect(typeof result.height).toBe("number");
50
+ });
51
+
52
+ it("should adjust bounds for zoom", () => {
53
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(2);
54
+ vi.mocked(adjustForZoomModule.adjustForZoom).mockImplementation((value) => value / 2);
55
+
56
+ const result = getElementBounds(element, nodeProvider);
57
+
58
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalled();
59
+ });
60
+
61
+ it("should use default zoom of 1 when zoom is undefined", () => {
62
+ vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(undefined);
63
+
64
+ getElementBounds(element, nodeProvider);
65
+
66
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalled();
67
+ });
68
+
69
+ it("should ensure minimum width of 4", () => {
70
+ element.style.width = "2px";
71
+ vi.mocked(adjustForZoomModule.adjustForZoom).mockImplementation((value) => {
72
+ // Return very small width
73
+ if (value < 10) return 2;
74
+ return value;
75
+ });
76
+
77
+ const result = getElementBounds(element, nodeProvider);
78
+
79
+ expect(result.width).toBeGreaterThanOrEqual(4);
80
+ });
81
+
82
+ it("should use custom canvas name", () => {
83
+ getElementBounds(element, nodeProvider, "custom-canvas");
84
+
85
+ expect(getCanvasWindowValueModule.getCanvasWindowValue).toHaveBeenCalledWith(["zoom", "current"], "custom-canvas");
86
+ });
87
+
88
+ it("should calculate relative position correctly", () => {
89
+ const elementRect = {
90
+ top: 275,
91
+ left: 150,
92
+ width: 200,
93
+ height: 150,
94
+ bottom: 425,
95
+ right: 350,
96
+ x: 150,
97
+ y: 275,
98
+ toJSON: vi.fn(),
99
+ };
100
+ const providerRect = {
101
+ top: 200,
102
+ left: 100,
103
+ width: 500,
104
+ height: 400,
105
+ bottom: 600,
106
+ right: 600,
107
+ x: 100,
108
+ y: 200,
109
+ toJSON: vi.fn(),
110
+ };
111
+
112
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(elementRect as DOMRect);
113
+ vi.spyOn(nodeProvider, "getBoundingClientRect").mockReturnValue(providerRect as DOMRect);
114
+
115
+ const result = getElementBounds(element, nodeProvider);
116
+
117
+ // Relative top = 275 - 200 = 75
118
+ // Relative left = 150 - 100 = 50
119
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalledWith(75, expect.any(Number));
120
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalledWith(50, expect.any(Number));
121
+ });
122
+
123
+ it("should handle negative relative positions", () => {
124
+ const elementRect = {
125
+ top: 150,
126
+ left: 50,
127
+ width: 200,
128
+ height: 150,
129
+ bottom: 300,
130
+ right: 250,
131
+ x: 50,
132
+ y: 150,
133
+ toJSON: vi.fn(),
134
+ };
135
+ const providerRect = {
136
+ top: 200,
137
+ left: 100,
138
+ width: 500,
139
+ height: 400,
140
+ bottom: 600,
141
+ right: 600,
142
+ x: 100,
143
+ y: 200,
144
+ toJSON: vi.fn(),
145
+ };
146
+
147
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(elementRect as DOMRect);
148
+ vi.spyOn(nodeProvider, "getBoundingClientRect").mockReturnValue(providerRect as DOMRect);
149
+
150
+ const result = getElementBounds(element, nodeProvider);
151
+
152
+ // Relative top = 150 - 200 = -50
153
+ // Relative left = 50 - 100 = -50
154
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalledWith(-50, expect.any(Number));
155
+ expect(adjustForZoomModule.adjustForZoom).toHaveBeenCalledWith(-50, expect.any(Number));
156
+ });
157
+ });
158
+
@@ -1,4 +1,5 @@
1
1
  import { getCanvasWindowValue } from "@/lib/canvas/helpers/getCanvasWindowValue";
2
+ import { adjustForZoom } from "@/lib/helpers/adjustForZoom";
2
3
 
3
4
  export function getElementBounds(
4
5
  element: Element,
@@ -16,12 +17,12 @@ export function getElementBounds(
16
17
  const relativeTop = elementRect.top - componentRootRect.top;
17
18
  const relativeLeft = elementRect.left - componentRootRect.left;
18
19
 
19
- const zoom = getCanvasWindowValue(["zoom", "current"], canvasName) ?? 1;
20
+ const zoom = (getCanvasWindowValue(["zoom", "current"], canvasName) as number | undefined) ?? 1;
20
21
 
21
- const top = parseFloat((relativeTop / zoom).toFixed(5));
22
- const left = parseFloat((relativeLeft / zoom).toFixed(5));
23
- const width = Math.max(4, parseFloat((elementRect.width / zoom).toFixed(5)));
24
- const height = parseFloat((elementRect.height / zoom).toFixed(5));
22
+ const top = adjustForZoom(relativeTop, zoom);
23
+ const left = adjustForZoom(relativeLeft, zoom);
24
+ const width = Math.max(4, adjustForZoom(elementRect.width, zoom));
25
+ const height = adjustForZoom(elementRect.height, zoom);
25
26
 
26
27
  return {
27
28
  top,
@@ -0,0 +1,78 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import * as getCanvasContainerOrBodyModule from "@/lib/canvas/helpers/getCanvasContainerOrBody";
3
+ import { getHighlightFrameElement } from "./getHighlightFrameElement";
4
+
5
+ vi.mock("@/lib/canvas/helpers/getCanvasContainerOrBody");
6
+
7
+ describe("getHighlightFrameElement", () => {
8
+ let container: HTMLElement;
9
+ let highlightFrame: SVGSVGElement;
10
+
11
+ beforeEach(() => {
12
+ container = document.createElement("div");
13
+ document.body.appendChild(container);
14
+
15
+ highlightFrame = document.createElementNS("http://www.w3.org/2000/svg", "svg");
16
+ highlightFrame.classList.add("highlight-frame-overlay");
17
+ });
18
+
19
+ afterEach(() => {
20
+ if (document.body.contains(container)) {
21
+ document.body.removeChild(container);
22
+ }
23
+ vi.clearAllMocks();
24
+ });
25
+
26
+ it("should return highlight frame element when it exists", () => {
27
+ container.appendChild(highlightFrame);
28
+ vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
29
+
30
+ const result = getHighlightFrameElement();
31
+
32
+ expect(result).toBe(highlightFrame);
33
+ });
34
+
35
+ it("should return null when highlight frame does not exist", () => {
36
+ vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
37
+
38
+ const result = getHighlightFrameElement();
39
+
40
+ expect(result).toBeNull();
41
+ });
42
+
43
+ it("should return first highlight frame when multiple exist", () => {
44
+ const frame1 = document.createElementNS("http://www.w3.org/2000/svg", "svg");
45
+ frame1.classList.add("highlight-frame-overlay");
46
+ const frame2 = document.createElementNS("http://www.w3.org/2000/svg", "svg");
47
+ frame2.classList.add("highlight-frame-overlay");
48
+ container.appendChild(frame1);
49
+ container.appendChild(frame2);
50
+ vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
51
+
52
+ const result = getHighlightFrameElement();
53
+
54
+ expect(result).toBe(frame1);
55
+ });
56
+
57
+ it("should return null after frame is removed", () => {
58
+ container.appendChild(highlightFrame);
59
+ vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
60
+
61
+ const result1 = getHighlightFrameElement();
62
+ expect(result1).toBe(highlightFrame);
63
+
64
+ container.removeChild(highlightFrame);
65
+ const result2 = getHighlightFrameElement();
66
+ expect(result2).toBeNull();
67
+ });
68
+
69
+ it("should return SVG element", () => {
70
+ container.appendChild(highlightFrame);
71
+ vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
72
+
73
+ const result = getHighlightFrameElement();
74
+
75
+ expect(result).toBeInstanceOf(SVGSVGElement);
76
+ });
77
+ });
78
+
@@ -1,7 +1,6 @@
1
- import { getCanvasContainer } from "@/lib/canvas/helpers/getCanvasContainer";
1
+ import { getCanvasContainerOrBody } from "@/lib/canvas/helpers/getCanvasContainerOrBody";
2
2
 
3
3
  export function getHighlightFrameElement(): SVGSVGElement | null {
4
- const canvasContainer = getCanvasContainer();
5
- const container = canvasContainer || document.body;
4
+ const container = getCanvasContainerOrBody();
6
5
  return container.querySelector(".highlight-frame-overlay") as SVGSVGElement | null;
7
6
  }
@@ -0,0 +1,133 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { getScreenBounds } from "./getScreenBounds";
3
+
4
+ describe("getScreenBounds", () => {
5
+ let element: HTMLElement;
6
+
7
+ beforeEach(() => {
8
+ element = document.createElement("div");
9
+ document.body.appendChild(element);
10
+ });
11
+
12
+ afterEach(() => {
13
+ if (document.body.contains(element)) {
14
+ document.body.removeChild(element);
15
+ }
16
+ });
17
+
18
+ it("should return bounds from getBoundingClientRect", () => {
19
+ // Mock getBoundingClientRect
20
+ const mockRect = {
21
+ top: 100,
22
+ left: 200,
23
+ width: 300,
24
+ height: 400,
25
+ bottom: 500,
26
+ right: 500,
27
+ x: 200,
28
+ y: 100,
29
+ toJSON: vi.fn(),
30
+ };
31
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
32
+
33
+ const result = getScreenBounds(element);
34
+
35
+ expect(result.top).toBe(100);
36
+ expect(result.left).toBe(200);
37
+ expect(result.width).toBe(300);
38
+ expect(result.height).toBe(400);
39
+ });
40
+
41
+ it("should handle zero dimensions", () => {
42
+ const mockRect = {
43
+ top: 0,
44
+ left: 0,
45
+ width: 0,
46
+ height: 0,
47
+ bottom: 0,
48
+ right: 0,
49
+ x: 0,
50
+ y: 0,
51
+ toJSON: vi.fn(),
52
+ };
53
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
54
+
55
+ const result = getScreenBounds(element);
56
+
57
+ expect(result.top).toBe(0);
58
+ expect(result.left).toBe(0);
59
+ expect(result.width).toBe(0);
60
+ expect(result.height).toBe(0);
61
+ });
62
+
63
+ it("should handle negative positions", () => {
64
+ const mockRect = {
65
+ top: -50,
66
+ left: -100,
67
+ width: 200,
68
+ height: 150,
69
+ bottom: 100,
70
+ right: 100,
71
+ x: -100,
72
+ y: -50,
73
+ toJSON: vi.fn(),
74
+ };
75
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
76
+
77
+ const result = getScreenBounds(element);
78
+
79
+ expect(result.top).toBe(-50);
80
+ expect(result.left).toBe(-100);
81
+ expect(result.width).toBe(200);
82
+ expect(result.height).toBe(150);
83
+ });
84
+
85
+ it("should handle decimal values", () => {
86
+ const mockRect = {
87
+ top: 123.45,
88
+ left: 678.90,
89
+ width: 234.56,
90
+ height: 789.01,
91
+ bottom: 912.46,
92
+ right: 913.46,
93
+ x: 678.90,
94
+ y: 123.45,
95
+ toJSON: vi.fn(),
96
+ };
97
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
98
+
99
+ const result = getScreenBounds(element);
100
+
101
+ expect(result.top).toBe(123.45);
102
+ expect(result.left).toBe(678.9);
103
+ expect(result.width).toBe(234.56);
104
+ expect(result.height).toBe(789.01);
105
+ });
106
+
107
+ it("should return object with all required properties", () => {
108
+ const mockRect = {
109
+ top: 100,
110
+ left: 200,
111
+ width: 300,
112
+ height: 400,
113
+ bottom: 500,
114
+ right: 500,
115
+ x: 200,
116
+ y: 100,
117
+ toJSON: vi.fn(),
118
+ };
119
+ vi.spyOn(element, "getBoundingClientRect").mockReturnValue(mockRect as DOMRect);
120
+
121
+ const result = getScreenBounds(element);
122
+
123
+ expect(result).toHaveProperty("top");
124
+ expect(result).toHaveProperty("left");
125
+ expect(result).toHaveProperty("width");
126
+ expect(result).toHaveProperty("height");
127
+ expect(typeof result.top).toBe("number");
128
+ expect(typeof result.left).toBe("number");
129
+ expect(typeof result.width).toBe("number");
130
+ expect(typeof result.height).toBe("number");
131
+ });
132
+ });
133
+