@floor/vlist 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -21
- package/dist/builder/scroll.d.ts +1 -1
- package/dist/builder/types.d.ts +6 -4
- package/dist/features/{sections → groups}/feature.d.ts +3 -4
- package/dist/features/{sections → groups}/index.d.ts +2 -2
- package/dist/features/table/feature.d.ts +67 -0
- package/dist/features/table/header.d.ts +49 -0
- package/dist/features/table/index.d.ts +10 -0
- package/dist/features/table/layout.d.ts +26 -0
- package/dist/features/table/renderer.d.ts +67 -0
- package/dist/features/table/types.d.ts +239 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/vlist-table.css +1 -0
- package/dist/vlist.css +1 -1
- package/package.json +2 -1
- /package/dist/features/{sections → groups}/layout.d.ts +0 -0
- /package/dist/features/{sections → groups}/sticky.d.ts +0 -0
- /package/dist/features/{sections → groups}/types.d.ts +0 -0
package/README.md
CHANGED
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight, high-performance virtual list with zero dependencies and dimension-agnostic architecture.
|
|
4
4
|
|
|
5
|
+
**v1.2.0** — [Changelog](./changelog.txt)
|
|
6
|
+
|
|
5
7
|
[](https://www.npmjs.com/package/@floor/vlist)
|
|
6
8
|
[](https://bundlephobia.com/package/@floor/vlist)
|
|
7
|
-
[](https://github.com/floor/vlist)
|
|
8
10
|
[](https://github.com/floor/vlist/blob/main/LICENSE)
|
|
9
11
|
|
|
10
12
|
- **Zero dependencies** — no external libraries
|
|
11
13
|
- **Ultra memory efficient** — ~0.1-0.2 MB constant overhead regardless of dataset size
|
|
12
|
-
- **~8 KB gzipped** — pay only for features you use (vs 20 KB+ monolithic alternatives)
|
|
14
|
+
- **~8.4 KB gzipped** — pay only for features you use (vs 20 KB+ monolithic alternatives)
|
|
13
15
|
- **Builder API** — composable features with perfect tree-shaking
|
|
14
|
-
- **Grid, masonry,
|
|
16
|
+
- **Grid, masonry, groups, async, selection, scale** — all opt-in
|
|
15
17
|
- **Horizontal & vertical** — semantically correct orientation support
|
|
16
18
|
- **Reverse, page-scroll, wrap** — every layout mode
|
|
17
|
-
- **Accessible** — WAI-ARIA, keyboard navigation, screen-reader friendly
|
|
19
|
+
- **Accessible** — WAI-ARIA, keyboard navigation, focus-visible, screen-reader friendly
|
|
18
20
|
- **React, Vue, Svelte** — framework adapters available
|
|
19
21
|
|
|
20
22
|
**30+ interactive examples → [vlist.dev](https://vlist.dev)**
|
|
@@ -24,9 +26,11 @@ Lightweight, high-performance virtual list with zero dependencies and dimension-
|
|
|
24
26
|
|
|
25
27
|
- **Dimension-agnostic API** — semantically correct terminology for both orientations
|
|
26
28
|
- **Performance optimized** — 13-pattern optimization playbook applied across the entire rendering pipeline
|
|
27
|
-
- **Horizontal
|
|
29
|
+
- **Horizontal groups** — sticky headers work in horizontal carousels
|
|
28
30
|
- **Horizontal grid layouts** — 2D grids work in both orientations
|
|
29
31
|
- **Masonry** — shortest-lane placement via `withMasonry()`
|
|
32
|
+
- **Keyboard accessible** — focus-visible outlines, arrow/Home/End navigation, Tab support
|
|
33
|
+
- **Responsive grid & masonry** — context-injected `columnWidth` auto-recalculates on resize
|
|
30
34
|
|
|
31
35
|
## Installation
|
|
32
36
|
|
|
@@ -63,7 +67,7 @@ list.on('item:click', ({ item }) => console.log(item))
|
|
|
63
67
|
Start with the base, add only what you need:
|
|
64
68
|
|
|
65
69
|
```typescript
|
|
66
|
-
import { vlist, withGrid,
|
|
70
|
+
import { vlist, withGrid, withGroups, withSelection } from '@floor/vlist'
|
|
67
71
|
|
|
68
72
|
const list = vlist({
|
|
69
73
|
container: '#app',
|
|
@@ -71,7 +75,7 @@ const list = vlist({
|
|
|
71
75
|
item: { height: 200, template: renderPhoto },
|
|
72
76
|
})
|
|
73
77
|
.use(withGrid({ columns: 4, gap: 16 }))
|
|
74
|
-
.use(
|
|
78
|
+
.use(withGroups({
|
|
75
79
|
getGroupForIndex: (i) => photos[i].category,
|
|
76
80
|
headerHeight: 40,
|
|
77
81
|
headerTemplate: (cat) => `<h2>${cat}</h2>`,
|
|
@@ -84,12 +88,12 @@ const list = vlist({
|
|
|
84
88
|
|
|
85
89
|
| Feature | Size | Description |
|
|
86
90
|
|---------|------|-------------|
|
|
87
|
-
| **Base** | 8.
|
|
88
|
-
| `withGrid()` | +3.
|
|
89
|
-
| `withMasonry()` | +2.
|
|
90
|
-
| `
|
|
91
|
+
| **Base** | 8.4 KB | Core virtualization |
|
|
92
|
+
| `withGrid()` | +3.9 KB | 2D grid layout with context injection |
|
|
93
|
+
| `withMasonry()` | +2.4 KB | Pinterest-style masonry layout |
|
|
94
|
+
| `withGroups()` | +4.1 KB | Grouped lists with sticky/inline headers |
|
|
91
95
|
| `withAsync()` | +3.9 KB | Lazy loading with adapters |
|
|
92
|
-
| `withSelection()` | +1.
|
|
96
|
+
| `withSelection()` | +1.7 KB | Single/multiple selection + keyboard nav |
|
|
93
97
|
| `withScale()` | +2.6 KB | 1M+ items via scroll compression |
|
|
94
98
|
| `withScrollbar()` | +1.2 KB | Custom scrollbar UI |
|
|
95
99
|
| `withPage()` | +0.4 KB | Document-level scrolling |
|
|
@@ -125,7 +129,7 @@ const gallery = vlist({
|
|
|
125
129
|
### Sticky Headers
|
|
126
130
|
|
|
127
131
|
```typescript
|
|
128
|
-
import { vlist,
|
|
132
|
+
import { vlist, withGroups } from '@floor/vlist'
|
|
129
133
|
|
|
130
134
|
const contacts = vlist({
|
|
131
135
|
container: '#contacts',
|
|
@@ -135,7 +139,7 @@ const contacts = vlist({
|
|
|
135
139
|
template: (contact) => `<div>${contact.name}</div>`,
|
|
136
140
|
},
|
|
137
141
|
})
|
|
138
|
-
.use(
|
|
142
|
+
.use(withGroups({
|
|
139
143
|
getGroupForIndex: (i) => sortedContacts[i].lastName[0].toUpperCase(),
|
|
140
144
|
headerHeight: 36,
|
|
141
145
|
headerTemplate: (letter) => `<div class="header">${letter}</div>`,
|
|
@@ -176,9 +180,9 @@ const list = vlist({
|
|
|
176
180
|
|
|
177
181
|
| Pattern | Key options |
|
|
178
182
|
|---------|------------|
|
|
179
|
-
| **Chat UI** | `reverse: true` + `
|
|
183
|
+
| **Chat UI** | `reverse: true` + `withGroups({ sticky: false })` |
|
|
180
184
|
| **Horizontal carousel** | `orientation: 'horizontal'`, `item.width` |
|
|
181
|
-
| **Horizontal
|
|
185
|
+
| **Horizontal groups** | `orientation: 'horizontal'` + `withGroups()` |
|
|
182
186
|
| **Horizontal grid** | `orientation: 'horizontal'` + `withGrid()` |
|
|
183
187
|
| **Masonry** | `withMasonry({ columns: 4, gap: 16 })` |
|
|
184
188
|
| **Page-level scroll** | `withPage()` |
|
|
@@ -275,7 +279,7 @@ Each feature's config is fully typed — hover in your IDE for details.
|
|
|
275
279
|
```typescript
|
|
276
280
|
withGrid({ columns: 4, gap: 16 })
|
|
277
281
|
withMasonry({ columns: 4, gap: 16 })
|
|
278
|
-
|
|
282
|
+
withGroups({ getGroupForIndex, headerHeight, headerTemplate, sticky?: true })
|
|
279
283
|
withSelection({ mode: 'single' | 'multiple', initial?: [...ids] })
|
|
280
284
|
withAsync({ adapter: { read }, loading?: { cancelThreshold? } })
|
|
281
285
|
withScale() // no config — auto-activates at 16.7M px
|
|
@@ -337,10 +341,10 @@ This makes the codebase clearer and eliminates semantic confusion when working w
|
|
|
337
341
|
|
|
338
342
|
| Configuration | Gzipped |
|
|
339
343
|
|---------------|---------|
|
|
340
|
-
| Base only | 8.
|
|
341
|
-
| + Grid |
|
|
342
|
-
| +
|
|
343
|
-
| + Async | 12.
|
|
344
|
+
| Base only | 8.4 KB |
|
|
345
|
+
| + Grid | 12.3 KB |
|
|
346
|
+
| + Groups | 12.6 KB |
|
|
347
|
+
| + Async | 12.4 KB |
|
|
344
348
|
|
|
345
349
|
### Memory Efficiency
|
|
346
350
|
|
package/dist/builder/scroll.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* vlist/builder — Scroll Utilities
|
|
3
3
|
* Easing, scroll-argument resolution, and smooth scroll animation.
|
|
4
4
|
*
|
|
5
|
-
* Shared by builder/core.ts, grid feature, and
|
|
5
|
+
* Shared by builder/core.ts, grid feature, and groups feature to
|
|
6
6
|
* avoid duplicating ~70 lines of scroll helpers in each consumer.
|
|
7
7
|
*/
|
|
8
8
|
import type { ScrollToOptions } from "../types";
|
package/dist/builder/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* vlist/builder - Types
|
|
3
3
|
* Feature interface, builder config, builder context, and return types
|
|
4
4
|
*/
|
|
5
|
-
import type { VListItem, VListEvents, ItemConfig, ItemTemplate, Range, ViewportState, EventHandler, Unsubscribe, ScrollToOptions, ScrollSnapshot, VListAdapter, GridConfig, GroupsConfig, SelectionConfig, ScrollbarOptions } from "../types";
|
|
5
|
+
import type { VListItem, VListEvents, ItemConfig, ItemTemplate, Range, ViewportState, EventHandler, Unsubscribe, ScrollToOptions, ScrollSnapshot, VListAdapter, GridConfig, MasonryConfig, GroupsConfig, SelectionConfig, ScrollbarOptions } from "../types";
|
|
6
6
|
import type { DOMStructure, Renderer, SizeCache, CompressionContext } from "../rendering";
|
|
7
7
|
import type { CompressionState } from "../rendering/viewport";
|
|
8
8
|
import type { SimpleDataManager } from "./data";
|
|
@@ -54,10 +54,12 @@ export interface VListConfig<T extends VListItem = VListItem> extends Omit<Build
|
|
|
54
54
|
/** Scrollbar mode (shorthand — same as top-level `scrollbar`). */
|
|
55
55
|
scrollbar?: "native" | "none" | ScrollbarOptions;
|
|
56
56
|
};
|
|
57
|
-
/** Layout mode (default: list). Set to `'grid'`
|
|
58
|
-
layout?: "list" | "grid";
|
|
57
|
+
/** Layout mode (default: list). Set to `'grid'` or `'masonry'` with matching config. */
|
|
58
|
+
layout?: "list" | "grid" | "masonry";
|
|
59
59
|
/** Grid configuration — used when `layout` is `'grid'`. */
|
|
60
60
|
grid?: GridConfig;
|
|
61
|
+
/** Masonry configuration — used when `layout` is `'masonry'`. */
|
|
62
|
+
masonry?: MasonryConfig;
|
|
61
63
|
/** Async data adapter — enables `withAsync()`. Omit `items` when using an adapter. */
|
|
62
64
|
adapter?: VListAdapter<T>;
|
|
63
65
|
/** Loading behavior for async adapter. */
|
|
@@ -69,7 +71,7 @@ export interface VListConfig<T extends VListItem = VListItem> extends Omit<Build
|
|
|
69
71
|
/** Number of items to preload in scroll direction. Default: 50 */
|
|
70
72
|
preloadAhead?: number;
|
|
71
73
|
};
|
|
72
|
-
/** Section grouping configuration — enables `
|
|
74
|
+
/** Section grouping configuration — enables `withGroups()`. */
|
|
73
75
|
groups?: GroupsConfig;
|
|
74
76
|
/** Selection configuration — enables `withSelection()`. */
|
|
75
77
|
selection?: SelectionConfig;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vlist/groups - Builder Feature
|
|
3
|
-
* Adds grouped lists with sticky
|
|
3
|
+
* Adds grouped lists with sticky headers.
|
|
4
4
|
*
|
|
5
5
|
* Priority: 10 (runs first — transforms item list and height function before rendering)
|
|
6
6
|
*
|
|
@@ -39,8 +39,7 @@ export interface GroupsFeatureConfig {
|
|
|
39
39
|
* Adds grouped lists with sticky section headers.
|
|
40
40
|
*
|
|
41
41
|
* ```ts
|
|
42
|
-
* import { vlist } from 'vlist
|
|
43
|
-
* import { withGroups } from 'vlist/groups'
|
|
42
|
+
* import { vlist, withGroups } from '@floor/vlist'
|
|
44
43
|
*
|
|
45
44
|
* const contacts = vlist({
|
|
46
45
|
* container: '#contacts',
|
|
@@ -60,5 +59,5 @@ export interface GroupsFeatureConfig {
|
|
|
60
59
|
* .build()
|
|
61
60
|
* ```
|
|
62
61
|
*/
|
|
63
|
-
export declare const
|
|
62
|
+
export declare const withGroups: <T extends VListItem = VListItem>(config: GroupsFeatureConfig) => VListFeature<T>;
|
|
64
63
|
//# sourceMappingURL=feature.d.ts.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* vlist - Groups Domain
|
|
3
3
|
* Sticky headers and grouped lists
|
|
4
4
|
*/
|
|
5
|
-
export {
|
|
5
|
+
export { withGroups, type GroupsFeatureConfig } from "./feature";
|
|
6
6
|
export type { GroupsConfig, GroupBoundary, LayoutEntry, GroupHeaderItem, GroupLayout, StickyHeader, } from "./types";
|
|
7
|
-
export { isGroupHeader
|
|
7
|
+
export { isGroupHeader } from "./types";
|
|
8
8
|
export { createGroupLayout, buildLayoutItems, createGroupedSizeFn, } from "./layout";
|
|
9
9
|
export { createStickyHeader } from "./sticky";
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/table - Builder Feature
|
|
3
|
+
* Switches from list layout to a data table with columns, resizable headers,
|
|
4
|
+
* sticky header row, and cell-based rendering.
|
|
5
|
+
*
|
|
6
|
+
* Priority: 10 (runs first — replaces the renderer before anything else renders)
|
|
7
|
+
*
|
|
8
|
+
* What it wires:
|
|
9
|
+
* - Replaces render functions — swaps the core render loop with table-aware rendering
|
|
10
|
+
* - Sticky header — creates a fixed header row above the viewport
|
|
11
|
+
* - Column layout — manages column widths, offsets, and resize logic
|
|
12
|
+
* - Resize interaction — drag handles on header column borders
|
|
13
|
+
* - Sort events — click on sortable header emits column:sort
|
|
14
|
+
* - Horizontal scroll sync — header scrolls in sync with the viewport
|
|
15
|
+
* - CSS class — adds .vlist--table to the root element
|
|
16
|
+
* - Variable row heights — supports fixed and function-based heights
|
|
17
|
+
*
|
|
18
|
+
* Critical design: This feature uses ctx.setRenderFns() to completely replace
|
|
19
|
+
* the core's render loop, NOT ctx.replaceRenderer() which is a no-op in the
|
|
20
|
+
* materialize context. This follows the same pattern as withGrid.
|
|
21
|
+
*
|
|
22
|
+
* Restrictions:
|
|
23
|
+
* - Cannot be combined with withGrid or withMasonry (conflicting layout modes)
|
|
24
|
+
* - Cannot be combined with orientation: 'horizontal' (tables are always vertical)
|
|
25
|
+
*
|
|
26
|
+
* Can be combined with:
|
|
27
|
+
* - withSelection (row selection works as-is)
|
|
28
|
+
* - withScrollbar (custom scrollbar)
|
|
29
|
+
* - withAsync (async data loading)
|
|
30
|
+
* - withSnapshots (scroll position save/restore)
|
|
31
|
+
* - withScale (large dataset compression)
|
|
32
|
+
*/
|
|
33
|
+
import type { VListItem } from "../../types";
|
|
34
|
+
import type { VListFeature } from "../../builder/types";
|
|
35
|
+
import type { TableConfig } from "./types";
|
|
36
|
+
/** Table feature configuration — re-exported as TableFeatureConfig */
|
|
37
|
+
export type TableFeatureConfig<T extends VListItem = VListItem> = TableConfig<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Create a table feature for the builder.
|
|
40
|
+
*
|
|
41
|
+
* Switches from list layout to a data table with column headers, resizable
|
|
42
|
+
* columns, and cell-based row rendering.
|
|
43
|
+
*
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { vlist } from 'vlist/builder'
|
|
46
|
+
* import { withTable } from 'vlist/table'
|
|
47
|
+
*
|
|
48
|
+
* const table = vlist({
|
|
49
|
+
* container: '#my-table',
|
|
50
|
+
* item: { height: 40, template: () => '' },
|
|
51
|
+
* items: users,
|
|
52
|
+
* })
|
|
53
|
+
* .use(withTable({
|
|
54
|
+
* columns: [
|
|
55
|
+
* { key: 'name', label: 'Name', width: 200 },
|
|
56
|
+
* { key: 'email', label: 'Email', width: 300 },
|
|
57
|
+
* { key: 'role', label: 'Role', width: 120 },
|
|
58
|
+
* ],
|
|
59
|
+
* rowHeight: 40,
|
|
60
|
+
* headerHeight: 44,
|
|
61
|
+
* resizable: true,
|
|
62
|
+
* }))
|
|
63
|
+
* .build()
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare const withTable: <T extends VListItem = VListItem>(config: TableFeatureConfig<T>) => VListFeature<T>;
|
|
67
|
+
//# sourceMappingURL=feature.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/table - Header
|
|
3
|
+
* Manages the sticky header row that sits above the scrolling viewport.
|
|
4
|
+
*
|
|
5
|
+
* The header is a positioned DOM element inserted into the vlist root
|
|
6
|
+
* container (above the viewport, like the sticky group header). It contains
|
|
7
|
+
* one cell per column, each showing the column label. Resize handles are
|
|
8
|
+
* rendered at the right edge of each resizable column's header cell.
|
|
9
|
+
*
|
|
10
|
+
* Layout:
|
|
11
|
+
* .vlist (root, position: relative)
|
|
12
|
+
* ├── .vlist-table-header (position: absolute, top: 0, z-index: 5)
|
|
13
|
+
* │ ├── .vlist-table-header-cell [col 0]
|
|
14
|
+
* │ │ ├── .vlist-table-header-content (label)
|
|
15
|
+
* │ │ ├── .vlist-table-header-sort (sort indicator)
|
|
16
|
+
* │ │ └── .vlist-table-header-resize (drag handle)
|
|
17
|
+
* │ ├── .vlist-table-header-cell [col 1]
|
|
18
|
+
* │ │ └── ...
|
|
19
|
+
* │ └── ...
|
|
20
|
+
* └── .vlist-viewport (scrollable, top offset by headerHeight)
|
|
21
|
+
*
|
|
22
|
+
* Resize interaction:
|
|
23
|
+
* mousedown on handle → pointermove updates column width → pointerup commits
|
|
24
|
+
* During drag, a class is added to the root for cursor override.
|
|
25
|
+
*
|
|
26
|
+
* Sort interaction:
|
|
27
|
+
* click on a sortable header cell emits column:sort via the provided callback.
|
|
28
|
+
* The header renders a visual indicator (▲/▼) for the active sort column.
|
|
29
|
+
*
|
|
30
|
+
* Horizontal scroll sync:
|
|
31
|
+
* The header's scrollLeft is kept in sync with the viewport's scrollLeft
|
|
32
|
+
* via the `syncScroll` method, called from the feature's afterScroll hook.
|
|
33
|
+
*/
|
|
34
|
+
import type { VListItem } from "../../types";
|
|
35
|
+
import type { TableHeader, ColumnSortEvent, ColumnClickEvent } from "./types";
|
|
36
|
+
/**
|
|
37
|
+
* Create a TableHeader instance.
|
|
38
|
+
*
|
|
39
|
+
* @param root - The vlist root element (.vlist)
|
|
40
|
+
* @param viewport - The vlist viewport element (for scroll sync)
|
|
41
|
+
* @param headerHeight - Height of the header row in pixels
|
|
42
|
+
* @param classPrefix - CSS class prefix (default: 'vlist')
|
|
43
|
+
* @param onResize - Callback when a column is resized (receives column index and new width)
|
|
44
|
+
* @param onSort - Callback when a sortable header is clicked
|
|
45
|
+
* @param onClick - Callback when any header cell is clicked
|
|
46
|
+
* @returns TableHeader instance
|
|
47
|
+
*/
|
|
48
|
+
export declare const createTableHeader: <T extends VListItem = VListItem>(root: HTMLElement, viewport: HTMLElement, headerHeight: number, classPrefix: string, onResize: (columnIndex: number, newWidth: number) => void, onSort?: (event: ColumnSortEvent) => void, onClick?: (event: ColumnClickEvent) => void) => TableHeader<T>;
|
|
49
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - Table Domain
|
|
3
|
+
* Data table layout with columns, resizable headers, and cell rendering
|
|
4
|
+
*/
|
|
5
|
+
export { withTable, type TableFeatureConfig } from "./feature";
|
|
6
|
+
export { createTableLayout } from "./layout";
|
|
7
|
+
export { createTableHeader } from "./header";
|
|
8
|
+
export { createTableRenderer, type TableRendererInstance } from "./renderer";
|
|
9
|
+
export type { TableConfig, TableColumn, TableLayout, TableHeader, TableRenderer, ResolvedColumn, ColumnResizeEvent, ColumnSortEvent, ColumnClickEvent, } from "./types";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/table - Layout
|
|
3
|
+
* Manages column widths, offsets, and resize operations.
|
|
4
|
+
*
|
|
5
|
+
* Column width resolution strategy:
|
|
6
|
+
* 1. Columns with explicit `width` get their requested width (clamped to min/max)
|
|
7
|
+
* 2. Remaining container space is distributed equally among columns without `width`
|
|
8
|
+
* 3. If all columns have explicit widths and total < container, no stretching occurs
|
|
9
|
+
* 4. If total column width > container, the table scrolls horizontally
|
|
10
|
+
*
|
|
11
|
+
* All offset calculations are O(n) where n = number of columns (typically small).
|
|
12
|
+
* Resize operations recalculate offsets for columns after the resized one.
|
|
13
|
+
*/
|
|
14
|
+
import type { VListItem } from "../../types";
|
|
15
|
+
import type { TableColumn, TableLayout } from "./types";
|
|
16
|
+
/**
|
|
17
|
+
* Create a TableLayout instance.
|
|
18
|
+
*
|
|
19
|
+
* @param columnDefs - Column definitions from config
|
|
20
|
+
* @param globalMinWidth - Default min column width (from TableConfig.minColumnWidth)
|
|
21
|
+
* @param globalMaxWidth - Default max column width (from TableConfig.maxColumnWidth)
|
|
22
|
+
* @param globalResizable - Default resizable flag (from TableConfig.resizable)
|
|
23
|
+
* @returns TableLayout with column resolution and resize capabilities
|
|
24
|
+
*/
|
|
25
|
+
export declare const createTableLayout: <T extends VListItem = VListItem>(columnDefs: TableColumn<T>[], globalMinWidth?: number, globalMaxWidth?: number, globalResizable?: boolean) => TableLayout<T>;
|
|
26
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/table - Renderer
|
|
3
|
+
* Renders virtualized rows with cell-based layout within the virtual scroll container.
|
|
4
|
+
*
|
|
5
|
+
* Each row is an absolutely positioned element (like the list renderer),
|
|
6
|
+
* containing child elements for each cell. Cells are sized and positioned
|
|
7
|
+
* according to the resolved column layout from TableLayout.
|
|
8
|
+
*
|
|
9
|
+
* Key design decisions:
|
|
10
|
+
* - Rows are the unit of virtualization (same as list mode — 1:1 with items)
|
|
11
|
+
* - Each row contains N cell elements (one per column)
|
|
12
|
+
* - Row positioning is translateY-based (from the size cache)
|
|
13
|
+
* - Cell positioning uses absolute left + width from the column layout
|
|
14
|
+
* - Element pooling avoids createElement cost (row-level pooling)
|
|
15
|
+
* - Change tracking skips template re-evaluation when data + state unchanged
|
|
16
|
+
* - Release grace period prevents boundary thrashing (hover blink, transition replay)
|
|
17
|
+
* - DocumentFragment batched insertion for new elements
|
|
18
|
+
*
|
|
19
|
+
* Performance:
|
|
20
|
+
* - O(1) Set-based visibility diffing (not O(n) .some())
|
|
21
|
+
* - Template re-evaluation skipped when item id + selection/focus state unchanged
|
|
22
|
+
* - Position update skipped when coordinates unchanged (position tracking)
|
|
23
|
+
* - Cell widths are only updated when column layout changes (not every scroll frame)
|
|
24
|
+
* - Released elements removed from DOM immediately, pooled for reuse
|
|
25
|
+
*
|
|
26
|
+
* DOM structure per row:
|
|
27
|
+
* .vlist-item.vlist-table-row (position: absolute, translateY)
|
|
28
|
+
* ├── .vlist-table-cell [col 0] (position: absolute, left, width)
|
|
29
|
+
* ├── .vlist-table-cell [col 1]
|
|
30
|
+
* └── ...
|
|
31
|
+
*/
|
|
32
|
+
import type { VListItem, Range } from "../../types";
|
|
33
|
+
import type { SizeCache } from "../../rendering/sizes";
|
|
34
|
+
import type { TableLayout, TableColumn } from "./types";
|
|
35
|
+
/** Table renderer instance */
|
|
36
|
+
export interface TableRendererInstance<T extends VListItem = VListItem> {
|
|
37
|
+
/** Render rows for a range, with cell-based layout */
|
|
38
|
+
render: (items: T[], range: Range, selectedIds: Set<string | number>, focusedIndex: number) => void;
|
|
39
|
+
/** Update a single row (e.g., after selection change) */
|
|
40
|
+
updateItem: (index: number, item: T, isSelected: boolean, isFocused: boolean) => void;
|
|
41
|
+
/** Update only CSS classes on a rendered row */
|
|
42
|
+
updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
|
|
43
|
+
/** Get rendered row element by item index */
|
|
44
|
+
getElement: (index: number) => HTMLElement | undefined;
|
|
45
|
+
/** Update cell positions and widths after column resize */
|
|
46
|
+
updateColumnLayout: (layout: TableLayout<T>) => void;
|
|
47
|
+
/** Clear all rendered rows */
|
|
48
|
+
clear: () => void;
|
|
49
|
+
/** Destroy renderer and cleanup */
|
|
50
|
+
destroy: () => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a TableRenderer instance.
|
|
54
|
+
*
|
|
55
|
+
* @param container - The .vlist-items container element
|
|
56
|
+
* @param sizeCache - Size cache for row offset lookups
|
|
57
|
+
* @param layout - Table layout for column widths/offsets
|
|
58
|
+
* @param columns - Column definitions (for cell templates)
|
|
59
|
+
* @param classPrefix - CSS class prefix
|
|
60
|
+
* @param ariaIdPrefix - Prefix for ARIA IDs
|
|
61
|
+
* @param columnBorders - Whether to show vertical borders between cells
|
|
62
|
+
* @param rowBorders - Whether to show horizontal borders between rows
|
|
63
|
+
* @param getTotalItems - Function to get total item count (for ARIA)
|
|
64
|
+
* @returns TableRendererInstance
|
|
65
|
+
*/
|
|
66
|
+
export declare const createTableRenderer: <T extends VListItem = VListItem>(container: HTMLElement, sizeCache: SizeCache, layout: TableLayout<T>, _columns: TableColumn<T>[], classPrefix: string, ariaIdPrefix: string, getTotalItems: () => number) => TableRendererInstance<T>;
|
|
67
|
+
//# sourceMappingURL=renderer.d.ts.map
|