@floor/vlist 0.5.7 → 0.6.0

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 (108) hide show
  1. package/README.md +793 -592
  2. package/dist/async/index.js +1 -0
  3. package/dist/builder/context.d.ts +3 -3
  4. package/dist/builder/context.d.ts.map +1 -1
  5. package/dist/builder/core.d.ts +1 -1
  6. package/dist/builder/core.d.ts.map +1 -1
  7. package/dist/builder/index.js +1 -250
  8. package/dist/builder/types.d.ts +3 -3
  9. package/dist/builder/types.d.ts.map +1 -1
  10. package/dist/compression/index.js +1 -104
  11. package/dist/core/core.js +1 -0
  12. package/dist/core/full.d.ts +22 -0
  13. package/dist/core/full.d.ts.map +1 -0
  14. package/dist/core/index.js +1 -133
  15. package/dist/core/lite.d.ts +129 -0
  16. package/dist/core/lite.d.ts.map +1 -0
  17. package/dist/core/minimal.d.ts +104 -0
  18. package/dist/core/minimal.d.ts.map +1 -0
  19. package/dist/core-light.js +1 -68
  20. package/dist/data/index.js +1 -233
  21. package/dist/features/async/index.d.ts +9 -0
  22. package/dist/features/async/index.d.ts.map +1 -0
  23. package/dist/features/async/manager.d.ts +103 -0
  24. package/dist/features/async/manager.d.ts.map +1 -0
  25. package/dist/features/async/placeholder.d.ts +62 -0
  26. package/dist/features/async/placeholder.d.ts.map +1 -0
  27. package/dist/features/async/plugin.d.ts +60 -0
  28. package/dist/features/async/plugin.d.ts.map +1 -0
  29. package/dist/features/async/sparse.d.ts +91 -0
  30. package/dist/features/async/sparse.d.ts.map +1 -0
  31. package/dist/features/grid/index.d.ts +9 -0
  32. package/dist/features/grid/index.d.ts.map +1 -0
  33. package/dist/features/grid/layout.d.ts +29 -0
  34. package/dist/features/grid/layout.d.ts.map +1 -0
  35. package/dist/features/grid/plugin.d.ts +48 -0
  36. package/dist/features/grid/plugin.d.ts.map +1 -0
  37. package/dist/features/grid/renderer.d.ts +55 -0
  38. package/dist/features/grid/renderer.d.ts.map +1 -0
  39. package/dist/features/grid/types.d.ts +71 -0
  40. package/dist/features/grid/types.d.ts.map +1 -0
  41. package/dist/features/page/index.d.ts +8 -0
  42. package/dist/features/page/index.d.ts.map +1 -0
  43. package/dist/features/page/plugin.d.ts +53 -0
  44. package/dist/features/page/plugin.d.ts.map +1 -0
  45. package/dist/features/scale/index.d.ts +10 -0
  46. package/dist/features/scale/index.d.ts.map +1 -0
  47. package/dist/features/scale/plugin.d.ts +42 -0
  48. package/dist/features/scale/plugin.d.ts.map +1 -0
  49. package/dist/features/scrollbar/controller.d.ts +121 -0
  50. package/dist/features/scrollbar/controller.d.ts.map +1 -0
  51. package/dist/features/scrollbar/index.d.ts +8 -0
  52. package/dist/features/scrollbar/index.d.ts.map +1 -0
  53. package/dist/features/scrollbar/plugin.d.ts +60 -0
  54. package/dist/features/scrollbar/plugin.d.ts.map +1 -0
  55. package/dist/features/scrollbar/scrollbar.d.ts +73 -0
  56. package/dist/features/scrollbar/scrollbar.d.ts.map +1 -0
  57. package/dist/features/sections/index.d.ts +10 -0
  58. package/dist/features/sections/index.d.ts.map +1 -0
  59. package/dist/features/sections/layout.d.ts +46 -0
  60. package/dist/features/sections/layout.d.ts.map +1 -0
  61. package/dist/features/sections/plugin.d.ts +64 -0
  62. package/dist/features/sections/plugin.d.ts.map +1 -0
  63. package/dist/features/sections/sticky.d.ts +33 -0
  64. package/dist/features/sections/sticky.d.ts.map +1 -0
  65. package/dist/features/sections/types.d.ts +86 -0
  66. package/dist/features/sections/types.d.ts.map +1 -0
  67. package/dist/features/selection/index.d.ts +7 -0
  68. package/dist/features/selection/index.d.ts.map +1 -0
  69. package/dist/features/selection/plugin.d.ts +44 -0
  70. package/dist/features/selection/plugin.d.ts.map +1 -0
  71. package/dist/features/selection/state.d.ts +102 -0
  72. package/dist/features/selection/state.d.ts.map +1 -0
  73. package/dist/features/snapshots/index.d.ts +8 -0
  74. package/dist/features/snapshots/index.d.ts.map +1 -0
  75. package/dist/features/snapshots/plugin.d.ts +44 -0
  76. package/dist/features/snapshots/plugin.d.ts.map +1 -0
  77. package/dist/grid/index.js +1 -198
  78. package/dist/groups/index.js +1 -204
  79. package/dist/index.d.ts +17 -8
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +1 -1129
  82. package/dist/page/index.js +1 -0
  83. package/dist/plugins/groups/plugin.d.ts +3 -2
  84. package/dist/plugins/groups/plugin.d.ts.map +1 -1
  85. package/dist/react/index.js +1 -1024
  86. package/dist/react/react.js +1 -0
  87. package/dist/rendering/heights.d.ts +63 -0
  88. package/dist/rendering/heights.d.ts.map +1 -0
  89. package/dist/rendering/index.d.ts +9 -0
  90. package/dist/rendering/index.d.ts.map +1 -0
  91. package/dist/rendering/renderer.d.ts +103 -0
  92. package/dist/rendering/renderer.d.ts.map +1 -0
  93. package/dist/rendering/scale.d.ts +116 -0
  94. package/dist/rendering/scale.d.ts.map +1 -0
  95. package/dist/rendering/viewport.d.ts +139 -0
  96. package/dist/rendering/viewport.d.ts.map +1 -0
  97. package/dist/scale/index.js +1 -0
  98. package/dist/scroll/index.js +1 -116
  99. package/dist/scrollbar/index.js +1 -0
  100. package/dist/sections/index.js +1 -0
  101. package/dist/selection/index.js +1 -96
  102. package/dist/snapshots/index.js +1 -21
  103. package/dist/svelte/index.js +1 -1012
  104. package/dist/svelte/svelte.js +1 -0
  105. package/dist/vue/index.js +1 -1018
  106. package/dist/vue/vue.js +1 -0
  107. package/dist/window/index.js +1 -18
  108. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/sections/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGjE,YAAY,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,aAAa,EAAE,aAAa,IAAI,eAAe,EAAE,MAAM,SAAS,CAAC;AAG1E,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * vlist - Group Layout
