Skip to content

Commit 8105170

Browse files
Merge branch 'master' into remove-utils-and-value-params-from-translations
2 parents 28c4417 + 5619497 commit 8105170

File tree

48 files changed

+620
-136
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+620
-136
lines changed

docs/data/data-grid/column-definition/AutogeneratedRows.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import * as React from 'react';
22
import {
33
DataGridPremium,
4+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
45
isAutogeneratedRow,
56
useGridApiRef,
67
useKeepGroupedColumnsHidden,
78
} from '@mui/x-data-grid-premium';
89
import { useMovieData } from '@mui/x-data-grid-generator';
910

1011
const columns = [
11-
{ field: '__row_group_by_columns_group__', width: 200 },
12+
{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, width: 200 },
1213
{ field: 'company', width: 200 },
1314
{
1415
field: 'title',

docs/data/data-grid/column-definition/AutogeneratedRows.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import {
33
DataGridPremium,
4+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
45
GridColDef,
56
isAutogeneratedRow,
67
useGridApiRef,
@@ -9,7 +10,7 @@ import {
910
import { useMovieData } from '@mui/x-data-grid-generator';
1011

1112
const columns: GridColDef[] = [
12-
{ field: '__row_group_by_columns_group__', width: 200 },
13+
{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, width: 200 },
1314
{ field: 'company', width: 200 },
1415
{
1516
field: 'title',

docs/data/data-grid/column-visibility/ColumnSelectorGridCustomizeColumns.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import {
44
GridToolbar,
55
useKeepGroupedColumnsHidden,
66
useGridApiRef,
7+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
78
} from '@mui/x-data-grid-premium';
89
import { useDemoData } from '@mui/x-data-grid-generator';
910

10-
const hiddenFields = ['id', '__row_group_by_columns_group__', 'status'];
11+
const hiddenFields = ['id', GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, 'status'];
1112

1213
const getTogglableColumns = (columns) => {
1314
return columns

docs/data/data-grid/column-visibility/ColumnSelectorGridCustomizeColumns.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import {
55
GridColDef,
66
useKeepGroupedColumnsHidden,
77
useGridApiRef,
8+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
89
} from '@mui/x-data-grid-premium';
910
import { useDemoData } from '@mui/x-data-grid-generator';
1011

11-
const hiddenFields = ['id', '__row_group_by_columns_group__', 'status'];
12+
const hiddenFields = ['id', GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, 'status'];
1213

1314
const getTogglableColumns = (columns: GridColDef[]) => {
1415
return columns

docs/data/data-grid/column-visibility/column-visibility.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,21 @@ In the following demo, the columns panel is disabled, and access to columns `id`
8686
To show or hide specific columns in the column visibility panel, use the `slotProps.columnsManagement.getTogglableColumns` prop. It should return an array of column field names.
8787

8888
```tsx
89-
// stop `id`, `__row_group_by_columns_group__`, and `status` columns to be togglable
90-
const hiddenFields = ['id', '__row_group_by_columns_group__', 'status'];
89+
import {
90+
DataGridPremium,
91+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
92+
} from '@mui/x-data-grid-premium';
93+
94+
// stop `id`, GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, and `status` columns to be togglable
95+
const hiddenFields = ['id', GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, 'status'];
9196

9297
const getTogglableColumns = (columns: GridColDef[]) => {
9398
return columns
9499
.filter((column) => !hiddenFields.includes(column.field))
95100
.map((column) => column.field);
96101
};
97102

98-
<DataGrid
103+
<DataGridPremium
99104
slots={{
100105
toolbar: GridToolbar,
101106
}}

docs/data/data-grid/overview/DataGridPremiumDemo.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import Box from '@mui/material/Box';
33
import {
44
DataGridPremium,
5+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
56
GridToolbar,
67
useGridApiRef,
78
useKeepGroupedColumnsHidden,
@@ -40,7 +41,7 @@ export default function DataGridPremiumDemo() {
4041
model: ['commodity'],
4142
},
4243
sorting: {
43-
sortModel: [{ field: '__row_group_by_columns_group__', sort: 'asc' }],
44+
sortModel: [{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, sort: 'asc' }],
4445
},
4546
aggregation: {
4647
model: {

docs/data/data-grid/overview/DataGridPremiumDemo.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import Box from '@mui/material/Box';
33
import {
44
DataGridPremium,
5+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
56
GridToolbar,
67
useGridApiRef,
78
useKeepGroupedColumnsHidden,
@@ -40,7 +41,7 @@ export default function DataGridPremiumDemo() {
4041
model: ['commodity'],
4142
},
4243
sorting: {
43-
sortModel: [{ field: '__row_group_by_columns_group__', sort: 'asc' }],
44+
sortModel: [{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, sort: 'asc' }],
4445
},
4546
aggregation: {
4647
model: {

docs/data/data-grid/row-grouping/RowGroupingFullExample.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import {
33
DataGridPremium,
4+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
45
useGridApiRef,
56
useKeepGroupedColumnsHidden,
67
} from '@mui/x-data-grid-premium';
@@ -23,7 +24,7 @@ export default function RowGroupingFullExample() {
2324
model: ['commodity'],
2425
},
2526
sorting: {
26-
sortModel: [{ field: '__row_group_by_columns_group__', sort: 'asc' }],
27+
sortModel: [{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, sort: 'asc' }],
2728
},
2829
},
2930
});

docs/data/data-grid/row-grouping/RowGroupingFullExample.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import {
33
DataGridPremium,
4+
GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD,
45
useGridApiRef,
56
useKeepGroupedColumnsHidden,
67
} from '@mui/x-data-grid-premium';
@@ -23,7 +24,7 @@ export default function RowGroupingFullExample() {
2324
model: ['commodity'],
2425
},
2526
sorting: {
26-
sortModel: [{ field: '__row_group_by_columns_group__', sort: 'asc' }],
27+
sortModel: [{ field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, sort: 'asc' }],
2728
},
2829
},
2930
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import * as React from 'react';
2+
import dayjs from 'dayjs';
3+
import { useRifm } from 'rifm';
4+
import TextField from '@mui/material/TextField';
5+
import useControlled from '@mui/utils/useControlled';
6+
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
7+
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
8+
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
9+
import { useSplitFieldProps, useParsedFormat } from '@mui/x-date-pickers/hooks';
10+
import { useValidation, validateDate } from '@mui/x-date-pickers/validation';
11+
12+
const MASK_USER_INPUT_SYMBOL = '_';
13+
const ACCEPT_REGEX = /[\d]/gi;
14+
15+
const staticDateWith2DigitTokens = dayjs('2019-11-21T11:30:00.000');
16+
const staticDateWith1DigitTokens = dayjs('2019-01-01T09:00:00.000');
17+
18+
function getValueStrFromValue(value, format) {
19+
if (value == null) {
20+
return '';
21+
}
22+
23+
return value.isValid() ? value.format(format) : '';
24+
}
25+
26+
function MaskedField(props) {
27+
const { slots, slotProps, ...other } = props;
28+
29+
const { forwardedProps, internalProps } = useSplitFieldProps(other, 'date');
30+
31+
const {
32+
format,
33+
value: valueProp,
34+
defaultValue,
35+
onChange,
36+
timezone,
37+
onError,
38+
} = internalProps;
39+
40+
const [value, setValue] = useControlled({
41+
controlled: valueProp,
42+
default: defaultValue ?? null,
43+
name: 'MaskedField',
44+
state: 'value',
45+
});
46+
47+
// Control the input text
48+
const [inputValue, setInputValue] = React.useState(() =>
49+
getValueStrFromValue(value, format),
50+
);
51+
52+
React.useEffect(() => {
53+
if (value && value.isValid()) {
54+
const newDisplayDate = getValueStrFromValue(value, format);
55+
setInputValue(newDisplayDate);
56+
}
57+
}, [format, value]);
58+
59+
const parsedFormat = useParsedFormat(internalProps);
60+
61+
const { hasValidationError, getValidationErrorForNewValue } = useValidation({
62+
value,
63+
timezone,
64+
onError,
65+
props: internalProps,
66+
validator: validateDate,
67+
});
68+
69+
const handleValueStrChange = (newValueStr) => {
70+
setInputValue(newValueStr);
71+
72+
const newValue = dayjs(newValueStr, format);
73+
setValue(newValue);
74+
75+
if (onChange) {
76+
onChange(newValue, {
77+
validationError: getValidationErrorForNewValue(newValue),
78+
});
79+
}
80+
};
81+
82+
const rifmFormat = React.useMemo(() => {
83+
const formattedDateWith1Digit = staticDateWith1DigitTokens.format(format);
84+
const inferredFormatPatternWith1Digits = formattedDateWith1Digit.replace(
85+
ACCEPT_REGEX,
86+
MASK_USER_INPUT_SYMBOL,
87+
);
88+
const inferredFormatPatternWith2Digits = staticDateWith2DigitTokens
89+
.format(format)
90+
.replace(ACCEPT_REGEX, '_');
91+
92+
if (inferredFormatPatternWith1Digits !== inferredFormatPatternWith2Digits) {
93+
throw new Error(
94+
`Mask does not support numbers with variable length such as 'M'.`,
95+
);
96+
}
97+
98+
const maskToUse = inferredFormatPatternWith1Digits;
99+
100+
return function formatMaskedDate(valueToFormat) {
101+
let outputCharIndex = 0;
102+
return valueToFormat
103+
.split('')
104+
.map((character, characterIndex) => {
105+
ACCEPT_REGEX.lastIndex = 0;
106+
107+
if (outputCharIndex > maskToUse.length - 1) {
108+
return '';
109+
}
110+
111+
const maskChar = maskToUse[outputCharIndex];
112+
const nextMaskChar = maskToUse[outputCharIndex + 1];
113+
114+
const acceptedChar = ACCEPT_REGEX.test(character) ? character : '';
115+
const formattedChar =
116+
maskChar === MASK_USER_INPUT_SYMBOL
117+
? acceptedChar
118+
: maskChar + acceptedChar;
119+
120+
outputCharIndex += formattedChar.length;
121+
122+
const isLastCharacter = characterIndex === valueToFormat.length - 1;
123+
if (
124+
isLastCharacter &&
125+
nextMaskChar &&
126+
nextMaskChar !== MASK_USER_INPUT_SYMBOL
127+
) {
128+
// when cursor at the end of mask part (e.g. month) prerender next symbol "21" -> "21/"
129+
return formattedChar ? formattedChar + nextMaskChar : '';
130+
}
131+
132+
return formattedChar;
133+
})
134+
.join('');
135+
};
136+
}, [format]);
137+
138+
const rifmProps = useRifm({
139+
value: inputValue,
140+
onChange: handleValueStrChange,
141+
format: rifmFormat,
142+
});
143+
144+
return (
145+
<TextField
146+
placeholder={parsedFormat}
147+
error={!!hasValidationError}
148+
{...rifmProps}
149+
{...forwardedProps}
150+
/>
151+
);
152+
}
153+
154+
function MaskedFieldDatePicker(props) {
155+
return <DatePicker slots={{ ...props.slots, field: MaskedField }} {...props} />;
156+
}
157+
158+
export default function MaskedMaterialTextField() {
159+
return (
160+
<LocalizationProvider dateAdapter={AdapterDayjs}>
161+
<MaskedFieldDatePicker />
162+
</LocalizationProvider>
163+
);
164+
}

0 commit comments

Comments
 (0)