diff --git a/docs/data/data-grid/custom-columns/CustomColumnFullExample.js b/docs/data/data-grid/custom-columns/CustomColumnFullExample.js
index 5e9f7cef20087..298db79e44586 100644
--- a/docs/data/data-grid/custom-columns/CustomColumnFullExample.js
+++ b/docs/data/data-grid/custom-columns/CustomColumnFullExample.js
@@ -1,4 +1,5 @@
import * as React from 'react';
+import clsx from 'clsx';
import {
generateFilledQuantity,
randomColor,
@@ -9,28 +10,655 @@ import {
randomName,
randomRating,
randomStatusOptions,
- renderAvatar,
- renderCountry,
- renderEditCountry,
- renderEditIncoterm,
- renderEditProgress,
- renderEditRating,
- renderEditStatus,
- renderEmail,
- renderIncoterm,
- renderProgress,
- renderRating,
- renderStatus,
} from '@mui/x-data-grid-generator';
import {
+ COUNTRY_ISO_OPTIONS,
COUNTRY_ISO_OPTIONS_SORTED,
INCOTERM_OPTIONS,
STATUS_OPTIONS,
} from '@mui/x-data-grid-generator/services/static-data';
import { SparkLineChart } from '@mui/x-charts/SparkLineChart';
-import { DataGrid, gridStringOrNumberComparator } from '@mui/x-data-grid';
+import {
+ DataGrid,
+ GridEditModes,
+ gridStringOrNumberComparator,
+ useGridApiContext,
+ useGridRootProps,
+} from '@mui/x-data-grid';
+import {
+ alpha,
+ Autocomplete,
+ autocompleteClasses,
+ Avatar,
+ Box,
+ Chip,
+ debounce,
+ InputBase,
+ ListItemIcon,
+ ListItemText,
+ MenuItem,
+ Rating,
+ Select,
+ Slider,
+ sliderClasses,
+ styled,
+ Tooltip,
+} from '@mui/material';
+import ReportProblemIcon from '@mui/icons-material/ReportProblem';
+import InfoIcon from '@mui/icons-material/Info';
+import AutorenewIcon from '@mui/icons-material/Autorenew';
+import DoneIcon from '@mui/icons-material/Done';
+
+/** Custom components supporting custom renderers */
+const Link = styled('a')({
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ color: 'inherit',
+});
+
+const DemoLink = React.memo(function DemoLink(props) {
+ const handleClick = (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ };
+
+ return (
+
+ {props.children}
+
+ );
+});
+
+const RatingValue = React.memo(function RatingValue(props) {
+ const { value } = props;
+ return (
+
+ {' '}
+ {Math.round(Number(value) * 10) / 10}
+
+ );
+});
+
+const EditRating = (props) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const changedThroughKeyboard = React.useRef(false);
+
+ const handleChange = async (event) => {
+ await apiRef.current.setEditCellValue(
+ { id, field, value: Number(event.target.value) },
+ event,
+ );
+ if (!changedThroughKeyboard.current) {
+ apiRef.current.stopCellEditMode({ id, field });
+ }
+ changedThroughKeyboard.current = false;
+ };
+
+ const handleRef = (element) => {
+ if (element) {
+ if (value !== 0) {
+ element.querySelector(`input[value="${value}"]`).focus();
+ } else {
+ element.querySelector('input[value=""]').focus();
+ }
+ }
+ };
+
+ const handleKeyDown = (event) => {
+ if (event.key.startsWith('Arrow')) {
+ changedThroughKeyboard.current = true;
+ } else {
+ changedThroughKeyboard.current = false;
+ }
+ };
+
+ return (
+
+
+ {Number(value)}
+
+ );
+};
+
+const Country = React.memo(function Country(props) {
+ const { value } = props;
+
+ return (
+ img': {
+ mr: 0.5,
+ flexShrink: 0,
+ width: '20px',
+ },
+ }}
+ >
+
+
+ {value.label}
+
+
+ );
+});
+
+const StyledAutocomplete = styled(Autocomplete)(({ theme }) => ({
+ height: '100%',
+ [`& .${autocompleteClasses.inputRoot}`]: {
+ ...theme.typography.body2,
+ padding: '1px 0',
+ height: '100%',
+ '& input': {
+ padding: '0 16px',
+ height: '100%',
+ },
+ },
+}));
+
+const EditCountry = (props) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const handleChange = React.useCallback(
+ async (event, newValue) => {
+ await apiRef.current.setEditCellValue({ id, field, value: newValue }, event);
+ apiRef.current.stopCellEditMode({ id, field });
+ },
+ [apiRef, field, id],
+ );
+
+ return (
+ option.label}
+ autoHighlight
+ fullWidth
+ open
+ disableClearable
+ renderOption={(optionProps, option) => (
+ img': {
+ mr: 1.5,
+ flexShrink: 0,
+ },
+ }}
+ {...optionProps}
+ >
+
+ {option.label}
+
+ )}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+};
+
+const Center = styled('div')({
+ height: '100%',
+ display: 'flex',
+ alignItems: 'center',
+});
+
+const Element = styled('div')(({ theme }) => ({
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ position: 'relative',
+ overflow: 'hidden',
+ width: '100%',
+ height: 26,
+ borderRadius: 2,
+}));
+
+const Value = styled('div')({
+ position: 'absolute',
+ lineHeight: '24px',
+ width: '100%',
+ display: 'flex',
+ justifyContent: 'center',
+});
+
+const Bar = styled('div')({
+ height: '100%',
+ '&.low': {
+ backgroundColor: '#f44336',
+ },
+ '&.medium': {
+ backgroundColor: '#efbb5aa3',
+ },
+ '&.high': {
+ backgroundColor: '#088208a3',
+ },
+});
+
+const ProgressBar = React.memo(function ProgressBar(props) {
+ const { value } = props;
+ const valueInPercent = value * 100;
+
+ return (
+
+ {`${valueInPercent.toLocaleString()} %`}
+ = 30 && valueInPercent <= 70,
+ high: valueInPercent > 70,
+ })}
+ style={{ maxWidth: `${valueInPercent}%` }}
+ />
+
+ );
+});
+
+const StyledSlider = styled(Slider)(({ theme }) => ({
+ display: 'flex',
+ height: '100%',
+ width: '100%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 0,
+ borderRadius: 0,
+ [`& .${sliderClasses.rail}`]: {
+ height: '100%',
+ backgroundColor: 'transparent',
+ },
+ [`& .${sliderClasses.track}`]: {
+ height: '100%',
+ transition: theme.transitions.create('background-color', {
+ duration: theme.transitions.duration.shorter,
+ }),
+ '&.low': {
+ backgroundColor: '#f44336',
+ },
+ '&.medium': {
+ backgroundColor: '#efbb5aa3',
+ },
+ '&.high': {
+ backgroundColor: '#088208a3',
+ },
+ },
+ [`& .${sliderClasses.thumb}`]: {
+ height: '100%',
+ width: 5,
+ borderRadius: 0,
+ marginTop: 0,
+ backgroundColor: alpha('#000000', 0.2),
+ },
+}));
+
+const ValueLabelComponent = (props) => {
+ const { children, open, value } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+const EditProgress = (props) => {
+ const { id, value, field } = props;
+ const [valueState, setValueState] = React.useState(Number(value));
+
+ const apiRef = useGridApiContext();
+
+ const updateCellEditProps = React.useCallback(
+ (newValue) => {
+ apiRef.current.setEditCellValue({ id, field, value: newValue });
+ },
+ [apiRef, field, id],
+ );
+
+ const debouncedUpdateCellEditProps = React.useMemo(
+ () => debounce(updateCellEditProps, 60),
+ [updateCellEditProps],
+ );
+
+ const handleChange = (event, newValue) => {
+ setValueState(newValue);
+ debouncedUpdateCellEditProps(newValue);
+ };
+
+ React.useEffect(() => {
+ setValueState(Number(value));
+ }, [value]);
+
+ const handleRef = (element) => {
+ if (element) {
+ element.querySelector('[type="range"]').focus();
+ }
+ };
+
+ return (
+ = 0.3 && valueState <= 0.7,
+ high: valueState > 0.7,
+ }),
+ }}
+ value={valueState}
+ max={1}
+ step={0.00001}
+ onChange={handleChange}
+ components={{ ValueLabel: ValueLabelComponent }}
+ valueLabelDisplay="auto"
+ valueLabelFormat={(newValue) => `${(newValue * 100).toLocaleString()} %`}
+ />
+ );
+};
+
+const StyledChip = styled(Chip)(({ theme }) => ({
+ justifyContent: 'left',
+ '& .icon': {
+ color: 'inherit',
+ },
+ '&.Open': {
+ color: (theme.vars || theme).palette.info.dark,
+ border: `1px solid ${(theme.vars || theme).palette.info.main}`,
+ },
+ '&.Filled': {
+ color: (theme.vars || theme).palette.success.dark,
+ border: `1px solid ${(theme.vars || theme).palette.success.main}`,
+ },
+ '&.PartiallyFilled': {
+ color: (theme.vars || theme).palette.warning.dark,
+ border: `1px solid ${(theme.vars || theme).palette.warning.main}`,
+ },
+ '&.Rejected': {
+ color: (theme.vars || theme).palette.error.dark,
+ border: `1px solid ${(theme.vars || theme).palette.error.main}`,
+ },
+}));
+
+const Status = React.memo((props) => {
+ const { status } = props;
-function GridSparklineCell(params) {
+ let icon = null;
+ if (status === 'Rejected') {
+ icon = ;
+ } else if (status === 'Open') {
+ icon = ;
+ } else if (status === 'PartiallyFilled') {
+ icon = ;
+ } else if (status === 'Filled') {
+ icon = ;
+ }
+
+ let label = status;
+ if (status === 'PartiallyFilled') {
+ label = 'Partially Filled';
+ }
+
+ return (
+
+ );
+});
+
+const EditStatus = (props) => {
+ const { id, value, field } = props;
+ const rootProps = useGridRootProps();
+ const apiRef = useGridApiContext();
+
+ const handleChange = async (event) => {
+ const isValid = await apiRef.current.setEditCellValue({
+ id,
+ field,
+ value: event.target.value,
+ });
+
+ if (isValid && rootProps.editMode === GridEditModes.Cell) {
+ apiRef.current.stopCellEditMode({ id, field, cellToFocusAfter: 'below' });
+ }
+ };
+
+ const handleClose = (event, reason) => {
+ if (reason === 'backdropClick') {
+ apiRef.current.stopCellEditMode({ id, field, ignoreModifications: true });
+ }
+ };
+
+ return (
+
+ );
+};
+
+const Incoterm = React.memo(function Incoterm(props) {
+ const { value } = props;
+
+ if (!value) {
+ return null;
+ }
+
+ const valueStr = value.toString();
+ const tooltip = valueStr.slice(valueStr.indexOf('(') + 1, valueStr.indexOf(')'));
+ const code = valueStr.slice(0, valueStr.indexOf('(')).trim();
+
+ return (
+
+ {code}
+
+
+
+
+ );
+});
+
+const EditIncoterm = (props) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const handleChange = async (event) => {
+ await apiRef.current.setEditCellValue(
+ { id, field, value: event.target.value },
+ event,
+ );
+ apiRef.current.stopCellEditMode({ id, field });
+ };
+
+ const handleClose = (event, reason) => {
+ if (reason === 'backdropClick') {
+ apiRef.current.stopCellEditMode({ id, field });
+ }
+ };
+
+ return (
+
+ );
+};
+
+/** Custom cell renderers */
+// Avatar
+function renderAvatar(params) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return (
+
+ {params.value.name.toUpperCase().substring(0, 1)}
+
+ );
+}
+
+// Email
+function renderEmail(params) {
+ const email = params.value ?? '';
+
+ return (
+
+ {email}
+
+ );
+}
+
+// Rating
+function renderRating(params) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditRating(params) {
+ return ;
+}
+
+// Country
+function renderCountry(params) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditCountry(params) {
+ return ;
+}
+
+// Sparkline
+function renderSparkline(params) {
if (params.value == null) {
return '';
}
@@ -44,6 +672,45 @@ function GridSparklineCell(params) {
);
}
+// Progress
+function renderProgress(params) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return (
+
+
+
+ );
+}
+
+function renderEditProgress(params) {
+ return ;
+}
+
+// Status
+function renderStatus(params) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditStatus(params) {
+ return ;
+}
+
+// Incoterm
+function renderIncoterm(params) {
+ return ;
+}
+
+function renderEditIncoterm(params) {
+ return ;
+}
+
const columns = [
{
field: 'name',
@@ -116,7 +783,7 @@ const columns = [
editable: false,
groupable: false,
display: 'flex',
- renderCell: GridSparklineCell,
+ renderCell: renderSparkline,
width: 150,
valueGetter: (value, row) => row.monthlyActivity,
},
diff --git a/docs/data/data-grid/custom-columns/CustomColumnFullExample.tsx b/docs/data/data-grid/custom-columns/CustomColumnFullExample.tsx
index 487b3abe1ab5d..b23b67313e0e8 100644
--- a/docs/data/data-grid/custom-columns/CustomColumnFullExample.tsx
+++ b/docs/data/data-grid/custom-columns/CustomColumnFullExample.tsx
@@ -1,4 +1,5 @@
import * as React from 'react';
+import clsx from 'clsx';
import {
generateFilledQuantity,
randomColor,
@@ -9,20 +10,9 @@ import {
randomName,
randomRating,
randomStatusOptions,
- renderAvatar,
- renderCountry,
- renderEditCountry,
- renderEditIncoterm,
- renderEditProgress,
- renderEditRating,
- renderEditStatus,
- renderEmail,
- renderIncoterm,
- renderProgress,
- renderRating,
- renderStatus,
} from '@mui/x-data-grid-generator';
import {
+ COUNTRY_ISO_OPTIONS,
COUNTRY_ISO_OPTIONS_SORTED,
CountryIsoOption,
INCOTERM_OPTIONS,
@@ -32,11 +22,681 @@ import { SparkLineChart } from '@mui/x-charts/SparkLineChart';
import {
DataGrid,
GridColDef,
+ GridEditModes,
GridRenderCellParams,
+ GridRenderEditCellParams,
gridStringOrNumberComparator,
+ useGridApiContext,
+ useGridRootProps,
} from '@mui/x-data-grid';
+import {
+ alpha,
+ Autocomplete,
+ autocompleteClasses,
+ AutocompleteProps,
+ Avatar,
+ Box,
+ Chip,
+ debounce,
+ InputBase,
+ ListItemIcon,
+ ListItemText,
+ MenuItem,
+ MenuProps,
+ Rating,
+ Select,
+ SelectProps,
+ Slider,
+ sliderClasses,
+ SliderProps,
+ styled,
+ Tooltip,
+} from '@mui/material';
+import ReportProblemIcon from '@mui/icons-material/ReportProblem';
+import InfoIcon from '@mui/icons-material/Info';
+import AutorenewIcon from '@mui/icons-material/Autorenew';
+import DoneIcon from '@mui/icons-material/Done';
+
+interface DemoLinkProps {
+ href: string;
+ children: string;
+ tabIndex: number;
+}
+
+interface RatingValueProps {
+ value: number;
+}
+
+interface CountryProps {
+ value: CountryIsoOption;
+}
+
+interface ProgressBarProps {
+ value: number;
+}
+
+interface StatusProps {
+ status: string;
+}
+
+interface IncotermProps {
+ value: string | null | undefined;
+}
+
+/** Custom components supporting custom renderers */
+const Link = styled('a')({
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ color: 'inherit',
+});
+
+const DemoLink = React.memo(function DemoLink(props: DemoLinkProps) {
+ const handleClick = (event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+ };
+
+ return (
+
+ {props.children}
+
+ );
+});
+
+const RatingValue = React.memo(function RatingValue(props: RatingValueProps) {
+ const { value } = props;
+ return (
+
+ {' '}
+ {Math.round(Number(value) * 10) / 10}
+
+ );
+});
+
+const EditRating = (props: GridRenderEditCellParams) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const changedThroughKeyboard = React.useRef(false);
+
+ const handleChange = async (event: any) => {
+ await apiRef.current.setEditCellValue(
+ { id, field, value: Number(event.target.value) },
+ event,
+ );
+ if (!changedThroughKeyboard.current) {
+ apiRef.current.stopCellEditMode({ id, field });
+ }
+ changedThroughKeyboard.current = false;
+ };
+
+ const handleRef = (element: HTMLElement | undefined) => {
+ if (element) {
+ if (value !== 0) {
+ element.querySelector(`input[value="${value}"]`)!.focus();
+ } else {
+ element.querySelector('input[value=""]')!.focus();
+ }
+ }
+ };
+
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key.startsWith('Arrow')) {
+ changedThroughKeyboard.current = true;
+ } else {
+ changedThroughKeyboard.current = false;
+ }
+ };
+
+ return (
+
+
+ {Number(value)}
+
+ );
+};
+
+const Country = React.memo(function Country(props: CountryProps) {
+ const { value } = props;
+
+ return (
+ img': {
+ mr: 0.5,
+ flexShrink: 0,
+ width: '20px',
+ },
+ }}
+ >
+
+
+ {value.label}
+
+
+ );
+});
+
+const StyledAutocomplete = styled(Autocomplete)(({ theme }) => ({
+ height: '100%',
+ [`& .${autocompleteClasses.inputRoot}`]: {
+ ...theme.typography.body2,
+ padding: '1px 0',
+ height: '100%',
+ '& input': {
+ padding: '0 16px',
+ height: '100%',
+ },
+ },
+})) as typeof Autocomplete;
+
+const EditCountry = (props: GridRenderEditCellParams) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const handleChange = React.useCallback<
+ NonNullable['onChange']>
+ >(
+ async (event, newValue) => {
+ await apiRef.current.setEditCellValue({ id, field, value: newValue }, event);
+ apiRef.current.stopCellEditMode({ id, field });
+ },
+ [apiRef, field, id],
+ );
+
+ return (
+
+ value={value}
+ onChange={handleChange}
+ options={COUNTRY_ISO_OPTIONS}
+ getOptionLabel={(option: any) => option.label}
+ autoHighlight
+ fullWidth
+ open
+ disableClearable
+ renderOption={(optionProps, option: any) => (
+ img': {
+ mr: 1.5,
+ flexShrink: 0,
+ },
+ }}
+ {...optionProps}
+ >
+
+ {option.label}
+
+ )}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+};
+
+const Center = styled('div')({
+ height: '100%',
+ display: 'flex',
+ alignItems: 'center',
+});
+
+const Element = styled('div')(({ theme }) => ({
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ position: 'relative',
+ overflow: 'hidden',
+ width: '100%',
+ height: 26,
+ borderRadius: 2,
+}));
+
+const Value = styled('div')({
+ position: 'absolute',
+ lineHeight: '24px',
+ width: '100%',
+ display: 'flex',
+ justifyContent: 'center',
+});
+
+const Bar = styled('div')({
+ height: '100%',
+ '&.low': {
+ backgroundColor: '#f44336',
+ },
+ '&.medium': {
+ backgroundColor: '#efbb5aa3',
+ },
+ '&.high': {
+ backgroundColor: '#088208a3',
+ },
+});
+
+const ProgressBar = React.memo(function ProgressBar(props: ProgressBarProps) {
+ const { value } = props;
+ const valueInPercent = value * 100;
+
+ return (
+
+ {`${valueInPercent.toLocaleString()} %`}
+ = 30 && valueInPercent <= 70,
+ high: valueInPercent > 70,
+ })}
+ style={{ maxWidth: `${valueInPercent}%` }}
+ />
+
+ );
+});
+
+const StyledSlider = styled(Slider)(({ theme }) => ({
+ display: 'flex',
+ height: '100%',
+ width: '100%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 0,
+ borderRadius: 0,
+ [`& .${sliderClasses.rail}`]: {
+ height: '100%',
+ backgroundColor: 'transparent',
+ },
+ [`& .${sliderClasses.track}`]: {
+ height: '100%',
+ transition: theme.transitions.create('background-color', {
+ duration: theme.transitions.duration.shorter,
+ }),
+ '&.low': {
+ backgroundColor: '#f44336',
+ },
+ '&.medium': {
+ backgroundColor: '#efbb5aa3',
+ },
+ '&.high': {
+ backgroundColor: '#088208a3',
+ },
+ },
+ [`& .${sliderClasses.thumb}`]: {
+ height: '100%',
+ width: 5,
+ borderRadius: 0,
+ marginTop: 0,
+ backgroundColor: alpha('#000000', 0.2),
+ },
+}));
+
+const ValueLabelComponent = (props: any) => {
+ const { children, open, value } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+const EditProgress = (props: GridRenderEditCellParams) => {
+ const { id, value, field } = props;
+ const [valueState, setValueState] = React.useState(Number(value));
+
+ const apiRef = useGridApiContext();
+
+ const updateCellEditProps = React.useCallback(
+ (newValue: number) => {
+ apiRef.current.setEditCellValue({ id, field, value: newValue });
+ },
+ [apiRef, field, id],
+ );
+
+ const debouncedUpdateCellEditProps = React.useMemo(
+ () => debounce(updateCellEditProps, 60),
+ [updateCellEditProps],
+ );
+
+ const handleChange = (event: Event, newValue: number | number[]) => {
+ setValueState(newValue as number);
+ debouncedUpdateCellEditProps(newValue as number);
+ };
+
+ React.useEffect(() => {
+ setValueState(Number(value));
+ }, [value]);
+
+ const handleRef: SliderProps['ref'] = (element) => {
+ if (element) {
+ element.querySelector('[type="range"]')!.focus();
+ }
+ };
+
+ return (
+ = 0.3 && valueState <= 0.7,
+ high: valueState > 0.7,
+ }),
+ }}
+ value={valueState}
+ max={1}
+ step={0.00001}
+ onChange={handleChange}
+ components={{ ValueLabel: ValueLabelComponent }}
+ valueLabelDisplay="auto"
+ valueLabelFormat={(newValue) => `${(newValue * 100).toLocaleString()} %`}
+ />
+ );
+};
+
+const StyledChip = styled(Chip)(({ theme }) => ({
+ justifyContent: 'left',
+ '& .icon': {
+ color: 'inherit',
+ },
+ '&.Open': {
+ color: (theme.vars || theme).palette.info.dark,
+ border: `1px solid ${(theme.vars || theme).palette.info.main}`,
+ },
+ '&.Filled': {
+ color: (theme.vars || theme).palette.success.dark,
+ border: `1px solid ${(theme.vars || theme).palette.success.main}`,
+ },
+ '&.PartiallyFilled': {
+ color: (theme.vars || theme).palette.warning.dark,
+ border: `1px solid ${(theme.vars || theme).palette.warning.main}`,
+ },
+ '&.Rejected': {
+ color: (theme.vars || theme).palette.error.dark,
+ border: `1px solid ${(theme.vars || theme).palette.error.main}`,
+ },
+}));
+
+const Status = React.memo((props: StatusProps) => {
+ const { status } = props;
+
+ let icon: any = null;
+ if (status === 'Rejected') {
+ icon = ;
+ } else if (status === 'Open') {
+ icon = ;
+ } else if (status === 'PartiallyFilled') {
+ icon = ;
+ } else if (status === 'Filled') {
+ icon = ;
+ }
+
+ let label: string = status;
+ if (status === 'PartiallyFilled') {
+ label = 'Partially Filled';
+ }
+
+ return (
+
+ );
+});
+
+const EditStatus = (props: GridRenderEditCellParams) => {
+ const { id, value, field } = props;
+ const rootProps = useGridRootProps();
+ const apiRef = useGridApiContext();
+
+ const handleChange: SelectProps['onChange'] = async (event) => {
+ const isValid = await apiRef.current.setEditCellValue({
+ id,
+ field,
+ value: event.target.value,
+ });
+
+ if (isValid && rootProps.editMode === GridEditModes.Cell) {
+ apiRef.current.stopCellEditMode({ id, field, cellToFocusAfter: 'below' });
+ }
+ };
+
+ const handleClose: MenuProps['onClose'] = (event, reason) => {
+ if (reason === 'backdropClick') {
+ apiRef.current.stopCellEditMode({ id, field, ignoreModifications: true });
+ }
+ };
+
+ return (
+
+ );
+};
+
+const Incoterm = React.memo(function Incoterm(props: IncotermProps) {
+ const { value } = props;
+
+ if (!value) {
+ return null;
+ }
+
+ const valueStr = value.toString();
+ const tooltip = valueStr.slice(valueStr.indexOf('(') + 1, valueStr.indexOf(')'));
+ const code = valueStr.slice(0, valueStr.indexOf('(')).trim();
+
+ return (
+
+ {code}
+
+
+
+
+ );
+});
+
+const EditIncoterm = (props: GridRenderEditCellParams) => {
+ const { id, value, field } = props;
+
+ const apiRef = useGridApiContext();
+
+ const handleChange: SelectProps['onChange'] = async (event) => {
+ await apiRef.current.setEditCellValue(
+ { id, field, value: event.target.value as any },
+ event,
+ );
+ apiRef.current.stopCellEditMode({ id, field });
+ };
+
+ const handleClose: MenuProps['onClose'] = (event, reason) => {
+ if (reason === 'backdropClick') {
+ apiRef.current.stopCellEditMode({ id, field });
+ }
+ };
+
+ return (
+
+ );
+};
+
+/** Custom cell renderers */
+// Avatar
+function renderAvatar(
+ params: GridRenderCellParams<{ name: string; color: string }, any, any>,
+) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return (
+
+ {params.value.name.toUpperCase().substring(0, 1)}
+
+ );
+}
+
+// Email
+function renderEmail(params: GridRenderCellParams) {
+ const email = params.value ?? '';
+
+ return (
+
+ {email}
+
+ );
+}
+
+// Rating
+function renderRating(params: GridRenderCellParams) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditRating(params: GridRenderEditCellParams) {
+ return ;
+}
+
+// Country
+function renderCountry(params: GridRenderCellParams) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditCountry(params: GridRenderEditCellParams) {
+ return ;
+}
-function GridSparklineCell(params: GridRenderCellParams) {
+// Sparkline
+function renderSparkline(params: GridRenderCellParams) {
if (params.value == null) {
return '';
}
@@ -50,6 +710,45 @@ function GridSparklineCell(params: GridRenderCellParams) {
);
}
+// Progress
+function renderProgress(params: GridRenderCellParams) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return (
+
+
+
+ );
+}
+
+function renderEditProgress(params: GridRenderEditCellParams) {
+ return ;
+}
+
+// Status
+function renderStatus(params: GridRenderCellParams) {
+ if (params.value == null) {
+ return '';
+ }
+
+ return ;
+}
+
+function renderEditStatus(params: GridRenderEditCellParams) {
+ return ;
+}
+
+// Incoterm
+function renderIncoterm(params: GridRenderCellParams) {
+ return ;
+}
+
+function renderEditIncoterm(params: GridRenderEditCellParams) {
+ return ;
+}
+
const columns: GridColDef<(typeof rows)[number]>[] = [
{
field: 'name',
@@ -122,7 +821,7 @@ const columns: GridColDef<(typeof rows)[number]>[] = [
editable: false,
groupable: false,
display: 'flex',
- renderCell: GridSparklineCell,
+ renderCell: renderSparkline,
width: 150,
valueGetter: (value, row) => row.monthlyActivity,
},