Skip to content

Commit 58083ae

Browse files
Merge pull request #445 from EdwardEB/v2
Add MRT_TableBodyEmptyRow component to render when table has no rows
2 parents 24fc9da + 23b0a59 commit 58083ae

File tree

9 files changed

+295
-40
lines changed

9 files changed

+295
-40
lines changed

packages/mantine-react-table/src/components/body/MRT_TableBody.tsx

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
type TableProps,
66
TableTbody,
77
type TableTbodyProps,
8-
Text,
98
} from '@mantine/core';
109
import { MRT_TableBodyRow, Memo_MRT_TableBodyRow } from './MRT_TableBodyRow';
1110
import { useMRT_RowVirtualizer } from '../../hooks/useMRT_RowVirtualizer';
@@ -18,6 +17,7 @@ import {
1817
type MRT_VirtualItem,
1918
} from '../../types';
2019
import { parseFromValuesOrFunc } from '../../utils/utils';
20+
import { MRT_TableBodyEmptyRow } from './MRT_TableBodyEmptyRow';
2121

2222
export interface MRT_TableBodyProps<TData extends MRT_RowData>
2323
extends TableTbodyProps {
@@ -42,16 +42,14 @@ export const MRT_TableBody = <TData extends MRT_RowData>({
4242
enableStickyFooter,
4343
enableStickyHeader,
4444
layoutMode,
45-
localization,
4645
mantineTableBodyProps,
4746
memoMode,
4847
renderDetailPanel,
49-
renderEmptyRowsFallback,
5048
rowPinningDisplayMode,
5149
},
52-
refs: { tableFooterRef, tableHeadRef, tablePaperRef },
50+
refs: { tableFooterRef, tableHeadRef },
5351
} = table;
54-
const { columnFilters, globalFilter, isFullScreen, rowPinning } = getState();
52+
const { isFullScreen, rowPinning } = getState();
5553

5654
const tableBodyProps = {
5755
...parseFromValuesOrFunc(mantineTableBodyProps, { table }),
@@ -133,34 +131,7 @@ export const MRT_TableBody = <TData extends MRT_RowData>({
133131
>
134132
{tableBodyProps?.children ??
135133
(!rows.length ? (
136-
<tr
137-
className={clsx(
138-
'mrt-table-body-row',
139-
layoutMode?.startsWith('grid') && classes['empty-row-tr-grid'],
140-
)}
141-
>
142-
<td
143-
className={clsx(
144-
'mrt-table-body-cell',
145-
layoutMode?.startsWith('grid') &&
146-
classes['empty-row-td-grid'],
147-
)}
148-
colSpan={table.getVisibleLeafColumns().length}
149-
>
150-
{renderEmptyRowsFallback?.({ table }) ?? (
151-
<Text
152-
__vars={{
153-
'--mrt-paper-width': `${tablePaperRef.current?.clientWidth}`,
154-
}}
155-
className={clsx(classes['empty-row-td-content'])}
156-
>
157-
{globalFilter || columnFilters.length
158-
? localization.noResultsFound
159-
: localization.noRecordsToDisplay}
160-
</Text>
161-
)}
162-
</td>
163-
</tr>
134+
<MRT_TableBodyEmptyRow {...commonRowProps} />
164135
) : (
165136
<>
166137
{(virtualRows ?? rows).map(
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import clsx from 'clsx';
2+
import classes from './MRT_TableBody.module.css';
3+
import { useMemo } from 'react';
4+
import { type TableProps, Text, TableTd, TableTrProps } from '@mantine/core';
5+
import { MRT_TableBodyRow } from './MRT_TableBodyRow';
6+
import {
7+
type MRT_Row,
8+
type MRT_RowData,
9+
type MRT_TableInstance,
10+
} from '../../types';
11+
import { createRow } from '@tanstack/react-table';
12+
import { MRT_ExpandButton } from '../buttons/MRT_ExpandButton';
13+
14+
interface Props<TData extends MRT_RowData> extends TableTrProps {
15+
table: MRT_TableInstance<TData>;
16+
tableProps: Partial<TableProps>;
17+
}
18+
19+
export const MRT_TableBodyEmptyRow = <TData extends MRT_RowData>({
20+
table,
21+
tableProps,
22+
...commonRowProps
23+
}: Props<TData>) => {
24+
const {
25+
getState,
26+
options: {
27+
layoutMode,
28+
localization,
29+
renderDetailPanel,
30+
renderEmptyRowsFallback,
31+
},
32+
refs: { tablePaperRef },
33+
} = table;
34+
const { columnFilters, globalFilter } = getState();
35+
36+
const emptyRow = useMemo(
37+
() =>
38+
createRow(
39+
table as any,
40+
'mrt-row-empty',
41+
{} as TData,
42+
0,
43+
0,
44+
) as MRT_Row<TData>,
45+
[],
46+
);
47+
48+
const emptyRowProps = {
49+
...commonRowProps,
50+
renderedRowIndex: 0,
51+
row: emptyRow,
52+
virtualRow: undefined,
53+
};
54+
55+
return (
56+
<MRT_TableBodyRow
57+
table={table}
58+
tableProps={tableProps}
59+
className={clsx(
60+
'mrt-table-body-row',
61+
layoutMode?.startsWith('grid') && classes['empty-row-tr-grid'],
62+
)}
63+
{...emptyRowProps}
64+
>
65+
{renderDetailPanel && (
66+
<TableTd
67+
className={clsx(
68+
'mrt-table-body-cell',
69+
layoutMode?.startsWith('grid') && classes['empty-row-td-grid'],
70+
)}
71+
colSpan={1}
72+
>
73+
<MRT_ExpandButton row={emptyRow} table={table} />
74+
</TableTd>
75+
)}
76+
<td
77+
className={clsx(
78+
'mrt-table-body-cell',
79+
layoutMode?.startsWith('grid') && classes['empty-row-td-grid'],
80+
)}
81+
colSpan={table.getVisibleLeafColumns().length}
82+
>
83+
{renderEmptyRowsFallback?.({ table }) ?? (
84+
<Text
85+
__vars={{
86+
'--mrt-paper-width': `${tablePaperRef.current?.clientWidth}`,
87+
}}
88+
className={clsx(classes['empty-row-td-content'])}
89+
>
90+
{globalFilter || columnFilters.length
91+
? localization.noResultsFound
92+
: localization.noRecordsToDisplay}
93+
</Text>
94+
)}
95+
</td>
96+
</MRT_TableBodyRow>
97+
);
98+
};

packages/mantine-react-table/src/components/body/MRT_TableBodyRow.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface Props<TData extends MRT_RowData> extends TableTrProps {
3434
}
3535

3636
export const MRT_TableBodyRow = <TData extends MRT_RowData>({
37+
children,
3738
columnVirtualizer,
3839
numRows,
3940
pinnedRowIds,
@@ -189,7 +190,7 @@ export const MRT_TableBodyRow = <TData extends MRT_RowData>({
189190
{virtualPaddingLeft ? (
190191
<Box component="td" display="flex" w={virtualPaddingLeft} />
191192
) : null}
192-
{(virtualColumns ?? row.getVisibleCells()).map(
193+
{children ? children : (virtualColumns ?? row.getVisibleCells()).map(
193194
(cellOrVirtualCell, renderedColumnIndex) => {
194195
let cell = cellOrVirtualCell as MRT_Cell<TData>;
195196
if (columnVirtualizer) {

packages/mantine-react-table/src/components/body/MRT_TableDetailPanel.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
type MRT_VirtualItem,
1111
} from '../../types';
1212
import { parseFromValuesOrFunc } from '../../utils/utils';
13+
import { MRT_EditCellTextInput } from '../inputs/MRT_EditCellTextInput';
1314

1415
interface Props<TData extends MRT_RowData> extends TableTdProps {
1516
parentRowRef: RefObject<HTMLTableRowElement>;
@@ -57,8 +58,15 @@ export const MRT_TableDetailPanel = <TData extends MRT_RowData>({
5758
...rest,
5859
};
5960

61+
const internalEditComponents = row
62+
.getAllCells()
63+
.filter((cell) => cell.column.columnDef.columnDefType === 'data')
64+
.map((cell) => (
65+
<MRT_EditCellTextInput cell={cell} key={cell.id} table={table} />
66+
));
67+
6068
const DetailPanel =
61-
!isLoading && row.getIsExpanded() && renderDetailPanel?.({ row, table });
69+
!isLoading && row.getIsExpanded() && renderDetailPanel?.({ row, table, internalEditComponents });
6270

6371
return (
6472
<TableTr

packages/mantine-react-table/src/components/buttons/MRT_ExpandButton.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
type MRT_TableInstance,
1414
} from '../../types';
1515
import { parseFromValuesOrFunc } from '../../utils/utils';
16+
import { MRT_EditCellTextInput } from '../inputs/MRT_EditCellTextInput';
1617

1718
interface Props<TData extends MRT_RowData> extends ActionIconProps {
1819
row: MRT_Row<TData>;
@@ -42,10 +43,18 @@ export const MRT_ExpandButton = <TData extends MRT_RowData>({
4243
}),
4344
...rest,
4445
};
46+
47+
const internalEditComponents = row
48+
.getAllCells()
49+
.filter((cell) => cell.column.columnDef.columnDefType === 'data')
50+
.map((cell) => (
51+
<MRT_EditCellTextInput cell={cell} key={cell.id} table={table} />
52+
));
53+
4554
const canExpand = row.getCanExpand();
4655
const isExpanded = row.getIsExpanded();
4756

48-
const DetailPanel = !!renderDetailPanel?.({ row, table });
57+
const DetailPanel = !!renderDetailPanel?.({ row, table, internalEditComponents });
4958

5059
const handleToggleExpand = (event: MouseEvent<HTMLButtonElement>) => {
5160
event.stopPropagation();
@@ -59,9 +68,8 @@ export const MRT_ExpandButton = <TData extends MRT_RowData>({
5968
<Tooltip
6069
disabled={!canExpand && !DetailPanel}
6170
label={
62-
actionIconProps?.title ?? (isExpanded
63-
? localization.collapse
64-
: localization.expand)
71+
actionIconProps?.title ??
72+
(isExpanded ? localization.collapse : localization.expand)
6573
}
6674
openDelay={1000}
6775
withinPortal

packages/mantine-react-table/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export * from './components/MantineReactTable';
2727
export * from './components/body/MRT_TableBody';
2828
export * from './components/body/MRT_TableBodyCell';
2929
export * from './components/body/MRT_TableBodyCellValue';
30+
export * from './components/body/MRT_TableBodyEmptyRow';
3031
export * from './components/body/MRT_TableBodyRow';
3132
export * from './components/body/MRT_TableBodyRowGrabHandle';
3233
export * from './components/body/MRT_TableBodyRowPinButton';

packages/mantine-react-table/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,7 @@ export type MRT_TableOptions<TData extends MRT_RowData> = Omit<
12181218
renderDetailPanel?: (props: {
12191219
row: MRT_Row<TData>;
12201220
table: MRT_TableInstance<TData>;
1221+
internalEditComponents: ReactNode[];
12211222
}) => ReactNode;
12221223
renderEditRowModalContent?: (props: {
12231224
internalEditComponents: ReactNode[];

packages/mantine-react-table/stories/features/Editing.stories.tsx

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { useState } from 'react';
2-
import { Flex, Stack, Switch, Title } from '@mantine/core';
2+
import { Center, Flex, Group, Stack, Switch, Title, Text } from '@mantine/core';
33
import {
44
type MRT_Cell,
55
type MRT_ColumnOrderState,
66
MRT_EditActionButtons,
77
type MRT_TableOptions,
88
MantineReactTable,
99
MRT_ColumnDef,
10+
useMantineReactTable,
1011
} from '../../src';
1112
import { faker } from '@faker-js/faker';
1213
import { type Meta } from '@storybook/react';
@@ -1238,3 +1239,64 @@ export const EditingTurnedOnDynamically = () => {
12381239
</Stack>
12391240
);
12401241
};
1242+
1243+
export const EditingInDetailPannel = () => {
1244+
const [withData, setWithData] = useState(false);
1245+
1246+
const columns = [
1247+
{
1248+
accessorKey: 'firstName',
1249+
header: 'First Name',
1250+
},
1251+
{
1252+
accessorKey: 'lastName',
1253+
header: 'Last Name',
1254+
},
1255+
{
1256+
accessorKey: 'address',
1257+
header: 'Address',
1258+
},
1259+
{
1260+
accessorKey: 'state',
1261+
header: 'State',
1262+
},
1263+
{
1264+
accessorKey: 'phoneNumber',
1265+
enableEditing: false,
1266+
header: 'Phone Number',
1267+
},
1268+
];
1269+
1270+
const table = useMantineReactTable({
1271+
columns,
1272+
data: withData ? data : [],
1273+
renderDetailPanel: ({ table, row, internalEditComponents }) => (
1274+
<Center>
1275+
<form onSubmit={(e) => e.preventDefault()}>
1276+
<Group gap="md" pb={24} pt={16}>
1277+
{internalEditComponents}
1278+
</Group>
1279+
</form>
1280+
<Flex justify="flex-end">
1281+
<MRT_EditActionButtons row={row} table={table} variant="text" />
1282+
</Flex>
1283+
</Center>
1284+
),
1285+
renderEmptyRowsFallback: () => (
1286+
<Center>
1287+
<Text>This table is empty, click on the chevron to add a record</Text>
1288+
</Center>
1289+
),
1290+
});
1291+
1292+
return (
1293+
<Stack>
1294+
<Switch
1295+
checked={withData}
1296+
label="Show data"
1297+
onChange={(e) => setWithData(e.currentTarget.checked)}
1298+
/>
1299+
<MantineReactTable table={table} />
1300+
</Stack>
1301+
);
1302+
};

0 commit comments

Comments
 (0)