From 409a7afeac2dcbee4062f418b72e64195d222ad5 Mon Sep 17 00:00:00 2001 From: jeiea Date: Sat, 29 Aug 2020 14:28:44 +0900 Subject: [PATCH] Forward ref in data grid element --- .../ra-ui-materialui/src/list/Datagrid.tsx | 5 +- .../src/list/DatagridBody.tsx | 106 +++--- .../{DatagridCell.js => DatagridCell.tsx} | 26 +- .../ra-ui-materialui/src/list/DatagridRow.tsx | 316 +++++++++--------- 4 files changed, 240 insertions(+), 213 deletions(-) rename packages/ra-ui-materialui/src/list/{DatagridCell.js => DatagridCell.tsx} (67%) diff --git a/packages/ra-ui-materialui/src/list/Datagrid.tsx b/packages/ra-ui-materialui/src/list/Datagrid.tsx index 37fc93babc2..7d6c4fb37d7 100644 --- a/packages/ra-ui-materialui/src/list/Datagrid.tsx +++ b/packages/ra-ui-materialui/src/list/Datagrid.tsx @@ -63,7 +63,7 @@ import { ClassesOverride } from '../types'; * * */ -const Datagrid: FC = props => { +const Datagrid: FC = React.forwardRef((props, ref) => { const classes = useDatagridStyles(props); const { optimized = false, @@ -168,6 +168,7 @@ const Datagrid: FC = props => { */ return ( = props => { )}
); -}; +}); Datagrid.propTypes = { basePath: PropTypes.string, diff --git a/packages/ra-ui-materialui/src/list/DatagridBody.tsx b/packages/ra-ui-materialui/src/list/DatagridBody.tsx index 418c55afd1f..5be95d1dc60 100644 --- a/packages/ra-ui-materialui/src/list/DatagridBody.tsx +++ b/packages/ra-ui-materialui/src/list/DatagridBody.tsx @@ -9,54 +9,64 @@ import { Identifier, Record, RecordMap } from 'ra-core'; import DatagridRow, { PureDatagridRow } from './DatagridRow'; import useDatagridStyles from './useDatagridStyles'; -const DatagridBody: FC = ({ - basePath, - children, - classes, - className, - data, - expand, - hasBulkActions, - hover, - ids, - onToggleItem, - resource, - row, - rowClick, - rowStyle, - selectedIds, - isRowSelectable, - ...rest -}) => ( - - {ids.map((id, rowIndex) => - cloneElement( - row, - { - basePath, - classes, - className: classnames(classes.row, { - [classes.rowEven]: rowIndex % 2 === 0, - [classes.rowOdd]: rowIndex % 2 !== 0, - [classes.clickableRow]: rowClick, - }), - expand, - hasBulkActions, - hover, - id, - key: id, - onToggleItem, - record: data[id], - resource, - rowClick, - selectable: !isRowSelectable || isRowSelectable(data[id]), - selected: selectedIds.includes(id), - style: rowStyle ? rowStyle(data[id], rowIndex) : null, - }, - children - ) - )} - +const DatagridBody: FC = React.forwardRef( + ( + { + basePath, + children, + classes, + className, + data, + expand, + hasBulkActions, + hover, + ids, + onToggleItem, + resource, + row, + rowClick, + rowStyle, + selectedIds, + isRowSelectable, + ...rest + }, + ref + ) => ( + + {ids.map((id, rowIndex) => + cloneElement( + row, + { + basePath, + classes, + className: classnames(classes.row, { + [classes.rowEven]: rowIndex % 2 === 0, + [classes.rowOdd]: rowIndex % 2 !== 0, + [classes.clickableRow]: rowClick, + }), + expand, + hasBulkActions, + hover, + id, + key: id, + onToggleItem, + record: data[id], + resource, + rowClick, + selectable: + !isRowSelectable || isRowSelectable(data[id]), + selected: selectedIds.includes(id), + style: rowStyle ? rowStyle(data[id], rowIndex) : null, + }, + children + ) + )} + + ) ); DatagridBody.propTypes = { diff --git a/packages/ra-ui-materialui/src/list/DatagridCell.js b/packages/ra-ui-materialui/src/list/DatagridCell.tsx similarity index 67% rename from packages/ra-ui-materialui/src/list/DatagridCell.js rename to packages/ra-ui-materialui/src/list/DatagridCell.tsx index 1430b48494c..a478268cfc6 100644 --- a/packages/ra-ui-materialui/src/list/DatagridCell.js +++ b/packages/ra-ui-materialui/src/list/DatagridCell.tsx @@ -1,8 +1,15 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import TableCell from '@material-ui/core/TableCell'; +import TableCell, { TableCellProps } from '@material-ui/core/TableCell'; import classnames from 'classnames'; +export type DatagridCellProps = { + field: React.ReactElement; + record: Record; + basePath: string; + resource: string; +} & TableCellProps; + const sanitizeRestProps = ({ cellClassName, className, @@ -13,17 +20,14 @@ const sanitizeRestProps = ({ basePath, resource, ...rest -}) => rest; +}: Record) => rest; -const DatagridCell = ({ - className, - field, - record, - basePath, - resource, - ...rest -}) => ( +const DatagridCell: React.FC = React.forwardRef< + HTMLTableCellElement, + DatagridCellProps +>(({ className, field, record, basePath, resource, ...rest }, ref) => ( -); +)); DatagridCell.propTypes = { className: PropTypes.string, diff --git a/packages/ra-ui-materialui/src/list/DatagridRow.tsx b/packages/ra-ui-materialui/src/list/DatagridRow.tsx index 72f1f4ac5e0..c6914b92c3b 100644 --- a/packages/ra-ui-materialui/src/list/DatagridRow.tsx +++ b/packages/ra-ui-materialui/src/list/DatagridRow.tsx @@ -35,166 +35,178 @@ const computeNbColumns = (expand, children, hasBulkActions) => const defaultClasses = { expandIconCell: '', checkbox: '', rowCell: '' }; -const DatagridRow: FC = ({ - basePath, - children, - classes = defaultClasses, - className, - expand, - hasBulkActions, - hover, - id, - onToggleItem, - record, - resource, - rowClick, - selected, - style, - selectable, - ...rest -}) => { - const [expanded, toggleExpanded] = useExpanded(resource, id); - const [nbColumns, setNbColumns] = useState( - computeNbColumns(expand, children, hasBulkActions) - ); - useEffect(() => { - // Fields can be hidden dynamically based on permissions; - // The expand panel must span over the remaining columns - // So we must recompute the number of columns to span on - const newNbColumns = computeNbColumns(expand, children, hasBulkActions); - if (newNbColumns !== nbColumns) { - setNbColumns(newNbColumns); - } - }, [expand, nbColumns, children, hasBulkActions]); - - const history = useHistory(); - - const handleToggleExpand = useCallback( - event => { - toggleExpanded(); - event.stopPropagation(); - }, - [toggleExpanded] - ); - const handleToggleSelection = useCallback( - event => { - if (!selectable) return; - onToggleItem(id); - event.stopPropagation(); - }, - [id, onToggleItem, selectable] - ); - const handleClick = useCallback( - async event => { - if (!rowClick) return; - event.persist(); - - const effect = - typeof rowClick === 'function' - ? await rowClick(id, basePath, record) - : rowClick; - switch (effect) { - case 'edit': - history.push(linkToRecord(basePath, id)); - return; - case 'show': - history.push(linkToRecord(basePath, id, 'show')); - return; - case 'expand': - handleToggleExpand(event); - return; - case 'toggleSelection': - handleToggleSelection(event); - return; - default: - if (effect) history.push(effect); - return; - } - }, - [ +const DatagridRow: FC = React.forwardRef( + ( + { basePath, - history, - handleToggleExpand, - handleToggleSelection, + children, + classes = defaultClasses, + className, + expand, + hasBulkActions, + hover, id, + onToggleItem, record, + resource, rowClick, - ] - ); + selected, + style, + selectable, + ...rest + }, + ref + ) => { + const [expanded, toggleExpanded] = useExpanded(resource, id); + const [nbColumns, setNbColumns] = useState( + computeNbColumns(expand, children, hasBulkActions) + ); + useEffect(() => { + // Fields can be hidden dynamically based on permissions; + // The expand panel must span over the remaining columns + // So we must recompute the number of columns to span on + const newNbColumns = computeNbColumns( + expand, + children, + hasBulkActions + ); + if (newNbColumns !== nbColumns) { + setNbColumns(newNbColumns); + } + }, [expand, nbColumns, children, hasBulkActions]); - return ( - - - {expand && ( - - - - )} - {hasBulkActions && ( - - {selectable && ( - { + toggleExpanded(); + event.stopPropagation(); + }, + [toggleExpanded] + ); + const handleToggleSelection = useCallback( + event => { + if (!selectable) return; + onToggleItem(id); + event.stopPropagation(); + }, + [id, onToggleItem, selectable] + ); + const handleClick = useCallback( + async event => { + if (!rowClick) return; + event.persist(); + + const effect = + typeof rowClick === 'function' + ? await rowClick(id, basePath, record) + : rowClick; + switch (effect) { + case 'edit': + history.push(linkToRecord(basePath, id)); + return; + case 'show': + history.push(linkToRecord(basePath, id, 'show')); + return; + case 'expand': + handleToggleExpand(event); + return; + case 'toggleSelection': + handleToggleSelection(event); + return; + default: + if (effect) history.push(effect); + return; + } + }, + [ + basePath, + history, + handleToggleExpand, + handleToggleSelection, + id, + record, + rowClick, + ] + ); + + return ( + + + {expand && ( + + - )} - - )} - {React.Children.map(children, (field, index) => - isValidElement(field) ? ( - + )} + {hasBulkActions && ( + + {selectable && ( + )} - record={record} - {...{ field, basePath, resource }} - /> - ) : null - )} - - {expand && expanded && ( - - - {isValidElement(expand) - ? cloneElement(expand, { - // @ts-ignore - record, - basePath, - resource, - id: String(id), - }) - : createElement(expand, { - record, - basePath, - resource, - id: String(id), - })} - + + )} + {React.Children.map(children, (field, index) => + isValidElement(field) ? ( + + ) : null + )} - )} - - ); -}; + {expand && expanded && ( + + + {isValidElement(expand) + ? cloneElement(expand, { + // @ts-ignore + record, + basePath, + resource, + id: String(id), + }) + : createElement(expand, { + record, + basePath, + resource, + id: String(id), + })} + + + )} + + ); + } +); DatagridRow.propTypes = { basePath: PropTypes.string,