diff --git a/packages/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx b/packages/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx index c8b0aa44c7330..523bac623d133 100644 --- a/packages/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx +++ b/packages/x-data-grid/src/components/columnSelection/GridCellCheckboxRenderer.tsx @@ -1,9 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { - unstable_composeClasses as composeClasses, - unstable_useForkRef as useForkRef, -} from '@mui/utils'; +import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { forwardRef } from '@mui/x-internals/forwardRef'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; @@ -26,10 +23,6 @@ const useUtilityClasses = (ownerState: OwnerState) => { return composeClasses(slots, getDataGridUtilityClass, classes); }; -interface TouchRippleActions { - stop: (event: any, callback?: () => void) => void; -} - const GridCellCheckboxForwardRef = forwardRef( function GridCellCheckboxRenderer(props, ref) { const { @@ -50,10 +43,6 @@ const GridCellCheckboxForwardRef = forwardRef(null); - - const rippleRef = React.useRef(null); - const handleRef = useForkRef(checkboxElement, ref); const handleChange = (event: React.ChangeEvent) => { const params: GridRowSelectionCheckboxParams = { value: event.target.checked, id }; @@ -69,16 +58,6 @@ const GridCellCheckboxForwardRef = forwardRef { - if (hasFocus) { - const input = checkboxElement.current?.querySelector('input'); - input?.focus({ preventScroll: true }); - } else if (rippleRef.current) { - // Only available in @mui/material v5.4.1 or later - rippleRef.current.stop({}); - } - }, [hasFocus]); - const handleKeyDown = React.useCallback((event: React.KeyboardEvent) => { if (event.key === ' ') { // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom @@ -114,14 +93,15 @@ const GridCellCheckboxForwardRef = forwardRef ); }, diff --git a/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx b/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx index fe2c647be7159..0c3b315d51f2a 100644 --- a/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx +++ b/packages/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx @@ -145,7 +145,9 @@ const GridHeaderCheckbox = forwardRef checked={isChecked && !isIndeterminate} onChange={handleChange} className={classes.root} - inputProps={{ 'aria-label': label, name: 'select_all_rows' }} + slotProps={{ + htmlInput: { 'aria-label': label, name: 'select_all_rows' }, + }} tabIndex={tabIndex} onKeyDown={handleKeyDown} disabled={!isMultipleRowSelectionEnabled(rootProps)} diff --git a/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx b/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx index 962bf69976ae7..cc1989a9fdac7 100644 --- a/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx +++ b/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; -import FormControlLabel from '@mui/material/FormControlLabel'; import { styled } from '@mui/material/styles'; import { inputBaseClasses } from '@mui/material/InputBase'; import { TextFieldProps } from '../../models/gridBaseSlots'; @@ -272,21 +271,19 @@ function GridColumnsManagement(props: GridColumnsManagementProps) { {currentColumns.map((column) => ( - - } + disabled={column.hideable === false} + checked={columnVisibilityModel[column.field] !== false} + onClick={toggleColumn} + name={column.field} + inputRef={isFirstHideableColumn(column) ? firstSwitchRef : undefined} label={column.headerName || column.field} + size="medium" + density="compact" + fullWidth + {...rootProps.slotProps?.baseCheckbox} /> ))} {currentColumns.length === 0 && ( @@ -298,19 +295,14 @@ function GridColumnsManagement(props: GridColumnsManagementProps) { {(!disableShowHideToggle || !disableResetButton) && currentColumns.length > 0 ? ( {!disableShowHideToggle ? ( - toggleAllColumns(!allHideableColumnsVisible)} - name={apiRef.current.getLocaleText('columnsManagementShowHideAllText')} - sx={{ p: 0.5 }} - {...rootProps.slotProps?.baseCheckbox} - /> - } + toggleAllColumns(!allHideableColumnsVisible)} + name={apiRef.current.getLocaleText('columnsManagementShowHideAllText')} label={apiRef.current.getLocaleText('columnsManagementShowHideAllText')} + {...rootProps.slotProps?.baseCheckbox} /> ) : ( @@ -427,9 +419,8 @@ GridColumnsManagement.propTypes = { const GridColumnsManagementBody = styled('div', { name: 'MuiDataGrid', slot: 'ColumnsManagement', - overridesResolver: (props, styles) => styles.columnsManagement, })<{ ownerState: OwnerState }>(({ theme }) => ({ - padding: theme.spacing(0, 3, 1.5), + padding: theme.spacing(0, 2, 1.5), display: 'flex', flexDirection: 'column', overflow: 'auto', @@ -441,7 +432,6 @@ const GridColumnsManagementBody = styled('div', { const GridColumnsManagementHeader = styled('div', { name: 'MuiDataGrid', slot: 'ColumnsManagementHeader', - overridesResolver: (props, styles) => styles.columnsManagementHeader, })<{ ownerState: OwnerState }>(({ theme }) => ({ padding: theme.spacing(1.5, 3), })); @@ -449,7 +439,6 @@ const GridColumnsManagementHeader = styled('div', { const SearchInput = styled(NotRendered, { name: 'MuiDataGrid', slot: 'ColumnsManagementSearchInput', - overridesResolver: (props, styles) => styles.columnsManagementSearchInput, })<{ ownerState: OwnerState }>(({ theme }) => ({ [`& .${inputBaseClasses.root}`]: { padding: theme.spacing(0, 1.5, 0, 1.5), @@ -466,7 +455,6 @@ const SearchInput = styled(NotRendered, { const GridColumnsManagementFooter = styled('div', { name: 'MuiDataGrid', slot: 'ColumnsManagementFooter', - overridesResolver: (props, styles) => styles.columnsManagementFooter, })<{ ownerState: OwnerState }>(({ theme }) => ({ padding: theme.spacing(0.5, 1, 0.5, 3), display: 'flex', diff --git a/packages/x-data-grid/src/material/index.tsx b/packages/x-data-grid/src/material/index.tsx index 2fa1c002cae28..85e99346849c1 100644 --- a/packages/x-data-grid/src/material/index.tsx +++ b/packages/x-data-grid/src/material/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import useForkRef from '@mui/utils/useForkRef'; import MUIBadge from '@mui/material/Badge'; import MUICheckbox from '@mui/material/Checkbox'; import MUIChip from '@mui/material/Chip'; @@ -11,6 +12,7 @@ import MUIMenuList from '@mui/material/MenuList'; import MUIMenuItem from '@mui/material/MenuItem'; import MUITextField from '@mui/material/TextField'; import MUIFormControl from '@mui/material/FormControl'; +import MUIFormControlLabel from '@mui/material/FormControlLabel'; import MUISelect from '@mui/material/Select'; import MUIButton from '@mui/material/Button'; import MUIIconButton from '@mui/material/IconButton'; @@ -52,6 +54,8 @@ import type { GridBaseSlots } from '../models/gridSlotsComponent'; import type { GridSlotProps } from '../models/gridSlotsComponentsProps'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; +/* eslint-disable material-ui/disallow-react-api-in-server-components */ + const iconSlots: GridIconSlotsComponent = { booleanCellTrueIcon: GridCheckIcon, booleanCellFalseIcon: GridCloseIcon, @@ -93,7 +97,7 @@ const iconSlots: GridIconSlotsComponent = { const baseSlots: GridBaseSlots = { baseBadge: MUIBadge, - baseCheckbox: MUICheckbox, + baseCheckbox: React.forwardRef(BaseCheckbox), baseCircularProgress: MUICircularProgress, baseDivider: MUIDivider, baseLinearProgress: MUILinearProgress, @@ -120,6 +124,59 @@ const materialSlots: GridBaseSlots & GridIconSlotsComponent = { export default materialSlots; +const CHECKBOX_COMPACT = { p: 0.5 }; + +function BaseCheckbox(props: GridSlotProps['baseCheckbox'], ref: React.Ref) { + const { autoFocus, label, fullWidth, slotProps, className, density, ...other } = props; + + const elementRef = React.useRef(null); + const handleRef = useForkRef(elementRef, ref); + const rippleRef = React.useRef(null); + + const sx = density === 'compact' ? CHECKBOX_COMPACT : undefined; + + React.useEffect(() => { + if (autoFocus) { + const input = elementRef.current?.querySelector('input'); + input?.focus({ preventScroll: true }); + } else if (autoFocus === false && rippleRef.current) { + // Only available in @mui/material v5.4.1 or later + // @ts-ignore + rippleRef.current.stop({}); + } + }, [autoFocus]); + + if (!label) { + return ( + + ); + } + + return ( + + } + label={label} + sx={fullWidth ? { width: '100%', margin: 0 } : undefined} + /> + ); +} + function BaseMenuList(props: GridSlotProps['baseMenuList']) { return ; } diff --git a/packages/x-data-grid/src/models/gridBaseSlots.ts b/packages/x-data-grid/src/models/gridBaseSlots.ts index bf023a12921f2..fae67fce34232 100644 --- a/packages/x-data-grid/src/models/gridBaseSlots.ts +++ b/packages/x-data-grid/src/models/gridBaseSlots.ts @@ -27,6 +27,31 @@ export type ButtonProps = { touchRippleRef?: any; // FIXME(v8:romgrk): find a way to remove }; +export type CheckboxProps = { + ref?: Ref; + id?: string; + autoFocus?: boolean; + checked?: boolean; + className?: string; + disabled?: boolean; + fullWidth?: boolean; + indeterminate?: boolean; + inputRef?: React.Ref; + name?: string; + label?: React.ReactNode; + onClick?: React.MouseEventHandler; + onChange?: React.ChangeEventHandler; + onKeyDown?: React.KeyboardEventHandler; + size?: 'small' | 'medium'; + density?: 'standard' | 'compact'; + slotProps?: { + htmlInput?: React.InputHTMLAttributes; + }; + style?: React.CSSProperties; + tabIndex?: number; + touchRippleRef?: any; // FIXME(v8:romgrk): find a way to remove +}; + export type IconButtonProps = Omit & { label?: string; color?: 'default' | 'inherit' | 'primary'; diff --git a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts index a599bf9b4c3be..4f2053b2d4aed 100644 --- a/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts +++ b/packages/x-data-grid/src/models/gridSlotsComponentsProps.ts @@ -1,7 +1,6 @@ import * as React from 'react'; import type { BadgeProps as MUIBadgeProps } from '@mui/material/Badge'; import type { ButtonProps as MUIButtonProps } from '@mui/material/Button'; -import type { CheckboxProps } from '@mui/material/Checkbox'; import type { CircularProgressProps as MUICircularProgressProps } from '@mui/material/CircularProgress'; import type { LinearProgressProps as MUILinearProgressProps } from '@mui/material/LinearProgress'; import type { MenuItemProps as MUIMenuItemProps } from '@mui/material/MenuItem'; @@ -35,6 +34,7 @@ import type { GridColumnHeaderSortIconProps } from '../components/columnHeaders/ import type { BadgeProps, ButtonProps, + CheckboxProps, CircularProgressProps, DividerProps, IconButtonProps,