3
+ * Computes group boundaries and maps between data indices and layout indices.
4
+ *
5
+ * The layout transforms a flat items array into a "layout" that includes
6
+ * group header pseudo-items interspersed at group boundaries:
7
+ *
8
+ * Data: [item0, item1, item2, item3, item4, item5]
9
+ * Groups: [ A, A, A, B, B, C ]
10
+ * Layout: [headerA, item0, item1, item2, headerB, item3, item4, headerC, item5]
11
+ * Index: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
12
+ *
13
+ * All lookups are O(log g) where g = number of groups, using binary search
14
+ * on the sorted group boundaries array.
15
+ */
16
+ import type { GroupsConfig, GroupBoundary, GroupLayout, GroupHeaderItem } from "./types";
17
+ import type { VListItem } from "../../types";
18
+ /**
19
+ * Build the transformed layout items array with header pseudo-items inserted
20
+ * at group boundaries.
21
+ *
22
+ * @param items - Original data items
23
+ * @param groups - Computed group boundaries
24
+ * @returns Array of items and header pseudo-items in layout order
25
+ */
26
+ export declare const buildLayoutItems: <T extends VListItem>(items: T[], groups: readonly GroupBoundary[]) => Array<T | GroupHeaderItem>;
27
+ /**
28
+ * Create a height function for the layout that returns the correct height
29
+ * for both group headers and data items.
30
+ *
31
+ * @param layout - The group layout instance
32
+ * @param itemHeight - Original item height config (number or function)
33
+ * @returns A height function (layoutIndex) => number suitable for HeightCache
34
+ */
35
+ export declare const createGroupedHeightFn: (layout: GroupLayout, itemHeight: number | ((index: number) => number)) => ((layoutIndex: number) => number);
36
+ /**
37
+ * Create a GroupLayout instance.
38
+ *
39
+ * The layout computes group boundaries from items and provides efficient
40
+ * O(log g) mappings between data indices and layout indices.
41
+ *
42
+ * @param itemCount - Number of data items
43
+ * @param config - Groups configuration
44
+ */
45
+ export declare const createGroupLayout: (itemCount: number, config: GroupsConfig) => GroupLayout;
46
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/features/sections/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EAEX,eAAe,EAChB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA+G7C;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,SAAS,EAClD,OAAO,CAAC,EAAE,EACV,QAAQ,SAAS,aAAa,EAAE,KAC/B,KAAK,CAAC,CAAC,GAAG,eAAe,CA0B3B,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,WAAW,EACnB,YAAY,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,KAC/C,CAAC,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAelC,CAAC;AAMF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,QAAQ,YAAY,KACnB,WAkIF,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * vlist/groups - Builder Plugin
3
+ * Adds grouped lists with sticky section headers.
4
+ *
5
+ * Priority: 10 (runs first — transforms item list and height function before rendering)
6
+ *
7
+ * What it wires:
8
+ * - Transforms item list — inserts header items at group boundaries
9
+ * - Replaces height function — headers use headerHeight, data items use configured item.height
10
+ * - Unified template — dispatches to headerTemplate for headers, user template for items
11
+ * - Sticky header DOM — creates a positioned header element that updates as you scroll
12
+ * - Index mapping — translates between data indices and layout indices
13
+ * - CSS class — adds .vlist--grouped to the root element
14
+ *
15
+ * Restrictions:
16
+ * - Items must be pre-sorted by group
17
+ * - Cannot be combined with direction: 'horizontal'
18
+ *
19
+ * Can be combined with:
20
+ * - withGrid for grouped 2D layouts
21
+ * - reverse: true (sticky header shows current section as you scroll up through history)
22
+ */
23
+ import type { VListItem } from "../../types";
24
+ import type { VListPlugin } from "../../builder/types";
25
+ /** Groups plugin configuration */
26
+ export interface GroupsPluginConfig {
27
+ /** Returns group key for item at index (required) */
28
+ getGroupForIndex: (index: number) => string;
29
+ /** Height of group headers in pixels (required) */
30
+ headerHeight: number;
31
+ /** Render function for headers (required) */
32
+ headerTemplate: (key: string, groupIndex: number) => HTMLElement | string;
33
+ /** Enable sticky headers — iOS Contacts style (default: true) */
34
+ sticky?: boolean;
35
+ }
36
+ /**
37
+ * Create a groups plugin for the builder.
38
+ *
39
+ * Adds grouped lists with sticky section headers.
40
+ *
41
+ * ```ts
42
+ * import { vlist } from 'vlist/builder'
43
+ * import { withGroups } from 'vlist/groups'
44
+ *
45
+ * const contacts = vlist({
46
+ * container: '#contacts',
47
+ * item: { height: 56, template: renderContact },
48
+ * items: sortedContacts,
49
+ * })
50
+ * .use(withGroups({
51
+ * getGroupForIndex: (i) => sortedContacts[i].lastName[0],
52
+ * headerHeight: 32,
53
+ * headerTemplate: (letter) => {
54
+ * const el = document.createElement('div')
55
+ * el.className = 'letter-header'
56
+ * el.textContent = letter
57
+ * return el
58
+ * },
59
+ * }))
60
+ * .build()
61
+ * ```
62
+ */
63
+ export declare const withSections: <T extends VListItem = VListItem>(config: GroupsPluginConfig) => VListPlugin<T>;
64
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/features/sections/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAuBvE,kCAAkC;AAClC,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAE5C,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IAErB,6CAA6C;IAC7C,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,WAAW,GAAG,MAAM,CAAC;IAE1E,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAC1D,QAAQ,kBAAkB,KACzB,WAAW,CAAC,CAAC,CAmRf,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * vlist - Sticky Header
3
+ * Manages a floating header element that "sticks" to the top of the viewport
4
+ * and transitions smoothly when the next group's header approaches.
5
+ *
6
+ * The sticky header is a separate DOM element positioned absolutely at the
7
+ * top of the root container. It overlays the scrolling content and shows
8
+ * the current group's header. When the next group's inline header scrolls
9
+ * into view, the sticky header is pushed upward to create the classic
10
+ * iOS Contacts-style transition effect.
11
+ *
12
+ * Layout:
13
+ * .vlist (root, position: relative)
14
+ * ├── .vlist-sticky-header (position: absolute, top: 0, z-index: 5)
15
+ * │ └── (content rendered by headerTemplate)
16
+ * └── .vlist-viewport
17
+ * └── .vlist-content
18
+ * └── .vlist-items
19
+ */
20
+ import type { GroupLayout, GroupsConfig, StickyHeader } from "./types";
21
+ import type { HeightCache } from "../../rendering/heights";
22
+ /**
23
+ * Create a sticky header manager.
24
+ *
25
+ * @param root - The vlist root element (.vlist) — sticky header is appended here
26
+ * @param layout - Group layout for index/group resolution
27
+ * @param heightCache - The LAYOUT height cache (includes headers)
28
+ * @param config - Groups configuration (headerTemplate, headerHeight)
29
+ * @param classPrefix - CSS class prefix (default: 'vlist')
30
+ * @returns StickyHeader instance
31
+ */
32
+ export declare const createStickyHeader: (root: HTMLElement, layout: GroupLayout, heightCache: HeightCache, config: GroupsConfig, classPrefix: string) => StickyHeader;
33
+ //# sourceMappingURL=sticky.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sticky.d.ts","sourceRoot":"","sources":["../../../src/features/sections/sticky.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAM3D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,WAAW,EACjB,QAAQ,WAAW,EACnB,aAAa,WAAW,EACxB,QAAQ,YAAY,EACpB,aAAa,MAAM,KAClB,YAgMF,CAAC"}
@@ -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 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/features/sections/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3D,YAAY,EAAE,YAAY,EAAE,CAAC;AAM7B,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IAEZ,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;IAEnB,0CAA0C;IAC1C,iBAAiB,EAAE,MAAM,CAAC;IAE1B,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IAEvB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,sEAAsE;AACtE,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAM9D;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IAEX,yBAAyB;IACzB,aAAa,EAAE,IAAI,CAAC;IAEpB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IAEjB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,OAAO,KAAG,IAAI,IAAI,eAMrD,CAAC;AAMF,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,uBAAuB;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAE1C,wDAAwD;IACxD,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,WAAW,CAAC;IAE/C,uEAAuE;IACvE,iBAAiB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;IAEnD,+CAA+C;IAC/C,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAEjD,2EAA2E;IAC3E,qBAAqB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,aAAa,CAAC;IAE9D,yEAAyE;IACzE,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa,CAAC;IAE1D,oCAAoC;IACpC,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAEhD;;;OAGG;IACH,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAMD,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpC,wEAAwE;IACxE,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB,uDAAuD;IACvD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * vlist - Selection Domain
3
+ * Selection state management
4
+ */
5
+ export { withSelection, type SelectionPluginConfig } from "./plugin";
6
+ export { createSelectionState, selectItems, deselectItems, toggleSelection, selectAll, clearSelection, setFocusedIndex, moveFocusUp, moveFocusDown, moveFocusToFirst, moveFocusToLast, moveFocusByPage, selectFocused, selectRange, getSelectedIds, getSelectedItems, getSelectionCount, isSelected, isSelectionEmpty, type SelectionState, } from "./state";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/selection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGrE,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,SAAS,EACT,cAAc,EACd,eAAe,EACf,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,KAAK,cAAc,GACpB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * vlist/selection - Builder Plugin
3
+ * Wraps the selection domain into a VListPlugin for the composable builder.
4
+ *
5
+ * Priority: 50 (runs after renderer and data are ready)
6
+ *
7
+ * What it wires:
8
+ * - Click handler on items container — toggles selection on item click
9
+ * - Keyboard handler on root — ArrowUp/Down for focus, Space/Enter for toggle
10
+ * - ARIA attributes — aria-selected on items, aria-activedescendant on root
11
+ * - Live region — announces selection changes to screen readers
12
+ * - Render integration — passes selection state to render pipeline
13
+ *
14
+ * Added methods: select, deselect, toggleSelect, selectAll, clearSelection,
15
+ * getSelected, getSelectedItems
16
+ *
17
+ * Added events: item:click, selection:change
18
+ */
19
+ import type { VListItem, SelectionMode } from "../../types";
20
+ import type { VListPlugin } from "../../builder/types";
21
+ /** Selection plugin configuration */
22
+ export interface SelectionPluginConfig {
23
+ /** Selection mode (default: 'single') */
24
+ mode?: SelectionMode;
25
+ /** Initially selected item IDs */
26
+ initial?: Array<string | number>;
27
+ }
28
+ /**
29
+ * Create a selection plugin for the builder.
30
+ *
31
+ * ```ts
32
+ * import { vlist } from 'vlist/builder'
33
+ * import { withSelection } from 'vlist/selection'
34
+ *
35
+ * const list = vlist({ ... })
36
+ * .use(withSelection({ mode: 'multiple', initial: ['id-1'] }))
37
+ * .build()
38
+ *
39
+ * list.select('id-2')
40
+ * list.getSelected() // ['id-1', 'id-2']
41
+ * ```
42
+ */
43
+ export declare const withSelection: <T extends VListItem = VListItem>(config?: SelectionPluginConfig) => VListPlugin<T>;
44
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/features/selection/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAwBvE,qCAAqC;AACrC,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,IAAI,CAAC,EAAE,aAAa,CAAC;IAErB,kCAAkC;IAClC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CAClC;AAMD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAC3D,SAAS,qBAAqB,KAC7B,WAAW,CAAC,CAAC,CAwWf,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * vlist - Selection State Management
3
+ * Pure functions for managing selection state
4
+ */
5
+ import type { VListItem, SelectionMode, SelectionState } from "../../types";
6
+ export type { SelectionState } from "../../types";
7
+ /**
8
+ * Create initial selection state
9
+ * Pure function - no side effects
10
+ */
11
+ export declare const createSelectionState: (initial?: Array<string | number>) => SelectionState;
12
+ /**
13
+ * Select items by ID
14
+ * Pure function - returns new state
15
+ */
16
+ export declare const selectItems: (state: SelectionState, ids: Array<string | number>, mode: SelectionMode) => SelectionState;
17
+ /**
18
+ * Deselect items by ID
19
+ * Pure function - returns new state
20
+ */
21
+ export declare const deselectItems: (state: SelectionState, ids: Array<string | number>) => SelectionState;
22
+ /**
23
+ * Toggle item selection
24
+ * Pure function - returns new state
25
+ */
26
+ export declare const toggleSelection: (state: SelectionState, id: string | number, mode: SelectionMode) => SelectionState;
27
+ /**
28
+ * Select all items
29
+ * Pure function - returns new state
30
+ */
31
+ export declare const selectAll: <T extends VListItem>(state: SelectionState, items: T[], mode: SelectionMode) => SelectionState;
32
+ /**
33
+ * Clear all selection
34
+ * Pure function - returns new state
35
+ */
36
+ export declare const clearSelection: (state: SelectionState) => SelectionState;
37
+ /**
38
+ * Set focused index
39
+ * Mutates state in-place to avoid allocation on hot path
40
+ */
41
+ export declare const setFocusedIndex: (state: SelectionState, index: number) => SelectionState;
42
+ /**
43
+ * Move focus up
44
+ * Mutates state in-place to avoid allocation on hot path
45
+ */
46
+ export declare const moveFocusUp: (state: SelectionState, totalItems: number, wrap?: boolean) => SelectionState;
47
+ /**
48
+ * Move focus down
49
+ * Mutates state in-place to avoid allocation on hot path
50
+ */
51
+ export declare const moveFocusDown: (state: SelectionState, totalItems: number, wrap?: boolean) => SelectionState;
52
+ /**
53
+ * Move focus to first item
54
+ * Mutates state in-place to avoid allocation on hot path
55
+ */
56
+ export declare const moveFocusToFirst: (state: SelectionState, totalItems: number) => SelectionState;
57
+ /**
58
+ * Move focus to last item
59
+ * Mutates state in-place to avoid allocation on hot path
60
+ */
61
+ export declare const moveFocusToLast: (state: SelectionState, totalItems: number) => SelectionState;
62
+ /**
63
+ * Move focus by page (for Page Up/Down)
64
+ * Mutates state in-place to avoid allocation on hot path
65
+ */
66
+ export declare const moveFocusByPage: (state: SelectionState, totalItems: number, pageSize: number, direction: "up" | "down") => SelectionState;
67
+ /**
68
+ * Check if an item is selected
69
+ * Pure function - no side effects
70
+ */
71
+ export declare const isSelected: (state: SelectionState, id: string | number) => boolean;
72
+ /**
73
+ * Get selected IDs as array
74
+ * Pure function - no side effects
75
+ */
76
+ export declare const getSelectedIds: (state: SelectionState) => Array<string | number>;
77
+ /**
78
+ * Get selected items using ID lookup (O(k) where k = selected count)
79
+ * Pure function - no side effects
80
+ */
81
+ export declare const getSelectedItems: <T extends VListItem>(state: SelectionState, getItemById: (id: string | number) => T | undefined) => T[];
82
+ /**
83
+ * Get selection count
84
+ * Pure function - no side effects
85
+ */
86
+ export declare const getSelectionCount: (state: SelectionState) => number;
87
+ /**
88
+ * Check if selection is empty
89
+ * Pure function - no side effects
90
+ */
91
+ export declare const isSelectionEmpty: (state: SelectionState) => boolean;
92
+ /**
93
+ * Handle keyboard selection (Space/Enter on focused item)
94
+ * Pure function - returns new state
95
+ */
96
+ export declare const selectFocused: <T extends VListItem>(state: SelectionState, items: T[], mode: SelectionMode) => SelectionState;
97
+ /**
98
+ * Handle shift+click range selection
99
+ * Pure function - returns new state
100
+ */
101
+ export declare const selectRange: <T extends VListItem>(state: SelectionState, items: T[], fromIndex: number, toIndex: number, mode: SelectionMode) => SelectionState;
102
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/features/selection/state.ts"],"names":[],"mappings":"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"}
@@ -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/features/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/features/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;AAMvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,GACxB,CAAC,SAAS,SAAS,GAAG,SAAS,OAC5B,WAAW,CAAC,CAAC,CA8FjB,CAAC"}