@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,213 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as getCanvasContainerOrBodyModule from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
3
|
+
import * as toggleClassModule from "@/lib/helpers/toggleClass";
|
|
4
|
+
import * as isComponentInstanceModule from "../select/helpers/isComponentInstance";
|
|
5
|
+
import * as createHighlightFrameModule from "./createHighlightFrame";
|
|
6
|
+
import * as createToolsContainerModule from "./createToolsContainer";
|
|
7
|
+
import * as getHighlightFrameElementModule from "./helpers/getHighlightFrameElement";
|
|
8
|
+
import * as getScreenBoundsModule from "./helpers/getScreenBounds";
|
|
9
|
+
import { highlightNode } from "./highlightNode";
|
|
10
|
+
|
|
11
|
+
vi.mock("@/lib/canvas/helpers/getCanvasContainerOrBody");
|
|
12
|
+
vi.mock("@/lib/helpers/toggleClass");
|
|
13
|
+
vi.mock("../select/helpers/isComponentInstance");
|
|
14
|
+
vi.mock("./createHighlightFrame");
|
|
15
|
+
vi.mock("./createToolsContainer");
|
|
16
|
+
vi.mock("./helpers/getHighlightFrameElement");
|
|
17
|
+
vi.mock("./helpers/getScreenBounds");
|
|
18
|
+
|
|
19
|
+
describe("highlightNode", () => {
|
|
20
|
+
let node: HTMLElement;
|
|
21
|
+
let container: HTMLElement;
|
|
22
|
+
let existingFrame: SVGSVGElement;
|
|
23
|
+
let existingToolsWrapper: HTMLElement;
|
|
24
|
+
let newFrame: SVGSVGElement;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
node = document.createElement("div");
|
|
28
|
+
node.setAttribute("data-node-id", "test-node");
|
|
29
|
+
document.body.appendChild(node);
|
|
30
|
+
|
|
31
|
+
container = document.createElement("div");
|
|
32
|
+
document.body.appendChild(container);
|
|
33
|
+
|
|
34
|
+
existingFrame = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
35
|
+
existingFrame.classList.add("highlight-frame-overlay");
|
|
36
|
+
container.appendChild(existingFrame);
|
|
37
|
+
|
|
38
|
+
existingToolsWrapper = document.createElement("div");
|
|
39
|
+
existingToolsWrapper.classList.add("highlight-frame-tools-wrapper");
|
|
40
|
+
container.appendChild(existingToolsWrapper);
|
|
41
|
+
|
|
42
|
+
newFrame = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
43
|
+
newFrame.classList.add("highlight-frame-overlay");
|
|
44
|
+
|
|
45
|
+
vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
|
|
46
|
+
vi.mocked(getHighlightFrameElementModule.getHighlightFrameElement).mockReturnValue(existingFrame);
|
|
47
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(false);
|
|
48
|
+
vi.mocked(getScreenBoundsModule.getScreenBounds).mockReturnValue({
|
|
49
|
+
top: 100,
|
|
50
|
+
left: 200,
|
|
51
|
+
width: 300,
|
|
52
|
+
height: 400,
|
|
53
|
+
});
|
|
54
|
+
vi.mocked(createHighlightFrameModule.createHighlightFrame).mockReturnValue(newFrame);
|
|
55
|
+
vi.mocked(toggleClassModule.toggleClass).mockImplementation(() => {});
|
|
56
|
+
vi.mocked(createToolsContainerModule.createToolsContainer).mockImplementation(() => {});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
if (document.body.contains(node)) {
|
|
61
|
+
document.body.removeChild(node);
|
|
62
|
+
}
|
|
63
|
+
if (document.body.contains(container)) {
|
|
64
|
+
document.body.removeChild(container);
|
|
65
|
+
}
|
|
66
|
+
vi.clearAllMocks();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should do nothing when node is null", () => {
|
|
70
|
+
highlightNode(null);
|
|
71
|
+
|
|
72
|
+
expect(createHighlightFrameModule.createHighlightFrame).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should remove existing highlight frame", () => {
|
|
76
|
+
highlightNode(node);
|
|
77
|
+
|
|
78
|
+
expect(existingFrame.parentNode).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should remove existing tools wrapper", () => {
|
|
82
|
+
highlightNode(node);
|
|
83
|
+
|
|
84
|
+
expect(existingToolsWrapper.parentNode).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should create new highlight frame", () => {
|
|
88
|
+
highlightNode(node);
|
|
89
|
+
|
|
90
|
+
expect(createHighlightFrameModule.createHighlightFrame).toHaveBeenCalledWith(node, false, false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should create highlight frame with instance flag", () => {
|
|
94
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(true);
|
|
95
|
+
|
|
96
|
+
highlightNode(node);
|
|
97
|
+
|
|
98
|
+
expect(createHighlightFrameModule.createHighlightFrame).toHaveBeenCalledWith(node, true, false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should create highlight frame with text edit flag", () => {
|
|
102
|
+
node.contentEditable = "true";
|
|
103
|
+
|
|
104
|
+
highlightNode(node);
|
|
105
|
+
|
|
106
|
+
expect(createHighlightFrameModule.createHighlightFrame).toHaveBeenCalledWith(node, false, true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should add is-editable class when node is contentEditable", () => {
|
|
110
|
+
node.contentEditable = "true";
|
|
111
|
+
|
|
112
|
+
highlightNode(node);
|
|
113
|
+
|
|
114
|
+
expect(newFrame.classList.contains("is-editable")).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should create tools wrapper with correct styles", () => {
|
|
118
|
+
highlightNode(node);
|
|
119
|
+
|
|
120
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
121
|
+
expect(toolsWrapper).not.toBeNull();
|
|
122
|
+
expect((toolsWrapper as HTMLElement).style.position).toBe("absolute");
|
|
123
|
+
expect((toolsWrapper as HTMLElement).style.transform).toBe("translate(200px, 500px)");
|
|
124
|
+
expect((toolsWrapper as HTMLElement).style.transformOrigin).toBe("left center");
|
|
125
|
+
expect((toolsWrapper as HTMLElement).style.pointerEvents).toBe("none");
|
|
126
|
+
expect((toolsWrapper as HTMLElement).style.zIndex).toBe("500");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should toggle classes on tools wrapper", () => {
|
|
130
|
+
highlightNode(node);
|
|
131
|
+
|
|
132
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should create tools container", () => {
|
|
136
|
+
highlightNode(node);
|
|
137
|
+
|
|
138
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
139
|
+
expect(createToolsContainerModule.createToolsContainer).toHaveBeenCalledWith(
|
|
140
|
+
node,
|
|
141
|
+
toolsWrapper as HTMLElement,
|
|
142
|
+
false,
|
|
143
|
+
false
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should append tools wrapper to container", () => {
|
|
148
|
+
highlightNode(node);
|
|
149
|
+
|
|
150
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
151
|
+
expect(toolsWrapper?.parentNode).toBe(container);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should handle instance node", () => {
|
|
155
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(true);
|
|
156
|
+
|
|
157
|
+
highlightNode(node);
|
|
158
|
+
|
|
159
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
160
|
+
expect(createToolsContainerModule.createToolsContainer).toHaveBeenCalledWith(
|
|
161
|
+
node,
|
|
162
|
+
toolsWrapper as HTMLElement,
|
|
163
|
+
true,
|
|
164
|
+
false
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("should handle text edit node", () => {
|
|
169
|
+
node.contentEditable = "true";
|
|
170
|
+
|
|
171
|
+
highlightNode(node);
|
|
172
|
+
|
|
173
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
174
|
+
expect(createToolsContainerModule.createToolsContainer).toHaveBeenCalledWith(
|
|
175
|
+
node,
|
|
176
|
+
toolsWrapper as HTMLElement,
|
|
177
|
+
false,
|
|
178
|
+
true
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should calculate bottomY correctly", () => {
|
|
183
|
+
vi.mocked(getScreenBoundsModule.getScreenBounds).mockReturnValue({
|
|
184
|
+
top: 50,
|
|
185
|
+
left: 100,
|
|
186
|
+
width: 200,
|
|
187
|
+
height: 150,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
highlightNode(node);
|
|
191
|
+
|
|
192
|
+
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
193
|
+
expect((toolsWrapper as HTMLElement).style.transform).toBe("translate(100px, 200px)");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should work when no existing frame exists", () => {
|
|
197
|
+
vi.mocked(getHighlightFrameElementModule.getHighlightFrameElement).mockReturnValue(null);
|
|
198
|
+
container.removeChild(existingFrame);
|
|
199
|
+
|
|
200
|
+
expect(() => {
|
|
201
|
+
highlightNode(node);
|
|
202
|
+
}).not.toThrow();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should work when no existing tools wrapper exists", () => {
|
|
206
|
+
container.removeChild(existingToolsWrapper);
|
|
207
|
+
|
|
208
|
+
expect(() => {
|
|
209
|
+
highlightNode(node);
|
|
210
|
+
}).not.toThrow();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCanvasContainerOrBody } from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
2
|
+
import { toggleClass } from "@/lib/helpers/toggleClass";
|
|
2
3
|
import { isComponentInstance } from "../select/helpers/isComponentInstance";
|
|
3
4
|
import { createHighlightFrame } from "./createHighlightFrame";
|
|
4
5
|
import { createToolsContainer } from "./createToolsContainer";
|
|
@@ -9,9 +10,8 @@ export const highlightNode = (node: HTMLElement | null): void => {
|
|
|
9
10
|
if (!node) return;
|
|
10
11
|
|
|
11
12
|
const existingHighlightFrame = getHighlightFrameElement();
|
|
12
|
-
const
|
|
13
|
-
const existingToolsWrapper =
|
|
14
|
-
canvasContainer?.querySelector(".highlight-frame-tools-wrapper") || document.body.querySelector(".highlight-frame-tools-wrapper");
|
|
13
|
+
const container = getCanvasContainerOrBody();
|
|
14
|
+
const existingToolsWrapper = container.querySelector(".highlight-frame-tools-wrapper");
|
|
15
15
|
|
|
16
16
|
if (existingHighlightFrame) {
|
|
17
17
|
existingHighlightFrame.remove();
|
|
@@ -35,12 +35,8 @@ export const highlightNode = (node: HTMLElement | null): void => {
|
|
|
35
35
|
// Create tools wrapper using CSS transform (GPU-accelerated)
|
|
36
36
|
const toolsWrapper = document.createElement("div");
|
|
37
37
|
toolsWrapper.classList.add("highlight-frame-tools-wrapper");
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
if (isTextEdit) {
|
|
42
|
-
toolsWrapper.classList.add("is-text-edit");
|
|
43
|
-
}
|
|
38
|
+
toggleClass(toolsWrapper, "is-instance", isInstance);
|
|
39
|
+
toggleClass(toolsWrapper, "is-text-edit", isTextEdit);
|
|
44
40
|
toolsWrapper.style.position = "absolute";
|
|
45
41
|
toolsWrapper.style.transform = `translate(${left}px, ${bottomY}px)`;
|
|
46
42
|
toolsWrapper.style.transformOrigin = "left center";
|
|
@@ -48,9 +44,5 @@ export const highlightNode = (node: HTMLElement | null): void => {
|
|
|
48
44
|
toolsWrapper.style.zIndex = "500";
|
|
49
45
|
|
|
50
46
|
createToolsContainer(node, toolsWrapper, isInstance, isTextEdit);
|
|
51
|
-
|
|
52
|
-
canvasContainer.appendChild(toolsWrapper);
|
|
53
|
-
} else {
|
|
54
|
-
document.body.appendChild(toolsWrapper);
|
|
55
|
-
}
|
|
47
|
+
container.appendChild(toolsWrapper);
|
|
56
48
|
};
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as getCanvasContainerOrBodyModule from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
3
|
+
import * as getCanvasWindowValueModule from "@/lib/canvas/helpers/getCanvasWindowValue";
|
|
4
|
+
import * as getViewportDimensionsModule from "@/lib/helpers/getViewportDimensions";
|
|
5
|
+
import * as toggleClassModule from "@/lib/helpers/toggleClass";
|
|
6
|
+
import * as isComponentInstanceModule from "../select/helpers/isComponentInstance";
|
|
7
|
+
import * as getHighlightFrameElementModule from "./helpers/getHighlightFrameElement";
|
|
8
|
+
import * as getScreenBoundsModule from "./helpers/getScreenBounds";
|
|
9
|
+
import { refreshHighlightFrame } from "./refreshHighlightFrame";
|
|
10
|
+
|
|
11
|
+
vi.mock("@/lib/canvas/helpers/getCanvasContainerOrBody");
|
|
12
|
+
vi.mock("@/lib/canvas/helpers/getCanvasWindowValue");
|
|
13
|
+
vi.mock("@/lib/helpers/getViewportDimensions");
|
|
14
|
+
vi.mock("@/lib/helpers/toggleClass");
|
|
15
|
+
vi.mock("../select/helpers/isComponentInstance");
|
|
16
|
+
vi.mock("./helpers/getHighlightFrameElement");
|
|
17
|
+
vi.mock("./helpers/getScreenBounds");
|
|
18
|
+
|
|
19
|
+
describe("refreshHighlightFrame", () => {
|
|
20
|
+
let node: HTMLElement;
|
|
21
|
+
let nodeProvider: HTMLElement;
|
|
22
|
+
let container: HTMLElement;
|
|
23
|
+
let frame: SVGSVGElement;
|
|
24
|
+
let group: SVGGElement;
|
|
25
|
+
let rect: SVGRectElement;
|
|
26
|
+
let toolsWrapper: HTMLElement;
|
|
27
|
+
let nodeTools: HTMLElement;
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
node = document.createElement("div");
|
|
31
|
+
node.setAttribute("data-node-id", "test-node");
|
|
32
|
+
document.body.appendChild(node);
|
|
33
|
+
|
|
34
|
+
nodeProvider = document.createElement("div");
|
|
35
|
+
document.body.appendChild(nodeProvider);
|
|
36
|
+
|
|
37
|
+
container = document.createElement("div");
|
|
38
|
+
document.body.appendChild(container);
|
|
39
|
+
|
|
40
|
+
frame = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
41
|
+
frame.classList.add("highlight-frame-overlay");
|
|
42
|
+
container.appendChild(frame);
|
|
43
|
+
|
|
44
|
+
group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
45
|
+
group.classList.add("highlight-frame-group");
|
|
46
|
+
frame.appendChild(group);
|
|
47
|
+
|
|
48
|
+
rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
49
|
+
group.appendChild(rect);
|
|
50
|
+
|
|
51
|
+
toolsWrapper = document.createElement("div");
|
|
52
|
+
toolsWrapper.classList.add("highlight-frame-tools-wrapper");
|
|
53
|
+
container.appendChild(toolsWrapper);
|
|
54
|
+
|
|
55
|
+
nodeTools = document.createElement("div");
|
|
56
|
+
nodeTools.classList.add("node-tools");
|
|
57
|
+
toolsWrapper.appendChild(nodeTools);
|
|
58
|
+
|
|
59
|
+
vi.mocked(getCanvasContainerOrBodyModule.getCanvasContainerOrBody).mockReturnValue(container);
|
|
60
|
+
vi.mocked(getHighlightFrameElementModule.getHighlightFrameElement).mockReturnValue(frame);
|
|
61
|
+
vi.mocked(getViewportDimensionsModule.getViewportDimensions).mockReturnValue({
|
|
62
|
+
width: 1920,
|
|
63
|
+
height: 1080,
|
|
64
|
+
});
|
|
65
|
+
vi.mocked(getScreenBoundsModule.getScreenBounds).mockReturnValue({
|
|
66
|
+
top: 100,
|
|
67
|
+
left: 200,
|
|
68
|
+
width: 300,
|
|
69
|
+
height: 400,
|
|
70
|
+
});
|
|
71
|
+
vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(1);
|
|
72
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(false);
|
|
73
|
+
vi.mocked(toggleClassModule.toggleClass).mockImplementation(() => {});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterEach(() => {
|
|
77
|
+
if (document.body.contains(node)) {
|
|
78
|
+
document.body.removeChild(node);
|
|
79
|
+
}
|
|
80
|
+
if (document.body.contains(nodeProvider)) {
|
|
81
|
+
document.body.removeChild(nodeProvider);
|
|
82
|
+
}
|
|
83
|
+
if (document.body.contains(container)) {
|
|
84
|
+
document.body.removeChild(container);
|
|
85
|
+
}
|
|
86
|
+
vi.clearAllMocks();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should do nothing when frame does not exist", () => {
|
|
90
|
+
vi.mocked(getHighlightFrameElementModule.getHighlightFrameElement).mockReturnValue(null);
|
|
91
|
+
|
|
92
|
+
expect(() => {
|
|
93
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
94
|
+
}).not.toThrow();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should update SVG dimensions", () => {
|
|
98
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
99
|
+
|
|
100
|
+
expect(frame.getAttribute("width")).toBe("1920");
|
|
101
|
+
expect(frame.getAttribute("height")).toBe("1080");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should toggle is-instance class", () => {
|
|
105
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(true);
|
|
106
|
+
|
|
107
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
108
|
+
|
|
109
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(frame, "is-instance", true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should toggle is-text-edit class", () => {
|
|
113
|
+
node.contentEditable = "true";
|
|
114
|
+
|
|
115
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
116
|
+
|
|
117
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(frame, "is-text-edit", true);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should update group transform", () => {
|
|
121
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
122
|
+
|
|
123
|
+
expect(group.getAttribute("transform")).toBe("translate(200, 100)");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should update rect dimensions", () => {
|
|
127
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
128
|
+
|
|
129
|
+
expect(rect.getAttribute("width")).toBe("300");
|
|
130
|
+
expect(rect.getAttribute("height")).toBe("400");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should ensure minimum width of 3", () => {
|
|
134
|
+
vi.mocked(getScreenBoundsModule.getScreenBounds).mockReturnValue({
|
|
135
|
+
top: 100,
|
|
136
|
+
left: 200,
|
|
137
|
+
width: 1,
|
|
138
|
+
height: 400,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
142
|
+
|
|
143
|
+
expect(rect.getAttribute("width")).toBe("3");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should apply instance color when isInstance is true", () => {
|
|
147
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
148
|
+
window.getComputedStyle = vi.fn().mockReturnValue({
|
|
149
|
+
getPropertyValue: vi.fn((prop: string) => {
|
|
150
|
+
if (prop === "--component-color") return "rgb(255, 0, 0)";
|
|
151
|
+
return "";
|
|
152
|
+
}),
|
|
153
|
+
} as unknown as CSSStyleDeclaration);
|
|
154
|
+
|
|
155
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(true);
|
|
156
|
+
|
|
157
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
158
|
+
|
|
159
|
+
expect(rect.getAttribute("stroke")).toBe("rgb(255, 0, 0)");
|
|
160
|
+
|
|
161
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should apply text edit color when isTextEdit is true", () => {
|
|
165
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
166
|
+
window.getComputedStyle = vi.fn().mockReturnValue({
|
|
167
|
+
getPropertyValue: vi.fn((prop: string) => {
|
|
168
|
+
if (prop === "--text-edit-color") return "rgb(0, 255, 0)";
|
|
169
|
+
return "";
|
|
170
|
+
}),
|
|
171
|
+
} as unknown as CSSStyleDeclaration);
|
|
172
|
+
|
|
173
|
+
node.contentEditable = "true";
|
|
174
|
+
|
|
175
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
176
|
+
|
|
177
|
+
expect(rect.getAttribute("stroke")).toBe("rgb(0, 255, 0)");
|
|
178
|
+
|
|
179
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should remove stroke when neither flag is true", () => {
|
|
183
|
+
rect.setAttribute("stroke", "rgb(255, 0, 0)");
|
|
184
|
+
|
|
185
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
186
|
+
|
|
187
|
+
expect(rect.getAttribute("stroke")).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("should update tools wrapper transform", () => {
|
|
191
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
192
|
+
|
|
193
|
+
expect(toolsWrapper.style.transform).toBe("translate(200px, 500px)");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should toggle classes on tools wrapper", () => {
|
|
197
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
198
|
+
|
|
199
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(toolsWrapper, "is-instance", false);
|
|
200
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(toolsWrapper, "is-text-edit", false);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should toggle classes on node tools", () => {
|
|
204
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
205
|
+
|
|
206
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(nodeTools, "is-instance", false);
|
|
207
|
+
expect(toggleClassModule.toggleClass).toHaveBeenCalledWith(nodeTools, "is-text-edit", false);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should update tool opacity when zoom <= 10", () => {
|
|
211
|
+
vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(5);
|
|
212
|
+
|
|
213
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
214
|
+
|
|
215
|
+
expect(nodeProvider.style.getPropertyValue("--tool-opacity")).toBe("1");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should set tool opacity to 0 when zoom > 10", () => {
|
|
219
|
+
vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(15);
|
|
220
|
+
|
|
221
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
222
|
+
|
|
223
|
+
expect(nodeProvider.style.getPropertyValue("--tool-opacity")).toBe("0");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("should use default zoom of 1 when zoom is undefined", () => {
|
|
227
|
+
vi.mocked(getCanvasWindowValueModule.getCanvasWindowValue).mockReturnValue(undefined);
|
|
228
|
+
|
|
229
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
230
|
+
|
|
231
|
+
expect(nodeProvider.style.getPropertyValue("--tool-opacity")).toBe("1");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should use custom canvas name", () => {
|
|
235
|
+
refreshHighlightFrame(node, nodeProvider, "custom-canvas");
|
|
236
|
+
|
|
237
|
+
expect(getCanvasWindowValueModule.getCanvasWindowValue).toHaveBeenCalledWith(["zoom", "current"], "custom-canvas");
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should update corner handle positions", () => {
|
|
241
|
+
const topLeft = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
242
|
+
topLeft.classList.add("handle-top-left");
|
|
243
|
+
group.appendChild(topLeft);
|
|
244
|
+
|
|
245
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
246
|
+
|
|
247
|
+
expect(topLeft.getAttribute("x")).toBe("-3");
|
|
248
|
+
expect(topLeft.getAttribute("y")).toBe("-3");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("should update all corner handles", () => {
|
|
252
|
+
const topLeft = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
253
|
+
topLeft.classList.add("handle-top-left");
|
|
254
|
+
const topRight = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
255
|
+
topRight.classList.add("handle-top-right");
|
|
256
|
+
const bottomRight = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
257
|
+
bottomRight.classList.add("handle-bottom-right");
|
|
258
|
+
const bottomLeft = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
259
|
+
bottomLeft.classList.add("handle-bottom-left");
|
|
260
|
+
group.appendChild(topLeft);
|
|
261
|
+
group.appendChild(topRight);
|
|
262
|
+
group.appendChild(bottomRight);
|
|
263
|
+
group.appendChild(bottomLeft);
|
|
264
|
+
|
|
265
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
266
|
+
|
|
267
|
+
expect(topLeft.getAttribute("x")).toBe("-3");
|
|
268
|
+
expect(topLeft.getAttribute("y")).toBe("-3");
|
|
269
|
+
expect(topRight.getAttribute("x")).toBe("297");
|
|
270
|
+
expect(topRight.getAttribute("y")).toBe("-3");
|
|
271
|
+
expect(bottomRight.getAttribute("x")).toBe("297");
|
|
272
|
+
expect(bottomRight.getAttribute("y")).toBe("397");
|
|
273
|
+
expect(bottomLeft.getAttribute("x")).toBe("-3");
|
|
274
|
+
expect(bottomLeft.getAttribute("y")).toBe("397");
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should update handle colors for instance", () => {
|
|
278
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
279
|
+
window.getComputedStyle = vi.fn().mockReturnValue({
|
|
280
|
+
getPropertyValue: vi.fn((prop: string) => {
|
|
281
|
+
if (prop === "--component-color") return "rgb(255, 0, 0)";
|
|
282
|
+
return "";
|
|
283
|
+
}),
|
|
284
|
+
} as unknown as CSSStyleDeclaration);
|
|
285
|
+
|
|
286
|
+
const handle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
287
|
+
handle.classList.add("handle-top-left");
|
|
288
|
+
group.appendChild(handle);
|
|
289
|
+
|
|
290
|
+
vi.mocked(isComponentInstanceModule.isComponentInstance).mockReturnValue(true);
|
|
291
|
+
|
|
292
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
293
|
+
|
|
294
|
+
expect(handle.getAttribute("stroke")).toBe("rgb(255, 0, 0)");
|
|
295
|
+
|
|
296
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("should not update when group does not exist", () => {
|
|
300
|
+
group.remove();
|
|
301
|
+
|
|
302
|
+
expect(() => {
|
|
303
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
304
|
+
}).not.toThrow();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("should not update when rect does not exist", () => {
|
|
308
|
+
rect.remove();
|
|
309
|
+
|
|
310
|
+
expect(() => {
|
|
311
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
312
|
+
}).not.toThrow();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("should not update tools wrapper when it does not exist", () => {
|
|
316
|
+
container.removeChild(toolsWrapper);
|
|
317
|
+
|
|
318
|
+
expect(() => {
|
|
319
|
+
refreshHighlightFrame(node, nodeProvider);
|
|
320
|
+
}).not.toThrow();
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCanvasContainerOrBody } from "@/lib/canvas/helpers/getCanvasContainerOrBody";
|
|
2
2
|
import { getCanvasWindowValue } from "@/lib/canvas/helpers/getCanvasWindowValue";
|
|
3
|
+
import { getViewportDimensions } from "@/lib/helpers/getViewportDimensions";
|
|
4
|
+
import { toggleClass } from "@/lib/helpers/toggleClass";
|
|
3
5
|
import { isComponentInstance } from "../select/helpers/isComponentInstance";
|
|
4
6
|
import { getHighlightFrameElement } from "./helpers/getHighlightFrameElement";
|
|
5
7
|
import { getScreenBounds } from "./helpers/getScreenBounds";
|
|
@@ -22,24 +24,15 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
22
24
|
|
|
23
25
|
// Update SVG dimensions to match current viewport (handles window resize and ensures coordinate system is correct)
|
|
24
26
|
// Use clientWidth/Height to match getBoundingClientRect() coordinate system (excludes scrollbars)
|
|
25
|
-
const viewportWidth
|
|
26
|
-
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
27
|
+
const { width: viewportWidth, height: viewportHeight } = getViewportDimensions();
|
|
27
28
|
frame.setAttribute("width", viewportWidth.toString());
|
|
28
29
|
frame.setAttribute("height", viewportHeight.toString());
|
|
29
30
|
|
|
30
31
|
// Update instance class
|
|
31
|
-
|
|
32
|
-
frame.classList.add("is-instance");
|
|
33
|
-
} else {
|
|
34
|
-
frame.classList.remove("is-instance");
|
|
35
|
-
}
|
|
32
|
+
toggleClass(frame, "is-instance", isInstance);
|
|
36
33
|
|
|
37
34
|
// Update text edit class
|
|
38
|
-
|
|
39
|
-
frame.classList.add("is-text-edit");
|
|
40
|
-
} else {
|
|
41
|
-
frame.classList.remove("is-text-edit");
|
|
42
|
-
}
|
|
35
|
+
toggleClass(frame, "is-text-edit", isTextEdit);
|
|
43
36
|
|
|
44
37
|
const group = frame.querySelector(".highlight-frame-group") as SVGGElement | null;
|
|
45
38
|
if (!group) return;
|
|
@@ -56,12 +49,11 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
56
49
|
rect.removeAttribute("stroke"); // Use CSS default
|
|
57
50
|
}
|
|
58
51
|
|
|
59
|
-
const
|
|
60
|
-
const container = canvasContainer || document.body;
|
|
52
|
+
const container = getCanvasContainerOrBody();
|
|
61
53
|
const toolsWrapper = container.querySelector(".highlight-frame-tools-wrapper") as HTMLElement | null;
|
|
62
54
|
const nodeTools = toolsWrapper?.querySelector(".node-tools") as HTMLElement | null;
|
|
63
55
|
|
|
64
|
-
const zoom = getCanvasWindowValue(["zoom", "current"], canvasName) ?? 1;
|
|
56
|
+
const zoom = (getCanvasWindowValue(["zoom", "current"], canvasName) as number | undefined) ?? 1;
|
|
65
57
|
const bounds = getScreenBounds(node);
|
|
66
58
|
|
|
67
59
|
// Calculate all values before any DOM writes
|
|
@@ -71,32 +63,10 @@ export const refreshHighlightFrame = (node: HTMLElement, nodeProvider: HTMLEleme
|
|
|
71
63
|
const bottomY = top + height;
|
|
72
64
|
|
|
73
65
|
// Update instance classes on tools wrapper and node tools
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
toolsWrapper.classList.remove("is-instance");
|
|
79
|
-
}
|
|
80
|
-
// Update text edit class
|
|
81
|
-
if (isTextEdit) {
|
|
82
|
-
toolsWrapper.classList.add("is-text-edit");
|
|
83
|
-
} else {
|
|
84
|
-
toolsWrapper.classList.remove("is-text-edit");
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (nodeTools) {
|
|
88
|
-
if (isInstance) {
|
|
89
|
-
nodeTools.classList.add("is-instance");
|
|
90
|
-
} else {
|
|
91
|
-
nodeTools.classList.remove("is-instance");
|
|
92
|
-
}
|
|
93
|
-
// Update text edit class
|
|
94
|
-
if (isTextEdit) {
|
|
95
|
-
nodeTools.classList.add("is-text-edit");
|
|
96
|
-
} else {
|
|
97
|
-
nodeTools.classList.remove("is-text-edit");
|
|
98
|
-
}
|
|
99
|
-
}
|
|
66
|
+
toggleClass(toolsWrapper, "is-instance", isInstance);
|
|
67
|
+
toggleClass(toolsWrapper, "is-text-edit", isTextEdit);
|
|
68
|
+
toggleClass(nodeTools, "is-instance", isInstance);
|
|
69
|
+
toggleClass(nodeTools, "is-text-edit", isTextEdit);
|
|
100
70
|
|
|
101
71
|
// Batch all DOM writes (single paint pass)
|
|
102
72
|
// Update group transform to move entire group (rect + handles) at once
|