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] Clean view management #8989

Open
flaviendelangle opened this issue May 15, 2023 · 7 comments
Open

[pickers] Clean view management #8989

flaviendelangle opened this issue May 15, 2023 · 7 comments
Labels
component: pickers This is the name of the generic UI component, not the React module! dx Related to developers' experience RFC Request For Comments v7.x

Comments

@flaviendelangle
Copy link
Member

flaviendelangle commented May 15, 2023

Current behavior

We have 5 props:

  • views to define the views used inside the components
  • openTo to define the view to render when opening the component
  • view to control the current view
  • onViewChange to update the current view
  • viewRenderers to change how each view is rendered

Problem

Our main problem is that the term "views" is used to define 2 different concepts that were equivalent but that not anymore.

1. Configure the pieces of date-time the user can select

Example with TimePicker

If a user does the following customization:

<TimePicker views={['hours', 'minutes', 'seconds']} />

Then he wants to allow editing the seconds, which are not included in the TimePicker by default.

Example with DatePicker

If a user does the following customization:

<DatePicker views={['year', 'month']} />

Then he wants to disable the editing of the day and add the editing of the month.

2. Configure the flow of picking a value

Example with DatePicker

If a user does the following customization:

<DatePicker openTo="year" />

Then he wants every user to pass through the year view (which is not part of the default flow; you must click on the header to access it).

Example with TimePicker

If a user does the following customization:

<TimePicker 
  viewRenderers={{
          hours: renderTimeViewClock,
          minutes: renderTimeViewClock,
          seconds: renderTimeViewClock,
  }}
 />

Then he wants to change the UI of all the time views to use the TimeClock component even on desktop.

Proposals

Proposal A: Use a sections prop to define the date-time parts to edit

On one hand, we would have the sections which would be used to define the part of the date-time user can select.

  • Rename FieldSectionType into PickersSectionType
  • Create a new prop sections of type PickersSectionType

The examples above about the 1st concept would become:

<TimePicker sections={['hours', 'minutes', 'seconds']} />
<DatePicker sections={['year', 'month']} />

On the other hand, we would have the views, which would be used to define the steps used to select a value.
The pickers would have only one view, which would handle its internal screens if several (like currently in the DateCalendar).
It would be impossible to change the order of the views, but I honestly struggle to find a real use case for this feature.
The MobileDateTimePicker would need a new renderer that renders TimeClock and DateCalendar alternatively.
The DesktopDateTimePicker would need a new renderer that renders both DigitalClock and DateCalendar (but @LukasTy needs it anyway).
The other pickers would keep their current renderers.

People could update their renderer like today but without duplicates

// Set the `TimeClock` UI for both mobile and desktop
<TimePicker viewRenderer={renderTimeViewClock} />

Problems

  • How to force field-editing on some sections
    We could say that if at any point a renderer returns null, then we fallback to field editing.

  • How to allow the user to open the DateCalendar on the year view or even to control the view inside the renderer?
    We could move the view / openTo / onVIewChange logic as props of DateCalendar only and pass them through props. This one is very unclear to me.

@flaviendelangle flaviendelangle added component: pickers This is the name of the generic UI component, not the React module! v7.x labels May 15, 2023
@alexfauquette
Copy link
Member

It would be impossible to change the order of the views, but I honestly struggle to find a real use case for this feature.

Not sure to understand. isn't the sections order describing the views order? Would it still be possible to choose if the date picker starts with the day or year view?


For me, the current API is a legacy of the v5. At that time, you could not create custom views, and the workflow was a succession of views.

We broke this behavior multiple times:

  • Allowing to have sections without any view
  • Allowing to merge multiple sections in a single view

My proposal is to remove the link between views and time scale (day, month, hours, ...) and only describe the view itself. This because:

  • views are not necessarily associated with a single time scale
  • views don't use their name. We could switch dayRenderer and yearRendere. it would just create a mismatch between the internal view state and the UI displayed.
  • views are not necessarily associated with a standard time scale we currently support (centuries, decades, or quarters)

The DX could look something like that:

import DatePicker from '@mui/x-date-pickers/DatePicker'
import { yearView, dayView } from '@mui/x-date-pickers'

<DatePicker
  views={[yearView, dayView]}
  openTo='year'
/>

with yearView = { id: 'year', view: <YearPicker />}

Which would allows users to do customYearView = { id: 'year', view: <CustomYearPicker />}
Or even create a completely new view, customTimeView = { id: 'timeSlot', view: <TimeSlotPicker /> } that could be a grid of available slots (which is a mix of hours and minutes pickers). It could be the default open with openTo='timeSlot'

