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.
Files changed (117) hide show
  1. package/AI.md +28 -230
  2. package/CLAUDE.md +882 -0
  3. package/build.js +253 -24
  4. package/package.json +14 -4
  5. package/scripts/debug/vlist-selection.ts +121 -0
  6. package/src/components/index.ts +5 -41
  7. package/src/components/{list → vlist}/config.ts +66 -95
  8. package/src/components/vlist/constants.ts +23 -0
  9. package/src/components/vlist/features/api.ts +626 -0
  10. package/src/components/vlist/features/index.ts +10 -0
  11. package/src/components/vlist/features/selection.ts +436 -0
  12. package/src/components/vlist/features/viewport.ts +59 -0
  13. package/src/components/vlist/index.ts +17 -0
  14. package/src/components/{list → vlist}/types.ts +242 -32
  15. package/src/components/vlist/vlist.ts +92 -0
  16. package/src/core/compose/features/gestures/index.ts +227 -0
  17. package/src/core/compose/features/gestures/longpress.ts +383 -0
  18. package/src/core/compose/features/gestures/pan.ts +424 -0
  19. package/src/core/compose/features/gestures/pinch.ts +475 -0
  20. package/src/core/compose/features/gestures/rotate.ts +485 -0
  21. package/src/core/compose/features/gestures/swipe.ts +492 -0
  22. package/src/core/compose/features/gestures/tap.ts +334 -0
  23. package/src/core/compose/features/index.ts +2 -38
  24. package/src/core/compose/index.ts +13 -29
  25. package/src/core/gestures/index.ts +31 -0
  26. package/src/core/gestures/longpress.ts +68 -0
  27. package/src/core/gestures/manager.ts +418 -0
  28. package/src/core/gestures/pan.ts +48 -0
  29. package/src/core/gestures/pinch.ts +58 -0
  30. package/src/core/gestures/rotate.ts +58 -0
  31. package/src/core/gestures/swipe.ts +66 -0
  32. package/src/core/gestures/tap.ts +45 -0
  33. package/src/core/gestures/types.ts +387 -0
  34. package/src/core/gestures/utils.ts +128 -0
  35. package/src/core/index.ts +27 -151
  36. package/src/core/layout/schema.ts +153 -72
  37. package/src/core/layout/types.ts +5 -2
  38. package/src/core/viewport/constants.ts +145 -0
  39. package/src/core/viewport/features/base.ts +73 -0
  40. package/src/core/viewport/features/collection.ts +1182 -0
  41. package/src/core/viewport/features/events.ts +130 -0
  42. package/src/core/viewport/features/index.ts +20 -0
  43. package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +31 -34
  44. package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
  45. package/src/core/viewport/features/momentum.ts +269 -0
  46. package/src/core/viewport/features/placeholders.ts +335 -0
  47. package/src/core/viewport/features/rendering.ts +962 -0
  48. package/src/core/viewport/features/scrollbar.ts +434 -0
  49. package/src/core/viewport/features/scrolling.ts +634 -0
  50. package/src/core/viewport/features/utils.ts +94 -0
  51. package/src/core/viewport/features/virtual.ts +525 -0
  52. package/src/core/viewport/index.ts +31 -0
  53. package/src/core/viewport/types.ts +133 -0
  54. package/src/core/viewport/utils/speed-tracker.ts +79 -0
  55. package/src/core/viewport/viewport.ts +265 -0
  56. package/src/index.ts +0 -7
  57. package/src/styles/components/_vlist.scss +352 -0
  58. package/src/styles/index.scss +1 -1
  59. package/test/components/vlist-selection.test.ts +240 -0
  60. package/test/components/vlist.test.ts +63 -0
  61. package/test/core/collection/adapter.test.ts +161 -0
  62. package/bun.lock +0 -792
  63. package/src/components/list/api.ts +0 -314
  64. package/src/components/list/constants.ts +0 -56
  65. package/src/components/list/features/api.ts +0 -428
  66. package/src/components/list/features/index.ts +0 -31
  67. package/src/components/list/features/list-manager.ts +0 -502
  68. package/src/components/list/index.ts +0 -39
  69. package/src/components/list/list.ts +0 -234
  70. package/src/core/collection/base-collection.ts +0 -100
  71. package/src/core/collection/collection-composer.ts +0 -178
  72. package/src/core/collection/collection.ts +0 -745
  73. package/src/core/collection/constants.ts +0 -172
  74. package/src/core/collection/events.ts +0 -428
  75. package/src/core/collection/features/api/loading.ts +0 -279
  76. package/src/core/collection/features/operations/data-operations.ts +0 -147
  77. package/src/core/collection/index.ts +0 -104
  78. package/src/core/collection/state.ts +0 -497
  79. package/src/core/collection/types.ts +0 -404
  80. package/src/core/compose/features/collection.ts +0 -119
  81. package/src/core/compose/features/selection.ts +0 -213
  82. package/src/core/compose/features/styling.ts +0 -108
  83. package/src/core/list-manager/api.ts +0 -599
  84. package/src/core/list-manager/config.ts +0 -593
  85. package/src/core/list-manager/constants.ts +0 -268
  86. package/src/core/list-manager/features/api.ts +0 -58
  87. package/src/core/list-manager/features/collection/collection.ts +0 -705
  88. package/src/core/list-manager/features/collection/index.ts +0 -17
  89. package/src/core/list-manager/features/viewport/constants.ts +0 -42
  90. package/src/core/list-manager/features/viewport/index.ts +0 -16
  91. package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
  92. package/src/core/list-manager/features/viewport/rendering.ts +0 -575
  93. package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
  94. package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
  95. package/src/core/list-manager/features/viewport/template.ts +0 -220
  96. package/src/core/list-manager/features/viewport/viewport.ts +0 -654
  97. package/src/core/list-manager/features/viewport/virtual.ts +0 -309
  98. package/src/core/list-manager/index.ts +0 -279
  99. package/src/core/list-manager/list-manager.ts +0 -206
  100. package/src/core/list-manager/types.ts +0 -439
  101. package/src/core/list-manager/utils/calculations.ts +0 -290
  102. package/src/core/list-manager/utils/range-calculator.ts +0 -349
  103. package/src/core/list-manager/utils/speed-tracker.ts +0 -273
  104. package/src/styles/components/_list.scss +0 -244
  105. package/src/types/mtrl.d.ts +0 -6
  106. package/test/components/list.test.ts +0 -256
  107. package/test/core/collection/failed-ranges.test.ts +0 -270
  108. package/test/core/compose/features.test.ts +0 -183
  109. package/test/core/list-manager/features/collection.test.ts +0 -704
  110. package/test/core/list-manager/features/viewport.test.ts +0 -698
  111. package/test/core/list-manager/list-manager.test.ts +0 -593
  112. package/test/core/list-manager/utils/calculations.test.ts +0 -433
  113. package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
  114. package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
  115. package/tsconfig.build.json +0 -23
  116. /package/src/components/{list → vlist}/features.ts +0 -0
  117. /package/src/core/{compose → viewport}/features/performance.ts +0 -0
