vlist 1.6.1 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.github.md +28 -309
- package/README.md +1 -1
- package/dist/features/page/feature.d.ts +57 -1
- package/dist/features/page/index.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/internals.js +1 -1
- package/dist/size.json +1 -1
- package/package.json +1 -1
package/README.github.md
CHANGED
|
@@ -2,46 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
The virtual list library for every framework. Accessible by default, batteries-included, with composable features — in 10.5 KB.
|
|
4
4
|
|
|
5
|
-
**v1.6.1** — [Changelog](./changelog.txt)
|
|
6
|
-
|
|
7
5
|
[](https://www.npmjs.com/package/vlist)
|
|
8
6
|
[](https://github.com/floor/vlist/actions/workflows/ci.yml)
|
|
9
7
|
[](https://github.com/floor/vlist/blob/main/LICENSE)
|
|
10
8
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
9
|
+
- **Zero dependencies** — framework-agnostic core, tiny adapters for Vue, Svelte, Solid, React
|
|
10
|
+
- **Accessible** — WAI-ARIA, 2D keyboard navigation, focus recovery, screen-reader DOM ordering
|
|
13
11
|
- **10.5 KB gzipped** — composable features with perfect tree-shaking
|
|
14
12
|
- **Constant memory** — ~0.1 MB overhead at any scale, from 10K to 1M+ items
|
|
15
|
-
- **Grid, masonry, table, groups, async, selection, scale** — all opt-in
|
|
16
|
-
- **Vertical & horizontal** — dimension-agnostic API, every layout mode works in both orientations
|
|
17
|
-
|
|
18
|
-
**18 interactive examples, docs & benchmarks → [vlist.io](https://vlist.io)**
|
|
19
|
-
|
|
20
|
-
## Why vlist
|
|
21
|
-
|
|
22
|
-
| | vlist | TanStack Virtual | react-virtuoso | virtua | vue-virtual-scroller |
|
|
23
|
-
|---|---|---|---|---|---|
|
|
24
|
-
| **A11y built-in** | WAI-ARIA + 2D keyboard | None (DIY) | Partial | Minimal | None |
|
|
25
|
-
| **Grid + Masonry + Table** | All | Grid only | Grid + Table | Grid only | None |
|
|
26
|
-
| **Vue** | 0.6 KB adapter | Yes | — | Yes | 11.8 KB |
|
|
27
|
-
| **Svelte** | 0.5 KB adapter | Yes | — | Yes | — |
|
|
28
|
-
| **Solid** | 0.5 KB adapter | Yes | — | Yes | — |
|
|
29
|
-
| **Vanilla JS** | Native | Yes | — | — | — |
|
|
30
|
-
| **Constant memory** | ~0.1 MB at 1M | No | No | No | No |
|
|
31
|
-
|
|
32
|
-
## Framework Adapters
|
|
33
13
|
|
|
34
|
-
|
|
35
|
-
|-----------|---------|------|
|
|
36
|
-
| Vanilla JS | `vlist` | Native — no adapter needed |
|
|
37
|
-
| Vue | [`vlist-vue`](https://github.com/floor/vlist-vue) | 0.6 KB gzip |
|
|
38
|
-
| Svelte | [`vlist-svelte`](https://github.com/floor/vlist-svelte) | 0.5 KB gzip |
|
|
39
|
-
| SolidJS | [`vlist-solidjs`](https://github.com/floor/vlist-solidjs) | 0.5 KB gzip |
|
|
40
|
-
| React | [`vlist-react`](https://github.com/floor/vlist-react) | 0.6 KB gzip |
|
|
14
|
+
## Install
|
|
41
15
|
|
|
42
16
|
```bash
|
|
43
|
-
npm install vlist
|
|
44
|
-
npm install vlist vlist-vue # or vlist-svelte / vlist-solidjs / vlist-react
|
|
17
|
+
npm install vlist
|
|
45
18
|
```
|
|
46
19
|
|
|
47
20
|
## Quick Start
|
|
@@ -62,303 +35,49 @@ const list = vlist({
|
|
|
62
35
|
template: (item) => `<div>${item.name}</div>`,
|
|
63
36
|
},
|
|
64
37
|
}).build()
|
|
65
|
-
|
|
66
|
-
list.scrollToIndex(10)
|
|
67
|
-
list.setItems(newItems)
|
|
68
|
-
list.on('item:click', ({ item }) => console.log(item))
|
|
69
38
|
```
|
|
70
39
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Start with the base, add only what you need:
|
|
40
|
+
Add features with the builder pattern:
|
|
74
41
|
|
|
75
42
|
```typescript
|
|
76
|
-
import { vlist, withGrid,
|
|
43
|
+
import { vlist, withGrid, withSelection } from 'vlist'
|
|
77
44
|
|
|
78
|
-
const list = vlist({
|
|
79
|
-
container: '#app',
|
|
80
|
-
items: photos,
|
|
81
|
-
item: { height: 200, template: renderPhoto },
|
|
82
|
-
})
|
|
45
|
+
const list = vlist({ container: '#app', items, item: { height: 200, template: render } })
|
|
83
46
|
.use(withGrid({ columns: 4, gap: 16 }))
|
|
84
|
-
.use(withGroups({
|
|
85
|
-
getGroupForIndex: (i) => photos[i].category,
|
|
86
|
-
header: { height: 40, template: (cat) => `<h2>${cat}</h2>` },
|
|
87
|
-
}))
|
|
88
47
|
.use(withSelection({ mode: 'multiple' }))
|
|
89
48
|
.build()
|
|
90
49
|
```
|
|
91
50
|
|
|
92
|
-
|
|
51
|
+
## Features
|
|
93
52
|
|
|
94
53
|
| Feature | Size | Description |
|
|
95
54
|
|---------|------|-------------|
|
|
96
|
-
| **Base** | 10.5 KB |
|
|
97
|
-
| `withGrid()` | +3.8 KB | 2D grid layout
|
|
98
|
-
| `withMasonry()` | +3.3 KB | Pinterest-style masonry
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
55
|
+
| **Base** | 10.5 KB | Virtualization, ARIA, keyboard nav, gap, padding |
|
|
56
|
+
| `withGrid()` | +3.8 KB | 2D grid layout |
|
|
57
|
+
| `withMasonry()` | +3.3 KB | Pinterest-style masonry with lane-aware keyboard nav |
|
|
58
|
+
| `withTable()` | +5.5 KB | Data table with columns, resize, sort |
|
|
59
|
+
| `withGroups()` | +2.7 KB | Sticky/inline headers |
|
|
60
|
+
| `withAsync()` | +4.5 KB | Lazy loading with velocity-aware fetching |
|
|
61
|
+
| `withSelection()` | +2.7 KB | Single/multiple selection with 2D keyboard nav |
|
|
102
62
|
| `withScale()` | +3.1 KB | 1M+ items via scroll compression |
|
|
103
|
-
| `withScrollbar()` | +1.1 KB | Custom scrollbar UI |
|
|
104
|
-
| `withTable()` | +5.5 KB | Data table with columns, resize, sort, groups |
|
|
105
63
|
| `withAutoSize()` | +0.9 KB | Auto-measure items via ResizeObserver |
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
|
|
109
|
-
## Examples
|
|
110
|
-
|
|
111
|
-
More examples at **[vlist.io](https://vlist.io)**.
|
|
112
|
-
|
|
113
|
-
### Data Table
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
import { vlist, withTable, withSelection } from 'vlist'
|
|
117
|
-
|
|
118
|
-
const table = vlist({
|
|
119
|
-
container: '#my-table',
|
|
120
|
-
items: contacts,
|
|
121
|
-
item: { height: 36, template: () => '' },
|
|
122
|
-
})
|
|
123
|
-
.use(withTable({
|
|
124
|
-
columns: [
|
|
125
|
-
{ key: 'name', label: 'Name', width: 200, sortable: true },
|
|
126
|
-
{ key: 'email', label: 'Email', width: 260, sortable: true },
|
|
127
|
-
{ key: 'role', label: 'Role', width: 160, sortable: true },
|
|
128
|
-
{ key: 'status', label: 'Status', width: 100, align: 'center' },
|
|
129
|
-
],
|
|
130
|
-
rowHeight: 36,
|
|
131
|
-
headerHeight: 36,
|
|
132
|
-
resizable: true,
|
|
133
|
-
}))
|
|
134
|
-
.use(withSelection({ mode: 'single' }))
|
|
135
|
-
.build()
|
|
136
|
-
|
|
137
|
-
table.on('column:sort', ({ key, direction }) => { /* re-sort data */ })
|
|
138
|
-
table.on('column:resize', ({ key, width }) => { /* persist widths */ })
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Grid Layout
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import { vlist, withGrid, withScrollbar } from 'vlist'
|
|
145
|
-
|
|
146
|
-
const gallery = vlist({
|
|
147
|
-
container: '#gallery',
|
|
148
|
-
items: photos,
|
|
149
|
-
item: {
|
|
150
|
-
height: 200,
|
|
151
|
-
template: (photo) => `
|
|
152
|
-
<div class="card">
|
|
153
|
-
<img src="${photo.url}" />
|
|
154
|
-
<span>${photo.title}</span>
|
|
155
|
-
</div>
|
|
156
|
-
`,
|
|
157
|
-
},
|
|
158
|
-
})
|
|
159
|
-
.use(withGrid({ columns: 4, gap: 16 }))
|
|
160
|
-
.use(withScrollbar({ autoHide: true }))
|
|
161
|
-
.build()
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Async Loading
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
import { vlist, withAsync } from 'vlist'
|
|
168
|
-
|
|
169
|
-
const list = vlist({
|
|
170
|
-
container: '#list',
|
|
171
|
-
item: {
|
|
172
|
-
height: 64,
|
|
173
|
-
template: (item) => item
|
|
174
|
-
? `<div>${item.name}</div>`
|
|
175
|
-
: `<div class="placeholder">Loading…</div>`,
|
|
176
|
-
},
|
|
177
|
-
})
|
|
178
|
-
.use(withAsync({
|
|
179
|
-
adapter: {
|
|
180
|
-
read: async ({ offset, limit }) => {
|
|
181
|
-
const res = await fetch(`/api/users?offset=${offset}&limit=${limit}`)
|
|
182
|
-
const data = await res.json()
|
|
183
|
-
return { items: data.items, total: data.total, hasMore: data.hasMore }
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
}))
|
|
187
|
-
.build()
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Accessibility
|
|
191
|
-
|
|
192
|
-
Every vlist is accessible by default following the [WAI-ARIA listbox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/):
|
|
193
|
-
|
|
194
|
-
- **Arrow keys** move focus between items with a visible focus ring
|
|
195
|
-
- **2D navigation** in grids and masonry — Up/Down by row, Left/Right by cell
|
|
196
|
-
- **Masonry lane-aware nav** — arrows stay in the same visual column
|
|
197
|
-
- **Home/End, PageUp/PageDown, Ctrl+Home/End** — full keyboard coverage
|
|
198
|
-
- **Screen-reader DOM ordering** — items reordered on scroll idle for correct reading order
|
|
199
|
-
- **ARIA live region** — announces loading state changes
|
|
200
|
-
- **Focus recovery** — maintains focus when items are removed
|
|
201
|
-
|
|
202
|
-
Set `interactive: false` for display-only lists (log viewers, activity feeds) where items contain their own interactive elements.
|
|
203
|
-
|
|
204
|
-
## API
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
const list = vlist(config).use(...features).build()
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Data
|
|
211
|
-
|
|
212
|
-
| Method | Description |
|
|
213
|
-
|--------|-------------|
|
|
214
|
-
| `list.setItems(items)` | Replace all items |
|
|
215
|
-
| `list.appendItems(items)` | Add to end (auto-scrolls in reverse mode) |
|
|
216
|
-
| `list.prependItems(items)` | Add to start (preserves scroll position) |
|
|
217
|
-
| `list.updateItem(index, partial)` | Update a single item by index |
|
|
218
|
-
| `list.removeItem(index)` | Remove by index |
|
|
219
|
-
| `list.getItemAt(index)` | Get item at index |
|
|
220
|
-
| `list.getIndexById(id)` | Get index by item ID |
|
|
221
|
-
| `list.reload()` | Re-fetch from adapter (async) |
|
|
222
|
-
|
|
223
|
-
### Navigation
|
|
224
|
-
|
|
225
|
-
| Method | Description |
|
|
226
|
-
|--------|-------------|
|
|
227
|
-
| `list.scrollToIndex(i, align?)` | Scroll to index (`'start'` \| `'center'` \| `'end'`) |
|
|
228
|
-
| `list.scrollToIndex(i, opts?)` | With `{ align, behavior: 'smooth', duration }` |
|
|
229
|
-
| `list.cancelScroll()` | Cancel smooth scroll animation |
|
|
230
|
-
| `list.getScrollPosition()` | Current scroll offset |
|
|
231
|
-
|
|
232
|
-
### Selection (with `withSelection()`)
|
|
233
|
-
|
|
234
|
-
| Method | Description |
|
|
235
|
-
|--------|-------------|
|
|
236
|
-
| `list.select(...ids)` | Select item(s) |
|
|
237
|
-
| `list.deselect(...ids)` | Deselect item(s) |
|
|
238
|
-
| `list.toggleSelect(id)` | Toggle |
|
|
239
|
-
| `list.selectAll()` / `list.clearSelection()` | Bulk operations |
|
|
240
|
-
| `list.getSelected()` | Array of selected IDs |
|
|
241
|
-
| `list.getSelectedItems()` | Array of selected items |
|
|
242
|
-
|
|
243
|
-
### Events
|
|
244
|
-
|
|
245
|
-
`list.on()` returns an unsubscribe function. You can also use `list.off(event, handler)`.
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
list.on('scroll', ({ scrollPosition, direction }) => {})
|
|
249
|
-
list.on('range:change', ({ range }) => {})
|
|
250
|
-
list.on('item:click', ({ item, index, event }) => {})
|
|
251
|
-
list.on('item:dblclick', ({ item, index, event }) => {})
|
|
252
|
-
list.on('selection:change', ({ selectedIds, selectedItems }) => {})
|
|
253
|
-
list.on('load:start', ({ offset, limit }) => {})
|
|
254
|
-
list.on('load:end', ({ items, offset, total }) => {})
|
|
255
|
-
list.on('load:error', ({ error, offset, limit }) => {})
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Properties
|
|
259
|
-
|
|
260
|
-
| Property | Description |
|
|
261
|
-
|----------|-------------|
|
|
262
|
-
| `list.element` | Root DOM element |
|
|
263
|
-
| `list.items` | Current items (readonly) |
|
|
264
|
-
| `list.total` | Total item count |
|
|
265
|
-
| `list.destroy()` | Cleanup and remove from DOM |
|
|
266
|
-
|
|
267
|
-
## Feature Configuration
|
|
268
|
-
|
|
269
|
-
Each feature's config is fully typed — hover in your IDE for details.
|
|
270
|
-
|
|
271
|
-
```typescript
|
|
272
|
-
withGrid({ columns: 4, gap: 16 })
|
|
273
|
-
withMasonry({ columns: 4, gap: 16 })
|
|
274
|
-
withGroups({ getGroupForIndex, header: { height, template }, sticky?: true })
|
|
275
|
-
withSelection({ mode: 'single' | 'multiple', initial?: [...ids] })
|
|
276
|
-
withAsync({ adapter: { read }, loading?: { cancelThreshold? } })
|
|
277
|
-
withTable({ columns, rowHeight, headerHeight?, resizable? })
|
|
278
|
-
withAutoSize() // auto-measure items (requires estimatedHeight)
|
|
279
|
-
withScale() // auto-activates at 16.7M px
|
|
280
|
-
withScrollbar({ autoHide?, autoHideDelay?, minThumbSize? })
|
|
281
|
-
withPage() // no config — uses document scroll
|
|
282
|
-
withSnapshots({ autoSave: 'key' }) // automatic sessionStorage save/restore
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
Full configuration reference → **[vlist.io](https://vlist.io)**
|
|
286
|
-
|
|
287
|
-
## Base Configuration
|
|
288
|
-
|
|
289
|
-
| Option | Default | Description |
|
|
290
|
-
|--------|---------|-------------|
|
|
291
|
-
| `overscan` | `3` | Extra items rendered outside viewport |
|
|
292
|
-
| `ariaLabel` | — | Accessible label for the listbox |
|
|
293
|
-
| `orientation` | `'vertical'` | `'vertical'` or `'horizontal'` scroll direction |
|
|
294
|
-
| `padding` | `0` | Content inset — number, `[v, h]`, or `[top, right, bottom, left]` |
|
|
295
|
-
| `interactive` | `true` | Enable built-in keyboard navigation |
|
|
296
|
-
| `reverse` | `false` | Reverse mode for chat UIs |
|
|
297
|
-
| `scroll.wrap` | `false` | Wrap focus around at boundaries |
|
|
298
|
-
|
|
299
|
-
## Styling
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
import 'vlist/styles' // core (always required)
|
|
303
|
-
import 'vlist/styles/grid' // when using withGrid()
|
|
304
|
-
import 'vlist/styles/masonry' // when using withMasonry()
|
|
305
|
-
import 'vlist/styles/table' // when using withTable()
|
|
306
|
-
import 'vlist/styles/extras' // optional (variants, loading states, animations)
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
Dark mode works out of the box via `prefers-color-scheme`, Tailwind's `.dark` class, or `data-theme-mode="dark"`. Override CSS custom properties to match your design system. See [vlist.io/tutorials/styling](https://vlist.io/tutorials/styling) for the full guide.
|
|
310
|
-
|
|
311
|
-
## Performance
|
|
312
|
-
|
|
313
|
-
| Dataset Size | After Render | Scroll Delta |
|
|
314
|
-
|--------------|-------------|--------------|
|
|
315
|
-
| 10K items | 0.07 MB | ~0 MB |
|
|
316
|
-
| 100K items | 0.08 MB | ~0 MB |
|
|
317
|
-
| 1M items | 0.09 MB | 0.19 MB |
|
|
318
|
-
|
|
319
|
-
- **Initial render:** ~8ms (constant, regardless of item count)
|
|
320
|
-
- **Scroll:** 120 FPS at any scale
|
|
321
|
-
- **DOM nodes:** ~26 in document with 100K items (visible + overscan only)
|
|
322
|
-
|
|
323
|
-
Live benchmarks against 9 competitors → **[vlist.io/benchmarks](https://vlist.io/benchmarks)**
|
|
324
|
-
|
|
325
|
-
## TypeScript
|
|
326
|
-
|
|
327
|
-
Fully typed. Generic over your item type:
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
import { vlist, withGrid, type VList } from 'vlist'
|
|
64
|
+
| `withScrollbar()` | +1.1 KB | Custom scrollbar UI |
|
|
65
|
+
| `withPage()` | +0.9 KB | Window-level scrolling |
|
|
66
|
+
| `withSnapshots()` | +0.7 KB | Scroll position save/restore |
|
|
331
67
|
|
|
332
|
-
|
|
68
|
+
## Framework Adapters
|
|
333
69
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
},
|
|
341
|
-
})
|
|
342
|
-
.use(withGrid({ columns: 4 }))
|
|
343
|
-
.build()
|
|
344
|
-
```
|
|
70
|
+
| Framework | Package | Size |
|
|
71
|
+
|-----------|---------|------|
|
|
72
|
+
| Vue | [`vlist-vue`](https://github.com/floor/vlist-vue) | 0.6 KB |
|
|
73
|
+
| Svelte | [`vlist-svelte`](https://github.com/floor/vlist-svelte) | 0.5 KB |
|
|
74
|
+
| SolidJS | [`vlist-solidjs`](https://github.com/floor/vlist-solidjs) | 0.5 KB |
|
|
75
|
+
| React | [`vlist-react`](https://github.com/floor/vlist-react) | 0.6 KB |
|
|
345
76
|
|
|
346
|
-
##
|
|
77
|
+
## Docs & Examples
|
|
347
78
|
|
|
348
|
-
|
|
349
|
-
2. Run `bun test` and `bun run build` before submitting
|
|
79
|
+
**18 interactive examples, full API reference, tutorials, and live benchmarks → [vlist.io](https://vlist.io)**
|
|
350
80
|
|
|
351
81
|
## License
|
|
352
82
|
|
|
353
|
-
[MIT](LICENSE)
|
|
354
|
-
|
|
355
|
-
## Links
|
|
356
|
-
|
|
357
|
-
- **Docs & Examples:** [vlist.io](https://vlist.io)
|
|
358
|
-
- **GitHub:** [github.com/floor/vlist](https://github.com/floor/vlist)
|
|
359
|
-
- **NPM:** [vlist](https://www.npmjs.com/package/vlist)
|
|
360
|
-
- **Issues:** [GitHub Issues](https://github.com/floor/vlist/issues)
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
Built by [Floor IO](https://floor.io)
|
|
83
|
+
[MIT](LICENSE) — Built by [Floor IO](https://floor.io)
|
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ const list = vlist({ container: '#app', items, item: { height: 200, template: re
|
|
|
62
62
|
| `withScale()` | +3.1 KB | 1M+ items via scroll compression |
|
|
63
63
|
| `withAutoSize()` | +0.9 KB | Auto-measure items via ResizeObserver |
|
|
64
64
|
| `withScrollbar()` | +1.1 KB | Custom scrollbar UI |
|
|
65
|
-
| `withPage()` | +0.
|
|
65
|
+
| `withPage()` | +0.9 KB | Window-level scrolling |
|
|
66
66
|
| `withSnapshots()` | +0.7 KB | Scroll position save/restore |
|
|
67
67
|
|
|
68
68
|
## Framework Adapters
|
|
@@ -13,11 +13,56 @@
|
|
|
13
13
|
* - Uses window.innerWidth/innerHeight for container dimensions
|
|
14
14
|
* - Listens to window resize events instead of ResizeObserver
|
|
15
15
|
* - Adjusts DOM styles (overflow: visible, height: auto)
|
|
16
|
+
* - Optionally accounts for fixed/sticky chrome via scrollPadding
|
|
17
|
+
* - Uses behavior: "instant" on all scrollTo calls to override CSS
|
|
18
|
+
* scroll-behavior: smooth that may be set on the page
|
|
16
19
|
*
|
|
17
20
|
* Bundle impact: ~0.3 KB gzipped when used
|
|
18
21
|
*/
|
|
19
22
|
import type { VListItem } from "../../types";
|
|
20
23
|
import type { VListFeature } from "../../builder/types";
|
|
24
|
+
/**
|
|
25
|
+
* Options for the window scroll mode feature.
|
|
26
|
+
*/
|
|
27
|
+
export interface WithPageOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Scroll padding — insets from the viewport edges where fixed/sticky
|
|
30
|
+
* elements (headers, footers, toolbars) live.
|
|
31
|
+
*
|
|
32
|
+
* When keyboard focus moves an item behind a sticky bar, the list
|
|
33
|
+
* auto-scrolls to keep it within the visible (unobstructed) area.
|
|
34
|
+
* Also affects `scrollToIndex` alignment (start/center/end).
|
|
35
|
+
*
|
|
36
|
+
* Mirrors CSS `scroll-padding` semantics: defines the optimal viewing
|
|
37
|
+
* region within the scrollport.
|
|
38
|
+
*
|
|
39
|
+
* Values can be numbers (pixels) or functions that return pixels
|
|
40
|
+
* (useful when the sticky element's height is dynamic).
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* withPage({
|
|
45
|
+
* scrollPadding: { top: 60, bottom: 50 }
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Dynamic values
|
|
50
|
+
* ```ts
|
|
51
|
+
* withPage({
|
|
52
|
+
* scrollPadding: {
|
|
53
|
+
* top: () => document.getElementById('sticky-header')!.offsetHeight,
|
|
54
|
+
* bottom: 50
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
scrollPadding?: {
|
|
60
|
+
top?: number | (() => number);
|
|
61
|
+
bottom?: number | (() => number);
|
|
62
|
+
left?: number | (() => number);
|
|
63
|
+
right?: number | (() => number);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
21
66
|
/**
|
|
22
67
|
* Create a window scroll mode feature.
|
|
23
68
|
*
|
|
@@ -38,6 +83,17 @@ import type { VListFeature } from "../../builder/types";
|
|
|
38
83
|
* .build()
|
|
39
84
|
* ```
|
|
40
85
|
*
|
|
86
|
+
* @example With scroll padding for sticky chrome
|
|
87
|
+
* ```ts
|
|
88
|
+
* const feed = vlist({
|
|
89
|
+
* container: '#infinite-feed',
|
|
90
|
+
* item: { height: 200, template: renderPost },
|
|
91
|
+
* items: posts
|
|
92
|
+
* })
|
|
93
|
+
* .use(withPage({ scrollPadding: { top: 60, bottom: 50 } }))
|
|
94
|
+
* .build()
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
41
97
|
* @example Horizontal window scrolling
|
|
42
98
|
* ```ts
|
|
43
99
|
* const timeline = vlist({
|
|
@@ -49,5 +105,5 @@ import type { VListFeature } from "../../builder/types";
|
|
|
49
105
|
* .build()
|
|
50
106
|
* ```
|
|
51
107
|
*/
|
|
52
|
-
export declare const withPage: <T extends VListItem = VListItem>() => VListFeature<T>;
|
|
108
|
+
export declare const withPage: <T extends VListItem = VListItem>(options?: WithPageOptions) => VListFeature<T>;
|
|
53
109
|
//# sourceMappingURL=feature.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type { ScaleConfig } from "./features/scale";
|
|
|
14
14
|
export { withAsync } from "./features/async";
|
|
15
15
|
export { withScrollbar } from "./features/scrollbar";
|
|
16
16
|
export { withPage } from "./features/page";
|
|
17
|
+
export type { WithPageOptions } from "./features/page";
|
|
17
18
|
export { withGroups } from "./features/groups";
|
|
18
19
|
export { withGrid } from "./features/grid";
|
|
19
20
|
export { withMasonry } from "./features/masonry";
|