@coveord/plasma-mantine 52.9.0 → 52.10.1

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 (112) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/.turbo/turbo-test.log +33 -32
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/cjs/components/code-editor/CodeEditor.d.ts.map +1 -1
  5. package/dist/cjs/components/code-editor/CodeEditor.js +8 -3
  6. package/dist/cjs/components/code-editor/CodeEditor.js.map +1 -1
  7. package/dist/cjs/components/collection/Collection.js +5 -3
  8. package/dist/cjs/components/collection/Collection.js.map +1 -1
  9. package/dist/cjs/components/date-range-picker/DateRangePickerPresetSelect.d.ts.map +1 -1
  10. package/dist/cjs/components/date-range-picker/DateRangePickerPresetSelect.js +2 -1
  11. package/dist/cjs/components/date-range-picker/DateRangePickerPresetSelect.js.map +1 -1
  12. package/dist/cjs/components/date-range-picker/EditableDateRangePicker.js +2 -2
  13. package/dist/cjs/components/date-range-picker/EditableDateRangePicker.js.map +1 -1
  14. package/dist/cjs/components/modal-wizard/ModalWizard.js +2 -2
  15. package/dist/cjs/components/modal-wizard/ModalWizard.js.map +1 -1
  16. package/dist/cjs/components/table/Table.d.ts.map +1 -1
  17. package/dist/cjs/components/table/Table.js +25 -13
  18. package/dist/cjs/components/table/Table.js.map +1 -1
  19. package/dist/cjs/components/table/Table.styles.d.ts.map +1 -1
  20. package/dist/cjs/components/table/Table.styles.js +1 -10
  21. package/dist/cjs/components/table/Table.styles.js.map +1 -1
  22. package/dist/cjs/components/table/Table.types.d.ts +14 -3
  23. package/dist/cjs/components/table/Table.types.d.ts.map +1 -1
  24. package/dist/cjs/components/table/TableFooter.js +2 -2
  25. package/dist/cjs/components/table/TableFooter.js.map +1 -1
  26. package/dist/cjs/components/table/TableHeader.js +1 -1
  27. package/dist/cjs/components/table/TableHeader.js.map +1 -1
  28. package/dist/cjs/components/table/TableLastUpdated.d.ts +24 -0
  29. package/dist/cjs/components/table/TableLastUpdated.d.ts.map +1 -0
  30. package/dist/cjs/components/table/TableLastUpdated.js +73 -0
  31. package/dist/cjs/components/table/TableLastUpdated.js.map +1 -0
  32. package/dist/cjs/components/table/TablePagination.d.ts.map +1 -1
  33. package/dist/cjs/components/table/TablePagination.js +1 -0
  34. package/dist/cjs/components/table/TablePagination.js.map +1 -1
  35. package/dist/cjs/components/table/TablePerPage.js +5 -3
  36. package/dist/cjs/components/table/TablePerPage.js.map +1 -1
  37. package/dist/cjs/components/table/layouts/RowLayout.d.ts.map +1 -1
  38. package/dist/cjs/components/table/layouts/RowLayout.js +41 -9
  39. package/dist/cjs/components/table/layouts/RowLayout.js.map +1 -1
  40. package/dist/cjs/components/table/useRowSelection.d.ts +2 -2
  41. package/dist/cjs/components/table/useRowSelection.d.ts.map +1 -1
  42. package/dist/cjs/components/table/useRowSelection.js +8 -3
  43. package/dist/cjs/components/table/useRowSelection.js.map +1 -1
  44. package/dist/cjs/theme/Theme.js +1 -1
  45. package/dist/cjs/theme/Theme.js.map +1 -1
  46. package/dist/esm/components/code-editor/CodeEditor.d.ts.map +1 -1
  47. package/dist/esm/components/code-editor/CodeEditor.js +8 -3
  48. package/dist/esm/components/code-editor/CodeEditor.js.map +1 -1
  49. package/dist/esm/components/collection/Collection.js +5 -3
  50. package/dist/esm/components/collection/Collection.js.map +1 -1
  51. package/dist/esm/components/date-range-picker/DateRangePickerPresetSelect.d.ts.map +1 -1
  52. package/dist/esm/components/date-range-picker/DateRangePickerPresetSelect.js +2 -1
  53. package/dist/esm/components/date-range-picker/DateRangePickerPresetSelect.js.map +1 -1
  54. package/dist/esm/components/date-range-picker/EditableDateRangePicker.js +2 -2
  55. package/dist/esm/components/date-range-picker/EditableDateRangePicker.js.map +1 -1
  56. package/dist/esm/components/modal-wizard/ModalWizard.js +2 -2
  57. package/dist/esm/components/modal-wizard/ModalWizard.js.map +1 -1
  58. package/dist/esm/components/table/Table.d.ts.map +1 -1
  59. package/dist/esm/components/table/Table.js +27 -15
  60. package/dist/esm/components/table/Table.js.map +1 -1
  61. package/dist/esm/components/table/Table.styles.d.ts.map +1 -1
  62. package/dist/esm/components/table/Table.styles.js +1 -10
  63. package/dist/esm/components/table/Table.styles.js.map +1 -1
  64. package/dist/esm/components/table/Table.types.d.ts +14 -3
  65. package/dist/esm/components/table/Table.types.d.ts.map +1 -1
  66. package/dist/esm/components/table/Table.types.js.map +1 -1
  67. package/dist/esm/components/table/TableFooter.js +2 -2
  68. package/dist/esm/components/table/TableFooter.js.map +1 -1
  69. package/dist/esm/components/table/TableHeader.js +1 -1
  70. package/dist/esm/components/table/TableHeader.js.map +1 -1
  71. package/dist/esm/components/table/TableLastUpdated.d.ts +24 -0
  72. package/dist/esm/components/table/TableLastUpdated.d.ts.map +1 -0
  73. package/dist/esm/components/table/TableLastUpdated.js +62 -0
  74. package/dist/esm/components/table/TableLastUpdated.js.map +1 -0
  75. package/dist/esm/components/table/TablePagination.d.ts.map +1 -1
  76. package/dist/esm/components/table/TablePagination.js +1 -0
  77. package/dist/esm/components/table/TablePagination.js.map +1 -1
  78. package/dist/esm/components/table/TablePerPage.js +5 -3
  79. package/dist/esm/components/table/TablePerPage.js.map +1 -1
  80. package/dist/esm/components/table/layouts/RowLayout.d.ts.map +1 -1
  81. package/dist/esm/components/table/layouts/RowLayout.js +42 -10
  82. package/dist/esm/components/table/layouts/RowLayout.js.map +1 -1
  83. package/dist/esm/components/table/useRowSelection.d.ts +2 -2
  84. package/dist/esm/components/table/useRowSelection.d.ts.map +1 -1
  85. package/dist/esm/components/table/useRowSelection.js +8 -3
  86. package/dist/esm/components/table/useRowSelection.js.map +1 -1
  87. package/dist/esm/theme/Theme.js +1 -1
  88. package/dist/esm/theme/Theme.js.map +1 -1
  89. package/package.json +17 -17
  90. package/src/__tests__/VitestSetup.ts +12 -0
  91. package/src/components/code-editor/CodeEditor.tsx +5 -3
  92. package/src/components/code-editor/__tests__/CodeEditor.spec.tsx +1 -0
  93. package/src/components/date-range-picker/DateRangePickerPresetSelect.tsx +1 -0
  94. package/src/components/date-range-picker/__tests__/DateRangePickerInlineCalendar.spec.tsx +2 -0
  95. package/src/components/date-range-picker/__tests__/DateRangePickerPopoverCalendar.spec.tsx +4 -19
  96. package/src/components/date-range-picker/__tests__/EditableDateRangePicker.spec.tsx +3 -3
  97. package/src/components/modal-wizard/__tests__/ModalWizard.spec.tsx +19 -4
  98. package/src/components/table/Table.styles.ts +0 -9
  99. package/src/components/table/Table.tsx +22 -13
  100. package/src/components/table/Table.types.ts +14 -3
  101. package/src/components/table/TableFooter.tsx +1 -1
  102. package/src/components/table/TableHeader.tsx +1 -1
  103. package/src/components/table/TableLastUpdated.tsx +51 -0
  104. package/src/components/table/TablePagination.tsx +1 -0
  105. package/src/components/table/TablePerPage.tsx +3 -3
  106. package/src/components/table/__tests__/Table.spec.tsx +44 -5
  107. package/src/components/table/__tests__/TableActions.spec.tsx +4 -3
  108. package/src/components/table/__tests__/TableDateRangePicker.spec.tsx +26 -59
  109. package/src/components/table/__tests__/TableLastUpdated.spec.tsx +97 -0
  110. package/src/components/table/__tests__/TablePredicate.spec.tsx +7 -55
  111. package/src/components/table/layouts/RowLayout.tsx +45 -11
  112. package/src/components/table/useRowSelection.ts +13 -6
