mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
3.95k stars 1.21k forks source link

[pickers] Masking is broken with `MM/yyyy` format and views prop #4664

Closed benjamin-andersen closed 1 year ago

benjamin-andersen commented 2 years ago

Duplicates

Latest version

Current behavior 😯

When using the inputFormat prop set to 'MM/yyyy', the masking is broken. Adding a custom rifm formatter doesn't seem to help.

https://user-images.githubusercontent.com/70706530/150567891-60b109ae-92ac-419a-9d94-6cd4e05c0554.mp4

Expected behavior 🤔

The masking shouldn't break when using a 'MM/yyyy' format.

Steps to reproduce 🕹

This was forked from the official template for the basic example of date picker usage:

https://codesandbox.io/s/basicdatepicker-material-demo-forked-2ey8d?file=/demo.tsx

Context 🔦

I'm trying to have my date formatted like 'MM/yyyy'. Examples are:

Your environment 🌎

Was reproduced on the mui template from code sandbox (see above).

miguelCT commented 2 years ago

If you add manually the mask prop:

mask="__/____"

supposedly it should apply the mask. But I found that the prop views is the one that seems to be breaking the masking. If you remove the views prop, the mask will work as expected.

I editted your sandbox with the changes I mentioned: https://codesandbox.io/s/basicdatepicker-material-demo-forked-m2n36?file=/demo.tsx:471-542

Obviously this is not a solution, but I just wanted to point out, that the problem could be related to the views prop.

thomas-kahn commented 2 years ago

I've made the same observation as @miguelCT. I saw in another discussion that when the views prop is set to ['year', 'month'] without any format applied, it defaults to the year in digits and the month in text (month name according to locale). This means that applying a mask would be hard since the length of the months' name vary depending on month and language.

So my guess is that there's a rule somewhere that disables the mask when year is set to ['year', 'month']. And maybe the bug is that the mask is disabled even though the user has specified a format where you do know the exact length of the date (in my case yyyy-MM).

rdanielmurphy commented 2 years ago

So my guess is that there's a rule somewhere that disables the mask when year is set to ['year', 'month']. And maybe the bug is that the mask is disabled even though the user has specified a format where you do know the exact length of the date (in my case yyyy-MM).

This might be the rule here: https://github.com/mui-org/material-ui/blob/becb199bd3c32471fb26a9ac6dc2d7d0b1a4d3ac/packages/mui-lab/src/DatePicker/shared.ts#L72

This is preventing me from upgrading from v4. Why is this mask not allowed?

benjamin-andersen commented 2 years ago

Any updates on this?

cati97 commented 2 years ago

Hello,

I found solution to this problem by adding prop - disableMaskedInput={false} (setting it to false is necessary). I guess somewhere it is set to true and that is causing the issue here.

Below working sandbox example with inputFormat, mask and disableMaskedInput: https://codesandbox.io/s/basicdatepicker-material-demo-forked-7yut0k?file=/demo.tsx

flaviendelangle commented 2 years ago

@alexfauquette I think you worked on related topics

alexfauquette commented 2 years ago

@cati97 bring a good workaround

The problem seems to come from default settings.

useDatePickerDefaultizedProps is using ...getFormatAndMaskByViews(views, utils), to set the inputFormat, mask and disableMaskedInput. In the codesandbox example, the inputFormat and the mask are override by the provided props, but not the disableMaskedInput added when there is only month and years.

https://github.com/alexfauquette/material-ui-x/blob/e1b3a6d5804975bdbdf0d735ece812fcf5e16ac6/packages/x-date-pickers/src/DatePicker/shared.ts#L70:L75

  if (isYearAndMonthViews(views)) {
    return {
      disableMaskedInput: true,
      inputFormat: utils.formats.monthAndYear,
    };
  }

I see two solutions:


Personally, I prefer the first option, because monthAndYear format does not change with the localization. It is not year-month for some country and month-year for others. The order is fixed by date-io so I do not see any problem to do the same but with numbers instead a natural language for months https://github.com/dmtrKovalenko/date-io/blob/f96f0929e1a4020db1b171416e18c0e314ee9a31/packages/date-fns/src/date-fns-utils.ts#L74-L75

  monthAndYear: "LLLL yyyy",
  monthShort: "MMM",

If you have another idea, or find the other solution more suitable, feel free to add a comment @flaviendelangle

alexfauquette commented 2 years ago

This has a problem with special date formatted such as hijri which uses iMM for months, so either

  1. we propose in date-io a new feature to get month/year digits, but using them does not solves digit order (following locales supported by core set year first: az-AZ, zh-CN, zh-TW, hu-HU, ja-JP, ko-KR, sv-SE)
  2. we remove the custom default. Even if the views contain yearn and month, we add a demo for this specific case to show how to manage inputFormat and mask
filliperomero commented 2 years ago

@cati97 bring a good workaround

The problem seems to come from default settings.

useDatePickerDefaultizedProps is using ...getFormatAndMaskByViews(views, utils), to set the inputFormat, mask and disableMaskedInput. In the codesandbox example, the inputFormat and the mask are override by the provided props, but not the disableMaskedInput added when there is only month and years.

https://github.com/alexfauquette/material-ui-x/blob/e1b3a6d5804975bdbdf0d735ece812fcf5e16ac6/packages/x-date-pickers/src/DatePicker/shared.ts#L70:L75

  if (isYearAndMonthViews(views)) {
    return {
      disableMaskedInput: true,
      inputFormat: utils.formats.monthAndYear,
    };
  }

I see two solutions:

  • remove the default values for month and year. or set them numerical like in the proposed codesandbox, at least until we manage to handle "Jan", "Fev", ... in the masked input

    • Pro: it avoids having disableMaskedInput=true in the default whereas we recommend avoiding it in the doc
    • Cons: It's a breaking change
  • do not apply default as soon as one of inputFormat, mask, disableMaskedInput is set

    • Pro: As soon as the mask is set, setting the inputFormat will have to be adapted so its does not makes sens to add a default for one and use a custom props for the other
    • Cons: hard to explain that de default value is not applied depending on another prop

Personally, I prefer the first option, because monthAndYear format does not change with the localization. It is not year-month for some country and month-year for others. The order is fixed by date-io so I do not see any problem to do the same but with numbers instead a natural language for months https://github.com/dmtrKovalenko/date-io/blob/f96f0929e1a4020db1b171416e18c0e314ee9a31/packages/date-fns/src/date-fns-utils.ts#L74-L75

  monthAndYear: "LLLL yyyy",
  monthShort: "MMM",

If you have another idea, or find the other solution more suitable, feel free to add a comment @flaviendelangle

I ended up with this problem today but I think the solution could be simple. If the views is provided with Month and Year only (['year', 'month']), we should do an additional check in the code. If the mask and inputFormat is also provided and different from the default, then we should not set disableMaskedInput to true. This would solve the problem since the mask provided would work and we would not need to add additional information to the documents.

flaviendelangle commented 1 year ago

I am closing this issue.

We recently launched the first beta of @mui/x-date-pickers and @mui/x-date-pickers-pro v6.x. This new version contains a full rework of the input editing. You can have a look at the v6 doc which is currently in beta and the related blog post.

We won't apply complicated (and not always doable) fixes to the v5 version, I hope this new version solves your problem.