Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pickers] New unstable field components #5504

Merged
merged 63 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
a27e983
[POC] New component DateField
flaviendelangle Jul 15, 2022
bfbc627
Work on keyboard edit with numeric value
flaviendelangle Jul 15, 2022
f65cfe5
mend
flaviendelangle Jul 15, 2022
8333afd
Work
flaviendelangle Jul 15, 2022
85e5af2
Work
flaviendelangle Jul 18, 2022
51ab705
Support letter editing (basic) for months
flaviendelangle Jul 18, 2022
03ffed4
Work
flaviendelangle Jul 18, 2022
7afab04
Prettier
flaviendelangle Jul 18, 2022
dc58f12
Work
flaviendelangle Jul 18, 2022
7d2a453
Work on empty values
flaviendelangle Jul 19, 2022
24b1a6c
Continue working on empty value
flaviendelangle Jul 19, 2022
d9994a0
Work
flaviendelangle Jul 19, 2022
5e025e7
Fix
flaviendelangle Jul 19, 2022
be952ae
Fix
flaviendelangle Jul 19, 2022
d1a1ebc
Merge
flaviendelangle Jul 21, 2022
d93acf0
l10n
flaviendelangle Jul 21, 2022
bc2c9cf
Merge branch 'master' into date-field
flaviendelangle Aug 9, 2022
db5c78e
Add basic support for range fields
flaviendelangle Aug 10, 2022
2a2e865
Small improvement
flaviendelangle Aug 10, 2022
599bdc1
Refato
flaviendelangle Aug 10, 2022
9d3a723
Fix lint
flaviendelangle Aug 10, 2022
ffcb865
Improve numeric edition
flaviendelangle Aug 10, 2022
12b3cd1
Work on nullable dates
flaviendelangle Aug 10, 2022
8e4d719
Improve selection behavior
flaviendelangle Aug 10, 2022
c03591b
Work on selection
flaviendelangle Aug 10, 2022
848c857
Update date-io to get addYears method
flaviendelangle Aug 10, 2022
589da3c
Allow to reset the whole date with Backspace
flaviendelangle Aug 10, 2022
663ab1b
Work
flaviendelangle Aug 10, 2022
66012cb
Work
flaviendelangle Aug 10, 2022
99e53b9
Support browser input and unstyled input in doc
flaviendelangle Aug 10, 2022
aae69cf
Work
flaviendelangle Aug 10, 2022
2784dcb
Fix
flaviendelangle Aug 10, 2022
701bbfd
Work
flaviendelangle Aug 10, 2022
37b08ba
Work
flaviendelangle Aug 10, 2022
10d11b9
Merge branch 'master' into date-field
flaviendelangle Aug 10, 2022
a305285
Fix
flaviendelangle Aug 10, 2022
0b01e4b
Allow uncontrolled date field
flaviendelangle Aug 11, 2022
99c649d
Support read-only fields
flaviendelangle Aug 11, 2022
aa77af9
Add multi input date range field
flaviendelangle Aug 11, 2022
58de7f6
Fix
flaviendelangle Aug 11, 2022
6259b53
Fix
flaviendelangle Aug 11, 2022
622c826
Fix
flaviendelangle Aug 11, 2022
f0d35c7
Merge
flaviendelangle Aug 12, 2022
21216fc
Add basic validation to field components
flaviendelangle Aug 12, 2022
b59fa00
Add doc for validation
flaviendelangle Aug 12, 2022
9a52389
Add fields home page
flaviendelangle Aug 12, 2022
c302aea
Work
flaviendelangle Aug 12, 2022
c11d662
Docs ts
flaviendelangle Aug 12, 2022
b4ab68c
Fix
flaviendelangle Aug 12, 2022
8a27cc4
fix maximum day length
alexfauquette Aug 19, 2022
d27ffb4
Update packages/x-date-pickers/src/internals/hooks/useField/useField.ts
flaviendelangle Aug 22, 2022
bdb30ef
Merge
flaviendelangle Aug 22, 2022
c0c8fc2
Work
flaviendelangle Aug 22, 2022
9d71ed9
Rework editing on invalid date
flaviendelangle Aug 22, 2022
6c7fb7e
Fix
flaviendelangle Aug 22, 2022
7a62420
Fix
flaviendelangle Aug 22, 2022
e9ed42f
Fix
flaviendelangle Aug 22, 2022
7b7cc0a
Merge branch 'master' into date-field
flaviendelangle Aug 23, 2022
209409f
Code review: Lukas
flaviendelangle Aug 23, 2022
436d3aa
Fix
flaviendelangle Aug 23, 2022
f288a3f
Merge branch 'master' into date-field
flaviendelangle Aug 23, 2022
37614b8
Work
flaviendelangle Aug 24, 2022
842cf5e
Merge
flaviendelangle Aug 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/data/date-pickers/date-field/BasicDateField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';

