@dust-tt/sparkle 0.2.589-rc-2 → 0.2.590
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/cjs/index.js +1 -1
- package/dist/esm/components/DataTable.d.ts +1 -1
- package/dist/esm/components/DataTable.d.ts.map +1 -1
- package/dist/esm/components/DataTable.js +48 -51
- package/dist/esm/components/DataTable.js.map +1 -1
- package/dist/esm/stories/DataTable.stories.d.ts +0 -1
- package/dist/esm/stories/DataTable.stories.d.ts.map +1 -1
- package/dist/esm/stories/DataTable.stories.js +0 -28
- package/dist/esm/stories/DataTable.stories.js.map +1 -1
- package/dist/sparkle.css +4 -0
- package/package.json +1 -1
- package/src/components/DataTable.tsx +111 -115
- package/src/stories/DataTable.stories.tsx +0 -61
|
@@ -327,7 +327,7 @@ export function DataTable<TData extends TBaseData>({
|
|
|
327
327
|
|
|
328
328
|
export interface ScrollableDataTableProps<TData extends TBaseData>
|
|
329
329
|
extends DataTableProps<TData> {
|
|
330
|
-
maxHeight?: string
|
|
330
|
+
maxHeight?: string;
|
|
331
331
|
onLoadMore?: () => void;
|
|
332
332
|
isLoading?: boolean;
|
|
333
333
|
}
|
|
@@ -343,7 +343,7 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
343
343
|
className,
|
|
344
344
|
widthClassName = "s-w-full",
|
|
345
345
|
columnsBreakpoints = {},
|
|
346
|
-
maxHeight,
|
|
346
|
+
maxHeight = "s-h-100",
|
|
347
347
|
onLoadMore,
|
|
348
348
|
isLoading = false,
|
|
349
349
|
rowSelection,
|
|
@@ -480,95 +480,24 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
480
480
|
}, [onLoadMore, isLoading]);
|
|
481
481
|
|
|
482
482
|
return (
|
|
483
|
-
<div
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
>
|
|
496
|
-
<div className="s-relative">
|
|
497
|
-
<DataTable.Root className="s-w-full s-table-fixed">
|
|
498
|
-
<DataTable.Header className="s-sticky s-top-0 s-z-20 s-bg-white s-shadow-sm dark:s-bg-background-night">
|
|
499
|
-
{table.getHeaderGroups().map((headerGroup) => (
|
|
500
|
-
<DataTable.Row
|
|
501
|
-
key={headerGroup.id}
|
|
502
|
-
widthClassName={widthClassName}
|
|
503
|
-
>
|
|
504
|
-
{headerGroup.headers.map((header) => {
|
|
505
|
-
const breakpoint = columnsBreakpoints[header.id];
|
|
506
|
-
if (
|
|
507
|
-
!windowSize.width ||
|
|
508
|
-
!shouldRenderColumn(windowSize.width, breakpoint)
|
|
509
|
-
) {
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return (
|
|
514
|
-
<DataTable.Head
|
|
515
|
-
column={header.column}
|
|
516
|
-
key={header.id}
|
|
517
|
-
className="s-max-w-0"
|
|
518
|
-
style={{
|
|
519
|
-
width: columnSizing[header.id],
|
|
520
|
-
minWidth: columnSizing[header.id],
|
|
521
|
-
}}
|
|
522
|
-
>
|
|
523
|
-
<div className="s-flex s-w-full s-items-center s-space-x-1">
|
|
524
|
-
<span className="s-truncate">
|
|
525
|
-
{flexRender(
|
|
526
|
-
header.column.columnDef.header,
|
|
527
|
-
header.getContext()
|
|
528
|
-
)}
|
|
529
|
-
</span>
|
|
530
|
-
</div>
|
|
531
|
-
</DataTable.Head>
|
|
532
|
-
);
|
|
533
|
-
})}
|
|
534
|
-
</DataTable.Row>
|
|
535
|
-
))}
|
|
536
|
-
</DataTable.Header>
|
|
537
|
-
<DataTable.Body
|
|
538
|
-
className="s-relative s-w-full"
|
|
539
|
-
style={{
|
|
540
|
-
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
541
|
-
}}
|
|
542
|
-
>
|
|
543
|
-
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
|
544
|
-
const row = rows[virtualRow.index];
|
|
545
|
-
const handleRowClick = () => {
|
|
546
|
-
if (enableRowSelection && row.getCanSelect()) {
|
|
547
|
-
row.toggleSelected(
|
|
548
|
-
!enableMultiRowSelection ? true : undefined
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
row.original.onClick?.();
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
return (
|
|
483
|
+
<div className={cn("s-flex s-flex-col s-gap-2", className, widthClassName)}>
|
|
484
|
+
<div
|
|
485
|
+
className={cn(
|
|
486
|
+
"s-relative s-overflow-y-auto s-overflow-x-hidden",
|
|
487
|
+
maxHeight
|
|
488
|
+
)}
|
|
489
|
+
ref={tableContainerRef}
|
|
490
|
+
>
|
|
491
|
+
<div className="s-relative">
|
|
492
|
+
<DataTable.Root className="s-w-full s-table-fixed">
|
|
493
|
+
<DataTable.Header className="s-sticky s-top-0 s-z-20 s-bg-white s-shadow-sm dark:s-bg-background-night">
|
|
494
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
555
495
|
<DataTable.Row
|
|
556
|
-
key={
|
|
557
|
-
id={row.id}
|
|
496
|
+
key={headerGroup.id}
|
|
558
497
|
widthClassName={widthClassName}
|
|
559
|
-
onClick={
|
|
560
|
-
enableRowSelection ? handleRowClick : row.original.onClick
|
|
561
|
-
}
|
|
562
|
-
className="s-absolute s-w-full"
|
|
563
|
-
{...(enableRowSelection && {
|
|
564
|
-
"data-selected": row.getIsSelected(),
|
|
565
|
-
})}
|
|
566
|
-
style={{
|
|
567
|
-
transform: `translateY(${virtualRow.start}px)`,
|
|
568
|
-
}}
|
|
569
498
|
>
|
|
570
|
-
{
|
|
571
|
-
const breakpoint = columnsBreakpoints[
|
|
499
|
+
{headerGroup.headers.map((header) => {
|
|
500
|
+
const breakpoint = columnsBreakpoints[header.id];
|
|
572
501
|
if (
|
|
573
502
|
!windowSize.width ||
|
|
574
503
|
!shouldRenderColumn(windowSize.width, breakpoint)
|
|
@@ -577,47 +506,114 @@ export function ScrollableDataTable<TData extends TBaseData>({
|
|
|
577
506
|
}
|
|
578
507
|
|
|
579
508
|
return (
|
|
580
|
-
<DataTable.
|
|
581
|
-
column={
|
|
582
|
-
key={
|
|
583
|
-
id={cell.id}
|
|
509
|
+
<DataTable.Head
|
|
510
|
+
column={header.column}
|
|
511
|
+
key={header.id}
|
|
584
512
|
className="s-max-w-0"
|
|
585
513
|
style={{
|
|
586
|
-
width: columnSizing[
|
|
587
|
-
minWidth: columnSizing[
|
|
514
|
+
width: columnSizing[header.id],
|
|
515
|
+
minWidth: columnSizing[header.id],
|
|
588
516
|
}}
|
|
589
517
|
>
|
|
590
|
-
<div className="s-flex s-items-center s-space-x-1">
|
|
518
|
+
<div className="s-flex s-w-full s-items-center s-space-x-1">
|
|
591
519
|
<span className="s-truncate">
|
|
592
520
|
{flexRender(
|
|
593
|
-
|
|
594
|
-
|
|
521
|
+
header.column.columnDef.header,
|
|
522
|
+
header.getContext()
|
|
595
523
|
)}
|
|
596
524
|
</span>
|
|
597
525
|
</div>
|
|
598
|
-
</DataTable.
|
|
526
|
+
</DataTable.Head>
|
|
599
527
|
);
|
|
600
528
|
})}
|
|
601
529
|
</DataTable.Row>
|
|
602
|
-
)
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
530
|
+
))}
|
|
531
|
+
</DataTable.Header>
|
|
532
|
+
<DataTable.Body
|
|
533
|
+
className="s-relative s-w-full"
|
|
534
|
+
style={{
|
|
535
|
+
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
536
|
+
}}
|
|
537
|
+
>
|
|
538
|
+
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
|
539
|
+
const row = rows[virtualRow.index];
|
|
540
|
+
const handleRowClick = () => {
|
|
541
|
+
if (enableRowSelection && row.getCanSelect()) {
|
|
542
|
+
row.toggleSelected(
|
|
543
|
+
!enableMultiRowSelection ? true : undefined
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
row.original.onClick?.();
|
|
547
|
+
};
|
|
612
548
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
549
|
+
return (
|
|
550
|
+
<DataTable.Row
|
|
551
|
+
key={row.id}
|
|
552
|
+
id={row.id}
|
|
553
|
+
widthClassName={widthClassName}
|
|
554
|
+
onClick={
|
|
555
|
+
enableRowSelection ? handleRowClick : row.original.onClick
|
|
556
|
+
}
|
|
557
|
+
className="s-absolute s-w-full"
|
|
558
|
+
{...(enableRowSelection && {
|
|
559
|
+
"data-selected": row.getIsSelected(),
|
|
560
|
+
})}
|
|
561
|
+
style={{
|
|
562
|
+
transform: `translateY(${virtualRow.start}px)`,
|
|
563
|
+
}}
|
|
564
|
+
>
|
|
565
|
+
{row.getVisibleCells().map((cell) => {
|
|
566
|
+
const breakpoint = columnsBreakpoints[cell.column.id];
|
|
567
|
+
if (
|
|
568
|
+
!windowSize.width ||
|
|
569
|
+
!shouldRenderColumn(windowSize.width, breakpoint)
|
|
570
|
+
) {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return (
|
|
575
|
+
<DataTable.Cell
|
|
576
|
+
column={cell.column}
|
|
577
|
+
key={cell.id}
|
|
578
|
+
id={cell.id}
|
|
579
|
+
className="s-max-w-0"
|
|
580
|
+
style={{
|
|
581
|
+
width: columnSizing[cell.column.id],
|
|
582
|
+
minWidth: columnSizing[cell.column.id],
|
|
583
|
+
}}
|
|
584
|
+
>
|
|
585
|
+
<div className="s-flex s-items-center s-space-x-1">
|
|
586
|
+
<span className="s-truncate">
|
|
587
|
+
{flexRender(
|
|
588
|
+
cell.column.columnDef.cell,
|
|
589
|
+
cell.getContext()
|
|
590
|
+
)}
|
|
591
|
+
</span>
|
|
592
|
+
</div>
|
|
593
|
+
</DataTable.Cell>
|
|
594
|
+
);
|
|
595
|
+
})}
|
|
596
|
+
</DataTable.Row>
|
|
597
|
+
);
|
|
598
|
+
})}
|
|
599
|
+
</DataTable.Body>
|
|
600
|
+
</DataTable.Root>
|
|
601
|
+
{/*sentinel div used for the intersection observer*/}
|
|
602
|
+
<div
|
|
603
|
+
ref={loadMoreRef}
|
|
604
|
+
className="s-absolute s-bottom-0 s-h-1 s-w-full"
|
|
605
|
+
/>
|
|
619
606
|
</div>
|
|
620
|
-
|
|
607
|
+
|
|
608
|
+
{isLoading && (
|
|
609
|
+
<div className="s-sticky s-bottom-0 s-left-0 s-right-0 s-flex s-justify-center s-bg-white/80 s-py-2 s-backdrop-blur-sm dark:s-bg-background-night/80">
|
|
610
|
+
<div className="s-flex s-items-center s-gap-2 s-text-sm s-text-muted-foreground">
|
|
611
|
+
<Spinner size="xs" />
|
|
612
|
+
<span>Loading more data...</span>
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
)}
|
|
616
|
+
</div>
|
|
621
617
|
</div>
|
|
622
618
|
);
|
|
623
619
|
}
|
|
@@ -607,67 +607,6 @@ export const ScrollableDataTableExample = () => {
|
|
|
607
607
|
);
|
|
608
608
|
};
|
|
609
609
|
|
|
610
|
-
export const ScrollableDataTableFullHeightExample = () => {
|
|
611
|
-
const [filter, setFilter] = useState("");
|
|
612
|
-
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
|
613
|
-
const [data, setData] = useState(() => createData(0, 50));
|
|
614
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
615
|
-
|
|
616
|
-
// Load more data when user scrolls to bottom
|
|
617
|
-
const loadMore = useCallback(() => {
|
|
618
|
-
setIsLoading(true);
|
|
619
|
-
|
|
620
|
-
// Simulate API call delay
|
|
621
|
-
setTimeout(() => {
|
|
622
|
-
setData((prevData) => [...prevData, ...createData(prevData.length, 50)]);
|
|
623
|
-
setIsLoading(false);
|
|
624
|
-
}, 1000);
|
|
625
|
-
}, []);
|
|
626
|
-
|
|
627
|
-
const columnsWithSize = columns.map((column, index) => {
|
|
628
|
-
return { ...column, meta: { sizeRatio: index % 2 === 0 ? 15 : 10 } };
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
const columnsWithSelection: ColumnDef<Data>[] = useMemo(
|
|
632
|
-
() => [createSelectionColumn<Data>(), ...columnsWithSize],
|
|
633
|
-
[]
|
|
634
|
-
);
|
|
635
|
-
return (
|
|
636
|
-
<div className="s-flex s-w-full s-max-w-4xl s-flex-col s-gap-6">
|
|
637
|
-
<h3 className="s-text-lg s-font-medium">
|
|
638
|
-
Virtualized ScrollableDataTable with Infinite Scrolling based on parent
|
|
639
|
-
height
|
|
640
|
-
</h3>
|
|
641
|
-
|
|
642
|
-
<div className="s-flex s-h-[400px] s-flex-col s-gap-4">
|
|
643
|
-
<Input
|
|
644
|
-
name="filter"
|
|
645
|
-
placeholder="Filter"
|
|
646
|
-
value={filter}
|
|
647
|
-
onChange={(e) => setFilter(e.target.value)}
|
|
648
|
-
/>
|
|
649
|
-
|
|
650
|
-
<ScrollableDataTable
|
|
651
|
-
data={data}
|
|
652
|
-
filter={filter}
|
|
653
|
-
filterColumn="name"
|
|
654
|
-
columns={columnsWithSelection}
|
|
655
|
-
onLoadMore={loadMore}
|
|
656
|
-
isLoading={isLoading}
|
|
657
|
-
maxHeight
|
|
658
|
-
rowSelection={rowSelection}
|
|
659
|
-
setRowSelection={setRowSelection}
|
|
660
|
-
enableRowSelection={true}
|
|
661
|
-
/>
|
|
662
|
-
|
|
663
|
-
<div className="s-text-sm s-text-muted-foreground">
|
|
664
|
-
Loaded {data.length} rows. Scroll to the bottom to load more.
|
|
665
|
-
</div>
|
|
666
|
-
</div>
|
|
667
|
-
</div>
|
|
668
|
-
);
|
|
669
|
-
};
|
|
670
|
-
|
|
671
610
|
export const DataTableWithRowSelectionExample = () => {
|
|
672
611
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
|
673
612
|
const [data] = useState<Data[]>(() => createData(0, 10));
|