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/
4.54k stars 1.32k forks source link

[DatePicker] Make the month drop-down from CalendarPicker available in sx #6218

Closed TheRealCuran closed 1 year ago

TheRealCuran commented 2 years ago

Duplicates

Latest version

Summary 💡

I maintain an Electron app, that sets a global fontSize of 1.3rem. This size propagates to the font size of the text in the month drop-down of the <CalendarPicker /> component, making it overflow: image

I thought it would be easy fixing this, by adding a sx property to my <DatePicker /> and (re-)set the fontSize to a better value for this particular component. However I didn't manage to address the <CalendarPicker />, since it gets created dynamically and especially since there is a <div> with the role="presentation" that overwrites any value you might assign to & .MuiCalendarPicker-root: image

I did try stuff like:

<DatePicker
  sx={{
    '& .MuiCalendarPicker-root': {
      '& div[role="presentation"]': {
        fontSize: 'initial', 
      },
    },
  }}
/>

but as I said, that never got applied, since the component is inserted dynamically (AFAICT).

In the end I put the above snippet into the theme (which is OK for me, since I only have these pickers in one view and the size issue applies to all of them anyway):

MuiCalendarPicker: {
  styleOverrides: {
    root: sx({
      '& div[role="presentation"]': {
        fontSize: 'initial',
      },
    }),
  },
},

I would love to have a way to set this in my <DatePicker>'s sx property. I imagine something like this:

<DatePicker
  sx={{
    '& .MuiCalendarPicker-select': {
      fontSize: 'initial', // or whatever other property you might want to set
    },
  }}
/>

This also applies to .MuiCalendarPicker-root, because if that was reachable, it would be possible to force the fontSize in any case.

Examples 🌈

This is how I want it to look: image

Motivation 🔦

I had to abuse the theme to style a particular component. And if I had to do different sizes for different pages I would already have to work with two themes, introduce styled components, etc. to change the value of one sub-component properties style.

Order ID 💳 (optional)

47016

LukasTy commented 2 years ago

Hello @TheRealCuran We've just recently released (v5.0.2) quite a big overhaul of pickers styling in both themeAugmentation (TS) side and adding classes to various components missing them.

I've tried replicating your case in web and was able to solve the issue with a very similar solution to your expected one:

sx={{
  '& .MuiPickersCalendarHeader-label': {
    fontSize: 'initial',
  },
}}

Could you confirm if it solves your issue?

TheRealCuran commented 2 years ago