export default function BasicDateField() {
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateField label="Basic date field" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow 00?

Screenshot 2022-08-24 at 22 47 14

Maybe we should reset the field when this happens

Screenshot 2022-08-24 at 22 47 18

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know for this one
In Spectrum, if I press 0 it does not write anything, even if the end format will be 01

Press 0 => still render the placeholder (totally ignores the event I think)
Press 1 => renders 01

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow 00?

To be more precise, I was thinking of what would happen when leaving the selection. A native browser seems to turn 00 to 01 when unselecting.

</LocalizationProvider>
);
}
12 changes: 12 additions & 0 deletions docs/data/date-pickers/date-field/BasicDateField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';

export default function BasicDateField() {
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateField label="Basic date field" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End-users need to click twice to be able to select the year. Compare:

Screen.Recording.2022-08-24.at.22.33.21.mov

https://deploy-preview-5504--material-ui-x.netlify.app/x/react-date-pickers/date-field/#basic-usage

With (better):

Screen.Recording.2022-08-24.at.22.35.41.mov

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a known issue
You have the same in Telerik: https://www.telerik.com/kendo-react-ui/components/dateinputs/datepicker/

The problem is that I select all sections on focus.
And when you click, it fires onFocus before onClick.
So when onClick is fired, the focus the selection caused by the focus is already applied, so it clicks on a fully selected input.

And on a fully selected input, I can't find the cursor position of the click, the cursor just moves to the beginning of the input.

One solution would be to delay the selection caused by the focus and to skip it if a click selection has been done in the meanwhile.

Copy link
Member

@oliviertassinari oliviertassinari Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I select all sections on focus

I would dive into this. I think it's where the problem starts:

const handleInputFocus = useEventCallback(() => {
// TODO: Avoid applying focus when focus is caused by a click
updateSelectedSections(0, state.sections.length - 1);
});

Maybe instead of a "select all" on focus, the browser does it automatically when focusing an input with a Tab, we could look at inputRef.current.selectionEnd - inputRef.current.selectionStart. If the value equals 0 it would mean that it wasn't a keyboard focus, it was a click focus with a caret that has no selections. Then, we can look at where the current selection is on, and select the corresponding segment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a PR to improve this behavior #5901

</LocalizationProvider>
);
}
3 changes: 3 additions & 0 deletions docs/data/date-pickers/date-field/BasicDateField.tsx.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateField label="Basic date field" />
</LocalizationProvider>
9 changes: 9 additions & 0 deletions docs/data/date-pickers/date-field/CustomDateField.tsx.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateField
value={value}
onChange={(newValue) => {
setValue(newValue);
}}
variant="standard"
/>
</LocalizationProvider>
46 changes: 46 additions & 0 deletions docs/data/date-pickers/date-field/CustomDateFormat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';
import Stack from '@mui/material/Stack';

export default function CustomDateFormat() {
const [value, setValue] = React.useState(new Date());

return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={2} sx={(theme) => ({ width: theme.spacing(48) })}>
<DateField
label="Dash separator"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd-MM-yyyy"
/>
<DateField
label="Dash and white space separator"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd / MM / yyyy"
/>
<DateField
label="Full letter month"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd MMMM yyyy"
/>
<DateField
label="Date and time format"
value={value}
onChange={(newValue) => setValue(newValue)}
format="Pp"
/>
<DateField
label="Time format"
value={value}
onChange={(newValue) => setValue(newValue)}
format="p"
/>
</Stack>
</LocalizationProvider>
);
}
46 changes: 46 additions & 0 deletions docs/data/date-pickers/date-field/CustomDateFormat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';
import Stack from '@mui/material/Stack';

export default function CustomDateFormat() {
const [value, setValue] = React.useState<Date | null>(new Date());

return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={2} sx={(theme) => ({ width: theme.spacing(48) })}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make the demo easier to scan:

Suggested change
<Stack spacing={2} sx={(theme) => ({ width: theme.spacing(48) })}>
<Stack spacing={2} sx={{ width: 384 })}>