@@ -1,6 +1,5 @@
1
1
  import {ColumnDef, createColumnHelper} from '@tanstack/table-core';
2
- import {render, screen, userEvent, waitFor} from '@test-utils';
3
- import {act} from 'react-dom/test-utils';
2
+ import {render, screen, userEvent, waitFor, within} from '@test-utils';
4
3
 
5
4
  import {Table} from '../Table';
6
5
 
@@ -20,62 +19,32 @@ const basicTableWithDateRangePicker = (
20
19
  </Table>
21
20
  );
22
21
 
23
- // Since we're mocking the date and the animations are timer based we're mocking useReduceMotion to disable all the animations
24
- // I tried wrapping the components in <MantineProvider theme={{components: {Transition: {defaultProps: {duration: 0}}}}}>
25
- // but the animation was still happening. :(
26
- vi.mock('@mantine/hooks', async () => {
27
- const actual = await vi.importActual('@mantine/hooks');
28
- return {
29
- ...actual,
30
- useReduceMotion: () => true,
31
- };
32
- });
33
-
34
22
  describe('Table.DateRangePicker', () => {
35
- beforeEach(() => {
36
- vi.useFakeTimers().setSystemTime(new Date(2022, 0, 15));
37
- });
38
-
39
- afterEach(() => {
40
- vi.useRealTimers();
41
- });
42
-
43
23
  it('displays the initial dates', async () => {
44
24
  render(basicTableWithDateRangePicker);
45
25
 
46
- await waitFor(() => {
47
- expect(screen.getByText('Jan 01, 2022 - Jan 07, 2022')).toBeVisible();
48
- });
26
+ expect(screen.getByText('Jan 01, 2022 - Jan 07, 2022')).toBeVisible();
49
27
  });
50
28
 
51
29
  it('opens the dialog when clicking on the calendar button', async () => {
52
- // Otherwise, css transition is not triggered in Mantine component
53
- vi.useRealTimers();
54
- const user = userEvent.setup({delay: null});
30
+ const user = userEvent.setup();
55
31
  render(basicTableWithDateRangePicker);
56
32
 
57
- await screen.findByRole('button', {name: 'calendar'});
58
- await act(async () => {
59
- await user.click(screen.getByRole('button', {name: 'calendar'}));
60
- });
61
- expect(screen.queryByRole('dialog')).toBeVisible();
33
+ await user.click(screen.getByRole('button', {name: 'calendar'}));
34
+ expect(screen.getByRole('dialog', {name: 'calendar'})).toBeVisible();
62
35
  });
63
36
 
64
37
  it('closes the dialog when clicking back on the calendar button', async () => {
65
- // Otherwise, css transition is not triggered in Mantine component
66
- vi.useRealTimers();
67
- const user = userEvent.setup({delay: null});
38
+ const user = userEvent.setup();
68
39
  render(basicTableWithDateRangePicker);
69
40
 
70
- await screen.findByRole('button', {name: 'calendar'});
71
- await act(async () => {
72
- await user.click(screen.getByRole('button', {name: 'calendar'}));
73
- await user.click(screen.getByRole('button', {name: 'calendar'}));
74
- });
75
- expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
76
- });
41
+ await user.click(screen.getByRole('button', {name: 'calendar'}));
42
+ await user.click(screen.getByRole('button', {name: 'calendar'}));
43
+ expect(screen.queryByRole('dialog', {name: 'calendar'})).not.toBeInTheDocument();
44
+ }, 10000);
77
45
 
