From 6fc1da5a1de101bbeb65435f955f5752421eabfa Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskii Date: Tue, 19 Mar 2024 17:25:52 +0100 Subject: [PATCH] [DataGrid] Fix `ElementType` usage (#12479) --- .../src/components/GridPagination.tsx | 180 ++++++++++-------- .../components/cell/GridActionsCellItem.tsx | 33 ++-- 2 files changed, 120 insertions(+), 93 deletions(-) diff --git a/packages/x-data-grid/src/components/GridPagination.tsx b/packages/x-data-grid/src/components/GridPagination.tsx index 03be488965ca..9fe8e5cf2f93 100644 --- a/packages/x-data-grid/src/components/GridPagination.tsx +++ b/packages/x-data-grid/src/components/GridPagination.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import PropTypes from 'prop-types'; import TablePagination, { tablePaginationClasses, TablePaginationProps, @@ -31,88 +32,107 @@ const GridPaginationRoot = styled(TablePagination)(({ theme }) => ({ type MutableArray = A extends readonly (infer T)[] ? T[] : never; -export const GridPagination = React.forwardRef>( - function GridPagination(props, ref) { - const apiRef = useGridApiContext(); - const rootProps = useGridRootProps(); - const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector); - const rowCount = useGridSelector(apiRef, gridPaginationRowCountSelector); - - const lastPage = React.useMemo(() => { - const calculatedValue = Math.ceil(rowCount / (paginationModel.pageSize || 1)) - 1; - return Math.max(0, calculatedValue); - }, [rowCount, paginationModel.pageSize]); - - const handlePageSizeChange = React.useCallback( - (event: React.ChangeEvent) => { - const pageSize = Number(event.target.value); - apiRef.current.setPageSize(pageSize); - }, - [apiRef], - ); - - const handlePageChange = React.useCallback( - (_, page) => { - apiRef.current.setPage(page); - }, - [apiRef], - ); - - const isPageSizeIncludedInPageSizeOptions = (pageSize: number) => { - for (let i = 0; i < rootProps.pageSizeOptions.length; i += 1) { - const option = rootProps.pageSizeOptions[i]; - if (typeof option === 'number') { - if (option === pageSize) { - return true; - } - } else if (option.value === pageSize) { +interface GridPaginationOwnProps { + component?: React.ElementType; +} + +const GridPagination = React.forwardRef< + unknown, + Partial< + // See https://github.com/mui/material-ui/issues/40427 + Omit + > & + GridPaginationOwnProps +>(function GridPagination(props, ref) { + const apiRef = useGridApiContext(); + const rootProps = useGridRootProps(); + const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector); + const rowCount = useGridSelector(apiRef, gridPaginationRowCountSelector); + + const lastPage = React.useMemo(() => { + const calculatedValue = Math.ceil(rowCount / (paginationModel.pageSize || 1)) - 1; + return Math.max(0, calculatedValue); + }, [rowCount, paginationModel.pageSize]); + + const handlePageSizeChange = React.useCallback( + (event: React.ChangeEvent) => { + const pageSize = Number(event.target.value); + apiRef.current.setPageSize(pageSize); + }, + [apiRef], + ); + + const handlePageChange = React.useCallback( + (_, page) => { + apiRef.current.setPage(page); + }, + [apiRef], + ); + + const isPageSizeIncludedInPageSizeOptions = (pageSize: number) => { + for (let i = 0; i < rootProps.pageSizeOptions.length; i += 1) { + const option = rootProps.pageSizeOptions[i]; + if (typeof option === 'number') { + if (option === pageSize) { return true; } - } - return false; - }; - - if (process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line react-hooks/rules-of-hooks - const warnedOnceMissingInPageSizeOptions = React.useRef(false); - - const pageSize = rootProps.paginationModel?.pageSize ?? paginationModel.pageSize; - if ( - !warnedOnceMissingInPageSizeOptions.current && - !rootProps.autoPageSize && - !isPageSizeIncludedInPageSizeOptions(pageSize) - ) { - console.warn( - [ - `MUI X: The page size \`${paginationModel.pageSize}\` is not preset in the \`pageSizeOptions\`.`, - `Add it to show the pagination select.`, - ].join('\n'), - ); - - warnedOnceMissingInPageSizeOptions.current = true; + } else if (option.value === pageSize) { + return true; } } + return false; + }; - const pageSizeOptions = isPageSizeIncludedInPageSizeOptions(paginationModel.pageSize) - ? rootProps.pageSizeOptions - : []; - - return ( - } - rowsPerPage={paginationModel.pageSize} - onPageChange={handlePageChange} - onRowsPerPageChange={handlePageSizeChange} - {...apiRef.current.getLocaleText('MuiTablePagination')} - {...props} - /> - ); - }, -); + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line react-hooks/rules-of-hooks + const warnedOnceMissingInPageSizeOptions = React.useRef(false); + + const pageSize = rootProps.paginationModel?.pageSize ?? paginationModel.pageSize; + if ( + !warnedOnceMissingInPageSizeOptions.current && + !rootProps.autoPageSize && + !isPageSizeIncludedInPageSizeOptions(pageSize) + ) { + console.warn( + [ + `MUI X: The page size \`${paginationModel.pageSize}\` is not preset in the \`pageSizeOptions\`.`, + `Add it to show the pagination select.`, + ].join('\n'), + ); + + warnedOnceMissingInPageSizeOptions.current = true; + } + } + + const pageSizeOptions = isPageSizeIncludedInPageSizeOptions(paginationModel.pageSize) + ? rootProps.pageSizeOptions + : []; + + return ( + } + rowsPerPage={paginationModel.pageSize} + onPageChange={handlePageChange} + onRowsPerPageChange={handlePageSizeChange} + {...apiRef.current.getLocaleText('MuiTablePagination')} + {...props} + /> + ); +}); + +GridPagination.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + component: PropTypes.elementType, +} as any; + +export { GridPagination }; diff --git a/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx b/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx index 642d410d54ed..d11bd15188a0 100644 --- a/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx +++ b/packages/x-data-grid/src/components/cell/GridActionsCellItem.tsx @@ -5,23 +5,26 @@ import MenuItem, { MenuItemProps } from '@mui/material/MenuItem'; import ListItemIcon from '@mui/material/ListItemIcon'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; -export type GridActionsCellItemProps = { +interface GridActionsCellItemCommonProps { label: string; icon?: React.ReactElement; /** from https://mui.com/material-ui/api/button-base/#ButtonBase-prop-component */ component?: React.ElementType; -} & ( - | ({ showInMenu?: false; icon: React.ReactElement } & IconButtonProps) - | ({ - showInMenu: true; - /** - * If false, the menu will not close when this item is clicked. - * @default true - */ - closeMenuOnClick?: boolean; - closeMenu?: () => void; - } & MenuItemProps) -); +} + +export type GridActionsCellItemProps = GridActionsCellItemCommonProps & + ( + | ({ showInMenu?: false; icon: React.ReactElement } & Omit) + | ({ + showInMenu: true; + /** + * If false, the menu will not close when this item is clicked. + * @default true + */ + closeMenuOnClick?: boolean; + closeMenu?: () => void; + } & Omit) + ); const GridActionsCellItem = React.forwardRef( (props, ref) => { @@ -80,6 +83,10 @@ GridActionsCellItem.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * from https://mui.com/material-ui/api/button-base/#ButtonBase-prop-component + */ + component: PropTypes.elementType, icon: PropTypes.element, label: PropTypes.string.isRequired, showInMenu: PropTypes.bool,