@coveord/plasma-mantine 52.26.6 → 52.27.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 (59) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/.turbo/turbo-test.log +35 -34
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/cjs/components/table/Table.d.ts.map +1 -1
  5. package/dist/cjs/components/table/Table.js +7 -3
  6. package/dist/cjs/components/table/Table.js.map +1 -1
  7. package/dist/cjs/components/table/Table.styles.d.ts +1 -0
  8. package/dist/cjs/components/table/Table.styles.d.ts.map +1 -1
  9. package/dist/cjs/components/table/Table.styles.js +6 -5
  10. package/dist/cjs/components/table/Table.styles.js.map +1 -1
  11. package/dist/cjs/components/table/Table.types.d.ts +8 -2
  12. package/dist/cjs/components/table/Table.types.d.ts.map +1 -1
  13. package/dist/cjs/components/table/layouts/RowLayout.js +2 -1
  14. package/dist/cjs/components/table/layouts/RowLayout.js.map +1 -1
  15. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.d.ts +4 -0
  16. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.d.ts.map +1 -0
  17. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.js +99 -0
  18. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.js.map +1 -0
  19. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.styles.d.ts +10 -0
  20. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.styles.d.ts.map +1 -0
  21. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.styles.js +23 -0
  22. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.styles.js.map +1 -0
  23. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.types.d.ts +46 -0
  24. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.types.d.ts.map +1 -0
  25. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.types.js +6 -0
  26. package/dist/cjs/components/table/table-columns-selector/TableColumnsSelector.types.js.map +1 -0
  27. package/dist/esm/components/table/Table.d.ts.map +1 -1
  28. package/dist/esm/components/table/Table.js +6 -2
  29. package/dist/esm/components/table/Table.js.map +1 -1
  30. package/dist/esm/components/table/Table.styles.d.ts +1 -0
  31. package/dist/esm/components/table/Table.styles.d.ts.map +1 -1
  32. package/dist/esm/components/table/Table.styles.js +6 -5
  33. package/dist/esm/components/table/Table.styles.js.map +1 -1
  34. package/dist/esm/components/table/Table.types.d.ts +8 -2
  35. package/dist/esm/components/table/Table.types.d.ts.map +1 -1
  36. package/dist/esm/components/table/Table.types.js.map +1 -1
  37. package/dist/esm/components/table/layouts/RowLayout.js +1 -1
  38. package/dist/esm/components/table/layouts/RowLayout.js.map +1 -1
  39. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.d.ts +4 -0
  40. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.d.ts.map +1 -0
  41. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.js +84 -0
  42. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.js.map +1 -0
  43. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.styles.d.ts +10 -0
  44. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.styles.d.ts.map +1 -0
  45. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.styles.js +11 -0
  46. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.styles.js.map +1 -0
  47. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.types.d.ts +46 -0
  48. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.types.d.ts.map +1 -0
  49. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.types.js +3 -0
  50. package/dist/esm/components/table/table-columns-selector/TableColumnsSelector.types.js.map +1 -0
  51. package/package.json +1 -1
  52. package/src/components/table/Table.styles.ts +6 -5
  53. package/src/components/table/Table.tsx +6 -1
  54. package/src/components/table/Table.types.ts +8 -1
  55. package/src/components/table/__tests__/TableColumnsSelector.spec.tsx +260 -0
  56. package/src/components/table/layouts/RowLayout.tsx +1 -1
  57. package/src/components/table/table-columns-selector/TableColumnsSelector.styles.ts +8 -0
  58. package/src/components/table/table-columns-selector/TableColumnsSelector.tsx +78 -0
  59. package/src/components/table/table-columns-selector/TableColumnsSelector.types.ts +46 -0
@@ -21,6 +21,7 @@ import {TableLayouts} from './layouts/TableLayouts';
21
21
  import {TableActions} from './table-actions/TableActions';
22
22
  import {TableAccordionColumn, TableCollapsibleColumn} from './table-column/TableCollapsibleColumn';
23
23
  import {TableSelectableColumn} from './table-column/TableSelectableColumn';
24
+ import {TableColumnsSelector} from './table-columns-selector/TableColumnsSelector';
24
25
  import {TableConsumer} from './table-consumer/TableConsumer';
