@tuturuuu/ui 0.25.2 → 0.26.0

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/biome.json +1 -1
  3. package/package.json +13 -12
  4. package/src/components/ui/chat/chat-sidebar-items.tsx +25 -19
  5. package/src/components/ui/chat/chat-utils.test.ts +88 -2
  6. package/src/components/ui/chat/chat-workspace.tsx +1 -0
  7. package/src/components/ui/chat/composer-attachment-chip.tsx +128 -0
  8. package/src/components/ui/chat/external-message-content.test.ts +41 -0
  9. package/src/components/ui/chat/external-message-content.ts +28 -0
  10. package/src/components/ui/chat/message-bubble.tsx +4 -2
  11. package/src/components/ui/chat/message-composer.tsx +121 -33
  12. package/src/components/ui/chat/message-links.test.tsx +14 -0
  13. package/src/components/ui/chat/utils.ts +39 -3
  14. package/src/components/ui/custom/education/courses/course-row-actions.tsx +1 -1
  15. package/src/components/ui/custom/education/modules/course-module-row-actions.tsx +1 -1
  16. package/src/components/ui/custom/structure.test.tsx +55 -1
  17. package/src/components/ui/custom/structure.tsx +10 -1
  18. package/src/components/ui/custom/tables/custom-data-table.tsx +3 -2
  19. package/src/components/ui/custom/tables/data-table-column-header.tsx +4 -3
  20. package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +4 -3
  21. package/src/components/ui/custom/tables/data-table-pagination.tsx +6 -6
  22. package/src/components/ui/custom/tables/data-table-toolbar.tsx +5 -5
  23. package/src/components/ui/custom/tables/data-table-view-options.tsx +4 -3
  24. package/src/components/ui/custom/tables/data-table.tsx +69 -30
  25. package/src/components/ui/finance/invoices/columns.test.tsx +3 -3
  26. package/src/components/ui/finance/invoices/columns.tsx +4 -2
  27. package/src/components/ui/finance/invoices/pending-columns.tsx +1 -1
  28. package/src/components/ui/finance/invoices/row-actions.tsx +1 -1
  29. package/src/components/ui/finance/transactions/categories/columns.test.tsx +5 -5
  30. package/src/components/ui/finance/transactions/categories/columns.tsx +4 -2
  31. package/src/components/ui/finance/transactions/categories/row-actions.tsx +1 -1
  32. package/src/components/ui/finance/transactions/columns.test.tsx +5 -5
  33. package/src/components/ui/finance/transactions/columns.tsx +4 -2
  34. package/src/components/ui/finance/transactions/row-actions.tsx +1 -1
  35. package/src/components/ui/finance/wallets/columns.tsx +4 -2
  36. package/src/components/ui/finance/wallets/row-actions.tsx +1 -1
@@ -1,33 +1,73 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
- type ColumnDef,
5
4
  type ColumnFiltersState,
5
+ type ColumnVisibilityState,
6
+ columnFacetingFeature,
7
+ columnFilteringFeature,
8
+ columnVisibilityFeature,
9
+ createFacetedRowModel,
10
+ createFacetedUniqueValues,
11
+ createFilteredRowModel,
12
+ createSortedRowModel,
6
13
  flexRender,
7
- getCoreRowModel,
8
- getFacetedRowModel,
9
- getFacetedUniqueValues,
10
- getFilteredRowModel,
11
- getSortedRowModel,
12
- type Row,
14
+ globalFilteringFeature,
15
+ type ReactTable,
16
+ type RowData,
17
+ rowPaginationFeature,
18
+ rowSelectionFeature,
19
+ rowSortingFeature,
13
20
  type SortingState,
14
- useReactTable,
15
- type VisibilityState,
21
+ type Column as TanStackColumn,
22
+ type ColumnDef as TanStackColumnDef,
23
+ type Row as TanStackRow,
24
+ tableFeatures,
25
+ useTable,
16
26
  } from '@tanstack/react-table';
17
27
  import { cn } from '@tuturuuu/utils/format';
18
28
  import { type ReactNode, useState } from 'react';
19
29
  import { Card } from '../../card';
20
30
  import {
21
- Table,
22
31
  TableBody,
23
32
  TableCell,
24
33
  TableHead,
25
34
  TableHeader,
26
35
  TableRow,
36
+ Table as UiTable,
27
37
  } from '../../table';
28
38
  import { DataTablePagination } from './data-table-pagination';
29
39
  import { DataTableToolbar } from './data-table-toolbar';
30
40
 
