@tuturuuu/ui 0.0.4

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 (104) hide show
  1. package/.checksum +1 -0
  2. package/README.md +46 -0
  3. package/components.json +20 -0
  4. package/eslint.config.mjs +20 -0
  5. package/jsr.json +10 -0
  6. package/package.json +120 -0
  7. package/postcss.config.mjs +8 -0
  8. package/rollup.config.js +40 -0
  9. package/src/components/ui/accordion.tsx +70 -0
  10. package/src/components/ui/alert-dialog.tsx +156 -0
  11. package/src/components/ui/alert.tsx +58 -0
  12. package/src/components/ui/aspect-ratio.tsx +11 -0
  13. package/src/components/ui/avatar.tsx +52 -0
  14. package/src/components/ui/badge.tsx +49 -0
  15. package/src/components/ui/breadcrumb.tsx +108 -0
  16. package/src/components/ui/button.tsx +61 -0
  17. package/src/components/ui/calendar.tsx +212 -0
  18. package/src/components/ui/card.tsx +74 -0
  19. package/src/components/ui/carousel.tsx +240 -0
  20. package/src/components/ui/chart.tsx +365 -0
  21. package/src/components/ui/checkbox.tsx +31 -0
  22. package/src/components/ui/codeblock.tsx +161 -0
  23. package/src/components/ui/collapsible.tsx +33 -0
  24. package/src/components/ui/color-picker.tsx +143 -0
  25. package/src/components/ui/command.tsx +176 -0
  26. package/src/components/ui/context-menu.tsx +251 -0
  27. package/src/components/ui/custom/autosize-textarea.tsx +111 -0
  28. package/src/components/ui/custom/calendar/core.tsx +61 -0
  29. package/src/components/ui/custom/calendar/day-cell.tsx +74 -0
  30. package/src/components/ui/custom/calendar/month-header.tsx +59 -0
  31. package/src/components/ui/custom/calendar/month-view.tsx +110 -0
  32. package/src/components/ui/custom/calendar/utils.ts +76 -0
  33. package/src/components/ui/custom/calendar/year-calendar.tsx +64 -0
  34. package/src/components/ui/custom/calendar/year-view.tsx +58 -0
  35. package/src/components/ui/custom/combobox.tsx +197 -0
  36. package/src/components/ui/custom/common-footer.tsx +215 -0
  37. package/src/components/ui/custom/compared-date-range-picker.tsx +561 -0
  38. package/src/components/ui/custom/date-input.tsx +279 -0
  39. package/src/components/ui/custom/empty-card.tsx +39 -0
  40. package/src/components/ui/custom/feature-summary.tsx +135 -0
  41. package/src/components/ui/custom/file-uploader.tsx +349 -0
  42. package/src/components/ui/custom/input-field.tsx +29 -0
  43. package/src/components/ui/custom/loading-indicator.tsx +28 -0
  44. package/src/components/ui/custom/modifiable-dialog-trigger.tsx +83 -0
  45. package/src/components/ui/custom/month-picker.tsx +157 -0
  46. package/src/components/ui/custom/report-preview.tsx +175 -0
  47. package/src/components/ui/custom/search-bar.tsx +56 -0
  48. package/src/components/ui/custom/select-field.tsx +78 -0
  49. package/src/components/ui/custom/tables/data-table-column-header.tsx +72 -0
  50. package/src/components/ui/custom/tables/data-table-create-button.tsx +31 -0
  51. package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +142 -0
  52. package/src/components/ui/custom/tables/data-table-pagination.tsx +243 -0
  53. package/src/components/ui/custom/tables/data-table-refresh-button.tsx +45 -0
  54. package/src/components/ui/custom/tables/data-table-toolbar.tsx +133 -0
  55. package/src/components/ui/custom/tables/data-table-view-options.tsx +112 -0
  56. package/src/components/ui/custom/tables/data-table.tsx +228 -0
  57. package/src/components/ui/custom/uploaded-files-card.tsx +50 -0
  58. package/src/components/ui/dialog.tsx +137 -0
  59. package/src/components/ui/drawer.tsx +131 -0
  60. package/src/components/ui/dropdown-menu.tsx +256 -0
  61. package/src/components/ui/form.tsx +167 -0
  62. package/src/components/ui/hover-card.tsx +41 -0
  63. package/src/components/ui/icons.tsx +506 -0
  64. package/src/components/ui/input-otp.tsx +78 -0
  65. package/src/components/ui/input.tsx +18 -0
  66. package/src/components/ui/label.tsx +23 -0
  67. package/src/components/ui/markdown.tsx +7 -0
  68. package/src/components/ui/menubar.tsx +275 -0
  69. package/src/components/ui/navigation-menu.tsx +169 -0
  70. package/src/components/ui/pagination.tsx +126 -0
  71. package/src/components/ui/popover.tsx +47 -0
  72. package/src/components/ui/progress.tsx +30 -0
  73. package/src/components/ui/radio-group.tsx +44 -0
  74. package/src/components/ui/resizable.tsx +55 -0
  75. package/src/components/ui/scroll-area.tsx +57 -0
  76. package/src/components/ui/select.tsx +180 -0
  77. package/src/components/ui/separator.tsx +27 -0
  78. package/src/components/ui/sheet.tsx +138 -0
  79. package/src/components/ui/sidebar.tsx +734 -0
  80. package/src/components/ui/skeleton.tsx +13 -0
  81. package/src/components/ui/slider.tsx +62 -0
  82. package/src/components/ui/sonner.tsx +29 -0
  83. package/src/components/ui/switch.tsx +30 -0
  84. package/src/components/ui/table.tsx +112 -0
  85. package/src/components/ui/tabs.tsx +68 -0
  86. package/src/components/ui/tag-input.tsx +141 -0
  87. package/src/components/ui/textarea.tsx +17 -0
  88. package/src/components/ui/time-picker-input.tsx +117 -0
  89. package/src/components/ui/time-picker-utils.tsx +146 -0
  90. package/src/components/ui/toast.tsx +128 -0
  91. package/src/components/ui/toaster.tsx +35 -0
  92. package/src/components/ui/toggle-group.tsx +72 -0
  93. package/src/components/ui/toggle.tsx +46 -0
  94. package/src/components/ui/tooltip.tsx +60 -0
  95. package/src/globals.css +252 -0
  96. package/src/hooks/use-callback-ref.ts +28 -0
  97. package/src/hooks/use-controllable-state.ts +68 -0
  98. package/src/hooks/use-copy-to-clipboard.ts +46 -0
  99. package/src/hooks/use-form.ts +23 -0
  100. package/src/hooks/use-forwarded-ref.ts +17 -0
  101. package/src/hooks/use-mobile.tsx +21 -0
  102. package/src/hooks/use-toast.ts +191 -0
  103. package/src/resolvers.ts +3 -0
  104. package/tsconfig.json +17 -0
