@requence/table 0.0.0 → 1.0.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 CHANGED
@@ -1,14 +1,694 @@
1
+ // src/VirtualTable.tsx
2
+ import {
3
+ Children,
4
+ isValidElement,
5
+ useCallback,
6
+ useEffect,
7
+ useRef,
8
+ useState
9
+ } from "react";
10
+ import { flushSync } from "react-dom";
11
+ import { twMerge } from "tailwind-merge";
12
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
13
+ function asSlot(slot, defaults) {
14
+ const Component = () => null;
15
+ Component.slot = slot;
16
+ Component.slotDefaults = defaults ?? {};
17
+ return Component;
18
+ }
19
+ function createTableHeader(defaults) {
20
+ return asSlot("header", defaults);
21
+ }
22
+ function createTableColumn(defaults) {
23
+ return asSlot("column", defaults);
24
+ }
25
+ function createTableBody(defaults) {
26
+ return asSlot("body", defaults);
27
+ }
28
+ function createTableSkeletonRow(defaults) {
29
+ return asSlot("skeletonRow", defaults);
30
+ }
31
+ function createTableEmpty(defaults) {
32
+ return asSlot("empty", defaults);
33
+ }
34
+ function createTableFooter(defaults) {
35
+ return asSlot("footer", defaults);
36
+ }
37
+ function createTableRow(defaults) {
38
+ return asSlot("row", defaults);
39
+ }
40
+ var GRID_VAR = "--vtable-grid-cols";
41
+ var GRID_VAR_REF = `var(${GRID_VAR})`;
42
+ function buildGridTemplate(columns) {
43
+ return columns.map((col) => {
44
+ if (typeof col.width === "number") {
45
+ return `${col.width}px`;
46
+ }
47
+ const min = col.minWidth ? `${col.minWidth}px` : "0";
48
+ if (typeof col.width === "string") {
49
+ return `minmax(${min}, ${col.width})`;
50
+ }
51
+ return `minmax(${min}, 1fr)`;
52
+ }).join(" ");
53
+ }
54
+ var VirtualTableHeader = asSlot("header");
55
+ var VirtualTableColumn = asSlot("column");
56
+ var VirtualTableBody = asSlot("body");
57
+ var VirtualTableRow = asSlot("row");
58
+ var VirtualTableSkeletonRow = asSlot("skeletonRow");
59
+ var VirtualTableEmpty = asSlot("empty");
60
+ var VirtualTableFooter = asSlot("footer");
61
+ function slotIs(child, slot) {
62
+ return child.type?.slot === slot;
63
+ }
64
+ function extractSlots(children) {
65
+ let header = null;
66
+ let body = null;
67
+ let skeletonRow = null;
68
+ let empty = null;
69
+ let footer = null;
70
+ Children.forEach(children, (child) => {
71
+ if (!isValidElement(child)) {
72
+ return;
73
+ }
74
+ if (slotIs(child, "header")) {
75
+ const defaults = child.type.slotDefaults ?? {};
76
+ const props = child.props;
77
+ const columns = [];
78
+ Children.forEach(props.children, (col) => {
79
+ if (isValidElement(col) && slotIs(col, "column")) {
80
+ const d = col.type.slotDefaults ?? {};
81
+ const p = col.props;
82
+ columns.push({
83
+ width: p.width ?? d.width,
84
+ header: p.children,
85
+ className: twMerge(d.className, p.className),
86
+ resizable: p.resizable ?? d.resizable,
87
+ minWidth: p.minWidth ?? d.minWidth,
88
+ maxWidth: p.maxWidth ?? d.maxWidth,
89
+ transparent: p.transparent ?? d.transparent,
90
+ onResizeStart: p.onResizeStart ?? d.onResizeStart,
91
+ onResizeEnd: p.onResizeEnd ?? d.onResizeEnd
92
+ });
93
+ }
94
+ });
95
+ header = {
96
+ className: twMerge(defaults.className, props.className),
97
+ columns
98
+ };
99
+ } else if (slotIs(child, "body")) {
100
+ body = child.props;
101
+ } else if (slotIs(child, "skeletonRow")) {
102
+ const defaults = child.type.slotDefaults ?? {};
103
+ const props = child.props;
104
+ skeletonRow = {
105
+ ...defaults,
106
+ ...props,
107
+ className: twMerge(defaults.className, props.className)
108
+ };
109
+ } else if (slotIs(child, "empty")) {
110
+ const defaults = child.type.slotDefaults ?? {};
111
+ const props = child.props;
112
+ empty = {
113
+ ...defaults,
114
+ ...props,
115
+ className: twMerge(defaults.className, props.className)
116
+ };
117
+ } else if (slotIs(child, "footer")) {
118
+ const defaults = child.type.slotDefaults ?? {};
119
+ const props = child.props;
120
+ footer = {
121
+ ...defaults,
122
+ ...props,
123
+ className: twMerge(defaults.className, props.className)
124
+ };
125
+ }
126
+ });
127
+ return { header, body, skeletonRow, empty, footer };
128
+ }
129
+ function ResizeHandle({ onMouseDown }) {
130
+ return /* @__PURE__ */ jsx("div", {
131
+ role: "separator",
132
+ "aria-orientation": "vertical",
133
+ className: "resizer absolute right-0 top-0 z-10 h-full w-1.5 cursor-col-resize",
134
+ onMouseDown
135
+ });
136
+ }
137
+ function VirtualTableCell({
138
+ className,
139
+ style,
140
+ showOnHover,
141
+ colSpan,
142
+ ...rest
143
+ }) {
144
+ return /* @__PURE__ */ jsx("div", {
145
+ role: "cell",
146
+ className: twMerge("overflow-hidden text-ellipsis whitespace-nowrap", showOnHover && "not-group-hover/row:*:delay-200 *:opacity-10 *:transition-opacity *:duration-300 *:ease-in-out group-hover/row:*:opacity-100", className),
147
+ style: colSpan ? { gridColumn: `span ${colSpan}`, ...style } : style,
148
+ ...rest
149
+ });
150
+ }
151
+ function DataRow({ index, rowHeight, rowProps, children }) {
152
+ const { className, style, ...restProps } = rowProps;
153
+ return /* @__PURE__ */ jsx("div", {
154
+ role: "row",
155
+ "aria-rowindex": index + 1,
156
+ className: twMerge("group/row absolute w-full", className),
157
+ style: {
158
+ height: rowHeight,
159
+ transform: `translateY(${index * rowHeight}px)`,
160
+ display: "grid",
161
+ gridTemplateColumns: GRID_VAR_REF,
162
+ alignItems: "center",
163
+ willChange: "transform",
164
+ contain: "layout style paint",
165
+ ...style
166
+ },
167
+ ...restProps,
168
+ children
169
+ });
170
+ }
171
+ function VirtualTableRoot({
172
+ totalCount,
173
+ rowHeight,
174
+ overscan = 5,
175
+ onRangeChange,
176
+ className,
177
+ style: styleProp,
178
+ "aria-label": ariaLabel,
179
+ children
180
+ }) {
181
+ const scrollRef = useRef(null);
182
+ const [visibleRange, setVisibleRange] = useState({ start: 0, end: 0 });
183
+ const prevRangeRef = useRef({ start: 0, end: 0 });
184
+ const { header, body, skeletonRow, empty, footer } = extractSlots(children);
185
+ const columns = header?.columns ?? [];
186
+ const gridTemplate = buildGridTemplate(columns);
187
+ const renderRow = body?.children ?? (() => null);
188
+ const calculateRange = useCallback(() => {
189
+ const el = scrollRef.current;
190
+ if (!el || totalCount === 0) {
191
+ return;
192
+ }
193
+ const scrollTop = el.scrollTop;
194
+ const viewportHeight = el.clientHeight;
195
+ const rawStart = Math.floor(scrollTop / rowHeight);
196
+ const rawEnd = Math.ceil((scrollTop + viewportHeight) / rowHeight);
197
+ const start = Math.max(0, rawStart - overscan);
198
+ const end = Math.min(totalCount, rawEnd + overscan);
199
+ const prev = prevRangeRef.current;
200
+ if (prev.start !== start || prev.end !== end) {
201
+ prevRangeRef.current = { start, end };
202
+ flushSync(() => setVisibleRange({ start, end }));
203
+ }
204
+ }, [totalCount, rowHeight, overscan]);
205
+ const handleScroll = useCallback(() => {
206
+ calculateRange();
207
+ }, [calculateRange]);
208
+ useEffect(() => {
209
+ calculateRange();
210
+ }, [calculateRange]);
211
+ useEffect(() => {
212
+ onRangeChange?.(visibleRange);
213
+ }, [visibleRange, onRangeChange]);
214
+ const handleResizeMouseDown = useCallback((columnIndex, e) => {
215
+ e.preventDefault();
216
+ const container = scrollRef.current;
217
+ if (!container) {
218
+ return;
219
+ }
220
+ const col = columns[columnIndex];
221
+ const headerCells = container.querySelectorAll('[role="columnheader"]');
222
+ const startWidth = headerCells[columnIndex]?.getBoundingClientRect().width ?? (typeof col.width === "number" ? col.width : 100);
223
+ const startX = e.clientX;
224
+ const minW = col.minWidth ?? 50;
225
+ const maxW = col.maxWidth ?? Infinity;
226
+ const otherColumnsMinWidth = columns.reduce((sum, c, i) => {
227
+ if (i === columnIndex) {
228
+ return sum;
229
+ }
230
+ if (typeof c.width === "number") {
231
+ return sum + c.width;
232
+ }
233
+ return sum + (c.minWidth ?? 0);
234
+ }, 0);
235
+ const maxAllowedWidth = container.clientWidth - otherColumnsMinWidth;
236
+ let currentWidth = startWidth;
237
+ col.onResizeStart?.();
238
+ const prevCursor = document.body.style.cursor;
239
+ document.body.style.cursor = "col-resize";
240
+ const handleMouseMove = (moveEvent) => {
241
+ const delta = moveEvent.clientX - startX;
242
+ currentWidth = Math.min(maxW, maxAllowedWidth, Math.max(minW, startWidth + delta));
243
+ const template = columns.map((c, i) => {
244
+ if (i === columnIndex) {
245
+ return `${currentWidth}px`;
246
+ }
247
+ return buildGridTemplate([c]);
248
+ }).join(" ");
249
+ container.style.setProperty(GRID_VAR, template);
250
+ };
251
+ const handleMouseUp = () => {
252
+ document.body.style.cursor = prevCursor;
253
+ document.removeEventListener("mousemove", handleMouseMove);
254
+ document.removeEventListener("mouseup", handleMouseUp);
255
+ const allCells = container.querySelectorAll('[role="columnheader"]');
256
+ let otherFrPx = 0;
257
+ let otherFrUnits = 0;
258
+ columns.forEach((c, i) => {
259
+ if (i === columnIndex) {
260
+ return;
261
+ }
262
+ if (typeof c.width !== "number") {
263
+ otherFrPx += allCells[i]?.getBoundingClientRect().width ?? 0;
264
+ otherFrUnits += typeof c.width === "string" ? parseFloat(c.width) || 1 : 1;
265
+ }
266
+ });
267
+ const frValue = otherFrPx > 0 ? currentWidth / otherFrPx * otherFrUnits : 1;
268
+ col.onResizeEnd?.(currentWidth, startWidth, frValue);
269
+ };
270
+ document.addEventListener("mousemove", handleMouseMove);
271
+ document.addEventListener("mouseup", handleMouseUp);
272
+ }, [columns]);
273
+ if (totalCount === 0 && empty) {
274
+ return /* @__PURE__ */ jsxs("div", {
275
+ role: "table",
276
+ "aria-label": ariaLabel,
277
+ className: twMerge("flex flex-col overflow-hidden", className),
278
+ style: { [GRID_VAR]: gridTemplate, ...styleProp },
279
+ children: [
280
+ /* @__PURE__ */ jsx("div", {
281
+ role: "rowgroup",
282
+ className: twMerge("sticky top-0 z-10", header?.className),
283
+ children: /* @__PURE__ */ jsx("div", {
284
+ role: "row",
285
+ style: {
286
+ display: "grid",
287
+ gridTemplateColumns: GRID_VAR_REF,
288
+ alignItems: "center",
289
+ height: rowHeight
290
+ },
291
+ children: columns.map((col, i) => /* @__PURE__ */ jsxs("div", {
292
+ role: "columnheader",
293
+ className: twMerge("whitespace-nowrap", col.resizable && "relative", col.className),
294
+ children: [
295
+ col.header,
296
+ col.resizable && /* @__PURE__ */ jsx(ResizeHandle, {
297
+ onMouseDown: (e) => handleResizeMouseDown(i, e)
298
+ })
299
+ ]
300
+ }, i))
301
+ })
302
+ }),
303
+ /* @__PURE__ */ jsx("div", {
304
+ className: twMerge("flex items-center justify-center", empty.className),
305
+ children: empty.children
306
+ })
307
+ ]
308
+ });
309
+ }
310
+ const rows = [];
311
+ for (let i = visibleRange.start;i < visibleRange.end; i++) {
312
+ const content = renderRow(i);
313
+ if (content === null) {
314
+ if (skeletonRow) {
315
+ const { children: skeletonContent, ...skeletonProps } = skeletonRow;
316
+ rows.push(/* @__PURE__ */ jsx(DataRow, {
317
+ index: i,
318
+ rowHeight,
319
+ rowProps: skeletonProps,
320
+ children: skeletonContent
321
+ }, `row-${i}`));
322
+ }
323
+ } else {
324
+ const rowElement = content;
325
+ const rowDefaults = rowElement.type?.slotDefaults ?? {};
326
+ const rawProps = rowElement.props;
327
+ const { children: cellContent, ...userRowProps } = rawProps;
328
+ const rowProps = {
329
+ ...rowDefaults,
330
+ ...userRowProps,
331
+ className: twMerge(rowDefaults.className, userRowProps.className)
332
+ };
333
+ rows.push(/* @__PURE__ */ jsx(DataRow, {
334
+ index: i,
335
+ rowHeight,
336
+ rowProps,
337
+ children: cellContent
338
+ }, `row-${i}`));
339
+ }
340
+ }
341
+ const totalHeight = totalCount * rowHeight;
342
+ return /* @__PURE__ */ jsxs(Fragment, {
343
+ children: [
344
+ /* @__PURE__ */ jsxs("div", {
345
+ role: "table",
346
+ "aria-label": ariaLabel,
347
+ "aria-rowcount": totalCount,
348
+ ref: scrollRef,
349
+ onScroll: handleScroll,
350
+ className: twMerge("relative overflow-auto", className),
351
+ style: { [GRID_VAR]: gridTemplate, ...styleProp },
352
+ children: [
353
+ /* @__PURE__ */ jsx("div", {
354
+ role: "rowgroup",
355
+ className: twMerge("sticky top-0 z-10", header?.className),
356
+ children: /* @__PURE__ */ jsx("div", {
357
+ role: "row",
358
+ style: {
359
+ display: "grid",
360
+ gridTemplateColumns: GRID_VAR_REF,
361
+ alignItems: "center"
362
+ },
363
+ children: columns.map((col, i) => /* @__PURE__ */ jsxs("div", {
364
+ role: "columnheader",
365
+ className: twMerge("whitespace-nowrap", col.resizable && "relative", col.className),
366
+ children: [
367
+ col.header,
368
+ col.resizable && /* @__PURE__ */ jsx(ResizeHandle, {
369
+ onMouseDown: (e) => handleResizeMouseDown(i, e)
370
+ })
371
+ ]
372
+ }, i))
373
+ })
374
+ }),
375
+ /* @__PURE__ */ jsx("div", {
376
+ role: "rowgroup",
377
+ className: "relative",
378
+ style: { height: totalHeight },
379
+ children: rows
380
+ })
381
+ ]
382
+ }),
383
+ footer && totalCount > 0 && /* @__PURE__ */ jsx("div", {
384
+ className: footer.className,
385
+ children: footer.children(visibleRange)
386
+ })
387
+ ]
388
+ });
389
+ }
390
+ var VirtualTable = Object.assign(VirtualTableRoot, {
391
+ Header: VirtualTableHeader,
392
+ Column: VirtualTableColumn,
393
+ Body: VirtualTableBody,
394
+ SkeletonRow: VirtualTableSkeletonRow,
395
+ Row: VirtualTableRow,
396
+ Cell: VirtualTableCell,
397
+ Empty: VirtualTableEmpty,
398
+ Footer: VirtualTableFooter
399
+ });
400
+
401
+ // src/useTableCache.ts
402
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
403
+ var cacheMap = new Map;
404
+ function resolveCache(id, options, pageSize) {
405
+ let state = cacheMap.get(id);
406
+ if (!state) {
407
+ state = {
408
+ pages: new Map,
409
+ totalCount: 0,
410
+ inflight: new Set,
411
+ compare: options.compare,
412
+ fetchItems: options.fetchItems,
413
+ fetchCount: options.fetchCount,
414
+ getItemId: options.getItemId,
415
+ promise: null,
416
+ knownIds: new Set,
417
+ fetchCountTimer: null
418
+ };
419
+ cacheMap.set(id, state);
420
+ const s = state;
421
+ s.promise = options.fetchItems(0, pageSize).then((result) => {
422
+ if (cacheMap.get(id) === s) {
423
+ s.pages.set(0, result.items);
424
+ s.totalCount = result.total;
425
+ for (const item of result.items) {
426
+ s.knownIds.add(s.getItemId(item));
427
+ }
428
+ }
429
+ }).then(() => {
430
+ s.promise = null;
431
+ }).catch((error) => {
432
+ console.error(error);
433
+ throw error;
434
+ });
435
+ }
436
+ state.fetchItems = options.fetchItems;
437
+ state.fetchCount = options.fetchCount;
438
+ state.compare = options.compare;
439
+ state.getItemId = options.getItemId;
440
+ return state;
441
+ }
442
+ function useTableCache(key, options) {
443
+ const { pageSize, getItemId, compare, fetchItems, fetchCount } = options;
444
+ const [, forceRender] = useState2(0);
445
+ const [iteration, setIteration] = useState2(0);
446
+ const rerender = useCallback2(() => {
447
+ forceRender((c) => c + 1);
448
+ }, []);
449
+ const activeKey = [key, iteration].join("-");
450
+ const currentCache = resolveCache(activeKey, { fetchItems, fetchCount, compare, getItemId }, pageSize);
451
+ const cacheRef = useRef2(currentCache);
452
+ cacheRef.current = currentCache;
453
+ if (currentCache.promise) {
454
+ throw currentCache.promise;
455
+ }
456
+ useEffect2(() => () => {
457
+ for (const k of cacheMap.keys()) {
458
+ if (k.startsWith(key)) {
459
+ cacheMap.delete(k);
460
+ }
461
+ }
462
+ }, [key]);
463
+ const fetchPage = useCallback2((pageIndex) => {
464
+ const c = cacheRef.current;
465
+ if (c.pages.has(pageIndex) || c.inflight.has(pageIndex)) {
466
+ return;
467
+ }
468
+ const offset = pageIndex * pageSize;
469
+ c.inflight.add(pageIndex);
470
+ c.fetchItems(offset, pageSize).then((result) => {
471
+ if (cacheRef.current === c) {
472
+ c.pages.set(pageIndex, result.items);
473
+ c.totalCount = result.total;
474
+ c.inflight.delete(pageIndex);
475
+ for (const item of result.items) {
476
+ c.knownIds.add(c.getItemId(item));
477
+ }
478
+ rerender();
479
+ }
480
+ });
481
+ }, [pageSize, rerender]);
482
+ const getItem = useCallback2((index) => {
483
+ const c = cacheRef.current;
484
+ const pageIndex = Math.floor(index / pageSize);
485
+ const page = c.pages.get(pageIndex);
486
+ if (!page) {
487
+ return;
488
+ }
489
+ const offsetInPage = index - pageIndex * pageSize;
490
+ return page[offsetInPage];
491
+ }, [pageSize]);
492
+ const handleRangeChange = useCallback2((range) => {
493
+ const c = cacheRef.current;
494
+ if (c.totalCount === 0) {
495
+ return;
496
+ }
497
+ const startPage = Math.floor(range.start / pageSize);
498
+ const endPage = Math.floor(Math.min(range.end, c.totalCount - 1) / pageSize);
499
+ for (let p = startPage;p <= endPage; p++) {
500
+ fetchPage(p);
501
+ }
502
+ }, [pageSize, fetchPage]);
503
+ const debouncedFetchCount = useCallback2(() => {
504
+ const c = cacheRef.current;
505
+ if (!c.fetchCount) {
506
+ return;
507
+ }
508
+ if (c.fetchCountTimer) {
509
+ clearTimeout(c.fetchCountTimer);
510
+ }
511
+ c.fetchCountTimer = setTimeout(() => {
512
+ const current = cacheRef.current;
513
+ current.fetchCountTimer = null;
514
+ current.fetchCount?.().then((total) => {
515
+ if (cacheRef.current === current) {
516
+ current.totalCount = total;
517
+ rerender();
518
+ }
519
+ });
520
+ }, 150);
521
+ }, [rerender]);
522
+ const upsert = useCallback2((item) => {
523
+ const c = cacheRef.current;
524
+ const id = getItemId(item);
525
+ for (const [, page] of c.pages) {
526
+ const idx = page.findIndex((p) => getItemId(p) === id);
527
+ if (idx !== -1) {
528
+ page[idx] = item;
529
+ rerender();
530
+ return;
531
+ }
532
+ }
533
+ if (c.knownIds.has(id)) {
534
+ return;
535
+ }
536
+ c.knownIds.add(id);
537
+ let inserted = false;
538
+ const sortedPageIndices = [...c.pages.keys()].sort((a, b) => a - b);
539
+ for (const pageIndex of sortedPageIndices) {
540
+ const page = c.pages.get(pageIndex);
541
+ if (page.length > 0 && c.compare(item, page[0]) <= 0) {
542
+ page.unshift(item);
543
+ inserted = true;
544
+ invalidateAfter(c, pageIndex);
545
+ break;
546
+ }
547
+ if (page.length > 0) {
548
+ const lastItem = page[page.length - 1];
549
+ if (c.compare(item, lastItem) <= 0) {
550
+ let lo = 0;
551
+ let hi = page.length;
552
+ while (lo < hi) {
553
+ const mid = lo + hi >>> 1;
554
+ if (c.compare(item, page[mid]) <= 0) {
555
+ hi = mid;
556
+ } else {
557
+ lo = mid + 1;
558
+ }
559
+ }
560
+ page.splice(lo, 0, item);
561
+ inserted = true;
562
+ invalidateAfter(c, pageIndex);
563
+ break;
564
+ }
565
+ }
566
+ }
567
+ if (!inserted) {
568
+ if (sortedPageIndices.length > 0) {
569
+ const firstPageIndex = sortedPageIndices[0];
570
+ const firstPage = c.pages.get(firstPageIndex);
571
+ if (firstPage.length > 0 && c.compare(item, firstPage[0]) <= 0) {
572
+ firstPage.unshift(item);
573
+ invalidateAfter(c, firstPageIndex);
574
+ }
575
+ }
576
+ }
577
+ if (c.fetchCount) {
578
+ debouncedFetchCount();
579
+ } else {
580
+ c.totalCount += 1;
581
+ }
582
+ rerender();
583
+ }, [getItemId, rerender, debouncedFetchCount]);
584
+ const remove = useCallback2((id) => {
585
+ const c = cacheRef.current;
586
+ let removedFromPage = null;
587
+ c.knownIds.delete(id);
588
+ for (const [pageIndex, page] of c.pages) {
589
+ const idx = page.findIndex((item) => getItemId(item) === id);
590
+ if (idx !== -1) {
591
+ page.splice(idx, 1);
592
+ removedFromPage = pageIndex;
593
+ break;
594
+ }
595
+ }
596
+ c.totalCount = Math.max(0, c.totalCount - 1);
597
+ if (removedFromPage !== null) {
598
+ invalidateAfter(c, removedFromPage);
599
+ }
600
+ rerender();
601
+ }, [getItemId, rerender]);
602
+ const reset = useCallback2(() => {
603
+ const c = cacheRef.current;
604
+ if (c.fetchCountTimer) {
605
+ clearTimeout(c.fetchCountTimer);
606
+ c.fetchCountTimer = null;
607
+ }
608
+ setIteration((iteration2) => iteration2 + 1);
609
+ rerender();
610
+ }, [rerender]);
611
+ return {
612
+ totalCount: currentCache.totalCount,
613
+ getItem,
614
+ handleRangeChange,
615
+ upsert,
616
+ remove,
617
+ reset,
618
+ loading: currentCache.inflight.size > 0
619
+ };
620
+ }
621
+ function invalidateAfter(cache, afterPageIndex) {
622
+ for (const key of cache.pages.keys()) {
623
+ if (key > afterPageIndex) {
624
+ cache.pages.delete(key);
625
+ }
626
+ }
627
+ }
628
+
629
+ // src/useTableColumnWidths.ts
630
+ import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
631
+ function loadPersisted(key) {
632
+ try {
633
+ const raw = localStorage.getItem(`columnWidths:${key}`);
634
+ return raw ? JSON.parse(raw) : null;
635
+ } catch {
636
+ return null;
637
+ }
638
+ }
639
+ function useTableColumnWidths(options) {
640
+ const persistKey = options?.persist;
641
+ const [widths, setWidths] = useState3(() => (persistKey ? loadPersisted(persistKey) : null) ?? {});
642
+ useEffect3(() => {
643
+ if (persistKey) {
644
+ localStorage.setItem(`columnWidths:${persistKey}`, JSON.stringify(widths));
645
+ }
646
+ }, [widths, persistKey]);
647
+ const register = useCallback3((key, registerOptions) => ({
648
+ width: widths[key] ?? registerOptions?.defaultValue,
649
+ resizable: true,
650
+ onResizeEnd: (width, _startWidth, frValue) => {
651
+ if (registerOptions?.relative) {
652
+ setWidths((prev) => ({
653
+ ...prev,
654
+ [key]: `${parseFloat(frValue.toFixed(2))}fr`
655
+ }));
656
+ } else {
657
+ setWidths((prev) => ({ ...prev, [key]: width }));
658
+ }
659
+ }
660
+ }), [widths]);
661
+ const reset = useCallback3(() => {
662
+ setWidths({});
663
+ if (persistKey) {
664
+ localStorage.removeItem(`columnWidths:${persistKey}`);
665
+ }
666
+ }, [persistKey]);
667
+ return { register, reset };
668
+ }
669
+
670
+ // src/index.ts
671
+ var VirtualTable2 = VirtualTable;
672
+ var createTableHeader2 = createTableHeader;
673
+ var createTableColumn2 = createTableColumn;
674
+ var createTableBody2 = createTableBody;
675
+ var createTableSkeletonRow2 = createTableSkeletonRow;
676
+ var createTableEmpty2 = createTableEmpty;
677
+ var createTableFooter2 = createTableFooter;
678
+ var createTableRow2 = createTableRow;
679
+ var useTableCache2 = useTableCache;
680
+ var useTableColumnWidths2 = useTableColumnWidths;
1
681
  export {
2
- useTableColumnWidths,
3
- useTableCache,
4
- createTableSkeletonRow,
5
- createTableRow,
6
- createTableHeader,
7
- createTableFooter,
8
- createTableEmpty,
9
- createTableColumn,
10
- createTableBody,
11
- VirtualTable
682
+ useTableColumnWidths2 as useTableColumnWidths,
683
+ useTableCache2 as useTableCache,
684
+ createTableSkeletonRow2 as createTableSkeletonRow,
685
+ createTableRow2 as createTableRow,
686
+ createTableHeader2 as createTableHeader,
687
+ createTableFooter2 as createTableFooter,
688
+ createTableEmpty2 as createTableEmpty,
689
+ createTableColumn2 as createTableColumn,
690
+ createTableBody2 as createTableBody,
691
+ VirtualTable2 as VirtualTable
12
692
  };
13
693
 
14
- //# debugId=1E46849E0CE9A88764756E2164756E21
694
+ //# debugId=35F50DE454A2B11E64756E2164756E21