vlist 0.1.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +558 -0
  3. package/dist/builder/a11y.d.ts +16 -0
  4. package/dist/builder/api.d.ts +21 -0
  5. package/dist/builder/context.d.ts +36 -0
  6. package/dist/builder/core.d.ts +16 -0
  7. package/dist/builder/data.d.ts +69 -0
  8. package/dist/builder/dom.d.ts +15 -0
  9. package/dist/builder/index.d.ts +25 -0
  10. package/dist/builder/materialize.d.ts +165 -0
  11. package/dist/builder/pool.d.ts +10 -0
  12. package/dist/builder/range.d.ts +10 -0
  13. package/dist/builder/scroll.d.ts +24 -0
  14. package/dist/builder/types.d.ts +464 -0
  15. package/dist/builder/velocity.d.ts +23 -0
  16. package/dist/constants.d.ts +58 -0
  17. package/dist/events/emitter.d.ts +18 -0
  18. package/dist/events/index.d.ts +6 -0
  19. package/dist/features/async/feature.d.ts +72 -0
  20. package/dist/features/async/index.d.ts +9 -0
  21. package/dist/features/async/manager.d.ts +103 -0
  22. package/dist/features/async/placeholder.d.ts +54 -0
  23. package/dist/features/async/sparse.d.ts +91 -0
  24. package/dist/features/autosize/feature.d.ts +34 -0
  25. package/dist/features/autosize/index.d.ts +2 -0
  26. package/dist/features/grid/feature.d.ts +48 -0
  27. package/dist/features/grid/index.d.ts +9 -0
  28. package/dist/features/grid/layout.d.ts +29 -0
  29. package/dist/features/grid/renderer.d.ts +71 -0
  30. package/dist/features/grid/types.d.ts +71 -0
  31. package/dist/features/groups/feature.d.ts +74 -0
  32. package/dist/features/groups/index.d.ts +10 -0
  33. package/dist/features/groups/layout.d.ts +47 -0
  34. package/dist/features/groups/sticky.d.ts +21 -0
  35. package/dist/features/groups/types.d.ts +86 -0
  36. package/dist/features/masonry/feature.d.ts +45 -0
  37. package/dist/features/masonry/index.d.ts +9 -0
  38. package/dist/features/masonry/layout.d.ts +29 -0
  39. package/dist/features/masonry/renderer.d.ts +55 -0
  40. package/dist/features/masonry/types.d.ts +68 -0
  41. package/dist/features/page/feature.d.ts +53 -0
  42. package/dist/features/page/index.d.ts +8 -0
  43. package/dist/features/scale/feature.d.ts +42 -0
  44. package/dist/features/scale/index.d.ts +10 -0
  45. package/dist/features/scrollbar/controller.d.ts +121 -0
  46. package/dist/features/scrollbar/feature.d.ts +60 -0
  47. package/dist/features/scrollbar/index.d.ts +8 -0
  48. package/dist/features/scrollbar/scrollbar.d.ts +73 -0
  49. package/dist/features/selection/feature.d.ts +75 -0
  50. package/dist/features/selection/index.d.ts +7 -0
  51. package/dist/features/selection/state.d.ts +115 -0
  52. package/dist/features/snapshots/feature.d.ts +79 -0
  53. package/dist/features/snapshots/index.d.ts +9 -0
  54. package/dist/features/table/feature.d.ts +67 -0
  55. package/dist/features/table/header.d.ts +49 -0
  56. package/dist/features/table/index.d.ts +10 -0
  57. package/dist/features/table/layout.d.ts +26 -0
  58. package/dist/features/table/renderer.d.ts +72 -0
  59. package/dist/features/table/types.d.ts +239 -0
  60. package/dist/index.d.ts +28 -0
  61. package/dist/index.js +1 -0
  62. package/dist/internals.d.ts +21 -0
  63. package/dist/internals.js +1 -0
  64. package/dist/rendering/index.d.ts +12 -0
  65. package/dist/rendering/measured.d.ts +52 -0
  66. package/dist/rendering/renderer.d.ts +111 -0
  67. package/dist/rendering/scale.d.ts +121 -0
  68. package/dist/rendering/scroll.d.ts +23 -0
  69. package/dist/rendering/sizes.d.ts +63 -0
  70. package/dist/rendering/sort.d.ts +33 -0
  71. package/dist/rendering/viewport.d.ts +139 -0
  72. package/dist/size.json +1 -0
  73. package/dist/types.d.ts +487 -0
  74. package/dist/utils/padding.d.ts +38 -0
  75. package/dist/utils/stats.d.ts +49 -0
  76. package/dist/vlist-extras.css +1 -0
  77. package/dist/vlist-grid.css +1 -0
  78. package/dist/vlist-masonry.css +1 -0
  79. package/dist/vlist-table.css +1 -0
  80. package/dist/vlist.css +1 -0
  81. package/package.json +66 -14
  82. package/README.MD +0 -80
  83. package/index.d.ts +0 -3
  84. package/index.js +0 -188
  85. package/virtual-scroll.component.d.ts +0 -37
  86. package/vlist.d.ts +0 -4
  87. package/vlist.metadata.json +0 -1
  88. package/vlist.umd.js +0 -189
