Skip to content

Commit

Permalink
[DataGrid] Enable using non-native Select in filter panel (mui#4361)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyeongsoosoo authored and alexfauquette committed Aug 26, 2022
1 parent 3f071e9 commit 5f42c8d
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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' ? (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
) : (
<MenuItem key={option} value={option}>
{option}
</MenuItem>
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 (
<OptionComponent key={key} value={value}>
{content}
</OptionComponent>
);
};

function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit<SelectProps, 'id'>) {
const {
Expand Down Expand Up @@ -51,6 +55,9 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit<SelectP
const rootProps = useGridRootProps();
const [open, setOpen] = React.useState(rootProps.editMode === 'cell');

const baseSelectProps = rootProps.componentsProps?.baseSelect || {};
const isSelectNative = baseSelectProps.native ?? false;

let valueOptionsFormatted: Array<ValueOptions>;
if (typeof colDef.valueOptions === 'function') {
valueOptionsFormatted = colDef.valueOptions!({ id, row, field });
Expand All @@ -75,7 +82,9 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit<SelectP
const handleChange = async (event: React.KeyboardEvent<HTMLInputElement>) => {
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;
Expand Down Expand Up @@ -134,11 +143,14 @@ function GridEditSingleSelectCell(props: GridRenderEditCellParams & Omit<SelectP
onClose: handleClose,
}}
error={error}
native={isSelectNative}
fullWidth
{...other}
{...rootProps.componentsProps?.baseSelect}
>
{valueOptionsFormatted.map(renderSingleSelectOptions)}
{valueOptionsFormatted.map((valueOptions) =>
renderSingleSelectOptions(valueOptions, isSelectNative ? 'option' : MenuItem),
)}
</rootProps.components.BaseSelect>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const GridPanel = React.forwardRef<HTMLDivElement, GridPanelProps>((props, ref)
modifiers={modifiers}
{...other}
>
<ClickAwayListener onClickAway={handleClickAway}>
<ClickAwayListener mouseEvent="onMouseUp" onClickAway={handleClickAway}>
<GridPaperRoot className={classes.paper} elevation={8} onKeyDown={handleKeyDown}>
{isPlaced && children}
</GridPaperRoot>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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) => (
<option key={linkOperator.toString()} value={linkOperator.toString()}>
<OptionComponent key={linkOperator.toString()} value={linkOperator.toString()}>
{apiRef.current.getLocaleText(getLinkOperatorLocaleKey(linkOperator))}
</option>
</OptionComponent>
))}
</rootProps.components.BaseSelect>
</FilterFormLinkOperatorInput>
Expand All @@ -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) => (
<option key={col.field} value={col.field}>
<OptionComponent key={col.field} value={col.field}>
{getColumnLabel(col)}
</option>
</OptionComponent>
))}
</rootProps.components.BaseSelect>
</FilterFormColumnInput>
Expand All @@ -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) => (
<option key={operator.value} value={operator.value}>
<OptionComponent key={operator.value} value={operator.value}>
{operator.label ||
apiRef.current.getLocaleText(
`filterOperator${capitalize(operator.value)}` as GridTranslationKeys,
)}
</option>
</OptionComponent>
))}
</rootProps.components.BaseSelect>
</FilterFormOperatorInput>
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -38,9 +45,13 @@ export function GridFilterInputBoolean(props: GridFilterInputValueProps & TextFi
{...others}
{...rootProps.componentsProps?.baseTextField}
>
<option value="">{apiRef.current.getLocaleText('filterValueAny')}</option>
<option value="true">{apiRef.current.getLocaleText('filterValueTrue')}</option>
<option value="false">{apiRef.current.getLocaleText('filterValueFalse')}</option>
<OptionComponent value="">{apiRef.current.getLocaleText('filterValueAny')}</OptionComponent>
<OptionComponent value="true">
{apiRef.current.getLocaleText('filterValueTrue')}
</OptionComponent>
<OptionComponent value="false">
{apiRef.current.getLocaleText('filterValueFalse')}
</OptionComponent>
</rootProps.components.BaseTextField>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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' ? (
<option key={option.value} value={option.value}>
{option.label}
</option>
) : (
<option key={option} value={option}>
{valueFormatter && option !== '' ? valueFormatter({ value: option, field, api }) : option}
</option>
),
);
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 (
<OptionComponent key={key} value={value}>
{content}
</OptionComponent>
);
});
};

export type GridFilterInputSingleSelectProps = GridFilterInputValueProps &
Expand All @@ -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(() => {
Expand Down Expand Up @@ -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,
)}
</rootProps.components.BaseTextField>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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' ? (
<option key={option.value} value={option.value}>
{option.label}
</option>
) : (
<option key={option} value={option}>
{valueFormatter && option !== '' ? valueFormatter({ value: option, field, api }) : option}
</option>
),
);
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 (
<OptionComponent key={key} value={value}>
{content}
</OptionComponent>
);
});
};

export const SUBMIT_FILTER_STROKE_TIME = 500;
Expand All @@ -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,
),
}
: {};
Expand Down

0 comments on commit 5f42c8d

Please sign in to comment.