@dust-tt/sparkle 0.2.236 → 0.2.238

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,4 +1,5 @@
1
1
  import {
2
+ Column,
2
3
  type ColumnDef,
3
4
  ColumnFiltersState,
4
5
  flexRender,
@@ -28,6 +29,15 @@ import { classNames } from "@sparkle/lib/utils";
28
29
  import { Icon } from "./Icon";
29
30
  import { breakpoints, useWindowSize } from "./WindowUtility";
30
31
 
32
+ declare module "@tanstack/react-table" {
33
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
+ interface ColumnMeta<TData, TValue> {
35
+ className?: string;
36
+ width?: string;
37
+ flex?: number;
38
+ }
39
+ }
40
+
31
41
  interface TBaseData {
32
42
  onClick?: () => void;
33
43
  moreMenuItems?: DropdownItemProps[];
@@ -42,6 +52,7 @@ interface DataTableProps<TData extends TBaseData> {
42
52
  totalRowCount?: number;
43
53
  columns: ColumnDef<TData, any>[]; // eslint-disable-line @typescript-eslint/no-explicit-any
44
54
  className?: string;
55
+ widthClassName?: string;
45
56
  filter?: string;
46
57
  filterColumn?: string;
47
58
  pagination?: PaginationState;
@@ -66,6 +77,7 @@ export function DataTable<TData extends TBaseData>({
66
77
  totalRowCount,
67
78
  columns,
68
79
  className,
80
+ widthClassName = "s-w-full s-max-w-4xl",
69
81
  filter,
70
82
  filterColumn,
71
83
  initialColumnOrder,
@@ -118,11 +130,17 @@ export function DataTable<TData extends TBaseData>({
118
130
  }, [filter, filterColumn]);
119
131
 
120
132
  return (
121
- <div className="s-flex s-flex-col s-gap-2">
122
- <DataTable.Root className={className}>
133
+ <div
134
+ className={classNames(
135
+ "s-flex s-flex-col s-gap-2",
136
+ className || "",
137
+ widthClassName
138
+ )}
139
+ >
140
+ <DataTable.Root>
123
141
  <DataTable.Header>
124
142
  {table.getHeaderGroups().map((headerGroup) => (
125
- <DataTable.Row key={headerGroup.id}>
143
+ <DataTable.Row key={headerGroup.id} widthClassName={widthClassName}>
126
144
  {headerGroup.headers.map((header) => {
127
145
  const breakpoint = columnsBreakpoints[header.id];
128
146
  if (
@@ -133,6 +151,7 @@ export function DataTable<TData extends TBaseData>({
133
151
  }
134
152
  return (
135
153
  <DataTable.Head
154
+ column={header.column}
136
155
  key={header.id}
137
156
  onClick={header.column.getToggleSortingHandler()}
138
157
  className={classNames(
@@ -172,6 +191,7 @@ export function DataTable<TData extends TBaseData>({
172
191
  <DataTable.Body>
173
192
  {table.getRowModel().rows.map((row) => (
174
193
  <DataTable.Row
194
+ widthClassName={widthClassName}
175
195
  key={row.id}
176
196
  onClick={row.original.onClick}
177
197
  moreMenuItems={row.original.moreMenuItems}
@@ -185,7 +205,7 @@ export function DataTable<TData extends TBaseData>({
185
205
  return null;
186
206
  }
187
207
  return (
188
- <DataTable.Cell key={cell.id}>
208
+ <DataTable.Cell column={cell.column} key={cell.id}>
189
209
  {flexRender(cell.column.columnDef.cell, cell.getContext())}
190
210
  </DataTable.Cell>
191
211
  );
@@ -213,14 +233,10 @@ interface DataTableRootProps extends React.HTMLAttributes<HTMLTableElement> {
213
233
 
214
234
  DataTable.Root = function DataTableRoot({
215
235
  children,
216
- className,
217
236
  ...props
218
237
  }: DataTableRootProps) {
219
238
  return (
220
- <table
221
- className={classNames("s-w-full s-border-collapse", className || "")}
222
- {...props}
223
- >
239
+ <table className="s-w-full s-border-collapse" {...props}>
224
240
  {children}
225
241
  </table>
226
242
  );
@@ -247,13 +263,20 @@ DataTable.Header = function Header({
247
263
 
248
264
  interface HeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
249
265
  children?: ReactNode;
266
+ column: Column<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
250
267
  }
251
268
 
252
- DataTable.Head = function Head({ children, className, ...props }: HeadProps) {
269
+ DataTable.Head = function Head({
270
+ children,
271
+ className,
272
+ column,
273
+ ...props
274
+ }: HeadProps) {
253
275
  return (
254
276
  <th
277
+ style={getSize(column.columnDef)}
255
278
  className={classNames(
256
- "s-w-full s-py-1 s-pr-3 s-text-left s-font-medium s-text-element-800",
279
+ "s-py-1 s-pr-3 s-text-left s-font-medium s-text-element-800",
257
280
  className || ""
258
281
  )}
259
282
  {...props}
@@ -279,6 +302,7 @@ interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
279
302
  children: ReactNode;
280
303
  onClick?: () => void;
281
304
  moreMenuItems?: DropdownItemProps[];
305
+ widthClassName: string;
282
306
  }
283
307
 
284
308
  DataTable.Row = function Row({
@@ -286,24 +310,31 @@ DataTable.Row = function Row({
286
310
  className,
287
311
  onClick,
288
312
  moreMenuItems,
313
+ widthClassName,
289
314
  ...props
290
315
  }: RowProps) {
291
316
  return (
292
317
  <tr
293
318
  className={classNames(
294
- "s-group/dt s-border-b s-border-structure-200 s-text-sm s-transition-colors s-duration-300 s-ease-out",
319
+ "s-group/dt s-flex s-items-center s-border-b s-border-structure-200 s-text-sm s-transition-colors s-duration-300 s-ease-out",
295
320
  onClick ? "s-cursor-pointer hover:s-bg-structure-50" : "",
321
+ widthClassName,
296
322
  className || ""
297
323
  )}
298
324
  onClick={onClick ? onClick : undefined}
299
325
  {...props}
300
326
  >
301
327
  {children}
302
- <td className="s-w-1 s-cursor-pointer s-pl-1 s-text-element-600">
328
+ <td className="s-flex s-w-8 s-cursor-pointer s-items-center s-pl-1 s-text-element-600">
303
329
  {moreMenuItems && moreMenuItems.length > 0 && (
304
330
  <DropdownMenu className="s-mr-1.5 s-flex">
305
331
  <DropdownMenu.Button>
306
- <IconButton icon={MoreIcon} size="sm" variant="tertiary" />
332
+ <IconButton
333
+ icon={MoreIcon}
334
+ size="sm"
335
+ variant="tertiary"
336
+ className="s-m-1"
337
+ />
307
338
  </DropdownMenu.Button>
308
339
  <DropdownMenu.Items origin="topRight" width={220}>
309
340
  {moreMenuItems?.map((item, index) => (
@@ -319,13 +350,22 @@ DataTable.Row = function Row({
319
350
 
320
351
  interface CellProps extends React.HTMLAttributes<HTMLTableCellElement> {
321
352
  children: ReactNode;
353
+ column: Column<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
322
354
  }
323
355
 
324
- DataTable.Cell = function Cell({ children, className, ...props }: CellProps) {
356
+ DataTable.Cell = function Cell({
357
+ children,
358
+ className,
359
+ column,
360
+ ...props
361
+ }: CellProps) {
362
+ column.columnDef.minSize;
325
363
  return (
326
364
  <td
365
+ style={getSize(column.columnDef)}
327
366
  className={classNames(
328
- "s-h-12 s-whitespace-nowrap s-pl-1.5 s-text-element-800",
367
+ "s-flex s-h-12 s-items-center s-truncate s-whitespace-nowrap s-pl-1.5 s-text-element-800",
368
+ column.columnDef.meta?.className || "",
329
369
  className || ""
330
370
  )}
331
371
  {...props}
@@ -335,6 +375,16 @@ DataTable.Cell = function Cell({ children, className, ...props }: CellProps) {
335
375
  );
336
376
  };
337
377
 
378
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
379
+ function getSize(columnDef: ColumnDef<any>) {
380
+ if (columnDef.meta?.width) {
381
+ return { width: columnDef.meta.width };
382
+ }
383
+ return {
384
+ flex: columnDef.meta?.flex ?? 1,
385
+ };
386
+ }
387
+
338
388
  interface CellContentProps extends React.TdHTMLAttributes<HTMLDivElement> {
339
389
  avatarUrl?: string;
340
390
  avatarTooltipLabel?: string;
@@ -358,7 +408,10 @@ DataTable.CellContent = function CellContent({
358
408
  }: CellContentProps) {
359
409
  return (
360
410
  <div
361
- className={classNames("s-flex s-items-center s-py-2", className || "")}
411
+ className={classNames(
412
+ "s-flex s-w-full s-items-center s-py-2",
413
+ className || ""
414
+ )}
362
415
  {...props}
363
416
  >
364
417
  {avatarUrl && avatarTooltipLabel && (
@@ -389,8 +442,10 @@ DataTable.CellContent = function CellContent({
389
442
  )}
390
443
  />
391
444
  )}
392
- <div className="s-flex">
393
- <span className="s-text-sm s-text-element-800">{children}</span>
445
+ <div className="s-flex s-shrink s-truncate">
446
+ <span className="s-truncate s-text-sm s-text-element-800">
447
+ {children}
448
+ </span>
394
449
  {description && (
395
450
  <span className="s-pl-2 s-text-sm s-text-element-600">
396
451
  {description}
@@ -73,10 +73,8 @@ export function Dialog({
73
73
  <HeadlessDialog.Title className="s-text-element-950 s-truncate s-text-lg s-font-medium">
74
74
  {title}
75
75
  </HeadlessDialog.Title>
76
- <div className="s-z-10 s-text-base s-text-element-700">
77
- {children}
78
- </div>
79
- <div className="s-z-10 s-flex s-w-full s-justify-end">
76
+ <div className="s-text-base s-text-element-700">{children}</div>
77
+ <div className="s-flex s-w-full s-justify-end">
80
78
  <Button.List>
81
79
  {!isSaving && (
82
80
  <>
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef } from "react";
1
+ import React, { useRef } from "react";
2
2
 
3
3
  import { classNames } from "@sparkle/lib/utils";
4
4
 
@@ -9,7 +9,7 @@ type TextAreaProps = {
9
9
  error?: string | null;
10
10
  showErrorLabel?: boolean;
11
11
  className?: string;
12
- rows?: number;
12
+ minRows?: number;
13
13
  };
14
14
 
15
15
  export function TextArea({
@@ -19,21 +19,14 @@ export function TextArea({
19
19
  error,
20
20
  showErrorLabel = false,
21
21
  className,
22
- rows = 10
22
+ minRows = 10
23
23
  }: TextAreaProps) {
24
24
  const textareaRef = useRef<HTMLTextAreaElement>(null);
25
25
 
26
- useEffect(() => {
27
- const textarea = textareaRef.current;
28
- if (textarea) {
29
- textarea.style.height = 'auto'; // Reset height
30
- textarea.style.height = `${textarea.scrollHeight}px`; // Set to scroll height
31
- }
32
- }, [value]); // Re-run when value changes
33
26
  return (
34
27
  <div className="s-flex s-flex-col s-gap-1 s-p-px">
35
28
  <textarea
36
- rows={rows}
29
+ rows={minRows}
37
30
  ref={textareaRef}
38
31
  className={classNames(
39
32
  "overflow-y-auto s-block s-w-full s-min-w-0 s-rounded-xl s-text-sm s-placeholder-element-700 s-transition-all s-duration-200 s-scrollbar-hide",
@@ -47,15 +40,6 @@ export function TextArea({
47
40
  placeholder={placeholder}
48
41
  value={value ?? ""}
49
42
  onChange={(e) => {
50
- const newValue = e.target.value;
51
- const textAreaComponent = textareaRef.current;
52
- if (
53
- textAreaComponent &&
54
- value?.length &&
55
- newValue.length < value.length
56
- ) {
57
- textAreaComponent.style.height = "auto"; // Reset height to recalculate
58
- }
59
43
  onChange(e.target.value);
60
44
  }}
61
45
  />
@@ -68,6 +68,22 @@ const data: Data[] = [
68
68
  ],
69
69
  onClick: () => alert("Design clicked"),
70
70
  },
71
+ {
72
+ name: "Very long name that should be truncated at some point to avoid overflow and make the table more readable",
73
+ usedBy: 2,
74
+ addedBy: "Another very long user name that should be truncated",
75
+ lastUpdated: "2023-07-09",
76
+ size: "64kb",
77
+ icon: FolderIcon,
78
+ moreMenuItems: [
79
+ {
80
+ label: "Edit (disabled)",
81
+ onClick: () => alert("Design menu clicked"),
82
+ disabled: true,
83
+ },
84
+ ],
85
+ onClick: () => alert("Design clicked"),
86
+ },
71
87
  {
72
88
  name: "design",
73
89
  usedBy: 3,
@@ -124,7 +140,12 @@ const columns: ColumnDef<Data>[] = [
124
140
  },
125
141
  {
126
142
  accessorKey: "usedBy",
143
+ minSize: 100,
144
+ size: 100,
127
145
  header: "Used by",
146
+ meta: {
147
+ width: "100px",
148
+ },
128
149
  cell: (info) => (
129
150
  <DataTable.CellContent>{info.row.original.usedBy}</DataTable.CellContent>
130
151
  ),
@@ -132,6 +153,9 @@ const columns: ColumnDef<Data>[] = [
132
153
  {
133
154
  accessorKey: "addedBy",
134
155
  header: "Added by",
156
+ meta: {
157
+ width: "100px",
158
+ },
135
159
  cell: (info) => (
136
160
  <DataTable.CellContent>{info.row.original.addedBy}</DataTable.CellContent>
137
161
  ),
@@ -139,6 +163,9 @@ const columns: ColumnDef<Data>[] = [
139
163
  {
140
164
  accessorKey: "lastUpdated",
141
165
  header: "Last updated",
166
+ meta: {
167
+ width: "200px",
168
+ },
142
169
  cell: (info) => (
143
170
  <DataTable.CellContent>
144
171
  {info.row.original.lastUpdated}
@@ -149,6 +176,9 @@ const columns: ColumnDef<Data>[] = [
149
176
  {
150
177
  accessorKey: "size",
151
178
  header: "Size",
179
+ meta: {
180
+ width: "100px",
181
+ },
152
182
  cell: (info) => (
153
183
  <DataTable.CellContent>{info.row.original.size}</DataTable.CellContent>
154
184
  ),
@@ -192,6 +222,7 @@ export const DataTablePaginatedExample = () => {
192
222
  onChange={(v) => setFilter(v)}
193
223
  />
194
224
  <DataTable
225
+ className="s-w-full s-max-w-4xl s-overflow-x-auto"
195
226
  data={data}
196
227
  filter={filter}
197
228
  filterColumn="name"
@@ -227,6 +258,7 @@ export const DataTablePaginatedServerSideExample = () => {
227
258
  onChange={(v) => setFilter(v)}
228
259
  />
229
260
  <DataTable
261
+ className="s-w-full s-max-w-4xl s-overflow-x-auto"
230
262
  data={rows}
231
263
  totalRowCount={data.length}
232
264
  filter={filter}
@@ -26,7 +26,7 @@ export const TextAreaExample = () => {
26
26
  onChange={(v) =>
27
27
  setTextValues([v, textValues[1], textValues[2], textValues[3]])
28
28
  }
29
- rows={2}
29
+ minRows={2}
30
30
  />
31
31
  <TextArea
32
32
  placeholder="placeholder"