@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
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/table - Types
|
|
3
|
+
* Types for data table layout with columns, resizable headers, and cell rendering.
|
|
4
|
+
*
|
|
5
|
+
* A table transforms a flat list of items into rows of cells:
|
|
6
|
+
* - Each row corresponds to one item (1:1 mapping, unlike grid)
|
|
7
|
+
* - Each cell is positioned horizontally according to its column definition
|
|
8
|
+
* - A sticky header row displays column labels and resize handles
|
|
9
|
+
* - Columns can be resized by dragging header borders
|
|
10
|
+
* - Variable row heights are supported (Mode A and Mode B)
|
|
11
|
+
*/
|
|
12
|
+
import type { VListItem } from "../../types";
|
|
13
|
+
/** Definition for a single table column */
|
|
14
|
+
export interface TableColumn<T extends VListItem = VListItem> {
|
|
15
|
+
/** Unique column key — used for identification and as default item property accessor */
|
|
16
|
+
key: string;
|
|
17
|
+
/** Header label — string or DOM element */
|
|
18
|
+
label: string | HTMLElement;
|
|
19
|
+
/**
|
|
20
|
+
* Initial column width in pixels.
|
|
21
|
+
* If omitted, remaining space is distributed equally among columns without a width.
|
|
22
|
+
*/
|
|
23
|
+
width?: number;
|
|
24
|
+
/** Minimum column width in pixels (default: 50) */
|
|
25
|
+
minWidth?: number;
|
|
26
|
+
/** Maximum column width in pixels (default: Infinity) */
|
|
27
|
+
maxWidth?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Whether this column can be resized (default: inherits from TableConfig.resizable).
|
|
30
|
+
* Set to `false` to lock a specific column's width.
|
|
31
|
+
*/
|
|
32
|
+
resizable?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Cell template — renders the cell content for this column.
|
|
35
|
+
*
|
|
36
|
+
* If omitted, the cell displays `String(item[column.key])` as text content.
|
|
37
|
+
*
|
|
38
|
+
* @param item - The row's data item
|
|
39
|
+
* @param column - This column definition (for context)
|
|
40
|
+
* @param rowIndex - The flat item index in the data array
|
|
41
|
+
* @returns HTML string or DOM element for the cell
|
|
42
|
+
*/
|
|
43
|
+
cell?: (item: T, column: TableColumn<T>, rowIndex: number) => string | HTMLElement;
|
|
44
|
+
/**
|
|
45
|
+
* Header template — custom render for the header cell.
|
|
46
|
+
*
|
|
47
|
+
* If omitted, the header displays `column.label` (string or element).
|
|
48
|
+
*
|
|
49
|
+
* @param column - This column definition
|
|
50
|
+
* @returns HTML string or DOM element for the header cell
|
|
51
|
+
*/
|
|
52
|
+
header?: (column: TableColumn<T>) => string | HTMLElement;
|
|
53
|
+
/** Text alignment within cells (default: 'left') */
|
|
54
|
+
align?: "left" | "center" | "right";
|
|
55
|
+
/**
|
|
56
|
+
* Whether clicking this column's header emits a sort event (default: false).
|
|
57
|
+
* The table feature does NOT sort data — it emits `column:sort` and the
|
|
58
|
+
* consumer is responsible for reordering items via `setItems()`.
|
|
59
|
+
*/
|
|
60
|
+
sortable?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Pin this column to the left or right edge.
|
|
63
|
+
* Pinned columns stay visible while the rest scroll horizontally.
|
|
64
|
+
* (Reserved for future use — not implemented in v1.)
|
|
65
|
+
*/
|
|
66
|
+
pin?: "left" | "right";
|
|
67
|
+
}
|
|
68
|
+
/** Configuration for the withTable feature */
|
|
69
|
+
export interface TableConfig<T extends VListItem = VListItem> {
|
|
70
|
+
/** Column definitions (required, at least one column) */
|
|
71
|
+
columns: TableColumn<T>[];
|
|
72
|
+
/**
|
|
73
|
+
* Row height in pixels (required).
|
|
74
|
+
*
|
|
75
|
+
* - `number` — Fixed height for all rows (fast path)
|
|
76
|
+
* - `(index: number) => number` — Variable height per row
|
|
77
|
+
*
|
|
78
|
+
* For auto-measured variable heights, use `estimatedRowHeight` instead.
|
|
79
|
+
*/
|
|
80
|
+
rowHeight: number | ((index: number) => number);
|
|
81
|
+
/**
|
|
82
|
+
* Estimated row height for auto-measurement (Mode B).
|
|
83
|
+
*
|
|
84
|
+
* When set, rows are rendered at this estimated height, then measured
|
|
85
|
+
* via ResizeObserver and corrected. Takes precedence only when
|
|
86
|
+
* `rowHeight` is a single number — if `rowHeight` is a function, this
|
|
87
|
+
* is ignored.
|
|
88
|
+
*
|
|
89
|
+
* Use for tables with wrapping text or dynamic cell content.
|
|
90
|
+
*/
|
|
91
|
+
estimatedRowHeight?: number;
|
|
92
|
+
/** Header row height in pixels (default: same as rowHeight when fixed, or 40) */
|
|
93
|
+
headerHeight?: number;
|
|
94
|
+
/** Enable column resizing globally (default: true) */
|
|
95
|
+
resizable?: boolean;
|
|
96
|
+
/** Default minimum column width in pixels (default: 50) */
|
|
97
|
+
minColumnWidth?: number;
|
|
98
|
+
/** Default maximum column width in pixels (default: Infinity) */
|
|
99
|
+
maxColumnWidth?: number;
|
|
100
|
+
/** Show vertical borders between columns (default: false) */
|
|
101
|
+
columnBorders?: boolean;
|
|
102
|
+
/** Show horizontal borders between rows (default: true) */
|
|
103
|
+
rowBorders?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Sort indicator for a column.
|
|
106
|
+
* The table renders an indicator in the header but does NOT sort data.
|
|
107
|
+
* Update this and call the exposed `updateColumns()` method to reflect changes.
|
|
108
|
+
*/
|
|
109
|
+
sort?: {
|
|
110
|
+
/** Column key currently sorted by */
|
|
111
|
+
key: string;
|
|
112
|
+
/** Sort direction */
|
|
113
|
+
direction: "asc" | "desc";
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** Column with resolved pixel width (internal use) */
|
|
117
|
+
export interface ResolvedColumn<T extends VListItem = VListItem> {
|
|
118
|
+
/** Original column definition */
|
|
119
|
+
def: TableColumn<T>;
|
|
120
|
+
/** Index in the columns array */
|
|
121
|
+
index: number;
|
|
122
|
+
/** Resolved width in pixels */
|
|
123
|
+
width: number;
|
|
124
|
+
/** Resolved minimum width */
|
|
125
|
+
minWidth: number;
|
|
126
|
+
/** Resolved maximum width */
|
|
127
|
+
maxWidth: number;
|
|
128
|
+
/** Whether this column is resizable */
|
|
129
|
+
resizable: boolean;
|
|
130
|
+
/** Left offset in pixels (cumulative) */
|
|
131
|
+
offset: number;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* TableLayout — manages column widths, offsets, and resize operations.
|
|
135
|
+
*
|
|
136
|
+
* Columns are laid out left-to-right. When the total column width exceeds
|
|
137
|
+
* the container width, the table scrolls horizontally. When columns fit
|
|
138
|
+
* within the container, remaining space is distributed.
|
|
139
|
+
*/
|
|
140
|
+
export interface TableLayout<T extends VListItem = VListItem> {
|
|
141
|
+
/** Current resolved columns (with computed widths and offsets) */
|
|
142
|
+
readonly columns: readonly ResolvedColumn<T>[];
|
|
143
|
+
/** Total width of all columns in pixels */
|
|
144
|
+
readonly totalWidth: number;
|
|
145
|
+
/** Resolve column widths given available container width */
|
|
146
|
+
resolve: (containerWidth: number) => void;
|
|
147
|
+
/** Update column definitions (e.g., after reorder or config change) */
|
|
148
|
+
updateColumns: (columns: TableColumn<T>[]) => void;
|
|
149
|
+
/**
|
|
150
|
+
* Resize a column by index.
|
|
151
|
+
* Clamps to min/max width. Recalculates offsets for subsequent columns.
|
|
152
|
+
* Returns the actual new width after clamping.
|
|
153
|
+
*/
|
|
154
|
+
resizeColumn: (columnIndex: number, newWidth: number) => number;
|
|
155
|
+
/** Get the resolved column at a given index */
|
|
156
|
+
getColumn: (index: number) => ResolvedColumn<T> | undefined;
|
|
157
|
+
/** Get the column whose horizontal range contains `x` pixels from left */
|
|
158
|
+
getColumnAtX: (x: number) => ResolvedColumn<T> | undefined;
|
|
159
|
+
/** Get the X offset for a column */
|
|
160
|
+
getColumnOffset: (columnIndex: number) => number;
|
|
161
|
+
/** Get the width for a column */
|
|
162
|
+
getColumnWidth: (columnIndex: number) => number;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* TableHeader — manages the sticky header row above the viewport.
|
|
166
|
+
*
|
|
167
|
+
* The header is a positioned DOM element containing one cell per column.
|
|
168
|
+
* It stays fixed at the top while rows scroll beneath it. Resize handles
|
|
169
|
+
* are rendered at column borders for drag-to-resize interaction.
|
|
170
|
+
*/
|
|
171
|
+
export interface TableHeader<T extends VListItem = VListItem> {
|
|
172
|
+
/** The header DOM element */
|
|
173
|
+
readonly element: HTMLElement;
|
|
174
|
+
/** Update header cell positions and widths (call after layout.resolve) */
|
|
175
|
+
update: (layout: TableLayout<T>) => void;
|
|
176
|
+
/** Update sort indicator display */
|
|
177
|
+
updateSort: (key: string | null, direction: "asc" | "desc") => void;
|
|
178
|
+
/** Rebuild header cells (call after column definitions change) */
|
|
179
|
+
rebuild: (layout: TableLayout<T>) => void;
|
|
180
|
+
/** Show the header */
|
|
181
|
+
show: () => void;
|
|
182
|
+
/** Hide the header */
|
|
183
|
+
hide: () => void;
|
|
184
|
+
/** Destroy and remove header DOM */
|
|
185
|
+
destroy: () => void;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* TableRenderer — renders virtualized rows with cell-based layout.
|
|
189
|
+
*
|
|
190
|
+
* Each row is an absolutely positioned element (like the list renderer),
|
|
191
|
+
* containing child elements for each cell. Cells are sized and positioned
|
|
192
|
+
* according to the resolved column layout.
|
|
193
|
+
*/
|
|
194
|
+
export interface TableRenderer<T extends VListItem = VListItem> {
|
|
195
|
+
/** Render rows for a range, with cell-based layout */
|
|
196
|
+
render: (items: T[], range: import("../../types").Range, selectedIds: Set<string | number>, focusedIndex: number) => void;
|
|
197
|
+
/** Update a single row (e.g., after selection change) */
|
|
198
|
+
updateItem: (index: number, item: T, isSelected: boolean, isFocused: boolean) => void;
|
|
199
|
+
/** Update only CSS classes on a rendered row */
|
|
200
|
+
updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
|
|
201
|
+
/** Get rendered row element by item index */
|
|
202
|
+
getElement: (index: number) => HTMLElement | undefined;
|
|
203
|
+
/** Update cell positions and widths after column resize */
|
|
204
|
+
updateColumnLayout: (layout: TableLayout<T>) => void;
|
|
205
|
+
/** Clear all rendered rows */
|
|
206
|
+
clear: () => void;
|
|
207
|
+
/** Destroy renderer and cleanup */
|
|
208
|
+
destroy: () => void;
|
|
209
|
+
}
|
|
210
|
+
/** Payload for column:resize event */
|
|
211
|
+
export interface ColumnResizeEvent {
|
|
212
|
+
/** Column key */
|
|
213
|
+
key: string;
|
|
214
|
+
/** Column index */
|
|
215
|
+
index: number;
|
|
216
|
+
/** Previous width in pixels */
|
|
217
|
+
previousWidth: number;
|
|
218
|
+
/** New width in pixels */
|
|
219
|
+
width: number;
|
|
220
|
+
}
|
|
221
|
+
/** Payload for column:sort event */
|
|
222
|
+
export interface ColumnSortEvent {
|
|
223
|
+
/** Column key */
|
|
224
|
+
key: string;
|
|
225
|
+
/** Column index */
|
|
226
|
+
index: number;
|
|
227
|
+
/** Current sort direction (toggles on each click: null → asc → desc → null) */
|
|
228
|
+
direction: "asc" | "desc" | null;
|
|
229
|
+
}
|
|
230
|
+
/** Payload for column:click event */
|
|
231
|
+
export interface ColumnClickEvent {
|
|
232
|
+
/** Column key */
|
|
233
|
+
key: string;
|
|
234
|
+
/** Column index */
|
|
235
|
+
index: number;
|
|
236
|
+
/** Original mouse event */
|
|
237
|
+
event: MouseEvent;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -10,15 +10,17 @@ export { withScale } from "./features/scale";
|
|
|
10
10
|
export { withAsync } from "./features/async";
|
|
11
11
|
export { withScrollbar } from "./features/scrollbar";
|
|
12
12
|
export { withPage } from "./features/page";
|
|
13
|
-
export {
|
|
13
|
+
export { withGroups } from "./features/groups";
|
|
14
14
|
export { withGrid } from "./features/grid";
|
|
15
15
|
export { withMasonry } from "./features/masonry";
|
|
16
16
|
export { withSelection } from "./features/selection";
|
|
17
17
|
export { withSnapshots } from "./features/snapshots";
|
|
18
|
+
export { withTable } from "./features/table";
|
|
18
19
|
export type { VListItem, VListEvents, ItemTemplate, ItemState, SelectionMode, SelectionConfig, SelectionState, ScrollbarConfig, ScrollbarOptions, ScrollConfig, ScrollToOptions, ScrollSnapshot, VListAdapter, AdapterParams, AdapterResponse, Range, ViewportState, EventHandler, Unsubscribe, GridSizeContext, GridHeightContext, } from "./types";
|
|
19
20
|
export type { VListBuilder, VList, BuilderConfig, VListConfig, VListFeature, BuilderContext, } from "./builder";
|
|
20
|
-
export { createGroupLayout
|
|
21
|
+
export { createGroupLayout, buildLayoutItems, createGroupedSizeFn, createStickyHeader, isGroupHeader, type GroupsConfig, type GroupBoundary, type LayoutEntry, type GroupHeaderItem, type GroupLayout, type StickyHeader, } from "./features/groups";
|
|
21
22
|
export { createGridLayout, createGridRenderer, type GridConfig, type GridLayout, type GridPosition, type GridRenderer, type ItemRange, } from "./features/grid";
|
|
23
|
+
export { createTableLayout, createTableHeader, createTableRenderer, type TableConfig, type TableColumn, type TableLayout, type TableHeader, type TableRenderer, type TableRendererInstance, type ResolvedColumn, type ColumnResizeEvent, type ColumnSortEvent, type ColumnClickEvent, } from "./features/table";
|
|
22
24
|
export { createMasonryLayout, createMasonryRenderer, type MasonryConfig, type MasonryLayout, type MasonryRenderer, type GetItemFn, type ItemPlacement, } from "./features/masonry";
|
|
23
25
|
export { createSizeCache, type SizeCache, createMeasuredSizeCache, type MeasuredSizeCache, simpleVisibleRange, calculateRenderRange, calculateTotalSize, calculateActualSize, calculateItemOffset, calculateScrollToIndex, clampScrollPosition, rangesEqual, isInRange, getRangeCount, diffRanges, MAX_VIRTUAL_SIZE, MAX_VIRTUAL_HEIGHT, getCompressionState as getScaleState, getCompression as getScale, needsCompression as needsScaling, getMaxItemsWithoutCompression as getMaxItemsWithoutScaling, getCompressionInfo as getScaleInfo, calculateCompressedVisibleRange as calculateScaledVisibleRange, calculateCompressedRenderRange as calculateScaledRenderRange, calculateCompressedItemPosition as calculateScaledItemPosition, calculateCompressedScrollToIndex as calculateScaledScrollToIndex, calculateIndexFromScrollPosition, type CompressionState as ScaleState, } from "./rendering";
|
|
24
26
|
export { createSelectionState, selectItems, deselectItems, toggleSelection, selectAll, clearSelection, isSelected, getSelectedIds, getSelectedItems, } from "./features/selection";
|