Skip to content

Commit

Permalink
[data grid] Extract BaseSelectOption slot (#8072)
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii authored Mar 2, 2023
1 parent f5f9adf commit 34836e9
Show file tree
Hide file tree
Showing 17 changed files with 108 additions and 33 deletions.
1 change: 1 addition & 0 deletions docs/pages/x/api/data-grid/data-grid-premium.json
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@
"baseInputLabel": { "default": "InputLabel", "type": { "name": "elementType" } },
"basePopper": { "default": "Popper", "type": { "name": "elementType" } },
"baseSelect": { "default": "Select", "type": { "name": "elementType" } },
"baseSelectOption": { "default": "MenuItem", "type": { "name": "elementType" } },
"baseSwitch": { "default": "Switch", "type": { "name": "elementType" } },
"baseTextField": { "default": "TextField", "type": { "name": "elementType" } },
"baseTooltip": { "default": "Tooltip", "type": { "name": "elementType" } },
Expand Down
1 change: 1 addition & 0 deletions docs/pages/x/api/data-grid/data-grid-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
"baseInputLabel": { "default": "InputLabel", "type": { "name": "elementType" } },
"basePopper": { "default": "Popper", "type": { "name": "elementType" } },
"baseSelect": { "default": "Select", "type": { "name": "elementType" } },
"baseSelectOption": { "default": "MenuItem", "type": { "name": "elementType" } },
"baseSwitch": { "default": "Switch", "type": { "name": "elementType" } },
"baseTextField": { "default": "TextField", "type": { "name": "elementType" } },
"baseTooltip": { "default": "Tooltip", "type": { "name": "elementType" } },
Expand Down
1 change: 1 addition & 0 deletions docs/pages/x/api/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
"baseInputLabel": { "default": "InputLabel", "type": { "name": "elementType" } },
"basePopper": { "default": "Popper", "type": { "name": "elementType" } },
"baseSelect": { "default": "Select", "type": { "name": "elementType" } },
"baseSelectOption": { "default": "MenuItem", "type": { "name": "elementType" } },
"baseSwitch": { "default": "Switch", "type": { "name": "elementType" } },
"baseTextField": { "default": "TextField", "type": { "name": "elementType" } },
"baseTooltip": { "default": "Tooltip", "type": { "name": "elementType" } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@
"baseInputLabel": "The custom InputLabel component used in the grid.",
"basePopper": "The custom Popper component used in the grid.",
"baseSelect": "The custom Select component used in the grid.",
"baseSelectOption": "The custom SelectOption component used in the grid.",
"baseSwitch": "The custom Switch component used in the grid.",
"baseTextField": "The custom TextField component used in the grid.",
"baseTooltip": "The custom Tooltip component used in the grid.",
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/data-grid/data-grid-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@
"baseInputLabel": "The custom InputLabel component used in the grid.",
"basePopper": "The custom Popper component used in the grid.",
"baseSelect": "The custom Select component used in the grid.",
"baseSelectOption": "The custom SelectOption component used in the grid.",
"baseSwitch": "The custom Switch component used in the grid.",
"baseTextField": "The custom TextField component used in the grid.",
"baseTooltip": "The custom Tooltip component used in the grid.",
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@
"baseInputLabel": "The custom InputLabel component used in the grid.",
"basePopper": "The custom Popper component used in the grid.",
"baseSelect": "The custom Select component used in the grid.",
"baseSelectOption": "The custom SelectOption component used in the grid.",
"baseSwitch": "The custom Switch component used in the grid.",
"baseTextField": "The custom TextField component used in the grid.",
"baseTooltip": "The custom Tooltip component used in the grid.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils';
import { SelectProps, SelectChangeEvent } from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import { GridRenderEditCellParams } from '../../models/params/gridCellParams';
import { isEscapeKey } from '../../utils/keyboardUtils';
import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
Expand Down Expand Up @@ -131,8 +130,6 @@ function GridEditSingleSelectCell(props: GridEditSingleSelectCellProps) {
setOpen(true);
};

const OptionComponent = isSelectNative ? 'option' : MenuItem;

if (!valueOptions || !colDef) {
return null;
}
Expand All @@ -158,9 +155,14 @@ function GridEditSingleSelectCell(props: GridEditSingleSelectCellProps) {
const value = getOptionValue(valueOption);

return (
<OptionComponent key={value} value={value}>
<rootProps.slots.baseSelectOption
{...(rootProps.slotProps?.baseSelectOption || {})}
native={isSelectNative}
key={value}
value={value}
>
{getOptionLabel(valueOption)}
</OptionComponent>
</rootProps.slots.baseSelectOption>
);
})}
</rootProps.slots.baseSelect>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
unstable_useId as useId,
unstable_capitalize as capitalize,
} from '@mui/utils';
import MenuItem from '@mui/material/MenuItem';
import { SelectChangeEvent } from '@mui/material/Select';
import { styled } from '@mui/material/styles';
import clsx from 'clsx';
Expand Down Expand Up @@ -235,9 +234,9 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>(

const baseSelectProps = rootProps.slotProps?.baseSelect || {};
const isBaseSelectNative = baseSelectProps.native ?? true;
const OptionComponent = isBaseSelectNative ? 'option' : MenuItem;

const baseInputLabelProps = rootProps.slotProps?.baseInputLabel || {};
const baseSelectOptionProps = rootProps.slotProps?.baseSelectOption || {};

const { InputComponentProps, ...valueInputPropsOther } = valueInputProps;

Expand Down Expand Up @@ -428,9 +427,14 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>(
{...rootProps.slotProps?.baseSelect}
>
{logicOperators.map((logicOperator) => (
<OptionComponent key={logicOperator.toString()} value={logicOperator.toString()}>
<rootProps.slots.baseSelectOption
{...baseSelectOptionProps}
native={isBaseSelectNative}
key={logicOperator.toString()}
value={logicOperator.toString()}
>
{apiRef.current.getLocaleText(getLogicOperatorLocaleKey(logicOperator))}
</OptionComponent>
</rootProps.slots.baseSelectOption>
))}
</rootProps.slots.baseSelect>
</FilterFormLogicOperatorInput>
Expand Down Expand Up @@ -463,9 +467,14 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>(
{...rootProps.slotProps?.baseSelect}
>
{sortedFilteredColumns.map((col) => (
<OptionComponent key={col.field} value={col.field}>
<rootProps.slots.baseSelectOption
{...baseSelectOptionProps}
native={isBaseSelectNative}
key={col.field}
value={col.field}
>
{getColumnLabel(col)}
</OptionComponent>
</rootProps.slots.baseSelectOption>
))}
</rootProps.slots.baseSelect>
</FilterFormColumnInput>
Expand Down Expand Up @@ -499,12 +508,17 @@ const GridFilterForm = React.forwardRef<HTMLDivElement, GridFilterFormProps>(
{...rootProps.slotProps?.baseSelect}
>
{currentColumn?.filterOperators?.map((operator) => (
<OptionComponent key={operator.value} value={operator.value}>
<rootProps.slots.baseSelectOption
{...baseSelectOptionProps}
native={isBaseSelectNative}
key={operator.value}
value={operator.value}
>
{operator.label ||
apiRef.current.getLocaleText(
`filterOperator${capitalize(operator.value)}` as 'filterOperatorContains',
)}
</OptionComponent>
</rootProps.slots.baseSelectOption>
))}
</rootProps.slots.baseSelect>
</FilterFormOperatorInput>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import { TextFieldProps } from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import { GridFilterInputValueProps } from './GridFilterInputValueProps';
import { useGridRootProps } from '../../../hooks/utils/useGridRootProps';

Expand All @@ -11,7 +10,8 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi

const baseSelectProps = rootProps.slotProps?.baseSelect || {};
const isSelectNative = baseSelectProps.native ?? true;
const OptionComponent = isSelectNative ? 'option' : MenuItem;

const baseSelectOptionProps = rootProps.slotProps?.baseSelectOption || {};

const onFilterChange = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
Expand All @@ -28,6 +28,7 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi

return (
<rootProps.slots.baseTextField
// TODO: use baseSelect slot
label={apiRef.current.getLocaleText('filterPanelInputLabel')}
value={filterValueState}
onChange={onFilterChange}
Expand All @@ -45,13 +46,23 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi
{...others}
{...rootProps.slotProps?.baseTextField}
>
<OptionComponent value="">{apiRef.current.getLocaleText('filterValueAny')}</OptionComponent>
<OptionComponent value="true">
<rootProps.slots.baseSelectOption {...baseSelectOptionProps} native={isSelectNative} value="">
{apiRef.current.getLocaleText('filterValueAny')}
</rootProps.slots.baseSelectOption>
<rootProps.slots.baseSelectOption
{...baseSelectOptionProps}
native={isSelectNative}
value="true"
>
{apiRef.current.getLocaleText('filterValueTrue')}
</OptionComponent>
<OptionComponent value="false">
</rootProps.slots.baseSelectOption>
<rootProps.slots.baseSelectOption
{...baseSelectOptionProps}
native={isSelectNative}
value="false"
>
{apiRef.current.getLocaleText('filterValueFalse')}
</OptionComponent>
</rootProps.slots.baseSelectOption>
</rootProps.slots.baseTextField>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import { TextFieldProps } from '@mui/material/TextField';
import { unstable_useId as useId } from '@mui/utils';
import MenuItem from '@mui/material/MenuItem';
import { GridFilterInputValueProps } from './GridFilterInputValueProps';
import { GridSingleSelectColDef } from '../../../models/colDef/gridColDef';
import { useGridRootProps } from '../../../hooks/utils/useGridRootProps';
import { getValueFromValueOptions, isSingleSelectColDef } from './filterPanelUtils';

const renderSingleSelectOptions = (
{ valueOptions, field }: GridSingleSelectColDef,
OptionComponent: React.ElementType,
getOptionLabel: NonNullable<GridSingleSelectColDef['getOptionLabel']>,
getOptionValue: NonNullable<GridSingleSelectColDef['getOptionValue']>,
) => {
import type { GridSlotsComponentsProps } from '../../../models/gridSlotsComponentsProps';

const renderSingleSelectOptions = ({
column: { valueOptions, field },
OptionComponent,
getOptionLabel,
getOptionValue,
isSelectNative,
baseSelectOptionProps,
}: {
column: GridSingleSelectColDef;
OptionComponent: React.ElementType;
getOptionLabel: NonNullable<GridSingleSelectColDef['getOptionLabel']>;
getOptionValue: NonNullable<GridSingleSelectColDef['getOptionValue']>;
isSelectNative: boolean;
baseSelectOptionProps: GridSlotsComponentsProps['baseSelectOption'];
}) => {
const iterableColumnValues =
typeof valueOptions === 'function'
? ['', ...valueOptions({ field })]
Expand All @@ -24,7 +33,7 @@ const renderSingleSelectOptions = (
const label = getOptionLabel(option);

return (
<OptionComponent key={value} value={value}>
<OptionComponent {...baseSelectOptionProps} native={isSelectNative} key={value} value={value}>
{label}
</OptionComponent>
);
Expand Down Expand Up @@ -55,6 +64,8 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) {
const baseSelectProps = rootProps.slotProps?.baseSelect || {};
const isSelectNative = baseSelectProps.native ?? true;

const baseSelectOptionProps = rootProps.slotProps?.baseSelectOption || {};

let resolvedColumn: GridSingleSelectColDef | null = null;
if (item.field) {
const column = apiRef.current.getColumn(item.field);
Expand Down Expand Up @@ -117,6 +128,7 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) {

return (
<rootProps.slots.baseTextField
// TODO: use baseSelect slot
id={id}
label={apiRef.current.getLocaleText('filterPanelInputLabel')}
placeholder={apiRef.current.getLocaleText('filterPanelInputPlaceholder')}
Expand All @@ -136,12 +148,14 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) {
{...others}
{...rootProps.slotProps?.baseTextField}
>
{renderSingleSelectOptions(
resolvedColumn,
isSelectNative ? 'option' : MenuItem,
{renderSingleSelectOptions({
column: resolvedColumn,
OptionComponent: rootProps.slots.baseSelectOption,
getOptionLabel,
getOptionValue,
)}
isSelectNative,
baseSelectOptionProps,
})}
</rootProps.slots.baseTextField>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react';
import MUIMenuItem from '@mui/material/MenuItem';
import type { GridSlotsComponentsProps } from '../../models/gridSlotsComponentsProps';

export default function MUISelectOption({
native,
...props
}: NonNullable<GridSlotsComponentsProps['baseSelectOption']>) {
if (native) {
return <option {...props} />;
}
return <MUIMenuItem {...props} />;
}
2 changes: 2 additions & 0 deletions packages/grid/x-data-grid/src/material/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
GridDeleteForeverIcon,
} from './icons';
import type { GridIconSlotsComponent } from '../models';
import MUISelectOption from './components/MUISelectOption';

const iconSlots: GridIconSlotsComponent = {
BooleanCellTrueIcon: GridCheckIcon,
Expand Down Expand Up @@ -88,6 +89,7 @@ const materialSlots = {
BaseTooltip: MUITooltip,
BasePopper: MUIPopper,
BaseInputLabel: MUIInputLabel,
BaseSelectOption: MUISelectOption,
};

export default materialSlots;
5 changes: 5 additions & 0 deletions packages/grid/x-data-grid/src/models/gridSlotsComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export interface GridSlotsComponent extends GridIconSlotsComponent {
* @default InputLabel
*/
BaseInputLabel: React.JSXElementConstructor<any>;
/**
* The custom SelectOption component used in the grid.
* @default MenuItem
*/
BaseSelectOption: React.JSXElementConstructor<any>;
/**
* Component rendered for each cell.
* @default GridCell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface BaseIconButtonPropsOverrides {}
export interface BaseTooltipPropsOverrides {}
export interface BasePopperPropsOverrides {}
export interface BaseInputLabelPropsOverrides {}
export interface BaseSelectOptionPropsOverrides {}
export interface CellPropsOverrides {}
export interface ToolbarPropsOverrides {}
export interface ColumnHeaderFilterIconButtonPropsOverrides {}
Expand Down Expand Up @@ -63,6 +64,10 @@ export interface GridSlotsComponentsProps {
basePopper?: SlotProps<PopperProps, BasePopperPropsOverrides>;
baseTooltip?: SlotProps<TooltipProps, BaseTooltipPropsOverrides>;
baseInputLabel?: SlotProps<InputLabelProps, BaseInputLabelPropsOverrides>;
baseSelectOption?: SlotProps<
{ native: boolean; value: any; children?: React.ReactNode },
BaseSelectOptionPropsOverrides
>;
cell?: SlotProps<GridCellProps, CellPropsOverrides>;
columnHeaderFilterIconButton?: SlotProps<
ColumnHeaderFilterIconButtonProps,
Expand Down
1 change: 1 addition & 0 deletions scripts/x-data-grid-premium.exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{ "name": "BaseIconButtonPropsOverrides", "kind": "Interface" },
{ "name": "BaseInputLabelPropsOverrides", "kind": "Interface" },
{ "name": "BasePopperPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectPropsOverrides", "kind": "Interface" },
{ "name": "BaseSwitchPropsOverrides", "kind": "Interface" },
{ "name": "BaseTextFieldPropsOverrides", "kind": "Interface" },
Expand Down
1 change: 1 addition & 0 deletions scripts/x-data-grid-pro.exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{ "name": "BaseIconButtonPropsOverrides", "kind": "Interface" },
{ "name": "BaseInputLabelPropsOverrides", "kind": "Interface" },
{ "name": "BasePopperPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectPropsOverrides", "kind": "Interface" },
{ "name": "BaseSwitchPropsOverrides", "kind": "Interface" },
{ "name": "BaseTextFieldPropsOverrides", "kind": "Interface" },
Expand Down
1 change: 1 addition & 0 deletions scripts/x-data-grid.exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{ "name": "BaseIconButtonPropsOverrides", "kind": "Interface" },
{ "name": "BaseInputLabelPropsOverrides", "kind": "Interface" },
{ "name": "BasePopperPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectOptionPropsOverrides", "kind": "Interface" },
{ "name": "BaseSelectPropsOverrides", "kind": "Interface" },
{ "name": "BaseSwitchPropsOverrides", "kind": "Interface" },
{ "name": "BaseTextFieldPropsOverrides", "kind": "Interface" },
Expand Down

0 comments on commit 34836e9

Please sign in to comment.