@dust-tt/sparkle 0.2.591 → 0.2.592

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.
@@ -1,7 +1,9 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import React, { useState } from "react";
2
+ import type { ColumnDef } from "@tanstack/react-table";
3
+ import React, { useCallback, useState } from "react";
3
4
 
4
5
  import { Button } from "@sparkle/components/Button";
6
+ import { ScrollableDataTable } from "@sparkle/components/DataTable";
5
7
  import {
6
8
  MultiPageSheet,
7
9
  MultiPageSheetContent,
@@ -466,3 +468,214 @@ export const WithConditionalNavigation: Story = {
466
468
  );
467
469
  },
468
470
  };
471
+
472
+ // Sample data types for the ScrollableDataTable
473
+ interface UserData {
474
+ id: string;
475
+ name: string;
476
+ email: string;
477
+ role: string;
478
+ status: string;
479
+ lastActive: string;
480
+ onClick?: () => void;
481
+ }
482
+
483
+ // Generate random user data
484
+ const generateRandomUsers = (
485
+ count: number,
486
+ startId: number = 0
487
+ ): UserData[] => {
488
+ const roles = ["Admin", "User", "Manager", "Developer", "Designer"];
489
+ const statuses = ["Active", "Inactive", "Pending"];
490
+ const firstNames = [
491
+ "John",
492
+ "Jane",
493
+ "Mike",
494
+ "Sarah",
495
+ "David",
496
+ "Lisa",
497
+ "Tom",
498
+ "Anna",
499
+ "Chris",
500
+ "Emma",
501
+ ];
502
+ const lastNames = [
503
+ "Smith",
504
+ "Johnson",
505
+ "Williams",
506
+ "Brown",
507
+ "Jones",
508
+ "Garcia",
509
+ "Miller",
510
+ "Davis",
511
+ "Rodriguez",
512
+ "Martinez",
513
+ ];
514
+
515
+ return Array.from({ length: count }, (_, index) => {
516
+ const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
517
+ const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
518
+ const id = (startId + index + 1).toString();
519
+
520
+ return {
521
+ id,
522
+ name: `${firstName} ${lastName}`,
523
+ email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`,
524
+ role: roles[Math.floor(Math.random() * roles.length)],
525
+ status: statuses[Math.floor(Math.random() * statuses.length)],
526
+ lastActive: new Date(
527
+ Date.now() - Math.floor(Math.random() * 30) * 24 * 60 * 60 * 1000
528
+ ).toLocaleDateString(),
529
+ onClick: () => alert(`Clicked on user: ${firstName} ${lastName}`),
530
+ };
531
+ });
532
+ };
533
+
534
+ export const WithScrollableDataTable: Story = {
535
+ render() {
536
+ const [currentPageId, setCurrentPageId] = useState("users");
537
+ const [users, setUsers] = useState<UserData[]>(() =>
538
+ generateRandomUsers(50)
539
+ );
540
+ const [isLoading, setIsLoading] = useState(false);
541
+ const [hasMore, setHasMore] = useState(true);
542
+
543
+ // Define columns for the data table
544
+ const columns: ColumnDef<UserData>[] = [
545
+ {
546
+ accessorKey: "name",
547
+ header: "Name",
548
+ cell: ({ row }) => (
549
+ <div className="s-font-medium">{row.getValue("name")}</div>
550
+ ),
551
+ meta: { sizeRatio: 25 },
552
+ },
553
+ {
554
+ accessorKey: "email",
555
+ header: "Email",
556
+ cell: ({ row }) => (
557
+ <div className="s-text-muted-foreground">{row.getValue("email")}</div>
558
+ ),
559
+ meta: { sizeRatio: 30 },
560
+ },
561
+ {
562
+ accessorKey: "role",
563
+ header: "Role",
564
+ cell: ({ row }) => (
565
+ <div className="s-inline-flex s-rounded-full s-bg-blue-100 s-px-2 s-py-1 s-text-xs s-font-semibold s-text-blue-800">
566
+ {row.getValue("role")}
567
+ </div>
568
+ ),
569
+ meta: { sizeRatio: 15 },
570
+ },
571
+ {
572
+ accessorKey: "status",
573
+ header: "Status",
574
+ cell: ({ row }) => {
575
+ const status = row.getValue("status") as string;
576
+ const colorClass =
577
+ status === "Active"
578
+ ? "s-bg-green-100 s-text-green-800"
579
+ : status === "Inactive"
580
+ ? "s-bg-red-100 s-text-red-800"
581
+ : "s-bg-yellow-100 s-text-yellow-800";
582
+
583
+ return (
584
+ <div
585
+ className={`s-inline-flex s-rounded-full s-px-2 s-py-1 s-text-xs s-font-semibold ${colorClass}`}
586
+ >
587
+ {status}
588
+ </div>
589
+ );
590
+ },
591
+ meta: { sizeRatio: 15 },
592
+ },
593
+ {
594
+ accessorKey: "lastActive",
595
+ header: "Last Active",
596
+ cell: ({ row }) => (
597
+ <div className="s-text-sm s-text-muted-foreground">
598
+ {row.getValue("lastActive")}
599
+ </div>
600
+ ),
601
+ meta: { sizeRatio: 15 },
602
+ },
603
+ ];
604
+
605
+ // Handle infinite loading
606
+ const handleLoadMore = useCallback(() => {
607
+ if (isLoading || !hasMore) {
608
+ return;
609
+ }
610
+
611
+ setIsLoading(true);
612
+
613
+ // Simulate API call delay
614
+ setTimeout(() => {
615
+ const newUsers = generateRandomUsers(25, users.length);
616
+ setUsers((prev) => [...prev, ...newUsers]);
617
+ setIsLoading(false);
618
+
619
+ // Stop loading more after reaching 200 items for demo purposes
620
+ if (users.length >= 175) {
621
+ setHasMore(false);
622
+ }
623
+ }, 1000);
624
+ }, [isLoading, hasMore, users.length]);
625
+
626
+ const handleSave = () => {
627
+ alert("User data saved!");
628
+ };
629
+
630
+ const scrollableDataTablePages: MultiPageSheetPage[] = [
631
+ {
632
+ id: "users",
633
+ title: "User Management",
634
+ description: "Manage users with infinite scroll",
635
+ icon: UserIcon,
636
+ noScroll: true,
637
+ content: (
638
+ <div className="s-flex s-h-full s-flex-col s-space-y-4">
639
+ <div className="s-flex-shrink-0">
640
+ <h3 className="s-mb-2 s-text-lg s-font-semibold">
641
+ Users Database
642
+ </h3>
643
+ <p className="s-text-sm s-text-muted-foreground">
644
+ Browse through all users with infinite scrolling. Click on any
645
+ row to view details.
646
+ </p>
647
+ </div>
648
+ <ScrollableDataTable
649
+ className="s-min-h-0"
650
+ data={users}
651
+ columns={columns}
652
+ maxHeight={true}
653
+ onLoadMore={hasMore ? handleLoadMore : undefined}
654
+ isLoading={isLoading}
655
+ enableRowSelection={false}
656
+ />
657
+ <div className="s-flex-shrink-0 s-text-xs s-text-muted-foreground">
658
+ Showing {users.length} users{" "}
659
+ {hasMore ? "(loading more available)" : "(all users loaded)"}
660
+ </div>
661
+ </div>
662
+ ),
663
+ },
664
+ ];
665
+
666
+ return (
667
+ <MultiPageSheet>
668
+ <MultiPageSheetTrigger asChild>
669
+ <Button label="Open User Management" />
670
+ </MultiPageSheetTrigger>
671
+ <MultiPageSheetContent
672
+ pages={scrollableDataTablePages}
673
+ currentPageId={currentPageId}
674
+ onPageChange={setCurrentPageId}
675
+ size="xl"
676
+ onSave={handleSave}
677
+ />
678
+ </MultiPageSheet>
679
+ );
680
+ },
681
+ };