@dust-tt/sparkle 0.2.193 → 0.2.194-rc

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dust-tt/sparkle",
3
- "version": "0.2.193",
3
+ "version": "0.2.194-rc",
4
4
  "scripts": {
5
5
  "build": "rm -rf dist && rollup -c",
6
6
  "build:with-tw-base": "rollup -c --environment INCLUDE_TW_BASE:true",
package/src/_index.ts CHANGED
@@ -148,6 +148,9 @@ export { Markdown };
148
148
  import { DataTable } from "./components/DataTable";
149
149
  export { DataTable };
150
150
 
151
+ import { Table, TableData } from "./components/Table";
152
+ export { Table, TableData };
153
+
151
154
  import {
152
155
  LogoHorizontalColor as LogoHorizontalColorLogo,
153
156
  LogoHorizontalColorLayer1 as LogoHorizontalColorLogoLayer1,
@@ -0,0 +1,286 @@
1
+ import {
2
+ type ColumnDef,
3
+ ColumnFiltersState,
4
+ flexRender,
5
+ getCoreRowModel,
6
+ getFilteredRowModel,
7
+ getSortedRowModel,
8
+ type SortingState,
9
+ useReactTable,
10
+ } from "@tanstack/react-table";
11
+ import React, { ReactNode, useState } from "react";
12
+
13
+ import { Avatar, MoreIcon } from "@sparkle/index";
14
+ import { ArrowDownIcon, ArrowUpIcon } from "@sparkle/index";
15
+ import { classNames } from "@sparkle/lib/utils";
16
+
17
+ import { Icon } from "./Icon";
18
+
19
+ type FirstColumnWidth = "expanded" | "normal";
20
+
21
+ interface TableProps<TData, TValue> {
22
+ data: TData[];
23
+ columns: ColumnDef<TData, TValue>[];
24
+ className?: string;
25
+ width?: FirstColumnWidth;
26
+ }
27
+
28
+ export function Table<TData, TValue>({
29
+ data,
30
+ columns,
31
+ className,
32
+ width = "normal",
33
+ }: TableProps<TData, TValue>) {
34
+ const [sorting, setSorting] = useState<SortingState>([]);
35
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
36
+
37
+ const table = useReactTable({
38
+ data,
39
+ columns,
40
+ onSortingChange: setSorting,
41
+ getCoreRowModel: getCoreRowModel(),
42
+ getSortedRowModel: getSortedRowModel(),
43
+ getFilteredRowModel: getFilteredRowModel(),
44
+ onColumnFiltersChange: setColumnFilters,
45
+ state: {
46
+ columnFilters,
47
+ sorting,
48
+ },
49
+ });
50
+
51
+ return (
52
+ <TableData className={className}>
53
+ <TableData.Header>
54
+ {table.getHeaderGroups().map((headerGroup) => (
55
+ <TableData.Row key={headerGroup.id}>
56
+ {headerGroup.headers.map((header) => (
57
+ <TableData.Head
58
+ key={header.id}
59
+ width={width}
60
+ onClick={header.column.getToggleSortingHandler()}
61
+ className={header.column.getCanSort() ? "s-cursor-pointer" : ""}
62
+ >
63
+ <div className="s-flex s-items-center s-space-x-1 s-whitespace-nowrap">
64
+ {flexRender(
65
+ header.column.columnDef.header,
66
+ header.getContext()
67
+ )}
68
+ {header.column.getCanSort() && (
69
+ <Icon
70
+ visual={
71
+ header.column.getIsSorted() === "asc"
72
+ ? ArrowUpIcon
73
+ : header.column.getIsSorted() === "desc"
74
+ ? ArrowDownIcon
75
+ : ArrowDownIcon
76
+ }
77
+ className={classNames(
78
+ "s-h-4 s-w-3 s-font-extralight",
79
+ header.column.getIsSorted()
80
+ ? "s-opacity-100"
81
+ : "s-opacity-0"
82
+ )}
83
+ />
84
+ )}
85
+ </div>
86
+ </TableData.Head>
87
+ ))}
88
+ </TableData.Row>
89
+ ))}
90
+ </TableData.Header>
91
+ <TableData.Body>
92
+ {table.getRowModel().rows.map((row) => (
93
+ <TableData.Row
94
+ key={row.id}
95
+ clickable={row.original.clickable}
96
+ onClick={row.original.onClick}
97
+ >
98
+ {row.getVisibleCells().map((cell) => (
99
+ <TableData.Cell key={cell.id}>
100
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
101
+ </TableData.Cell>
102
+ ))}
103
+ </TableData.Row>
104
+ ))}
105
+ </TableData.Body>
106
+ </TableData>
107
+ );
108
+ }
109
+
110
+ interface TableRootProps extends React.HTMLAttributes<HTMLTableElement> {
111
+ children: ReactNode;
112
+ }
113
+
114
+ interface HeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {
115
+ children: ReactNode;
116
+ }
117
+
118
+ interface HeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
119
+ children?: ReactNode;
120
+ width?: FirstColumnWidth;
121
+ }
122
+
123
+ interface CellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
124
+ avatarUrl?: string;
125
+ icon?: React.ComponentType<{ className?: string }>;
126
+ children?: ReactNode;
127
+ description?: string;
128
+ }
129
+
130
+ interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
131
+ children: ReactNode;
132
+ clickable?: boolean;
133
+ onClick?: () => void;
134
+ }
135
+
136
+ const TableRoot: React.FC<TableRootProps> = ({
137
+ children,
138
+ className,
139
+ ...props
140
+ }) => {
141
+ return (
142
+ <table
143
+ className={classNames("s-w-full s-border-collapse", className || "")}
144
+ {...props}
145
+ >
146
+ {children}
147
+ </table>
148
+ );
149
+ };
150
+
151
+ const Header: React.FC<HeaderProps> = ({ children, className, ...props }) => {
152
+ return (
153
+ <thead
154
+ className={classNames("s-text-xs s-capitalize", className || "")}
155
+ {...props}
156
+ >
157
+ {children}
158
+ </thead>
159
+ );
160
+ };
161
+
162
+ const Head: React.FC<HeadProps> = ({
163
+ children,
164
+ className,
165
+ width,
166
+ ...props
167
+ }) => {
168
+ return (
169
+ <th
170
+ className={classNames(
171
+ "s-py-1 s-pr-3 s-text-left s-font-medium s-text-element-800",
172
+ width === "expanded" ? "s-w-full" : "s-w-auto",
173
+ className || ""
174
+ )}
175
+ {...props}
176
+ >
177
+ <div className="s-flex s-items-center s-space-x-1 s-whitespace-nowrap">
178
+ {children}
179
+ </div>
180
+ </th>
181
+ );
182
+ };
183
+
184
+ const Body: React.FC<React.HTMLAttributes<HTMLTableSectionElement>> = ({
185
+ children,
186
+ className,
187
+ ...props
188
+ }) => (
189
+ <tbody className={className || ""} {...props}>
190
+ {children}
191
+ </tbody>
192
+ );
193
+
194
+ const Footer: React.FC<React.HTMLAttributes<HTMLTableSectionElement>> = ({
195
+ children,
196
+ className,
197
+ ...props
198
+ }) => (
199
+ <tfoot
200
+ className={classNames(
201
+ "s-border-t s-border-structure-200 s-bg-structure-50",
202
+ className || ""
203
+ )}
204
+ {...props}
205
+ >
206
+ {children}
207
+ </tfoot>
208
+ );
209
+
210
+ const Row: React.FC<RowProps> = ({
211
+ children,
212
+ className,
213
+ clickable = false,
214
+ onClick,
215
+ ...props
216
+ }) => (
217
+ <tr
218
+ className={classNames(
219
+ "s-border-b s-border-structure-200 s-text-sm",
220
+ className || ""
221
+ )}
222
+ {...props}
223
+ >
224
+ {children}
225
+ {clickable && (
226
+ <td
227
+ className="s-w-1 s-cursor-pointer s-pl-1 s-text-element-600"
228
+ onClick={clickable ? onClick : undefined}
229
+ >
230
+ <Icon visual={MoreIcon} size="sm" />
231
+ </td>
232
+ )}
233
+ </tr>
234
+ );
235
+
236
+ const Cell: React.FC<CellProps> = ({
237
+ children,
238
+ className,
239
+ avatarUrl,
240
+ icon,
241
+ description,
242
+ ...props
243
+ }) => (
244
+ <td
245
+ className={classNames(
246
+ "s-whitespace-nowrap s-py-2 s-pl-0.5 s-text-element-800",
247
+ className || ""
248
+ )}
249
+ {...props}
250
+ >
251
+ <div className="s-flex">
252
+ {avatarUrl && <Avatar visual={avatarUrl} size="xs" className="s-mr-2" />}
253
+ {icon && (
254
+ <Icon visual={icon} size="sm" className="s-mr-2 s-text-element-600" />
255
+ )}
256
+ <div className="s-flex">
257
+ <span className="s-text-sm s-text-element-800">{children}</span>
258
+ {description && (
259
+ <span className="s-pl-2 s-text-sm s-text-element-600">
260
+ {description}
261
+ </span>
262
+ )}
263
+ </div>
264
+ </div>
265
+ </td>
266
+ );
267
+
268
+ const Caption: React.FC<React.HTMLAttributes<HTMLTableCaptionElement>> = ({
269
+ children,
270
+ className,
271
+ ...props
272
+ }) => (
273
+ <caption className={classNames(className || "")} {...props}>
274
+ {children}
275
+ </caption>
276
+ );
277
+
278
+ export const TableData = Object.assign(TableRoot, {
279
+ Header,
280
+ Body,
281
+ Footer,
282
+ Head,
283
+ Row,
284
+ Cell,
285
+ Caption,
286
+ });
@@ -22,7 +22,7 @@ export function Tooltip({
22
22
  const handleMouseOver = () => {
23
23
  const id = window.setTimeout(() => {
24
24
  setIsHovered(true);
25
- }, 800);
25
+ }, 600);
26
26
  setTimerId(id);
27
27
  };