78
46
  it('displays the selected date range in the table', async () => {
47
+ vi.useFakeTimers().setSystemTime(new Date(2022, 0, 15));
79
48
  const user = userEvent.setup({delay: null});
80
49
  const onChange = vi.fn();
81
50
  render(
@@ -85,35 +54,33 @@ describe('Table.DateRangePicker', () => {
85
54
  onChange={onChange}
86
55
  initialState={{dateRange: [new Date(2022, 0, 1), new Date(2022, 0, 7)]}}
87
56
  >
88
- <Table.Header>
57
+ <Table.Header data-testid="table-header">
89
58
  <Table.DateRangePicker
90
59
  presets={{preset: {label: 'Preset', range: [new Date(2022, 0, 8), new Date(2022, 0, 14)]}}}
91
60
  />
92
61
  </Table.Header>
93
62
  </Table>
94
63
  );
64
+ const tableHeader = screen.getByTestId('table-header');
95
65
 
96
- await screen.findByText('Jan 01, 2022 - Jan 07, 2022');
97
- await screen.findByRole('button', {name: 'calendar'});
98
-
99
- await user.click(screen.getByRole('button', {name: 'calendar'}));
66
+ expect(within(tableHeader).getByText('Jan 01, 2022 - Jan 07, 2022')).toBeInTheDocument();
67
+ await user.click(within(tableHeader).getByRole('button', {name: 'calendar'}));
100
68
 
101
- await screen.findByRole('dialog');
69
+ const calendar = await screen.findByRole('dialog', {name: 'calendar'});
102
70
 
103
71
  // select a preset
104
- await user.click(
105
- screen.getByRole('searchbox', {
106
- name: 'Date range',
107
- })
108
- );
109
- await user.click(screen.getByRole('option', {name: 'Preset'}));
110
-
111
- await user.click(screen.getByRole('button', {name: 'Apply'}));
112
- vi.advanceTimersByTime(500);
72
+ await user.click(within(calendar).getByRole('searchbox', {name: 'Date range'}));
73
+ await user.click(within(calendar).getByRole('option', {name: 'Preset'}));
74
+ await user.click(within(calendar).getByRole('button', {name: 'Apply'}));
113
75
 
114
- await waitFor(() => expect(screen.queryByText('Jan 08, 2022 - Jan 14, 2022')).toBeVisible());
76
+ await waitFor(() => {
77
+ expect(onChange).toHaveBeenCalledTimes(1);
78
+ });
115
79
  expect(onChange).toHaveBeenCalledWith(
116
80
  expect.objectContaining({dateRange: [new Date(2022, 0, 8), new Date(2022, 0, 14)]})
117
81
  );
118
- });
82
+ expect(within(tableHeader).getByText('Jan 08, 2022 - Jan 14, 2022')).toBeInTheDocument();
83
+
84
+ vi.useRealTimers();
85
+ }, 20000);
119
86
  });
