@jakubmazanec/ui 0.4.2 → 0.5.0-next.7fc14073

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 (116) hide show
  1. package/build/components/Button.js +8 -5
  2. package/build/components/Button.js.map +2 -2
  3. package/build/components/Checkbox.js +2 -2
  4. package/build/components/Checkbox.js.map +1 -1
  5. package/build/components/Combobox.js +1 -1
  6. package/build/components/Combobox.js.map +1 -1
  7. package/build/components/DialogPanel.js +1 -1
  8. package/build/components/DialogPanel.js.map +1 -1
  9. package/build/components/DialogTitle.js +1 -1
  10. package/build/components/DialogTitle.js.map +1 -1
  11. package/build/components/Heading.d.ts +21 -0
  12. package/build/components/Heading.js +48 -0
  13. package/build/components/Heading.js.map +7 -0
  14. package/build/components/Icon.js +1 -1
  15. package/build/components/Icon.js.map +1 -1
  16. package/build/components/Input.js +4 -4
  17. package/build/components/Input.js.map +2 -2
  18. package/build/components/Legend.js +1 -1
  19. package/build/components/Legend.js.map +1 -1
  20. package/build/components/ListboxOption.js +1 -1
  21. package/build/components/ListboxOption.js.map +1 -1
  22. package/build/components/Radio.js +2 -2
  23. package/build/components/Radio.js.map +1 -1
  24. package/build/components/Spinner.js +1 -1
  25. package/build/components/Spinner.js.map +1 -1
  26. package/build/components/TableHead.js +1 -1
  27. package/build/components/TableHead.js.map +1 -1
  28. package/build/components/TableHeader.js +1 -1
  29. package/build/components/TableHeader.js.map +2 -2
  30. package/build/components/Textarea.js +2 -2
  31. package/build/components/Textarea.js.map +1 -1
  32. package/build/components/data-table/DataTable.d.ts +2 -1
  33. package/build/components/data-table/DataTable.js +78 -76
  34. package/build/components/data-table/DataTable.js.map +2 -2
  35. package/build/components/data-table/internals/DataTableFilter.d.ts +12 -0
  36. package/build/components/data-table/internals/DataTableFilter.js +275 -0
  37. package/build/components/data-table/internals/DataTableFilter.js.map +7 -0
  38. package/build/components/data-table/internals/DataTableFilters.d.ts +11 -0
  39. package/build/components/data-table/internals/DataTableFilters.js +40 -0
  40. package/build/components/data-table/internals/DataTableFilters.js.map +7 -0
  41. package/build/components/data-table/internals/DataTableHeader.d.ts +2 -11
  42. package/build/components/data-table/internals/DataTableHeader.js +18 -112
  43. package/build/components/data-table/internals/DataTableHeader.js.map +2 -2
  44. package/build/components/data-table/internals/DataTableMenu.d.ts +11 -0
  45. package/build/components/data-table/internals/DataTableMenu.js +34 -0
  46. package/build/components/data-table/internals/DataTableMenu.js.map +7 -0
  47. package/build/components/data-table/internals/DataTablePagination.js +2 -2
  48. package/build/components/data-table/internals/DataTablePagination.js.map +2 -2
  49. package/build/components/data-table/internals/DataTableRow.d.ts +6 -0
  50. package/build/components/data-table/internals/DataTableRow.js +26 -0
  51. package/build/components/data-table/internals/DataTableRow.js.map +7 -0
  52. package/build/components/data-table/internals/DataTableSetting.d.ts +10 -0
  53. package/build/components/data-table/internals/DataTableSetting.js +111 -0
  54. package/build/components/data-table/internals/DataTableSetting.js.map +7 -0
  55. package/build/components/data-table/internals/DataTableSettings.d.ts +9 -0
  56. package/build/components/data-table/internals/DataTableSettings.js +63 -0
  57. package/build/components/data-table/internals/DataTableSettings.js.map +7 -0
  58. package/build/components/data-table/internals/constants.d.ts +1 -1
  59. package/build/components/data-table/internals/constants.js +1 -1
  60. package/build/components/data-table/internals/constants.js.map +2 -2
  61. package/build/components/data-table/internals.d.ts +5 -0
  62. package/build/components/data-table/internals.js +5 -0
  63. package/build/components/data-table/internals.js.map +2 -2
  64. package/build/components.d.ts +1 -0
  65. package/build/components.js +1 -0
  66. package/build/components.js.map +2 -2
  67. package/build/development/createTailwindConfig.d.ts +79 -2
  68. package/build/development/createTailwindConfig.js +10 -55
  69. package/build/development/createTailwindConfig.js.map +2 -2
  70. package/build/development/internals/createTailwindThemeColors.d.ts +2 -0
  71. package/build/development/internals/createTailwindThemeColors.js +51 -0
  72. package/build/development/internals/createTailwindThemeColors.js.map +7 -0
  73. package/build/development/internals.d.ts +1 -0
  74. package/build/development/internals.js +1 -0
  75. package/build/development/internals.js.map +2 -2
  76. package/build/styles.css +15 -1
  77. package/build/styles.css.map +2 -2
  78. package/build/theme/Theme.d.ts +3 -0
  79. package/build/theme/defaultTheme.js +2 -0
  80. package/build/theme/defaultTheme.js.map +2 -2
  81. package/build/theme/internals/themeContext.d.ts +10 -0
  82. package/build/theme/internals/useTheme.d.ts +10 -0
  83. package/package.json +1 -1
  84. package/source/components/Button.tsx +12 -5
  85. package/source/components/Checkbox.tsx +2 -2
  86. package/source/components/Combobox.tsx +1 -1
  87. package/source/components/DialogPanel.tsx +1 -1
  88. package/source/components/DialogTitle.tsx +1 -1
  89. package/source/components/Heading.ts +69 -0
  90. package/source/components/Icon.tsx +1 -1
  91. package/source/components/Input.tsx +5 -5
  92. package/source/components/Legend.tsx +1 -1
  93. package/source/components/ListboxOption.tsx +1 -1
  94. package/source/components/Radio.tsx +2 -2
  95. package/source/components/Spinner.tsx +1 -1
  96. package/source/components/TableHead.ts +1 -1
  97. package/source/components/TableHeader.ts +2 -1
  98. package/source/components/Textarea.tsx +2 -2
  99. package/source/components/data-table/DataTable.tsx +97 -82
  100. package/source/components/data-table/internals/DataTableFilter.tsx +354 -0
  101. package/source/components/data-table/internals/DataTableFilters.tsx +56 -0
  102. package/source/components/data-table/internals/DataTableHeader.tsx +7 -145
  103. package/source/components/data-table/internals/DataTableMenu.tsx +60 -0
  104. package/source/components/data-table/internals/DataTablePagination.tsx +79 -77
  105. package/source/components/data-table/internals/DataTableRow.tsx +40 -0
  106. package/source/components/data-table/internals/DataTableSetting.tsx +142 -0
  107. package/source/components/data-table/internals/DataTableSettings.tsx +83 -0
  108. package/source/components/data-table/internals/constants.ts +1 -1
  109. package/source/components/data-table/internals.ts +5 -0
  110. package/source/components.ts +1 -0
  111. package/source/development/createTailwindConfig.ts +11 -57
  112. package/source/development/internals/createTailwindThemeColors.ts +53 -0
  113. package/source/development/internals.ts +1 -0
  114. package/source/styles.css +19 -3
  115. package/source/theme/Theme.ts +2 -0
  116. package/source/theme/defaultTheme.ts +2 -0