25
26
  import {TableDateRangePicker} from './table-date-range-picker/TableDateRangePicker';
26
27
  import {TableFilter} from './table-filter/TableFilter';
@@ -91,6 +92,8 @@ export const Table: TableType = <T,>({
91
92
  ...options,
92
93
  });
93
94
 
95
+ const getAllColumns = table.getAllFlatColumns;
96
+
94
97
  const [state, setState] = useState<TableState<T>>(table.initialState as TableState<T>);
95
98
  table.setOptions((prev) => ({
96
99
  ...prev,
@@ -144,7 +147,7 @@ export const Table: TableType = <T,>({
144
147
  }
145
148
 
146
149
  const Layout = layouts.find(({name}) => name === form.values.layout);
147
- const hasRows = table.getRowModel().rows.length > 0;
150
+ const hasRows = table.getRowModel()?.rows.length > 0;
148
151
 
149
152
  return (
150
153
  <Box ref={outsideClickRef}>
@@ -164,6 +167,7 @@ export const Table: TableType = <T,>({
164
167
  getPageCount: table.getPageCount,
165
168
  disableRowSelection,
166
169
  layouts,
170
+ getAllColumns,
167
171
  }}
168
172
  >
169
173
  {consumer}
@@ -217,6 +221,7 @@ export const Table: TableType = <T,>({
217
221
  );
218
222
  };
219
223
 
224
+ Table.ColumnsSelector = TableColumnsSelector;
220
225
  Table.Actions = TableActions;
221
226
  Table.Filter = TableFilter;
222
227
  Table.Footer = TableFooter;
@@ -2,6 +2,7 @@ import {Icon} from '@coveord/plasma-react-icons';
2
2
  import {DefaultProps, Selectors} from '@mantine/core';
3
3
  import {UseFormReturnType} from '@mantine/form';
4
4
  import {
5
+ Column,
5
6
  ColumnDef,
6
7
  CoreOptions,
7
8
  TableOptions,
@@ -11,10 +12,12 @@ import {
11
12
  import {Dispatch, ReactElement, ReactNode, RefObject} from 'react';
12
13
 
13
14
  import {DateRangePickerValue} from '../date-range-picker/DateRangePickerInlineCalendar';
15
+ import useStyles from './Table.styles';
14
16
  import {TableLayoutProps} from './layouts/RowLayout.types'; // TODO https://coveord.atlassian.net/browse/ADUI-9182
15
17
  import {TableLayouts} from './layouts/TableLayouts';
16
18
  import {TableActions} from './table-actions/TableActions';
17
19
  import {TableAccordionColumn, TableCollapsibleColumn} from './table-column/TableCollapsibleColumn';
20
+ import {TableColumnsSelector} from './table-columns-selector/TableColumnsSelector';
18
21
  import {TableConsumer} from './table-consumer/TableConsumer';
19
22
  import {TableDateRangePicker} from './table-date-range-picker/TableDateRangePicker';
20
23
  import {TableFilter} from './table-filter/TableFilter';
@@ -25,7 +28,6 @@ import {TableLoading} from './table-loading/TableLoading';
25
28
  import {TablePagination} from './table-pagination/TablePagination';
26
29
  import {TablePerPage} from './table-per-page/TablePerPage';
27
30
  import {TablePredicate} from './table-predicate/TablePredicate';
28
- import useStyles from './Table.styles';
29
31
 
30
32
  export type RowSelectionWithData<TData> = Record<string, TData>;
31
33
  export interface RowSelectionState<TData> {
@@ -84,6 +86,10 @@ export type TableFormType = {
84
86
  };
85
87
 
86
88
  export type TableContextType<TData> = {
89
+ /**
90
+ * Returns all flat columns in the table.
91
+ */
92
+ getAllColumns: () => Array<Column<TData, unknown>>;
87
93
  /**
88
94
  * Function to call when the table needs an update
89
95
  */
@@ -262,6 +268,7 @@ export interface TableProps<T> extends DefaultProps<TableStylesNames> {
262
268
 
263
269
  export interface TableType {
264
270
  <T>(props: TableProps<T>): ReactElement;
271
+ ColumnsSelector: typeof TableColumnsSelector;
265
272
  Actions: typeof TableActions;
266
273
  Filter: typeof TableFilter;
267
274
  Footer: typeof TableFooter;
@@ -0,0 +1,260 @@
1
+ import {Box} from '@mantine/core';
2
+ import {ColumnDef, createColumnHelper} from '@tanstack/table-core';
3
+ import {render, screen, userEvent} from '@test-utils';
4
+ import {Table} from '../Table';
5
+ import {TableColumnsSelector} from '../table-columns-selector/TableColumnsSelector';
6
+
7
+ const mockData = [
8
+ {
9
+ name: 'John Doe',
10
+ age: 30,
11
+ email: 'john.doe@example.com',
12
+ phone: '123-456-7890',
13
+ body: 'coucou',
14
+ },
15
+ {
16
+ name: 'Jane Doe',
17
+ age: 25,
18
+ email: 'jane.doe@example.com',
19
+ phone: '098-765-4321',
20
+ body: 'coucou 2',
21
+ },
22
+ ];
23
+
24
+ const columnNames: Record<string, string> = {
25
+ name: 'Name',
26
+ age: 'Age',
27
+ email: 'Email',
28
+ phone: 'Phone',
29
+ };
30
+
31
+ type RowData = {
32
+ name: string;
33
+ age: number;
34
+ email: string;
35
+ phone: string;
36
+ body: string;
37
+ };
38
+
39
+ const columnHelper = createColumnHelper<RowData>();
40
+ const columns: Array<ColumnDef<RowData>> = [
41
+ columnHelper.accessor('name', {enableSorting: false}),
42
+ columnHelper.accessor('age', {enableSorting: false}),
43
+ columnHelper.accessor('email', {enableSorting: false}),
44
+ columnHelper.accessor('phone', {enableSorting: false}),
45
+ Table.CollapsibleColumn as ColumnDef<RowData>,
46
+ ];
47
+
48
+ describe('TableColumnsSelector', () => {
49
+ it('render the edit button in the table header', () => {
50
+ render(
51
+ <Table data={mockData} columns={columns}>
52
+ <Table.Header>
53
+ <TableColumnsSelector columnNames={columnNames} />
54
+ </Table.Header>
55
+ </Table>,
56
+ );
57
+
58
+ expect(screen.getByRole('button', {name: 'Edit columns'})).toBeVisible();
59
+ expect(screen.queryByRole('button', {name: 'Edit columns (4)'})).not.toBeInTheDocument();
60
+ });
61
+
62
+ it('renders the custom label when defined', () => {
63
+ render(
64
+ <Table data={mockData} columns={columns}>
65
+ <Table.Header>
66
+ <TableColumnsSelector columnNames={columnNames} label="Custom label" />
67
+ </Table.Header>
68
+ </Table>,
69
+ );
70
+
71
+ expect(screen.getByRole('button', {name: 'Custom label'})).toBeVisible();
72
+ });
73
+
74
+ it('renders the count of visible columns if showVisibleCountLabel is true', () => {
75
+ render(
76
+ <Table data={mockData} columns={columns}>
77
+ <Table.Header>
78
+ <TableColumnsSelector columnNames={columnNames} showVisibleCountLabel />
79
+ </Table.Header>
80
+ </Table>,
81
+ );
82
+
83
+ expect(screen.getByRole('button', {name: 'Edit columns (4)'})).toBeVisible();
84
+ });
85
+
86
+ it('renders all columns in the dropdown, except the collapsible and the multiselectRow by default', async () => {
87
+ const user = userEvent.setup();
88
+ render(
89
+ <Table
90
+ data={mockData}
91
+ columns={columns}
92
+ multiRowSelectionEnabled
93
+ getExpandChildren={(datum) => <Box py="xs">{datum.body}</Box>}
94
+ >
95
+ <Table.Header>
96
+ <TableColumnsSelector columnNames={columnNames} />
97
+ </Table.Header>
98
+ </Table>,
99
+ );
100
+
101
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
102
+
103
+ // columns are rendered
104
+ expect(screen.getAllByRole('button', {name: /arrowheaddown/i})).toHaveLength(2);
105
+ expect(screen.getAllByRole('checkbox', {name: /select row/i})).toHaveLength(2);
106
+
107
+ expect(screen.getByRole('checkbox', {name: 'Name'})).toBeVisible();
108
+ expect(screen.getByRole('checkbox', {name: 'Age'})).toBeVisible();
109
+ expect(screen.getByRole('checkbox', {name: 'Email'})).toBeVisible();
110
+ expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeVisible();
111
+
112
+ // columns are not in the dropdown
113
+ expect(screen.queryByRole('checkbox', {name: /collapsible/i})).not.toBeInTheDocument();
114
+ expect(screen.queryByRole('checkbox', {name: 'select'})).not.toBeInTheDocument();
115
+ });
116
+
117
+ it('renders all checkboxes checked by default', async () => {
118
+ const user = userEvent.setup();
119
+ render(
120
+ <Table data={mockData} columns={columns}>
121
+ <Table.Header>
122
+ <TableColumnsSelector columnNames={columnNames} />
123
+ </Table.Header>
124
+ </Table>,
125
+ );
126
+
127
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
128
+
129
+ expect(screen.getByRole('checkbox', {name: 'Name'})).toBeChecked();
130
+ expect(screen.getByRole('checkbox', {name: 'Age'})).toBeChecked();
131
+ expect(screen.getByRole('checkbox', {name: 'Email'})).toBeChecked();
132
+ expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
133
+ });
134
+
135
+ it('does not render the checkboxes for the columns that are in the nonHideableColumns prop', async () => {
136
+ const user = userEvent.setup();
137
+ render(
138
+ <Table data={mockData} columns={columns}>
139
+ <Table.Header>
140
+ <TableColumnsSelector columnNames={columnNames} nonHideableColumns={['name']} />
141
+ </Table.Header>
142
+ </Table>,
143
+ );
144
+
145
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
146
+
147
+ expect(screen.queryByRole('checkbox', {name: 'Name'})).not.toBeInTheDocument();
148
+ expect(screen.getByRole('checkbox', {name: 'Age'})).toBeChecked();
149
+ expect(screen.getByRole('checkbox', {name: 'Email'})).toBeChecked();
150
+ expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
151
+ });
152
+
153
+ it('renders unchecked checkboxes for the columns that are not visible in the inital state of the table', async () => {
154
+ const user = userEvent.setup();
155
+ render(
156
+ <Table data={mockData} columns={columns} initialState={{columnVisibility: {email: false}}}>
157
+ <Table.Header>
158
+ <TableColumnsSelector columnNames={columnNames} />
159
+ </Table.Header>
160
+ </Table>,
161
+ );
162
+
163
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
164
+
165
+ expect(screen.getByRole('checkbox', {name: 'Name'})).toBeChecked();
166
+ expect(screen.getByRole('checkbox', {name: 'Age'})).toBeChecked();
167
+ expect(screen.getByRole('checkbox', {name: 'Email'})).not.toBeChecked();
168
+ expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
169
+ });
170
+
171
+ it('renders disabled checkboxes when the maxSelectableColumns is set and the maximum number of columns is checked', async () => {
172
+ const user = userEvent.setup();
173
+ render(
174
+ <Table data={mockData} columns={columns} initialState={{columnVisibility: {email: false}}}>
175
+ <Table.Header>
176
+ <TableColumnsSelector columnNames={columnNames} maxSelectableColumns={3} />
177
+ </Table.Header>
178
+ </Table>,
179
+ );
180
+
181
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
182
+
183
+ const nameCheckBox = screen.getByRole('checkbox', {name: /name/i});
184
+ const ageCheckBox = screen.getByRole('checkbox', {name: /age/i});
185
+ const emailCheckBox = screen.getByRole('checkbox', {name: /email/i});
186
+ const phoneCheckBox = screen.getByRole('checkbox', {name: /phone/i});
187
+
188
+ expect(nameCheckBox).toBeChecked();
189
+ expect(nameCheckBox).toBeEnabled();
190
+ expect(ageCheckBox).toBeChecked();
191
+ expect(ageCheckBox).toBeEnabled();
192
+ expect(emailCheckBox).not.toBeChecked();
193
+ expect(emailCheckBox).toBeDisabled();
194
+ expect(phoneCheckBox).toBeChecked();
195
+ expect(phoneCheckBox).toBeEnabled();
196
+
197
+ await user.click(nameCheckBox);
198
+
199
+ expect(nameCheckBox).toBeEnabled();
200
+ });
201
+
202
+ it('renders a tooltip when the maxSelectableColumns is set and the maximum number of columns is checked and the user hover a disabled checkbox', async () => {
203
+ const user = userEvent.setup();
204
+ render(
205
+ <Table data={mockData} columns={columns} initialState={{columnVisibility: {email: false}}}>
206
+ <Table.Header>
207
+ <TableColumnsSelector
208
+ columnNames={columnNames}
209
+ maxSelectableColumns={3}
210
+ limitReachedTooltip="You can display up to 3 columns"
211
+ />
212
+ </Table.Header>
213
+ </Table>,
214
+ );
215
+
216
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
217
+
218
+ const emailCheckBoxWrapper = screen.getByRole('checkbox', {name: /email/i}).parentElement;
219
+
220
+ await user.hover(emailCheckBoxWrapper);
221
+
222
+ expect(screen.getByText('You can display up to 3 columns')).toBeVisible();
223
+ });
224
+
225
+ describe('footer', () => {
226
+ it('does not render the footer when maxSelectableColumns is not defined', async () => {
227
+ const user = userEvent.setup();
228
+ render(
229
+ <Table data={mockData} columns={columns}>
230
+ <Table.Header>
231
+ <TableColumnsSelector columnNames={columnNames} />
232
+ </Table.Header>
233
+ </Table>,
234
+ );
235
+
236
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
237
+
238
+ expect(screen.queryByText('You can display up to 3 columns')).not.toBeInTheDocument();
239
+ });
240
+
241
+ it('renders the footer when maxSelectableColumns is defined and footer is defined', async () => {
242
+ const user = userEvent.setup();
243
+ render(
244
+ <Table data={mockData} columns={columns}>
245
+ <Table.Header>
246
+ <TableColumnsSelector
247
+ columnNames={columnNames}
248
+ maxSelectableColumns={3}
249
+ footer="You can display so many patate"
250
+ />
251
+ </Table.Header>
252
+ </Table>,
253
+ );
254
+
255
+ await user.click(screen.getByRole('button', {name: 'Edit columns'}));
256
+
257
+ expect(screen.getByText('You can display so many patate')).toBeVisible();
258
+ });
259
+ });
260
+ });
@@ -50,7 +50,7 @@ const RowLayoutBody = <T,>({
50
50
  cell.querySelector('button').click();
51
51
  };
52
52
 
53
- const rows = table.getRowModel().rows.map((row) => {
53
+ const rows = table.getRowModel()?.rows.map((row) => {
54
54
  const rowChildren = getExpandChildren?.(row.original) ?? null;
55
55
  const isSelected = !!row.getIsSelected();
56
56
  const shouldKeepSelection = keepSelection && isSelected;
@@ -0,0 +1,8 @@
1
+ import {createStyles} from '@mantine/core';
2
+
3
+ export default createStyles((theme) => ({
4
+ root: {maxWidth: '100%'},
5
+ wrapper: {
6
+ display: 'inline-flex',
7
+ },
8
+ }));
@@ -0,0 +1,78 @@
1
+ import {Button, Checkbox, Divider, Grid, Popover, ScrollArea, Stack, Tooltip} from '@mantine/core';
2
+ import {FunctionComponent} from 'react';
3
+
4
+ import {TableComponentsOrder} from '../Table.styles';
5
+ import {useTable} from '../TableContext';
6
+ import useStyles from './TableColumnsSelector.styles';
7
+ import {TableColumnsSelectorProps} from './TableColumnsSelector.types';
8
+
9
+ const COLUMNS_IDS_TO_EXCLUDE = ['collapsible', 'select'];
10
+
11
+ export const TableColumnsSelector: FunctionComponent<TableColumnsSelectorProps> = ({
12
+ classNames,
13
+ styles,
14
+ unstyled,
15
+ label = 'Edit columns',
16
+ buttonVariant = 'outline',
17
+ showVisibleCountLabel = false,
18
+ nonHideableColumns = [],
19
+ maxSelectableColumns,
20
+ footer,
21
+ limitReachedTooltip = 'You have reached the maximum display limit.',
22
+ columnNames,
23
+ }) => {
24
+ const {classes} = useStyles(null, {name: 'TableColumnsSelector', classNames, styles, unstyled});
25
+ const {getAllColumns} = useTable();
26
+
27
+ const columnsToExclude = [...nonHideableColumns, ...COLUMNS_IDS_TO_EXCLUDE];
28
+
29
+ const filteredColumns = getAllColumns().filter((column) => !columnsToExclude.includes(column.id));
30
+
31
+ const selectedColumnsCount = filteredColumns.filter((column) => column.getIsVisible()).length;
32
+
33
+ if (filteredColumns.length <= 0) {
34
+ return null;
35
+ }
36
+
37
+ return (
38
+ <Grid.Col span="content" order={TableComponentsOrder.ColumnsSelector} py="sm" className={classes.root}>
39
+ <Popover withinPortal position="bottom" shadow="md">
40
+ <Popover.Target>
41
+ <Button variant={buttonVariant}>{`${label}${
42
+ showVisibleCountLabel ? ` (${selectedColumnsCount})` : ''
43
+ }`}</Button>
44
+ </Popover.Target>
45
+ <Popover.Dropdown miw={240}>
46
+ <ScrollArea.Autosize mah={154}>
47
+ <Stack>
48
+ {filteredColumns.map((column) => {
49
+ const isDisabled =
50
+ selectedColumnsCount >= maxSelectableColumns && !column.getIsVisible();
51
+ return (
52
+ <Tooltip label={limitReachedTooltip} disabled={!isDisabled} position="left">
53
+ <div>
54
+ <Checkbox
55
+ key={column.id}
56
+ label={columnNames?.[column.id] || column.id}
57
+ name={column.id}
58
+ checked={column.getIsVisible()}
59
+ disabled={isDisabled}
60
+ onChange={column.getToggleVisibilityHandler()}
61
+ />
62
+ </div>
63
+ </Tooltip>
64
+ );
65
+ })}
66
+ </Stack>
67
+ </ScrollArea.Autosize>
68
+ {maxSelectableColumns && (
69
+ <>
70
+ <Divider mb="xs" mt="sm" />
71
+ {footer}
72
+ </>
73
+ )}
74
+ </Popover.Dropdown>
75
+ </Popover>
76
+ </Grid.Col>
77
+ );
78
+ };
@@ -0,0 +1,46 @@
1
+ import {DefaultProps, Selectors} from '@mantine/core';
2
+ import {ReactNode} from 'react';
3
+ import useStyles from './TableColumnsSelector.styles';
4
+
5
+ type TableColumnsSelectorStylesNames = Selectors<typeof useStyles>;
6
+
7
+ export interface TableColumnsSelectorProps extends DefaultProps<TableColumnsSelectorStylesNames> {
8
+ /**
9
+ * The label of the button
10
+ * @default 'Edit columns'
11
+ */
12
+ label?: ReactNode;
13
+ /**
14
+ * The style variant of the button
15
+ * @default 'outline'
16
+ */
17
+ buttonVariant?: string;
18
+ /**
19
+ * An array of column ids that the user cannot hide. This is useful for columns that are required for the table to function properly.
20
+ * @default []
21
+ */
22
+ nonHideableColumns?: string[];
23
+ /**
24
+ * Whether the count of visible columns is shown in the button label.
25
+ * @default false
26
+ */
27
+ showVisibleCountLabel?: boolean;
28
+ /**
29
+ * The maximum number of columns that can be selected at the same time.
30
+ * If defined a footer will render with the remaining number of columns that can be selected.
31
+ */
32
+ maxSelectableColumns?: number;
33
+ /**
34
+ * A dictionary of column ids and names to use for the checkbox labels.
35
+ */
36
+ columnNames: Record<string, string>;
37
+ /**
38
+ * The content to display in the footer when maxSelectableColumns is defined.
39
+ */
40
+ footer?: ReactNode;
41
+ /**
42
+ * The tooltip to display when the user hovers over a disabled checkbox.
43
+ * @default 'You have reached the maximum display limit.'
44
+ */
45
+ limitReachedTooltip?: string;
46
+ }