@coveord/plasma-mantine 56.8.0 → 56.9.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 (75) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/.turbo/turbo-test.log +108 -103
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/cjs/components/CodeEditor/languages/xml.d.ts.map +1 -1
  5. package/dist/cjs/components/CodeEditor/languages/xml.js.map +1 -1
  6. package/dist/cjs/components/Collection/enhanceWithCollectionProps.d.ts.map +1 -1
  7. package/dist/cjs/components/Collection/enhanceWithCollectionProps.js.map +1 -1
  8. package/dist/cjs/components/DateRangePicker/DateRange.module.css +4 -0
  9. package/dist/cjs/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
  10. package/dist/cjs/components/DateRangePicker/DateRangePicker.js +2 -1
  11. package/dist/cjs/components/DateRangePicker/DateRangePicker.js.map +1 -1
  12. package/dist/cjs/components/RadioCard/RadioCard.d.ts +26 -0
  13. package/dist/cjs/components/RadioCard/RadioCard.d.ts.map +1 -0
  14. package/dist/cjs/components/RadioCard/RadioCard.js +82 -0
  15. package/dist/cjs/components/RadioCard/RadioCard.js.map +1 -0
  16. package/dist/cjs/components/Table/Table.d.ts +2 -12
  17. package/dist/cjs/components/Table/Table.d.ts.map +1 -1
  18. package/dist/cjs/components/Table/Table.js +0 -3
  19. package/dist/cjs/components/Table/Table.js.map +1 -1
  20. package/dist/cjs/components/Table/table-column/TableActionsColumn.d.ts +15 -0
  21. package/dist/cjs/components/Table/table-column/TableActionsColumn.d.ts.map +1 -1
  22. package/dist/cjs/components/Table/table-column/TableActionsColumn.js +14 -1
  23. package/dist/cjs/components/Table/table-column/TableActionsColumn.js.map +1 -1
  24. package/dist/cjs/components/Table/table-columns-selector/TableColumnsSelector.d.ts +11 -32
  25. package/dist/cjs/components/Table/table-columns-selector/TableColumnsSelector.d.ts.map +1 -1
  26. package/dist/cjs/components/Table/table-columns-selector/TableColumnsSelector.js +101 -97
  27. package/dist/cjs/components/Table/table-columns-selector/TableColumnsSelector.js.map +1 -1
  28. package/dist/cjs/index.d.ts +2 -0
  29. package/dist/cjs/index.d.ts.map +1 -1
  30. package/dist/cjs/index.js +8 -0
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/styles/RadioCard.module.css +44 -0
  33. package/dist/esm/components/CodeEditor/languages/xml.d.ts.map +1 -1
  34. package/dist/esm/components/CodeEditor/languages/xml.js.map +1 -1
  35. package/dist/esm/components/Collection/enhanceWithCollectionProps.d.ts.map +1 -1
  36. package/dist/esm/components/Collection/enhanceWithCollectionProps.js.map +1 -1
  37. package/dist/esm/components/DateRangePicker/DateRange.module.css +4 -0
  38. package/dist/esm/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
  39. package/dist/esm/components/DateRangePicker/DateRangePicker.js +2 -1
  40. package/dist/esm/components/DateRangePicker/DateRangePicker.js.map +1 -1
  41. package/dist/esm/components/RadioCard/RadioCard.d.ts +26 -0
  42. package/dist/esm/components/RadioCard/RadioCard.d.ts.map +1 -0
  43. package/dist/esm/components/RadioCard/RadioCard.js +63 -0
  44. package/dist/esm/components/RadioCard/RadioCard.js.map +1 -0
  45. package/dist/esm/components/Table/Table.d.ts +2 -12
  46. package/dist/esm/components/Table/Table.d.ts.map +1 -1
  47. package/dist/esm/components/Table/Table.js +0 -3
  48. package/dist/esm/components/Table/Table.js.map +1 -1
  49. package/dist/esm/components/Table/table-column/TableActionsColumn.d.ts +15 -0
  50. package/dist/esm/components/Table/table-column/TableActionsColumn.d.ts.map +1 -1
  51. package/dist/esm/components/Table/table-column/TableActionsColumn.js +12 -1
  52. package/dist/esm/components/Table/table-column/TableActionsColumn.js.map +1 -1
  53. package/dist/esm/components/Table/table-columns-selector/TableColumnsSelector.d.ts +11 -32
  54. package/dist/esm/components/Table/table-columns-selector/TableColumnsSelector.d.ts.map +1 -1
  55. package/dist/esm/components/Table/table-columns-selector/TableColumnsSelector.js +94 -84
  56. package/dist/esm/components/Table/table-columns-selector/TableColumnsSelector.js.map +1 -1
  57. package/dist/esm/index.d.ts +2 -0
  58. package/dist/esm/index.d.ts.map +1 -1
  59. package/dist/esm/index.js +3 -0
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/styles/RadioCard.module.css +44 -0
  62. package/package.json +19 -19
  63. package/src/components/CodeEditor/languages/xml.ts +2 -1
  64. package/src/components/Collection/enhanceWithCollectionProps.ts +2 -2
  65. package/src/components/DateRangePicker/DateRange.module.css +4 -0
  66. package/src/components/DateRangePicker/DateRangePicker.tsx +2 -1
  67. package/src/components/RadioCard/RadioCard.tsx +73 -0
  68. package/src/components/RadioCard/__tests__/RadioCard.component.spec.tsx +25 -0
  69. package/src/components/Table/Table.tsx +4 -9
  70. package/src/components/Table/__tests__/TableColumnsSelectorHeader.spec.tsx +325 -0
  71. package/src/components/Table/table-column/TableActionsColumn.tsx +28 -1
  72. package/src/components/Table/table-columns-selector/TableColumnsSelector.tsx +96 -125
  73. package/src/index.ts +4 -0
  74. package/src/styles/RadioCard.module.css +44 -0
  75. package/src/components/Table/__tests__/TableColumnsSelector.spec.tsx +0 -352