28
28
 
@@ -0,0 +1,99 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { ColumnDef } from "@tanstack/react-table";
3
+ import React from 'react';
4
+
5
+ import { TableData } from "@sparkle/components/Table";
6
+
7
+ import { FolderIcon, Table } from "../index_with_tw_base";
8
+
9
+ const meta = {
10
+ title: "Components/Table",
11
+ component: Table
12
+ } satisfies Meta<typeof Table>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ type Data = {
18
+ name: string;
19
+ description?: string;
20
+ usedBy: number;
21
+ addedBy: string;
22
+ lastUpdated: string;
23
+ size: string;
24
+ avatarUrl?: string;
25
+ icon?: React.ComponentType<{ className?: string }>;
26
+ clickable?: boolean;
27
+ onClick?: () => void;
28
+ };
29
+
30
+ const TableExample = () => {
31
+ const data: Data[] = [
32
+ {
33
+ name: "Marketing",
34
+ description: "(23 items)",
35
+ usedBy: 8,
36
+ addedBy: "User1",
37
+ lastUpdated: "July 8, 2023",
38
+ size: "32kb",
39
+ avatarUrl: "https://dust.tt/static/droidavatar/Droid_Lime_3.jpg",
40
+ clickable: true,
41
+ onClick: (() => console.log("hehe"))
42
+ },
43
+ { name: "Design", usedBy: 2, addedBy: "User2", lastUpdated: "2023-07-09", size: "64kb", icon: FolderIcon, clickable: false},
44
+ { name: "Development", usedBy: 5, addedBy: "User3", lastUpdated: "2023-07-07", size: "128kb"},
45
+ { name: "Sales", usedBy: 10, addedBy: "User4", lastUpdated: "2023-07-10", size: "16kb"},
46
+ { name: "HR", usedBy: 3, addedBy: "User5", lastUpdated: "2023-07-06", size: "48kb"},
47
+ ];
48
+
49
+ const columns: ColumnDef<Data>[] = [
50
+ {
51
+ accessorKey: "name",
52
+ header: "Name",
53
+ cell: info => (
54
+ <TableData.Cell
55
+ avatarUrl={info.row.original.avatarUrl}
56
+ icon={info.row.original.icon}
57
+ description={info.row.original.description}
58
+ >
59
+ {info.row.original.name}
60
+ </TableData.Cell>
61
+ ),
62
+ meta: { width: "expanded" }
63
+ },
64
+ {
65
+ accessorKey: "usedBy",
66
+ header: "Used by",
67
+ cell: info => <TableData.Cell>{info.row.original.usedBy}</TableData.Cell>
68
+ },
69
+ {
70
+ accessorKey: "addedBy",
71
+ header: "Added by",
72
+ cell: info => <TableData.Cell>{info.row.original.addedBy}</TableData.Cell>
73
+ },
74
+ {
75
+ accessorKey: "lastUpdated",
76
+ header: "Last updated",
77
+ cell: info => <TableData.Cell>{info.row.original.lastUpdated}</TableData.Cell>,
78
+ enableSorting: false
79
+ },
80
+ {
81
+ accessorKey: "size",
82
+ header: "Size",
83
+ cell: info => <TableData.Cell>{info.row.original.size}</TableData.Cell>
84
+ }
85
+ ];
86
+
87
+ return (
88
+ <div className="s-w-full s-max-w-4xl s-overflow-x-auto">
89
+ <Table
90
+ data={data}
91
+ columns={columns}
92
+ />
93
+ </div>
94
+ );
95
+ };
96
+
97
+ export const Default: Story = {
98
+ render: () => <TableExample />,
99
+ };