@floor/vlist 0.5.1

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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +839 -0
  3. package/dist/adapters/index.d.ts +20 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/react.d.ts +119 -0
  6. package/dist/adapters/react.d.ts.map +1 -0
  7. package/dist/adapters/svelte.d.ts +198 -0
  8. package/dist/adapters/svelte.d.ts.map +1 -0
  9. package/dist/adapters/vue.d.ts +151 -0
  10. package/dist/adapters/vue.d.ts.map +1 -0
  11. package/dist/builder/context.d.ts +36 -0
  12. package/dist/builder/context.d.ts.map +1 -0
  13. package/dist/builder/core.d.ts +16 -0
  14. package/dist/builder/core.d.ts.map +1 -0
  15. package/dist/builder/data.d.ts +71 -0
  16. package/dist/builder/data.d.ts.map +1 -0
  17. package/dist/builder/index.d.ts +25 -0
  18. package/dist/builder/index.d.ts.map +1 -0
  19. package/dist/builder/index.js +1 -0
  20. package/dist/builder/types.d.ts +269 -0
  21. package/dist/builder/types.d.ts.map +1 -0
  22. package/dist/compression/index.js +1 -0
  23. package/dist/constants.d.ts +65 -0
  24. package/dist/constants.d.ts.map +1 -0
  25. package/dist/core/index.js +1 -0
  26. package/dist/core-light.d.ts +104 -0
  27. package/dist/core-light.d.ts.map +1 -0
  28. package/dist/core-light.js +1 -0
  29. package/dist/core.d.ts +129 -0
  30. package/dist/core.d.ts.map +1 -0
  31. package/dist/data/index.js +1 -0
  32. package/dist/events/emitter.d.ts +20 -0
  33. package/dist/events/emitter.d.ts.map +1 -0
  34. package/dist/events/index.d.ts +6 -0
  35. package/dist/events/index.d.ts.map +1 -0
  36. package/dist/grid/index.js +1 -0
  37. package/dist/groups/index.js +1 -0
  38. package/dist/index.d.ts +17 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +1 -0
  41. package/dist/plugins/compression/index.d.ts +10 -0
  42. package/dist/plugins/compression/index.d.ts.map +1 -0
  43. package/dist/plugins/compression/plugin.d.ts +42 -0
  44. package/dist/plugins/compression/plugin.d.ts.map +1 -0
  45. package/dist/plugins/data/index.d.ts +9 -0
  46. package/dist/plugins/data/index.d.ts.map +1 -0
  47. package/dist/plugins/data/manager.d.ts +103 -0
  48. package/dist/plugins/data/manager.d.ts.map +1 -0
  49. package/dist/plugins/data/placeholder.d.ts +62 -0
  50. package/dist/plugins/data/placeholder.d.ts.map +1 -0
  51. package/dist/plugins/data/plugin.d.ts +60 -0
  52. package/dist/plugins/data/plugin.d.ts.map +1 -0
  53. package/dist/plugins/data/sparse.d.ts +91 -0
  54. package/dist/plugins/data/sparse.d.ts.map +1 -0
  55. package/dist/plugins/grid/index.d.ts +9 -0
  56. package/dist/plugins/grid/index.d.ts.map +1 -0
  57. package/dist/plugins/grid/layout.d.ts +29 -0
  58. package/dist/plugins/grid/layout.d.ts.map +1 -0
  59. package/dist/plugins/grid/plugin.d.ts +48 -0
  60. package/dist/plugins/grid/plugin.d.ts.map +1 -0
  61. package/dist/plugins/grid/renderer.d.ts +55 -0
  62. package/dist/plugins/grid/renderer.d.ts.map +1 -0
  63. package/dist/plugins/grid/types.d.ts +71 -0
  64. package/dist/plugins/grid/types.d.ts.map +1 -0
  65. package/dist/plugins/groups/index.d.ts +10 -0
  66. package/dist/plugins/groups/index.d.ts.map +1 -0
  67. package/dist/plugins/groups/layout.d.ts +46 -0
  68. package/dist/plugins/groups/layout.d.ts.map +1 -0
  69. package/dist/plugins/groups/plugin.d.ts +63 -0
  70. package/dist/plugins/groups/plugin.d.ts.map +1 -0
  71. package/dist/plugins/groups/sticky.d.ts +33 -0
  72. package/dist/plugins/groups/sticky.d.ts.map +1 -0
  73. package/dist/plugins/groups/types.d.ts +86 -0
  74. package/dist/plugins/groups/types.d.ts.map +1 -0
  75. package/dist/plugins/scroll/controller.d.ts +121 -0
  76. package/dist/plugins/scroll/controller.d.ts.map +1 -0
  77. package/dist/plugins/scroll/index.d.ts +8 -0
  78. package/dist/plugins/scroll/index.d.ts.map +1 -0
  79. package/dist/plugins/scroll/plugin.d.ts +60 -0
  80. package/dist/plugins/scroll/plugin.d.ts.map +1 -0
  81. package/dist/plugins/scroll/scrollbar.d.ts +73 -0
  82. package/dist/plugins/scroll/scrollbar.d.ts.map +1 -0
  83. package/dist/plugins/selection/index.d.ts +7 -0
  84. package/dist/plugins/selection/index.d.ts.map +1 -0
  85. package/dist/plugins/selection/plugin.d.ts +44 -0
  86. package/dist/plugins/selection/plugin.d.ts.map +1 -0
  87. package/dist/plugins/selection/state.d.ts +102 -0
  88. package/dist/plugins/selection/state.d.ts.map +1 -0
  89. package/dist/plugins/snapshots/index.d.ts +8 -0
  90. package/dist/plugins/snapshots/index.d.ts.map +1 -0
  91. package/dist/plugins/snapshots/plugin.d.ts +44 -0
  92. package/dist/plugins/snapshots/plugin.d.ts.map +1 -0
  93. package/dist/plugins/window/index.d.ts +8 -0
  94. package/dist/plugins/window/index.d.ts.map +1 -0
  95. package/dist/plugins/window/plugin.d.ts +53 -0
  96. package/dist/plugins/window/plugin.d.ts.map +1 -0
  97. package/dist/react/index.js +1 -0
  98. package/dist/render/compression.d.ts +116 -0
  99. package/dist/render/compression.d.ts.map +1 -0
  100. package/dist/render/heights.d.ts +63 -0
  101. package/dist/render/heights.d.ts.map +1 -0
  102. package/dist/render/index.d.ts +9 -0
  103. package/dist/render/index.d.ts.map +1 -0
  104. package/dist/render/renderer.d.ts +103 -0
  105. package/dist/render/renderer.d.ts.map +1 -0
  106. package/dist/render/virtual.d.ts +139 -0
  107. package/dist/render/virtual.d.ts.map +1 -0
  108. package/dist/scroll/index.js +1 -0
  109. package/dist/selection/index.js +1 -0
  110. package/dist/snapshots/index.js +1 -0
  111. package/dist/svelte/index.js +1 -0
  112. package/dist/types.d.ts +559 -0
  113. package/dist/types.d.ts.map +1 -0
  114. package/dist/vlist-extras.css +1 -0
  115. package/dist/vlist.css +1 -0
  116. package/dist/vlist.d.ts +22 -0
  117. package/dist/vlist.d.ts.map +1 -0
  118. package/dist/vue/index.js +1 -0
  119. package/dist/window/index.js +1 -0
  120. package/package.json +137 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * vlist/snapshots - Scroll Save/Restore