Maybe it's introducing too much complexity for most users compared to the number of users willing to have that deep customization.

By the way, it's still possible to keep views={['year', 'day']} and internally do the mapping to [yearView, dayView]. Such that views type would be ('day' | 'month' | 'year' | PickerViewCongif)[]

@flaviendelangle
Copy link
Member Author

Not sure to understand. isn't the sections order describing the views order?

My proposal is to totally decorrelate the two concepts, so no.

Would it still be possible to choose if the date picker starts with the day or year view?

That's the question I raise at the end of my message.
It's the main limitation that my solution need to overcome in order to be viable.


If we go for something similar to what you are proposing, then I would indeed be in favor of supporting the string version, I don't think we should bother people with renderers for basic use cases.

I see 3 downsides with your solution:

  1. If a user creates a custom view like the timeSlot you are describing, how do we keep the smart format default value that is currently based on views and is based on sections in my proposal?

  2. If a user wants to provide a custom renderer, then he also has to define the order of the renderers at the same time. Let's take someone that wants to keep the TimeClock on desktop, he sets the views prop on the theme, but then if on some components he wants to change the order of some views, he also have to re-define his custom views here.

  3. We still have this meridiem view which is here just for internal management. But my solution does not solve this problem very elegantly either since sections also have it.

@alexfauquette
Copy link
Member

  1. If a user creates a custom view like the timeSlot you are describing, how do we keep the smart format default value currently based on views and sections in my proposal?

We don't. If there is an unknown view, we can just fall back on the default format. If the user is advanced enough to creat its own view, they can probably set the format that want

  1. If a user wants to provide a custom renderer, then he also has to define the order of the renderers at the same time. Let's take someone that wants to keep the TimeClock on desktop, he sets the views prop on the theme, but then if on some components he wants to change the order of some views, he also have to re-define his custom views here.

The only difference with string views is the need of an import line. For example for a datetime that start with time, the modification would be the following:

+import { hourClock, minuteClock } from '@mui/x-date-pickers

<DateTimePicker 
-   views=['hour', 'minute', 'day']
+   views=[hourClock, minuteClock, 'day']
/>
  1. I did not follow close enough the digital clock internals to fully understand the complexity, but I thought it would be possible to get the digital clock as a single view { id: 'time', view: <DigitalClock />}

@flaviendelangle
Copy link
Member Author

flaviendelangle commented May 15, 2023

We don't. If there is an unknown view, we can just fall back on the default format. If the user is advanced enough to creat its own view, they can probably set the format that want

But it means that we can't use those "meta" views for our buit-in views.
Which would be nice for us, since the more we are moving on, the lass the list of views matches our UI.

The only difference with string views is the need of an import line. For example for a datetime that start with time, the modification would be the following:

So you would keep the viewRenderers prop at the same time?
Otherwise, this does not answer my question.

I did not follow close enough the digital clock internals to fully understand the complexity, but I thought it would be possible to get the digital clock as a single view { id: 'time', view: }

In which case we go back to my point 1. => we can no longer have the smart format with the time (which we don't use right now on this component to be fair).

@flaviendelangle
Copy link
Member Author

flaviendelangle commented May 15, 2023

Moreover, concerning the order of the views, if we say view="year", what does it mean on the new DesktopDateTimePicker where we render both a date view and a time view at the same time?
If the user changes view from year to minutes, do we stay in the year on the left of the screen ? Or default back to the day ?

My feeling is that, if the UI is no longer 1 view = 1 screen, it requires more and more hacks to make reconciliate the views and the actual info rendered on screen.

@flaviendelangle
Copy link
Member Author

Honestly, I struggle to find a good and simple mental model to raise this inconsistency.
Especially one that would fit both the basic and the advanced use-cases.

@alexfauquette alexfauquette added the RFC Request For Comments label May 30, 2023
@joserodolfofreitas joserodolfofreitas added the dx Related to developers' experience label May 30, 2023
@LukasTy
Copy link
Member

LukasTy commented May 30, 2023

IMHO, we are still not sure about the right direction to take on this topic.

  • The new time views are only iteratively coming to certain pickers and didn't yet receive enough "battle testing"
  • We haven't decided if and in what form those new view renderers would be supported on Static and Mobile versions
  • We are often introducing many breaking changes already, so not changing anything in this regard, wouldn't seem to hurt

On the contrary, we still have not documented anything about viewRenderers, so, technically, making BCs in that regard would be a perfect time now. 🙈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: pickers This is the name of the generic UI component, not the React module! dx Related to developers' experience RFC Request For Comments v7.x
Projects
None yet
Development

No branches or pull requests

4 participants