virtualized-ui 0.0.1 → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,471 @@
1
+ import { useRef, useMemo, useState, useCallback } from 'react';
2
+ import { useReactTable, getExpandedRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
3
+ export { createColumnHelper } from '@tanstack/react-table';
4
+ import { useVirtualizer } from '@tanstack/react-virtual';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ // src/VirtualTable/VirtualTable.tsx
8
+ var DEFAULT_ROW_HEIGHT = 40;
9
+ var DEFAULT_EXPANDED_ROW_HEIGHT = 200;
10
+ var DEFAULT_OVERSCAN = 5;
11
+ var DEFAULT_SCROLL_THRESHOLD = 100;
12
+ function getColumnId(column) {
13
+ if ("id" in column && typeof column.id === "string") {
14
+ return column.id;
15
+ }
16
+ if ("accessorKey" in column && typeof column.accessorKey === "string") {
17
+ return column.accessorKey;
18
+ }
19
+ return "";
20
+ }
21
+ function useVirtualTable(options) {
22
+ const {
23
+ data,
24
+ columns,
25
+ rowHeight = DEFAULT_ROW_HEIGHT,
26
+ overscan = DEFAULT_OVERSCAN,
27
+ enableRowSelection = false,
28
+ rowSelection: controlledRowSelection,
29
+ onRowSelectionChange,
30
+ enableSorting = false,
31
+ sorting: controlledSorting,
32
+ onSortingChange,
33
+ enableMultiSort = false,
34
+ maxMultiSortColCount,
35
+ enableColumnResizing = false,
36
+ columnResizeMode = "onChange",
37
+ columnSizing: controlledColumnSizing,
38
+ onColumnSizingChange,
39
+ enableColumnReordering = false,
40
+ columnOrder: controlledColumnOrder,
41
+ onColumnOrderChange,
42
+ enableRowExpansion = false,
43
+ expanded: controlledExpanded,
44
+ onExpandedChange,
45
+ expandedRowHeight = DEFAULT_EXPANDED_ROW_HEIGHT,
46
+ getRowCanExpand,
47
+ getRowId,
48
+ enableKeyboardNavigation = false,
49
+ focusedRowIndex: controlledFocusedRowIndex,
50
+ onFocusedRowChange,
51
+ onScrollToBottom,
52
+ scrollBottomThreshold = DEFAULT_SCROLL_THRESHOLD
53
+ } = options;
54
+ const containerRef = useRef(null);
55
+ const defaultColumnOrder = useMemo(() => columns.map(getColumnId), [columns]);
56
+ const [internalRowSelection, setInternalRowSelection] = useState({});
57
+ const [internalSorting, setInternalSorting] = useState([]);
58
+ const [internalExpanded, setInternalExpanded] = useState({});
59
+ const [internalColumnSizing, setInternalColumnSizing] = useState({});
60
+ const [internalColumnOrder, setInternalColumnOrder] = useState([]);
61
+ const [internalFocusedRowIndex, setInternalFocusedRowIndex] = useState(-1);
62
+ const rowSelectionState = controlledRowSelection ?? internalRowSelection;
63
+ const sortingState = controlledSorting ?? internalSorting;
64
+ const expandedState = controlledExpanded ?? internalExpanded;
65
+ const columnSizingState = controlledColumnSizing ?? internalColumnSizing;
66
+ const columnOrderState = controlledColumnOrder ?? (internalColumnOrder.length ? internalColumnOrder : defaultColumnOrder);
67
+ const focusedRowIndex = controlledFocusedRowIndex ?? internalFocusedRowIndex;
68
+ const handleRowSelectionChange = useCallback(
69
+ (updater) => {
70
+ const newValue = typeof updater === "function" ? updater(rowSelectionState) : updater;
71
+ if (onRowSelectionChange) {
72
+ onRowSelectionChange(newValue);
73
+ } else {
74
+ setInternalRowSelection(newValue);
75
+ }
76
+ },
77
+ [rowSelectionState, onRowSelectionChange]
78
+ );
79
+ const handleSortingChange = useCallback(
80
+ (updater) => {
81
+ const newValue = typeof updater === "function" ? updater(sortingState) : updater;
82
+ if (onSortingChange) {
83
+ onSortingChange(newValue);
84
+ } else {
85
+ setInternalSorting(newValue);
86
+ }
87
+ },
88
+ [sortingState, onSortingChange]
89
+ );
90
+ const handleExpandedChange = useCallback(
91
+ (updater) => {
92
+ const newValue = typeof updater === "function" ? updater(expandedState) : updater;
93
+ if (onExpandedChange) {
94
+ onExpandedChange(newValue);
95
+ } else {
96
+ setInternalExpanded(newValue);
97
+ }
98
+ },
99
+ [expandedState, onExpandedChange]
100
+ );
101
+ const handleColumnSizingChange = useCallback(
102
+ (updater) => {
103
+ const newValue = typeof updater === "function" ? updater(columnSizingState) : updater;
104
+ if (onColumnSizingChange) {
105
+ onColumnSizingChange(newValue);
106
+ } else {
107
+ setInternalColumnSizing(newValue);
108
+ }
109
+ },
110
+ [columnSizingState, onColumnSizingChange]
111
+ );
112
+ const handleColumnOrderChange = useCallback(
113
+ (updater) => {
114
+ const newValue = typeof updater === "function" ? updater(columnOrderState) : updater;
115
+ if (onColumnOrderChange) {
116
+ onColumnOrderChange(newValue);
117
+ } else {
118
+ setInternalColumnOrder(newValue);
119
+ }
120
+ },
121
+ [columnOrderState, onColumnOrderChange]
122
+ );
123
+ const table = useReactTable({
124
+ data,
125
+ columns,
126
+ getCoreRowModel: getCoreRowModel(),
127
+ getSortedRowModel: enableSorting ? getSortedRowModel() : void 0,
128
+ getExpandedRowModel: enableRowExpansion ? getExpandedRowModel() : void 0,
129
+ enableRowSelection,
130
+ enableSorting,
131
+ enableMultiSort,
132
+ maxMultiSortColCount,
133
+ enableColumnResizing,
134
+ columnResizeMode,
135
+ getRowCanExpand: enableRowExpansion ? getRowCanExpand ?? (() => true) : void 0,
136
+ state: {
137
+ rowSelection: rowSelectionState,
138
+ sorting: sortingState,
139
+ expanded: expandedState,
140
+ columnSizing: columnSizingState,
141
+ columnOrder: enableColumnReordering ? columnOrderState : void 0
142
+ },
143
+ onRowSelectionChange: handleRowSelectionChange,
144
+ onSortingChange: handleSortingChange,
145
+ onExpandedChange: handleExpandedChange,
146
+ onColumnSizingChange: handleColumnSizingChange,
147
+ onColumnOrderChange: enableColumnReordering ? handleColumnOrderChange : void 0,
148
+ getRowId
149
+ });
150
+ const { rows } = table.getRowModel();
151
+ const estimateSize = useCallback(
152
+ (index) => {
153
+ if (!enableRowExpansion) return rowHeight;
154
+ const row = rows[index];
155
+ return row?.getIsExpanded() ? rowHeight + expandedRowHeight : rowHeight;
156
+ },
157
+ [rows, rowHeight, expandedRowHeight, enableRowExpansion]
158
+ );
159
+ const virtualizer = useVirtualizer({
160
+ count: rows.length,
161
+ getScrollElement: () => containerRef.current,
162
+ estimateSize,
163
+ overscan
164
+ });
165
+ const virtualItems = virtualizer.getVirtualItems();
166
+ const totalSize = virtualizer.getTotalSize();
167
+ const handleScroll = useCallback(() => {
168
+ if (!onScrollToBottom || !containerRef.current) return;
169
+ const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
170
+ const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
171
+ if (distanceFromBottom < scrollBottomThreshold) {
172
+ onScrollToBottom();
173
+ }
174
+ }, [onScrollToBottom, scrollBottomThreshold]);
175
+ const reorderColumn = useCallback(
176
+ (draggedColumnId, targetColumnId) => {
177
+ const newOrder = [...columnOrderState];
178
+ const draggedIndex = newOrder.indexOf(draggedColumnId);
179
+ const targetIndex = newOrder.indexOf(targetColumnId);
180
+ if (draggedIndex === -1 || targetIndex === -1) return;
181
+ newOrder.splice(draggedIndex, 1);
182
+ newOrder.splice(targetIndex, 0, draggedColumnId);
183
+ handleColumnOrderChange(newOrder);
184
+ },
185
+ [columnOrderState, handleColumnOrderChange]
186
+ );
187
+ const setFocusedRow = useCallback(
188
+ (index) => {
189
+ const clampedIndex = Math.max(-1, Math.min(index, rows.length - 1));
190
+ if (onFocusedRowChange) {
191
+ onFocusedRowChange(clampedIndex);
192
+ } else {
193
+ setInternalFocusedRowIndex(clampedIndex);
194
+ }
195
+ if (clampedIndex >= 0) {
196
+ virtualizer.scrollToIndex(clampedIndex, { align: "auto" });
197
+ }
198
+ },
199
+ [rows.length, onFocusedRowChange, virtualizer]
200
+ );
201
+ const handleKeyDown = useCallback(
202
+ (e) => {
203
+ if (!enableKeyboardNavigation) return;
204
+ const currentIndex = focusedRowIndex;
205
+ switch (e.key) {
206
+ case "ArrowDown":
207
+ e.preventDefault();
208
+ setFocusedRow(currentIndex + 1);
209
+ break;
210
+ case "ArrowUp":
211
+ e.preventDefault();
212
+ setFocusedRow(currentIndex - 1);
213
+ break;
214
+ case "Home":
215
+ e.preventDefault();
216
+ setFocusedRow(0);
217
+ break;
218
+ case "End":
219
+ e.preventDefault();
220
+ setFocusedRow(rows.length - 1);
221
+ break;
222
+ case "Enter":
223
+ if (currentIndex >= 0 && enableRowExpansion) {
224
+ e.preventDefault();
225
+ const row = rows[currentIndex];
226
+ if (row?.getCanExpand()) {
227
+ row.toggleExpanded();
228
+ }
229
+ }
230
+ break;
231
+ case " ":
232
+ if (currentIndex >= 0 && enableRowSelection) {
233
+ e.preventDefault();
234
+ const row = rows[currentIndex];
235
+ row?.toggleSelected();
236
+ }
237
+ break;
238
+ }
239
+ },
240
+ [
241
+ enableKeyboardNavigation,
242
+ focusedRowIndex,
243
+ rows,
244
+ enableRowExpansion,
245
+ enableRowSelection,
246
+ setFocusedRow
247
+ ]
248
+ );
249
+ return {
250
+ table,
251
+ rows,
252
+ virtualizer,
253
+ virtualItems,
254
+ totalSize,
255
+ containerRef,
256
+ handleScroll,
257
+ handleKeyDown,
258
+ reorderColumn,
259
+ setFocusedRow,
260
+ // Expose state for consumers
261
+ rowSelection: rowSelectionState,
262
+ sorting: sortingState,
263
+ expanded: expandedState,
264
+ columnSizing: columnSizingState,
265
+ columnOrder: columnOrderState,
266
+ focusedRowIndex
267
+ };
268
+ }
269
+ var DEFAULT_HEIGHT = 400;
270
+ function VirtualTable(props) {
271
+ const {
272
+ height = DEFAULT_HEIGHT,
273
+ stickyHeader = true,
274
+ renderExpandedRow,
275
+ className,
276
+ style,
277
+ ...tableOptions
278
+ } = props;
279
+ const {
280
+ rows,
281
+ virtualizer,
282
+ virtualItems,
283
+ totalSize,
284
+ containerRef,
285
+ handleScroll,
286
+ handleKeyDown,
287
+ table,
288
+ reorderColumn,
289
+ setFocusedRow,
290
+ focusedRowIndex
291
+ } = useVirtualTable(tableOptions);
292
+ const headerGroups = table.getHeaderGroups();
293
+ const enableRowExpansion = tableOptions.enableRowExpansion;
294
+ const enableColumnResizing = tableOptions.enableColumnResizing;
295
+ const enableColumnReordering = tableOptions.enableColumnReordering;
296
+ const enableKeyboardNavigation = tableOptions.enableKeyboardNavigation;
297
+ const [draggedColumnId, setDraggedColumnId] = useState(null);
298
+ return /* @__PURE__ */ jsx(
299
+ "div",
300
+ {
301
+ ref: containerRef,
302
+ className,
303
+ tabIndex: enableKeyboardNavigation ? 0 : void 0,
304
+ style: {
305
+ height,
306
+ overflow: "auto",
307
+ position: "relative",
308
+ outline: "none",
309
+ ...style
310
+ },
311
+ onScroll: handleScroll,
312
+ onKeyDown: enableKeyboardNavigation ? handleKeyDown : void 0,
313
+ children: /* @__PURE__ */ jsxs(
314
+ "table",
315
+ {
316
+ style: {
317
+ display: "grid",
318
+ width: "100%"
319
+ },
320
+ children: [
321
+ /* @__PURE__ */ jsx(
322
+ "thead",
323
+ {
324
+ style: {
325
+ display: "grid",
326
+ position: stickyHeader ? "sticky" : "relative",
327
+ top: 0,
328
+ zIndex: 1
329
+ },
330
+ children: headerGroups.map((headerGroup) => /* @__PURE__ */ jsx(
331
+ "tr",
332
+ {
333
+ style: {
334
+ display: "flex",
335
+ width: "100%"
336
+ },
337
+ children: headerGroup.headers.map((header) => /* @__PURE__ */ jsxs(
338
+ "th",
339
+ {
340
+ draggable: enableColumnReordering && !header.isPlaceholder,
341
+ "data-dragging": draggedColumnId === header.column.id || void 0,
342
+ onDragStart: enableColumnReordering ? (e) => {
343
+ setDraggedColumnId(header.column.id);
344
+ e.dataTransfer.effectAllowed = "move";
345
+ } : void 0,
346
+ onDragOver: enableColumnReordering ? (e) => {
347
+ e.preventDefault();
348
+ e.dataTransfer.dropEffect = "move";
349
+ } : void 0,
350
+ onDrop: enableColumnReordering ? (e) => {
351
+ e.preventDefault();
352
+ if (draggedColumnId && draggedColumnId !== header.column.id) {
353
+ reorderColumn(draggedColumnId, header.column.id);
354
+ }
355
+ } : void 0,
356
+ onDragEnd: enableColumnReordering ? () => setDraggedColumnId(null) : void 0,
357
+ style: {
358
+ flex: `0 0 ${header.getSize()}px`,
359
+ cursor: enableColumnReordering ? "grab" : header.column.getCanSort() ? "pointer" : "default",
360
+ position: "relative",
361
+ opacity: draggedColumnId === header.column.id ? 0.5 : 1
362
+ },
363
+ onClick: !enableColumnReordering ? header.column.getToggleSortingHandler() : void 0,
364
+ children: [
365
+ header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()),
366
+ header.column.getIsSorted() === "asc" && " \u2191",
367
+ header.column.getIsSorted() === "desc" && " \u2193",
368
+ enableColumnResizing && header.column.getCanResize() && /* @__PURE__ */ jsx(
369
+ "div",
370
+ {
371
+ onMouseDown: header.getResizeHandler(),
372
+ onTouchStart: header.getResizeHandler(),
373
+ onClick: (e) => e.stopPropagation(),
374
+ className: "virtual-table-resizer",
375
+ "data-resizing": header.column.getIsResizing() || void 0,
376
+ style: {
377
+ position: "absolute",
378
+ right: 0,
379
+ top: 0,
380
+ height: "100%",
381
+ width: "5px",
382
+ cursor: "col-resize",
383
+ userSelect: "none",
384
+ touchAction: "none",
385
+ background: header.column.getIsResizing() ? "rgba(0, 0, 0, 0.5)" : "transparent"
386
+ }
387
+ }
388
+ )
389
+ ]
390
+ },
391
+ header.id
392
+ ))
393
+ },
394
+ headerGroup.id
395
+ ))
396
+ }
397
+ ),
398
+ /* @__PURE__ */ jsx(
399
+ "tbody",
400
+ {
401
+ style: {
402
+ display: "grid",
403
+ height: `${totalSize}px`,
404
+ position: "relative"
405
+ },
406
+ children: virtualItems.map((virtualRow) => {
407
+ const row = rows[virtualRow.index];
408
+ const isExpanded = row.getIsExpanded();
409
+ const canExpand = enableRowExpansion && row.getCanExpand();
410
+ const isFocused = enableKeyboardNavigation && virtualRow.index === focusedRowIndex;
411
+ const handleRowClick = () => {
412
+ if (enableKeyboardNavigation) {
413
+ setFocusedRow(virtualRow.index);
414
+ }
415
+ if (canExpand) {
416
+ row.toggleExpanded();
417
+ }
418
+ };
419
+ return /* @__PURE__ */ jsxs(
420
+ "tr",
421
+ {
422
+ "data-index": virtualRow.index,
423
+ "data-expanded": isExpanded || void 0,
424
+ "data-focused": isFocused || void 0,
425
+ ref: (node) => virtualizer.measureElement(node),
426
+ style: {
427
+ display: "block",
428
+ position: "absolute",
429
+ transform: `translateY(${virtualRow.start}px)`,
430
+ width: "100%",
431
+ cursor: canExpand || enableKeyboardNavigation ? "pointer" : "default"
432
+ },
433
+ onClick: handleRowClick,
434
+ children: [
435
+ /* @__PURE__ */ jsx(
436
+ "div",
437
+ {
438
+ style: {
439
+ display: "flex",
440
+ width: "100%"
441
+ },
442
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(
443
+ "td",
444
+ {
445
+ style: {
446
+ flex: `0 0 ${cell.column.getSize()}px`
447
+ },
448
+ children: flexRender(cell.column.columnDef.cell, cell.getContext())
449
+ },
450
+ cell.id
451
+ ))
452
+ }
453
+ ),
454
+ isExpanded && renderExpandedRow && /* @__PURE__ */ jsx("div", { onClick: (e) => e.stopPropagation(), style: { width: "100%" }, children: renderExpandedRow(row) })
455
+ ]
456
+ },
457
+ row.id
458
+ );
459
+ })
460
+ }
461
+ )
462
+ ]
463
+ }
464
+ )
465
+ }
466
+ );
467
+ }
468
+
469
+ export { VirtualTable, useVirtualTable };
470
+ //# sourceMappingURL=index.js.map
471
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/VirtualTable/useVirtualTable.ts","../src/VirtualTable/VirtualTable.tsx"],"names":["useState"],"mappings":"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","file":"index.js","sourcesContent":["import { useRef, useCallback, useState, useMemo } from 'react';\nimport {\n useReactTable,\n getCoreRowModel,\n getSortedRowModel,\n getExpandedRowModel,\n type RowSelectionState,\n type SortingState,\n type ExpandedState,\n type ColumnSizingState,\n type ColumnOrderState,\n type Updater,\n type ColumnDef,\n} from '@tanstack/react-table';\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport type { UseVirtualTableOptions } from './types';\n\nconst DEFAULT_ROW_HEIGHT = 40;\nconst DEFAULT_EXPANDED_ROW_HEIGHT = 200;\nconst DEFAULT_OVERSCAN = 5;\nconst DEFAULT_SCROLL_THRESHOLD = 100;\n\n/** Extract column ID from a ColumnDef */\nfunction getColumnId<TData>(column: ColumnDef<TData, unknown>): string {\n // Check for explicit id first\n if ('id' in column && typeof column.id === 'string') {\n return column.id;\n }\n // Fall back to accessorKey for accessor columns\n if ('accessorKey' in column && typeof column.accessorKey === 'string') {\n return column.accessorKey;\n }\n return '';\n}\n\nexport function useVirtualTable<TData>(options: UseVirtualTableOptions<TData>) {\n const {\n data,\n columns,\n rowHeight = DEFAULT_ROW_HEIGHT,\n overscan = DEFAULT_OVERSCAN,\n enableRowSelection = false,\n rowSelection: controlledRowSelection,\n onRowSelectionChange,\n enableSorting = false,\n sorting: controlledSorting,\n onSortingChange,\n enableMultiSort = false,\n maxMultiSortColCount,\n enableColumnResizing = false,\n columnResizeMode = 'onChange',\n columnSizing: controlledColumnSizing,\n onColumnSizingChange,\n enableColumnReordering = false,\n columnOrder: controlledColumnOrder,\n onColumnOrderChange,\n enableRowExpansion = false,\n expanded: controlledExpanded,\n onExpandedChange,\n expandedRowHeight = DEFAULT_EXPANDED_ROW_HEIGHT,\n getRowCanExpand,\n getRowId,\n enableKeyboardNavigation = false,\n focusedRowIndex: controlledFocusedRowIndex,\n onFocusedRowChange,\n onScrollToBottom,\n scrollBottomThreshold = DEFAULT_SCROLL_THRESHOLD,\n } = options;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Default column order from column definitions\n const defaultColumnOrder = useMemo(() => columns.map(getColumnId), [columns]);\n\n // Internal state for uncontrolled mode\n const [internalRowSelection, setInternalRowSelection] = useState<RowSelectionState>({});\n const [internalSorting, setInternalSorting] = useState<SortingState>([]);\n const [internalExpanded, setInternalExpanded] = useState<ExpandedState>({});\n const [internalColumnSizing, setInternalColumnSizing] = useState<ColumnSizingState>({});\n const [internalColumnOrder, setInternalColumnOrder] = useState<ColumnOrderState>([]);\n const [internalFocusedRowIndex, setInternalFocusedRowIndex] = useState<number>(-1);\n\n // Use controlled or internal state\n const rowSelectionState = controlledRowSelection ?? internalRowSelection;\n const sortingState = controlledSorting ?? internalSorting;\n const expandedState = controlledExpanded ?? internalExpanded;\n const columnSizingState = controlledColumnSizing ?? internalColumnSizing;\n const columnOrderState =\n controlledColumnOrder ??\n (internalColumnOrder.length ? internalColumnOrder : defaultColumnOrder);\n const focusedRowIndex = controlledFocusedRowIndex ?? internalFocusedRowIndex;\n\n const handleRowSelectionChange = useCallback(\n (updater: Updater<RowSelectionState>) => {\n const newValue = typeof updater === 'function' ? updater(rowSelectionState) : updater;\n if (onRowSelectionChange) {\n onRowSelectionChange(newValue);\n } else {\n setInternalRowSelection(newValue);\n }\n },\n [rowSelectionState, onRowSelectionChange]\n );\n\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n const newValue = typeof updater === 'function' ? updater(sortingState) : updater;\n if (onSortingChange) {\n onSortingChange(newValue);\n } else {\n setInternalSorting(newValue);\n }\n },\n [sortingState, onSortingChange]\n );\n\n const handleExpandedChange = useCallback(\n (updater: Updater<ExpandedState>) => {\n const newValue = typeof updater === 'function' ? updater(expandedState) : updater;\n if (onExpandedChange) {\n onExpandedChange(newValue);\n } else {\n setInternalExpanded(newValue);\n }\n },\n [expandedState, onExpandedChange]\n );\n\n const handleColumnSizingChange = useCallback(\n (updater: Updater<ColumnSizingState>) => {\n const newValue = typeof updater === 'function' ? updater(columnSizingState) : updater;\n if (onColumnSizingChange) {\n onColumnSizingChange(newValue);\n } else {\n setInternalColumnSizing(newValue);\n }\n },\n [columnSizingState, onColumnSizingChange]\n );\n\n const handleColumnOrderChange = useCallback(\n (updater: Updater<ColumnOrderState>) => {\n const newValue = typeof updater === 'function' ? updater(columnOrderState) : updater;\n if (onColumnOrderChange) {\n onColumnOrderChange(newValue);\n } else {\n setInternalColumnOrder(newValue);\n }\n },\n [columnOrderState, onColumnOrderChange]\n );\n\n const table = useReactTable({\n data,\n columns,\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: enableSorting ? getSortedRowModel() : undefined,\n getExpandedRowModel: enableRowExpansion ? getExpandedRowModel() : undefined,\n enableRowSelection,\n enableSorting,\n enableMultiSort,\n maxMultiSortColCount,\n enableColumnResizing,\n columnResizeMode,\n getRowCanExpand: enableRowExpansion ? (getRowCanExpand ?? (() => true)) : undefined,\n state: {\n rowSelection: rowSelectionState,\n sorting: sortingState,\n expanded: expandedState,\n columnSizing: columnSizingState,\n columnOrder: enableColumnReordering ? columnOrderState : undefined,\n },\n onRowSelectionChange: handleRowSelectionChange,\n onSortingChange: handleSortingChange,\n onExpandedChange: handleExpandedChange,\n onColumnSizingChange: handleColumnSizingChange,\n onColumnOrderChange: enableColumnReordering ? handleColumnOrderChange : undefined,\n getRowId,\n });\n\n const { rows } = table.getRowModel();\n\n // Dynamic row height estimation based on expanded state\n const estimateSize = useCallback(\n (index: number) => {\n if (!enableRowExpansion) return rowHeight;\n const row = rows[index];\n return row?.getIsExpanded() ? rowHeight + expandedRowHeight : rowHeight;\n },\n [rows, rowHeight, expandedRowHeight, enableRowExpansion]\n );\n\n const virtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => containerRef.current,\n estimateSize,\n overscan,\n });\n\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n\n // Handle scroll to bottom detection\n const handleScroll = useCallback(() => {\n if (!onScrollToBottom || !containerRef.current) return;\n\n const { scrollTop, scrollHeight, clientHeight } = containerRef.current;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n\n if (distanceFromBottom < scrollBottomThreshold) {\n onScrollToBottom();\n }\n }, [onScrollToBottom, scrollBottomThreshold]);\n\n // Helper to reorder columns (for drag and drop)\n const reorderColumn = useCallback(\n (draggedColumnId: string, targetColumnId: string) => {\n const newOrder = [...columnOrderState];\n const draggedIndex = newOrder.indexOf(draggedColumnId);\n const targetIndex = newOrder.indexOf(targetColumnId);\n\n if (draggedIndex === -1 || targetIndex === -1) return;\n\n newOrder.splice(draggedIndex, 1);\n newOrder.splice(targetIndex, 0, draggedColumnId);\n\n handleColumnOrderChange(newOrder);\n },\n [columnOrderState, handleColumnOrderChange]\n );\n\n // Focus row change handler\n const setFocusedRow = useCallback(\n (index: number) => {\n const clampedIndex = Math.max(-1, Math.min(index, rows.length - 1));\n if (onFocusedRowChange) {\n onFocusedRowChange(clampedIndex);\n } else {\n setInternalFocusedRowIndex(clampedIndex);\n }\n // Scroll focused row into view\n if (clampedIndex >= 0) {\n virtualizer.scrollToIndex(clampedIndex, { align: 'auto' });\n }\n },\n [rows.length, onFocusedRowChange, virtualizer]\n );\n\n // Keyboard navigation handler\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (!enableKeyboardNavigation) return;\n\n const currentIndex = focusedRowIndex;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setFocusedRow(currentIndex + 1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n setFocusedRow(currentIndex - 1);\n break;\n case 'Home':\n e.preventDefault();\n setFocusedRow(0);\n break;\n case 'End':\n e.preventDefault();\n setFocusedRow(rows.length - 1);\n break;\n case 'Enter':\n if (currentIndex >= 0 && enableRowExpansion) {\n e.preventDefault();\n const row = rows[currentIndex];\n if (row?.getCanExpand()) {\n row.toggleExpanded();\n }\n }\n break;\n case ' ':\n if (currentIndex >= 0 && enableRowSelection) {\n e.preventDefault();\n const row = rows[currentIndex];\n row?.toggleSelected();\n }\n break;\n }\n },\n [\n enableKeyboardNavigation,\n focusedRowIndex,\n rows,\n enableRowExpansion,\n enableRowSelection,\n setFocusedRow,\n ]\n );\n\n return {\n table,\n rows,\n virtualizer,\n virtualItems,\n totalSize,\n containerRef,\n handleScroll,\n handleKeyDown,\n reorderColumn,\n setFocusedRow,\n // Expose state for consumers\n rowSelection: rowSelectionState,\n sorting: sortingState,\n expanded: expandedState,\n columnSizing: columnSizingState,\n columnOrder: columnOrderState,\n focusedRowIndex,\n };\n}\n","import { useState } from 'react';\nimport { flexRender } from '@tanstack/react-table';\nimport { useVirtualTable } from './useVirtualTable';\nimport type { VirtualTableProps } from './types';\n\nconst DEFAULT_HEIGHT = 400;\n\nexport function VirtualTable<TData>(props: VirtualTableProps<TData>) {\n const {\n height = DEFAULT_HEIGHT,\n stickyHeader = true,\n renderExpandedRow,\n className,\n style,\n ...tableOptions\n } = props;\n\n const {\n rows,\n virtualizer,\n virtualItems,\n totalSize,\n containerRef,\n handleScroll,\n handleKeyDown,\n table,\n reorderColumn,\n setFocusedRow,\n focusedRowIndex,\n } = useVirtualTable(tableOptions);\n\n const headerGroups = table.getHeaderGroups();\n const enableRowExpansion = tableOptions.enableRowExpansion;\n const enableColumnResizing = tableOptions.enableColumnResizing;\n const enableColumnReordering = tableOptions.enableColumnReordering;\n const enableKeyboardNavigation = tableOptions.enableKeyboardNavigation;\n\n // Drag state for column reordering\n const [draggedColumnId, setDraggedColumnId] = useState<string | null>(null);\n\n return (\n <div\n ref={containerRef}\n className={className}\n tabIndex={enableKeyboardNavigation ? 0 : undefined}\n style={{\n height,\n overflow: 'auto',\n position: 'relative',\n outline: 'none',\n ...style,\n }}\n onScroll={handleScroll}\n onKeyDown={enableKeyboardNavigation ? handleKeyDown : undefined}\n >\n <table\n style={{\n display: 'grid',\n width: '100%',\n }}\n >\n <thead\n style={{\n display: 'grid',\n position: stickyHeader ? 'sticky' : 'relative',\n top: 0,\n zIndex: 1,\n }}\n >\n {headerGroups.map((headerGroup) => (\n <tr\n key={headerGroup.id}\n style={{\n display: 'flex',\n width: '100%',\n }}\n >\n {headerGroup.headers.map((header) => (\n <th\n key={header.id}\n draggable={enableColumnReordering && !header.isPlaceholder}\n data-dragging={draggedColumnId === header.column.id || undefined}\n onDragStart={\n enableColumnReordering\n ? (e) => {\n setDraggedColumnId(header.column.id);\n e.dataTransfer.effectAllowed = 'move';\n }\n : undefined\n }\n onDragOver={\n enableColumnReordering\n ? (e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n }\n : undefined\n }\n onDrop={\n enableColumnReordering\n ? (e) => {\n e.preventDefault();\n if (draggedColumnId && draggedColumnId !== header.column.id) {\n reorderColumn(draggedColumnId, header.column.id);\n }\n }\n : undefined\n }\n onDragEnd={enableColumnReordering ? () => setDraggedColumnId(null) : undefined}\n style={{\n flex: `0 0 ${header.getSize()}px`,\n cursor: enableColumnReordering\n ? 'grab'\n : header.column.getCanSort()\n ? 'pointer'\n : 'default',\n position: 'relative',\n opacity: draggedColumnId === header.column.id ? 0.5 : 1,\n }}\n onClick={\n !enableColumnReordering ? header.column.getToggleSortingHandler() : undefined\n }\n >\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n {header.column.getIsSorted() === 'asc' && ' ↑'}\n {header.column.getIsSorted() === 'desc' && ' ↓'}\n\n {/* Column resize handle */}\n {enableColumnResizing && header.column.getCanResize() && (\n <div\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onClick={(e) => e.stopPropagation()}\n className=\"virtual-table-resizer\"\n data-resizing={header.column.getIsResizing() || undefined}\n style={{\n position: 'absolute',\n right: 0,\n top: 0,\n height: '100%',\n width: '5px',\n cursor: 'col-resize',\n userSelect: 'none',\n touchAction: 'none',\n background: header.column.getIsResizing()\n ? 'rgba(0, 0, 0, 0.5)'\n : 'transparent',\n }}\n />\n )}\n </th>\n ))}\n </tr>\n ))}\n </thead>\n <tbody\n style={{\n display: 'grid',\n height: `${totalSize}px`,\n position: 'relative',\n }}\n >\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index];\n const isExpanded = row.getIsExpanded();\n const canExpand = enableRowExpansion && row.getCanExpand();\n const isFocused = enableKeyboardNavigation && virtualRow.index === focusedRowIndex;\n\n const handleRowClick = () => {\n if (enableKeyboardNavigation) {\n setFocusedRow(virtualRow.index);\n }\n if (canExpand) {\n row.toggleExpanded();\n }\n };\n\n return (\n <tr\n key={row.id}\n data-index={virtualRow.index}\n data-expanded={isExpanded || undefined}\n data-focused={isFocused || undefined}\n ref={(node) => virtualizer.measureElement(node)}\n style={{\n display: 'block',\n position: 'absolute',\n transform: `translateY(${virtualRow.start}px)`,\n width: '100%',\n cursor: canExpand || enableKeyboardNavigation ? 'pointer' : 'default',\n }}\n onClick={handleRowClick}\n >\n {/* Row cells */}\n <div\n style={{\n display: 'flex',\n width: '100%',\n }}\n >\n {row.getVisibleCells().map((cell) => (\n <td\n key={cell.id}\n style={{\n flex: `0 0 ${cell.column.getSize()}px`,\n }}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </div>\n\n {/* Expanded content */}\n {isExpanded && renderExpandedRow && (\n <div onClick={(e) => e.stopPropagation()} style={{ width: '100%' }}>\n {renderExpandedRow(row)}\n </div>\n )}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,18 +1,74 @@
1
1
  {
2
2
  "name": "virtualized-ui",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "description": "Headless virtualized table and select components for React",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "sideEffects": false,
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "dev": "tsup --watch",
28
+ "typecheck": "tsc --noEmit",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest"
31
+ },
5
32
  "keywords": [
6
33
  "react",
7
34
  "virtual",
35
+ "virtualized",
8
36
  "table",
9
37
  "select",
10
38
  "headless",
11
- "tanstack"
39
+ "tanstack",
40
+ "react-table",
41
+ "react-virtual"
12
42
  ],
13
43
  "license": "MIT",
14
44
  "repository": {
15
45
  "type": "git",
16
- "url": "git+https://github.com/grishalr/virtualized-ui.git"
46
+ "url": "git+https://github.com/grishalr/virtualized-ui.git",
47
+ "directory": "packages/core"
48
+ },
49
+ "homepage": "https://github.com/grishalr/virtualized-ui#readme",
50
+ "bugs": {
51
+ "url": "https://github.com/grishalr/virtualized-ui/issues"
52
+ },
53
+ "peerDependencies": {
54
+ "react": ">=18.0.0",
55
+ "react-dom": ">=18.0.0"
56
+ },
57
+ "dependencies": {
58
+ "@tanstack/react-table": "^8.20.0",
59
+ "@tanstack/react-virtual": "^3.10.0"
60
+ },
61
+ "devDependencies": {
62
+ "@testing-library/dom": "^10.4.1",
63
+ "@testing-library/react": "^16.3.2",
64
+ "@types/react": "^18.3.0",
65
+ "@types/react-dom": "^18.3.0",
66
+ "@vitejs/plugin-react": "^5.1.2",
67
+ "jsdom": "^27.4.0",
68
+ "react": "^18.3.0",
69
+ "react-dom": "^18.3.0",
70
+ "tsup": "^8.3.0",
71
+ "typescript": "^5.6.0",
72
+ "vitest": "^4.0.18"
17
73
  }
18
- }
74
+ }
package/CLAUDE.MD DELETED
@@ -1,54 +0,0 @@
1
- # CLAUDE.md
2
-
3
- ## Project Overview
4
-
5
- virtual-ui is a component library providing virtualized table and select primitives for React. Headless by design — logic and structure, no styles.
6
-
7
- ## Architecture
8
-
9
- ```
10
- packages/core/ # npm package (@virtual-ui/core)
11
- docs/ # Astro docs site
12
- .storybook/ # Storybook config (stories live in packages/core/src/)
13
- ```
14
-
15
- ## Key Dependencies
16
-
17
- - **VirtualTable**: TanStack Table + TanStack Virtual
18
- - **VirtualSelect**: react-select + TanStack Virtual
19
- - **Docs**: Astro + Tailwind + daisyUI
20
-
21
- ## Commands
22
-
23
- ```bash
24
- pnpm dev # Storybook (development)
25
- pnpm build # Build package
26
- pnpm build:docs # Build docs site
27
- cd docs && pnpm dev # Run docs locally
28
- ```
29
-
30
- ## Component Guidelines
31
-
32
- - Single component per feature, props enable variants (no separate AsyncSelect, etc.)
33
- - All features opt-in via props
34
- - No default styles — render semantic HTML, let users style
35
- - Export types alongside components
36
-
37
- ## File Conventions
38
-
39
- - `ComponentName.tsx` — component implementation
40
- - `ComponentName.stories.tsx` — Storybook stories
41
- - `types.ts` — TypeScript types per component folder
42
-
43
- ## Testing Changes
44
-
45
- 1. Run Storybook (`pnpm dev`)
46
- 2. Check relevant stories
47
- 3. Test with 10k items to verify virtualization works
48
-
49
- ## Publishing
50
-
51
- ```bash
52
- pnpm build
53
- cd packages/core && npm publish --access public
54
- ```