@@ -0,0 +1,97 @@
1
+ import {ColumnDef, createColumnHelper} from '@tanstack/table-core';
2
+ import {render, screen, userEvent} from '@test-utils';
3
+ import {useState} from 'react';
4
+
5
+ import {Table} from '../Table';
6
+
7
+ type RowData = {name: string};
8
+
9
+ const columnHelper = createColumnHelper<RowData>();
10
+ const columns: Array<ColumnDef<RowData>> = [columnHelper.accessor('name', {enableSorting: false})];
11
+
12
+ describe('Table.LastUpdated', () => {
13
+ beforeEach(() => {
14
+ vi.useFakeTimers().setSystemTime(new Date(2022, 0, 15, 13, 5, 50));
15
+ });
16
+
17
+ afterEach(() => {
18
+ vi.useRealTimers();
19
+ });
20
+
21
+ it('displays the label and time', () => {
22
+ const {rerender} = render(
23
+ <Table data={[{name: 'fruit'}]} columns={columns}>
24
+ <Table.LastUpdated />
25
+ </Table>
26
+ );
27
+
28
+ expect(screen.getByText('Last update:')).toBeVisible();
29
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
30
+
31
+ rerender(
32
+ <Table data={[{name: 'fruit'}]} columns={columns}>
33
+ <Table.LastUpdated label="CUSTOM label:" />
34
+ </Table>
35
+ );
36
+
37
+ expect(screen.queryByText('Last update:')).not.toBeInTheDocument();
38
+ expect(screen.getByText('CUSTOM label:')).toBeVisible();
39
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
40
+ });
41
+
42
+ it('updates the time when a dependency changes', async () => {
43
+ const user = userEvent.setup({delay: null});
44
+
45
+ // Using a fixture to have a button that will trigger a change of a dependency
46
+ const Fixture = () => {
47
+ const [isClicked, setIsClicked] = useState(false);
48
+ return (
49
+ <>
50
+ <button onClick={() => setIsClicked(true)}>Click me</button>
51
+ <Table data={[{name: 'fruit'}]} columns={columns}>
52
+ <Table.LastUpdated dependencies={[isClicked]} />
53
+ </Table>
54
+ </>
55
+ );
56
+ };
57
+ render(<Fixture />);
58
+
59
+ expect(screen.getByText('Last update:')).toBeVisible();
60
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
61
+
62
+ vi.setSystemTime(new Date(2022, 0, 15, 14, 11, 22));
63
+
64
+ // the date changed but the dependency didn't change yet, so the timer is still the same
65
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
66
+
67
+ // When we click on the button the isClicked switch from false to true which triggers an update
68
+ await user.click(screen.getByRole('button', {name: 'Click me'}));
69
+ expect(screen.getByRole('timer')).toHaveTextContent('2:11:22 PM');
70
+ });
71
+
72
+ it('updates the time when the data changes', async () => {
73
+ const user = userEvent.setup({delay: null});
74
+ const Fixture = () => {
75
+ const [data, setData] = useState([{name: 'fruit'}]);
76
+ return (
77
+ <>
78
+ <button onClick={() => setData([{name: 'vegetable'}])}>Click me</button>
79
+ <Table data={data} columns={columns}>
80
+ <Table.LastUpdated />
81
+ </Table>
82
+ </>
83
+ );
84
+ };
85
+ render(<Fixture />);
86
+
87
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
88
+
89
+ vi.setSystemTime(new Date(2022, 0, 15, 14, 11, 22));
90
+
91
+ expect(screen.getByRole('timer')).toHaveTextContent('1:05:50 PM');
92
+
93
+ await user.click(screen.getByRole('button', {name: 'Click me'}));
94
+
95
+ expect(screen.getByRole('timer')).toHaveTextContent('2:11:22 PM');
96
+ });
97
+ });
@@ -1,5 +1,5 @@
1
1
  import {ColumnDef, createColumnHelper} from '@tanstack/table-core';