Hey @LukasTy , betrayed by my Renovate instance :-/ (meant I didn't see the 5.0.2 update). Anyway this does not solve my issue with <DatePicker /> and the styling of the used <CalendarPicker /> component. I see the new CSS classes, but the override from the sx prop in <DatePicker />still doesn't get applied: image

My <DatePicker /> looks like this:

<DatePicker
  sx={{
    '& .MuiPickersCalendarHeader-label': {
      fontSize: 'initial',
    },
  }}
  ampm={false}
  inputFormat="MM/yyyy"
  mask="__/____"
  views={['year', 'month']}
  renderInput={({ InputProps, ...params }) => (
    <TextField
      {...params}
      InputProps={{
        ...InputProps,
        endAdornment: (
          <React.Fragment>
            {this.props.searchOptions.fromDate && (
            <IconButton onClick={(e) => {
              e.stopPropagation();
              actions.searchSelectFrom(null);
            }}
            >
              <Clear />
            </IconButton>
            )}
            {InputProps?.endAdornment}
          </React.Fragment>
        ),
      }}
    />
  )}
  aria-label="select start date"
  value={this.dateFromEpoch(this.props.searchOptions.fromDate)}
  onChange={newDate => actions.searchSelectFrom(newDate.valueOf())}
/>

But maybe I am doing something really wrong here? If I move this to the theme it works again, which is already an improvement, since I get rid of the experimental sx() there and get something that is directly addressable.

Apart from that: I can't find the CSS class .MuiPickersCalendarHeader-label in the documentation, which would have helped in finding out about it. ;-) image

LukasTy commented 2 years ago

@TheRealCuran Sorry for causing confusion with sx solution. I probably mistakenly tested it with StaticDatePicker where it would work. In usual DatePicker the sx prop won't work as it is not propagated to the popper/modal, which is opened and appended to the bottom of body (be default).

If you need it fixed globally in your application, I would say that using a styleOverride is the easiest approach.

Apart from that: I can't find the CSS class .MuiPickersCalendarHeader-label in the documentation, which would have helped in finding out about it. ;-)

Yes, we are aware of this shortcoming as we did not update the documentation to include all the possible pickers sub-components, which are now style-able/overridable. We'll have to think of how to improve this (documentation) part with the next major release. For now, the easiest way to identify what is overridable is using TS codebase and importing import type {} from '@mui/x-date-pickers/themeAugmentation'; which will provide code completion with all the possible options.

TheRealCuran commented 2 years ago

In usual DatePicker the sx prop won't work as it is not propagated to the popper/modal, which is opened and appended to the bottom of body (be default).

Yeah, that is basically what this feature request is about: provide a way to style those dynamic parts too through sx (I don't mind if I need to use a special syntax for it or a special tool to generate it; maybe it could also be made available through the componentProps and then have a distinct sx in there?).

Yes, we are aware of this shortcoming as we did not update the documentation to include all the possible pickers sub-components, which are now style-able/overridable. We'll have to think of how to improve this (documentation) part with the next major release.

That would be much appreciated, I had other issues, where I only found the missing documentation part somewhere in a ticket or elsewhere.

For now, the easiest way to identify what is overridable is using TS codebase and importing import type {} from '@mui/x-date-pickers/themeAugmentation'; which will provide code completion with all the possible options.

This app is sadly still purely JS and while I do have a branch converting it to TS, that one needs a lot more work (mostly because it is the best time to get rid of some other technical debt as well). But thanks for the suggestion.

LukasTy commented 2 years ago

Yeah, that is basically what this feature request is about: provide a way to style those dynamic parts too through sx (I don't mind if I need to use a special syntax for it or a special tool to generate it; maybe it could also be made available through the componentProps and then have a distinct sx in there?).

I'm just curious to know—do you specifically need to have different styles through the application?

Because the sx prop is a new approach introduced in v5 with the indent of having easy way to provide styling in certain cases. There might still be a few instances missing correct usage/propagation of this prop. Although, we've made effort to apply sx prop to the root element on every root pickers component. Whereas the styleOverrides have existed previously as arguably a better DX for overriding certain styled components styles and helps to achieve consistent styling needs among the application.

TL.DR.:

TheRealCuran commented 2 years ago

Yeah, I do need the ability to style this individually and would appreciate the sx option very much. There is an update in the queue which will add another picker in another place, where I already saw, that I would like to have the ability to override some of the <CalendarPicker /> properties.

And I think what is missing here (and probably other places) is, that sx can only address the styles of directly rendered (sub) components. If something is added dynamically it becomes inaccessible. And that would be really helpful to have as a one-off solution as well. sx was an awesome edition to the v5 update, I really love it.

LukasTy commented 2 years ago

I see, in such case, I'd say that your best bet with the current implementation is the following snippet:

// overrides style in desktop version
PaperProps={{
  sx: {
    '.MuiPickersCalendarHeader-label': {
      fontSize: 'initial',
    },
  },
}}
// overrides style in mobile version (if you need it)
DialogProps={{
  sx: {
    '.MuiPickersCalendarHeader-label': {
      fontSize: 'initial',
    },
  },
}}

As you can see, this case helped in discovering an inconsistency—MobileDatePicker should also consume and use PaperProps as the Desktop version does.

TheRealCuran commented 2 years ago

Thanks! Yeah, that looks good.

I leave it up to you if you want to keep this request open or not. I can see arguments for both solutions being "better". Pushing this into the componentsProps (or in this case specialised properties on the picker) has the benefit of clearly separating where a style should be applied. On the other hand having it in the sx of the actual component I am setting up feels more like the way sx (and styled components) are training me to do my styles. At least that's what I get from the current docs, where having eg. a styled component is looking like this:

export const MyStyledComp = styled(MyStyledCompImpl, {
  name: 'MyStyledComp',
  slot: 'Root',
})<MyStyledCompProps>(({ theme }) => ({
  '& .MyStyledComp-active': {
    // some props here
    '&:hover': {
      // some other props here
    }
  },
}))
LukasTy commented 2 years ago

Pushing this into the componentsProps (or in this case specialised properties on the picker) has the benefit of clearly separating where a style should be applied.

I'm not sure it would be the best approach to add a prop for basically every different component. Pickers are a bit more rare case, because they have a Popup and Modal components, which are not children of the root component in the DOM, hence, we can't override all the styles with the sx prop on the root (DatePicker in this case) component. But that's the reason we have such props as PaperProps—to which we can provide an sx prop and override any styles for children elements in the Paper component.

Do you see any possible non-intrusive improvement for this case @alexfauquette @flaviendelangle ?

LukasTy commented 1 year ago

This no longer seem like a problem as we can easily target all slots and pass the sx prop to them if needed. The up-to-date solution for this problem (https://github.com/mui/mui-x/issues/6218#issuecomment-1252130056) could be:

slotProps={{
  layout: {
    sx: {
      ".MuiPickersCalendarHeader-label": {
        fontSize: "inherit"
      }
    }
  }
}}