41
+ export const dataTableFeatures = tableFeatures({
42
+ columnFilteringFeature,
43
+ globalFilteringFeature,
44
+ columnFacetingFeature,
45
+ rowSortingFeature,
46
+ rowPaginationFeature,
47
+ rowSelectionFeature,
48
+ columnVisibilityFeature,
49
+ filteredRowModel: createFilteredRowModel(),
50
+ sortedRowModel: createSortedRowModel(),
51
+ facetedRowModel: createFacetedRowModel(),
52
+ facetedUniqueValues: createFacetedUniqueValues(),
53
+ });
54
+
55
+ const EMPTY_DATA: never[] = [];
56
+
57
+ export type DataTableFeatures = typeof dataTableFeatures;
58
+ export type ColumnDef<TData extends RowData, TValue = any> = TanStackColumnDef<
59
+ DataTableFeatures,
60
+ TData,
61
+ TValue
62
+ >;
63
+ export type Row<TData extends RowData> = TanStackRow<DataTableFeatures, TData>;
64
+ export type Column<TData extends RowData, TValue = unknown> = TanStackColumn<
65
+ DataTableFeatures,
66
+ TData,
67
+ TValue
68
+ >;
69
+ export type Table<TData extends RowData> = ReactTable<DataTableFeatures, TData>;
70
+
31
71
  function isInteractiveTarget(target: EventTarget | null) {
32
72
  if (!(target instanceof HTMLElement)) return false;
33
73
  return Boolean(
@@ -59,26 +99,27 @@ export interface ColumnGeneratorOptions<
59
99
  /**
60
100
  * Type for column generator functions that create table columns.
61
101
  */
62
- export type ColumnGenerator<TData = unknown, TValue = unknown> = (
102
+ export type ColumnGenerator<TData extends RowData, TValue = unknown> = (
63
103
  options: ColumnGeneratorOptions<TData, TValue>
64
- ) => ColumnDef<TData, TValue>[];
104
+ ) => ColumnDef<TData>[];
65
105
 
66
- export interface DataTableProps<TData, TValue> {
106
+ export interface DataTableProps<TData extends RowData, TValue> {
67
107
  hideToolbar?: boolean;
68
108
  hidePagination?: boolean;
69
- columns?: ColumnDef<TData, TValue>[];
109
+ columns?: ColumnDef<TData>[];
70
110
  filters?: ReactNode[] | ReactNode;
71
111
  extraColumns?: any[];
72
112
  extraData?: any;
73
113
  newObjectTitle?: string;
74
114
  editContent?: ReactNode;
115
+ emptyState?: ReactNode;
75
116
  namespace?: string | undefined;
76
117
  data?: TData[];
77
118
  count?: number | null;
78
119
  pageIndex?: number;
79
120
  pageSize?: number;
80
121
  defaultQuery?: string;
81
- defaultVisibility?: VisibilityState;
122
+ defaultVisibility?: ColumnVisibilityState;
82
123
  disableSearch?: boolean;
83
124
  isFiltered?: boolean;
84
125
  enableServerSideSorting?: boolean;
@@ -114,7 +155,7 @@ export interface DataTableProps<TData, TValue> {
114
155
  rowWrapper?: (row: React.ReactElement, rowData: TData) => React.ReactElement;
115
156
  }
116
157
 
117
- export function DataTable<TData, TValue>({
158
+ export function DataTable<TData extends RowData, TValue>({
118
159
  hideToolbar = false,
119
160
  hidePagination = false,
120
161
  columns,
@@ -123,6 +164,7 @@ export function DataTable<TData, TValue>({
123
164
  extraData,
124
165
  newObjectTitle,
125
166
  editContent,
167
+ emptyState,
126
168
  namespace,
127
169
  data,
128
170
  count,
@@ -155,7 +197,7 @@ export function DataTable<TData, TValue>({
155
197
  }: DataTableProps<TData, TValue>) {
156
198
  const [rowSelection, setRowSelection] = useState({});
157
199
  const [columnVisibility, setColumnVisibility] =
158
- useState<VisibilityState>(defaultVisibility);
200
+ useState<ColumnVisibilityState>(defaultVisibility);
159
201
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
160
202
  const [sorting, setSorting] = useState<SortingState>(
161
203
  enableServerSideSorting && currentSortBy && currentSortOrder
@@ -163,8 +205,9 @@ export function DataTable<TData, TValue>({
163
205
  : []
164
206
  );
165
207
 
166
- const table = useReactTable({
167
- data: data || [],
208
+ const table = useTable({
209
+ features: dataTableFeatures,
210
+ data: data || EMPTY_DATA,
168
211
  columns:
169
212
  columnGenerator && t
170
213
  ? columnGenerator({ t, namespace, extraColumns, extraData })
@@ -215,14 +258,7 @@ export function DataTable<TData, TValue>({
215
258
  : setSorting,
216
259
  onColumnFiltersChange: setColumnFilters,
217
260
  onColumnVisibilityChange: setColumnVisibility,
218
- getCoreRowModel: getCoreRowModel(),
219
- getFilteredRowModel: getFilteredRowModel(),
220
- getSortedRowModel: enableServerSideSorting
221
- ? undefined
222
- : getSortedRowModel(),
223
261
  manualSorting: enableServerSideSorting,
224
- getFacetedRowModel: getFacetedRowModel(),
225
- getFacetedUniqueValues: getFacetedUniqueValues(),
226
262
  });
227
263
 
228
264
  return (
@@ -250,7 +286,7 @@ export function DataTable<TData, TValue>({
250
286
  />
251
287
  )}
252
288
  <Card className={tableCardClassName}>
253
- <Table className={tableClassName}>
289
+ <UiTable className={tableClassName}>
254
290
  <TableHeader>
255
291
  {table.getHeaderGroups().map((headerGroup) => (
256
292
  <TableRow key={headerGroup.id}>
@@ -339,16 +375,19 @@ export function DataTable<TData, TValue>({
339
375
  columns?.length ||
340
376
  1
341
377
  }
342
- className="h-24 text-center opacity-60"
378
+ className={cn(
379
+ 'text-center',
380
+ emptyState ? 'p-0' : 'h-24 opacity-60'
381
+ )}
343
382
  >
344
383
  {data
345
- ? `${t?.('common.no-results')}.`
384
+ ? emptyState || `${t?.('common.no-results')}.`
346
385
  : `${t?.('common.loading')}…`}
347
386
  </TableCell>
348
387
  </TableRow>
349
388
  )}
350
389
  </TableBody>
351
- </Table>
390
+ </UiTable>
352
391
  </Card>
353
392
 
354
393
  {hidePagination ||
@@ -1,5 +1,5 @@
1
- import type { ColumnDef } from '@tanstack/react-table';
2
1
  import { render, screen, waitFor } from '@testing-library/react';
2
+ import type { ColumnDef } from '@tuturuuu/ui/custom/tables/data-table';
3
3
  import { beforeEach, describe, expect, it, vi } from 'vitest';
4
4
  import { invoiceColumns } from './columns';
5
5
 
@@ -19,8 +19,8 @@ function InvoicePriceCell({ price }: { price: number }) {
19
19
  });
20
20
  const priceColumn = columns.find(
21
21
  (column) =>
22
- (column as ColumnDef<unknown> & { accessorKey?: string }).accessorKey ===
23
- 'price'
22
+ (column as ColumnDef<Record<string, unknown>> & { accessorKey?: string })
23
+ .accessorKey === 'price'
24
24
  );
25
25
 
26
26
  if (typeof priceColumn?.cell !== 'function') return null;
@@ -1,9 +1,11 @@
1
1
  'use client';
2
2
 
3
- import type { ColumnDef } from '@tanstack/react-table';
4
3
  import type { Invoice } from '@tuturuuu/types/primitives/Invoice';
5
4
  import { Avatar, AvatarFallback, AvatarImage } from '@tuturuuu/ui/avatar';
6
- import type { ColumnGeneratorOptions } from '@tuturuuu/ui/custom/tables/data-table';
5
+ import type {
6
+ ColumnDef,
7
+ ColumnGeneratorOptions,
8
+ } from '@tuturuuu/ui/custom/tables/data-table';
7
9
  import { DataTableColumnHeader } from '@tuturuuu/ui/custom/tables/data-table-column-header';
8
10
  import { InvoiceRowActions } from '@tuturuuu/ui/finance/invoices/row-actions';
9
11
  import {
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
 
3
- import type { ColumnDef } from '@tanstack/react-table';
4
3
  import { FileText } from '@tuturuuu/icons';
5
4
  import type { PendingInvoice } from '@tuturuuu/types/primitives/PendingInvoice';
6
5
  import { Avatar, AvatarFallback, AvatarImage } from '@tuturuuu/ui/avatar';
7
6
  import { Button } from '@tuturuuu/ui/button';
7
+ import type { ColumnDef } from '@tuturuuu/ui/custom/tables/data-table';
8
8
  import { DataTableColumnHeader } from '@tuturuuu/ui/custom/tables/data-table-column-header';
9
9
  import { Popover, PopoverContent, PopoverTrigger } from '@tuturuuu/ui/popover';
10
10
  import { formatCurrency } from '@tuturuuu/utils/format';
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
- import type { Row } from '@tanstack/react-table';
5
4
  import { Ellipsis, Eye } from '@tuturuuu/icons';
6
5
  import { deleteInvoice } from '@tuturuuu/internal-api/finance';
7
6
  import type { Invoice } from '@tuturuuu/types/primitives/Invoice';
@@ -17,6 +16,7 @@ import {
17
16
  AlertDialogTrigger,
18
17
  } from '@tuturuuu/ui/alert-dialog';
19
18
  import { Button } from '@tuturuuu/ui/button';
19
+ import type { Row } from '@tuturuuu/ui/custom/tables/data-table';
20
20
  import {
21
21
  DropdownMenu,
22
22
  DropdownMenuContent,
@@ -1,5 +1,5 @@
1
- import type { ColumnDef } from '@tanstack/react-table';
2
1
  import { render, screen, waitFor } from '@testing-library/react';
2
+ import type { ColumnDef } from '@tuturuuu/ui/custom/tables/data-table';
3
3
  import { beforeEach, describe, expect, it } from 'vitest';
4
4
  import { transactionCategoryColumns } from './columns';
5
5
 
@@ -15,8 +15,8 @@ function CategoryAmountCell({ amount }: { amount: number }) {
15
15
  });
16
16
  const amountColumn = columns.find(
17
17
  (column) =>
18
- (column as ColumnDef<unknown> & { accessorKey?: string }).accessorKey ===
19
- 'amount'
18
+ (column as ColumnDef<Record<string, unknown>> & { accessorKey?: string })
19
+ .accessorKey === 'amount'
20
20
  );
21
21
 
22
22
  if (typeof amountColumn?.cell !== 'function') return null;
@@ -45,8 +45,8 @@ function CategoryCountCell({ count }: { count: number }) {
45
45
  });
46
46
  const countColumn = columns.find(
47
47
  (column) =>
48
- (column as ColumnDef<unknown> & { accessorKey?: string }).accessorKey ===
49
- 'transaction_count'
48
+ (column as ColumnDef<Record<string, unknown>> & { accessorKey?: string })
49
+ .accessorKey === 'transaction_count'
50
50
  );
51
51
 
52
52
  if (typeof countColumn?.cell !== 'function') return null;
@@ -1,13 +1,15 @@
1
1
  'use client';
2
2
 
3
- import type { ColumnDef } from '@tanstack/react-table';
4
3
  import { ArrowDownCircle, ArrowUpCircle } from '@tuturuuu/icons';
5
4
  import type { TransactionCategoryWithStats } from '@tuturuuu/types/primitives/TransactionCategory';
6
5
  import {
7
6
  getIconComponentByKey,
8
7
  type PlatformIconKey,
9
8
  } from '@tuturuuu/ui/custom/icon-picker';
10
- import type { ColumnGeneratorOptions } from '@tuturuuu/ui/custom/tables/data-table';
9
+ import type {
10
+ ColumnDef,
11
+ ColumnGeneratorOptions,
12
+ } from '@tuturuuu/ui/custom/tables/data-table';
11
13
  import { DataTableColumnHeader } from '@tuturuuu/ui/custom/tables/data-table-column-header';
12
14
  import { TransactionCategoryRowActions } from '@tuturuuu/ui/finance/transactions/categories/row-actions';
13
15
  import { computeAccessibleLabelStyles } from '@tuturuuu/utils/label-colors';
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { useMutation, useQueryClient } from '@tanstack/react-query';
4
- import type { Row } from '@tanstack/react-table';
5
4
  import { Ellipsis } from '@tuturuuu/icons';
6
5
  import { deleteTransactionCategory } from '@tuturuuu/internal-api/finance';
7
6
  import type { TransactionCategory } from '@tuturuuu/types/primitives/TransactionCategory';
@@ -18,6 +17,7 @@ import {
18
17
  } from '@tuturuuu/ui/alert-dialog';
19
18
  import { Button } from '@tuturuuu/ui/button';
20
19
  import ModifiableDialogTrigger from '@tuturuuu/ui/custom/modifiable-dialog-trigger';
20
+ import type { Row } from '@tuturuuu/ui/custom/tables/data-table';
21
21
  import {
22
22
  DropdownMenu,
23
23
  DropdownMenuContent,
@@ -1,5 +1,5 @@
1
- import type { ColumnDef } from '@tanstack/react-table';
2
1
  import { render, screen, waitFor } from '@testing-library/react';
2
+ import type { ColumnDef } from '@tuturuuu/ui/custom/tables/data-table';
3
3
  import { beforeEach, describe, expect, it, vi } from 'vitest';
4
4
  import { transactionColumns } from './columns';
5
5
 
@@ -23,8 +23,8 @@ function TransactionAmountCell({ amount }: { amount: number }) {
23
23
  });
24
24
  const amountColumn = columns.find(
25
25
  (column) =>
26
- (column as ColumnDef<unknown> & { accessorKey?: string }).accessorKey ===
27
- 'amount'
26
+ (column as ColumnDef<Record<string, unknown>> & { accessorKey?: string })
27
+ .accessorKey === 'amount'
28
28
  );
29
29
 
30
30
  if (typeof amountColumn?.cell !== 'function') return null;
@@ -57,8 +57,8 @@ function TransactionColumnCell({
57
57
  });
58
58
  const column = columns.find(
59
59
  (item) =>
60
- (item as ColumnDef<unknown> & { accessorKey?: string }).accessorKey ===
61
- accessorKey
60
+ (item as ColumnDef<Record<string, unknown>> & { accessorKey?: string })
61
+ .accessorKey === accessorKey
62
62
  );
63
63
 
64
64
  if (typeof column?.cell !== 'function') return null;
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
 
3
- import type { ColumnDef } from '@tanstack/react-table';
4
3
  import { Check, X } from '@tuturuuu/icons';
5
4
  import type { Transaction } from '@tuturuuu/types/primitives/Transaction';
6
5
  import { Avatar, AvatarFallback, AvatarImage } from '@tuturuuu/ui/avatar';
7
- import type { ColumnGeneratorOptions } from '@tuturuuu/ui/custom/tables/data-table';
6
+ import type {
7
+ ColumnDef,
8
+ ColumnGeneratorOptions,
9
+ } from '@tuturuuu/ui/custom/tables/data-table';
8
10
  import { TransactionRowActions } from '@tuturuuu/ui/finance/transactions/row-actions';
9
11
  import { formatCurrency } from '@tuturuuu/utils/format';
10
12
  import moment from 'moment';
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
- import type { Row } from '@tanstack/react-table';
5
4
  import { Ellipsis, Eye } from '@tuturuuu/icons';
6
5
  import { deleteTransaction as deleteTransactionWithInternalApi } from '@tuturuuu/internal-api/finance';
7
6
  import type { Transaction } from '@tuturuuu/types/primitives/Transaction';
@@ -18,6 +17,7 @@ import {
18
17
  } from '@tuturuuu/ui/alert-dialog';
19
18
  import { Button } from '@tuturuuu/ui/button';
20
19
  import ModifiableDialogTrigger from '@tuturuuu/ui/custom/modifiable-dialog-trigger';
20
+ import type { Row } from '@tuturuuu/ui/custom/tables/data-table';
21
21
  import {
22
22
  DropdownMenu,
23
23
  DropdownMenuContent,
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import type { ColumnDef } from '@tanstack/react-table';
4
3
  import {
5
4
  BookOpen,
6
5
  Check,
@@ -14,7 +13,10 @@ import {
14
13
  } from '@tuturuuu/icons';
15
14
  import type { Wallet } from '@tuturuuu/types/primitives/Wallet';
16
15
  import { Badge } from '@tuturuuu/ui/badge';
17
- import type { ColumnGeneratorOptions } from '@tuturuuu/ui/custom/tables/data-table';
16
+ import type {
17
+ ColumnDef,
18
+ ColumnGeneratorOptions,
19
+ } from '@tuturuuu/ui/custom/tables/data-table';
18
20
  import { DataTableColumnHeader } from '@tuturuuu/ui/custom/tables/data-table-column-header';
19
21
  import { WalletRowActions } from '@tuturuuu/ui/finance/wallets/row-actions';
20
22
  import type { ExchangeRate } from '@tuturuuu/utils/exchange-rates';
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
- import type { Row } from '@tanstack/react-table';
5
4
  import { Ellipsis, Eye } from '@tuturuuu/icons';
6
5
  import { deleteWallet as deleteWalletWithInternalApi } from '@tuturuuu/internal-api/finance';
7
6
  import type { Wallet } from '@tuturuuu/types/primitives/Wallet';
@@ -18,6 +17,7 @@ import {
18
17
  } from '@tuturuuu/ui/alert-dialog';
19
18
  import { Button } from '@tuturuuu/ui/button';
20
19
  import ModifiableDialogTrigger from '@tuturuuu/ui/custom/modifiable-dialog-trigger';
20
+ import type { Row } from '@tuturuuu/ui/custom/tables/data-table';
21
21
  import {
22
22
  DropdownMenu,
23
23
  DropdownMenuContent,