@@ -0,0 +1,354 @@
1
+ import {type Column, flexRender, type Header, type Table} from '@tanstack/react-table';
2
+ import {type ChangeEvent, type FormEvent, useCallback, useMemo, useState} from 'react';
3
+
4
+ import {Button} from '../../Button.js';
5
+ import {Combobox} from '../../Combobox.js';
6
+ import {Container} from '../../Container.js';
7
+ import {Field} from '../../Field.js';
8
+ import {Form} from '../../Form.js';
9
+ import {Icon} from '../../Icon.js';
10
+ import {Input} from '../../Input.js';
11
+ import {Label} from '../../Label.js';
12
+ import {Listbox} from '../../Listbox.js';
13
+ import {type DataTableProps} from '../DataTable.js';
14
+ import {addFilter} from './addFilter.js';
15
+ import {normalizeFilter} from './normalizeFilter.js';
16
+ import {normalizeFilters} from './normalizeFilters.js';
17
+ import {removeFilter} from './removeFilter.js';
18
+
19
+ export type DataTableFilterProps = {
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
21
+ table: Table<any>;
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
23
+ column: Column<any>;
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
25
+ clientFilters: DataTableProps<any, any>['clientFilters'];
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
27
+ filters: DataTableProps<any, any>['filters'];
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
29
+ onFiltering: DataTableProps<any, any>['onFiltersChange'];
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
31
+ clientFaceting: DataTableProps<any, any>['clientFaceting'];
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
33
+ faceting: DataTableProps<any, any>['faceting'];
34
+ };
35
+
36
+ export function DataTableFilter({
37
+ table,
38
+ column,
39
+ clientFilters,
40
+ filters: controlledFilters,
41
+ onFiltering,
42
+ clientFaceting,
43
+ faceting,
44
+ }: DataTableFilterProps) {
45
+ let {filterVariant} = column.columnDef.meta ?? {};
46
+
47
+ let currentFilters =
48
+ clientFilters ? normalizeFilters(table) : normalizeFilters(table, controlledFilters);
49
+ let currentFilter =
50
+ clientFilters ? normalizeFilter(column) : normalizeFilter(column, controlledFilters);
51
+
52
+ let currentMin =
53
+ filterVariant === 'range' ?
54
+ ((currentFilter as [number?, number?] | undefined)?.[0] ?? undefined)
55
+ : undefined;
56
+ let currentMax =
57
+ filterVariant === 'range' ?
58
+ ((currentFilter as [number?, number?] | undefined)?.[1] ?? undefined)
59
+ : undefined;
60
+
61
+ let [filter, setFilter] = useState<string | undefined>(
62
+ typeof currentFilter === 'string' ? currentFilter : undefined,
63
+ );
64
+ let [min, setMin] = useState(currentMin);
65
+ let [max, setMax] = useState(currentMax);
66
+
67
+ let facetingValues = useMemo(() => {
68
+ if (!clientFaceting) {
69
+ return faceting?.[column.id]?.values ?? [];
70
+ }
71
+
72
+ if (filterVariant === 'range') {
73
+ return [];
74
+ }
75
+
76
+ return [...column.getFacetedUniqueValues().keys()].sort().slice(0, 5000) as unknown[];
77
+ }, [clientFaceting, column, faceting, filterVariant]);
78
+
79
+ let facetingMin =
80
+ clientFaceting ?
81
+ Number(column.getFacetedMinMaxValues()?.[0] ?? null)
82
+ : (faceting?.[column.id]?.min ?? null);
83
+ let facetingMax =
84
+ clientFaceting ?
85
+ Number(column.getFacetedMinMaxValues()?.[1] ?? null)
86
+ : (faceting?.[column.id]?.max ?? null);
87
+
88
+ let handleMinRangeChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
89
+ setMin(event.target.value ? Number(event.target.value) : undefined);
90
+ }, []);
91
+
92
+ let handleMaxRangeChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
93
+ setMax(event.target.value ? Number(event.target.value) : undefined);
94
+ }, []);
95
+
96
+ let handleSelectFilterChange = useCallback(
97
+ (value: string) => {
98
+ if (clientFilters) {
99
+ column.setFilterValue(value);
100
+ }
101
+
102
+ if (onFiltering) {
103
+ onFiltering(addFilter(currentFilters, column.id, value));
104
+ }
105
+ },
106
+ [clientFilters, column, currentFilters, onFiltering],
107
+ );
108
+
109
+ let handleTextFilterChange = useCallback(
110
+ (value: string | undefined) => {
111
+ if (value) {
112
+ if (clientFilters) {
113
+ column.setFilterValue(value);
114
+ }
115
+
116
+ if (onFiltering) {
117
+ onFiltering(addFilter(currentFilters, column.id, value));
118
+ }
119
+ } else {
120
+ if (clientFilters) {
121
+ column.setFilterValue(undefined);
122
+ }
123
+
124
+ if (onFiltering) {
125
+ onFiltering(removeFilter(currentFilters, column.id));
126
+ }
127
+ }
128
+ },
129
+ [clientFilters, column, currentFilters, onFiltering],
130
+ );
131
+
132
+ let handleFilterChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
133
+ if (event.target.value) {
134
+ setFilter(event.target.value);
135
+ } else {
136
+ setFilter(undefined);
137
+ }
138
+ }, []);
139
+
140
+ let handleFilterClick = useCallback(() => {
141
+ if (filterVariant === 'range') {
142
+ if (!min && !max) {
143
+ if (clientFilters) {
144
+ column.setFilterValue(undefined);
145
+ }
146
+
147
+ if (onFiltering) {
148
+ onFiltering(removeFilter(currentFilters, column.id));
149
+ }
150
+ } else {
151
+ if (clientFilters) {
152
+ column.setFilterValue([min, max]);
153
+ }
154
+
155
+ if (onFiltering) {
156
+ onFiltering(addFilter(currentFilters, column.id, [min, max]));
157
+ }
158
+ }
159
+ }
160
+
161
+ if ((filterVariant === 'text' && !facetingValues.length) || !filterVariant) {
162
+ if (filter) {
163
+ if (clientFilters) {
164
+ column.setFilterValue(filter);
165
+ }
166
+
167
+ if (onFiltering) {
168
+ onFiltering(addFilter(currentFilters, column.id, filter));
169
+ }
170
+ } else {
171
+ if (clientFilters) {
172
+ column.setFilterValue(undefined);
173
+ }
174
+
175
+ if (onFiltering) {
176
+ onFiltering(removeFilter(currentFilters, column.id));
177
+ }
178
+ }
179
+ }
180
+ }, [
181
+ clientFilters,
182
+ column,
183
+ currentFilters,
184
+ facetingValues.length,
185
+ filter,
186
+ filterVariant,
187
+ max,
188
+ min,
189
+ onFiltering,
190
+ ]);
191
+
192
+ let handleFilterSubmit = useCallback(
193
+ (event: FormEvent<HTMLFormElement>) => {
194
+ event.preventDefault();
195
+
196
+ if (filterVariant === 'range') {
197
+ if (min === undefined && max === undefined) {
198
+ if (clientFilters) {
199
+ column.setFilterValue(undefined);
200
+ }
201
+
202
+ if (onFiltering) {
203
+ onFiltering(removeFilter(currentFilters, column.id));
204
+ }
205
+ } else {
206
+ if (clientFilters) {
207
+ column.setFilterValue([min, max]);
208
+ }
209
+
210
+ if (onFiltering) {
211
+ onFiltering(addFilter(currentFilters, column.id, [min, max]));
212
+ }
213
+ }
214
+ }
215
+
216
+ if ((filterVariant === 'text' && !facetingValues.length) || !filterVariant) {
217
+ if (filter) {
218
+ if (clientFilters) {
219
+ column.setFilterValue(filter);
220
+ }
221
+
222
+ if (onFiltering) {
223
+ onFiltering(addFilter(currentFilters, column.id, filter));
224
+ }
225
+ } else {
226
+ if (clientFilters) {
227
+ column.setFilterValue(undefined);
228
+ }
229
+
230
+ if (onFiltering) {
231
+ onFiltering(removeFilter(currentFilters, column.id));
232
+ }
233
+ }
234
+ }
235
+ },
236
+ [
237
+ clientFilters,
238
+ column,
239
+ currentFilters,
240
+ facetingValues.length,
241
+ filter,
242
+ filterVariant,
243
+ max,
244
+ min,
245
+ onFiltering,
246
+ ],
247
+ );
248
+
249
+ let handleResetClick = useCallback(() => {
250
+ setFilter(undefined);
251
+ setMin(undefined);
252
+ setMax(undefined);
253
+
254
+ if (clientFilters) {
255
+ column.setFilterValue(undefined);
256
+ }
257
+
258
+ if (onFiltering) {
259
+ onFiltering(removeFilter(currentFilters, column.id));
260
+ }
261
+ }, [clientFilters, column, currentFilters, onFiltering]);
262
+
263
+ let filterElement = null;
264
+
265
+ if (filterVariant === 'range') {
266
+ filterElement = (
267
+ <Container spacing="small">
268
+ <Input
269
+ max={String(facetingMax ?? '')}
270
+ min={String(facetingMin ?? '')}
271
+ placeholder={`Min ${facetingMin === null ? '' : `(${facetingMin})`}`}
272
+ type="number"
273
+ value={min ?? ''}
274
+ onChange={handleMinRangeChange}
275
+ />
276
+ <Input
277
+ max={String(facetingMax ?? '')}
278
+ min={String(facetingMin ?? '')}
279
+ placeholder={`Max ${facetingMax === null ? '' : `(${facetingMax})`}`}
280
+ type="number"
281
+ value={max ?? ''}
282
+ onChange={handleMaxRangeChange}
283
+ />
284
+ <Button submit aria-label="Filter" variant="outline" onClick={handleFilterClick}>
285
+ <Icon name="Funnel" size="large" />
286
+ </Button>
287
+ <Button aria-label="Cancel" variant="outline" onClick={handleResetClick}>
288
+ <Icon name="XMark" size="large" />
289
+ </Button>
290
+ </Container>
291
+ );
292
+ } else if (filterVariant === 'select' && facetingValues.length) {
293
+ filterElement = (
294
+ <Container spacing="small">
295
+ <Listbox
296
+ items={(facetingValues as string[]).map((value: string) => ({
297
+ value,
298
+ label: `${value as unknown}`,
299
+ }))}
300
+ value={currentFilter as string}
301
+ onChange={handleSelectFilterChange}
302
+ />
303
+ <Button aria-label="Cancel" variant="outline" onClick={handleResetClick}>
304
+ <Icon name="XMark" size="large" />
305
+ </Button>
306
+ </Container>
307
+ );
308
+ } else if (filterVariant === 'text' && facetingValues.length) {
309
+ filterElement = (
310
+ <Container spacing="small">
311
+ <Combobox
312
+ customValue
313
+ items={(facetingValues as string[]).map((value: string) => ({
314
+ value,
315
+ label: `${value as unknown}`,
316
+ }))}
317
+ value={(currentFilter ?? '') as string}
318
+ onChange={handleTextFilterChange}
319
+ />
320
+ <Button aria-label="Cancel" variant="outline" onClick={handleResetClick}>
321
+ <Icon name="XMark" size="large" />
322
+ </Button>
323
+ </Container>
324
+ );
325
+ } else if ((filterVariant === 'text' && !facetingValues.length) || !filterVariant) {
326
+ filterElement = (
327
+ <Container spacing="small">
328
+ <Input value={filter ?? ''} onChange={handleFilterChange} />
329
+ <Button aria-label="Filter" variant="outline" onClick={handleFilterClick}>
330
+ <Icon name="Funnel" size="large" />
331
+ </Button>
332
+ <Button aria-label="Cancel" variant="outline" onClick={handleResetClick}>
333
+ <Icon name="XMark" size="large" />
334
+ </Button>
335
+ </Container>
336
+ );
337
+ }
338
+
339
+ return (
340
+ <Form onSubmit={handleFilterSubmit}>
341
+ <Field className="gap-2">
342
+ <Label>
343
+ {flexRender(column.columnDef.header, {
344
+ table,
345
+ column,
346
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions -- needed
347
+ header: {column} as Header<any, any>,
348
+ })}
349
+ </Label>
350
+ {filterElement}
351
+ </Field>
352
+ </Form>
353
+ );
354
+ }
@@ -0,0 +1,56 @@
1
+ import {type Table} from '@tanstack/react-table';
2
+
3
+ import {Container} from '../../Container.js';
4
+ import {Heading} from '../../Heading.js';
5
+ import {type DataTableProps} from '../DataTable.js';
6
+ import {DataTableFilter} from './DataTableFilter.js';
7
+
8
+ export type DataTableFiltersProps = {
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
10
+ table: Table<any>;
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
12
+ clientFilters: DataTableProps<any, any>['clientFilters'];
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
14
+ filters: DataTableProps<any, any>['filters'];
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
16
+ onFiltering: DataTableProps<any, any>['onFiltersChange'];
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
18
+ clientFaceting: DataTableProps<any, any>['clientFaceting'];
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
20
+ faceting: DataTableProps<any, any>['faceting'];
21
+ };
22
+
23
+ export function DataTableFilters({
24
+ table,
25
+ clientFilters,
26
+ filters: controlledFilters,
27
+ onFiltering,
28
+ clientFaceting,
29
+ faceting,
30
+ }: DataTableFiltersProps) {
31
+ return (
32
+ <Container
33
+ className="hidden w-full justify-items-stretch bg-white sm:order-first sm:row-span-3 sm:border-r-2 sm:border-neutral-100 sm:pr-4 [[data-show-filters]_&]:flex"
34
+ direction="column"
35
+ >
36
+ <Heading size="small">Filters</Heading>
37
+
38
+ {table
39
+ .getAllLeafColumns()
40
+ .map((column) =>
41
+ column.getCanFilter() ?
42
+ <DataTableFilter
43
+ key={column.id}
44
+ clientFaceting={clientFaceting}
45
+ clientFilters={clientFilters}
46
+ column={column}
47
+ faceting={faceting}
48
+ filters={controlledFilters}
49
+ table={table}
50
+ onFiltering={onFiltering}
51
+ />
52
+ : null,
53
+ )}
54
+ </Container>
55
+ );
56
+ }
@@ -1,27 +1,16 @@
1
- import {useSortable} from '@dnd-kit/sortable';
2
- import {CSS} from '@dnd-kit/utilities';
3
- import {flexRender, type Header, type Table} from '@tanstack/react-table';
1
+ import {flexRender, type Header} from '@tanstack/react-table';
4
2
  import {type CSSProperties, useCallback} from 'react';