3
+ * Plugin for SPA navigation and tab switching
4
+ *
5
+ * Usage: import { withSnapshots } from 'vlist/snapshots'
6
+ */
7
+ export { withSnapshots } from "./plugin";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/snapshots/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * vlist/snapshots - Builder Plugin
3
+ * Adds scroll save/restore for SPA navigation and tab switching.
4
+ *
5
+ * Priority: 50 (runs last — needs all other plugins initialized)
6
+ *
7
+ * What it wires:
8
+ * - getScrollSnapshot() — captures current scroll position (item index + sub-pixel offset)
9
+ * - restoreScroll() — restores scroll position from snapshot
10
+ *
11
+ * Snapshots capture the first visible item index and the pixel offset within
12
+ * that item — not raw scrollTop. This means:
13
+ * - Snapshots survive list recreation (navigate away and back)
14
+ * - Snapshots work correctly with compression (1M+ items)
15
+ * - Snapshots include selection state if selection is installed
16
+ *
17
+ * Added methods: getScrollSnapshot, restoreScroll
18
+ */
19
+ import type { VListItem } from "../../types";
20
+ import type { VListPlugin } from "../../builder/types";
21
+ /**
22
+ * Create a snapshots plugin for the builder.
23
+ *
24
+ * Adds scroll save/restore for SPA navigation and tab switching.
25
+ *
26
+ * ```ts
27
+ * import { vlist } from 'vlist/builder'
28
+ * import { withSnapshots } from 'vlist/snapshots'
29
+ *
30
+ * const list = vlist({ ... })
31
+ * .use(withSnapshots())
32
+ * .build()
33
+ *
34
+ * // Save before navigating away
35
+ * const snapshot = list.getScrollSnapshot()
36
+ * sessionStorage.setItem('list-scroll', JSON.stringify(snapshot))
37
+ *
38
+ * // Restore when coming back
39
+ * const saved = JSON.parse(sessionStorage.getItem('list-scroll'))
40
+ * if (saved) list.restoreScroll(saved)
41
+ * ```
42
+ */
43
+ export declare const withSnapshots: <T extends VListItem = VListItem>() => VListPlugin<T>;
44
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/snapshots/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAUvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,OAAK,WAAW,CAAC,CAAC,CA4G9E,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * vlist/window - Window Scroll Mode Plugin
3
+ *
4
+ * Entry point for the window scroll plugin.
5
+ */
6
+ export { withWindow } from "./plugin";
7
+ export type { VListPlugin } from "../../builder/types";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/window/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * vlist/window - Window Scroll Mode Plugin
3
+ *
4
+ * Enables the list to scroll with the page instead of in its own container.
5
+ * Useful for infinite feeds, full-page lists, and chat UIs that integrate
6
+ * with page scroll.
7
+ *
8
+ * Priority: 5 (runs early, before other plugins that depend on scroll)
9
+ *
10
+ * What it does:
11
+ * - Uses window as scroll target instead of viewport element
12
+ * - Calculates scroll position relative to document
13
+ * - Uses window.innerWidth/innerHeight for container dimensions
14
+ * - Listens to window resize events instead of ResizeObserver
15
+ * - Adjusts DOM styles (overflow: visible, height: auto)
16
+ *
17
+ * Bundle impact: ~0.3 KB gzipped when used
18
+ */
19
+ import type { VListItem } from "../../types";
20
+ import type { VListPlugin } from "../../builder/types";
21
+ /**
22
+ * Create a window scroll mode plugin.
23
+ *
24
+ * Use this when you want your list to scroll with the page instead of
25
+ * in a fixed-height container.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { vlist } from 'vlist/builder'
30
+ * import { withWindow } from 'vlist/window'
31
+ *
32
+ * const feed = vlist({
33
+ * container: '#infinite-feed',
34
+ * item: { height: 200, template: renderPost },
35
+ * items: posts
36
+ * })
37
+ * .use(withWindow())
38
+ * .build()
39
+ * ```
40
+ *
41
+ * @example Horizontal window scrolling
42
+ * ```ts
43
+ * const timeline = vlist({
44
+ * container: '#timeline',
45
+ * item: { height: 100, template: renderEvent },
46
+ * direction: 'horizontal'
47
+ * })
48
+ * .use(withWindow())
49
+ * .build()
50
+ * ```
51
+ */
52
+ export declare const withWindow: <T extends VListItem = VListItem>() => VListPlugin<T>;
53
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/window/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,UAAU,GACrB,CAAC,SAAS,SAAS,GAAG,SAAS,OAC5B,WAAW,CAAC,CAAC,CA+HjB,CAAC"}
@@ -0,0 +1 @@
1
+ import{useRef as D,useEffect as K,useCallback as M}from"react";import{createVList as N}from"vlist";function Q(q){let A=D(null),j=D(null),B=D(q);B.current=q;let z=D(!1);K(()=>{let J=A.current;if(!J)return;let F=N({...B.current,container:J});return j.current=F,z.current=!0,()=>{z.current=!1,F.destroy(),j.current=null}},[]),K(()=>{if(!z.current||!j.current)return;if(q.items)j.current.setItems(q.items)},[q.items]);let G=M(()=>{return j.current},[]);return{containerRef:A,instanceRef:j,getInstance:G}}function S(q,A,j){let B=D(j);B.current=j,K(()=>{let z=q.current;if(!z)return;let G=(F)=>{B.current(F)};return z.on(A,G)},[q.current,A])}export{S as useVListEvent,Q as useVList};
@@ -0,0 +1,116 @@
1
+ /**
2
+ * vlist - Compression Module
3
+ * Pure functions for handling large lists that exceed browser height limits
4
+ *
5
+ * When a list's total height (totalItems × itemHeight) exceeds the browser's
6
+ * maximum element height (~16.7M pixels), we "compress" the virtual scroll space.
7
+ *
8
+ * Key concepts:
9
+ * - actualHeight: The true height if all items were rendered
10
+ * - virtualHeight: The capped height used for the scroll container (≤ MAX_VIRTUAL_HEIGHT)
11
+ * - compressionRatio: virtualHeight / actualHeight (1 = no compression, <1 = compressed)
12
+ *
13
+ * When compressed:
14
+ * - Scroll position maps to item index via ratio, not pixel math
15
+ * - Item positions are calculated relative to a "virtual index" at current scroll
16
+ * - Near-bottom interpolation ensures the last items are reachable
17
+ */
18
+ import type { Range } from "../types";
19
+ import { MAX_VIRTUAL_HEIGHT } from "../constants";
20
+ import type { HeightCache } from "./heights";
21
+ export { MAX_VIRTUAL_HEIGHT };
22
+ /** Compression calculation result */
23
+ export interface CompressionState {
24
+ /** Whether compression is active */
25
+ isCompressed: boolean;
26
+ /** The actual total height */
27
+ actualHeight: number;
28
+ /** The virtual height (capped at MAX_VIRTUAL_HEIGHT) */
29
+ virtualHeight: number;
30
+ /** Compression ratio (1 = no compression, <1 = compressed) */
31
+ ratio: number;
32
+ }
33
+ /**
34
+ * Calculate compression state for a list
35
+ * Pure function - no side effects
36
+ */
37
+ export declare const getCompressionState: (_totalItems: number, heightCache: HeightCache) => CompressionState;
38
+ /**
39
+ * Calculate visible range with compression support
40
+ * Pure function - no side effects
41
+ *
42
+ * @param scrollTop - Current scroll position
43
+ * @param containerHeight - Viewport container height
44
+ * @param heightCache - Height cache for item heights/offsets
45
+ * @param totalItems - Total number of items
46
+ * @param compression - Compression state
47
+ * @param out - Output range to mutate (avoids allocation on hot path)
48
+ */
49
+ export declare const calculateCompressedVisibleRange: (scrollTop: number, containerHeight: number, heightCache: HeightCache, totalItems: number, compression: CompressionState, out: Range) => Range;
50
+ /**
51
+ * Calculate render range with compression support (adds overscan)
52
+ * Pure function - no side effects
53
+ *
54
+ * @param out - Output range to mutate (avoids allocation on hot path)
55
+ */
56
+ export declare const calculateCompressedRenderRange: (visibleRange: Range, overscan: number, totalItems: number, out: Range) => Range;
57
+ /**
58
+ * Calculate item position (translateY) with compression support
59
+ * Pure function - no side effects
60
+ *
61
+ * In compressed mode (manual wheel scrolling, overflow: hidden), items are
62
+ * positioned RELATIVE TO THE VIEWPORT. The scroll container doesn't actually
63
+ * scroll - we intercept wheel events and manually position items.
64
+ *
65
+ * Key insight:
66
+ * - Calculate a "virtual scroll index" from the scroll ratio
67
+ * - Items are positioned relative to this virtual index using actual heights
68
+ * - Each item keeps its full height for proper rendering
69
+ *
70
+ * @param index - Item index
71
+ * @param scrollTop - Current (virtual) scroll position
72
+ * @param heightCache - Height cache for item heights/offsets
73
+ * @param totalItems - Total number of items
74
+ * @param containerHeight - Viewport container height
75
+ * @param compression - Compression state
76
+ * @param _rangeStart - (unused, kept for API compatibility)
77
+ */
78
+ export declare const calculateCompressedItemPosition: (index: number, scrollTop: number, heightCache: HeightCache, totalItems: number, containerHeight: number, compression: CompressionState, _rangeStart?: number) => number;
79
+ /**
80
+ * Calculate scroll position to bring an index into view (with compression)
81
+ * Pure function - no side effects
82
+ *
83
+ * @param index - Target item index
84
+ * @param heightCache - Height cache for item heights/offsets
85
+ * @param containerHeight - Viewport container height
86
+ * @param totalItems - Total number of items
87
+ * @param compression - Compression state
88
+ * @param align - Alignment within viewport
89
+ */
90
+ export declare const calculateCompressedScrollToIndex: (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, compression: CompressionState, align?: "start" | "center" | "end") => number;
91
+ /**
92
+ * Calculate the approximate item index at a given scroll position
93
+ * Useful for debugging and scroll position restoration
94
+ * Pure function - no side effects
95
+ */
96
+ export declare const calculateIndexFromScrollPosition: (scrollTop: number, heightCache: HeightCache, totalItems: number, compression: CompressionState) => number;
97
+ /**
98
+ * Check if compression is needed for a list configuration
99
+ * Pure function - no side effects
100
+ *
101
+ * Note: This overload accepts a HeightCache for variable heights.
102
+ * For simple fixed-height checks, use needsCompressionFixed().
103
+ */
104
+ export declare const needsCompression: (totalItems: number, heightOrCache: number | HeightCache) => boolean;
105
+ /**
106
+ * Calculate maximum items supported without compression
107
+ * Only meaningful for fixed-height items
108
+ * Pure function - no side effects
109
+ */
110
+ export declare const getMaxItemsWithoutCompression: (itemHeight: number) => number;
111
+ /**
112
+ * Get human-readable compression info for debugging
113
+ * Pure function - no side effects
114
+ */
115
+ export declare const getCompressionInfo: (totalItems: number, heightCache: HeightCache) => string;
116
+ //# sourceMappingURL=compression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../src/render/compression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAQ7C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAM9B,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,YAAY,EAAE,OAAO,CAAC;IAEtB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IAEtB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,aAAa,WAAW,KACvB,gBAYF,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,+BAA+B,GAC1C,WAAW,MAAM,EACjB,iBAAiB,MAAM,EACvB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,aAAa,gBAAgB,EAC7B,KAAK,KAAK,KACT,KAmEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GACzC,cAAc,KAAK,EACnB,UAAU,MAAM,EAChB,YAAY,MAAM,EAClB,KAAK,KAAK,KACT,KAUF,CAAC;AAMF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,+BAA+B,GAC1C,OAAO,MAAM,EACb,WAAW,MAAM,EACjB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,iBAAiB,MAAM,EACvB,aAAa,gBAAgB,EAC7B,cAAc,MAAM,KACnB,MAyDF,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC3C,OAAO,MAAM,EACb,aAAa,WAAW,EACxB,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,aAAa,gBAAgB,EAC7B,QAAO,OAAO,GAAG,QAAQ,GAAG,KAAe,KAC1C,MAmCF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,GAC3C,WAAW,MAAM,EACjB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,aAAa,gBAAgB,KAC5B,MASF,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,eAAe,MAAM,GAAG,WAAW,KAClC,OAKF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,YAAY,MAAM,KAAG,MAGlE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,aAAa,WAAW,KACvB,MASF,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * vlist - Height Cache
3
+ * Efficient height management for fixed and variable item heights
4
+ *
5
+ * Provides two implementations:
6
+ * - Fixed: O(1) operations using multiplication (zero overhead, matches existing behavior)
7
+ * - Variable: O(1) offset lookup via prefix sums, O(log n) binary search for index-at-offset
8
+ *
9
+ * The HeightCache abstraction allows all virtual scrolling and compression code
10
+ * to work identically with both fixed and variable heights.
11
+ */
12
+ /** Height cache for efficient offset/index lookups */
13
+ export interface HeightCache {
14
+ /** Get offset (Y position) for an item index — O(1) */
15
+ getOffset(index: number): number;
16
+ /** Get height of a specific item */
17
+ getHeight(index: number): number;
18
+ /** Find item index at a scroll offset — O(1) fixed, O(log n) variable */
19
+ indexAtOffset(offset: number): number;
20
+ /** Total content height */
21
+ getTotalHeight(): number;
22
+ /** Current total item count */
23
+ getTotal(): number;
24
+ /** Rebuild cache (call when items change) */
25
+ rebuild(totalItems: number): void;
26
+ /** Whether heights are variable (false = fixed fast path) */
27
+ isVariable(): boolean;
28
+ }
29
+ /**
30
+ * Create a height cache — returns fixed or variable implementation
31
+ *
32
+ * When height is a number, returns a zero-overhead fixed implementation.
33
+ * When height is a function, builds a prefix-sum array for efficient lookups.
34
+ */
35
+ export declare const createHeightCache: (height: number | ((index: number) => number), initialTotal: number) => HeightCache;
36
+ /**
37
+ * Count how many items fit in a given container height starting from startIndex
38
+ * Used for compressed mode visible range calculations
39
+ *
40
+ * For fixed heights: O(1) via division
41
+ * For variable heights: O(k) where k = visible item count (typically 10-50)
42
+ */
43
+ export declare const countVisibleItems: (heightCache: HeightCache, startIndex: number, containerHeight: number, totalItems: number) => number;
44
+ /**
45
+ * Count how many items fit starting from the bottom of the list
46
+ * Used for near-bottom interpolation in compressed mode
47
+ *
48
+ * For fixed heights: O(1) via division
49
+ * For variable heights: O(k) where k = items fitting (typically 10-50)
50
+ */
51
+ export declare const countItemsFittingFromBottom: (heightCache: HeightCache, containerHeight: number, totalItems: number) => number;
52
+ /**
53
+ * Calculate the pixel offset for a fractional virtual scroll index
54
+ *
55
+ * In compressed mode, the scroll position maps to a fractional item index
56
+ * (e.g., 5.3 means 30% into item 5). This function calculates the actual
57
+ * pixel offset for such a fractional position using variable heights.
58
+ *
59
+ * For fixed heights this reduces to: virtualIndex * itemHeight
60
+ * For variable heights: offset(floor) + frac * height(floor)
61
+ */
62
+ export declare const getOffsetForVirtualIndex: (heightCache: HeightCache, virtualIndex: number, totalItems: number) => number;
63
+ //# sourceMappingURL=heights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heights.d.ts","sourceRoot":"","sources":["../../src/render/heights.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEjC,oCAAoC;IACpC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEjC,yEAAyE;IACzE,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtC,2BAA2B;IAC3B,cAAc,IAAI,MAAM,CAAC;IAEzB,+BAA+B;IAC/B,QAAQ,IAAI,MAAM,CAAC;IAEnB,6CAA6C;IAC7C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,6DAA6D;IAC7D,UAAU,IAAI,OAAO,CAAC;CACvB;AAiID;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,EAC5C,cAAc,MAAM,KACnB,WAKF,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,iBAAiB,MAAM,EACvB,YAAY,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,aAAa,WAAW,EACxB,iBAAiB,MAAM,EACvB,YAAY,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACnC,aAAa,WAAW,EACxB,cAAc,MAAM,EACpB,YAAY,MAAM,KACjB,MAUF,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * vlist - Render Domain
3
+ * Rendering, virtualization, and compression
4
+ */
5
+ export { createHeightCache, countVisibleItems, countItemsFittingFromBottom, getOffsetForVirtualIndex, type HeightCache, } from "./heights";
6
+ export { createRenderer, createDOMStructure, updateContentHeight, updateContentWidth, resolveContainer, getContainerDimensions, type Renderer, type DOMStructure, type CompressionContext, type CompressedPositionFn, type CompressionStateFn, } from "./renderer";
7
+ export { createViewportState, updateViewportState, updateViewportSize, updateViewportItems, calculateRenderRange, calculateTotalHeight, calculateActualHeight, calculateItemOffset, calculateScrollToIndex, clampScrollPosition, getScrollDirection, rangesEqual, isInRange, getRangeCount, diffRanges, getSimpleCompressionState, simpleVisibleRange, simpleScrollToIndex, NO_COMPRESSION, type CompressionState, type VisibleRangeFn, type ScrollToIndexFn, } from "./virtual";
8
+ export { MAX_VIRTUAL_HEIGHT, getCompressionState, getCompressionState as getCompression, needsCompression, getMaxItemsWithoutCompression, getCompressionInfo, calculateCompressedVisibleRange, calculateCompressedRenderRange, calculateCompressedItemPosition, calculateCompressedScrollToIndex, calculateIndexFromScrollPosition, } from "./compression";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,2BAA2B,EAC3B,wBAAwB,EACxB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,aAAa,EACb,UAAU,EACV,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,IAAI,cAAc,EACrC,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC9B,+BAA+B,EAC/B,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,eAAe,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * vlist - DOM Rendering
3
+ * Efficient DOM rendering with element pooling
4
+ * Supports compression for large lists (1M+ items)
5
+ */
6
+ import type { VListItem, ItemTemplate, Range } from "../types";
7
+ import type { CompressionState } from "./virtual";
8
+ import type { HeightCache } from "./heights";
9
+ /**
10
+ * Optional compression position calculator.
11
+ * Injected by the monolithic factory or the withCompression plugin.
12
+ * When not provided, the renderer uses simple heightCache offsets.
13
+ */
14
+ export type CompressedPositionFn = (index: number, scrollTop: number, heightCache: HeightCache, totalItems: number, containerHeight: number, compression: CompressionState, rangeStart?: number) => number;
15
+ /**
16
+ * Optional compression state getter.
17
+ * Injected by the monolithic factory or the withCompression plugin.
18
+ * When not provided, the renderer assumes no compression.
19
+ */
20
+ export type CompressionStateFn = (totalItems: number, heightCache: HeightCache) => CompressionState;
21
+ /** Element pool for recycling DOM elements */
22
+ export interface ElementPool {
23
+ /** Get an element from the pool (or create new) */
24
+ acquire: () => HTMLElement;
25
+ /** Return an element to the pool */
26
+ release: (element: HTMLElement) => void;
27
+ /** Clear the pool */
28
+ clear: () => void;
29
+ /** Get pool statistics */
30
+ stats: () => {
31
+ poolSize: number;
32
+ created: number;
33
+ reused: number;
34
+ };
35
+ }
36
+ /** Compression context for positioning */
37
+ export interface CompressionContext {
38
+ scrollTop: number;
39
+ totalItems: number;
40
+ containerHeight: number;
41
+ rangeStart: number;
42
+ }
43
+ /** DOM structure created by createDOMStructure */
44
+ export interface DOMStructure {
45
+ root: HTMLElement;
46
+ viewport: HTMLElement;
47
+ content: HTMLElement;
48
+ items: HTMLElement;
49
+ }
50
+ /** Renderer instance */
51
+ export interface Renderer<T extends VListItem = VListItem> {
52
+ /** Render items for a range */
53
+ render: (items: T[], range: Range, selectedIds: Set<string | number>, focusedIndex: number, compressionCtx?: CompressionContext) => void;
54
+ /** Update item positions (for compressed scrolling) */
55
+ updatePositions: (compressionCtx: CompressionContext) => void;
56
+ /** Update a single item */
57
+ updateItem: (index: number, item: T, isSelected: boolean, isFocused: boolean) => void;
58
+ /** Update only CSS classes on a rendered item (no template re-evaluation) */
59
+ updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
60
+ /** Get rendered item element by index */
61
+ getElement: (index: number) => HTMLElement | undefined;
62
+ /** Clear all rendered items */
63
+ clear: () => void;
64
+ /** Destroy renderer and cleanup */
65
+ destroy: () => void;
66
+ }
67
+ /**
68
+ * Create an element pool for recycling DOM elements
69
+ * Reduces garbage collection and improves performance
70
+ */
71
+ export declare const createElementPool: (tagName?: string, maxSize?: number) => ElementPool;
72
+ /**
73
+ * Create a renderer for managing DOM elements
74
+ * Supports compression for large lists
75
+ */
76
+ export declare const createRenderer: <T extends VListItem = VListItem>(itemsContainer: HTMLElement, template: ItemTemplate<T>, heightCache: HeightCache, classPrefix: string, totalItemsGetter?: () => number, ariaIdPrefix?: string, horizontal?: boolean, crossAxisSize?: number, compressionFns?: {
77
+ getState: CompressionStateFn;
78
+ getPosition: CompressedPositionFn;
79
+ }) => Renderer<T>;
80
+ /**
81
+ * Create the vlist DOM structure
82
+ */
83
+ export declare const createDOMStructure: (container: HTMLElement, classPrefix: string, ariaLabel?: string, horizontal?: boolean) => DOMStructure;
84
+ /**
85
+ * Update content height for virtual scrolling
86
+ */
87
+ export declare const updateContentHeight: (content: HTMLElement, totalHeight: number) => void;
88
+ /**
89
+ * Update content width for horizontal virtual scrolling
90
+ */
91
+ export declare const updateContentWidth: (content: HTMLElement, totalWidth: number) => void;
92
+ /**
93
+ * Get container dimensions
94
+ */
95
+ export declare const getContainerDimensions: (viewport: HTMLElement) => {
96
+ width: number;
97
+ height: number;
98
+ };
99
+ /**
100
+ * Resolve container from selector or element
101
+ */
102
+ export declare const resolveContainer: (container: HTMLElement | string) => HTMLElement;
103
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EAEZ,KAAK,EAEN,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,gBAAgB,EAC7B,UAAU,CAAC,EAAE,MAAM,KAChB,MAAM,CAAC;AAEZ;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,WAAW,KACrB,gBAAgB,CAAC;AAMtB,8CAA8C;AAC9C,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,OAAO,EAAE,MAAM,WAAW,CAAC;IAE3B,oCAAoC;IACpC,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAExC,qBAAqB;IACrB,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,0BAA0B;IAC1B,KAAK,EAAE,MAAM;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACpE;AAED,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,WAAW,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED,wBAAwB;AACxB,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IACvD,+BAA+B;IAC/B,MAAM,EAAE,CACN,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EACjC,YAAY,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,kBAAkB,KAChC,IAAI,CAAC;IAEV,uDAAuD;IACvD,eAAe,EAAE,CAAC,cAAc,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAE9D,2BAA2B;IAC3B,UAAU,EAAE,CACV,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,EACP,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,KACf,IAAI,CAAC;IAEV,6EAA6E;IAC7E,iBAAiB,EAAE,CACjB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,KACf,IAAI,CAAC;IAEV,yCAAyC;IACzC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IAEvD,+BAA+B;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,mCAAmC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAMD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAS,MAAc,EACvB,UAAS,MAAY,KACpB,WA4CF,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAC5D,gBAAgB,WAAW,EAC3B,UAAU,YAAY,CAAC,CAAC,CAAC,EACzB,aAAa,WAAW,EACxB,aAAa,MAAM,EACnB,mBAAmB,MAAM,MAAM,EAC/B,eAAe,MAAM,EACrB,aAAa,OAAO,EACpB,gBAAgB,MAAM,EACtB,iBAAiB;IACf,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,WAAW,EAAE,oBAAoB,CAAC;CACnC,KACA,QAAQ,CAAC,CAAC,CA4XZ,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,WAAW,WAAW,EACtB,aAAa,MAAM,EACnB,YAAY,MAAM,EAClB,aAAa,OAAO,KACnB,YA4DF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,EACpB,aAAa,MAAM,KAClB,IAEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,WAAW,EACpB,YAAY,MAAM,KACjB,IAEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAU,WAAW,KACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAGhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,WAAW,GAAG,MAAM,KAC9B,WASF,CAAC"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * vlist - Virtual Scrolling Core
3
+ * Pure functions for virtual scroll calculations
4
+ *
5
+ * Compression support is NOT imported here — it's injected via
6
+ * CompressionState parameters. When compression is inactive
7
+ * (the common case), all calculations use simple height-cache math
8
+ * with zero dependency on the compression module.
9
+ *
10
+ * This keeps the builder core lightweight. The withCompression plugin
11
+ * and the monolithic createVList entry point import compression
12
+ * separately and pass the state in.
13
+ */
14
+ import type { Range, ViewportState } from "../types";
15
+ import type { HeightCache } from "./heights";
16
+ /** Compression calculation result */
17
+ export interface CompressionState {
18
+ /** Whether compression is active */
19
+ isCompressed: boolean;
20
+ /** The actual total height */
21
+ actualHeight: number;
22
+ /** The virtual height (capped at MAX_VIRTUAL_HEIGHT) */
23
+ virtualHeight: number;
24
+ /** Compression ratio (1 = no compression, <1 = compressed) */
25
+ ratio: number;
26
+ }
27
+ /**
28
+ * A "no compression" state for lists that don't need it.
29
+ * Used by the builder core when withCompression is not installed.
30
+ */
31
+ export declare const NO_COMPRESSION: CompressionState;
32
+ /**
33
+ * Create a trivial compression state from a height cache.
34
+ * No compression logic — just reads the total height.
35
+ * For use when the full compression module is not loaded.
36
+ */
37
+ export declare const getSimpleCompressionState: (_totalItems: number, heightCache: HeightCache) => CompressionState;
38
+ /**
39
+ * Signature for the function that calculates the visible item range.
40
+ * The compression module provides a version that handles compressed scroll;
41
+ * virtual.ts provides a simple fallback for non-compressed lists.
42
+ */
43
+ export type VisibleRangeFn = (scrollTop: number, containerHeight: number, heightCache: HeightCache, totalItems: number, compression: CompressionState, out: Range) => Range;
44
+ /**
45
+ * Signature for the scroll-to-index calculator.
46
+ */
47
+ export type ScrollToIndexFn = (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, compression: CompressionState, align: "start" | "center" | "end") => number;
48
+ /**
49
+ * Calculate visible range using height cache lookups.
50
+ * Fast path for lists that don't need compression (< ~350 000 items at 48px).
51
+ * Mutates `out` to avoid allocation on the scroll hot path.
52
+ */
53
+ export declare const simpleVisibleRange: VisibleRangeFn;
54
+ /**
55
+ * Calculate render range (adds overscan around visible range).
56
+ * This function is compression-agnostic — works for both paths.
57
+ * Mutates `out` to avoid allocation on the scroll hot path.
58
+ */
59
+ export declare const calculateRenderRange: (visibleRange: Range, overscan: number, totalItems: number, out: Range) => Range;
60
+ /**
61
+ * Simple scroll-to-index calculation (non-compressed).
62
+ * Uses height cache offsets directly.
63
+ */
64
+ export declare const simpleScrollToIndex: ScrollToIndexFn;
65
+ /**
66
+ * Calculate total content height.
67
+ * Uses compression's virtualHeight when compressed, raw height otherwise.
68
+ */
69
+ export declare const calculateTotalHeight: (_totalItems: number, heightCache: HeightCache, compression?: CompressionState | null) => number;
70
+ /**
71
+ * Calculate actual total height (without compression cap)
72
+ */
73
+ export declare const calculateActualHeight: (_totalItems: number, heightCache: HeightCache) => number;
74
+ /**
75
+ * Calculate the offset (translateY) for an item
76
+ * For non-compressed lists only
77
+ */
78
+ export declare const calculateItemOffset: (index: number, heightCache: HeightCache) => number;
79
+ /**
80
+ * Clamp scroll position to valid range
81
+ */
82
+ export declare const clampScrollPosition: (scrollTop: number, totalHeight: number, containerHeight: number) => number;
83
+ /**
84
+ * Determine scroll direction
85
+ */
86
+ export declare const getScrollDirection: (currentScrollTop: number, previousScrollTop: number) => "up" | "down";
87
+ /**
88
+ * Create initial viewport state.
89
+ *
90
+ * Accepts an optional `visibleRangeFn` so that compression-aware callers
91
+ * can inject the compressed version. Defaults to `simpleVisibleRange`.
92
+ */
93
+ export declare const createViewportState: (containerHeight: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
94
+ /**
95
+ * Update viewport state after scroll.
96
+ * Mutates state in place for performance on the scroll hot path.
97
+ */
98
+ export declare const updateViewportState: (state: ViewportState, scrollTop: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
99
+ /**
100
+ * Update viewport state when container resizes.
101
+ * Mutates state in place for performance.
102
+ */
103
+ export declare const updateViewportSize: (state: ViewportState, containerHeight: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
104
+ /**
105
+ * Update viewport state when total items changes.
106
+ * Mutates state in place for performance.
107
+ */
108
+ export declare const updateViewportItems: (state: ViewportState, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
109
+ /**
110
+ * Calculate scroll position to bring an index into view.
111
+ *
112
+ * Accepts an optional `scrollToIndexFn` so that compression-aware callers
113
+ * can inject the compressed version. Defaults to `simpleScrollToIndex`.
114
+ */
115
+ export declare const calculateScrollToIndex: (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, align: "start" | "center" | "end" | undefined, compression: CompressionState, scrollToIndexFn?: ScrollToIndexFn) => number;
116
+ /**
117
+ * Check if two ranges are equal
118
+ */
119
+ export declare const rangesEqual: (a: Range, b: Range) => boolean;
120
+ /**
121
+ * Check if an index is within a range
122
+ */
123
+ export declare const isInRange: (index: number, range: Range) => boolean;
124
+ /**
125
+ * Get the count of items in a range
126
+ */
127
+ export declare const getRangeCount: (range: Range) => number;
128
+ /**
129
+ * Create an array of indices from a range
130
+ */
131
+ export declare const rangeToIndices: (range: Range) => number[];
132
+ /**
133
+ * Calculate which indices need to be added/removed when range changes
134
+ */
135
+ export declare const diffRanges: (oldRange: Range, newRange: Range) => {
136
+ add: number[];
137
+ remove: number[];
138
+ };
139
+ //# sourceMappingURL=virtual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["../../src/render/virtual.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ var Gj=(j,J,G={},_="vlist",F=!1)=>{let{autoHide:E=!0,autoHideDelay:D=1000,minThumbSize:H=30,showOnHover:V=!0,hoverZoneWidth:X=16,showOnViewportEnter:Z=!0}=G,Q=0,U=0,W=0,N=0,O=!1,q=!1,y=0,f=0,h=0,I=null,p=!1,R=null,M=null,S=F?"width":"height",x=F?"translateX":"translateY",b=F?(B)=>B.clientX:(B)=>B.clientY,t=F?"left":"top",L=document.createElement("div"),C=document.createElement("div"),A=V?document.createElement("div"):null,i=()=>{if(L.className=`${_}-scrollbar`,C.className=`${_}-scrollbar-thumb`,F)L.classList.add(`${_}-scrollbar--horizontal`);if(L.appendChild(C),j.appendChild(L),A){if(A.className=`${_}-scrollbar-hover`,F)A.classList.add(`${_}-scrollbar-hover--horizontal`),A.style.height=`${X}px`;else A.style.width=`${X}px`;j.appendChild(A)}},T=()=>{if(I)clearTimeout(I),I=null},P=()=>{if(!E)return;T(),I=setTimeout(d,D)},k=()=>{if(Q<=U)return;if(T(),!p)L.classList.add(`${_}-scrollbar--visible`),p=!0;if(E&&!O&&!q)P()},d=()=>{if(O||q)return;L.classList.remove(`${_}-scrollbar--visible`),p=!1},r=(B,g)=>{Q=B,U=g;let m=Q>U;if(L.style.display=m?"":"none",!m){d();return}let z=U/Q;W=Math.max(H,z*U),C.style[S]=`${W}px`,N=U-W,s(h)},s=(B)=>{if(h=B,Q<=U||N<=0)return;let g=Q-U,z=Math.min(1,Math.max(0,B/g))*N;C.style.transform=`${x}(${z}px)`},c=(B)=>{if(B.target===C)return;let g=L.getBoundingClientRect(),o=b(B)-g[t]-W/2,Kj=Math.max(0,Math.min(o,N))/N,jj=Q-U,Xj=Kj*jj;J(Xj),k()},n=(B)=>{B.preventDefault(),B.stopPropagation(),O=!0,y=b(B),f=h,T(),L.classList.add(`${_}-scrollbar--dragging`),document.addEventListener("mousemove",w),document.addEventListener("mouseup",v)},w=(B)=>{if(!O)return;let g=b(B)-y,m=N>0?g/N:0,z=Q-U,o=m*z,e=Math.max(0,Math.min(f+o,z)),jj=e/z*N;if(C.style.transform=`${x}(${jj}px)`,M=e,R===null)R=requestAnimationFrame(()=>{if(M!==null)J(M);R=null})},v=()=>{if(O=!1,R!==null)cancelAnimationFrame(R),R=null;if(M!==null)J(M),M=null;if(L.classList.remove(`${_}-scrollbar--dragging`),E&&!q)P();document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",v)},a=()=>{if(Z)k()},K=()=>{if(!O){if(q=!1,E)P()}},Y=()=>{q=!0,T(),k()},$=()=>{if(q=!1,!O&&E)P()},u=()=>{if(T(),R!==null)cancelAnimationFrame(R),R=null;if(L.removeEventListener("click",c),L.removeEventListener("mouseenter",Y),L.removeEventListener("mouseleave",$),C.removeEventListener("mousedown",n),j.removeEventListener("mouseenter",a),j.removeEventListener("mouseleave",K),document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",v),A){if(A.removeEventListener("mouseenter",Y),A.removeEventListener("mouseleave",$),A.parentNode)A.parentNode.removeChild(A)}if(L.parentNode)L.parentNode.removeChild(L)};if(i(),L.addEventListener("click",c),L.addEventListener("mouseenter",Y),L.addEventListener("mouseleave",$),C.addEventListener("mousedown",n),j.addEventListener("mouseenter",a),j.addEventListener("mouseleave",K),A)A.addEventListener("mouseenter",Y),A.addEventListener("mouseleave",$);return{show:k,hide:d,updateBounds:r,updatePosition:s,isVisible:()=>p,destroy:u}};var Yj=(j)=>{let J=null;return{name:"withScrollbar",priority:30,setup(G){let{dom:_,config:F}=G,{classPrefix:E,horizontal:D}=F;if(J=Gj(_.viewport,(X)=>G.scrollController.scrollTo(X),j??{},E,D),!_.viewport.classList.contains(`${E}-viewport--custom-scrollbar`))_.viewport.classList.add(`${E}-viewport--custom-scrollbar`);let H=G.getCachedCompression();J.updateBounds(H.virtualHeight,G.state.viewportState.containerHeight);let V=J;G.afterScroll.push((X,Z)=>{V.updatePosition(X),V.show()}),G.resizeHandlers.push((X,Z)=>{if(V){let Q=G.getCachedCompression();V.updateBounds(Q.virtualHeight,G.state.viewportState.containerHeight)}}),G.contentSizeHandlers.push(()=>{if(V){let X=G.getCachedCompression();V.updateBounds(X.virtualHeight,G.state.viewportState.containerHeight)}}),G.destroyHandlers.push(()=>{if(V)V.destroy()})},destroy(){if(J)J.destroy(),J=null}}};var Qj=(j=0)=>{let J=[,,,,,,,,];for(let G=0;G<8;G++)J[G]={position:0,time:0};return{velocity:0,lastPosition:j,lastTime:performance.now(),samples:J,sampleIndex:0,sampleCount:0}},l=(j,J)=>{let G=performance.now(),_=G-j.lastTime;if(_===0)return j;if(_>100){j.sampleCount=0,j.sampleIndex=0,j.velocity=0;let E=j.samples[0];return E.position=J,E.time=G,j.sampleIndex=1,j.sampleCount=1,j.lastPosition=J,j.lastTime=G,j}let F=j.samples[j.sampleIndex];if(F.position=J,F.time=G,j.sampleIndex=(j.sampleIndex+1)%8,j.sampleCount=Math.min(j.sampleCount+1,8),j.sampleCount>=2){let E=(j.sampleIndex-j.sampleCount+8)%8,D=j.samples[E],H=J-D.position,V=G-D.time;j.velocity=V>0?H/V:0}return j.lastPosition=J,j.lastTime=G,j},_j=(j)=>j.sampleCount>=3,$j=(j,J={})=>{let{wheel:G=!0,sensitivity:_=1,smoothing:F=!1,idleTimeout:E=150,onScroll:D,onIdle:H,scrollElement:V,horizontal:X=!1}=J,Z=!!V,Q=0,U=0,W=Z?X?window.innerWidth:window.innerHeight:X?j.clientWidth:j.clientHeight,N=J.compressed??!1,O=J.compression,q=Qj(),y=!1,f=null,I=Jj(()=>{let K=X?j.scrollLeft:j.scrollTop,Y=K>=Q?"down":"up";if(q=l(q,K),Q=K,D)D({scrollTop:Q,direction:Y,velocity:q.velocity});b()}),R=Jj(()=>{let K=j.getBoundingClientRect(),Y=X?Math.max(0,-K.left):Math.max(0,-K.top),$=Y>=Q?"down":"up";if(q=l(q,Y),Q=Y,!y)y=!0;if(D)D({scrollTop:Q,direction:$,velocity:q.velocity});b()}),M=(K)=>{K.preventDefault()},S=(K)=>{if(K.deltaX)return;K.preventDefault(),j.scrollLeft+=K.deltaY},x=(K)=>{if(!N)return;K.preventDefault();let Y=(X?K.deltaX||K.deltaY:K.deltaY)*_,$=Q+Y;if(F)$=Q+Y*0.3;if($=Math.max(0,Math.min($,U)),$!==Q){let B=$>=Q?"down":"up";if(q=l(q,$),Q=$,!y)y=!0;if(D)D({scrollTop:Q,direction:B,velocity:q.velocity});b()}},b=()=>{if(f)clearTimeout(f);f=setTimeout(()=>{if(y=!1,q=Qj(Q),H)H()},E)},t=(K)=>{if(N)return;if(N=!0,O=K,U=K.virtualHeight-W,Z)return;if(I.cancel(),j.removeEventListener("scroll",I),!G)j.removeEventListener("wheel",M);else if(X)j.removeEventListener("wheel",S);if(X)j.style.overflowX="hidden";else j.style.overflow="hidden";if(G)j.addEventListener("wheel",x,{passive:!1});let Y=X?j.scrollLeft:j.scrollTop;if(Y>0){let $=X?O?.actualHeight??j.scrollWidth:O?.actualHeight??j.scrollHeight;Q=Y/$*U}if(X)j.scrollLeft=0;else j.scrollTop=0},L=()=>{if(!N)return;if(N=!1,Z){O=void 0;return}if(j.removeEventListener("wheel",x),X)j.style.overflowX="auto";else j.style.overflow="auto";if(j.addEventListener("scroll",I,{passive:!0}),!G)j.addEventListener("wheel",M,{passive:!1});else if(X)j.addEventListener("wheel",S,{passive:!1});if(O&&Q>0){let Y=Q/U*(O.actualHeight-W);if(X)j.scrollLeft=Y;else j.scrollTop=Y}O=void 0},C=()=>{if(Z||N)return Q;return X?j.scrollLeft:j.scrollTop},A=(K,Y=!1)=>{let $=Math.max(0,Math.min(K,U||1/0));if(Z){let u=j.getBoundingClientRect();if(X){let B=u.left+window.scrollX;window.scrollTo({left:B+$,behavior:Y?"smooth":"auto"})}else{let B=u.top+window.scrollY;window.scrollTo({top:B+$,behavior:Y?"smooth":"auto"})}}else if(N){if($===Q)return;let B=$>=Q?"down":"up";if(q=l(q,$),Q=$,!y)y=!0;if(D)D({scrollTop:Q,direction:B,velocity:q.velocity});b()}else if(X)j.scrollTo({left:$,behavior:Y?"smooth":"auto"});else j.scrollTo({top:$,behavior:Y?"smooth":"auto"})},i=(K)=>{A(C()+K)},T=()=>{return C()<=0},P=(K=0)=>{let Y=C(),$=Z||N?U:X?j.scrollWidth-j.clientWidth:j.scrollHeight-j.clientHeight;return Y>=$-K},k=()=>{let K=C(),Y=Z||N?U:X?j.scrollWidth-j.clientWidth:j.scrollHeight-j.clientHeight;if(Y<=0)return 0;return Math.min(1,Math.max(0,K/Y))},d=(K)=>{if(K.compression)O=K.compression,U=O.virtualHeight-W},r=()=>N,s=()=>Math.abs(q.velocity),c=()=>_j(q),n=()=>y,w=()=>Z,v=(K)=>{if(W=K,O)U=O.virtualHeight-W},a=()=>{if(f)clearTimeout(f);if(Z)R.cancel(),window.removeEventListener("scroll",R);else I.cancel(),j.removeEventListener("scroll",I),j.removeEventListener("wheel",x),j.removeEventListener("wheel",M),j.removeEventListener("wheel",S)};if(Z){if(N&&O)U=O.virtualHeight-W;window.addEventListener("scroll",R,{passive:!0})}else if(N&&O){if(U=O.virtualHeight-W,X)j.style.overflowX="hidden";else j.style.overflow="hidden";if(G)j.addEventListener("wheel",x,{passive:!1})}else{if(X)j.style.overflowX="auto",j.style.overflowY="hidden";else j.style.overflow="auto";if(j.addEventListener("scroll",I,{passive:!0}),!G)j.addEventListener("wheel",M,{passive:!1});else if(X)j.addEventListener("wheel",S,{passive:!1})}return{getScrollTop:C,scrollTo:A,scrollBy:i,isAtTop:T,isAtBottom:P,getScrollPercentage:k,getVelocity:s,isTracking:c,isScrolling:n,updateConfig:d,enableCompression:t,disableCompression:L,isCompressed:r,isWindowMode:w,updateContainerHeight:v,destroy:a}},Jj=(j)=>{let J=null,G=null,_=(...F)=>{if(G=F,J===null)J=requestAnimationFrame(()=>{if(J=null,G)j(...G)})};return _.cancel=()=>{if(J!==null)cancelAnimationFrame(J),J=null},_},Bj=(j,J,G,_=0)=>{return j+G>=J-_},Oj=(j,J=0)=>{return j<=J},Uj=(j,J,G)=>{let _=J-G;if(_<=0)return 0;return Math.min(1,Math.max(0,j/_))},qj=(j,J,G,_)=>{return j<=_&&J>=G};export{Yj as withScrollbar,Jj as rafThrottle,qj as isRangeVisible,Oj as isAtTop,Bj as isAtBottom,Uj as getScrollPercentage,Gj as createScrollbar,$j as createScrollController};
@@ -0,0 +1 @@
1
+ var H=(D)=>({selected:new Set(D??[]),focusedIndex:-1}),E=(D,q,G)=>{if(G==="none")return D;let j=new Set(D.selected);if(G==="single"){if(j.clear(),q.length>0)j.add(q[0])}else for(let J of q)j.add(J);return{...D,selected:j}},F=(D,q)=>{let G=new Set(D.selected);for(let j of q)G.delete(j);return{...D,selected:G}},V=(D,q,G)=>{if(G==="none")return D;if(D.selected.has(q))return F(D,[q]);else return E(D,[q],G)},C=(D,q,G)=>{if(G!=="multiple")return D;return{...D,selected:new Set(q.map((j)=>j.id))}},f=(D)=>({...D,selected:new Set}),w=(D,q)=>{return D.focusedIndex=q,D},u=(D,q,G=!0)=>{if(q===0)return D;let j=D.focusedIndex-1;if(j<0)j=G?q-1:0;return D.focusedIndex=j,D},v=(D,q,G=!0)=>{if(q===0)return D;let j=D.focusedIndex+1;if(j>=q)j=G?0:q-1;return D.focusedIndex=j,D},R=(D,q)=>{if(q===0)return D;return D.focusedIndex=0,D},S=(D,q)=>{if(q===0)return D;return D.focusedIndex=q-1,D},r=(D,q,G,j)=>{if(q===0)return D;let J=j==="up"?D.focusedIndex-G:D.focusedIndex+G;return J=Math.max(0,Math.min(q-1,J)),D.focusedIndex=J,D},m=(D,q)=>{return D.selected.has(q)},y=(D)=>{return Array.from(D.selected)},O=(D,q)=>{let G=[];for(let j of D.selected){let J=q(j);if(J)G.push(J)}return G},d=(D)=>{return D.selected.size},l=(D)=>{return D.selected.size===0},c=(D,q,G)=>{if(G==="none"||D.focusedIndex<0||D.focusedIndex>=q.length)return D;let j=q[D.focusedIndex];if(!j)return D;return V(D,j.id,G)},o=(D,q,G,j,J)=>{if(J!=="multiple")return D;let B=Math.min(G,j),X=Math.max(G,j),U=[];for(let $=B;$<=X;$++){let k=q[$];if(k)U.push(k.id)}return E(D,U,J)};var h=(D,q,G,j,J,B)=>{if(j===0)return 0;let X=Math.max(0,Math.min(D,j-1)),U=q.getOffset(X),$=q.getHeight(X),k=q.getTotalHeight(),T=Math.max(0,k-G),W;switch(B){case"center":W=U-G/2+$/2;break;case"end":W=U-G+$;break;case"start":default:W=U;break}return Math.max(0,Math.min(W,T))};var p=(D,q,G,j,J="start",B,X=h)=>{return X(D,q,G,j,B,J)};var n=(D)=>{let q=D?.mode??"single",G=D?.initial,j=H(G),J=null;return{name:"withSelection",priority:50,methods:["select","deselect","toggleSelect","selectAll","clearSelection","getSelected","getSelectedItems"],setup(B){let{dom:X,emitter:U,config:$}=B,{classPrefix:k,ariaIdPrefix:T}=$;if(q==="none"){B.methods.set("select",()=>{}),B.methods.set("deselect",()=>{}),B.methods.set("toggleSelect",()=>{}),B.methods.set("selectAll",()=>{}),B.methods.set("clearSelection",()=>{}),B.methods.set("getSelected",()=>[]),B.methods.set("getSelectedItems",()=>[]),B.methods.set("setSelectionMode",()=>{});return}let{renderIfNeeded:W,forceRender:g}=B.getRenderFns(),b=()=>{B.dom.items.querySelectorAll("[data-index]").forEach((Q)=>{let M=Q,L=M.dataset.id;if(L!==void 0){let Y=/^\d+$/.test(L)?parseInt(L,10):L,_=j.selected.has(Y),N=parseInt(M.dataset.index??"-1",10)===j.focusedIndex;M.classList.toggle(`${k}-item--selected`,_),M.classList.toggle(`${k}-item--focused`,N),M.ariaSelected=_?"true":"false"}})},x=()=>{if(B.state.isDestroyed)return;W(),b()},I=()=>{if(B.state.isDestroyed)return;g(),b()};B.setRenderFns(x,I);let A=()=>{b(),U.emit("selection:change",{selected:y(j),items:O(j,(K)=>B.dataManager.getItemById(K))})};J=document.createElement("div"),J.setAttribute("aria-live","polite"),J.setAttribute("aria-atomic","true"),J.className=`${k}-live-region`,J.style.cssText="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0",X.root.appendChild(J);let z=J;U.on("selection:change",({selected:K})=>{let Q=K.length;if(Q===0)z.textContent="";else if(Q===1)z.textContent="1 item selected";else z.textContent=`${Q} items selected`}),B.clickHandlers.push((K)=>{if(B.state.isDestroyed)return;let M=K.target.closest("[data-index]");if(!M)return;let L=parseInt(M.dataset.index??"-1",10);if(L<0)return;let Y=B.dataManager.getItem(L);if(!Y)return;U.emit("item:click",{item:Y,index:L,event:K}),j=w(j,L),X.root.setAttribute("aria-activedescendant",`${T}-item-${L}`),j=V(j,Y.id,q),A()}),B.keydownHandlers.push((K)=>{if(B.state.isDestroyed)return;let Q=B.dataManager.getTotal(),M=j.focusedIndex,L=!1,Y=!1,_=j;switch(K.key){case"ArrowUp":_=u(j,Q),L=!0,Y=!0;break;case"ArrowDown":_=v(j,Q),L=!0,Y=!0;break;case"Home":_=R(j,Q),L=!0,Y=!0;break;case"End":_=S(j,Q),L=!0,Y=!0;break;case" ":case"Enter":if(j.focusedIndex>=0){let Z=B.dataManager.getItem(j.focusedIndex);if(Z)_=V(j,Z.id,q);L=!0}break}if(L){K.preventDefault(),j=_;let Z=j.focusedIndex;if(Z>=0){let N=B.dataManager.getState(),P=p(Z,B.heightCache,B.state.viewportState.containerHeight,N.total,"center",B.getCachedCompression());B.scrollController.scrollTo(P),X.root.setAttribute("aria-activedescendant",`${T}-item-${Z}`)}else X.root.removeAttribute("aria-activedescendant");if(Y){let{selected:N}=j;if(M>=0&&M!==Z){let P=B.dataManager.getItem(M);if(P)B.renderer.updateItemClasses(M,N.has(P.id),!1)}if(Z>=0){let P=B.dataManager.getItem(Z);if(P)B.renderer.updateItemClasses(Z,N.has(P.id),!0)}}else I(),U.emit("selection:change",{selected:y(j),items:O(j,(N)=>B.dataManager.getItemById(N))})}}),B.methods.set("select",(...K)=>{if(q==="none")return;j=E(j,K,q),A()}),B.methods.set("deselect",(...K)=>{j=F(j,K),A()}),B.methods.set("toggleSelect",(K)=>{if(q==="none")return;j=V(j,K,q),A()}),B.methods.set("selectAll",()=>{if(q!=="multiple")return;let K=B.getAllLoadedItems();j=C(j,K,q),A()}),B.methods.set("clearSelection",()=>{j=f(j);let{renderRange:K,isCompressed:Q}=B.state.viewportState,M=B.getItemsForRange(K),L=Q?B.getCompressionContext():void 0;B.renderer.render(M,K,j.selected,j.focusedIndex,L),U.emit("selection:change",{selected:[],items:[]})}),B.methods.set("getSelected",()=>{return y(j)}),B.methods.set("getSelectedItems",()=>{return O(j,(K)=>B.dataManager.getItemById(K))}),B.destroyHandlers.push(()=>{if(z&&z.parentNode)z.remove()})},destroy(){if(J&&J.parentNode)J.remove();J=null}}};export{n as withSelection,V as toggleSelection,w as setFocusedIndex,o as selectRange,E as selectItems,c as selectFocused,C as selectAll,u as moveFocusUp,S as moveFocusToLast,R as moveFocusToFirst,v as moveFocusDown,r as moveFocusByPage,l as isSelectionEmpty,m as isSelected,d as getSelectionCount,O as getSelectedItems,y as getSelectedIds,F as deselectItems,H as createSelectionState,f as clearSelection};