mtrl-addons 0.1.2 → 0.2.2
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/AI.md +28 -230
- package/CLAUDE.md +882 -0
- package/build.js +253 -24
- package/package.json +14 -4
- package/scripts/debug/vlist-selection.ts +121 -0
- package/src/components/index.ts +5 -41
- package/src/components/{list → vlist}/config.ts +66 -95
- package/src/components/vlist/constants.ts +23 -0
- package/src/components/vlist/features/api.ts +626 -0
- package/src/components/vlist/features/index.ts +10 -0
- package/src/components/vlist/features/selection.ts +436 -0
- package/src/components/vlist/features/viewport.ts +59 -0
- package/src/components/vlist/index.ts +17 -0
- package/src/components/{list → vlist}/types.ts +242 -32
- package/src/components/vlist/vlist.ts +92 -0
- package/src/core/compose/features/gestures/index.ts +227 -0
- package/src/core/compose/features/gestures/longpress.ts +383 -0
- package/src/core/compose/features/gestures/pan.ts +424 -0
- package/src/core/compose/features/gestures/pinch.ts +475 -0
- package/src/core/compose/features/gestures/rotate.ts +485 -0
- package/src/core/compose/features/gestures/swipe.ts +492 -0
- package/src/core/compose/features/gestures/tap.ts +334 -0
- package/src/core/compose/features/index.ts +2 -38
- package/src/core/compose/index.ts +13 -29
- package/src/core/gestures/index.ts +31 -0
- package/src/core/gestures/longpress.ts +68 -0
- package/src/core/gestures/manager.ts +418 -0
- package/src/core/gestures/pan.ts +48 -0
- package/src/core/gestures/pinch.ts +58 -0
- package/src/core/gestures/rotate.ts +58 -0
- package/src/core/gestures/swipe.ts +66 -0
- package/src/core/gestures/tap.ts +45 -0
- package/src/core/gestures/types.ts +387 -0
- package/src/core/gestures/utils.ts +128 -0
- package/src/core/index.ts +27 -151
- package/src/core/layout/schema.ts +153 -72
- package/src/core/layout/types.ts +5 -2
- package/src/core/viewport/constants.ts +145 -0
- package/src/core/viewport/features/base.ts +73 -0
- package/src/core/viewport/features/collection.ts +1182 -0
- package/src/core/viewport/features/events.ts +130 -0
- package/src/core/viewport/features/index.ts +20 -0
- package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +31 -34
- package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
- package/src/core/viewport/features/momentum.ts +269 -0
- package/src/core/viewport/features/placeholders.ts +335 -0
- package/src/core/viewport/features/rendering.ts +962 -0
- package/src/core/viewport/features/scrollbar.ts +434 -0
- package/src/core/viewport/features/scrolling.ts +634 -0
- package/src/core/viewport/features/utils.ts +94 -0
- package/src/core/viewport/features/virtual.ts +525 -0
- package/src/core/viewport/index.ts +31 -0
- package/src/core/viewport/types.ts +133 -0
- package/src/core/viewport/utils/speed-tracker.ts +79 -0
- package/src/core/viewport/viewport.ts +265 -0
- package/src/index.ts +0 -7
- package/src/styles/components/_vlist.scss +352 -0
- package/src/styles/index.scss +1 -1
- package/test/components/vlist-selection.test.ts +240 -0
- package/test/components/vlist.test.ts +63 -0
- package/test/core/collection/adapter.test.ts +161 -0
- package/bun.lock +0 -792
- package/src/components/list/api.ts +0 -314
- package/src/components/list/constants.ts +0 -56
- package/src/components/list/features/api.ts +0 -428
- package/src/components/list/features/index.ts +0 -31
- package/src/components/list/features/list-manager.ts +0 -502
- package/src/components/list/index.ts +0 -39
- package/src/components/list/list.ts +0 -234
- package/src/core/collection/base-collection.ts +0 -100
- package/src/core/collection/collection-composer.ts +0 -178
- package/src/core/collection/collection.ts +0 -745
- package/src/core/collection/constants.ts +0 -172
- package/src/core/collection/events.ts +0 -428
- package/src/core/collection/features/api/loading.ts +0 -279
- package/src/core/collection/features/operations/data-operations.ts +0 -147
- package/src/core/collection/index.ts +0 -104
- package/src/core/collection/state.ts +0 -497
- package/src/core/collection/types.ts +0 -404
- package/src/core/compose/features/collection.ts +0 -119
- package/src/core/compose/features/selection.ts +0 -213
- package/src/core/compose/features/styling.ts +0 -108
- package/src/core/list-manager/api.ts +0 -599
- package/src/core/list-manager/config.ts +0 -593
- package/src/core/list-manager/constants.ts +0 -268
- package/src/core/list-manager/features/api.ts +0 -58
- package/src/core/list-manager/features/collection/collection.ts +0 -705
- package/src/core/list-manager/features/collection/index.ts +0 -17
- package/src/core/list-manager/features/viewport/constants.ts +0 -42
- package/src/core/list-manager/features/viewport/index.ts +0 -16
- package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
- package/src/core/list-manager/features/viewport/rendering.ts +0 -575
- package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
- package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
- package/src/core/list-manager/features/viewport/template.ts +0 -220
- package/src/core/list-manager/features/viewport/viewport.ts +0 -654
- package/src/core/list-manager/features/viewport/virtual.ts +0 -309
- package/src/core/list-manager/index.ts +0 -279
- package/src/core/list-manager/list-manager.ts +0 -206
- package/src/core/list-manager/types.ts +0 -439
- package/src/core/list-manager/utils/calculations.ts +0 -290
- package/src/core/list-manager/utils/range-calculator.ts +0 -349
- package/src/core/list-manager/utils/speed-tracker.ts +0 -273
- package/src/styles/components/_list.scss +0 -244
- package/src/types/mtrl.d.ts +0 -6
- package/test/components/list.test.ts +0 -256
- package/test/core/collection/failed-ranges.test.ts +0 -270
- package/test/core/compose/features.test.ts +0 -183
- package/test/core/list-manager/features/collection.test.ts +0 -704
- package/test/core/list-manager/features/viewport.test.ts +0 -698
- package/test/core/list-manager/list-manager.test.ts +0 -593
- package/test/core/list-manager/utils/calculations.test.ts +0 -433
- package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
- package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
- package/tsconfig.build.json +0 -23
- /package/src/components/{list → vlist}/features.ts +0 -0
- /package/src/core/{compose → viewport}/features/performance.ts +0 -0
|
@@ -1,530 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
createSpeedTracker,
|
|
4
|
-
updateSpeedTracker,
|
|
5
|
-
isFastScrolling,
|
|
6
|
-
isSlowScrolling,
|
|
7
|
-
getLoadingStrategy,
|
|
8
|
-
calculateScrollMomentum,
|
|
9
|
-
createSpeedBasedLoadingConfig,
|
|
10
|
-
resetSpeedTracker,
|
|
11
|
-
getScrollThrottleInterval,
|
|
12
|
-
hasSignificantDirectionChange,
|
|
13
|
-
calculateAdaptiveOverscan,
|
|
14
|
-
getSpeedTrackerDebugInfo,
|
|
15
|
-
} from "../../../../src/core/list-manager/utils/speed-tracker";
|
|
16
|
-
import type { SpeedTracker } from "../../../../src/core/list-manager/types";
|
|
17
|
-
|
|
18
|
-
describe("Speed Tracker Utility", () => {
|
|
19
|
-
let speedTracker: SpeedTracker;
|
|
20
|
-
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
speedTracker = createSpeedTracker();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe("createSpeedTracker", () => {
|
|
26
|
-
it("should create speed tracker with initial values", () => {
|
|
27
|
-
const tracker = createSpeedTracker();
|
|
28
|
-
|
|
29
|
-
expect(tracker.velocity).toBe(0);
|
|
30
|
-
expect(tracker.direction).toBe("forward");
|
|
31
|
-
expect(tracker.lastPosition).toBe(0);
|
|
32
|
-
expect(tracker.lastTimestamp).toBeGreaterThan(0);
|
|
33
|
-
expect(tracker.samples).toEqual([]);
|
|
34
|
-
expect(tracker.isScrolling).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("should create tracker with custom initial position", () => {
|
|
38
|
-
const tracker = createSpeedTracker(100);
|
|
39
|
-
|
|
40
|
-
expect(tracker.lastPosition).toBe(100);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("updateSpeedTracker", () => {
|
|
45
|
-
it("should update speed tracker with new position", () => {
|
|
46
|
-
const initialTime = speedTracker.lastTimestamp;
|
|
47
|
-
|
|
48
|
-
// Simulate moving 100px forward after 100ms
|
|
49
|
-
const updated = updateSpeedTracker(speedTracker, 100, initialTime + 100);
|
|
50
|
-
|
|
51
|
-
expect(updated.velocity).toBeGreaterThan(0);
|
|
52
|
-
expect(updated.direction).toBe("forward");
|
|
53
|
-
expect(updated.lastPosition).toBe(100);
|
|
54
|
-
expect(updated.lastTimestamp).toBe(initialTime + 100);
|
|
55
|
-
expect(updated.isScrolling).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("should detect backward direction", () => {
|
|
59
|
-
// Start at position 100
|
|
60
|
-
speedTracker.lastPosition = 100;
|
|
61
|
-
|
|
62
|
-
// Move backward to position 50
|
|
63
|
-
const updated = updateSpeedTracker(
|
|
64
|
-
speedTracker,
|
|
65
|
-
50,
|
|
66
|
-
speedTracker.lastTimestamp + 100
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
expect(updated.direction).toBe("backward");
|
|
70
|
-
expect(updated.velocity).toBeGreaterThan(0); // Always positive
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("should handle same position (no movement)", () => {
|
|
74
|
-
const updated = updateSpeedTracker(
|
|
75
|
-
speedTracker,
|
|
76
|
-
0,
|
|
77
|
-
speedTracker.lastTimestamp + 100
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
expect(updated.velocity).toBe(0);
|
|
81
|
-
expect(updated.lastPosition).toBe(0);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("should maintain sample history", () => {
|
|
85
|
-
let tracker = speedTracker;
|
|
86
|
-
|
|
87
|
-
// Add several samples
|
|
88
|
-
for (let i = 1; i <= 10; i++) {
|
|
89
|
-
tracker = updateSpeedTracker(
|
|
90
|
-
tracker,
|
|
91
|
-
i * 10,
|
|
92
|
-
tracker.lastTimestamp + 16
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
expect(tracker.samples).toBeDefined();
|
|
97
|
-
expect(tracker.samples.length).toBeGreaterThan(0);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("should limit sample history size", () => {
|
|
101
|
-
let tracker = speedTracker;
|
|
102
|
-
|
|
103
|
-
// Add many samples (more than the limit)
|
|
104
|
-
for (let i = 1; i <= 100; i++) {
|
|
105
|
-
tracker = updateSpeedTracker(
|
|
106
|
-
tracker,
|
|
107
|
-
i * 10,
|
|
108
|
-
tracker.lastTimestamp + 16
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Should not exceed reasonable limit (e.g., 20 samples)
|
|
113
|
-
expect(tracker.samples.length).toBeLessThanOrEqual(20);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe("isFastScrolling", () => {
|
|
118
|
-
it("should detect fast scrolling", () => {
|
|
119
|
-
// Simulate fast scrolling (high velocity)
|
|
120
|
-
const fastTracker = updateSpeedTracker(
|
|
121
|
-
speedTracker,
|
|
122
|
-
1000,
|
|
123
|
-
speedTracker.lastTimestamp + 100
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
expect(isFastScrolling(fastTracker)).toBe(true);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("should detect slow scrolling", () => {
|
|
130
|
-
// Simulate slow scrolling (low velocity)
|
|
131
|
-
const slowTracker = updateSpeedTracker(
|
|
132
|
-
speedTracker,
|
|
133
|
-
10,
|
|
134
|
-
speedTracker.lastTimestamp + 100
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
expect(isFastScrolling(slowTracker)).toBe(false);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("should handle stationary state", () => {
|
|
141
|
-
expect(isFastScrolling(speedTracker)).toBe(false);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe("isSlowScrolling", () => {
|
|
146
|
-
it("should detect slow scrolling", () => {
|
|
147
|
-
// Simulate slow scrolling
|
|
148
|
-
const slowTracker = updateSpeedTracker(
|
|
149
|
-
speedTracker,
|
|
150
|
-
10,
|
|
151
|
-
speedTracker.lastTimestamp + 100
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
expect(isSlowScrolling(slowTracker)).toBe(true);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("should not detect fast scrolling as slow", () => {
|
|
158
|
-
// Simulate fast scrolling
|
|
159
|
-
const fastTracker = updateSpeedTracker(
|
|
160
|
-
speedTracker,
|
|
161
|
-
1000,
|
|
162
|
-
speedTracker.lastTimestamp + 100
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
expect(isSlowScrolling(fastTracker)).toBe(false);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("should handle stationary state", () => {
|
|
169
|
-
expect(isSlowScrolling(speedTracker)).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe("getLoadingStrategy", () => {
|
|
174
|
-
it("should return aggressive strategy for fast scrolling", () => {
|
|
175
|
-
const fastTracker = updateSpeedTracker(
|
|
176
|
-
speedTracker,
|
|
177
|
-
1000,
|
|
178
|
-
speedTracker.lastTimestamp + 100
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
const strategy = getLoadingStrategy(fastTracker);
|
|
182
|
-
|
|
183
|
-
expect(strategy).toBe("aggressive");
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("should return conservative strategy for slow scrolling", () => {
|
|
187
|
-
const slowTracker = updateSpeedTracker(
|
|
188
|
-
speedTracker,
|
|
189
|
-
10,
|
|
190
|
-
speedTracker.lastTimestamp + 100
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
const strategy = getLoadingStrategy(slowTracker);
|
|
194
|
-
|
|
195
|
-
expect(strategy).toBe("conservative");
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("should return normal strategy for moderate scrolling", () => {
|
|
199
|
-
const moderateTracker = updateSpeedTracker(
|
|
200
|
-
speedTracker,
|
|
201
|
-
100,
|
|
202
|
-
speedTracker.lastTimestamp + 100
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
const strategy = getLoadingStrategy(moderateTracker);
|
|
206
|
-
|
|
207
|
-
expect(strategy).toBe("normal");
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("should return idle strategy when not scrolling", () => {
|
|
211
|
-
const strategy = getLoadingStrategy(speedTracker);
|
|
212
|
-
|
|
213
|
-
expect(strategy).toBe("idle");
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
describe("calculateScrollMomentum", () => {
|
|
218
|
-
it("should calculate momentum for fast scrolling", () => {
|
|
219
|
-
const fastTracker = updateSpeedTracker(
|
|
220
|
-
speedTracker,
|
|
221
|
-
1000,
|
|
222
|
-
speedTracker.lastTimestamp + 100
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
const momentum = calculateScrollMomentum(fastTracker);
|
|
226
|
-
|
|
227
|
-
expect(momentum).toBeGreaterThan(0);
|
|
228
|
-
expect(momentum).toBeLessThanOrEqual(1);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("should return zero momentum when stationary", () => {
|
|
232
|
-
const momentum = calculateScrollMomentum(speedTracker);
|
|
233
|
-
|
|
234
|
-
expect(momentum).toBe(0);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it("should cap momentum at 1.0", () => {
|
|
238
|
-
// Simulate extremely fast scrolling
|
|
239
|
-
const veryFastTracker = updateSpeedTracker(
|
|
240
|
-
speedTracker,
|
|
241
|
-
10000,
|
|
242
|
-
speedTracker.lastTimestamp + 16
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
const momentum = calculateScrollMomentum(veryFastTracker);
|
|
246
|
-
|
|
247
|
-
expect(momentum).toBeLessThanOrEqual(1);
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
describe("createSpeedBasedLoadingConfig", () => {
|
|
252
|
-
it("should create config for aggressive loading", () => {
|
|
253
|
-
const fastTracker = updateSpeedTracker(
|
|
254
|
-
speedTracker,
|
|
255
|
-
1000,
|
|
256
|
-
speedTracker.lastTimestamp + 100
|
|
257
|
-
);
|
|
258
|
-
|
|
259
|
-
const config = createSpeedBasedLoadingConfig(fastTracker);
|
|
260
|
-
|
|
261
|
-
expect(config.strategy).toBe("aggressive");
|
|
262
|
-
expect(config.rangeMultiplier).toBeGreaterThan(1);
|
|
263
|
-
expect(config.loadAhead).toBeGreaterThan(0);
|
|
264
|
-
expect(config.throttleMs).toBeGreaterThan(0);
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it("should create config for conservative loading", () => {
|
|
268
|
-
const slowTracker = updateSpeedTracker(
|
|
269
|
-
speedTracker,
|
|
270
|
-
10,
|
|
271
|
-
speedTracker.lastTimestamp + 100
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
const config = createSpeedBasedLoadingConfig(slowTracker);
|
|
275
|
-
|
|
276
|
-
expect(config.strategy).toBe("conservative");
|
|
277
|
-
expect(config.rangeMultiplier).toBeLessThanOrEqual(2);
|
|
278
|
-
expect(config.loadAhead).toBeGreaterThanOrEqual(0);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it("should create config for idle state", () => {
|
|
282
|
-
const config = createSpeedBasedLoadingConfig(speedTracker);
|
|
283
|
-
|
|
284
|
-
expect(config.strategy).toBe("idle");
|
|
285
|
-
expect(config.rangeMultiplier).toBe(1);
|
|
286
|
-
expect(config.loadAhead).toBe(0);
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
describe("resetSpeedTracker", () => {
|
|
291
|
-
it("should reset speed tracker to initial state", () => {
|
|
292
|
-
// First, modify the tracker
|
|
293
|
-
let tracker = updateSpeedTracker(
|
|
294
|
-
speedTracker,
|
|
295
|
-
500,
|
|
296
|
-
speedTracker.lastTimestamp + 100
|
|
297
|
-
);
|
|
298
|
-
tracker = updateSpeedTracker(tracker, 1000, tracker.lastTimestamp + 100);
|
|
299
|
-
|
|
300
|
-
expect(tracker.velocity).toBeGreaterThan(0);
|
|
301
|
-
expect(tracker.samples.length).toBeGreaterThan(0);
|
|
302
|
-
|
|
303
|
-
// Reset it
|
|
304
|
-
const reset = resetSpeedTracker(tracker);
|
|
305
|
-
|
|
306
|
-
expect(reset.velocity).toBe(0);
|
|
307
|
-
expect(reset.samples).toEqual([]);
|
|
308
|
-
expect(reset.isScrolling).toBe(false);
|
|
309
|
-
expect(reset.lastPosition).toBe(tracker.lastPosition); // Position preserved
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it("should preserve current position when resetting", () => {
|
|
313
|
-
const tracker = updateSpeedTracker(
|
|
314
|
-
speedTracker,
|
|
315
|
-
300,
|
|
316
|
-
speedTracker.lastTimestamp + 100
|
|
317
|
-
);
|
|
318
|
-
const reset = resetSpeedTracker(tracker);
|
|
319
|
-
|
|
320
|
-
expect(reset.lastPosition).toBe(300);
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
describe("getScrollThrottleInterval", () => {
|
|
325
|
-
it("should return shorter interval for fast scrolling", () => {
|
|
326
|
-
const fastTracker = updateSpeedTracker(
|
|
327
|
-
speedTracker,
|
|
328
|
-
1000,
|
|
329
|
-
speedTracker.lastTimestamp + 100
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
const interval = getScrollThrottleInterval(fastTracker);
|
|
333
|
-
|
|
334
|
-
expect(interval).toBeGreaterThan(0);
|
|
335
|
-
expect(interval).toBeLessThan(50); // Should be quite responsive
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it("should return longer interval for slow scrolling", () => {
|
|
339
|
-
const slowTracker = updateSpeedTracker(
|
|
340
|
-
speedTracker,
|
|
341
|
-
10,
|
|
342
|
-
speedTracker.lastTimestamp + 100
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
const interval = getScrollThrottleInterval(slowTracker);
|
|
346
|
-
|
|
347
|
-
expect(interval).toBeGreaterThan(0);
|
|
348
|
-
// Should be longer than fast scrolling but still reasonable
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it("should return default interval when not scrolling", () => {
|
|
352
|
-
const interval = getScrollThrottleInterval(speedTracker);
|
|
353
|
-
|
|
354
|
-
expect(interval).toBeGreaterThan(0);
|
|
355
|
-
expect(interval).toBeLessThanOrEqual(100); // Reasonable default
|
|
356
|
-
});
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
describe("hasSignificantDirectionChange", () => {
|
|
360
|
-
it("should detect direction change", () => {
|
|
361
|
-
// Start moving forward
|
|
362
|
-
let tracker = updateSpeedTracker(
|
|
363
|
-
speedTracker,
|
|
364
|
-
100,
|
|
365
|
-
speedTracker.lastTimestamp + 100
|
|
366
|
-
);
|
|
367
|
-
tracker = updateSpeedTracker(tracker, 200, tracker.lastTimestamp + 100);
|
|
368
|
-
|
|
369
|
-
// Then move backward
|
|
370
|
-
tracker = updateSpeedTracker(tracker, 150, tracker.lastTimestamp + 100);
|
|
371
|
-
tracker = updateSpeedTracker(tracker, 100, tracker.lastTimestamp + 100);
|
|
372
|
-
|
|
373
|
-
const hasChanged = hasSignificantDirectionChange(tracker);
|
|
374
|
-
|
|
375
|
-
expect(hasChanged).toBe(true);
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
it("should not detect change when continuing in same direction", () => {
|
|
379
|
-
// Consistent forward movement
|
|
380
|
-
let tracker = updateSpeedTracker(
|
|
381
|
-
speedTracker,
|
|
382
|
-
100,
|
|
383
|
-
speedTracker.lastTimestamp + 100
|
|
384
|
-
);
|
|
385
|
-
tracker = updateSpeedTracker(tracker, 200, tracker.lastTimestamp + 100);
|
|
386
|
-
tracker = updateSpeedTracker(tracker, 300, tracker.lastTimestamp + 100);
|
|
387
|
-
|
|
388
|
-
const hasChanged = hasSignificantDirectionChange(tracker);
|
|
389
|
-
|
|
390
|
-
expect(hasChanged).toBe(false);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it("should handle insufficient sample history", () => {
|
|
394
|
-
const tracker = updateSpeedTracker(
|
|
395
|
-
speedTracker,
|
|
396
|
-
100,
|
|
397
|
-
speedTracker.lastTimestamp + 100
|
|
398
|
-
);
|
|
399
|
-
|
|
400
|
-
const hasChanged = hasSignificantDirectionChange(tracker);
|
|
401
|
-
|
|
402
|
-
expect(hasChanged).toBe(false);
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
describe("calculateAdaptiveOverscan", () => {
|
|
407
|
-
it("should increase overscan for fast scrolling", () => {
|
|
408
|
-
const fastTracker = updateSpeedTracker(
|
|
409
|
-
speedTracker,
|
|
410
|
-
1000,
|
|
411
|
-
speedTracker.lastTimestamp + 100
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
const overscan = calculateAdaptiveOverscan(fastTracker, 5, 20);
|
|
415
|
-
|
|
416
|
-
expect(overscan).toBeGreaterThan(5); // Should increase from base
|
|
417
|
-
expect(overscan).toBeLessThanOrEqual(20); // Should not exceed max
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it("should maintain base overscan for slow scrolling", () => {
|
|
421
|
-
const slowTracker = updateSpeedTracker(
|
|
422
|
-
speedTracker,
|
|
423
|
-
10,
|
|
424
|
-
speedTracker.lastTimestamp + 100
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
const overscan = calculateAdaptiveOverscan(slowTracker, 5, 20);
|
|
428
|
-
|
|
429
|
-
expect(overscan).toBeCloseTo(5, 1); // Should be close to base
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it("should return base overscan when not scrolling", () => {
|
|
433
|
-
const overscan = calculateAdaptiveOverscan(speedTracker, 3, 15);
|
|
434
|
-
|
|
435
|
-
expect(overscan).toBe(3);
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it("should respect maximum overscan limit", () => {
|
|
439
|
-
// Extremely fast scrolling
|
|
440
|
-
const veryFastTracker = updateSpeedTracker(
|
|
441
|
-
speedTracker,
|
|
442
|
-
10000,
|
|
443
|
-
speedTracker.lastTimestamp + 16
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
const overscan = calculateAdaptiveOverscan(veryFastTracker, 2, 10);
|
|
447
|
-
|
|
448
|
-
expect(overscan).toBeLessThanOrEqual(10);
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
describe("getSpeedTrackerDebugInfo", () => {
|
|
453
|
-
it("should return comprehensive debug information", () => {
|
|
454
|
-
// Create tracker with some history
|
|
455
|
-
let tracker = speedTracker;
|
|
456
|
-
for (let i = 1; i <= 5; i++) {
|
|
457
|
-
tracker = updateSpeedTracker(
|
|
458
|
-
tracker,
|
|
459
|
-
i * 50,
|
|
460
|
-
tracker.lastTimestamp + 20
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const debug = getSpeedTrackerDebugInfo(tracker);
|
|
465
|
-
|
|
466
|
-
expect(debug).toHaveProperty("velocity");
|
|
467
|
-
expect(debug).toHaveProperty("direction");
|
|
468
|
-
expect(debug).toHaveProperty("isScrolling");
|
|
469
|
-
expect(debug).toHaveProperty("strategy");
|
|
470
|
-
expect(debug).toHaveProperty("momentum");
|
|
471
|
-
expect(debug).toHaveProperty("sampleCount");
|
|
472
|
-
expect(debug).toHaveProperty("averageVelocity");
|
|
473
|
-
expect(debug).toHaveProperty("throttleInterval");
|
|
474
|
-
expect(debug).toHaveProperty("adaptiveOverscan");
|
|
475
|
-
|
|
476
|
-
expect(debug.velocity).toBeGreaterThan(0);
|
|
477
|
-
expect(debug.isScrolling).toBe(true);
|
|
478
|
-
expect(debug.sampleCount).toBeGreaterThan(0);
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
it("should handle idle state debug info", () => {
|
|
482
|
-
const debug = getSpeedTrackerDebugInfo(speedTracker);
|
|
483
|
-
|
|
484
|
-
expect(debug.velocity).toBe(0);
|
|
485
|
-
expect(debug.isScrolling).toBe(false);
|
|
486
|
-
expect(debug.strategy).toBe("idle");
|
|
487
|
-
expect(debug.momentum).toBe(0);
|
|
488
|
-
expect(debug.sampleCount).toBe(0);
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
describe("Integration scenarios", () => {
|
|
493
|
-
it("should handle rapid velocity changes", () => {
|
|
494
|
-
let tracker = speedTracker;
|
|
495
|
-
|
|
496
|
-
// Fast acceleration
|
|
497
|
-
tracker = updateSpeedTracker(tracker, 100, tracker.lastTimestamp + 100);
|
|
498
|
-
tracker = updateSpeedTracker(tracker, 300, tracker.lastTimestamp + 50);
|
|
499
|
-
tracker = updateSpeedTracker(tracker, 600, tracker.lastTimestamp + 25);
|
|
500
|
-
|
|
501
|
-
expect(isFastScrolling(tracker)).toBe(true);
|
|
502
|
-
expect(getLoadingStrategy(tracker)).toBe("aggressive");
|
|
503
|
-
|
|
504
|
-
// Sudden deceleration
|
|
505
|
-
tracker = updateSpeedTracker(tracker, 650, tracker.lastTimestamp + 100);
|
|
506
|
-
tracker = updateSpeedTracker(tracker, 660, tracker.lastTimestamp + 100);
|
|
507
|
-
|
|
508
|
-
expect(isFastScrolling(tracker)).toBe(false);
|
|
509
|
-
expect(getLoadingStrategy(tracker)).not.toBe("aggressive");
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
it("should handle direction reversals during fast scrolling", () => {
|
|
513
|
-
let tracker = speedTracker;
|
|
514
|
-
|
|
515
|
-
// Fast forward movement
|
|
516
|
-
tracker = updateSpeedTracker(tracker, 500, tracker.lastTimestamp + 50);
|
|
517
|
-
tracker = updateSpeedTracker(tracker, 1000, tracker.lastTimestamp + 50);
|
|
518
|
-
|
|
519
|
-
expect(tracker.direction).toBe("forward");
|
|
520
|
-
expect(isFastScrolling(tracker)).toBe(true);
|
|
521
|
-
|
|
522
|
-
// Rapid reversal
|
|
523
|
-
tracker = updateSpeedTracker(tracker, 500, tracker.lastTimestamp + 50);
|
|
524
|
-
tracker = updateSpeedTracker(tracker, 0, tracker.lastTimestamp + 50);
|
|
525
|
-
|
|
526
|
-
expect(tracker.direction).toBe("backward");
|
|
527
|
-
expect(hasSignificantDirectionChange(tracker)).toBe(true);
|
|
528
|
-
});
|
|
529
|
-
});
|
|
530
|
-
});
|
package/tsconfig.build.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"emitDeclarationOnly": true,
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
"noEmitOnError": false,
|
|
10
|
-
"moduleResolution": "node",
|
|
11
|
-
"allowSyntheticDefaultImports": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"typeRoots": ["./node_modules/@types", "./src/types"]
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*.ts", "src/types/**/*.d.ts"],
|
|
16
|
-
"exclude": [
|
|
17
|
-
"node_modules",
|
|
18
|
-
"dist",
|
|
19
|
-
"**/*.test.ts",
|
|
20
|
-
"test/**/*",
|
|
21
|
-
"../mtrl/**/*"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
File without changes
|
|
File without changes
|