5
3
 
6
4
  import {Button} from '../../Button.js';
7
5
  import {Container} from '../../Container.js';
8
- import {Field} from '../../Field.js';
9
6
  import {Icon} from '../../Icon.js';
10
- import {Popover} from '../../Popover.js';
11
- import {PopoverButton} from '../../PopoverButton.js';
12
- import {PopoverPanel} from '../../PopoverPanel.js';
13
7
  import {TableHeader} from '../../TableHeader.js';
14
- import {Text} from '../../Text.js';
15
8
  import {type DataTableProps} from '../DataTable.js';
16
- import {DataTableHeaderColumnCheckbox} from './DataTableHeaderColumnCheckbox.js';
17
- import {DataTableHeaderFilter} from './DataTableHeaderFilter.js';
18
9
  import {getCommonPinningClasses} from './getCommonPinningClasses.js';
19
10
  import {getCommonPinningStyles} from './getCommonPinningStyles.js';
20
11
  import {normalizeSorting} from './normalizeSorting.js';
21
12
 
22
13
  export type DataTableHeaderProps = {
23
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
24
- table: Table<any>;
25
14
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
26
15
  header: Header<any, any>;
27
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
@@ -33,59 +22,23 @@ export type DataTableHeaderProps = {
33
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
34
23
  onSorting: DataTableProps<any, any>['onSortingChange'];
35
24
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
36
- clientFilters: DataTableProps<any, any>['clientFilters'];
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
38
- hideFilters: DataTableProps<any, any>['hideFilters'];
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
40
- filters: DataTableProps<any, any>['filters'];
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
42
- onFiltering: DataTableProps<any, any>['onFiltersChange'];
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
44
- clientFaceting: DataTableProps<any, any>['clientFaceting'];
45
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
46
- faceting: DataTableProps<any, any>['faceting'];
47
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
48
- hideColumnVisibility: DataTableProps<any, any>['hideColumnVisibility'];
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
50
25
  hideColumnOrder: DataTableProps<any, any>['hideColumnOrder'];
51
26
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
52
- hideColumnPinning: DataTableProps<any, any>['hideColumnPinning'];
53
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
54
27
  hideColumnResizing: DataTableProps<any, any>['hideColumnResizing'];
55
28
  };
56
29
 
57
30
  export function DataTableHeader({
58
- table,
59
31
  header,
60
32
  clientSorting,
61
33
  hideSorting = false,
62
34
  sorting: controlledSorting,
63
35
  onSorting,
64
- clientFilters,
65
- hideFilters = false,
66
- filters: controlledFilters,
67
- onFiltering,
68
- clientFaceting,
69
- faceting,
70
- hideColumnVisibility = false,
71
36
  hideColumnOrder = false,
72
- hideColumnPinning = false,
73
37
  hideColumnResizing = false,
74
38
  }: DataTableHeaderProps) {
75
- let {attributes, isDragging, listeners, setNodeRef, transform} = useSortable({
76
- id: header.column.id,
77
- });
78
-
79
39
  let sorting =
80
40
  clientSorting ? normalizeSorting(header) : normalizeSorting(header, controlledSorting);
81
41
 
82
- let style: CSSProperties = {
83
- transform: CSS.Translate.toString(transform),
84
- transition: 'width transform 0.2s ease-in-out',
85
- zIndex: isDragging ? 20 : undefined,
86
- ...getCommonPinningStyles(header.column),
87
- };
88
-
89
42
  let contentElement = null;
90
43
 
91
44
  if (!header.isPlaceholder) {
@@ -149,25 +102,15 @@ export function DataTableHeader({
149
102
  header.column.resetSize();
150
103
  }, [header.column]);
151
104
 
152
- let handlePinLeftClick = useCallback(() => {
153
- header.column.pin('left');
154
- }, [header.column]);
155
-
156
- let handlePinRightClick = useCallback(() => {
157
- header.column.pin('right');
158
- }, [header.column]);
159
-
160
- let handleUnpinClick = useCallback(() => {
161
- header.column.pin(false);
162
- }, [header.column]);
163
-
164
- let resolvedHideFilters = hideFilters || !header.column.getCanFilter();
165
105
  let resolvedHideSorting = hideSorting || !header.column.getCanSort();
166
- let resolvedHideColumnPinning = hideColumnPinning || !header.column.getCanPin();
106
+
107
+ let style: CSSProperties = {
108
+ transition: 'width transform 0.2s ease-in-out',
109
+ ...getCommonPinningStyles(header.column),
110
+ };
167
111
 
168
112
  return (
169
113
  <TableHeader
170
- ref={setNodeRef}
171
114
  className={getCommonPinningClasses(header.column)}
172
115
  colSpan={header.colSpan}
173
116
  style={style}
@@ -183,102 +126,21 @@ export function DataTableHeader({
183
126
  {resolvedHideSorting && hideColumnOrder ?
184
127
  contentElement
185
128
  : <Button
186
- className={hideColumnOrder ? 'inline-flex' : 'inline-flex cursor-move'}
129
+ className="inline-flex"
187
130
  size="small"
188
131
  title={title}
189
132
  variant="text"
190
133
  onClick={resolvedHideSorting ? undefined : handleSortClick}
191
- {...(hideColumnOrder ? {} : attributes)}
192
- {...(hideColumnOrder ? {} : listeners)}
193
134
  >
194
135
  {resolvedHideSorting ? null : sortElement}
195
136
  {contentElement}
196
137
  </Button>
197
138
  }
198
- {resolvedHideColumnPinning && resolvedHideFilters && hideColumnVisibility ? null : (
199
- <Popover>
200
- <PopoverButton>
201
- <Button aria-label="Settings" size="small" variant="text">
202
- <Icon name="Cog6Tooth" size="small" />
203
- </Button>
204
- </PopoverButton>
205
- <PopoverPanel anchor="right start">
206
- <Container direction="column" spacing="large">
207
- {resolvedHideColumnPinning ? null : (
208
- <Container direction="row" spacing="small">
209
- <Text>Pin column</Text>
210
-
211
- <Field>
212
- <Container spacing="small">
213
- {header.column.getIsPinned() === 'left' ? null : (
214
- <Button
215
- aria-label="Pin to left"
216
- variant="outline"
217
- onClick={handlePinLeftClick}
218
- >
219
- <Icon name="ArrowLeftEndOnRectangle" size="large" />
220
- </Button>
221
- )}
222
- {header.column.getIsPinned() ?
223
- <Button aria-label="Unpin" variant="outline" onClick={handleUnpinClick}>
224
- <Icon name="XMark" size="large" />
225
- </Button>
226
- : null}
227
- {header.column.getIsPinned() === 'right' ? null : (
228
- <Button
229
- aria-label="Pin to right"
230
- variant="outline"
231
- onClick={handlePinRightClick}
232
- >
233
- <Icon name="ArrowRightEndOnRectangle" size="large" />
234
- </Button>
235
- )}
236
- </Container>
237
- </Field>
238
- </Container>
239
- )}
240
-
241
- {resolvedHideFilters ? null : (
242
- <Container direction="column" spacing="small">
243
- <Text>Filter</Text>
244
-
245
- <Field>
246
- <DataTableHeaderFilter
247
- clientFaceting={clientFaceting}
248
- clientFilters={clientFilters}
249
- column={header.column}
250
- faceting={faceting}
251
- filters={controlledFilters}
252
- table={table}
253
- onFiltering={onFiltering}
254
- />
255
- </Field>
256
- </Container>
257
- )}
258
-
259
- {hideColumnVisibility ? null : (
260
- <Container direction="column" spacing="small">
261
- <Text>Visible columns</Text>
262
-
263
- {table.getAllLeafColumns().map((column) => (
264
- <DataTableHeaderColumnCheckbox
265
- key={column.id}
266
- column={column}
267
- table={table}
268
- />
269
- ))}
270
- </Container>
271
- )}
272
- </Container>
273
- </PopoverPanel>
274
- </Popover>
275
- )}
276
139
  </Container>
277
140
  </span>
278
141
  {hideColumnResizing ? null : (
279
142
  <Button
280
143
  aria-label="Resize"
281
- // className="absolute right-1 top-2.5 cursor-col-resize"
282
144
  className="absolute top-1/2 right-1 -mt-2.5 cursor-col-resize"
283
145
  size="small"
284
146
  variant="invisible"
@@ -0,0 +1,60 @@
1
+ import {type Table} from '@tanstack/react-table';
2
+
3
+ import {Button} from '../../Button.js';
4
+ import {Container} from '../../Container.js';
5
+ import {Icon} from '../../Icon.js';
6
+ import {Popover} from '../../Popover.js';
7
+ import {PopoverButton} from '../../PopoverButton.js';
8
+ import {PopoverPanel} from '../../PopoverPanel.js';
9
+ import {type DataTableProps} from '../DataTable.js';
10
+ import {DataTableSettings} from './DataTableSettings.js';
11
+
12
+ export type DataTableMenuProps = {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
14
+ table: Table<any>;
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
16
+ hideFilters: DataTableProps<any, any>['hideFilters'];
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
18
+ hideColumnVisibility: DataTableProps<any, any>['hideColumnVisibility'];
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
20
+ hideColumnOrder: DataTableProps<any, any>['hideColumnOrder'];
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needed
22
+ hideColumnPinning: DataTableProps<any, any>['hideColumnPinning'];
23
+
24
+ // TODO: this probablu should be passed via some context
25
+ toggleFilters: () => void;
26
+ };
27
+
28
+ export function DataTableMenu({
29
+ table,
30
+ hideFilters = false,
31
+ hideColumnVisibility = false,
32
+ hideColumnOrder = false,
33
+ hideColumnPinning = false,
34
+ toggleFilters,
35
+ }: DataTableMenuProps) {
36
+ return (
37
+ <Container justify="spaced" spacing="small">
38
+ {hideFilters ? null : (
39
+ <Button aria-label="Filter" variant="outline" onClick={toggleFilters}>
40
+ <Icon name="Funnel" size="large" />
41
+ </Button>
42
+ )}
43
+ <Popover className="ml-auto">
44
+ <PopoverButton>
45
+ <Button aria-label="Settings" variant="outline">
46
+ <Icon name="Cog6Tooth" size="large" />
47
+ </Button>
48
+ </PopoverButton>
49
+ <PopoverPanel anchor="bottom end">
50
+ <DataTableSettings
51
+ hideColumnOrder={hideColumnOrder}
52
+ hideColumnPinning={hideColumnPinning}
53
+ hideColumnVisibility={hideColumnVisibility}
54
+ table={table}
55
+ />
56
+ </PopoverPanel>
57
+ </Popover>
58
+ </Container>
59
+ );
60
+ }