@coveord/plasma-mantine 49.3.3 → 49.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coveord/plasma-mantine",
3
- "version": "49.3.3",
3
+ "version": "49.3.4",
4
4
  "description": "A Plasma flavoured Mantine theme",
5
5
  "keywords": [
6
6
  "plasma",
@@ -1,5 +1,10 @@
1
- import matchers from '@testing-library/jest-dom/matchers';
1
+ import matchers, {TestingLibraryMatchers} from '@testing-library/jest-dom/matchers';
2
2
  import {cleanup} from '@testing-library/react';
3
+ declare global {
4
+ namespace Vi {
5
+ interface JestAssertion<T = any> extends jest.Matchers<void, T>, TestingLibraryMatchers<T, void> {}
6
+ }
7
+ }
3
8
  expect.extend(matchers);
4
9
  Object.defineProperty(window, 'matchMedia', {
5
10
  writable: true,
@@ -226,6 +226,11 @@ export const Table: TableType = <T,>({
226
226
  onStateChange: setState,
227
227
  }));
228
228
  const {clearSelection, getSelectedRow, getSelectedRows} = useRowSelection(table);
229
+ const isFiltered =
230
+ !!state.globalFilter ||
231
+ Object.keys(form.values?.predicates ?? {}).some((predicate) => !!form.values.predicates[predicate]) ||
232
+ !!form.values.dateRange?.[0] ||
233
+ !!form.values.dateRange?.[1];
229
234
 
230
235
  const triggerChange = debounce(() => onChange?.({...state, ...form.values}), 500);
231
236
 
@@ -244,7 +249,7 @@ export const Table: TableType = <T,>({
244
249
  }, [state.globalFilter, state.pagination, state.sorting, form.values]);
245
250
 
246
251
  const clearFilters = useCallback(() => {
247
- form.setFieldValue('predicates', {});
252
+ form.setFieldValue('predicates', initialState.predicates ?? {});
248
253
  setState((prevState) => ({...prevState, globalFilter: ''}));
249
254
  }, []);
250
255
 
@@ -319,6 +324,7 @@ export const Table: TableType = <T,>({
319
324
  value={{
320
325
  onChange: triggerChange,
321
326
  state,
327
+ isFiltered,
322
328
  setState,
323
329
  clearFilters,
324
330
  getSelectedRow,
@@ -330,28 +336,34 @@ export const Table: TableType = <T,>({
330
336
  getPageCount: table.getPageCount,
331
337
  }}
332
338
  >
333
- {header}
334
- <MantineTable className={classes.table} horizontalSpacing="sm" verticalSpacing="xs" pb="sm">
335
- <thead className={classes.header}>
336
- {table.getHeaderGroups().map((headerGroup) => (
337
- <tr key={headerGroup.id}>
338
- {headerGroup.headers.map((columnHeader) => (
339
- <Th key={columnHeader.id} header={columnHeader} />
339
+ {!rows.length && !isFiltered && !loading ? (
340
+ noDataChildren
341
+ ) : (
342
+ <>
343
+ {header}
344
+ <MantineTable className={classes.table} horizontalSpacing="sm" verticalSpacing="xs" pb="sm">
345
+ <thead className={classes.header}>
346
+ {table.getHeaderGroups().map((headerGroup) => (
347
+ <tr key={headerGroup.id}>
348
+ {headerGroup.headers.map((columnHeader) => (
349
+ <Th key={columnHeader.id} header={columnHeader} />
350
+ ))}
351
+ </tr>
340
352
  ))}
341
- </tr>
342
- ))}
343
- </thead>
344
- <tbody>
345
- {rows.length ? (
346
- rows
347
- ) : (
348
- <tr>
349
- <td colSpan={columns.length}>{noDataChildren}</td>
350
- </tr>
351
- )}
352
- </tbody>
353
- </MantineTable>
354
- {footer}
353
+ </thead>
354
+ <tbody>
355
+ {rows.length ? (
356
+ rows
357
+ ) : (
358
+ <tr>
359
+ <td colSpan={columns.length}>{noDataChildren}</td>
360
+ </tr>
361
+ )}
362
+ </tbody>
363
+ </MantineTable>
364
+ {footer}
365
+ </>
366
+ )}
355
367
  </TableContext.Provider>
356
368
  </Box>
357
369
  );
@@ -35,6 +35,11 @@ type TableContextType = {
35
35
  * Function to update the table state
36
36
  */
37
37
  setState: Dispatch<(prevState: TableState) => TableState>;
38
+ /**
39
+ * Whether the table currently as any kind of filter applied.
40
+ * Useful to determine if the noDataChildren is an empty state or just the result of a filter
41
+ */
42
+ isFiltered: boolean;
38
43
  /**
39
44
  * Function that clears the filter and predicates
40
45
  */
@@ -3,6 +3,7 @@ import {render, screen, userEvent, waitFor, within} from '@test-utils';
3
3
  import {FunctionComponent} from 'react';
4
4
 
5
5
  import {Table} from '../Table';
6
+ import {useTable} from '../useTable';
6
7
 
7
8
  type RowData = {firstName: string; lastName?: string};
8
9
 
@@ -68,6 +69,67 @@ describe('Table', () => {
68
69
  expect(screen.getByRole('button', {name: 'Hello'})).toBeVisible();
69
70
  });
70
71
 
72
+ it('hides the footer and header when the table is empty and not filtered', () => {
73
+ const NoData = () => <span data-testid="empty-state" />;
74
+ const customColumns: Array<ColumnDef<RowData>> = [
75
+ columnHelper.accessor('firstName', {
76
+ header: () => 'First Name',
77
+ cell: (info) => info.getValue().toUpperCase(),
78
+ enableSorting: false,
79
+ }),
80
+ columnHelper.accessor('lastName', {
81
+ header: () => 'Last Name',
82
+ cell: (info) => info.getValue().toUpperCase(),
83
+ enableSorting: false,
84
+ }),
85
+ ];
86
+ render(
87
+ <Table data={[]} columns={customColumns} noDataChildren={<NoData />}>
88
+ <Table.Header data-testid="table-header">header</Table.Header>
89
+ <Table.Footer data-testid="table-footer">footer</Table.Footer>
90
+ </Table>
91
+ );
92
+
93
+ expect(screen.queryByTestId('table-header')).not.toBeInTheDocument();
94
+ expect(screen.queryByTestId('table-footer')).not.toBeInTheDocument();
95
+ expect(screen.getByTestId('empty-state')).toBeInTheDocument();
96
+ });
97
+
98
+ it('does not hide the footer and header when the table is empty and filtered', () => {
99
+ const NoData = () => {
100
+ const {isFiltered} = useTable();
101
+ return isFiltered ? <span data-testid="filtered-empty-state" /> : <span data-testid="empty-state" />;
102
+ };
103
+ const customColumns: Array<ColumnDef<RowData>> = [
104
+ columnHelper.accessor('firstName', {
105
+ header: () => 'First Name',
106
+ cell: (info) => info.getValue().toUpperCase(),
107
+ enableSorting: false,
108
+ }),
109
+ columnHelper.accessor('lastName', {
110
+ header: () => 'Last Name',
111
+ cell: (info) => info.getValue().toUpperCase(),
112
+ enableSorting: false,
113
+ }),
114
+ ];
115
+ render(
116
+ <Table
117
+ data={[]}
118
+ columns={customColumns}
119
+ noDataChildren={<NoData />}
120
+ initialState={{globalFilter: 'something'}}
121
+ >
122
+ <Table.Header data-testid="table-header">header</Table.Header>
123
+ <Table.Footer data-testid="table-footer">footer</Table.Footer>
124
+ </Table>
125
+ );
126
+
127
+ expect(screen.getByTestId('table-header')).toBeInTheDocument();
128
+ expect(screen.getByTestId('table-footer')).toBeInTheDocument();
129
+ expect(screen.getByTestId('filtered-empty-state')).toBeInTheDocument();
130
+ expect(screen.queryByTestId('empty-state')).not.toBeInTheDocument();
131
+ });
132
+
71
133
  it('opens the collapsible rows when the user click on the toggle', async () => {
72
134
  const user = userEvent.setup({delay: null});
73
135
  const Fixture: FunctionComponent<{row: RowData}> = ({row}) => <div>Collapsible content: {row.lastName}</div>;