Skip to content

Commit ede187b

Browse files
authoredAug 31, 2020
Merge pull request #5202 from jeiea/next
Forward ref in data grid element
2 parents d580844 + 409a7af commit ede187b

File tree

4 files changed

+240
-213
lines changed

4 files changed

+240
-213
lines changed
 

‎packages/ra-ui-materialui/src/list/Datagrid.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import { ClassesOverride } from '../types';
6363
* </Datagrid>
6464
* </ReferenceManyField>
6565
*/
66-
const Datagrid: FC<DatagridProps> = props => {
66+
const Datagrid: FC<DatagridProps> = React.forwardRef((props, ref) => {
6767
const classes = useDatagridStyles(props);
6868
const {
6969
optimized = false,
@@ -168,6 +168,7 @@ const Datagrid: FC<DatagridProps> = props => {
168168
*/
169169
return (
170170
<Table
171+
ref={ref}
171172
className={classnames(classes.table, className)}
172173
size={size}
173174
{...sanitizeListRestProps(rest)}
@@ -244,7 +245,7 @@ const Datagrid: FC<DatagridProps> = props => {
244245
)}
245246
</Table>
246247
);
247-
};
248+
});
248249

249250
Datagrid.propTypes = {
250251
basePath: PropTypes.string,

‎packages/ra-ui-materialui/src/list/DatagridBody.tsx

+58-48
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,64 @@ import { Identifier, Record, RecordMap } from 'ra-core';
99
import DatagridRow, { PureDatagridRow } from './DatagridRow';
1010
import useDatagridStyles from './useDatagridStyles';
1111

12-
const DatagridBody: FC<DatagridBodyRow> = ({
13-
basePath,
14-
children,
15-
classes,
16-
className,
17-
data,
18-
expand,
19-
hasBulkActions,
20-
hover,
21-
ids,
22-
onToggleItem,
23-
resource,
24-
row,
25-
rowClick,
26-
rowStyle,
27-
selectedIds,
28-
isRowSelectable,
29-
...rest
30-
}) => (
31-
<TableBody className={classnames('datagrid-body', className)} {...rest}>
32-
{ids.map((id, rowIndex) =>
33-
cloneElement(
34-
row,
35-
{
36-
basePath,
37-
classes,
38-
className: classnames(classes.row, {
39-
[classes.rowEven]: rowIndex % 2 === 0,
40-
[classes.rowOdd]: rowIndex % 2 !== 0,
41-
[classes.clickableRow]: rowClick,
42-
}),
43-
expand,
44-
hasBulkActions,
45-
hover,
46-
id,
47-
key: id,
48-
onToggleItem,
49-
record: data[id],
50-
resource,
51-
rowClick,
52-
selectable: !isRowSelectable || isRowSelectable(data[id]),
53-
selected: selectedIds.includes(id),
54-
style: rowStyle ? rowStyle(data[id], rowIndex) : null,
55-
},
56-
children
57-
)
58-
)}
59-
</TableBody>
12+
const DatagridBody: FC<DatagridBodyRow> = React.forwardRef(
13+
(
14+
{
15+
basePath,
16+
children,
17+
classes,
18+
className,
19+
data,
20+
expand,
21+
hasBulkActions,
22+
hover,
23+
ids,
24+
onToggleItem,
25+
resource,
26+
row,
27+
rowClick,
28+
rowStyle,
29+
selectedIds,
30+
isRowSelectable,
31+
...rest
32+
},
33+
ref
34+
) => (
35+
<TableBody
36+
ref={ref}
37+
className={classnames('datagrid-body', className)}
38+
{...rest}
39+
>
40+
{ids.map((id, rowIndex) =>
41+
cloneElement(
42+
row,
43+
{
44+
basePath,
45+
classes,
46+
className: classnames(classes.row, {
47+
[classes.rowEven]: rowIndex % 2 === 0,
48+
[classes.rowOdd]: rowIndex % 2 !== 0,
49+
[classes.clickableRow]: rowClick,
50+
}),
51+
expand,
52+
hasBulkActions,
53+
hover,
54+
id,
55+
key: id,
56+
onToggleItem,
57+
record: data[id],
58+
resource,
59+
rowClick,
60+
selectable:
61+
!isRowSelectable || isRowSelectable(data[id]),
62+
selected: selectedIds.includes(id),
63+
style: rowStyle ? rowStyle(data[id], rowIndex) : null,
64+
},
65+
children
66+
)
67+
)}
68+
</TableBody>
69+
)
6070
);
6171

6272
DatagridBody.propTypes = {

‎packages/ra-ui-materialui/src/list/DatagridCell.js ‎packages/ra-ui-materialui/src/list/DatagridCell.tsx

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import * as React from 'react';
22
import PropTypes from 'prop-types';
3-
import TableCell from '@material-ui/core/TableCell';
3+
import TableCell, { TableCellProps } from '@material-ui/core/TableCell';
44
import classnames from 'classnames';
55

6+
export type DatagridCellProps = {
7+
field: React.ReactElement;
8+
record: Record<string, any>;
9+
basePath: string;
10+
resource: string;
11+
} & TableCellProps;
12+
613
const sanitizeRestProps = ({
714
cellClassName,
815
className,
@@ -13,17 +20,14 @@ const sanitizeRestProps = ({
1320
basePath,
1421
resource,
1522
...rest
16-
}) => rest;
23+
}: Record<string, any>) => rest;
1724

18-
const DatagridCell = ({
19-
className,
20-
field,
21-
record,
22-
basePath,
23-
resource,
24-
...rest
25-
}) => (
25+
const DatagridCell: React.FC<DatagridCellProps> = React.forwardRef<
26+
HTMLTableCellElement,
27+
DatagridCellProps
28+
>(({ className, field, record, basePath, resource, ...rest }, ref) => (
2629
<TableCell
30+
ref={ref}
2731
className={classnames(className, field.props.cellClassName)}
2832
align={field.props.textAlign}
2933
{...sanitizeRestProps(rest)}
@@ -34,7 +38,7 @@ const DatagridCell = ({
3438
resource,
3539
})}
3640
</TableCell>
37-
);
41+
));
3842

3943
DatagridCell.propTypes = {
4044
className: PropTypes.string,

‎packages/ra-ui-materialui/src/list/DatagridRow.tsx

+164-152
Original file line numberDiff line numberDiff line change
@@ -35,166 +35,178 @@ const computeNbColumns = (expand, children, hasBulkActions) =>
3535

3636
const defaultClasses = { expandIconCell: '', checkbox: '', rowCell: '' };
3737

38-
const DatagridRow: FC<DatagridRowProps> = ({
39-
basePath,
40-
children,
41-
classes = defaultClasses,
42-
className,
43-
expand,
44-
hasBulkActions,
45-
hover,
46-
id,
47-
onToggleItem,
48-
record,
49-
resource,
50-
rowClick,
51-
selected,
52-
style,
53-
selectable,
54-
...rest
55-
}) => {
56-
const [expanded, toggleExpanded] = useExpanded(resource, id);
57-
const [nbColumns, setNbColumns] = useState(
58-
computeNbColumns(expand, children, hasBulkActions)
59-
);
60-
useEffect(() => {
61-
// Fields can be hidden dynamically based on permissions;
62-
// The expand panel must span over the remaining columns
63-
// So we must recompute the number of columns to span on
64-
const newNbColumns = computeNbColumns(expand, children, hasBulkActions);
65-
if (newNbColumns !== nbColumns) {
66-
setNbColumns(newNbColumns);
67-
}
68-
}, [expand, nbColumns, children, hasBulkActions]);
69-
70-
const history = useHistory();
71-
72-
const handleToggleExpand = useCallback(
73-
event => {
74-
toggleExpanded();
75-
event.stopPropagation();
76-
},
77-
[toggleExpanded]
78-
);
79-
const handleToggleSelection = useCallback(
80-
event => {
81-
if (!selectable) return;
82-
onToggleItem(id);
83-
event.stopPropagation();
84-
},
85-
[id, onToggleItem, selectable]
86-
);
87-
const handleClick = useCallback(
88-
async event => {
89-
if (!rowClick) return;
90-
event.persist();
91-
92-
const effect =
93-
typeof rowClick === 'function'
94-
? await rowClick(id, basePath, record)
95-
: rowClick;
96-
switch (effect) {
97-
case 'edit':
98-
history.push(linkToRecord(basePath, id));
99-
return;
100-
case 'show':
101-
history.push(linkToRecord(basePath, id, 'show'));
102-
return;
103-
case 'expand':
104-
handleToggleExpand(event);
105-
return;
106-
case 'toggleSelection':
107-
handleToggleSelection(event);
108-
return;
109-
default:
110-
if (effect) history.push(effect);
111-
return;
112-
}
113-
},
114-
[
38+
const DatagridRow: FC<DatagridRowProps> = React.forwardRef(
39+
(
40+
{
11541
basePath,
116-
history,
117-
handleToggleExpand,
118-
handleToggleSelection,
42+
children,
43+
classes = defaultClasses,
44+
className,
45+
expand,
46+
hasBulkActions,
47+
hover,
11948
id,
49+
onToggleItem,
12050
record,
51+
resource,
12152
rowClick,
122-
]
123-
);
53+
selected,
54+
style,
55+
selectable,
56+
...rest
57+
},
58+
ref
59+
) => {
60+
const [expanded, toggleExpanded] = useExpanded(resource, id);
61+
const [nbColumns, setNbColumns] = useState(
62+
computeNbColumns(expand, children, hasBulkActions)
63+
);
64+
useEffect(() => {
65+
// Fields can be hidden dynamically based on permissions;
66+
// The expand panel must span over the remaining columns
67+
// So we must recompute the number of columns to span on
68+
const newNbColumns = computeNbColumns(
69+
expand,
70+
children,
71+
hasBulkActions
72+
);
73+
if (newNbColumns !== nbColumns) {
74+
setNbColumns(newNbColumns);
75+
}
76+
}, [expand, nbColumns, children, hasBulkActions]);
12477

125-
return (
126-
<Fragment>
127-
<TableRow
128-
className={className}
129-
key={id}
130-
style={style}
131-
hover={hover}
132-
onClick={handleClick}
133-
{...rest}
134-
>
135-
{expand && (
136-
<TableCell
137-
padding="none"
138-
className={classes.expandIconCell}
139-
>
140-
<ExpandRowButton
141-
classes={classes}
142-
expanded={expanded}
143-
onClick={handleToggleExpand}
144-
expandContentId={`${id}-expand`}
145-
/>
146-
</TableCell>
147-
)}
148-
{hasBulkActions && (
149-
<TableCell padding="checkbox">
150-
{selectable && (
151-
<Checkbox
152-
color="primary"
153-
className={`select-item ${classes.checkbox}`}
154-
checked={selected}
155-
onClick={handleToggleSelection}
78+
const history = useHistory();
79+
80+
const handleToggleExpand = useCallback(
81+
event => {
82+
toggleExpanded();
83+
event.stopPropagation();
84+
},
85+
[toggleExpanded]
86+
);
87+
const handleToggleSelection = useCallback(
88+
event => {
89+
if (!selectable) return;
90+
onToggleItem(id);
91+
event.stopPropagation();
92+
},
93+
[id, onToggleItem, selectable]
94+
);
95+
const handleClick = useCallback(
96+
async event => {
97+
if (!rowClick) return;
98+
event.persist();
99+
100+
const effect =
101+
typeof rowClick === 'function'
102+
? await rowClick(id, basePath, record)
103+
: rowClick;
104+
switch (effect) {
105+
case 'edit':
106+
history.push(linkToRecord(basePath, id));
107+
return;
108+
case 'show':
109+
history.push(linkToRecord(basePath, id, 'show'));
110+
return;
111+
case 'expand':
112+
handleToggleExpand(event);
113+
return;
114+
case 'toggleSelection':
115+
handleToggleSelection(event);
116+
return;
117+
default:
118+
if (effect) history.push(effect);
119+
return;
120+
}
121+
},
122+
[
123+
basePath,
124+
history,
125+
handleToggleExpand,
126+
handleToggleSelection,
127+
id,
128+
record,
129+
rowClick,
130+
]
131+
);
132+
133+
return (
134+
<Fragment>
135+
<TableRow
136+
ref={ref}
137+
className={className}
138+
key={id}
139+
style={style}
140+
hover={hover}
141+
onClick={handleClick}
142+
{...rest}
143+
>
144+
{expand && (
145+
<TableCell
146+
padding="none"
147+
className={classes.expandIconCell}
148+
>
149+
<ExpandRowButton
150+
classes={classes}
151+
expanded={expanded}
152+
onClick={handleToggleExpand}
153+
expandContentId={`${id}-expand`}
156154
/>
157-
)}
158-
</TableCell>
159-
)}
160-
{React.Children.map(children, (field, index) =>
161-
isValidElement(field) ? (
162-
<DatagridCell
163-
key={`${id}-${(field.props as any).source ||
164-
index}`}
165-
className={classnames(
166-
`column-${(field.props as any).source}`,
167-
classes.rowCell
155+
</TableCell>
156+
)}
157+
{hasBulkActions && (
158+
<TableCell padding="checkbox">
159+
{selectable && (
160+
<Checkbox
161+
color="primary"
162+
className={`select-item ${
163+
classes.checkbox
164+
}`}
165+
checked={selected}
166+
onClick={handleToggleSelection}
167+
/>
168168
)}
169-
record={record}
170-
{...{ field, basePath, resource }}
171-
/>
172-
) : null
173-
)}
174-
</TableRow>
175-
{expand && expanded && (
176-
<TableRow key={`${id}-expand`} id={`${id}-expand`}>
177-
<TableCell colSpan={nbColumns}>
178-
{isValidElement(expand)
179-
? cloneElement(expand, {
180-
// @ts-ignore
181-
record,
182-
basePath,
183-
resource,
184-
id: String(id),
185-
})
186-
: createElement(expand, {
187-
record,
188-
basePath,
189-
resource,
190-
id: String(id),
191-
})}
192-
</TableCell>
169+
</TableCell>
170+
)}
171+
{React.Children.map(children, (field, index) =>
172+
isValidElement(field) ? (
173+
<DatagridCell
174+
key={`${id}-${(field.props as any).source ||
175+
index}`}
176+
className={classnames(
177+
`column-${(field.props as any).source}`,
178+
classes.rowCell
179+
)}
180+
record={record}
181+
{...{ field, basePath, resource }}
182+
/>
183+
) : null
184+
)}
193185
</TableRow>
194-
)}
195-
</Fragment>
196-
);
197-
};
186+
{expand && expanded && (
187+
<TableRow key={`${id}-expand`} id={`${id}-expand`}>
188+
<TableCell colSpan={nbColumns}>
189+
{isValidElement(expand)
190+
? cloneElement(expand, {
191+
// @ts-ignore
192+
record,
193+
basePath,
194+
resource,
195+
id: String(id),
196+
})
197+
: createElement(expand, {
198+
record,
199+
basePath,
200+
resource,
201+
id: String(id),
202+
})}
203+
</TableCell>
204+
</TableRow>
205+
)}
206+
</Fragment>
207+
);
208+
}
209+
);
198210

199211
DatagridRow.propTypes = {
200212
basePath: PropTypes.string,

0 commit comments

Comments
 (0)
Please sign in to comment.