diff --git a/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx index a78afe0dfde9a..4c7a9b7c7322d 100644 --- a/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx +++ b/packages/grid/x-data-grid/src/components/cell/GridEditSingleSelectCell.tsx @@ -12,17 +12,21 @@ import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { GridEditModes } from '../../models/gridEditRowModel'; import { GridEvents } from '../../models/events/gridEvents'; import { GridColDef, ValueOptions } from '../../models/colDef/gridColDef'; +import { getValueFromValueOptions } from '../panel/filterPanel/filterPanelUtils'; -const renderSingleSelectOptions = (option: ValueOptions) => - typeof option === 'object' ? ( - - {option.label} - - ) : ( - - {option} - +const renderSingleSelectOptions = (option: ValueOptions, OptionComponent: React.ElementType) => { + const isOptionTypeObject = typeof option === 'object'; + + const key = isOptionTypeObject ? option.value : option; + const value = isOptionTypeObject ? option.value : option; + const content = isOptionTypeObject ? option.label : option; + + return ( + + {content} + ); +}; function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit) { const { @@ -51,6 +55,9 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit; if (typeof colDef.valueOptions === 'function') { valueOptionsFormatted = colDef.valueOptions!({ id, row, field }); @@ -75,7 +82,9 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit) => { setOpen(false); const target = event.target as HTMLInputElement; - const isValid = await api.setEditCellValue({ id, field, value: target.value }, event); + // NativeSelect casts the value to a string. + const formattedTargetValue = getValueFromValueOptions(target.value, valueOptionsFormatted); + const isValid = await api.setEditCellValue({ id, field, value: formattedTargetValue }, event); if (rootProps.experimentalFeatures?.newEditingApi) { return; @@ -134,11 +143,14 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit - {valueOptionsFormatted.map(renderSingleSelectOptions)} + {valueOptionsFormatted.map((valueOptions) => + renderSingleSelectOptions(valueOptions, isSelectNative ? 'option' : MenuItem), + )} ); } diff --git a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx index cf53ad89018ae..07cf2a65bd779 100644 --- a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx +++ b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx @@ -106,7 +106,7 @@ const GridPanel = React.forwardRef((props, ref) modifiers={modifiers} {...other} > - + {isPlaced && children} diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx index c98cf21a6a98b..fb5e5d29d27dc 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { unstable_composeClasses as composeClasses } from '@mui/material'; import IconButton from '@mui/material/IconButton'; +import MenuItem from '@mui/material/MenuItem'; import InputLabel from '@mui/material/InputLabel'; import FormControl from '@mui/material/FormControl'; import { SelectChangeEvent } from '@mui/material/Select'; @@ -152,6 +153,10 @@ function GridFilterForm(props: GridFilterFormProps) { const baseFormControlProps = rootProps.componentsProps?.baseFormControl || {}; + const baseSelectProps = rootProps.componentsProps?.baseSelect || {}; + const isBaseSelectNative = baseSelectProps.native ?? true; + const OptionComponent = isBaseSelectNative ? 'option' : MenuItem; + const sortedFilterableColumns = React.useMemo(() => { switch (columnsSort) { case 'asc': @@ -314,13 +319,13 @@ function GridFilterForm(props: GridFilterFormProps) { value={multiFilterOperator} onChange={changeLinkOperator} disabled={!!disableMultiFilterOperator || linkOperators.length === 1} - native + native={isBaseSelectNative} {...rootProps.componentsProps?.baseSelect} > {linkOperators.map((linkOperator) => ( - + ))} @@ -344,13 +349,13 @@ function GridFilterForm(props: GridFilterFormProps) { label={apiRef.current.getLocaleText('filterPanelColumns')} value={item.columnField || ''} onChange={changeColumn} - native + native={isBaseSelectNative} {...rootProps.componentsProps?.baseSelect} > {sortedFilterableColumns.map((col) => ( - + ))} @@ -374,17 +379,17 @@ function GridFilterForm(props: GridFilterFormProps) { id={operatorSelectId} value={item.operatorValue} onChange={changeOperator} - native + native={isBaseSelectNative} inputRef={filterSelectorRef} {...rootProps.componentsProps?.baseSelect} > {currentColumn?.filterOperators?.map((operator) => ( - + ))} diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx index 8618a385642bb..453f90aa78079 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputBoolean.tsx @@ -1,5 +1,6 @@ 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'; @@ -8,6 +9,10 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi const [filterValueState, setFilterValueState] = React.useState(item.value || ''); const rootProps = useGridRootProps(); + const baseSelectProps = rootProps.componentsProps?.baseSelect || {}; + const isSelectNative = baseSelectProps.native ?? true; + const OptionComponent = isSelectNative ? 'option' : MenuItem; + const onFilterChange = React.useCallback( (event) => { const value = event.target.value; @@ -29,7 +34,9 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi variant="standard" select SelectProps={{ - native: true, + native: isSelectNative, + displayEmpty: true, + ...rootProps.componentsProps?.baseSelect, }} InputLabelProps={{ shrink: true, @@ -38,9 +45,13 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi {...others} {...rootProps.componentsProps?.baseTextField} > - - - + {apiRef.current.getLocaleText('filterValueAny')} + + {apiRef.current.getLocaleText('filterValueTrue')} + + + {apiRef.current.getLocaleText('filterValueFalse')} + ); } diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx index 5696f5d24eefb..2bb2a55b5aaaa 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputSingleSelect.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { TextFieldProps } from '@mui/material/TextField'; import { unstable_useId as useId } from '@mui/material/utils'; +import MenuItem from '@mui/material/MenuItem'; import { GridFilterInputValueProps } from './GridFilterInputValueProps'; import { GridColDef } from '../../../models/colDef/gridColDef'; import { GridApiCommunity } from '../../../models/api/gridApiCommunity'; @@ -11,23 +12,29 @@ import { getValueFromValueOptions } from './filterPanelUtils'; const renderSingleSelectOptions = ( { valueOptions, valueFormatter, field }: GridColDef, api: GridApiCommunity, + OptionComponent: React.ElementType, ) => { const iterableColumnValues = typeof valueOptions === 'function' ? ['', ...valueOptions({ field })] : ['', ...(valueOptions || [])]; - return iterableColumnValues.map((option) => - typeof option === 'object' ? ( - - ) : ( - - ), - ); + return iterableColumnValues.map((option) => { + const isOptionTypeObject = typeof option === 'object'; + + const key = isOptionTypeObject ? option.value : option; + const value = isOptionTypeObject ? option.value : option; + + const formattedValue = + valueFormatter && option !== '' ? valueFormatter({ value: option, field, api }) : option; + const content = isOptionTypeObject ? option.label : formattedValue; + + return ( + + {content} + + ); + }); }; export type GridFilterInputSingleSelectProps = GridFilterInputValueProps & @@ -39,6 +46,9 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) { const id = useId(); const rootProps = useGridRootProps(); + const baseSelectProps = rootProps.componentsProps?.baseSelect || {}; + const isSelectNative = baseSelectProps.native ?? true; + const currentColumn = item.columnField ? apiRef.current.getColumn(item.columnField) : null; const currentValueOptions = React.useMemo(() => { @@ -94,12 +104,17 @@ function GridFilterInputSingleSelect(props: GridFilterInputSingleSelectProps) { inputRef={focusElementRef} select SelectProps={{ - native: true, + native: isSelectNative, + ...rootProps.componentsProps?.baseSelect, }} {...others} {...rootProps.componentsProps?.baseTextField} > - {renderSingleSelectOptions(apiRef.current.getColumn(item.columnField), apiRef.current)} + {renderSingleSelectOptions( + apiRef.current.getColumn(item.columnField), + apiRef.current, + isSelectNative ? 'option' : MenuItem, + )} ); } diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx index 6477e43d9d41e..97843d2f94dde 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterInputValue.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { TextFieldProps } from '@mui/material/TextField'; import { unstable_useId as useId } from '@mui/material/utils'; +import MenuItem from '@mui/material/MenuItem'; import { GridLoadIcon } from '../../icons'; import { GridFilterInputValueProps } from './GridFilterInputValueProps'; import { GridColDef } from '../../../models/colDef/gridColDef'; @@ -24,23 +25,29 @@ function warnDeprecatedTypeSupport(type: string) { const renderSingleSelectOptions = ( { valueOptions, valueFormatter, field }: GridColDef, api: GridApiCommunity, + OptionComponent: React.ElementType, ) => { const iterableColumnValues = typeof valueOptions === 'function' ? ['', ...valueOptions({ field })] : ['', ...(valueOptions || [])]; - return iterableColumnValues.map((option) => - typeof option === 'object' ? ( - - ) : ( - - ), - ); + return iterableColumnValues.map((option) => { + const isOptionTypeObject = typeof option === 'object'; + + const key = isOptionTypeObject ? option.value : option; + const value = isOptionTypeObject ? option.value : option; + + const formattedValue = + valueFormatter && option !== '' ? valueFormatter({ value: option, field, api }) : option; + const content = isOptionTypeObject ? option.label : formattedValue; + + return ( + + {content} + + ); + }); }; export const SUBMIT_FILTER_STROKE_TIME = 500; @@ -63,16 +70,22 @@ function GridFilterInputValue(props: GridTypeFilterInputValueProps & TextFieldPr const [applying, setIsApplying] = React.useState(false); const id = useId(); const rootProps = useGridRootProps(); + + const baseSelectProps = rootProps.componentsProps?.baseSelect || {}; + const isSelectNative = baseSelectProps.native ?? true; + const singleSelectProps: TextFieldProps = type === 'singleSelect' ? { select: true, SelectProps: { - native: true, + native: isSelectNative, + ...rootProps.componentsProps?.baseSelect, }, children: renderSingleSelectOptions( apiRef.current.getColumn(item.columnField), apiRef.current, + isSelectNative ? 'option' : MenuItem, ), } : {};