2
- import {act, render, screen, userEvent, waitFor} from '@test-utils';
2
+ import {render, screen, userEvent, waitFor} from '@test-utils';
3
3
 
4
4
  import {Table} from '../Table';
5
5
 
@@ -9,40 +9,6 @@ const columnHelper = createColumnHelper<RowData>();
9
9
  const columns: Array<ColumnDef<RowData>> = [columnHelper.accessor('name', {enableSorting: false})];
10
10
 
11
11
  describe('Table.Predicate', () => {
12
- beforeEach(() => {
13
- vi.useFakeTimers();
14
- });
15
- afterEach(() => {
16
- vi.useRealTimers();
17
- });
18
- it('displays the intial value', async () => {
19
- render(
20
- <Table
21
- data={[{name: 'fruit'}, {name: 'vegetable'}]}
22
- columns={columns}
23
- initialState={{predicates: {rank: 'second'}}}
24
- >
25
- <Table.Header>
26
- <Table.Predicate
27
- id="rank"
28
- data={[
29
- {value: 'first', label: 'First'},
30
- {value: 'second', label: 'Second'},
31
- ]}
32
- />
33
- </Table.Header>
34
- </Table>
35
- );
36
-
37
- await waitFor(() => {
38
- expect(
39
- screen.getByRole('searchbox', {
40
- name: 'rank',
41
- })
42
- ).toHaveValue('Second');
43
- });
44
- });
45
-
46
12
  it('calls onMount with the initial value', async () => {
47
13
  const onMount = vi.fn();
48
14
  render(
@@ -65,26 +31,17 @@ describe('Table.Predicate', () => {
65
31
  );
66
32
 
67
33
  await waitFor(() => {
68
- expect(
69
- screen.getByRole('searchbox', {
70
- name: 'rank',
71
- })
72
- ).toHaveValue('Second');
34
+ expect(screen.getByRole('searchbox', {name: 'rank'})).toHaveValue('Second');
73
35
  });
74
36
  expect(onMount).toHaveBeenCalledWith(expect.objectContaining({predicates: {rank: 'second'}}));
75
37
  });
76
38
 
77
39
  it('calls onChange when changing the predicate', async () => {
78
- const user = userEvent.setup({advanceTimers: vi.advanceTimersByTime});
40
+ const user = userEvent.setup();
79
41
  const onChange = vi.fn();
80
42
  render(
81
- <Table
82
- data={[{name: 'fruit'}, {name: 'vegetable'}]}
83
- columns={columns}
84
- onChange={onChange}
85
- initialState={{predicates: {rank: 'second'}}}
86
- >
87
- <Table.Header>
43
+ <Table data={[{name: 'fruit'}, {name: 'vegetable'}]} columns={columns} onChange={onChange}>
44
+ <Table.Header data-testid="table-header">
88
45
  <Table.Predicate
89
46
  id="rank"
90
47
  data={[
@@ -96,18 +53,13 @@ describe('Table.Predicate', () => {
96
53
  </Table>
97
54
  );
98
55
 
99
- expect(screen.getByRole('searchbox', {name: 'rank'})).toHaveValue('Second');
100
-
101
56
  await user.click(screen.getByRole('searchbox', {name: 'rank'}));
102
-
103
57
  await user.click(screen.getByRole('option', {name: 'First'}));
104
58
 
105
59
  expect(screen.getByRole('searchbox', {name: 'rank'})).toHaveValue('First');
106
- act(() => {
107
- vi.advanceTimersByTime(500);
60
+ await waitFor(() => {
61
+ expect(onChange).toHaveBeenCalledTimes(1);
108
62
  });
109
-
110
- expect(onChange).toHaveBeenCalledTimes(1);
111
63
  expect(onChange).toHaveBeenCalledWith(expect.objectContaining({predicates: {rank: 'first'}}));
112
64
  });
113
65
  });
@@ -1,12 +1,13 @@
1
1
  import {ListSize16Px} from '@coveord/plasma-react-icons';
2
- import {Box, Collapse, createStyles} from '@mantine/core';
2
+ import {Box, Collapse, createStyles, rem} from '@mantine/core';
3
3
  import {flexRender} from '@tanstack/react-table';
4
4
  import {defaultColumnSizing} from '@tanstack/table-core';
5
- import {Fragment} from 'react';
5
+ import {Fragment, type MouseEvent} from 'react';
6
6
  import {TableLayout, TableLayoutProps} from '../Table.types';
7
7
  import {TableCollapsibleColumn} from '../TableCollapsibleColumn';
8
8
  import {useTable} from '../TableContext';
9
9
  import {TableLoading} from '../TableLoading';
10
+ import {TableSelectableColumn} from '../TableSelectableColumn';
10
11
  import {Th} from '../Th';
11
12
 
12
13
  interface TableStylesParams {
@@ -16,13 +17,12 @@ interface TableStylesParams {
16
17
 
17
18
  const useStyles = createStyles<string, TableStylesParams>((theme, {multiRowSelectionEnabled, disableRowSelection}) => {
18
19
  const rowBackgroundColor =
19
- theme.colorScheme === 'dark'
20
- ? theme.fn.rgba(theme.colors[theme.primaryColor][7], 0.2)
21
- : theme.colors[theme.primaryColor][0];
20
+ theme.colorScheme === 'dark' ? theme.fn.rgba(theme.colors[theme.primaryColor][7], 0.2) : theme.colors.gray[1];
21
+ const border = `${rem(1)} solid ${theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3]}`;
22
22
  return {
23
23
  headerColumns: {
24
24
  '& th:first-of-type > *': {
25
- paddingLeft: theme.spacing.xl,
25
+ paddingLeft: '40px',
26
26
  },
27
27
 
28
28
  '& input[type=checkbox]': {
@@ -60,10 +60,26 @@ const useStyles = createStyles<string, TableStylesParams>((theme, {multiRowSelec
60
60
  },
61
61
 
62
62
  row: {
63
+ '& td:first-of-type': {
64
+ paddingLeft: '40px',
65
+ },
63
66
  '&:hover': {
64
67
  backgroundColor: rowBackgroundColor,
65
68
  },
66
69
  },
70
+
71
+ cell: {
72
+ verticalAlign: 'middle',
73
+ // We must use height instead of minHeight here, otherwise it doesn't apply
74
+ height: '56px',
75
+ padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
76
+ borderBottom: border,
77
+ },
78
+
79
+ collapsible: {
80
+ backgroundColor: rowBackgroundColor,
81
+ borderBottom: border,
82
+ },
67
83
  };
68
84
  });
69
85
 
@@ -84,14 +100,27 @@ const RowLayoutBody = <T,>({table, doubleClickAction, getExpandChildren, loading
84
100
  const {multiRowSelectionEnabled, disableRowSelection} = useTable();
85
101
  const {classes, cx} = useStyles({disableRowSelection, multiRowSelectionEnabled});
86
102
 
103
+ const toggleCollapsible = (el: HTMLTableRowElement) => {
104
+ const cell = el.children[el.children.length - 1] as HTMLTableCellElement;
105
+ cell.querySelector('button').click();
106
+ };
107
+
87
108
  const rows = table.getRowModel().rows.map((row) => {
88
109
  const rowChildren = getExpandChildren?.(row.original) ?? null;
89
110
  const isSelected = !!row.getIsSelected();
111
+ const onClick = (event: MouseEvent<HTMLTableRowElement>) => {
112
+ if (rowChildren) {
113
+ toggleCollapsible(event.currentTarget);
114
+ }
115
+ if (!disableRowSelection && !multiRowSelectionEnabled) {
116
+ row.toggleSelected();
117
+ }
118
+ };
90
119
 
91
120
  return (
92
121
  <Fragment key={row.id}>
93
122
  <tr
94
- onClick={() => (disableRowSelection ? undefined : row.toggleSelected())}
123
+ onClick={onClick}
95
124
  onDoubleClick={() => doubleClickAction?.(row.original)}
96
125
  className={cx(classes.row, {
97
126
  [classes.rowSelected]: isSelected,
@@ -102,13 +131,20 @@ const RowLayoutBody = <T,>({table, doubleClickAction, getExpandChildren, loading
102
131
  {row.getVisibleCells().map((cell) => {
103
132
  const size = cell.column.getSize();
104
133
  const width = size !== defaultColumnSizing.size ? size : undefined;
134
+ const onCollapsibleCellClick = (event: MouseEvent<HTMLTableCellElement>) => {
135
+ if (cell.column.id === TableSelectableColumn.id && !disableRowSelection) {
136
+ event.stopPropagation();
137
+ row.getToggleSelectedHandler();
138
+ }
139
+ };
105
140
  return (
106
141
  <td
107
142
  key={cell.id}
108
143
  style={{width}}
109
- className={cx({
144
+ className={cx(classes.cell, {
110
145
  [classes.rowCollapsibleButtonCell]: cell.column.id === TableCollapsibleColumn.id,
111
146
  })}
147
+ onClick={onCollapsibleCellClick}
112
148
  >
113
149
  <TableLoading visible={loading}>
114
150
  {flexRender(cell.column.columnDef.cell, cell.getContext())}
@@ -123,12 +159,10 @@ const RowLayoutBody = <T,>({table, doubleClickAction, getExpandChildren, loading
123
159
  colSpan={table.getAllColumns().length}
124
160
  style={{
125
161
  padding: 0,
126
- borderTop: row.getIsExpanded() ? undefined : 'none',
127
- borderBottom: row.getIsExpanded() ? undefined : 'none',
128
162
  }}
129
163
  >
130
164
  <Collapse in={row.getIsExpanded()}>
131
- <Box px="sm" py="xs">
165
+ <Box className={classes.collapsible} px="sm" py="xs">
132
166
  {rowChildren}
133
167
  </Box>
134
168
  </Collapse>
@@ -2,6 +2,7 @@ import {useClickOutside} from '@mantine/hooks';
2
2
  import {functionalUpdate, RowSelectionState, Table} from '@tanstack/table-core';
3
3
  import isEqual from 'fast-deep-equal';
4
4
 
5
+ import {useRef} from 'react';
5
6
  import {RowSelectionWithData, TableProps, TableState} from './Table.types';
6
7
 
7
8
  export const useRowSelection = <T>(
@@ -9,13 +10,19 @@ export const useRowSelection = <T>(
9
10
  {
10
11
  onRowSelectionChange,
11
12
  multiRowSelectionEnabled,
12
- }: Pick<TableProps<T>, 'onRowSelectionChange' | 'multiRowSelectionEnabled'>
13
+ additionalRootNodes = [],
14
+ }: Pick<TableProps<T>, 'onRowSelectionChange' | 'multiRowSelectionEnabled' | 'additionalRootNodes'>
13
15
  ) => {
14
- const outsideClickRef = useClickOutside(() => {
15
- if (!multiRowSelectionEnabled) {
16
- clearSelection();
17
- }
18
- });
16
+ const outsideClickRef = useRef<HTMLDivElement>();
17
+ useClickOutside(
18
+ () => {
19
+ if (!multiRowSelectionEnabled) {
20
+ clearSelection();
21
+ }
22
+ },
23
+ null,
24
+ [outsideClickRef.current, ...additionalRootNodes]
25
+ );
19
26
 
20
27
  table.setOptions((prev) => ({
21
28
  ...prev,