@@ -1,495 +0,0 @@
1
- // Removed unused imports
2
- import { CLASSES } from "../../constants";
3
- import { addClass, removeClass } from "mtrl";
4
-
5
- /**
6
- * Scrollbar configuration
7
- */
8
- export interface ScrollbarConfig {
9
- enabled: boolean;
10
- trackWidth: number;
11
- thumbMinHeight: number; // Default: 10px (reduced from 20px)
12
- thumbColor: string;
13
- trackColor: string;
14
- borderRadius: number;
15
- fadeTimeout: number;
16
- itemHeight: number;
17
- totalItems: number;
18
- totalVirtualSize?: number; // The capped virtual size used by viewport
19
- }
20
-
21
- /**
22
- * Scrollbar implementation that bypasses browser scroll height limitations
23
- * Provides accurate scrollbar representation for datasets with millions of items
24
- */
25
- export const scrollbar = (config: Partial<ScrollbarConfig> = {}): any => ({
26
- name: "scrollbar",
27
- version: "1.0.0",
28
- dependencies: [],
29
-
30
- install: (listManager: any, pluginConfig: any) => {
31
- // Configuration with defaults
32
- const scrollbarConfig: ScrollbarConfig = {
33
- enabled: true,
34
- trackWidth: 12,
35
- thumbMinHeight: 10, // Reduced from 20 to 10 (divided by 2)
36
- thumbColor: "#999999",
37
- trackColor: "#f0f0f0",
38
- borderRadius: 6,
39
- fadeTimeout: 1000,
40
- itemHeight: 84,
41
- totalItems: 0,
42
- ...config,
43
- ...(pluginConfig || {}),
44
- };
45
-
46
- // State
47
- let isDragging = false;
48
- let dragStartY = 0;
49
- let dragStartScrollRatio = 0;
50
- let fadeTimeoutId: number | null = null;
51
- let totalVirtualHeight = 0;
52
- let viewportHeight = 0;
53
- let visibleRatio = 0;
54
- let scrollRatio = 0;
55
-
56
- // Get elements
57
- const getElements = () => {
58
- const config = listManager.getConfig?.();
59
- if (!config?.container) return null;
60
-
61
- const containerElement =
62
- typeof config.container === "string"
63
- ? (document.querySelector(config.container) as HTMLElement)
64
- : config.container;
65
-
66
- const viewport = containerElement?.querySelector(
67
- `.mtrl-list__viewport`
68
- ) as HTMLElement;
69
-
70
- // Find the actual mtrl-list element (parent of viewport)
71
- const listElement = viewport?.closest(".mtrl-list") as HTMLElement;
72
-
73
- return { containerElement, viewport, listElement };
74
- };
75
-
76
- let elements = getElements();
77
- if (!elements?.viewport) {
78
- return {};
79
- }
80
- if (!elements?.listElement) {
81
- return {};
82
- }
83
-
84
- const { containerElement, viewport, listElement } = elements;
85
-
86
- // Create scrollbar DOM structure
87
- const scrollbarTrack = document.createElement("div");
88
- addClass(scrollbarTrack, CLASSES.SCROLLBAR);
89
- addClass(scrollbarTrack, CLASSES.SCROLLBAR_TRACK);
90
-
91
- const scrollbarThumb = document.createElement("div");
92
- addClass(scrollbarThumb, CLASSES.SCROLLBAR_THUMB);
93
-
94
- scrollbarTrack.appendChild(scrollbarThumb);
95
- // Append scrollbar to the mtrl-list element, not the outer container
96
- listElement.appendChild(scrollbarTrack);
97
-
98
- // Hide native scrollbar using CSS classes instead of inline styles
99
- addClass(viewport, CLASSES.SCROLLBAR_ENABLED);
100
-
101
- /**
102
- * Calculate scrollbar dimensions and position
103
- */
104
- const updateScrollbarDimensions = (): void => {
105
- if (!scrollbarConfig.totalItems) return;
106
-
107
- // Use capped virtual size if available, otherwise calculate from items
108
- totalVirtualHeight =
109
- scrollbarConfig.totalVirtualSize ||
110
- scrollbarConfig.totalItems * scrollbarConfig.itemHeight;
111
- viewportHeight = viewport.clientHeight;
112
- visibleRatio = Math.min(viewportHeight / totalVirtualHeight, 1);
113
-
114
- // Calculate thumb height (proportional to visible area)
115
- const thumbHeight = Math.max(
116
- scrollbarConfig.thumbMinHeight,
117
- visibleRatio * (scrollbarTrack.clientHeight - 4) // 4px for padding
118
- );
119
-
120
- // Update thumb dimensions
121
- scrollbarThumb.style.height = `${thumbHeight}px`;
122
- };
123
-
124
- /**
125
- * Update scrollbar position based on scroll ratio
126
- */
127
- const updateScrollbarPosition = (newScrollRatio: number): void => {
128
- scrollRatio = Math.max(0, Math.min(1, newScrollRatio));
129
-
130
- const trackHeight = scrollbarTrack.clientHeight;
131
- const thumbHeight = scrollbarThumb.clientHeight;
132
- const maxThumbTop = trackHeight - thumbHeight;
133
- const thumbTop = scrollRatio * maxThumbTop;
134
-
135
- scrollbarThumb.style.top = `${thumbTop}px`;
136
- };
137
-
138
- /**
139
- * Calculate scroll ratio from virtual scroll position
140
- */
141
- const getScrollRatioFromVirtualPosition = (
142
- virtualScrollTop: number
143
- ): number => {
144
- if (totalVirtualHeight <= viewportHeight) return 0;
145
- const maxScroll = totalVirtualHeight - viewportHeight;
146
- return Math.max(0, Math.min(1, virtualScrollTop / maxScroll));
147
- };
148
-
149
- /**
150
- * Calculate virtual scroll position from scroll ratio
151
- */
152
- const getVirtualPositionFromScrollRatio = (ratio: number): number => {
153
- // Use the capped virtual size if available, otherwise calculate from items
154
- const currentTotalVirtualHeight =
155
- scrollbarConfig.totalVirtualSize ||
156
- scrollbarConfig.totalItems * scrollbarConfig.itemHeight;
157
- const currentViewportHeight = viewport.clientHeight;
158
- const maxScroll = Math.max(
159
- 0,
160
- currentTotalVirtualHeight - currentViewportHeight
161
- );
162
- return ratio * maxScroll;
163
- };
164
-
165
- /**
166
- * Show scrollbar with fade in
167
- */
168
- const showScrollbar = (): void => {
169
- if (fadeTimeoutId) {
170
- clearTimeout(fadeTimeoutId);
171
- fadeTimeoutId = null;
172
- }
173
- addClass(scrollbarTrack, CLASSES.SCROLLBAR_SCROLLING);
174
- };
175
-
176
- /**
177
- * Hide scrollbar with fade out
178
- */
179
- const hideScrollbar = (): void => {
180
- if (fadeTimeoutId) clearTimeout(fadeTimeoutId);
181
- fadeTimeoutId = window.setTimeout(() => {
182
- removeClass(scrollbarTrack, CLASSES.SCROLLBAR_SCROLLING);
183
- fadeTimeoutId = null;
184
- }, scrollbarConfig.fadeTimeout);
185
- };
186
-
187
- /**
188
- * Handle scrollbar thumb drag
189
- */
190
- const handleThumbMouseDown = (e: MouseEvent): void => {
191
- e.preventDefault();
192
- e.stopPropagation();
193
-
194
- isDragging = true;
195
- dragStartY = e.clientY;
196
- dragStartScrollRatio = scrollRatio;
197
-
198
- document.addEventListener("mousemove", handleThumbDrag);
199
- document.addEventListener("mouseup", handleThumbMouseUp);
200
-
201
- // Add dragging state class
202
- addClass(scrollbarTrack, CLASSES.SCROLLBAR_DRAGGING);
203
- addClass(scrollbarThumb, CLASSES.SCROLLBAR_THUMB_DRAGGING);
204
- showScrollbar();
205
- };
206
-
207
- /**
208
- * Handle scrollbar thumb drag movement
209
- */
210
- const handleThumbDrag = (e: MouseEvent): void => {
211
- if (!isDragging) return;
212
-
213
- const deltaY = e.clientY - dragStartY;
214
- const trackHeight = scrollbarTrack.clientHeight;
215
- const thumbHeight = scrollbarThumb.clientHeight;
216
- const maxThumbTravel = trackHeight - thumbHeight;
217
-
218
- if (maxThumbTravel <= 0) return;
219
-
220
- const deltaRatio = deltaY / maxThumbTravel;
221
- const newScrollRatio = Math.max(
222
- 0,
223
- Math.min(1, dragStartScrollRatio + deltaRatio)
224
- );
225
-
226
- // Update position immediately (visual only)
227
- updateScrollbarPosition(newScrollRatio);
228
-
229
- // Calculate and emit the new scroll position
230
- const virtualScrollTop =
231
- getVirtualPositionFromScrollRatio(newScrollRatio);
232
-
233
- listManager.emit("viewport:changed", {
234
- scrollTop: virtualScrollTop,
235
- scrollRatio: newScrollRatio,
236
- source: "scrollbar-drag",
237
- });
238
- };
239
-
240
- /**
241
- * Handle scrollbar thumb drag end
242
- */
243
- const handleThumbMouseUp = (): void => {
244
- if (!isDragging) {
245
- return;
246
- }
247
-
248
- isDragging = false;
249
-
250
- document.removeEventListener("mousemove", handleThumbDrag);
251
- document.removeEventListener("mouseup", handleThumbMouseUp);
252
-
253
- // Remove dragging state classes
254
- removeClass(scrollbarTrack, CLASSES.SCROLLBAR_DRAGGING);
255
- removeClass(scrollbarThumb, CLASSES.SCROLLBAR_THUMB_DRAGGING);
256
- hideScrollbar();
257
-
258
- // Calculate the start index and virtual position
259
- let finalStartIndex: number;
260
- let finalVirtualScrollTop: number;
261
-
262
- // Check if we're using compressed virtual space
263
- const actualTotalSize =
264
- scrollbarConfig.totalItems * scrollbarConfig.itemHeight;
265
- const isCompressed =
266
- scrollbarConfig.totalVirtualSize &&
267
- actualTotalSize > scrollbarConfig.totalVirtualSize;
268
-
269
- if (
270
- isCompressed &&
271
- scrollbarConfig.totalVirtualSize &&
272
- scrollbarConfig.totalItems
273
- ) {
274
- // Compressed space: map ratio directly to item index
275
- // When ratio = 1, we want to show the last viewport of items
276
- const viewportItemCount = Math.floor(
277
- viewportHeight / scrollbarConfig.itemHeight
278
- );
279
- const maxStartIndex = Math.max(
280
- 0,
281
- scrollbarConfig.totalItems - viewportItemCount
282
- );
283
-
284
- // Ensure we reach the last items when scrollbar is at the bottom
285
- if (scrollRatio >= 0.999) {
286
- // Close enough to bottom, snap to last items
287
- finalStartIndex = maxStartIndex;
288
- finalVirtualScrollTop =
289
- scrollbarConfig.totalVirtualSize - viewportHeight;
290
- } else {
291
- finalStartIndex = Math.floor(scrollRatio * maxStartIndex);
292
- // Map the index back to virtual space using the same ratio
293
- const maxVirtualScroll = Math.max(
294
- 0,
295
- scrollbarConfig.totalVirtualSize - viewportHeight
296
- );
297
- finalVirtualScrollTop = scrollRatio * maxVirtualScroll;
298
- }
299
- } else {
300
- // Direct 1:1 mapping when not compressed
301
- finalVirtualScrollTop = getVirtualPositionFromScrollRatio(scrollRatio);
302
- finalStartIndex = Math.floor(
303
- finalVirtualScrollTop / scrollbarConfig.itemHeight
304
- );
305
- }
306
-
307
- listManager.emit("viewport:changed", {
308
- scrollTop: finalVirtualScrollTop,
309
- scrollRatio: scrollRatio,
310
- startIndex: finalStartIndex,
311
- source: "scrollbar",
312
- action: "drag-end", // Indicate this is the final position
313
- });
314
- };
315
-
316
- /**
317
- * Handle scrollbar track click
318
- */
319
- const handleTrackClick = (e: MouseEvent): void => {
320
- if (isDragging) return;
321
-
322
- const rect = scrollbarTrack.getBoundingClientRect();
323
- const clickY = e.clientY - rect.top;
324
- const trackHeight = scrollbarTrack.clientHeight;
325
- const thumbHeight = scrollbarThumb.clientHeight;
326
-
327
- // Calculate new scroll ratio based on click position
328
- const newScrollRatio = Math.max(
329
- 0,
330
- Math.min(1, (clickY - thumbHeight / 2) / (trackHeight - thumbHeight))
331
- );
332
-
333
- // Update position and emit event
334
- updateScrollbarPosition(newScrollRatio);
335
-
336
- const virtualScrollTop =
337
- getVirtualPositionFromScrollRatio(newScrollRatio);
338
-
339
- listManager.emit("viewport:changed", {
340
- scrollTop: virtualScrollTop,
341
- scrollRatio: newScrollRatio,
342
- source: "scrollbar",
343
- });
344
-
345
- showScrollbar();
346
- hideScrollbar();
347
- };
348
-
349
- // Listen for virtual viewport updates
350
- const unsubscribeScrollbar = listManager.subscribe((payload: any) => {
351
- if (payload.event === "virtual:range:changed") {
352
- if (
353
- payload.data?.action === "update-scrollbar" &&
354
- payload.data?.source === "virtual-viewport"
355
- ) {
356
- const { totalItems, itemHeight, totalVirtualSize } = payload.data;
357
-
358
- if (totalItems !== undefined) {
359
- scrollbarConfig.totalItems = totalItems;
360
- }
361
- if (itemHeight !== undefined) {
362
- scrollbarConfig.itemHeight = itemHeight;
363
- }
364
- if (totalVirtualSize !== undefined) {
365
- scrollbarConfig.totalVirtualSize = totalVirtualSize;
366
- }
367
-
368
- updateScrollbarDimensions();
369
- }
370
- }
371
-
372
- // Listen for wheel scroll events to update scrollbar position
373
- if (payload.event === "viewport:changed") {
374
- if (payload.data?.source === "wheel-scroll-scrollbar-update") {
375
- // Skip this update - scrollbar is already updated via updateScrollPosition
376
- return;
377
- }
378
- }
379
- });
380
-
381
- // Attach event listeners
382
- scrollbarThumb.addEventListener("mousedown", handleThumbMouseDown);
383
- scrollbarTrack.addEventListener("click", handleTrackClick);
384
-
385
- // Show/hide on hover (use listElement since scrollbar is inside it)
386
- listElement.addEventListener("mouseenter", showScrollbar);
387
- listElement.addEventListener("mouseleave", hideScrollbar);
388
-
389
- // Show during scrolling
390
- viewport.addEventListener("scroll", showScrollbar);
391
-
392
- // Return plugin API
393
- return {
394
- /**
395
- * Update total items count
396
- */
397
- setTotalItems(count: number): void {
398
- // 🚫 PREVENT INFINITE LOOP: Only update if count actually changed
399
-
400
- if (scrollbarConfig.totalItems === count) {
401
- return;
402
- }
403
-
404
- const previousCount = scrollbarConfig.totalItems;
405
- scrollbarConfig.totalItems = count;
406
- updateScrollbarDimensions();
407
- },
408
-
409
- /**
410
- * Update scroll position from external source
411
- */
412
- updateScrollPosition(virtualScrollTop: number): void {
413
- // 🚫 PREVENT INFINITE LOOP: Don't update scrollbar position during drag
414
- if (!isDragging) {
415
- const newScrollRatio =
416
- getScrollRatioFromVirtualPosition(virtualScrollTop);
417
- updateScrollbarPosition(newScrollRatio);
418
- }
419
- },
420
-
421
- /**
422
- * Update item height
423
- */
424
- setItemHeight(height: number): void {
425
- scrollbarConfig.itemHeight = height;
426
- updateScrollbarDimensions();
427
- },
428
-
429
- /**
430
- * Get current virtual scroll position
431
- */
432
- getVirtualScrollTop(): number {
433
- return getVirtualPositionFromScrollRatio(scrollRatio);
434
- },
435
-
436
- /**
437
- * Get current scroll ratio (0-1)
438
- */
439
- getScrollRatio(): number {
440
- return scrollRatio;
441
- },
442
-
443
- /**
444
- * Show scrollbar
445
- */
446
- show(): void {
447
- showScrollbar();
448
- },
449
-
450
- /**
451
- * Hide scrollbar
452
- */
453
- hide(): void {
454
- hideScrollbar();
455
- },
456
-
457
- /**
458
- * Update configuration
459
- */
460
- updateConfig(newConfig: Partial<ScrollbarConfig>): void {
461
- Object.assign(scrollbarConfig, newConfig);
462
- updateScrollbarDimensions();
463
- },
464
-
465
- /**
466
- * Destroy scrollbar
467
- */
468
- destroy(): void {
469
- if (scrollbarTrack.parentNode) {
470
- scrollbarTrack.parentNode.removeChild(scrollbarTrack);
471
- }
472
-
473
- // Remove scrollbar classes from viewport
474
- removeClass(viewport, CLASSES.SCROLLBAR_ENABLED);
475
-
476
- // Clean up event subscriptions
477
- unsubscribeScrollbar();
478
-
479
- // Clean up event listeners
480
- listElement.removeEventListener("mouseenter", showScrollbar);
481
- listElement.removeEventListener("mouseleave", hideScrollbar);
482
- viewport.removeEventListener("scroll", showScrollbar);
483
- scrollbarThumb.removeEventListener("mousedown", handleThumbMouseDown);
484
- scrollbarTrack.removeEventListener("click", handleTrackClick);
485
- document.removeEventListener("mousemove", handleThumbDrag);
486
- document.removeEventListener("mouseup", handleThumbMouseUp);
487
-
488
- // Clean up timeouts
489
- if (fadeTimeoutId) {
490
- clearTimeout(fadeTimeoutId);
491
- }
492
- },
493
- };
494
- },
495
- });