@@ -1,50 +1,21 @@
1
- import {
2
- BoxProps,
3
- Button,
4
- Checkbox,
5
- CompoundStylesApiProps,
6
- Divider,
7
- factory,
8
- Factory,
9
- Grid,
10
- Popover,
11
- ScrollArea,
12
- Stack,
13
- Tooltip,
14
- useProps,
15
- } from '@mantine/core';
16
- import {flexRender, Header} from '@tanstack/react-table';
17
- import {ReactNode} from 'react';
18
- import {TableComponentsOrder} from '../Table.js';
19
- import {useTableContext} from '../TableContext.js';
1
+ import {IconSettings} from '@coveord/plasma-react-icons';
2
+ import {Checkbox, Combobox, Text, Tooltip, useCombobox} from '@mantine/core';
3
+ import {flexRender, Header, Table} from '@tanstack/react-table';
4
+ import {ActionIcon} from '../../ActionIcon/ActionIcon';
20
5
 
21
- export type TableColumnsSelectorStylesNames = 'columnSelector' | 'columnSelectorWrapper';
22
-
23
- export interface TableColumnsSelectorProps extends BoxProps, CompoundStylesApiProps<TableColumnsSelectorFactory> {
24
- /**
25
- * The label of the button
26
- * @default 'Edit columns'
27
- */
28
- label?: ReactNode;
29
- /**
30
- * The style variant of the button
31
- * @default 'outline'
32
- */
33
- buttonVariant?: string;
34
- /**
35
- * Whether the count of visible columns is shown in the button label.
36
- * @default false
37
- */
38
- showVisibleCountLabel?: boolean;
6
+ export interface TableColumnsSelectorOptions {
39
7
  /**
40
8
  * The maximum number of columns that can be selected at the same time.
41
9
  * If defined a footer will render with the remaining number of columns that can be selected.
10
+ * Must be a positive integer (greater than 0).
42
11
  */
43
12
  maxSelectableColumns?: number;
44
13
  /**
45
14
  * The content to display in the footer when maxSelectableColumns is defined.
15
+ * Can be a string or a function that receives the maxSelectableColumns value.
16
+ * @default (max) => `You can display up to ${max} columns.`
46
17
  */
47
- footer?: ReactNode;
18
+ footer?: string | ((maxSelectableColumns: number) => string);
48
19
  /**
49
20
  * The tooltip to display when the user hovers over a disabled checkbox because of the limit.
50
21
  * @default 'You have reached the maximum display limit.'
@@ -57,108 +28,108 @@ export interface TableColumnsSelectorProps extends BoxProps, CompoundStylesApiPr
57
28
  alwaysVisibleTooltip?: string;
58
29
  }
59
30
 
60
- export type TableColumnsSelectorFactory = Factory<{
61
- props: TableColumnsSelectorProps;
62
- ref: HTMLDivElement;
63
- stylesNames: TableColumnsSelectorStylesNames;
64
- compound: true;
65
- }>;
31
+ export interface TableColumnsSelectorHeaderProps {
32
+ table: Table<unknown>;
33
+ options?: TableColumnsSelectorOptions;
34
+ }
66
35
 
67
- const defaultProps: Partial<TableColumnsSelectorProps> = {
68
- label: 'Edit columns',
69
- buttonVariant: 'outline',
36
+ const DEFAULT_OPTIONS: Omit<TableColumnsSelectorOptions, 'footer'> & {
37
+ footer: (maxSelectableColumns: number) => string;
38
+ } = {
39
+ footer: (max) => `You can display up to ${max} columns.`,
70
40
  limitReachedTooltip: 'You have reached the maximum display limit.',
71
41
  alwaysVisibleTooltip: 'This column is always visible.',
72
- showVisibleCountLabel: false,
73
42
  };
74
43
 
75
- export const TableColumnsSelector = factory<TableColumnsSelectorFactory>((props, ref) => {
76
- const {getStyles} = useTableContext();
77
- const {
78
- label,
79
- buttonVariant,
80
- showVisibleCountLabel,
81
- maxSelectableColumns,
82
- footer,
83
- limitReachedTooltip,
84
- alwaysVisibleTooltip,
85
- classNames,
86
- className,
87
- styles,
88
- style,
89
- vars,
90
- ...others
91
- } = useProps('TableColumnsSelector', defaultProps, props);
92
- const {table} = useTableContext();
44
+ export const TableColumnsSelectorHeader = ({table, options}: TableColumnsSelectorHeaderProps) => {
45
+ const {maxSelectableColumns, footer, limitReachedTooltip, alwaysVisibleTooltip} = {
46
+ ...DEFAULT_OPTIONS,
47
+ ...options,
48
+ };
93
49
 
94
- const allColumns = table.getAllLeafColumns();
50
+ const combobox = useCombobox({
51
+ onDropdownClose: () => {
52
+ combobox.resetSelectedOption();
53
+ },
54
+ onDropdownOpen: () => combobox.updateSelectedOptionIndex('active'),
55
+ });
95
56
 
57
+ const allColumns = table.getAllLeafColumns();
96
58
  const filteredColumns = allColumns.filter((column) => !column.columnDef.meta?.controlColumn);
97
59
  const selectedColumnsCount = filteredColumns.filter((column) => column.getIsVisible()).length;
98
60
 
61
+ // Validate maxSelectableColumns - must be a positive integer to be effective
62
+ const effectiveMaxColumns =
63
+ maxSelectableColumns !== undefined && maxSelectableColumns > 0 ? maxSelectableColumns : undefined;
64
+
99
65
  if (filteredColumns.length <= 0) {
100
66
  return null;
101
67
  }
102
68
 
103
- const stylesApiProps = {classNames, styles};
69
+ const getColumnState = (column: (typeof filteredColumns)[number]) => {
70
+ const alwaysVisible = !column.getCanHide();
71
+ const isDisabled =
72
+ (effectiveMaxColumns !== undefined &&
73
+ selectedColumnsCount >= effectiveMaxColumns &&
74
+ !column.getIsVisible()) ||
75
+ alwaysVisible;
76
+ const isVisible = column.getIsVisible() || alwaysVisible;
77
+ return {alwaysVisible, isDisabled, isVisible};
78
+ };
104
79
 
105
- return (
106
- <Grid.Col
107
- span="content"
108
- order={TableComponentsOrder.ColumnsSelector}
109
- {...getStyles('columnSelector', {className, style, ...stylesApiProps})}
110
- {...others}
111
- >
112
- <Popover withinPortal position="bottom" shadow="md">
113
- <Popover.Target>
114
- <Button variant={buttonVariant}>
115
- {label}
116
- {showVisibleCountLabel ? ` (${selectedColumnsCount})` : ''}
117
- </Button>
118
- </Popover.Target>
119
- <Popover.Dropdown miw={240}>
120
- <ScrollArea.Autosize mah={154}>
121
- <Stack {...getStyles('columnSelectorWrapper', stylesApiProps)}>
122
- {filteredColumns.map((column) => {
123
- const alwaysVisible = !column.getCanHide();
124
- const isDisabled =
125
- (selectedColumnsCount >= maxSelectableColumns && !column.getIsVisible()) ||
126
- alwaysVisible;
80
+ const handleOptionClick = (columnId: string) => {
81
+ const column = filteredColumns.find((col) => col.id === columnId);
82
+ if (column) {
83
+ const {isDisabled} = getColumnState(column);
84
+ if (!isDisabled) {
85
+ column.toggleVisibility();
86
+ }
87
+ }
88
+ };
127
89
 
128
- return (
129
- <Tooltip
130
- label={alwaysVisible ? alwaysVisibleTooltip : limitReachedTooltip}
131
- disabled={!isDisabled}
132
- position="left"
133
- key={column.id}
134
- >
135
- <div>
136
- <Checkbox
137
- key={column.id}
138
- label={flexRender(column.columnDef.header, {
139
- table,
140
- column,
141
- header: {column} as Header<unknown, unknown>,
142
- })}
143
- name={column.id}
144
- checked={column.getIsVisible() || alwaysVisible}
145
- disabled={isDisabled}
146
- onChange={column.getToggleVisibilityHandler()}
147
- />
148
- </div>
149
- </Tooltip>
150
- );
90
+ const columnOptions = filteredColumns.map((column) => {
91
+ const {alwaysVisible, isDisabled, isVisible} = getColumnState(column);
92
+
93
+ return (
94
+ <Combobox.Option value={column.id} key={column.id} disabled={isDisabled} active={isVisible}>
95
+ <Tooltip
96
+ label={alwaysVisible ? alwaysVisibleTooltip : limitReachedTooltip}
97
+ disabled={!isDisabled}
98
+ position="left"
99
+ >
100
+ <div>
101
+ <Checkbox
102
+ checked={isVisible}
103
+ label={flexRender(column.columnDef.header, {
104
+ table,
105
+ column,
106
+ header: {column} as Header<unknown, unknown>,
151
107
  })}
152
- </Stack>
153
- </ScrollArea.Autosize>
154
- {maxSelectableColumns && (
155
- <>
156
- <Divider mb="xs" mt="sm" />
157
- {footer}
158
- </>
159
- )}
160
- </Popover.Dropdown>
161
- </Popover>
162
- </Grid.Col>
108
+ disabled={isDisabled}
109
+ />
110
+ </div>
111
+ </Tooltip>
112
+ </Combobox.Option>
113
+ );
114
+ });
115
+
116
+ return (
117
+ <Combobox store={combobox} position="bottom-end" shadow="md" onOptionSubmit={handleOptionClick}>
118
+ <Combobox.Target>
119
+ <ActionIcon.Tertiary onClick={() => combobox.toggleDropdown()} aria-label="settings">
120
+ <IconSettings height={16} />
121
+ </ActionIcon.Tertiary>
122
+ </Combobox.Target>
123
+ <Combobox.Dropdown miw={270}>
124
+ <Combobox.Options>{columnOptions}</Combobox.Options>
125
+ {effectiveMaxColumns && (
126
+ <Combobox.Footer>
127
+ <Text size="sm" c="dimmed">
128
+ {typeof footer === 'function' ? footer(effectiveMaxColumns) : footer}
129
+ </Text>
130
+ </Combobox.Footer>
131
+ )}
132
+ </Combobox.Dropdown>
133
+ </Combobox>
163
134
  );
164
- });
135
+ };
package/src/index.ts CHANGED
@@ -106,6 +106,9 @@ export * from './components/Modal/ModalFooter.js';
106
106
  // Prompt
107
107
  export * from './components/Prompt/Prompt.js';
108
108
 
109
+ // RadioCard - override Mantine RadioCard
110
+ export {RadioCard, type RadioCardProps} from './components/RadioCard/RadioCard.js';
111
+
109
112
  // Read Only - override Mantine PasswordInput and Select
110
113
  export {PasswordInput} from './components/PasswordInput/PasswordInput.js';
111
114
  export {Select} from './components/Select/Select.js';
@@ -115,6 +118,7 @@ export * from './components/StickyFooter/StickyFooter.js';
115
118
 
116
119
  // Table - override Mantine Table
117
120
  export {flexRender as renderTableCell} from '@tanstack/react-table';
121
+ export {TableActionsColumn} from './components/Table/table-column/TableActionsColumn.js';
118
122
  export {type TablePredicateProps} from './components/Table/table-predicate/TablePredicate.js';
119
123
  export {Table, TableComponentsOrder, type PlasmaTableFactory} from './components/Table/Table.js';
120
124
  export {
@@ -5,7 +5,51 @@
5
5
  }
6
6
 
7
7
  .card {
8
+ display: inline-flex;
9
+ flex-direction: column;
10
+ align-items: flex-start;
11
+ padding: var(--mantine-spacing-sm);
12
+ border-radius: var(--mantine-radius-lg);
13
+
14
+ &[data-checked] {
15
+ border-color: var(--mantine-primary-color-filled);
16
+ }
17
+
8
18
  &[disabled] {
9
19
  pointer-events: none;
20
+
21
+ .title {
22
+ color: var(--mantine-color-disabled-color);
23
+ }
24
+
25
+ .description {
26
+ color: var(--mantine-color-disabled-color);
27
+ }
10
28
  }
11
29
  }
30
+
31
+ .container {
32
+ flex-wrap: nowrap;
33
+ gap: var(--mantine-spacing-sm);
34
+ align-items: baseline;
35
+ justify-content: flex-start;
36
+ width: 100%;
37
+ margin-bottom: var(--mantine-spacing-xs);
38
+ }
39
+
40
+ .title {
41
+ flex: 1;
42
+ color: var(--coveo-color-title);
43
+ word-break: break-word;
44
+ }
45
+
46
+ .description {
47
+ padding-left: var(--mantine-spacing-lg);
48
+ color: var(--mantine-color-dimmed);
49
+ font-weight: 400;
50
+ font-size: var(--mantine-font-size-xs);
51
+ }
52
+
53
+ .indicator {
54
+ cursor: pointer;
55
+ }
@@ -1,352 +0,0 @@
1
- import {Box} from '@mantine/core';
2
- import {ColumnDef, createColumnHelper} from '@tanstack/table-core';
3
- import {render, screen, userEvent, waitFor, within} from '@test-utils';
4
- import {Table} from '../Table.js';
5
- import {TableColumnsSelector} from '../table-columns-selector/TableColumnsSelector.js';
6
- import {useTable} from '../use-table.js';
7
-
8
- const mockData = [
9
- {
10
- name: 'John Doe',
11
- age: 30,
12
- email: 'john.doe@example.com',
13
- phone: '123-456-7890',
14
- body: 'coucou',
15
- },
16
- {
17
- name: 'Jane Doe',
18
- age: 25,
19
- email: 'jane.doe@example.com',
20
- phone: '098-765-4321',
21
- body: 'coucou 2',
22
- },
23
- ];
24
-
25
- type RowData = {
26
- name: string;
27
- age: number;
28
- email: string;
29
- phone: string;
30
- body: string;
31
- };
32
-
33
- const columnHelper = createColumnHelper<RowData>();
34
- const baseColumns: Array<ColumnDef<RowData>> = [
35
- columnHelper.accessor('name', {header: 'Name', enableSorting: false}),
36
- columnHelper.accessor('age', {header: 'Age', enableSorting: false}),
37
- columnHelper.accessor('email', {header: 'Email', enableSorting: false}),
38
- columnHelper.accessor('phone', {header: 'Phone', enableSorting: false}),
39
- Table.CollapsibleColumn as ColumnDef<RowData>,
40
- ];
41
-
42
- describe('TableColumnsSelector', () => {
43
- it('render the edit button in the table header', () => {
44
- const Fixture = () => {
45
- const store = useTable<RowData>();
46
- return (
47
- <Table store={store} data={mockData} columns={baseColumns}>
48
- <Table.Header>
49
- <TableColumnsSelector />
50
- </Table.Header>
51
- </Table>
52
- );
53
- };
54
- render(<Fixture />);
55
-
56
- expect(screen.getByRole('button', {name: 'Edit columns'})).toBeVisible();
57
- expect(screen.queryByRole('button', {name: 'Edit columns (4)'})).not.toBeInTheDocument();
58
- });
59
-
60
- it('renders the custom label when defined', () => {
61
- const Fixture = () => {
62
- const store = useTable<RowData>();
63
- return (
64
- <Table store={store} data={mockData} columns={baseColumns}>
65
- <Table.Header>
66
- <TableColumnsSelector label="Custom label" />
67
- </Table.Header>
68
- </Table>
69
- );
70
- };
71
- render(<Fixture />);
72
-
73
- expect(screen.getByRole('button', {name: 'Custom label'})).toBeVisible();
74
- });
75
-
76
- it('renders the count of visible columns if showVisibleCountLabel is true', () => {
77
- const Fixture = () => {
78
- const store = useTable<RowData>();
79
- return (
80
- <Table store={store} data={mockData} columns={baseColumns}>
81
- <Table.Header>
82
- <TableColumnsSelector showVisibleCountLabel />
83
- </Table.Header>
84
- </Table>
85
- );
86
- };
87
- render(<Fixture />);
88
-
89
- expect(screen.getByRole('button', {name: 'Edit columns (4)'})).toBeVisible();
90
- });
91
-
92
- it('renders all columns in the dropdown, except the collapsible and the multiselectRow by default', async () => {
93
- const user = userEvent.setup();
94
- const Fixture = () => {
95
- const store = useTable<RowData>({enableMultiRowSelection: true});
96
- return (
97
- <Table
98
- store={store}
99
- data={mockData}
100
- columns={baseColumns}
101
- getRowExpandedContent={(datum) => <Box py="xs">{datum.body}</Box>}
102
- >
103
- <Table.Header>
104
- <TableColumnsSelector />
105
- </Table.Header>
106
- </Table>
107
- );
108
- };
109
- render(<Fixture />);
110
-
111
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
112
- const dropdown = await screen.findByRole('dialog', {name: 'Edit columns'});
113
- const columnsCheckboxes = within(dropdown).getAllByRole('checkbox');
114
-
115
- expect(columnsCheckboxes).toHaveLength(4);
116
- expect(columnsCheckboxes[0]).toHaveAccessibleName('Name');
117
- expect(columnsCheckboxes[1]).toHaveAccessibleName('Age');
118
- expect(columnsCheckboxes[2]).toHaveAccessibleName('Email');
119
- expect(columnsCheckboxes[3]).toHaveAccessibleName('Phone');
120
- });
121
-
122
- it('renders all checkboxes checked by default', async () => {
123
- const user = userEvent.setup();
124
- const Fixture = () => {
125
- const store = useTable<RowData>();
126
- return (
127
- <Table store={store} data={mockData} columns={baseColumns}>
128
- <Table.Header>
129
- <TableColumnsSelector />
130
- </Table.Header>
131
- </Table>
132
- );
133
- };
134
- render(<Fixture />);
135
-
136
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
137
-
138
- expect(await screen.findByRole('checkbox', {name: 'Name'})).toBeChecked();
139
- expect(screen.getByRole('checkbox', {name: 'Age'})).toBeChecked();
140
- expect(screen.getByRole('checkbox', {name: 'Email'})).toBeChecked();
141
- expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
142
- });
143
-
144
- it('renders a disabled checked checkbox for columns that are always visible', async () => {
145
- const columns: Array<ColumnDef<RowData>> = [
146
- columnHelper.accessor('name', {header: 'Name', enableSorting: false}),
147
- columnHelper.accessor('age', {header: 'Age', enableSorting: false, enableHiding: false}),
148
- columnHelper.accessor('email', {header: 'Email', enableSorting: false}),
149
- columnHelper.accessor('phone', {header: 'Phone', enableSorting: false}),
150
- ];
151
- const user = userEvent.setup();
152
- const Fixture = () => {
153
- const store = useTable<RowData>();
154
- return (
155
- <Table store={store} data={mockData} columns={columns}>
156
- <Table.Header>
157
- <TableColumnsSelector />
158
- </Table.Header>
159
- </Table>
160
- );
161
- };
162
- render(<Fixture />);
163
-
164
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
165
-
166
- expect(await screen.findByRole('checkbox', {name: 'Name'})).toBeChecked();
167
- expect(screen.getByRole('checkbox', {name: 'Email'})).toBeChecked();
168
- expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
169
-
170
- const ageColumn = screen.getByRole('checkbox', {name: 'Age'});
171
- expect(ageColumn).toBeChecked();
172
- expect(ageColumn).toBeDisabled();
173
- await user.hover(ageColumn.parentElement);
174
- await waitFor(() => {
175
- expect(screen.getByRole('tooltip', {name: 'This column is always visible.'})).toBeVisible();
176
- });
177
- });
178
-
179
- it('renders unchecked checkboxes for the columns that are not visible in the inital state of the table', async () => {
180
- const user = userEvent.setup();
181
- const Fixture = () => {
182
- const store = useTable<RowData>({initialState: {columnVisibility: {email: false}}});
183
- return (
184
- <Table store={store} data={mockData} columns={baseColumns}>
185
- <Table.Header>
186
- <TableColumnsSelector />
187
- </Table.Header>
188
- </Table>
189
- );
190
- };
191
- render(<Fixture />);
192
-
193
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
194
-
195
- expect(await screen.findByRole('checkbox', {name: 'Name'})).toBeChecked();
196
- expect(screen.getByRole('checkbox', {name: 'Age'})).toBeChecked();
197
- expect(screen.getByRole('checkbox', {name: 'Email'})).not.toBeChecked();
198
- expect(screen.getByRole('checkbox', {name: 'Phone'})).toBeChecked();
199
- });
200
-
201
- it('renders disabled checkboxes when the maxSelectableColumns is set and the maximum number of columns is checked', async () => {
202
- const user = userEvent.setup();
203
- const Fixture = () => {
204
- const store = useTable<RowData>({initialState: {columnVisibility: {email: false}}});
205
- return (
206
- <Table store={store} data={mockData} columns={baseColumns}>
207
- <Table.Header>
208
- <TableColumnsSelector maxSelectableColumns={3} />
209
- </Table.Header>
210
- </Table>
211
- );
212
- };
213
- render(<Fixture />);
214
-
215
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
216
-
217
- const nameCheckBox = await screen.findByRole('checkbox', {name: /name/i});
218
- const ageCheckBox = screen.getByRole('checkbox', {name: /age/i});
219
- const emailCheckBox = screen.getByRole('checkbox', {name: /email/i});
220
- const phoneCheckBox = screen.getByRole('checkbox', {name: /phone/i});
221
-
222
- expect(nameCheckBox).toBeChecked();
223
- expect(nameCheckBox).toBeEnabled();
224
- expect(ageCheckBox).toBeChecked();
225
- expect(ageCheckBox).toBeEnabled();
226
- expect(emailCheckBox).not.toBeChecked();
227
- expect(emailCheckBox).toBeDisabled();
228
- expect(phoneCheckBox).toBeChecked();
229
- expect(phoneCheckBox).toBeEnabled();
230
-
231
- await user.click(nameCheckBox);
232
-
233
- expect(nameCheckBox).toBeEnabled();
234
- });
235
-
236
- 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 () => {
237
- const user = userEvent.setup();
238
- const Fixture = () => {
239
- const store = useTable<RowData>({initialState: {columnVisibility: {email: false}}});
240
- return (
241
- <Table store={store} data={mockData} columns={baseColumns}>
242
- <Table.Header>
243
- <TableColumnsSelector
244
- maxSelectableColumns={3}
245
- limitReachedTooltip="You can display up to 3 columns"
246
- />
247
- </Table.Header>
248
- </Table>
249
- );
250
- };
251
- render(<Fixture />);
252
-
253
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
254
-
255
- const emailCheckBoxWrapper = (await screen.findByRole('checkbox', {name: /email/i})).parentElement;
256
-
257
- await user.hover(emailCheckBoxWrapper);
258
-
259
- await waitFor(() => expect(screen.getByText('You can display up to 3 columns')).toBeVisible());
260
- });
261
-
262
- describe('footer', () => {
263
- it('does not render the footer when maxSelectableColumns is not defined', async () => {
264
- const user = userEvent.setup();
265
- const Fixture = () => {
266
- const store = useTable<RowData>();
267
- return (
268
- <Table store={store} data={mockData} columns={baseColumns}>
269
- <Table.Header>
270
- <TableColumnsSelector />
271
- </Table.Header>
272
- </Table>
273
- );
274
- };
275
- render(<Fixture />);
276
-
277
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
278
-
279
- expect(screen.queryByText('You can display up to 3 columns')).not.toBeInTheDocument();
280
- });
281
-
282
- it('renders the footer when maxSelectableColumns is defined and footer is defined', async () => {
283
- const user = userEvent.setup();
284
- const Fixture = () => {
285
- const store = useTable<RowData>();
286
- return (
287
- <Table store={store} data={mockData} columns={baseColumns}>
288
- <Table.Header>
289
- <TableColumnsSelector maxSelectableColumns={3} footer="You can display so many patate" />
290
- </Table.Header>
291
- </Table>
292
- );
293
- };
294
- render(<Fixture />);
295
-
296
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
297
-
298
- await waitFor(() => expect(screen.getByText('You can display so many patate')).toBeVisible());
299
- });
300
- });
301
-
302
- describe('when url sync is activated', () => {
303
- afterEach(() => {
304
- window.history.replaceState(null, '', '/');
305
- });
306
-
307
- it('sets the current visible column ids in the url', async () => {
308
- const user = userEvent.setup();
309
- const Fixture = () => {
310
- const store = useTable<RowData>({
311
- syncWithUrl: true,
312
- initialState: {columnVisibility: {email: false, phone: true}},
313
- });
314
- return (
315
- <Table store={store} data={mockData} columns={baseColumns}>
316
- <Table.Header>
317
- <TableColumnsSelector />
318
- </Table.Header>
319
- </Table>
320
- );
321
- };
322
- render(<Fixture />);
323
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
324
- const emailCheckBox = await screen.findByRole('checkbox', {name: /email/i});
325
- await user.click(emailCheckBox);
326
- await user.click(screen.getByRole('checkbox', {name: /phone/i}));
327
- expect(window.location.search).toBe('?show=email&hide=phone');
328
- });
329
-
330
- it('determines the initial visible columns from the url', async () => {
331
- window.history.replaceState(null, '', '?show=email%2Cphone');
332
- const user = userEvent.setup();
333
- const Fixture = () => {
334
- const store = useTable<RowData>({
335
- syncWithUrl: true,
336
- initialState: {columnVisibility: {email: false, phone: false}},
337
- });
338
- return (
339
- <Table store={store} data={mockData} columns={baseColumns}>
340
- <Table.Header>
341
- <TableColumnsSelector />
342
- </Table.Header>
343
- </Table>
344
- );
345
- };
346
- render(<Fixture />);
347
- await user.click(screen.getByRole('button', {name: 'Edit columns'}));
348
- expect(await screen.findByRole('checkbox', {name: /email/i})).toBeChecked();
349
- expect(screen.getByRole('checkbox', {name: /phone/i})).toBeChecked();
350
- });
351
- });
352
- });