@@ -0,0 +1,21 @@
1
+ /**
2
+ * vlist - Sticky Header
3
+ *
4
+ * Manages a floating header that sticks to the viewport edge and transitions
5
+ * smoothly when the next group's header approaches (push-out effect).
6
+ *
7
+ * Two permanent slot elements are recycled — content is swapped via a
8
+ * caller-provided `renderInto` callback, keeping the sticky header
9
+ * template-agnostic (same pattern as item rendering).
10
+ *
11
+ * Header offsets and sizes are pre-cached into flat arrays on rebuild,
12
+ * keeping the per-tick scroll handler free of function calls.
13
+ *
14
+ * .vlist-sticky-header (position: relative, overflow: hidden)
15
+ * ├── .sticky-group (active slot — translated during push)
16
+ * └── .sticky-group (standby slot — translated during push)
17
+ */
18
+ import type { GroupLayout, StickyHeader } from "./types";
19
+ import type { SizeCache } from "../../rendering/sizes";
20
+ export declare const createStickyHeader: (root: HTMLElement, layout: GroupLayout, sizeCache: SizeCache, renderInto: (slot: HTMLElement, groupIndex: number) => void, classPrefix: string, horizontal?: boolean, stickyOffset?: number) => StickyHeader;
21
+ //# sourceMappingURL=sticky.d.ts.map
@@ -0,0 +1,86 @@
1
+ /**
2
+ * vlist - Group Types
3
+ * Types for sticky headers and grouped lists
4
+ */
5
+ import type { VListItem, GroupsConfig } from "../../types";
6
+ export type { GroupsConfig };
7
+ /** A single group boundary */
8
+ export interface GroupBoundary {
9
+ /** Group key (return value of getGroupForIndex) */
10
+ key: string;
11
+ /** Sequential group index (0-based) */
12
+ groupIndex: number;
13
+ /** Layout index of this group's header */
14
+ headerLayoutIndex: number;
15
+ /** Data index of the first item in this group */
16
+ firstDataIndex: number;
17
+ /** Number of data items in this group */
18
+ count: number;
19
+ }
20
+ /** Entry type in the layout — either a group header or a data item */
21
+ export type LayoutEntry = {
22
+ type: "header";
23
+ group: GroupBoundary;
24
+ } | {
25
+ type: "item";
26
+ dataIndex: number;
27
+ group: GroupBoundary;
28
+ };
29
+ /**
30
+ * Internal marker for group header pseudo-items inserted into the layout.
31
+ * These are interleaved with real data items in the transformed items array.
32
+ */
33
+ export interface GroupHeaderItem extends VListItem {
34
+ /** Always `__group_header_{groupIndex}` */
35
+ id: string;
36
+ /** Discriminator flag */
37
+ __groupHeader: true;
38
+ /** The group key */
39
+ groupKey: string;
40
+ /** Sequential group index (0-based) */
41
+ groupIndex: number;
42
+ }
43
+ /**
44
+ * Type guard: check if an item is a group header pseudo-item
45
+ */
46
+ export declare const isGroupHeader: (item: unknown) => item is GroupHeaderItem;
47
+ /** Group layout — maps between data indices and layout indices */
48
+ export interface GroupLayout {
49
+ /** Total layout entries (data items + group headers) */
50
+ readonly totalEntries: number;
51
+ /** Number of groups */
52
+ readonly groupCount: number;
53
+ /** All group boundaries, in order */
54
+ readonly groups: readonly GroupBoundary[];
55
+ /** Get the layout entry at a layout index — O(log g) */
56
+ getEntry: (layoutIndex: number) => LayoutEntry;
57
+ /** Map layout index → data index, or -1 if it's a header — O(log g) */
58
+ layoutToDataIndex: (layoutIndex: number) => number;
59
+ /** Map data index → layout index — O(log g) */
60
+ dataToLayoutIndex: (dataIndex: number) => number;
61
+ /** Get the group boundary that contains a given layout index — O(log g) */
62
+ getGroupAtLayoutIndex: (layoutIndex: number) => GroupBoundary;
63
+ /** Get the group boundary that contains a given data index — O(log g) */
64
+ getGroupAtDataIndex: (dataIndex: number) => GroupBoundary;
65
+ /** Get header height for a group */
66
+ getHeaderHeight: (groupIndex: number) => number;
67
+ /**
68
+ * Rebuild the layout from scratch.
69
+ * Call when items change (setItems, append, prepend, remove, etc.)
70
+ */
71
+ rebuild: (itemCount: number) => void;
72
+ }
73
+ /** Sticky header manager */
74
+ export interface StickyHeader {
75
+ /** Update sticky header position and content based on scroll position */
76
+ update: (scrollTop: number) => void;
77
+ /** Force refresh the sticky header content (e.g. after items change) */
78
+ refresh: () => void;
79
+ /** Show the sticky header */
80
+ show: () => void;
81
+ /** Hide the sticky header */
82
+ hide: () => void;
83
+ /** Destroy and remove the sticky header DOM element */
84
+ destroy: () => void;
85
+ }
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * vlist/masonry - Builder Feature
3
+ * Switches from list layout to masonry/Pinterest-style layout.
4
+ *
5
+ * Priority: 10 (runs first — replaces the renderer before anything else renders)
6
+ *
7
+ * What it does:
8
+ * - Replaces renderer — swaps the list renderer with a masonry renderer
9
+ * - Calculates item placements using shortest-lane algorithm
10
+ * - Positions items using absolute coordinates (no row alignment)
11
+ * - Renders only visible items based on scroll position
12
+ * - CSS class — adds .vlist--masonry to the root element
13
+ *
14
+ * Key differences from grid:
15
+ * - No row-based virtualization (items flow into shortest column/row)
16
+ * - O(n) layout calculation (must track lane heights)
17
+ * - Items positioned by cached x/y coordinates
18
+ * - Variable heights create organic, packed layout
19
+ *
20
+ * Restrictions:
21
+ * - Cannot be combined with reverse: true
22
+ * - Item sizes must be deterministic (no dynamic content sizing)
23
+ *
24
+ * Can be combined with withSelection for selectable masonry layouts.
25
+ *
26
+ * Performance:
27
+ * - Early exit when scroll position + container size unchanged (zero work per redundant frame)
28
+ * - Cached empty Set for no-selection case (zero allocation per frame)
29
+ * - Viewport state mutated in place (no object creation per frame)
30
+ * - Cached getItem closure (no closure allocation per frame)
31
+ *
32
+ * - Items passed to renderer via data manager reference (no sparse array)
33
+ * - All data mutation methods intercepted for layout recalculation
34
+ */
35
+ import type { VListItem } from "../../types";
36
+ import type { VListFeature } from "../../builder/types";
37
+ /** Masonry feature configuration */
38
+ export interface MasonryFeatureConfig {
39
+ /** Number of cross-axis divisions (columns in vertical, rows in horizontal) */
40
+ columns: number;
41
+ /** Gap between items in pixels (default: 0) */
42
+ gap?: number;
43
+ }
44
+ export declare const withMasonry: <T extends VListItem = VListItem>(config: MasonryFeatureConfig) => VListFeature<T>;
45
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * vlist - Masonry Domain
3
+ * Pinterest-style layout with shortest-lane placement
4
+ */
5
+ export { withMasonry, type MasonryFeatureConfig } from "./feature";
6
+ export { createMasonryLayout } from "./layout";
7
+ export { createMasonryRenderer, type MasonryRenderer, type GetItemFn } from "./renderer";
8
+ export type { MasonryConfig, MasonryLayout, ItemPlacement, } from "./types";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * vlist - Masonry Layout
3
+ * Shortest-lane placement algorithm for masonry/Pinterest-style layouts.
4
+ *
5
+ * Algorithm:
6
+ * 1. Track the size (height/width) of each lane (column/row)
7
+ * 2. For each item:
8
+ * - Find the shortest lane
9
+ * - Place item at the end of that lane
10
+ * - Update lane size
11
+ * 3. Cache all item positions for O(1) lookup during rendering
12
+ *
13
+ * Complexity:
14
+ * - Layout calculation: O(n) where n = total items
15
+ * - Position lookup: O(1) using cached placements
16
+ * - Visibility check: O(k * log(n/k)) using per-lane binary search
17
+ * where k = columns, n = total items
18
+ */
19
+ import type { MasonryConfig, MasonryLayout } from "./types";
20
+ /**
21
+ * Create a MasonryLayout instance.
22
+ *
23
+ * @param config - Masonry configuration (columns, gap, containerSize)
24
+ * @returns MasonryLayout with placement algorithm
25
+ */
26
+ export declare const createMasonryLayout: (config: MasonryConfig & {
27
+ containerSize: number;
28
+ }) => MasonryLayout;
29
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1,55 @@
1
+ /**
2
+ * vlist - Masonry Renderer
3
+ * Renders items in a masonry/Pinterest-style layout with absolute positioning.
4
+ *
5
+ * Unlike grid renderer (which uses row-based positioning), masonry renderer
6
+ * positions each item using its pre-calculated coordinates from the layout phase.
7
+ *
8
+ * Key differences from grid:
9
+ * - Items positioned using cached x/y coordinates (not row/col calculations)
10
+ * - Each item can have different height/width
11
+ * - No row alignment - items flow into shortest column/row
12
+ * - Visibility determined by checking each item's absolute position
13
+ *
14
+ * Performance:
15
+ * - Element pooling avoids createElement cost
16
+ * - Template re-evaluation skipped when item data + state unchanged
17
+ * - O(1) Set-based visibility diffing (not O(n) .some())
18
+ * - Release grace period prevents boundary thrashing (hover blink, transition replay)
19
+ * - Released elements removed from DOM immediately
20
+ */
21
+ import type { VListItem, ItemTemplate } from "../../types";
22
+ import type { ItemPlacement } from "./types";
23
+ /** Item lookup function — avoids sparse array allocation on every frame */
24
+ export type GetItemFn<T> = (index: number) => T | undefined;
25
+ /** Masonry renderer instance */
26
+ export interface MasonryRenderer<T extends VListItem = VListItem> {
27
+ /** Render visible items using pre-calculated placements */
28
+ render: (getItem: GetItemFn<T>, placements: ItemPlacement[], selectedIds: Set<string | number>, focusedIndex: number) => void;
29
+ /** Get rendered item element by flat item index */
30
+ getElement: (index: number) => HTMLElement | undefined;
31
+ /** Update only CSS classes on a rendered item (no template re-evaluation) */
32
+ updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
33
+ /**
34
+ * Reorder DOM children to match logical item order (by data-index).
35
+ * Called on scroll idle so screen readers encounter items in the correct
36
+ * sequence. Items are position:absolute so visual layout is unaffected.
37
+ */
38
+ sortDOM: () => void;
39
+ /** Clear all rendered items */
40
+ clear: () => void;
41
+ /** Destroy renderer and cleanup */
42
+ destroy: () => void;
43
+ }
44
+ /**
45
+ * Create a masonry renderer for managing DOM elements with absolute positioning.
46
+ *
47
+ * @param itemsContainer - The DOM element that holds rendered items
48
+ * @param template - Item template function
49
+ * @param classPrefix - CSS class prefix
50
+ * @param isHorizontal - Whether layout is horizontal (scrolls right)
51
+ * @param totalItemsGetter - Optional getter for total item count (for aria-setsize)
52
+ * @param ariaIdPrefix - Optional unique prefix for element IDs (for aria-activedescendant)
53
+ */
54
+ export declare const createMasonryRenderer: <T extends VListItem = VListItem>(itemsContainer: HTMLElement, template: ItemTemplate<T>, classPrefix: string, isHorizontal?: boolean, totalItemsGetter?: () => number, ariaIdPrefix?: string) => MasonryRenderer<T>;
55
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * vlist - Masonry Types
3
+ * Types for masonry/Pinterest-style layout mode
4
+ *
5
+ * Masonry layout arranges items in columns (vertical) or rows (horizontal)
6
+ * where items flow into the shortest column/row, creating a packed layout
7
+ * with no alignment across the cross-axis.
8
+ */
9
+ import type { MasonryConfig } from "../../types";
10
+ export type { MasonryConfig };
11
+ /** Cached item placement — flat structure for minimal allocation and fast access */
12
+ export interface ItemPlacement {
13
+ /** Item index */
14
+ index: number;
15
+ /** X coordinate in pixels (cross-axis offset) */
16
+ x: number;
17
+ /** Y coordinate in pixels (main-axis offset) */
18
+ y: number;
19
+ /** Cross-axis division index (column in vertical, row in horizontal) */
20
+ lane: number;
21
+ /** Item size in main axis (height in vertical, width in horizontal) */
22
+ size: number;
23
+ /** Item size in cross axis (width in vertical, height in horizontal) */
24
+ crossSize: number;
25
+ }
26
+ /**
27
+ * MasonryLayout — places items in the shortest column/row.
28
+ *
29
+ * Unlike grid (O(1) calculations), masonry requires O(n) layout calculation
30
+ * because each item's position depends on the accumulated sizes of items
31
+ * before it in the same column/row.
32
+ *
33
+ * The layout algorithm:
34
+ * 1. Track size of each column/row (cross-axis divisions)
35
+ * 2. For each item, find the shortest column/row
36
+ * 3. Place item at the end of that column/row
37
+ * 4. Update that column/row's size
38
+ * 5. Cache the item's position for rendering
39
+ */
40
+ export interface MasonryLayout {
41
+ /** Number of cross-axis divisions (columns in vertical, rows in horizontal) */
42
+ readonly columns: number;
43
+ /** Gap between items in pixels */
44
+ readonly gap: number;
45
+ /** Container width (for vertical) or height (for horizontal) */
46
+ readonly containerSize: number;
47
+ /** Update masonry configuration */
48
+ update: (config: Partial<MasonryConfig & {
49
+ containerSize: number;
50
+ }>) => void;
51
+ /**
52
+ * Calculate layout for all items.
53
+ * Returns array of item placements with positions.
54
+ * This is O(n) where n = totalItems.
55
+ */
56
+ calculateLayout: (totalItems: number, getSizeForItem: (index: number) => number) => ItemPlacement[];
57
+ /**
58
+ * Get the total size in the main axis (total height in vertical, total width in horizontal).
59
+ * This is the size of the tallest/widest column/row.
60
+ */
61
+ getTotalSize: (placements: ItemPlacement[]) => number;
62
+ /**
63
+ * Get items visible in the viewport.
64
+ * mainAxisStart/End = scroll position range (scrollTop/scrollLeft + viewport size)
65
+ */
66
+ getVisibleItems: (placements: ItemPlacement[], mainAxisStart: number, mainAxisEnd: number) => ItemPlacement[];
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * vlist/window - Window Scroll Mode Feature
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 features 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 { VListFeature } from "../../builder/types";
21
+ /**
22
+ * Create a window scroll mode feature.
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
+ * orientation: 'horizontal'
47
+ * })
48
+ * .use(withWindow())
49
+ * .build()
50
+ * ```
51
+ */
52
+ export declare const withPage: <T extends VListItem = VListItem>() => VListFeature<T>;
53
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * vlist/window - Window Scroll Mode Feature
3
+ *
4
+ * Entry point for the window scroll feature.
5
+ */
6
+ export { withPage } from "./feature";
7
+ export type { VListFeature } from "../../builder/types";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * vlist/compression - Builder Feature
3
+ * Enables support for lists with 1M+ items by compressing the scroll space
4
+ * when the total height exceeds the browser's ~16.7M pixel limit.
5
+ *
6
+ * Priority: 20 (runs before scrollbar, after grid/groups)
7
+ *
8
+ * What it wires:
9
+ * - Scroll mode switch — transitions from native to compressed scrolling when needed
10
+ * - Scroll position mapping — maps compressed scroll positions to item indices
11
+ * - Item positioning — positions items relative to viewport in compressed mode
12
+ * - Custom scrollbar fallback — forces custom scrollbar in compressed mode
13
+ * - Compression slack — extends scroll range so the linear index formula reaches every item
14
+ * - Cached compression state — recalculates only when total item count changes
15
+ * - Smooth scroll interpolation — lerp-based wheel handling for cross-browser consistency
16
+ * - Touch scroll support — finger tracking + momentum for iOS Safari / mobile browsers
17
+ *
18
+ * No configuration needed — compression activates automatically when the total
19
+ * height exceeds the browser limit, and deactivates when items are removed.
20
+ */
21
+ import type { VListItem } from "../../types";
22
+ import type { VListFeature } from "../../builder/types";
23
+ /** Configuration options for the scale feature */
24
+ export interface ScaleConfig {
25
+ /**
26
+ * Force compressed scroll mode even when the total size is below the
27
+ * browser's ~16.7M pixel limit.
28
+ *
29
+ * When `true`, the feature always activates compressed scrolling
30
+ * (custom wheel/touch handling, lerp-based smooth scroll, custom
31
+ * scrollbar fallback) regardless of the list size. This is useful for:
32
+ *
33
+ * - **Testing** — verify compression behaviour with a small item set
34
+ * - **Consistent UX** — prefer the smooth scroll physics for all lists
35
+ * - **Pre-emptive** — avoid the mode switch when items are added at runtime
36
+ *
37
+ * @default false
38
+ */
39
+ force?: boolean;
40
+ }
41
+ export declare const withScale: <T extends VListItem = VListItem>(config?: ScaleConfig) => VListFeature<T>;
42
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * vlist - Compression Sub-module
3
+ * Re-exports compression utilities for tree-shakeable imports
4
+ *
5
+ * Usage: import { getCompressionInfo } from 'vlist/compression'
6
+ * Usage: import { withScale } from 'vlist/compression'
7
+ */
8
+ export { MAX_VIRTUAL_SIZE, getCompressionState, needsCompression, getMaxItemsWithoutCompression, getCompressionInfo, calculateCompressedVisibleRange, calculateCompressedRenderRange, calculateCompressedItemPosition, calculateCompressedScrollToIndex, calculateIndexFromScrollPosition, type CompressionState, } from "../../rendering/scale";
9
+ export { withScale, type ScaleConfig } from "./feature";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * vlist - Scroll Controller
3
+ * Handles both native scrolling and manual wheel-based scrolling for compressed lists
4
+ *
5
+ * When compression is active (large lists exceeding browser height limits),
6
+ * we switch from native scrolling to manual wheel event handling.
7
+ * This allows smooth scrolling through millions of items.
8
+ */
9
+ import type { CompressionState } from "../../rendering/scale";
10
+ /** Scroll direction */
11
+ export type ScrollDirection = "up" | "down";
12
+ /** Scroll event data */
13
+ export interface ScrollEventData {
14
+ scrollTop: number;
15
+ direction: ScrollDirection;
16
+ velocity: number;
17
+ }
18
+ /** Scroll controller configuration */
19
+ export interface ScrollControllerConfig {
20
+ /** Enable compressed scroll mode (manual wheel handling) */
21
+ compressed?: boolean;
22
+ /** Compression state for calculating bounds */
23
+ compression?: CompressionState;
24
+ /**
25
+ * External scroll element for window/document scrolling.
26
+ * When set, the controller listens to this element's scroll events
27
+ * and computes list-relative positions from the viewport's bounding rect.
28
+ */
29
+ scrollElement?: Window;
30
+ /** Allow mouse wheel to scroll (default: true) */
31
+ wheel?: boolean;
32
+ /** Wheel sensitivity multiplier (default: 1) */
33
+ sensitivity?: number;
34
+ /** Enable smooth scrolling interpolation */
35
+ smoothing?: boolean;
36
+ /** Scroll idle detection timeout in ms (default: 150) */
37
+ idleTimeout?: number;
38
+ /**
39
+ * Enable horizontal scrolling mode.
40
+ * When true, the controller reads scrollLeft instead of scrollTop,
41
+ * uses clientWidth instead of clientHeight, and maps wheel deltaX.
42
+ */
43
+ horizontal?: boolean;
44
+ /** Callback when scroll position changes */
45
+ onScroll?: (data: ScrollEventData) => void;
46
+ /** Callback when scrolling becomes idle */
47
+ onIdle?: () => void;
48
+ }
49
+ /** Scroll controller instance */
50
+ export interface ScrollController {
51
+ /** Get current scroll position */
52
+ getScrollTop: () => number;
53
+ /** Set scroll position */
54
+ scrollTo: (position: number, smooth?: boolean) => void;
55
+ /** Scroll by delta */
56
+ scrollBy: (delta: number) => void;
57
+ /** Check if at top */
58
+ isAtTop: () => boolean;
59
+ /** Check if at bottom */
60
+ isAtBottom: (threshold?: number) => boolean;
61
+ /** Get scroll percentage (0-1) */
62
+ getScrollPercentage: () => number;
63
+ /** Get current scroll velocity (px/ms, absolute value) */
64
+ getVelocity: () => number;
65
+ /**
66
+ * Check if the velocity tracker is actively tracking with enough samples.
67
+ * Returns false during ramp-up (first few frames of a new scroll gesture)
68
+ * when the tracker doesn't have enough samples yet.
69
+ */
70
+ isTracking: () => boolean;
71
+ /** Check if currently scrolling */
72
+ isScrolling: () => boolean;
73
+ /** Update configuration (e.g., when compression state changes) */
74
+ updateConfig: (config: Partial<ScrollControllerConfig>) => void;
75
+ /** Enable compressed mode */
76
+ enableCompression: (compression: CompressionState) => void;
77
+ /** Disable compressed mode (revert to native scroll) */
78
+ disableCompression: () => void;
79
+ /** Check if compressed mode is active */
80
+ isCompressed: () => boolean;
81
+ /** Check if in window scroll mode */
82
+ isWindowMode: () => boolean;
83
+ /**
84
+ * Update the container height used for scroll calculations.
85
+ * In window mode, call this when the window resizes.
86
+ */
87
+ updateContainerHeight: (height: number) => void;
88
+ /** Destroy and cleanup */
89
+ destroy: () => void;
90
+ }
91
+ /**
92
+ * Create a scroll controller for a viewport element
93
+ *
94
+ * Supports two modes:
95
+ * 1. Native scrolling (default) - uses browser's built-in scroll
96
+ * 2. Compressed scrolling - manual wheel handling for large lists
97
+ */
98
+ export declare const createScrollController: (viewport: HTMLElement, config?: ScrollControllerConfig) => ScrollController;
99
+ /**
100
+ * Throttle scroll handler using requestAnimationFrame
101
+ */
102
+ export declare const rafThrottle: <T extends (...args: any[]) => void>(fn: T) => ((...args: Parameters<T>) => void) & {
103
+ cancel: () => void;
104
+ };
105
+ /**
106
+ * Check if scroll position is at bottom
107
+ */
108
+ export declare const isAtBottom: (scrollTop: number, scrollHeight: number, clientHeight: number, threshold?: number) => boolean;
109
+ /**
110
+ * Check if scroll position is at top
111
+ */
112
+ export declare const isAtTop: (scrollTop: number, threshold?: number) => boolean;
113
+ /**
114
+ * Get scroll percentage (0-1)
115
+ */
116
+ export declare const getScrollPercentage: (scrollTop: number, scrollHeight: number, clientHeight: number) => number;
117
+ /**
118
+ * Check if a range is visible in the scroll viewport
119
+ */
120
+ export declare const isRangeVisible: (rangeStart: number, rangeEnd: number, visibleStart: number, visibleEnd: number) => boolean;
121
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * vlist/scroll - Builder Feature
3
+ * Wraps the custom scrollbar into a VListFeature for the composable builder.
4
+ *
5
+ * Priority: 30 (runs after renderer/data setup but before selection)
6
+ *
7
+ * What it wires:
8
+ * - DOM elements — track, thumb, and optional hover zone appended to viewport
9
+ * - CSS class — .vlist-viewport--custom-scrollbar hides native scrollbar
10
+ * - Drag handlers — mousedown on thumb, mousemove/mouseup on document
11
+ * - Track click — click on track to jump to position
12
+ * - Hover handlers — mouseenter/leave on track, hover zone, and viewport
13
+ * - Scroll sync — updates thumb position on every scroll frame
14
+ * - Resize sync — updates thumb size when container or content height changes
15
+ *
16
+ * No public methods are added — the scrollbar is entirely automatic.
17
+ */
18
+ import type { VListItem } from "../../types";
19
+ import type { VListFeature } from "../../builder/types";
20
+ /** Scrollbar feature configuration */
21
+ export interface ScrollbarFeatureConfig {
22
+ /** Auto-hide scrollbar after idle (default: true) */
23
+ autoHide?: boolean;
24
+ /** Auto-hide delay in milliseconds (default: 1000) */
25
+ autoHideDelay?: number;
26
+ /** Minimum thumb size in pixels (default: 30) */
27
+ minThumbSize?: number;
28
+ /**
29
+ * Show scrollbar when hovering near the scrollbar edge (default: true).
30
+ * When true, an invisible hover zone is placed along the scrollbar edge.
31
+ */
32
+ showOnHover?: boolean;
33
+ /**
34
+ * Width of the invisible hover zone in pixels (default: 16).
35
+ * Only used when `showOnHover` is true.
36
+ */
37
+ hoverZoneWidth?: number;
38
+ /**
39
+ * Show scrollbar when the mouse enters the list viewport (default: true).
40
+ * When false, the scrollbar only appears on scroll or hover near edge.
41
+ */
42
+ showOnViewportEnter?: boolean;
43
+ }
44
+ /**
45
+ * Create a scrollbar feature for the builder.
46
+ *
47
+ * Replaces the native browser scrollbar with a custom, cross-browser
48
+ * consistent scrollbar.
49
+ *
50
+ * ```ts
51
+ * import { vlist } from 'vlist/builder'
52
+ * import { withScrollbar } from 'vlist/scroll'
53
+ *
54
+ * const list = vlist({ ... })
55
+ * .use(withScrollbar({ autoHide: true, autoHideDelay: 1000 }))
56
+ * .build()
57
+ * ```
58
+ */
59
+ export declare const withScrollbar: <T extends VListItem = VListItem>(config?: ScrollbarFeatureConfig) => VListFeature<T>;
60
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * vlist - Scroll Domain
3
+ * Scroll controller and custom scrollbar
4
+ */
5
+ export { withScrollbar, type ScrollbarFeatureConfig } from "./feature";
6
+ export { createScrollController, rafThrottle, isAtBottom, isAtTop, getScrollPercentage, isRangeVisible, type ScrollController, type ScrollControllerConfig, type ScrollEventData, type ScrollDirection, } from "./controller";
7
+ export { createScrollbar, type Scrollbar, type ScrollbarConfig, type ScrollCallback, } from "./scrollbar";
8
+ //# sourceMappingURL=index.d.ts.map