vlist 3.0.0-next.3 → 3.0.0-next.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.
package/README.github.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The virtual list library for every framework. Ultra efficient, batteries-included, and accessible with composable plugins.
4
4
 
5
- **v3.0.0-next.3** (prerelease on the npm `next` tag) — Native scrolling by default, opt-in `vlist/synthetic`, and removal of deprecated scroll configuration and plugin hooks. See the [changelog](https://github.com/floor/vlist/blob/next/CHANGELOG.md).
5
+ **v3.0.0-next.4** (prerelease on the npm `next` tag) — Native scrolling by default, opt-in `vlist/synthetic`, and removal of deprecated scroll configuration and plugin hooks. See the [changelog](https://github.com/floor/vlist/blob/next/CHANGELOG.md).
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/vlist.svg)](https://www.npmjs.com/package/vlist)
8
8
  [![bundle size](https://img.shields.io/bundlephobia/minzip/vlist)](https://bundlephobia.com/package/vlist)
@@ -11,7 +11,7 @@ The virtual list library for every framework. Ultra efficient, batteries-include
11
11
 
12
12
  - **Accessible** — `a11y()` or a selection mode adds WAI-ARIA, 2D keyboard navigation, focus recovery, screen-reader DOM ordering
13
13
  - **Zero dependencies** — framework-agnostic core with tiny adapters for Vue, Svelte, Solid, React
14
- - **9.5 KB gzipped (3.0 prerelease)** — composable plugins with perfect tree-shaking
14
+ - **10.0 KB gzipped (3.0 prerelease)** — composable plugins with perfect tree-shaking
15
15
  - **Constant memory** — ~0.1 MB overhead at any scale, from 10K to 1M+ items
16
16
  - **Tree, grid, masonry, carousel, table, groups, data, selection, search, sortable, transition** — all opt-in
17
17
  - **Axis-neutral** — vertical and horizontal scrolling through a single code path, all plugins work in both orientations
@@ -178,29 +178,29 @@ Removed mode/runway options throw a migration error before creating DOM. `vlist/
178
178
 
179
179
  | Entry / export | Minified | Gzipped |
180
180
  |---|---:|---:|
181
- | **Base (`vlist`)** | 25.7 KB | 9.5 KB |
182
- | `vlist/synthetic` | 31.7 KB | 11.7 KB |
183
- | `vlist/native` (alias) | 25.7 KB | 9.5 KB |
184
- | `a11y()` | 29.0 KB | 10.7 KB |
185
- | `selection()` | 35.1 KB | 12.3 KB |
186
- | `data()` | 39.4 KB | 14.3 KB |
187
- | `scrollbar()` | 33.9 KB | 12.4 KB |
188
- | `sortable()` | 37.5 KB | 13.0 KB |
189
- | `groups()` | 41.5 KB | 14.7 KB |
190
- | `page()` | 28.2 KB | 10.4 KB |
191
- | `snapshots()` | 29.0 KB | 10.6 KB |
192
- | `transition()` | 32.4 KB | 11.5 KB |
193
- | `autosize()` | 28.7 KB | 10.5 KB |
194
- | `grid()` | 32.5 KB | 11.9 KB |
195
- | `table()` | 44.1 KB | 15.4 KB |
196
- | `masonry()` | 36.9 KB | 13.6 KB |
197
- | `tree()` | 41.0 KB | 14.5 KB |
198
- | `search()` | 34.7 KB | 12.6 KB |
199
- | `carousel()` | 38.5 KB | 13.9 KB |
200
- | `vlist/synthetic` + `carousel()` | 44.4 KB | 16.2 KB |
201
- | `vlist/synthetic` + `sortable()` | 43.5 KB | 15.3 KB |
202
-
203
- Sizes are tree-shaken totals from `bun run size`, not additive plugin costs. Plugin rows include the native default factory plus that plugin. The base is **9,914 bytes gzipped**, below the 9.9 KB target. `bun run size` fails if a scenario fails to build, an unused plugin leaks into a bundle, or any published size exceeds its gzip budget. Synthetic input is **11,960 bytes** before plugins. The alias row measures the same source factory; the distributed alias re-exports it without duplicating the implementation.
181
+ | **Base (`vlist`)** | 26.9 KB | 10.0 KB |
182
+ | `vlist/synthetic` | 33.8 KB | 12.6 KB |
183
+ | `vlist/native` (alias) | 26.9 KB | 10.0 KB |
184
+ | `a11y()` | 30.7 KB | 11.3 KB |
185
+ | `selection()` | 36.4 KB | 12.9 KB |
186
+ | `data()` | 40.6 KB | 14.8 KB |
187
+ | `scrollbar()` | 35.1 KB | 12.8 KB |
188
+ | `sortable()` | 38.7 KB | 13.4 KB |
189
+ | `groups()` | 43.0 KB | 15.4 KB |
190
+ | `page()` | 29.5 KB | 10.9 KB |
191
+ | `snapshots()` | 30.2 KB | 11.1 KB |
192
+ | `transition()` | 33.7 KB | 12.0 KB |
193
+ | `autosize()` | 30.1 KB | 11.1 KB |
194
+ | `grid()` | 34.4 KB | 12.5 KB |
195
+ | `table()` | 45.4 KB | 15.9 KB |
196
+ | `masonry()` | 39.0 KB | 14.4 KB |
197
+ | `tree()` | 43.1 KB | 15.3 KB |
198
+ | `search()` | 36.5 KB | 13.3 KB |
199
+ | `carousel()` | 41.7 KB | 15.1 KB |
200
+ | `vlist/synthetic` + `carousel()` | 47.8 KB | 17.4 KB |
201
+ | `vlist/synthetic` + `sortable()` | 45.7 KB | 16.1 KB |
202
+
203
+ Sizes are tree-shaken totals from `bun run size`, not additive plugin costs. Plugin rows include the native default factory plus that plugin. The base is **10,200 bytes gzipped**, within the 10.0 KB budget (10,240 bytes). `bun run size` fails if a scenario fails to build, an unused plugin leaks into a bundle, or any published size exceeds its gzip budget. Synthetic input is **12,889 bytes** before plugins. The alias row measures the same source factory; the distributed alias re-exports it without duplicating the implementation.
204
204
 
205
205
  ## Examples
206
206
 
@@ -439,12 +439,14 @@ const list = createVList(config, [plugin1(), plugin2()])
439
439
 
440
440
  | Method | Description |
441
441
  |--------|-------------|
442
- | `list.select(...ids)` | Select item(s) |
442
+ | `list.select(...ids)` | Select item(s) without moving the viewport |
443
443
  | `list.deselect(...ids)` | Deselect item(s) |
444
444
  | `list.toggleSelect(id)` | Toggle |
445
445
  | `list.selectAll()` / `list.clearSelection()` | Bulk operations |
446
446
  | `list.getSelected()` | Array of selected IDs |
447
447
  | `list.getSelectedItems()` | Array of selected items |
448
+ | `list.selectNext()` | Select the next item and scroll it into view |
449
+ | `list.selectPrevious()` | Select the previous item and scroll it into view |
448
450
 
449
451
  ### Events
450
452
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The virtual list library for every framework. Ultra efficient, batteries-included, and accessible with composable plugins.
4
4
 
5
- **v3.0.0-next.3** (prerelease on the npm `next` tag) — Native scrolling by default, opt-in `vlist/synthetic`, and removal of deprecated scroll configuration and plugin hooks. See the [changelog](https://github.com/floor/vlist/blob/next/CHANGELOG.md).
5
+ **v3.0.0-next.4** (prerelease on the npm `next` tag) — Native scrolling by default, opt-in `vlist/synthetic`, and removal of deprecated scroll configuration and plugin hooks. See the [changelog](https://github.com/floor/vlist/blob/next/CHANGELOG.md).
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/vlist.svg)](https://www.npmjs.com/package/vlist)
8
8
  [![bundle size](https://img.shields.io/bundlephobia/minzip/vlist)](https://bundlephobia.com/package/vlist)
@@ -11,7 +11,7 @@ The virtual list library for every framework. Ultra efficient, batteries-include
11
11
 
12
12
  - **Accessible** — `a11y()` or a selection mode adds WAI-ARIA, 2D keyboard navigation, focus recovery, screen-reader DOM ordering
13
13
  - **Zero dependencies** — framework-agnostic core, tiny adapters for Vue, Svelte, Solid, React
14
- - **9.4 KB gzipped (3.0 prerelease)** — composable plugins with perfect tree-shaking
14
+ - **10.0 KB gzipped (3.0 prerelease)** — composable plugins with perfect tree-shaking
15
15
  - **Constant memory** — ~0.1 MB overhead at any scale, from 10K to 1M+ items
16
16
  - **Axis-neutral** — vertical and horizontal scrolling through a single code path, all plugins work in both orientations
17
17
 
@@ -124,29 +124,29 @@ Removed mode/runway options throw a migration error before creating DOM. `vlist/
124
124
 
125
125
  | Entry / export | Minified | Gzipped |
126
126
  |---|---:|---:|
127
- | **Base (`vlist`)** | 25.7 KB | 9.4 KB |
128
- | `vlist/synthetic` | 31.7 KB | 11.7 KB |
129
- | `vlist/native` (alias) | 25.7 KB | 9.5 KB |
130
- | `a11y()` | 29.0 KB | 10.7 KB |
131
- | `selection()` | 35.1 KB | 12.3 KB |
132
- | `data()` | 39.4 KB | 14.3 KB |
133
- | `scrollbar()` | 33.9 KB | 12.3 KB |
134
- | `sortable()` | 37.4 KB | 12.9 KB |
135
- | `groups()` | 41.4 KB | 14.7 KB |
136
- | `page()` | 28.2 KB | 10.3 KB |
137
- | `snapshots()` | 29.0 KB | 10.6 KB |
138
- | `transition()` | 32.4 KB | 11.4 KB |
139
- | `autosize()` | 28.8 KB | 10.5 KB |
140
- | `grid()` | 32.6 KB | 11.8 KB |
141
- | `table()` | 44.2 KB | 15.3 KB |
142
- | `masonry()` | 37.0 KB | 13.5 KB |
143
- | `tree()` | 41.0 KB | 14.5 KB |
144
- | `search()` | 34.7 KB | 12.6 KB |
145
- | `carousel()` | 38.5 KB | 13.9 KB |
146
- | `vlist/synthetic` + `carousel()` | 44.4 KB | 16.1 KB |
147
- | `vlist/synthetic` + `sortable()` | 43.4 KB | 15.2 KB |
148
-
149
- Sizes are tree-shaken totals from `bun run size`, not additive plugin costs. Plugin rows include the native default factory plus that plugin. The base is **9,914 bytes gzipped**, below the 9.9 KB target. `bun run size` fails if a scenario fails to build, an unused plugin leaks into a bundle, or any published size exceeds its gzip budget. Synthetic input is **11,960 bytes** before plugins. The alias row measures the same source factory; the distributed alias re-exports it without duplicating the implementation.
127
+ | **Base (`vlist`)** | 26.9 KB | 10.0 KB |
128
+ | `vlist/synthetic` | 33.8 KB | 12.6 KB |
129
+ | `vlist/native` (alias) | 26.9 KB | 10.0 KB |
130
+ | `a11y()` | 30.7 KB | 11.3 KB |
131
+ | `selection()` | 36.4 KB | 12.9 KB |
132
+ | `data()` | 40.6 KB | 14.8 KB |
133
+ | `scrollbar()` | 35.1 KB | 12.8 KB |
134
+ | `sortable()` | 38.7 KB | 13.4 KB |
135
+ | `groups()` | 43.0 KB | 15.4 KB |
136
+ | `page()` | 29.5 KB | 10.9 KB |
137
+ | `snapshots()` | 30.2 KB | 11.1 KB |
138
+ | `transition()` | 33.7 KB | 12.0 KB |
139
+ | `autosize()` | 30.1 KB | 11.1 KB |
140
+ | `grid()` | 34.4 KB | 12.5 KB |
141
+ | `table()` | 45.4 KB | 15.9 KB |
142
+ | `masonry()` | 39.0 KB | 14.4 KB |
143
+ | `tree()` | 43.1 KB | 15.3 KB |
144
+ | `search()` | 36.5 KB | 13.3 KB |
145
+ | `carousel()` | 41.7 KB | 15.1 KB |
146
+ | `vlist/synthetic` + `carousel()` | 47.8 KB | 17.4 KB |
147
+ | `vlist/synthetic` + `sortable()` | 45.7 KB | 16.1 KB |
148
+
149
+ Sizes are tree-shaken totals from `bun run size`, not additive plugin costs. Plugin rows include the native default factory plus that plugin. The base is **10,200 bytes gzipped**, within the 10.0 KB budget (10,240 bytes). `bun run size` fails if a scenario fails to build, an unused plugin leaks into a bundle, or any published size exceeds its gzip budget. Synthetic input is **12,889 bytes** before plugins. The alias row measures the same source factory; the distributed alias re-exports it without duplicating the implementation.
150
150
 
151
151
  ## Framework Adapters
152
152
 
package/dist/config.d.ts CHANGED
@@ -52,7 +52,7 @@ export interface VListConfig<T extends VListItem = VListItem> extends Omit<Creat
52
52
  /** Masonry layout options — applied when `layout: "masonry"`. */
53
53
  masonry?: MasonryPluginConfig;
54
54
  /** Sticky group headers. */
55
- groups?: GroupsConfig;
55
+ groups?: GroupsConfig<T>;
56
56
  /**
57
57
  * Row selection (single / multi). Omit it for a display-only list: nothing
58
58
  * is wired then, so the list keeps `role="list"` and stays out of the tab
@@ -87,8 +87,11 @@ export interface VListConfig<T extends VListItem = VListItem> extends Omit<Creat
87
87
  * the convenience fields: a plugin whose `name` matches an auto-wired one
88
88
  * (e.g. passing `grid()` while `layout: "grid"` is set) replaces it rather
89
89
  * than duplicating; plugins with new names are appended.
90
+ *
91
+ * Looser than `createVList`'s plugin list: a plugin explicitly typed for a
92
+ * different item, such as `groups<Other>()`, is accepted with no check.
90
93
  */
91
- plugins?: VListPlugin<T>[];
94
+ plugins?: VListPlugin<any, any>[];
92
95
  }
93
96
  /**
94
97
  * Translate a {@link VListConfig} into the ordered plugin array that the core
@@ -138,7 +141,7 @@ export type ConfigMethods<T extends VListItem, C extends VListConfig<T>> = Field
138
141
  layout: "grid";
139
142
  } ? GridMethods : {}) & (C extends {
140
143
  layout: "masonry";
141
- } ? MasonryMethods : {}) & Field<C, "groups", GroupsMethods> & Field<C, "selection", SelectionMethods<T>> & Field<C, "scrollbar", ScrollbarMethods> & Field<C, "snapshots", SnapshotsMethods> & Estimated<C> & (C extends {
144
+ } ? MasonryMethods : {}) & Field<C, "groups", GroupsMethods<T>> & Field<C, "selection", SelectionMethods<T>> & Field<C, "scrollbar", ScrollbarMethods> & Field<C, "snapshots", SnapshotsMethods> & Estimated<C> & (C extends {
142
145
  plugins: infer P extends readonly unknown[];
143
146
  } ? PluginMethods<P> : {});
144
147
  /**
@@ -153,19 +156,41 @@ export type ConfigItem<C> = C extends {
153
156
  template: (item: infer T extends VListItem, ...rest: never[]) => unknown;
154
157
  };
155
158
  } ? T : VListItem;
159
+ /**
160
+ * {@link VListConfig} with everything but `items` blocked as an inference site,
161
+ * so `items` decides the item type and every callback is *checked* against it.
162
+ *
163
+ * Blocking the template alone was not enough: a grouping callback annotated for
164
+ * a supertype (`entity?: Entity` on a list of `Row`) is a second candidate, and
165
+ * it widened the whole list to `Entity` — `getItemAt()` lost `category`, and
166
+ * `setItems()` accepted an item without it. A callback for a supertype is still
167
+ * accepted, as it should be: it safely takes every `Row`.
168
+ */
169
+ type CheckedConfig<T extends VListItem> = VListConfig<NoInfer<T>>;
156
170
  /**
157
171
  * Create a vlist instance from a high-level {@link VListConfig}, resolving its
158
172
  * feature fields into plugins via {@link resolvePlugins}. This is the single
159
173
  * entry point every framework adapter delegates to.
160
174
  *
161
- * One type parameter, the config itself: the item type comes from its `items`
162
- * or `template`, and the list's methods from its feature fields
163
- * ({@link ConfigMethods}). Do not pass a type argument — `createVListFromConfig<Row>`
164
- * would name a config type, not an item type, and fail to compile; the same
165
- * trap `createVList<Row>` falls into is closed here by having no second slot.
175
+ * The item type comes from `items` when present, otherwise the template, and
176
+ * the list's methods from the config's feature fields ({@link ConfigMethods}).
177
+ * Do not pass a type argument — `createVListFromConfig<Row>` does not compile
178
+ * (TypeScript requires both parameters), so the partial-argument trap
179
+ * `createVList<Row>` falls into stays closed.
180
+ *
181
+ * `groups.getGroupForIndex` is typed with that item: an inline callback
182
+ * receives `item?: T`, not `any`, and a callback written for a different
183
+ * item type is a type error, including when `groups` is optional on the
184
+ * input type.
166
185
  */
167
- export declare function createVListFromConfig<const C extends VListConfig<any> & {
186
+ export declare function createVListFromConfig<T extends VListItem, const C extends CheckedConfig<T> & {
187
+ container: HTMLElement | string;
188
+ items: readonly T[];
189
+ }>(config: {
190
+ items: readonly T[];
191
+ } & CheckedConfig<T> & C): VList<T> & ConfigMethods<T, C>;
192
+ export declare function createVListFromConfig<T extends VListItem, const C extends VListConfig<T> & {
168
193
  container: HTMLElement | string;
169
- }>(config: C): VList<ConfigItem<C>> & ConfigMethods<ConfigItem<C>, C>;
194
+ }>(config: VListConfig<T> & C): VList<T> & ConfigMethods<T, C>;
170
195
  export {};
171
196
  //# sourceMappingURL=config.d.ts.map