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,433 +0,0 @@
|
|
|
1
|
-
// test/core/list-manager/utils/calculations.test.ts
|
|
2
|
-
|
|
3
|
-
import { describe, it, expect } from "bun:test";
|
|
4
|
-
import {
|
|
5
|
-
calculateTotalVirtualSize,
|
|
6
|
-
calculateContainerPosition,
|
|
7
|
-
calculateScrollPositionForIndex,
|
|
8
|
-
calculateScrollPositionForPage,
|
|
9
|
-
calculateScrollbarMetrics,
|
|
10
|
-
calculateInitialRangeSize,
|
|
11
|
-
calculateMissingRanges,
|
|
12
|
-
calculateBufferRanges,
|
|
13
|
-
clamp,
|
|
14
|
-
applyBoundaryResistance,
|
|
15
|
-
} from "../../../../src/core/list-manager/utils/calculations";
|
|
16
|
-
import type { ItemRange } from "../../../../src/core/list-manager/types";
|
|
17
|
-
|
|
18
|
-
describe("Calculations Utility", () => {
|
|
19
|
-
describe("clamp", () => {
|
|
20
|
-
it("should clamp value within range", () => {
|
|
21
|
-
expect(clamp(5, 0, 10)).toBe(5);
|
|
22
|
-
expect(clamp(-5, 0, 10)).toBe(0);
|
|
23
|
-
expect(clamp(15, 0, 10)).toBe(10);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("should handle edge cases", () => {
|
|
27
|
-
expect(clamp(0, 0, 0)).toBe(0);
|
|
28
|
-
expect(clamp(5, 5, 5)).toBe(5);
|
|
29
|
-
expect(clamp(3, 5, 2)).toBe(3); // Invalid range
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Removed calculateVisibleRange tests - using unified index-based approach
|
|
34
|
-
|
|
35
|
-
describe("calculateTotalVirtualSize", () => {
|
|
36
|
-
it("should calculate total size for uniform items", () => {
|
|
37
|
-
const size = calculateTotalVirtualSize({
|
|
38
|
-
totalItems: 100,
|
|
39
|
-
estimatedItemSize: 50,
|
|
40
|
-
orientation: "vertical",
|
|
41
|
-
measuredSizes: new Map(),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(size).toBe(5000); // 100 * 50
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("should calculate size with some measured items", () => {
|
|
48
|
-
const measuredSizes = new Map<number, number>();
|
|
49
|
-
measuredSizes.set(0, 60);
|
|
50
|
-
measuredSizes.set(1, 70);
|
|
51
|
-
measuredSizes.set(2, 40);
|
|
52
|
-
|
|
53
|
-
const size = calculateTotalVirtualSize({
|
|
54
|
-
totalItems: 10,
|
|
55
|
-
estimatedItemSize: 50,
|
|
56
|
-
orientation: "vertical",
|
|
57
|
-
measuredSizes,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// First 3 items: 60 + 70 + 40 = 170
|
|
61
|
-
// Remaining 7 items: 7 * 50 = 350
|
|
62
|
-
// Total: 520
|
|
63
|
-
expect(size).toBe(520);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("should handle empty list", () => {
|
|
67
|
-
const size = calculateTotalVirtualSize({
|
|
68
|
-
totalItems: 0,
|
|
69
|
-
estimatedItemSize: 50,
|
|
70
|
-
orientation: "vertical",
|
|
71
|
-
measuredSizes: new Map(),
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
expect(size).toBe(0);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe("calculateContainerPosition", () => {
|
|
79
|
-
it("should calculate position for vertical orientation", () => {
|
|
80
|
-
const position = calculateContainerPosition({
|
|
81
|
-
index: 10,
|
|
82
|
-
estimatedItemSize: 50,
|
|
83
|
-
orientation: "vertical",
|
|
84
|
-
measuredSizes: new Map(),
|
|
85
|
-
totalItems: 100,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(position).toBe(500); // 10 * 50
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("should calculate position with measured sizes", () => {
|
|
92
|
-
const measuredSizes = new Map<number, number>();
|
|
93
|
-
measuredSizes.set(0, 60);
|
|
94
|
-
measuredSizes.set(1, 70);
|
|
95
|
-
measuredSizes.set(2, 40);
|
|
96
|
-
|
|
97
|
-
const position = calculateContainerPosition({
|
|
98
|
-
index: 3,
|
|
99
|
-
estimatedItemSize: 50,
|
|
100
|
-
orientation: "horizontal",
|
|
101
|
-
measuredSizes,
|
|
102
|
-
totalItems: 100,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
expect(position).toBe(170); // 60 + 70 + 40
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("should handle index 0", () => {
|
|
109
|
-
const position = calculateContainerPosition({
|
|
110
|
-
index: 0,
|
|
111
|
-
estimatedItemSize: 50,
|
|
112
|
-
orientation: "vertical",
|
|
113
|
-
measuredSizes: new Map(),
|
|
114
|
-
totalItems: 100,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
expect(position).toBe(0);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe("calculateScrollPositionForIndex", () => {
|
|
122
|
-
it("should calculate scroll position for 'start' alignment", () => {
|
|
123
|
-
const position = calculateScrollPositionForIndex({
|
|
124
|
-
index: 10,
|
|
125
|
-
alignment: "start",
|
|
126
|
-
containerSize: 300,
|
|
127
|
-
estimatedItemSize: 50,
|
|
128
|
-
orientation: "vertical",
|
|
129
|
-
measuredSizes: new Map(),
|
|
130
|
-
totalItems: 100,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
expect(position).toBe(500); // 10 * 50
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("should calculate scroll position for 'center' alignment", () => {
|
|
137
|
-
const position = calculateScrollPositionForIndex({
|
|
138
|
-
index: 10,
|
|
139
|
-
alignment: "center",
|
|
140
|
-
containerSize: 300,
|
|
141
|
-
estimatedItemSize: 50,
|
|
142
|
-
orientation: "vertical",
|
|
143
|
-
measuredSizes: new Map(),
|
|
144
|
-
totalItems: 100,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Item at 500, center in 300px container = 500 - 150 + 25 = 375
|
|
148
|
-
expect(position).toBe(375);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should calculate scroll position for 'end' alignment", () => {
|
|
152
|
-
const position = calculateScrollPositionForIndex({
|
|
153
|
-
index: 10,
|
|
154
|
-
alignment: "end",
|
|
155
|
-
containerSize: 300,
|
|
156
|
-
estimatedItemSize: 50,
|
|
157
|
-
orientation: "vertical",
|
|
158
|
-
measuredSizes: new Map(),
|
|
159
|
-
totalItems: 100,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Item at 500, end in 300px container = 500 - 300 + 50 = 250
|
|
163
|
-
expect(position).toBe(250);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it("should not scroll past beginning", () => {
|
|
167
|
-
const position = calculateScrollPositionForIndex({
|
|
168
|
-
index: 0,
|
|
169
|
-
alignment: "center",
|
|
170
|
-
containerSize: 300,
|
|
171
|
-
estimatedItemSize: 50,
|
|
172
|
-
orientation: "vertical",
|
|
173
|
-
measuredSizes: new Map(),
|
|
174
|
-
totalItems: 100,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
expect(position).toBeGreaterThanOrEqual(0);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe("calculateScrollPositionForPage", () => {
|
|
182
|
-
it("should calculate position for page", () => {
|
|
183
|
-
const position = calculateScrollPositionForPage({
|
|
184
|
-
page: 3,
|
|
185
|
-
pageSize: 10,
|
|
186
|
-
alignment: "start",
|
|
187
|
-
containerSize: 300,
|
|
188
|
-
estimatedItemSize: 50,
|
|
189
|
-
orientation: "vertical",
|
|
190
|
-
measuredSizes: new Map(),
|
|
191
|
-
totalItems: 100,
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// Page 3, item 20 (0-indexed), position 1000
|
|
195
|
-
expect(position).toBe(1000);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("should handle page 1 (first page)", () => {
|
|
199
|
-
const position = calculateScrollPositionForPage({
|
|
200
|
-
page: 1,
|
|
201
|
-
pageSize: 10,
|
|
202
|
-
alignment: "start",
|
|
203
|
-
containerSize: 300,
|
|
204
|
-
estimatedItemSize: 50,
|
|
205
|
-
orientation: "vertical",
|
|
206
|
-
measuredSizes: new Map(),
|
|
207
|
-
totalItems: 100,
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
expect(position).toBe(0);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
describe("calculateScrollbarMetrics", () => {
|
|
215
|
-
it("should calculate scrollbar metrics", () => {
|
|
216
|
-
const metrics = calculateScrollbarMetrics({
|
|
217
|
-
containerSize: 300,
|
|
218
|
-
totalVirtualSize: 1500,
|
|
219
|
-
scrollPosition: 300,
|
|
220
|
-
orientation: "vertical",
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
expect(metrics.trackSize).toBe(300);
|
|
224
|
-
expect(metrics.thumbSize).toBeGreaterThan(0);
|
|
225
|
-
expect(metrics.thumbPosition).toBeGreaterThan(0);
|
|
226
|
-
expect(metrics.scrollRatio).toBe(0.2); // 300/1500
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it("should handle case where content fits in container", () => {
|
|
230
|
-
const metrics = calculateScrollbarMetrics({
|
|
231
|
-
containerSize: 500,
|
|
232
|
-
totalVirtualSize: 300,
|
|
233
|
-
scrollPosition: 0,
|
|
234
|
-
orientation: "vertical",
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
expect(metrics.thumbSize).toBe(500); // Full size
|
|
238
|
-
expect(metrics.thumbPosition).toBe(0);
|
|
239
|
-
expect(metrics.scrollRatio).toBe(0);
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
it("should handle horizontal scrollbar", () => {
|
|
243
|
-
const metrics = calculateScrollbarMetrics({
|
|
244
|
-
containerSize: 400,
|
|
245
|
-
totalVirtualSize: 1200,
|
|
246
|
-
scrollPosition: 200,
|
|
247
|
-
orientation: "horizontal",
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
expect(metrics.trackSize).toBe(400);
|
|
251
|
-
expect(metrics.scrollRatio).toBeCloseTo(0.167, 2); // 200/1200
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// Removed calculateViewportInfo tests - viewport.ts now uses virtualManager directly
|
|
256
|
-
|
|
257
|
-
describe("calculateInitialRangeSize", () => {
|
|
258
|
-
it("should calculate initial range size", () => {
|
|
259
|
-
const size = calculateInitialRangeSize({
|
|
260
|
-
containerSize: 300,
|
|
261
|
-
estimatedItemSize: 50,
|
|
262
|
-
viewportMultiplier: 2,
|
|
263
|
-
minItems: 5,
|
|
264
|
-
maxItems: 50,
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
// Container fits 6 items (300/50), * 2 = 12 items
|
|
268
|
-
expect(size).toBe(12);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it("should respect min items constraint", () => {
|
|
272
|
-
const size = calculateInitialRangeSize({
|
|
273
|
-
containerSize: 100,
|
|
274
|
-
estimatedItemSize: 50,
|
|
275
|
-
viewportMultiplier: 1,
|
|
276
|
-
minItems: 10,
|
|
277
|
-
maxItems: 50,
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
expect(size).toBe(10); // Min constraint
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it("should respect max items constraint", () => {
|
|
284
|
-
const size = calculateInitialRangeSize({
|
|
285
|
-
containerSize: 1000,
|
|
286
|
-
estimatedItemSize: 10,
|
|
287
|
-
viewportMultiplier: 2,
|
|
288
|
-
minItems: 5,
|
|
289
|
-
maxItems: 50,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
expect(size).toBe(50); // Max constraint
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
describe("calculateMissingRanges", () => {
|
|
297
|
-
it("should find missing ranges", () => {
|
|
298
|
-
const loadedRanges = new Set([0, 1, 2, 5, 6, 7]);
|
|
299
|
-
const requiredRange: ItemRange = { start: 0, end: 10 };
|
|
300
|
-
|
|
301
|
-
const missing = calculateMissingRanges(requiredRange, loadedRanges);
|
|
302
|
-
|
|
303
|
-
expect(missing).toEqual([
|
|
304
|
-
{ start: 3, end: 4 },
|
|
305
|
-
{ start: 8, end: 10 },
|
|
306
|
-
]);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it("should handle no missing ranges", () => {
|
|
310
|
-
const loadedRanges = new Set([0, 1, 2, 3, 4, 5]);
|
|
311
|
-
const requiredRange: ItemRange = { start: 0, end: 5 };
|
|
312
|
-
|
|
313
|
-
const missing = calculateMissingRanges(requiredRange, loadedRanges);
|
|
314
|
-
|
|
315
|
-
expect(missing).toEqual([]);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("should handle completely missing range", () => {
|
|
319
|
-
const loadedRanges = new Set<number>();
|
|
320
|
-
const requiredRange: ItemRange = { start: 10, end: 15 };
|
|
321
|
-
|
|
322
|
-
const missing = calculateMissingRanges(requiredRange, loadedRanges);
|
|
323
|
-
|
|
324
|
-
expect(missing).toEqual([{ start: 10, end: 15 }]);
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
describe("calculateBufferRanges", () => {
|
|
329
|
-
it("should calculate buffer ranges", () => {
|
|
330
|
-
const visibleRange: ItemRange = { start: 10, end: 20 };
|
|
331
|
-
const bufferSize = 5;
|
|
332
|
-
const totalItems = 100;
|
|
333
|
-
|
|
334
|
-
const bufferRanges = calculateBufferRanges(
|
|
335
|
-
visibleRange,
|
|
336
|
-
bufferSize,
|
|
337
|
-
totalItems
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
expect(bufferRanges.before).toEqual({ start: 5, end: 9 });
|
|
341
|
-
expect(bufferRanges.after).toEqual({ start: 21, end: 25 });
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it("should handle buffer at beginning", () => {
|
|
345
|
-
const visibleRange: ItemRange = { start: 0, end: 10 };
|
|
346
|
-
const bufferSize = 5;
|
|
347
|
-
const totalItems = 100;
|
|
348
|
-
|
|
349
|
-
const bufferRanges = calculateBufferRanges(
|
|
350
|
-
visibleRange,
|
|
351
|
-
bufferSize,
|
|
352
|
-
totalItems
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
expect(bufferRanges.before).toEqual({ start: 0, end: -1 }); // Empty range
|
|
356
|
-
expect(bufferRanges.after).toEqual({ start: 11, end: 15 });
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it("should handle buffer at end", () => {
|
|
360
|
-
const visibleRange: ItemRange = { start: 90, end: 99 };
|
|
361
|
-
const bufferSize = 5;
|
|
362
|
-
const totalItems = 100;
|
|
363
|
-
|
|
364
|
-
const bufferRanges = calculateBufferRanges(
|
|
365
|
-
visibleRange,
|
|
366
|
-
bufferSize,
|
|
367
|
-
totalItems
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
expect(bufferRanges.before).toEqual({ start: 85, end: 89 });
|
|
371
|
-
expect(bufferRanges.after).toEqual({ start: 100, end: 99 }); // Empty range
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
describe("applyBoundaryResistance", () => {
|
|
376
|
-
it("should apply resistance at beginning", () => {
|
|
377
|
-
const result = applyBoundaryResistance({
|
|
378
|
-
requestedPosition: -100,
|
|
379
|
-
currentPosition: 0,
|
|
380
|
-
maxPosition: 1000,
|
|
381
|
-
resistance: 0.5,
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
expect(result).toBeGreaterThan(-100);
|
|
385
|
-
expect(result).toBeLessThan(0);
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
it("should apply resistance at end", () => {
|
|
389
|
-
const result = applyBoundaryResistance({
|
|
390
|
-
requestedPosition: 1100,
|
|
391
|
-
currentPosition: 1000,
|
|
392
|
-
maxPosition: 1000,
|
|
393
|
-
resistance: 0.5,
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
expect(result).toBeLessThan(1100);
|
|
397
|
-
expect(result).toBeGreaterThan(1000);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it("should not apply resistance within bounds", () => {
|
|
401
|
-
const result = applyBoundaryResistance({
|
|
402
|
-
requestedPosition: 500,
|
|
403
|
-
currentPosition: 400,
|
|
404
|
-
maxPosition: 1000,
|
|
405
|
-
resistance: 0.5,
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
expect(result).toBe(500);
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
it("should handle zero resistance", () => {
|
|
412
|
-
const result = applyBoundaryResistance({
|
|
413
|
-
requestedPosition: -100,
|
|
414
|
-
currentPosition: 0,
|
|
415
|
-
maxPosition: 1000,
|
|
416
|
-
resistance: 0,
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
expect(result).toBe(0); // Clamped to boundary
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it("should handle full resistance", () => {
|
|
423
|
-
const result = applyBoundaryResistance({
|
|
424
|
-
requestedPosition: -100,
|
|
425
|
-
currentPosition: 0,
|
|
426
|
-
maxPosition: 1000,
|
|
427
|
-
resistance: 1,
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
expect(result).toBe(0); // No movement beyond boundary
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
});
|