@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,439 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { withDoubleRAF, withRAF, withRAFThrottle } from "./withRAF";
|
|
3
|
+
|
|
4
|
+
describe("withRAF", () => {
|
|
5
|
+
let rafCallbacks: Map<number, FrameRequestCallback>;
|
|
6
|
+
let rafIdCounter: number;
|
|
7
|
+
let originalRAF: typeof requestAnimationFrame;
|
|
8
|
+
let originalCancelRAF: typeof cancelAnimationFrame;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
rafCallbacks = new Map();
|
|
12
|
+
rafIdCounter = 0;
|
|
13
|
+
originalRAF = global.requestAnimationFrame;
|
|
14
|
+
originalCancelRAF = global.cancelAnimationFrame;
|
|
15
|
+
|
|
16
|
+
global.requestAnimationFrame = vi.fn((callback: FrameRequestCallback) => {
|
|
17
|
+
const id = ++rafIdCounter;
|
|
18
|
+
rafCallbacks.set(id, callback);
|
|
19
|
+
return id;
|
|
20
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
21
|
+
|
|
22
|
+
global.cancelAnimationFrame = vi.fn((id: number) => {
|
|
23
|
+
rafCallbacks.delete(id);
|
|
24
|
+
}) as unknown as typeof cancelAnimationFrame;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
global.requestAnimationFrame = originalRAF;
|
|
29
|
+
global.cancelAnimationFrame = originalCancelRAF;
|
|
30
|
+
rafCallbacks.clear();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should execute operation on next animation frame", () => {
|
|
34
|
+
const operation = vi.fn();
|
|
35
|
+
const cleanup = withRAF(operation);
|
|
36
|
+
|
|
37
|
+
expect(operation).not.toHaveBeenCalled();
|
|
38
|
+
|
|
39
|
+
// Execute the RAF callback
|
|
40
|
+
rafCallbacks.forEach((callback) => {
|
|
41
|
+
callback(performance.now());
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(operation).toHaveBeenCalledTimes(1);
|
|
45
|
+
|
|
46
|
+
cleanup();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should return cleanup function", () => {
|
|
50
|
+
const operation = vi.fn();
|
|
51
|
+
const cleanup = withRAF(operation);
|
|
52
|
+
|
|
53
|
+
expect(typeof cleanup).toBe("function");
|
|
54
|
+
cleanup();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should cancel operation when cleanup is called", () => {
|
|
58
|
+
const operation = vi.fn();
|
|
59
|
+
const cleanup = withRAF(operation);
|
|
60
|
+
|
|
61
|
+
cleanup();
|
|
62
|
+
|
|
63
|
+
// Execute any remaining RAF callbacks
|
|
64
|
+
rafCallbacks.forEach((callback) => {
|
|
65
|
+
callback(performance.now());
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(operation).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should execute operation only once", () => {
|
|
72
|
+
const operation = vi.fn();
|
|
73
|
+
const cleanup = withRAF(operation);
|
|
74
|
+
|
|
75
|
+
// Execute RAF callback once
|
|
76
|
+
const rafId = Array.from(rafCallbacks.keys())[0];
|
|
77
|
+
const callback = rafCallbacks.get(rafId);
|
|
78
|
+
if (callback) {
|
|
79
|
+
callback(performance.now());
|
|
80
|
+
rafCallbacks.delete(rafId); // Remove after execution
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Try to execute again (should be empty now)
|
|
84
|
+
rafCallbacks.forEach((cb) => {
|
|
85
|
+
cb(performance.now());
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(operation).toHaveBeenCalledTimes(1);
|
|
89
|
+
|
|
90
|
+
cleanup();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("withRAFThrottle", () => {
|
|
95
|
+
let rafCallbacks: Map<number, FrameRequestCallback>;
|
|
96
|
+
let rafIdCounter: number;
|
|
97
|
+
let originalRAF: typeof requestAnimationFrame;
|
|
98
|
+
let originalCancelRAF: typeof cancelAnimationFrame;
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
rafCallbacks = new Map();
|
|
102
|
+
rafIdCounter = 0;
|
|
103
|
+
originalRAF = global.requestAnimationFrame;
|
|
104
|
+
originalCancelRAF = global.cancelAnimationFrame;
|
|
105
|
+
|
|
106
|
+
global.requestAnimationFrame = vi.fn((callback: FrameRequestCallback) => {
|
|
107
|
+
const id = ++rafIdCounter;
|
|
108
|
+
rafCallbacks.set(id, callback);
|
|
109
|
+
return id;
|
|
110
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
111
|
+
|
|
112
|
+
global.cancelAnimationFrame = vi.fn((id: number) => {
|
|
113
|
+
rafCallbacks.delete(id);
|
|
114
|
+
}) as unknown as typeof cancelAnimationFrame;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
global.requestAnimationFrame = originalRAF;
|
|
119
|
+
global.cancelAnimationFrame = originalCancelRAF;
|
|
120
|
+
rafCallbacks.clear();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should throttle function calls", () => {
|
|
124
|
+
const func = vi.fn();
|
|
125
|
+
const throttled = withRAFThrottle(func);
|
|
126
|
+
|
|
127
|
+
throttled("arg1");
|
|
128
|
+
throttled("arg2");
|
|
129
|
+
throttled("arg3");
|
|
130
|
+
|
|
131
|
+
expect(func).not.toHaveBeenCalled();
|
|
132
|
+
|
|
133
|
+
// Execute RAF callback
|
|
134
|
+
rafCallbacks.forEach((callback) => {
|
|
135
|
+
callback(performance.now());
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
139
|
+
expect(func).toHaveBeenCalledWith("arg3"); // Should use last args
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should return throttled function with cleanup", () => {
|
|
143
|
+
const func = vi.fn();
|
|
144
|
+
const throttled = withRAFThrottle(func);
|
|
145
|
+
|
|
146
|
+
expect(typeof throttled).toBe("function");
|
|
147
|
+
expect(typeof throttled.cleanup).toBe("function");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should cancel pending call on cleanup", () => {
|
|
151
|
+
const func = vi.fn();
|
|
152
|
+
const throttled = withRAFThrottle(func);
|
|
153
|
+
|
|
154
|
+
throttled("arg1");
|
|
155
|
+
throttled.cleanup();
|
|
156
|
+
|
|
157
|
+
// Try to execute any remaining RAF callbacks
|
|
158
|
+
rafCallbacks.forEach((callback) => {
|
|
159
|
+
callback(performance.now());
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(func).not.toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should handle multiple rapid calls", () => {
|
|
166
|
+
const func = vi.fn();
|
|
167
|
+
const throttled = withRAFThrottle(func);
|
|
168
|
+
|
|
169
|
+
throttled("call1");
|
|
170
|
+
throttled("call2");
|
|
171
|
+
throttled("call3");
|
|
172
|
+
throttled("call4");
|
|
173
|
+
throttled("call5");
|
|
174
|
+
|
|
175
|
+
// Execute RAF callback
|
|
176
|
+
rafCallbacks.forEach((callback) => {
|
|
177
|
+
callback(performance.now());
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
181
|
+
expect(func).toHaveBeenCalledWith("call5");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should allow new calls after previous one executes", () => {
|
|
185
|
+
const func = vi.fn();
|
|
186
|
+
const throttled = withRAFThrottle(func);
|
|
187
|
+
|
|
188
|
+
throttled("first");
|
|
189
|
+
rafCallbacks.forEach((callback) => {
|
|
190
|
+
callback(performance.now());
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
194
|
+
expect(func).toHaveBeenCalledWith("first");
|
|
195
|
+
|
|
196
|
+
throttled("second");
|
|
197
|
+
rafCallbacks.forEach((callback) => {
|
|
198
|
+
callback(performance.now());
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(func).toHaveBeenCalledTimes(2);
|
|
202
|
+
expect(func).toHaveBeenCalledWith("second");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should handle function with multiple arguments", () => {
|
|
206
|
+
const func = vi.fn();
|
|
207
|
+
const throttled = withRAFThrottle(func);
|
|
208
|
+
|
|
209
|
+
throttled("arg1", "arg2", "arg3");
|
|
210
|
+
rafCallbacks.forEach((callback) => {
|
|
211
|
+
callback(performance.now());
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(func).toHaveBeenCalledWith("arg1", "arg2", "arg3");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("should reset state on cleanup", () => {
|
|
218
|
+
const func = vi.fn();
|
|
219
|
+
const throttled = withRAFThrottle(func);
|
|
220
|
+
|
|
221
|
+
throttled("arg1");
|
|
222
|
+
throttled.cleanup();
|
|
223
|
+
|
|
224
|
+
// After cleanup, should be able to call again
|
|
225
|
+
throttled("arg2");
|
|
226
|
+
rafCallbacks.forEach((callback) => {
|
|
227
|
+
callback(performance.now());
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(func).toHaveBeenCalledWith("arg2");
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("withDoubleRAF", () => {
|
|
235
|
+
let rafCallbacks: Map<number, FrameRequestCallback>;
|
|
236
|
+
let rafIdCounter: number;
|
|
237
|
+
let originalRAF: typeof requestAnimationFrame;
|
|
238
|
+
let originalCancelRAF: typeof cancelAnimationFrame;
|
|
239
|
+
|
|
240
|
+
beforeEach(() => {
|
|
241
|
+
rafCallbacks = new Map();
|
|
242
|
+
rafIdCounter = 0;
|
|
243
|
+
originalRAF = global.requestAnimationFrame;
|
|
244
|
+
originalCancelRAF = global.cancelAnimationFrame;
|
|
245
|
+
|
|
246
|
+
global.requestAnimationFrame = vi.fn((callback: FrameRequestCallback) => {
|
|
247
|
+
const id = ++rafIdCounter;
|
|
248
|
+
rafCallbacks.set(id, callback);
|
|
249
|
+
return id;
|
|
250
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
251
|
+
|
|
252
|
+
global.cancelAnimationFrame = vi.fn((id: number) => {
|
|
253
|
+
rafCallbacks.delete(id);
|
|
254
|
+
}) as unknown as typeof cancelAnimationFrame;
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
afterEach(() => {
|
|
258
|
+
global.requestAnimationFrame = originalRAF;
|
|
259
|
+
global.cancelAnimationFrame = originalCancelRAF;
|
|
260
|
+
rafCallbacks.clear();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("should execute function after two animation frames", () => {
|
|
264
|
+
const func = vi.fn();
|
|
265
|
+
const throttled = withDoubleRAF(func);
|
|
266
|
+
|
|
267
|
+
throttled("arg1");
|
|
268
|
+
|
|
269
|
+
expect(func).not.toHaveBeenCalled();
|
|
270
|
+
|
|
271
|
+
// Execute first RAF (which schedules second RAF)
|
|
272
|
+
const firstRAFId = Array.from(rafCallbacks.keys())[0];
|
|
273
|
+
const firstCallback = rafCallbacks.get(firstRAFId);
|
|
274
|
+
if (firstCallback) {
|
|
275
|
+
firstCallback(performance.now());
|
|
276
|
+
rafCallbacks.delete(firstRAFId);
|
|
277
|
+
}
|
|
278
|
+
expect(func).not.toHaveBeenCalled();
|
|
279
|
+
|
|
280
|
+
// Execute second RAF
|
|
281
|
+
const secondRAFId = Array.from(rafCallbacks.keys())[0];
|
|
282
|
+
const secondCallback = rafCallbacks.get(secondRAFId);
|
|
283
|
+
if (secondCallback) {
|
|
284
|
+
secondCallback(performance.now());
|
|
285
|
+
}
|
|
286
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
287
|
+
expect(func).toHaveBeenCalledWith("arg1");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should return throttled function with cleanup", () => {
|
|
291
|
+
const func = vi.fn();
|
|
292
|
+
const throttled = withDoubleRAF(func);
|
|
293
|
+
|
|
294
|
+
expect(typeof throttled).toBe("function");
|
|
295
|
+
expect(typeof throttled.cleanup).toBe("function");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("should cancel pending calls on cleanup", () => {
|
|
299
|
+
const func = vi.fn();
|
|
300
|
+
const throttled = withDoubleRAF(func);
|
|
301
|
+
|
|
302
|
+
throttled("arg1");
|
|
303
|
+
throttled.cleanup();
|
|
304
|
+
|
|
305
|
+
// Try to execute any remaining RAF callbacks
|
|
306
|
+
rafCallbacks.forEach((callback) => {
|
|
307
|
+
callback(performance.now());
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(func).not.toHaveBeenCalled();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("should throttle multiple rapid calls", () => {
|
|
314
|
+
const func = vi.fn();
|
|
315
|
+
const throttled = withDoubleRAF(func);
|
|
316
|
+
|
|
317
|
+
throttled("call1");
|
|
318
|
+
throttled("call2");
|
|
319
|
+
throttled("call3");
|
|
320
|
+
|
|
321
|
+
// Execute first RAF
|
|
322
|
+
const firstRAFId = Array.from(rafCallbacks.keys())[0];
|
|
323
|
+
const firstCallback = rafCallbacks.get(firstRAFId);
|
|
324
|
+
if (firstCallback) {
|
|
325
|
+
firstCallback(performance.now());
|
|
326
|
+
rafCallbacks.delete(firstRAFId);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Execute second RAF
|
|
330
|
+
const secondRAFId = Array.from(rafCallbacks.keys())[0];
|
|
331
|
+
const secondCallback = rafCallbacks.get(secondRAFId);
|
|
332
|
+
if (secondCallback) {
|
|
333
|
+
secondCallback(performance.now());
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
337
|
+
expect(func).toHaveBeenCalledWith("call3");
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("should allow new calls after previous one executes", () => {
|
|
341
|
+
const func = vi.fn();
|
|
342
|
+
const throttled = withDoubleRAF(func);
|
|
343
|
+
|
|
344
|
+
throttled("first");
|
|
345
|
+
// Execute double RAF
|
|
346
|
+
const firstRAFId = Array.from(rafCallbacks.keys())[0];
|
|
347
|
+
const firstCallback = rafCallbacks.get(firstRAFId);
|
|
348
|
+
if (firstCallback) {
|
|
349
|
+
firstCallback(performance.now());
|
|
350
|
+
rafCallbacks.delete(firstRAFId);
|
|
351
|
+
const secondRAFId = Array.from(rafCallbacks.keys())[0];
|
|
352
|
+
const secondCallback = rafCallbacks.get(secondRAFId);
|
|
353
|
+
if (secondCallback) {
|
|
354
|
+
secondCallback(performance.now());
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
359
|
+
expect(func).toHaveBeenCalledWith("first");
|
|
360
|
+
|
|
361
|
+
throttled("second");
|
|
362
|
+
// Execute double RAF again
|
|
363
|
+
const firstRAFId2 = Array.from(rafCallbacks.keys())[0];
|
|
364
|
+
const firstCallback2 = rafCallbacks.get(firstRAFId2);
|
|
365
|
+
if (firstCallback2) {
|
|
366
|
+
firstCallback2(performance.now());
|
|
367
|
+
rafCallbacks.delete(firstRAFId2);
|
|
368
|
+
const secondRAFId2 = Array.from(rafCallbacks.keys())[0];
|
|
369
|
+
const secondCallback2 = rafCallbacks.get(secondRAFId2);
|
|
370
|
+
if (secondCallback2) {
|
|
371
|
+
secondCallback2(performance.now());
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
expect(func).toHaveBeenCalledTimes(2);
|
|
376
|
+
expect(func).toHaveBeenCalledWith("second");
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it("should handle function with multiple arguments", () => {
|
|
380
|
+
const func = vi.fn();
|
|
381
|
+
const throttled = withDoubleRAF(func);
|
|
382
|
+
|
|
383
|
+
throttled("arg1", "arg2", "arg3");
|
|
384
|
+
// Execute double RAF
|
|
385
|
+
const firstRAFId = Array.from(rafCallbacks.keys())[0];
|
|
386
|
+
const firstCallback = rafCallbacks.get(firstRAFId);
|
|
387
|
+
if (firstCallback) {
|
|
388
|
+
firstCallback(performance.now());
|
|
389
|
+
rafCallbacks.delete(firstRAFId);
|
|
390
|
+
const secondRAFId = Array.from(rafCallbacks.keys())[0];
|
|
391
|
+
const secondCallback = rafCallbacks.get(secondRAFId);
|
|
392
|
+
if (secondCallback) {
|
|
393
|
+
secondCallback(performance.now());
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
expect(func).toHaveBeenCalledWith("arg1", "arg2", "arg3");
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("should cancel first RAF if cleanup called before second RAF", () => {
|
|
401
|
+
const func = vi.fn();
|
|
402
|
+
const throttled = withDoubleRAF(func);
|
|
403
|
+
|
|
404
|
+
throttled("arg1");
|
|
405
|
+
|
|
406
|
+
throttled.cleanup();
|
|
407
|
+
|
|
408
|
+
// Try to execute any remaining RAF callbacks
|
|
409
|
+
rafCallbacks.forEach((callback) => {
|
|
410
|
+
callback(performance.now());
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(func).not.toHaveBeenCalled();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("should cancel second RAF if cleanup called after first RAF", () => {
|
|
417
|
+
const func = vi.fn();
|
|
418
|
+
const throttled = withDoubleRAF(func);
|
|
419
|
+
|
|
420
|
+
throttled("arg1");
|
|
421
|
+
|
|
422
|
+
// Execute first RAF
|
|
423
|
+
const firstRAFId = Array.from(rafCallbacks.keys())[0];
|
|
424
|
+
const firstCallback = rafCallbacks.get(firstRAFId);
|
|
425
|
+
if (firstCallback) {
|
|
426
|
+
firstCallback(performance.now());
|
|
427
|
+
rafCallbacks.delete(firstRAFId);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
throttled.cleanup();
|
|
431
|
+
|
|
432
|
+
// Try to execute any remaining RAF callbacks
|
|
433
|
+
rafCallbacks.forEach((callback) => {
|
|
434
|
+
callback(performance.now());
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
expect(func).not.toHaveBeenCalled();
|
|
438
|
+
});
|
|
439
|
+
});
|