@node-edit-utils/core 2.3.3 → 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/viewport/label/getViewportLabelOverlay.d.ts +1 -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 +100 -62
- package/dist/node-edit-utils.esm.js +100 -62
- package/dist/node-edit-utils.umd.js +100 -62
- 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/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/getCanvasWindowValue.test.ts +116 -0
- package/src/lib/helpers/adjustForZoom.test.ts +65 -0
- package/src/lib/helpers/createDragHandler.test.ts +325 -0
- package/src/lib/helpers/getNodeProvider.test.ts +71 -0
- package/src/lib/helpers/getNodeTools.test.ts +50 -0
- package/src/lib/helpers/getViewportDimensions.test.ts +93 -0
- 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/toggleClass.test.ts +71 -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/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/createCornerHandles.test.ts +150 -0
- package/src/lib/node-tools/highlight/createHighlightFrame.test.ts +237 -0
- 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/helpers/getElementBounds.test.ts +158 -0
- package/src/lib/node-tools/highlight/helpers/getHighlightFrameElement.test.ts +78 -0
- 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/refreshHighlightFrame.test.ts +323 -0
- package/src/lib/node-tools/highlight/updateHighlightFrameVisibility.test.ts +110 -0
- 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 +2 -2
- package/src/lib/viewport/createViewport.test.ts +267 -0
- package/src/lib/viewport/createViewport.ts +7 -4
- 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} +2 -1
- package/src/lib/viewport/label/helpers/getLabelPosition.test.ts +51 -0
- package/src/lib/viewport/label/helpers/getTransformValues.test.ts +59 -0
- 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 +8 -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 +17 -50
- 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/{setupViewportLabelDrag.ts → setupViewportDrag.ts} +14 -14
- 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/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
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as hasTextContentModule from "./hasTextContent";
|
|
3
|
+
import { shouldEnterTextEditMode } from "./shouldEnterTextEditMode";
|
|
4
|
+
|
|
5
|
+
vi.mock("./hasTextContent");
|
|
6
|
+
|
|
7
|
+
describe("shouldEnterTextEditMode", () => {
|
|
8
|
+
let node: HTMLElement;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
node = document.createElement("div");
|
|
12
|
+
document.body.appendChild(node);
|
|
13
|
+
vi.mocked(hasTextContentModule.hasTextContent).mockReturnValue(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
if (document.body.contains(node)) {
|
|
18
|
+
document.body.removeChild(node);
|
|
19
|
+
}
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should return false when node is null", () => {
|
|
24
|
+
const result = shouldEnterTextEditMode(null);
|
|
25
|
+
|
|
26
|
+
expect(result).toBe(false);
|
|
27
|
+
expect(hasTextContentModule.hasTextContent).not.toHaveBeenCalled();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should return false when node is undefined", () => {
|
|
31
|
+
const result = shouldEnterTextEditMode(undefined as unknown as HTMLElement);
|
|
32
|
+
|
|
33
|
+
expect(result).toBe(false);
|
|
34
|
+
expect(hasTextContentModule.hasTextContent).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return true when hasTextContent returns true", () => {
|
|
38
|
+
vi.mocked(hasTextContentModule.hasTextContent).mockReturnValue(true);
|
|
39
|
+
|
|
40
|
+
const result = shouldEnterTextEditMode(node);
|
|
41
|
+
|
|
42
|
+
expect(result).toBe(true);
|
|
43
|
+
expect(hasTextContentModule.hasTextContent).toHaveBeenCalledWith(node);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should return false when hasTextContent returns false", () => {
|
|
47
|
+
vi.mocked(hasTextContentModule.hasTextContent).mockReturnValue(false);
|
|
48
|
+
|
|
49
|
+
const result = shouldEnterTextEditMode(node);
|
|
50
|
+
|
|
51
|
+
expect(result).toBe(false);
|
|
52
|
+
expect(hasTextContentModule.hasTextContent).toHaveBeenCalledWith(node);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should call hasTextContent with the node", () => {
|
|
56
|
+
shouldEnterTextEditMode(node);
|
|
57
|
+
|
|
58
|
+
expect(hasTextContentModule.hasTextContent).toHaveBeenCalledWith(node);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as disableCanvasTextModeModule from "../../canvas/disableCanvasTextMode";
|
|
3
|
+
import * as enableCanvasTextModeModule from "../../canvas/enableCanvasTextMode";
|
|
4
|
+
import * as setupNodeListenersModule from "./events/setupNodeListeners";
|
|
5
|
+
import * as handleTextChangeModule from "./helpers/handleTextChange";
|
|
6
|
+
import * as hasTextContentModule from "./helpers/hasTextContent";
|
|
7
|
+
import * as makeNodeEditableModule from "./helpers/makeNodeEditable";
|
|
8
|
+
import * as makeNodeNonEditableModule from "./helpers/makeNodeNonEditable";
|
|
9
|
+
import { nodeText } from "./nodeText";
|
|
10
|
+
|
|
11
|
+
vi.mock("../../canvas/disableCanvasTextMode");
|
|
12
|
+
vi.mock("../../canvas/enableCanvasTextMode");
|
|
13
|
+
vi.mock("./events/setupNodeListeners");
|
|
14
|
+
vi.mock("./helpers/handleTextChange");
|
|
15
|
+
vi.mock("./helpers/hasTextContent");
|
|
16
|
+
vi.mock("./helpers/makeNodeEditable");
|
|
17
|
+
vi.mock("./helpers/makeNodeNonEditable");
|
|
18
|
+
|
|
19
|
+
describe("nodeText", () => {
|
|
20
|
+
let node: HTMLElement;
|
|
21
|
+
let nodeProvider: HTMLElement;
|
|
22
|
+
let cleanup: ReturnType<typeof vi.fn>;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
node = document.createElement("div");
|
|
26
|
+
node.setAttribute("data-node-id", "test-node");
|
|
27
|
+
node.textContent = "Test content";
|
|
28
|
+
document.body.appendChild(node);
|
|
29
|
+
|
|
30
|
+
nodeProvider = document.createElement("div");
|
|
31
|
+
document.body.appendChild(nodeProvider);
|
|
32
|
+
|
|
33
|
+
cleanup = vi.fn();
|
|
34
|
+
|
|
35
|
+
vi.mocked(hasTextContentModule.hasTextContent).mockReturnValue(true);
|
|
36
|
+
vi.mocked(setupNodeListenersModule.setupNodeListeners).mockReturnValue(cleanup);
|
|
37
|
+
vi.mocked(makeNodeEditableModule.makeNodeEditable).mockImplementation(() => {});
|
|
38
|
+
vi.mocked(makeNodeNonEditableModule.makeNodeNonEditable).mockImplementation(() => {});
|
|
39
|
+
vi.mocked(enableCanvasTextModeModule.enableCanvasTextMode).mockImplementation(() => {});
|
|
40
|
+
vi.mocked(disableCanvasTextModeModule.disableCanvasTextMode).mockImplementation(() => {});
|
|
41
|
+
vi.mocked(handleTextChangeModule.handleTextChange).mockImplementation(() => {});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
if (document.body.contains(node)) {
|
|
46
|
+
document.body.removeChild(node);
|
|
47
|
+
}
|
|
48
|
+
if (document.body.contains(nodeProvider)) {
|
|
49
|
+
document.body.removeChild(nodeProvider);
|
|
50
|
+
}
|
|
51
|
+
vi.clearAllMocks();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should return NodeText interface", () => {
|
|
55
|
+
const text = nodeText();
|
|
56
|
+
|
|
57
|
+
expect(text).toHaveProperty("enableEditMode");
|
|
58
|
+
expect(text).toHaveProperty("blurEditMode");
|
|
59
|
+
expect(text).toHaveProperty("getEditableNode");
|
|
60
|
+
expect(text).toHaveProperty("isEditing");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("enableEditMode", () => {
|
|
64
|
+
it("should enable edit mode for node with text content", () => {
|
|
65
|
+
const text = nodeText();
|
|
66
|
+
text.enableEditMode(node, nodeProvider);
|
|
67
|
+
|
|
68
|
+
expect(hasTextContentModule.hasTextContent).toHaveBeenCalledWith(node);
|
|
69
|
+
expect(makeNodeEditableModule.makeNodeEditable).toHaveBeenCalledWith(node);
|
|
70
|
+
expect(enableCanvasTextModeModule.enableCanvasTextMode).toHaveBeenCalledWith("canvas");
|
|
71
|
+
expect(setupNodeListenersModule.setupNodeListeners).toHaveBeenCalledWith(node, nodeProvider, expect.any(Function), "canvas");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should not enable edit mode for node without text content", () => {
|
|
75
|
+
vi.mocked(hasTextContentModule.hasTextContent).mockReturnValue(false);
|
|
76
|
+
const text = nodeText();
|
|
77
|
+
text.enableEditMode(node, nodeProvider);
|
|
78
|
+
|
|
79
|
+
expect(makeNodeEditableModule.makeNodeEditable).not.toHaveBeenCalled();
|
|
80
|
+
expect(enableCanvasTextModeModule.enableCanvasTextMode).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should not enable edit mode if same node is already editable", () => {
|
|
84
|
+
const text = nodeText();
|
|
85
|
+
text.enableEditMode(node, nodeProvider);
|
|
86
|
+
vi.clearAllMocks();
|
|
87
|
+
|
|
88
|
+
text.enableEditMode(node, nodeProvider);
|
|
89
|
+
|
|
90
|
+
expect(makeNodeEditableModule.makeNodeEditable).not.toHaveBeenCalled();
|
|
91
|
+
expect(enableCanvasTextModeModule.enableCanvasTextMode).not.toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should blur previous node when enabling different node", () => {
|
|
95
|
+
const text = nodeText();
|
|
96
|
+
const node2 = document.createElement("div");
|
|
97
|
+
node2.setAttribute("data-node-id", "test-node-2");
|
|
98
|
+
node2.textContent = "Node 2 content";
|
|
99
|
+
document.body.appendChild(node2);
|
|
100
|
+
|
|
101
|
+
text.enableEditMode(node, nodeProvider);
|
|
102
|
+
vi.clearAllMocks();
|
|
103
|
+
|
|
104
|
+
text.enableEditMode(node2, nodeProvider);
|
|
105
|
+
|
|
106
|
+
expect(makeNodeNonEditableModule.makeNodeNonEditable).toHaveBeenCalledWith(node);
|
|
107
|
+
expect(disableCanvasTextModeModule.disableCanvasTextMode).toHaveBeenCalledWith("canvas");
|
|
108
|
+
expect(cleanup).toHaveBeenCalled();
|
|
109
|
+
|
|
110
|
+
document.body.removeChild(node2);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should use custom canvas name", () => {
|
|
114
|
+
const text = nodeText("custom-canvas");
|
|
115
|
+
text.enableEditMode(node, nodeProvider);
|
|
116
|
+
|
|
117
|
+
expect(enableCanvasTextModeModule.enableCanvasTextMode).toHaveBeenCalledWith("custom-canvas");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should handle null nodeProvider", () => {
|
|
121
|
+
const text = nodeText();
|
|
122
|
+
text.enableEditMode(node, null);
|
|
123
|
+
|
|
124
|
+
expect(setupNodeListenersModule.setupNodeListeners).toHaveBeenCalledWith(node, null, expect.any(Function), "canvas");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("blurEditMode", () => {
|
|
129
|
+
it("should blur edit mode", () => {
|
|
130
|
+
const text = nodeText();
|
|
131
|
+
text.enableEditMode(node, nodeProvider);
|
|
132
|
+
vi.clearAllMocks();
|
|
133
|
+
|
|
134
|
+
text.blurEditMode();
|
|
135
|
+
|
|
136
|
+
expect(handleTextChangeModule.handleTextChange).toHaveBeenCalledWith(node, [], true);
|
|
137
|
+
expect(makeNodeNonEditableModule.makeNodeNonEditable).toHaveBeenCalledWith(node);
|
|
138
|
+
expect(disableCanvasTextModeModule.disableCanvasTextMode).toHaveBeenCalledWith("canvas");
|
|
139
|
+
expect(cleanup).toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should not blur if no node is editable", () => {
|
|
143
|
+
const text = nodeText();
|
|
144
|
+
|
|
145
|
+
text.blurEditMode();
|
|
146
|
+
|
|
147
|
+
expect(handleTextChangeModule.handleTextChange).not.toHaveBeenCalled();
|
|
148
|
+
expect(makeNodeNonEditableModule.makeNodeNonEditable).not.toHaveBeenCalled();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should not blur if blur is already in progress", () => {
|
|
152
|
+
const text = nodeText();
|
|
153
|
+
text.enableEditMode(node, nodeProvider);
|
|
154
|
+
vi.clearAllMocks();
|
|
155
|
+
|
|
156
|
+
// Start blur
|
|
157
|
+
text.blurEditMode();
|
|
158
|
+
vi.clearAllMocks();
|
|
159
|
+
|
|
160
|
+
// Try to blur again while in progress
|
|
161
|
+
text.blurEditMode();
|
|
162
|
+
|
|
163
|
+
expect(handleTextChangeModule.handleTextChange).not.toHaveBeenCalled();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should use custom canvas name", () => {
|
|
167
|
+
const text = nodeText("custom-canvas");
|
|
168
|
+
text.enableEditMode(node, nodeProvider);
|
|
169
|
+
vi.clearAllMocks();
|
|
170
|
+
|
|
171
|
+
text.blurEditMode();
|
|
172
|
+
|
|
173
|
+
expect(disableCanvasTextModeModule.disableCanvasTextMode).toHaveBeenCalledWith("custom-canvas");
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should handle cleanup being null", () => {
|
|
177
|
+
vi.mocked(setupNodeListenersModule.setupNodeListeners).mockReturnValue(null as unknown as () => void);
|
|
178
|
+
const text = nodeText();
|
|
179
|
+
text.enableEditMode(node, nodeProvider);
|
|
180
|
+
vi.clearAllMocks();
|
|
181
|
+
|
|
182
|
+
expect(() => {
|
|
183
|
+
text.blurEditMode();
|
|
184
|
+
}).not.toThrow();
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("getEditableNode", () => {
|
|
189
|
+
it("should return null when no node is editable", () => {
|
|
190
|
+
const text = nodeText();
|
|
191
|
+
|
|
192
|
+
expect(text.getEditableNode()).toBeNull();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should return editable node", () => {
|
|
196
|
+
const text = nodeText();
|
|
197
|
+
text.enableEditMode(node, nodeProvider);
|
|
198
|
+
|
|
199
|
+
expect(text.getEditableNode()).toBe(node);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should return null after blur", () => {
|
|
203
|
+
const text = nodeText();
|
|
204
|
+
text.enableEditMode(node, nodeProvider);
|
|
205
|
+
text.blurEditMode();
|
|
206
|
+
|
|
207
|
+
expect(text.getEditableNode()).toBeNull();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe("isEditing", () => {
|
|
212
|
+
it("should return false when no node is editable", () => {
|
|
213
|
+
const text = nodeText();
|
|
214
|
+
|
|
215
|
+
expect(text.isEditing()).toBe(false);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should return true when node is editable", () => {
|
|
219
|
+
const text = nodeText();
|
|
220
|
+
text.enableEditMode(node, nodeProvider);
|
|
221
|
+
|
|
222
|
+
expect(text.isEditing()).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should return false after blur", () => {
|
|
226
|
+
const text = nodeText();
|
|
227
|
+
text.enableEditMode(node, nodeProvider);
|
|
228
|
+
text.blurEditMode();
|
|
229
|
+
|
|
230
|
+
expect(text.isEditing()).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as isLockedModule from "../node-tools/select/helpers/isLocked";
|
|
3
|
+
import { processPostMessage } from "./processPostMessage";
|
|
4
|
+
|
|
5
|
+
vi.mock("../node-tools/select/helpers/isLocked");
|
|
6
|
+
|
|
7
|
+
describe("processPostMessage", () => {
|
|
8
|
+
let onNodeSelected: ReturnType<typeof vi.fn>;
|
|
9
|
+
let node: HTMLElement;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
onNodeSelected = vi.fn();
|
|
13
|
+
node = document.createElement("div");
|
|
14
|
+
node.setAttribute("data-node-id", "test-node-123");
|
|
15
|
+
document.body.appendChild(node);
|
|
16
|
+
|
|
17
|
+
vi.mocked(isLockedModule.isLocked).mockReturnValue(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
if (document.body.contains(node)) {
|
|
22
|
+
document.body.removeChild(node);
|
|
23
|
+
}
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should call onNodeSelected with node when message is from application and action is selectedNodeChanged", () => {
|
|
28
|
+
const event = new MessageEvent("message", {
|
|
29
|
+
data: {
|
|
30
|
+
source: "application",
|
|
31
|
+
action: "selectedNodeChanged",
|
|
32
|
+
data: "test-node-123",
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
processPostMessage(event, onNodeSelected);
|
|
37
|
+
|
|
38
|
+
expect(onNodeSelected).toHaveBeenCalledTimes(1);
|
|
39
|
+
expect(onNodeSelected).toHaveBeenCalledWith(node);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should not call onNodeSelected when source is not 'application'", () => {
|
|
43
|
+
const event = new MessageEvent("message", {
|
|
44
|
+
data: {
|
|
45
|
+
source: "other-source",
|
|
46
|
+
action: "selectedNodeChanged",
|
|
47
|
+
data: "test-node-123",
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
processPostMessage(event, onNodeSelected);
|
|
52
|
+
|
|
53
|
+
expect(onNodeSelected).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should not call onNodeSelected when action is not 'selectedNodeChanged'", () => {
|
|
57
|
+
const event = new MessageEvent("message", {
|
|
58
|
+
data: {
|
|
59
|
+
source: "application",
|
|
60
|
+
action: "otherAction",
|
|
61
|
+
data: "test-node-123",
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
processPostMessage(event, onNodeSelected);
|
|
66
|
+
|
|
67
|
+
expect(onNodeSelected).not.toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should call onNodeSelected with null when node is locked", () => {
|
|
71
|
+
vi.mocked(isLockedModule.isLocked).mockReturnValue(true);
|
|
72
|
+
|
|
73
|
+
const event = new MessageEvent("message", {
|
|
74
|
+
data: {
|
|
75
|
+
source: "application",
|
|
76
|
+
action: "selectedNodeChanged",
|
|
77
|
+
data: "test-node-123",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
processPostMessage(event, onNodeSelected);
|
|
82
|
+
|
|
83
|
+
expect(onNodeSelected).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(onNodeSelected).toHaveBeenCalledWith(null);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should not call onNodeSelected when node is not found", () => {
|
|
88
|
+
const event = new MessageEvent("message", {
|
|
89
|
+
data: {
|
|
90
|
+
source: "application",
|
|
91
|
+
action: "selectedNodeChanged",
|
|
92
|
+
data: "non-existent-node",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
processPostMessage(event, onNodeSelected);
|
|
97
|
+
|
|
98
|
+
expect(onNodeSelected).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should work without onNodeSelected callback", () => {
|
|
102
|
+
const event = new MessageEvent("message", {
|
|
103
|
+
data: {
|
|
104
|
+
source: "application",
|
|
105
|
+
action: "selectedNodeChanged",
|
|
106
|
+
data: "test-node-123",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(() => {
|
|
111
|
+
processPostMessage(event);
|
|
112
|
+
}).not.toThrow();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should check if node is locked before calling callback", () => {
|
|
116
|
+
const event = new MessageEvent("message", {
|
|
117
|
+
data: {
|
|
118
|
+
source: "application",
|
|
119
|
+
action: "selectedNodeChanged",
|
|
120
|
+
data: "test-node-123",
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
processPostMessage(event, onNodeSelected);
|
|
125
|
+
|
|
126
|
+
expect(isLockedModule.isLocked).toHaveBeenCalledWith(node);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should handle multiple nodes with different IDs", () => {
|
|
130
|
+
const node2 = document.createElement("div");
|
|
131
|
+
node2.setAttribute("data-node-id", "test-node-456");
|
|
132
|
+
document.body.appendChild(node2);
|
|
133
|
+
|
|
134
|
+
const event1 = new MessageEvent("message", {
|
|
135
|
+
data: {
|
|
136
|
+
source: "application",
|
|
137
|
+
action: "selectedNodeChanged",
|
|
138
|
+
data: "test-node-123",
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const event2 = new MessageEvent("message", {
|
|
143
|
+
data: {
|
|
144
|
+
source: "application",
|
|
145
|
+
action: "selectedNodeChanged",
|
|
146
|
+
data: "test-node-456",
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
processPostMessage(event1, onNodeSelected);
|
|
151
|
+
processPostMessage(event2, onNodeSelected);
|
|
152
|
+
|
|
153
|
+
expect(onNodeSelected).toHaveBeenCalledTimes(2);
|
|
154
|
+
expect(onNodeSelected).toHaveBeenNthCalledWith(1, node);
|
|
155
|
+
expect(onNodeSelected).toHaveBeenNthCalledWith(2, node2);
|
|
156
|
+
|
|
157
|
+
document.body.removeChild(node2);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should return early when node is locked", () => {
|
|
161
|
+
vi.mocked(isLockedModule.isLocked).mockReturnValue(true);
|
|
162
|
+
|
|
163
|
+
const event = new MessageEvent("message", {
|
|
164
|
+
data: {
|
|
165
|
+
source: "application",
|
|
166
|
+
action: "selectedNodeChanged",
|
|
167
|
+
data: "test-node-123",
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
processPostMessage(event, onNodeSelected);
|
|
172
|
+
|
|
173
|
+
// Should only be called once with null, not with the node
|
|
174
|
+
expect(onNodeSelected).toHaveBeenCalledTimes(1);
|
|
175
|
+
expect(onNodeSelected).toHaveBeenCalledWith(null);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should handle event with missing data properties", () => {
|
|
179
|
+
const event = new MessageEvent("message", {
|
|
180
|
+
data: {},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(() => {
|
|
184
|
+
processPostMessage(event, onNodeSelected);
|
|
185
|
+
}).not.toThrow();
|
|
186
|
+
|
|
187
|
+
expect(onNodeSelected).not.toHaveBeenCalled();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("should throw when event data is null", () => {
|
|
191
|
+
const event = new MessageEvent("message", {
|
|
192
|
+
data: null,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(() => {
|
|
196
|
+
processPostMessage(event, onNodeSelected);
|
|
197
|
+
}).toThrow();
|
|
198
|
+
|
|
199
|
+
expect(onNodeSelected).not.toHaveBeenCalled();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should handle node that exists but is locked", () => {
|
|
203
|
+
vi.mocked(isLockedModule.isLocked).mockReturnValue(true);
|
|
204
|
+
|
|
205
|
+
const event = new MessageEvent("message", {
|
|
206
|
+
data: {
|
|
207
|
+
source: "application",
|
|
208
|
+
action: "selectedNodeChanged",
|
|
209
|
+
data: "test-node-123",
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
processPostMessage(event, onNodeSelected);
|
|
214
|
+
|
|
215
|
+
expect(isLockedModule.isLocked).toHaveBeenCalledWith(node);
|
|
216
|
+
expect(onNodeSelected).toHaveBeenCalledWith(null);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { sendPostMessage } from "./sendPostMessage";
|
|
3
|
+
|
|
4
|
+
describe("sendPostMessage", () => {
|
|
5
|
+
let originalPostMessage: typeof window.parent.postMessage;
|
|
6
|
+
let mockPostMessage: ReturnType<typeof vi.fn>;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockPostMessage = vi.fn();
|
|
10
|
+
originalPostMessage = window.parent.postMessage;
|
|
11
|
+
window.parent.postMessage = mockPostMessage;
|
|
12
|
+
vi.useFakeTimers();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
window.parent.postMessage = originalPostMessage;
|
|
17
|
+
vi.useRealTimers();
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should send postMessage with correct format", () => {
|
|
22
|
+
const mockDate = new Date("2024-01-01T00:00:00Z");
|
|
23
|
+
vi.setSystemTime(mockDate);
|
|
24
|
+
|
|
25
|
+
sendPostMessage("testAction", "testData");
|
|
26
|
+
|
|
27
|
+
expect(mockPostMessage).toHaveBeenCalledTimes(1);
|
|
28
|
+
expect(mockPostMessage).toHaveBeenCalledWith(
|
|
29
|
+
{
|
|
30
|
+
source: "node-edit-utils",
|
|
31
|
+
action: "testAction",
|
|
32
|
+
data: "testData",
|
|
33
|
+
timestamp: mockDate.getTime(),
|
|
34
|
+
},
|
|
35
|
+
"*"
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should include timestamp in message", () => {
|
|
40
|
+
const mockDate = new Date("2024-01-01T12:00:00Z");
|
|
41
|
+
vi.setSystemTime(mockDate);
|
|
42
|
+
|
|
43
|
+
sendPostMessage("testAction", { test: "data" });
|
|
44
|
+
|
|
45
|
+
expect(mockPostMessage).toHaveBeenCalledWith(
|
|
46
|
+
expect.objectContaining({
|
|
47
|
+
timestamp: mockDate.getTime(),
|
|
48
|
+
}),
|
|
49
|
+
"*"
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should send different action types", () => {
|
|
54
|
+
sendPostMessage("selectedNodeChanged", "node-123");
|
|
55
|
+
sendPostMessage("textContentChanged", { nodeId: "node-123", textContent: "Hello" });
|
|
56
|
+
|
|
57
|
+
expect(mockPostMessage).toHaveBeenCalledTimes(2);
|
|
58
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(
|
|
59
|
+
1,
|
|
60
|
+
expect.objectContaining({
|
|
61
|
+
action: "selectedNodeChanged",
|
|
62
|
+
data: "node-123",
|
|
63
|
+
}),
|
|
64
|
+
"*"
|
|
65
|
+
);
|
|
66
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(
|
|
67
|
+
2,
|
|
68
|
+
expect.objectContaining({
|
|
69
|
+
action: "textContentChanged",
|
|
70
|
+
data: { nodeId: "node-123", textContent: "Hello" },
|
|
71
|
+
}),
|
|
72
|
+
"*"
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should send different data types", () => {
|
|
77
|
+
sendPostMessage("action1", "string");
|
|
78
|
+
sendPostMessage("action2", 123);
|
|
79
|
+
sendPostMessage("action3", { key: "value" });
|
|
80
|
+
sendPostMessage("action4", null);
|
|
81
|
+
sendPostMessage("action5", undefined);
|
|
82
|
+
|
|
83
|
+
expect(mockPostMessage).toHaveBeenCalledTimes(5);
|
|
84
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(1, expect.objectContaining({ data: "string" }), "*");
|
|
85
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(2, expect.objectContaining({ data: 123 }), "*");
|
|
86
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(3, expect.objectContaining({ data: { key: "value" } }), "*");
|
|
87
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(4, expect.objectContaining({ data: null }), "*");
|
|
88
|
+
expect(mockPostMessage).toHaveBeenNthCalledWith(5, expect.objectContaining({ data: undefined }), "*");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should always use source 'node-edit-utils'", () => {
|
|
92
|
+
sendPostMessage("anyAction", "anyData");
|
|
93
|
+
|
|
94
|
+
expect(mockPostMessage).toHaveBeenCalledWith(
|
|
95
|
+
expect.objectContaining({
|
|
96
|
+
source: "node-edit-utils",
|
|
97
|
+
}),
|
|
98
|
+
"*"
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should always use '*' as targetOrigin", () => {
|
|
103
|
+
sendPostMessage("anyAction", "anyData");
|
|
104
|
+
|
|
105
|
+
expect(mockPostMessage).toHaveBeenCalledWith(expect.any(Object), "*");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should include all required fields", () => {
|
|
109
|
+
const mockDate = new Date("2024-01-01T00:00:00Z");
|
|
110
|
+
vi.setSystemTime(mockDate);
|
|
111
|
+
|
|
112
|
+
sendPostMessage("testAction", "testData");
|
|
113
|
+
|
|
114
|
+
const callArgs = mockPostMessage.mock.calls[0][0];
|
|
115
|
+
expect(callArgs).toHaveProperty("source");
|
|
116
|
+
expect(callArgs).toHaveProperty("action");
|
|
117
|
+
expect(callArgs).toHaveProperty("data");
|
|
118
|
+
expect(callArgs).toHaveProperty("timestamp");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
.viewport-label-text:hover {
|
|
105
|
-
fill: oklch(0 0 0);
|
|
105
|
+
fill: oklch(0.7 0 0);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
.viewport-label-text:hover {
|
|
115
|
-
fill: oklch(0.
|
|
115
|
+
fill: oklch(0.5 0 0);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|