@@ -0,0 +1,243 @@
1
+ 'use client';
2
+
3
+ import { Button } from '../../button';
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from '../../select';
11
+ import { Separator } from '../../separator';
12
+ import { Table } from '@tanstack/react-table';
13
+ import { cn } from '@tuturuuu/utils/format';
14
+ import {
15
+ ArrowLeftToLine,
16
+ ArrowRightToLine,
17
+ ChevronLeft,
18
+ ChevronRight,
19
+ } from 'lucide-react';
20
+
21
+ interface DataTablePaginationProps<TData> {
22
+ table?: Table<TData>;
23
+ count?: number | null;
24
+ className?: string;
25
+ pageIndex?: number;
26
+ pageCount?: number;
27
+ pageSize?: number;
28
+ additionalSizes?: number[];
29
+ t?: any;
30
+ // eslint-disable-next-line no-unused-vars
31
+ setParams?: (params: { page?: number; pageSize?: string }) => void;
32
+ }
33
+
34
+ export function DataTablePagination<TData>({
35
+ table,
36
+ count,
37
+ className,
38
+ pageIndex,
39
+ pageCount,
40
+ pageSize,
41
+ additionalSizes,
42
+ t,
43
+ setParams,
44
+ }: DataTablePaginationProps<TData>) {
45
+ // filter duplicate and sort sizes
46
+ const sizes = [
47
+ 5,
48
+ 10,
49
+ 20,
50
+ 50,
51
+ 100,
52
+ 200,
53
+ 500,
54
+ 1000,
55
+ pageSize ?? 10,
56
+ ...(additionalSizes ?? []),
57
+ ]
58
+ .filter((value, index, self) => self.indexOf(value) === index)
59
+ .sort((a, b) => a - b);
60
+
61
+ const isPageOutOfRange = table
62
+ ? table.getState().pagination.pageIndex + 1 > table.getPageCount()
63
+ : pageIndex !== undefined
64
+ ? pageIndex + 1 > (pageCount ?? 1)
65
+ : false;
66
+
67
+ return (
68
+ <div
69
+ className={cn(
70
+ 'flex flex-col items-center justify-between gap-1 px-2 text-center md:flex-row',
71
+ className
72
+ )}
73
+ >
74
+ {count != undefined && count > 0 ? (
75
+ <div className="flex-none text-sm text-muted-foreground">
76
+ {/* {locale === 'vi' || locale === 'vi-VN' ? t('common.selected') : null}{' '} */}
77
+ {/* <span className="text-primary font-semibold">
78
+ {table ? table.getFilteredSelectedRowModel().rows.length : 0}
79
+ </span>{' '}
80
+ {t('common.of')}{' '} */}
81
+ {/* {table.getFilteredRowModel().rows.length} row(s) selected. */}
82
+ <span className="font-semibold text-primary">{count}</span>{' '}
83
+ {t?.('common.result(s)') ?? 'result(s)'}
84
+ {/* {locale !== 'vi' && locale !== 'vi-VN'
85
+ ? ' ' + t('common.selected').toLowerCase()
86
+ : null} */}
87
+ .
88
+ </div>
89
+ ) : (
90
+ <div />
91
+ )}
92
+
93
+ <Separator className="my-1 md:hidden" />
94
+
95
+ <div className="flex flex-wrap items-center justify-center gap-2 text-center md:gap-4 lg:gap-8">
96
+ <div className="hidden items-center space-x-2 md:flex">
97
+ <p className="text-sm font-medium">
98
+ {t?.('common.rows-per-page') ?? 'Rows per page'}
99
+ </p>
100
+ <Select
101
+ value={`${pageSize ?? table?.getState().pagination.pageSize ?? 0}`}
102
+ onValueChange={(value) => {
103
+ if (table) {
104
+ table.setPageIndex(0);
105
+ table.setPageSize(Number(value));
106
+ }
107
+
108
+ setParams?.({ page: 1, pageSize: value });
109
+ }}
110
+ >
111
+ <SelectTrigger className="h-8 w-[70px]">
112
+ <SelectValue
113
+ placeholder={
114
+ pageSize ?? table?.getState().pagination.pageSize ?? 0
115
+ }
116
+ />
117
+ </SelectTrigger>
118
+ <SelectContent side="top">
119
+ {sizes.map((pageSize) => (
120
+ <SelectItem key={pageSize} value={`${pageSize}`}>
121
+ {pageSize}
122
+ </SelectItem>
123
+ ))}
124
+ </SelectContent>
125
+ </Select>
126
+ </div>
127
+ <div className="w-fit text-sm text-muted-foreground">
128
+ {t?.('common.page') ?? 'Page'}{' '}
129
+ <span className="font-semibold text-primary">
130
+ {isPageOutOfRange
131
+ ? 1
132
+ : (pageIndex ?? table?.getState().pagination.pageIndex ?? 0) + 1}
133
+ </span>
134
+ {(pageCount ?? table?.getPageCount() ?? 0) > 0 && (
135
+ <>
136
+ {' '}
137
+ {t?.('common.of') ?? 'of'}{' '}
138
+ <span className="font-semibold text-primary">
139
+ {pageCount ?? table?.getPageCount() ?? 1}
140
+ </span>
141
+ </>
142
+ )}
143
+ </div>
144
+
145
+ {(pageCount ?? table?.getPageCount() ?? 0) > 0 && (
146
+ <div className="flex items-center space-x-2">
147
+ <Button
148
+ variant="outline"
149
+ className="hidden h-8 w-8 p-0 lg:flex"
150
+ onClick={() => {
151
+ if (table) {
152
+ table.resetRowSelection();
153
+ table.setPageIndex(0);
154
+ }
155
+
156
+ setParams?.({ page: 1 });
157
+ }}
158
+ disabled={
159
+ (pageIndex !== undefined
160
+ ? pageIndex <= 0
161
+ : table && !table.getCanPreviousPage()) || isPageOutOfRange
162
+ }
163
+ >
164
+ <span className="sr-only">Go to first page</span>
165
+ <ArrowLeftToLine className="h-4 w-4" />
166
+ </Button>
167
+ <Button
168
+ variant="outline"
169
+ className="h-8 w-8 p-0"
170
+ onClick={() => {
171
+ if (table) {
172
+ table.resetRowSelection();
173
+ table.previousPage();
174
+ }
175
+
176
+ setParams?.({
177
+ page:
178
+ pageIndex ?? table?.getState().pagination.pageIndex ?? 0,
179
+ });
180
+ }}
181
+ disabled={
182
+ (pageIndex !== undefined
183
+ ? pageIndex <= 0
184
+ : table && !table.getCanPreviousPage()) || isPageOutOfRange
185
+ }
186
+ >
187
+ <span className="sr-only">Go to previous page</span>
188
+ <ChevronLeft className="h-4 w-4" />
189
+ </Button>
190
+ <Button
191
+ variant="outline"
192
+ className="h-8 w-8 p-0"
193
+ onClick={() => {
194
+ if (table) {
195
+ table.resetRowSelection();
196
+ table.nextPage();
197
+ }
198
+
199
+ setParams?.({
200
+ page: isPageOutOfRange
201
+ ? 2
202
+ : (pageIndex ??
203
+ table?.getState().pagination.pageIndex ??
204
+ 0) + 2,
205
+ });
206
+ }}
207
+ disabled={
208
+ (pageIndex !== undefined
209
+ ? pageIndex >= (pageCount ?? 0) - 1
210
+ : table && !table.getCanNextPage()) && !isPageOutOfRange
211
+ }
212
+ >
213
+ <span className="sr-only">Go to next page</span>
214
+ <ChevronRight className="h-4 w-4" />
215
+ </Button>
216
+ <Button
217
+ variant="outline"
218
+ className="hidden h-8 w-8 p-0 lg:flex"
219
+ onClick={() => {
220
+ if (table) {
221
+ table.resetRowSelection();
222
+ table.setPageIndex(table.getPageCount() - 1);
223
+ }
224
+
225
+ setParams?.({
226
+ page: pageCount ?? table?.getPageCount() ?? 1,
227
+ });
228
+ }}
229
+ disabled={
230
+ (pageIndex !== undefined
231
+ ? pageIndex >= (pageCount ?? 0) - 1
232
+ : table && !table.getCanNextPage()) && !isPageOutOfRange
233
+ }
234
+ >
235
+ <span className="sr-only">Go to last page</span>
236
+ <ArrowRightToLine className="h-4 w-4" />
237
+ </Button>
238
+ </div>
239
+ )}
240
+ </div>
241
+ </div>
242
+ );
243
+ }
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+
3
+ import { Button } from '../../button';
4
+ import { cn } from '@tuturuuu/utils/format';
5
+ import { RefreshCcw } from 'lucide-react';
6
+ import { useEffect, useState } from 'react';
7
+
8
+ export function DataTableRefreshButton({
9
+ onRefresh,
10
+ refreshText,
11
+ disabled,
12
+ }: {
13
+ onRefresh: () => void;
14
+ refreshText: string;
15
+ disabled?: boolean;
16
+ }) {
17
+ const [isRefreshing, setIsRefreshing] = useState(false);
18
+
19
+ useEffect(() => {
20
+ if (!isRefreshing) return;
21
+ const timeout = setTimeout(() => {
22
+ setIsRefreshing(false);
23
+ }, 1000);
24
+
25
+ return () => {
26
+ clearTimeout(timeout);
27
+ };
28
+ }, [isRefreshing]);
29
+
30
+ return (
31
+ <Button
32
+ variant="outline"
33
+ size="sm"
34
+ className="ml-auto h-8 w-full md:w-fit"
35
+ onClick={() => {
36
+ setIsRefreshing(true);
37
+ onRefresh();
38
+ }}
39
+ disabled={isRefreshing || disabled}
40
+ >
41
+ <RefreshCcw className={cn('h-4 w-4', isRefreshing && 'animate-spin')} />
42
+ {refreshText}
43
+ </Button>
44
+ );
45
+ }
@@ -0,0 +1,133 @@
1
+ 'use client';
2
+
3
+ import { Button } from '../../button';
4
+ import SearchBar from '../search-bar';
5
+ import { DataTableCreateButton } from './data-table-create-button';
6
+ import { DataTableRefreshButton } from './data-table-refresh-button';
7
+ import { DataTableViewOptions } from './data-table-view-options';
8
+ import { Table } from '@tanstack/react-table';
9
+ import { Dialog, DialogContent, DialogTrigger } from '@tuturuuu/ui/dialog';
10
+ import { Download, RotateCcw, Upload } from 'lucide-react';
11
+ import { ReactNode } from 'react';
12
+
13
+ interface DataTableToolbarProps<TData> {
14
+ hasData: boolean;
15
+ newObjectTitle?: string;
16
+ editContent?: ReactNode;
17
+ namespace: string | undefined;
18
+ table: Table<TData>;
19
+ filters?: ReactNode[] | ReactNode;
20
+ extraColumns?: any[];
21
+ defaultQuery?: string;
22
+ disableSearch?: boolean;
23
+ isEmpty: boolean;
24
+ t?: any;
25
+ importContent?: ReactNode;
26
+ exportContent?: ReactNode;
27
+ onRefresh: () => void;
28
+ // eslint-disable-next-line no-unused-vars
29
+ onSearch: (query: string) => void;
30
+ resetParams: () => void;
31
+ }
32
+
33
+ export function DataTableToolbar<TData>({
34
+ hasData,
35
+ newObjectTitle,
36
+ editContent,
37
+ table,
38
+ filters,
39
+ extraColumns,
40
+ defaultQuery,
41
+ disableSearch = false,
42
+ isEmpty,
43
+ t,
44
+ namespace,
45
+ importContent,
46
+ exportContent,
47
+ onRefresh,
48
+ onSearch,
49
+ resetParams,
50
+ }: DataTableToolbarProps<TData>) {
51
+ const isFiltered =
52
+ table.getState().columnFilters.length > 0 ||
53
+ !isEmpty ||
54
+ (defaultQuery?.length || 0) > 0;
55
+
56
+ return (
57
+ <div className="flex flex-col items-start justify-between gap-2 md:flex-row">
58
+ <div className="grid w-full flex-1 flex-wrap items-center gap-2 md:flex">
59
+ {disableSearch || (
60
+ <SearchBar
61
+ t={t}
62
+ defaultValue={defaultQuery}
63
+ onSearch={onSearch}
64
+ className="col-span-full w-full md:col-span-1 md:max-w-xs"
65
+ />
66
+ )}
67
+ {filters}
68
+ {isFiltered && (
69
+ <Button
70
+ variant="secondary"
71
+ onClick={() => {
72
+ table.resetColumnFilters();
73
+ resetParams();
74
+ }}
75
+ className="h-8 px-2 lg:px-3"
76
+ >
77
+ {t?.('common.reset')}
78
+ <RotateCcw className="h-4 w-4" />
79
+ </Button>
80
+ )}
81
+ </div>
82
+
83
+ {importContent && (
84
+ <Dialog>
85
+ <DialogTrigger asChild>
86
+ <Button variant="outline" size="sm" className="h-8 w-full md:w-fit">
87
+ <Upload className="h-4 w-4" />
88
+ {t?.('common.import')}
89
+ </Button>
90
+ </DialogTrigger>
91
+ <DialogContent className="max-w-sm">{importContent}</DialogContent>
92
+ </Dialog>
93
+ )}
94
+
95
+ {exportContent && (
96
+ <Dialog>
97
+ <DialogTrigger asChild>
98
+ <Button
99
+ variant="outline"
100
+ size="sm"
101
+ className="ml-auto h-8 w-full md:w-fit"
102
+ >
103
+ <Download className="h-4 w-4" />
104
+ {t?.('common.export')}
105
+ </Button>
106
+ </DialogTrigger>
107
+ <DialogContent className="max-w-sm">{exportContent}</DialogContent>
108
+ </Dialog>
109
+ )}
110
+
111
+ <div className="grid w-full grid-cols-2 gap-2 md:flex md:w-fit">
112
+ {editContent && (
113
+ <DataTableCreateButton
114
+ newObjectTitle={newObjectTitle}
115
+ editContent={editContent}
116
+ />
117
+ )}
118
+ {hasData && (
119
+ <DataTableRefreshButton
120
+ onRefresh={onRefresh}
121
+ refreshText={t?.('common.refresh') || 'Refresh'}
122
+ />
123
+ )}
124
+ <DataTableViewOptions
125
+ t={t}
126
+ namespace={namespace}
127
+ table={table}
128
+ extraColumns={extraColumns}
129
+ />
130
+ </div>
131
+ </div>
132
+ );
133
+ }
@@ -0,0 +1,112 @@
1
+ 'use client';
2
+
3
+ import { Button } from '../../button';
4
+ import {
5
+ DropdownMenu,
6
+ DropdownMenuCheckboxItem,
7
+ DropdownMenuContent,
8
+ DropdownMenuLabel,
9
+ DropdownMenuSeparator,
10
+ } from '../../dropdown-menu';
11
+ import { ScrollArea } from '../../scroll-area';
12
+ import { DropdownMenuTrigger } from '@radix-ui/react-dropdown-menu';
13
+ import { Table } from '@tanstack/react-table';
14
+ import { Settings2, UserCog } from 'lucide-react';
15
+ import { Fragment } from 'react';
16
+
17
+ interface DataTableViewOptionsProps<TData> {
18
+ table: Table<TData>;
19
+ extraColumns?: any[];
20
+ namespace: string | undefined;
21
+ t?: any;
22
+ }
23
+
24
+ export function DataTableViewOptions<TData>({
25
+ t,
26
+ namespace,
27
+ table,
28
+ extraColumns,
29
+ }: DataTableViewOptionsProps<TData>) {
30
+ const isShowingAll = table
31
+ .getAllColumns()
32
+ .every((column) => column.getIsVisible());
33
+
34
+ return (
35
+ <DropdownMenu modal={false}>
36
+ <DropdownMenuTrigger asChild>
37
+ <Button
38
+ variant="outline"
39
+ size="sm"
40
+ className="ml-auto h-8 w-full md:w-fit"
41
+ >
42
+ <Settings2 className="h-4 w-4" />
43
+ {t?.('common.view-options') || 'View Options'}
44
+ </Button>
45
+ </DropdownMenuTrigger>
46
+ <DropdownMenuContent align="end" className="w-64">
47
+ <DropdownMenuLabel>
48
+ {t?.('common.toggle-columns') || 'Toggle Columns'}
49
+ </DropdownMenuLabel>
50
+ <DropdownMenuSeparator />
51
+ <ScrollArea className="h-36">
52
+ {table
53
+ .getAllColumns()
54
+ .filter(
55
+ (column) =>
56
+ typeof column.accessorFn !== 'undefined' && column.getCanHide()
57
+ )
58
+ .map((column, idx) => {
59
+ return (
60
+ <Fragment key={column.id}>
61
+ {/* If this item is the last system column before the extra
62
+ columns start (if there is any), add a separator */}
63
+ {extraColumns?.length &&
64
+ extraColumns[0].id === column.id &&
65
+ idx !== 0 ? (
66
+ <DropdownMenuSeparator key={`${column.id}-separator`} />
67
+ ) : null}
68
+
69
+ <DropdownMenuCheckboxItem
70
+ key={`${column.id}-checkbox`}
71
+ checked={column.getIsVisible()}
72
+ onCheckedChange={(value) => column.toggleVisibility(value)}
73
+ >
74
+ {extraColumns?.some(
75
+ (extraColumn) => extraColumn.id === column.id
76
+ ) ? (
77
+ <UserCog className="mr-1 h-4 w-4" />
78
+ ) : undefined}
79
+
80
+ {(extraColumns as Array<{ id: string; name?: string }>)
81
+ ?.filter(
82
+ (extraColumn: { id: string; name?: string }) =>
83
+ extraColumn.id === column.id
84
+ )
85
+ .pop()?.name || namespace
86
+ ? t?.(`${namespace}.${column.id}`)
87
+ : column.id}
88
+ </DropdownMenuCheckboxItem>
89
+ </Fragment>
90
+ );
91
+ })}
92
+ </ScrollArea>
93
+ <DropdownMenuSeparator />
94
+ <DropdownMenuLabel>
95
+ <Button
96
+ className="w-full"
97
+ size="sm"
98
+ onClick={() => {
99
+ table
100
+ .getAllColumns()
101
+ .forEach((column) => column.toggleVisibility(!isShowingAll));
102
+ }}
103
+ >
104
+ {isShowingAll
105
+ ? t?.('common.hide-all') || 'Hide All'
106
+ : t?.('common.show-all') || 'Show All'}
107
+ </Button>
108
+ </DropdownMenuLabel>
109
+ </DropdownMenuContent>
110
+ </DropdownMenu>
111
+ );
112
+ }