<DateField
label="Dash separator"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd-MM-yyyy"
/>
<DateField
label="Dash and white space separator"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd / MM / yyyy"
/>
<DateField
label="Full letter month"
value={value}
onChange={(newValue) => setValue(newValue)}
format="dd MMMM yyyy"
/>
<DateField
label="Date and time format"
value={value}
onChange={(newValue) => setValue(newValue)}
format="Pp"
/>
<DateField
label="Time format"
value={value}
onChange={(newValue) => setValue(newValue)}
format="p"
/>
</Stack>
</LocalizationProvider>
);
}
48 changes: 48 additions & 0 deletions docs/data/date-pickers/date-field/CustomInputProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';
import Stack from '@mui/material/Stack';
import IconButton from '@mui/material/IconButton';
import CancelIcon from '@mui/icons-material/Close';

export default function CustomInputProps() {
const [value, setValue] = React.useState(new Date());

return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={2} sx={(theme) => ({ width: theme.spacing(48) })}>
<DateField
label="Custom variant"
value={value}
onChange={(newValue) => setValue(newValue)}
variant="filled"
/>
<DateField
label="Disabled"
value={value}
onChange={(newValue) => setValue(newValue)}
disabled
/>
<DateField
label="Read only"
value={value}
onChange={(newValue) => setValue(newValue)}
readOnly
/>
<DateField
label="Clearable"
value={value}
onChange={(newValue) => setValue(newValue)}
InputProps={{
endAdornment: (
<IconButton size="small" onClick={() => setValue(null)}>
<CancelIcon />
</IconButton>
),
}}
/>
</Stack>
</LocalizationProvider>
);
}
48 changes: 48 additions & 0 deletions docs/data/date-pickers/date-field/CustomInputProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { Unstable_DateField as DateField } from '@mui/x-date-pickers/DateField';
import Stack from '@mui/material/Stack';
import IconButton from '@mui/material/IconButton';
import CancelIcon from '@mui/icons-material/Close';

export default function CustomInputProps() {
const [value, setValue] = React.useState<Date | null>(new Date());

return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={2} sx={(theme) => ({ width: theme.spacing(48) })}>
<DateField
label="Custom variant"
value={value}
onChange={(newValue) => setValue(newValue)}
variant="filled"
/>
<DateField
label="Disabled"
value={value}
onChange={(newValue) => setValue(newValue)}
disabled
/>
<DateField
label="Read only"
value={value}
onChange={(newValue) => setValue(newValue)}
readOnly
/>
<DateField
label="Clearable"
value={value}
onChange={(newValue) => setValue(newValue)}
InputProps={{
endAdornment: (
<IconButton size="small" onClick={() => setValue(null)}>
<CancelIcon />
</IconButton>
),
}}
/>
</Stack>
</LocalizationProvider>
);
}
70 changes: 70 additions & 0 deletions docs/data/date-pickers/date-field/CustomUIDateField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Stack from '@mui/material/Stack';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormLabel from '@mui/joy/FormLabel';
import JoyTextField from '@mui/joy/TextField';
import InputUnstyled from '@mui/base/InputUnstyled';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { unstable_useDateField as useDateField } from '@mui/x-date-pickers/DateField';

const JoyDateField = (props) => {
const { inputRef, inputProps } = useDateField(props);

return (
<JoyTextField
{...inputProps}
componentsProps={{ input: { componentsProps: { input: { ref: inputRef } } } }}
/>
);
};

const UnstyledDateField = (props) => {
const { inputRef, inputProps } = useDateField(props);

return (
<InputUnstyled
{...inputProps}
componentsProps={{ input: { ref: inputRef, style: { width: '100%' } } }}
/>
);
};

const BrowserInputDateField = (props) => {
const { inputRef, inputProps } = useDateField(props);

return <input {...inputProps} ref={inputRef} />;
};

export default function CustomUIDateField() {
const [value, setValue] = React.useState(new Date());

const handleChange = (newValue) => setValue(newValue);

return (
<CssVarsProvider>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Stack spacing={2}>
<JoyDateField
label="Using @mui/joy TextField"
value={value}
onChange={handleChange}
/>
<FormControlLabel
label={<FormLabel>Using unstyled input</FormLabel>}
control={<UnstyledDateField value={value} onChange={handleChange} />}
labelPlacement="top"
sx={{ alignItems: 'stretch' }}
/>
<FormControlLabel
label={<FormLabel>Using browser input</FormLabel>}
control={<BrowserInputDateField value={value} onChange={handleChange} />}
labelPlacement="top"
sx={{ alignItems: 'stretch' }}
/>
</Stack>
</LocalizationProvider>
</CssVarsProvider>
);
}
Loading