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] Rework view internals #7097

Merged
merged 19 commits into from
Dec 16, 2022
Merged

Conversation

flaviendelangle
Copy link
Member

@flaviendelangle flaviendelangle commented Dec 5, 2022

In this PR

  • Rename setOpenView => setView in useViews (and in any component passing this prop down we name it onViewChange)
  • Rename openView => view in useViews (and in any component passing this prop down)
  • Move useFocusManagement inside useViews and avoid having setFocusedView return a function (we were not memoizing anything anyway)
  • Rename handleChangeAndOpenNext => setValueAndGoToNextView in useViews (avoid mixing set, handle and on for callbacks returned by a hook and make clear what we are changing and opening)
  • Rename openNext => goToNextView (make clear that it is the view we are changing)
  • Use the params from useViews to create the props of every component using it (was already the case for the new pickers, did it for DateCalendar which causes some bug on the old picker because of type inconsistencies. For instance I had to redefine the sx prop on non-static pickers. This change helps us migrate away for ExportedDateCalendarProps = Omit<DateCalendarProps, ...> which is a very error-prone pattern.

Questions

  • Should we rename openTo => defaultView ? On static pickers and calendars, this name make no sense, and naming is defaultView would make very clear that it behaves like a value / defaultValue pattern.

=> We are keeping openTo for now

  • Should we apply a smarter fallback to openTo at the component level (useDatePickerDefaultizedProps for instance) in case the current fallback is not in the views (for the date picker, it would be something like views.includes('day') ? 'day' : views[0]. Because right now if we apply a custom set of views that do not contain day, we have to manually define openTo, otherwise it breaks.

=> Yes we should apply smart defaults

@flaviendelangle flaviendelangle added the component: pickers This is the name of the generic UI component, not the React module! label Dec 5, 2022
@flaviendelangle flaviendelangle self-assigned this Dec 5, 2022
@mui-bot
Copy link

mui-bot commented Dec 5, 2022

Messages
📖 Netlify deploy preview: https://deploy-preview-7097--material-ui-x.netlify.app/

These are the results for the performance tests:

Test case Unit Min Max Median Mean σ
Filter 100k rows ms 659.3 898.3 747 781 95.029
Sort 100k rows ms 620.4 1,191 883.2 911.54 183.331
Select 100k rows ms 211 376.8 241.7 263.3 59.485
Deselect 100k rows ms 137.1 318 189.3 212.28 63.605

Generated by 🚫 dangerJS against d6a20b2

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 6, 2022
@github-actions
Copy link

github-actions bot commented Dec 6, 2022

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 6, 2022
"onMonthChange": { "type": { "name": "func" } },
"onViewChange": { "type": { "name": "func" } },
"onYearChange": { "type": { "name": "func" } },
"openTo": {
"type": {
"name": "enum",
"description": "'day'<br>&#124;&nbsp;'month'<br>&#124;&nbsp;'year'"
},
"default": "'day'"
Copy link
Member Author

Choose a reason for hiding this comment

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

We already lost this precision on the new pickers due to the shared interface.

It would be nice to be able to do something like:

/**
 * @propDefaultValue view "day"
**/
interface MyComponentProps extends SomeShareInterface {}

Not sure about the exact synthax
This would allow to define doc default values without redefining the type itself.

If you know about any existing convention for this use case I'm very interested

Copy link
Member

Choose a reason for hiding this comment

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

This specific use case does not seem to be supported by jsdocs.

You have the list of "supported tags" here.

We could add a plugin to support an additional tag @overrideDefault. But it sounds to be an interesting project, but will require some time to navigate int jsdocs documentation

@@ -55,7 +55,6 @@
"onError": { "type": { "name": "func" } },
"onMonthChange": { "type": { "name": "func" } },
"onOpen": { "type": { "name": "func" } },
"onViewChange": { "type": { "name": "func" } },
Copy link
Member Author

@flaviendelangle flaviendelangle Dec 7, 2022

Choose a reason for hiding this comment

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

This prop is never used (and removed on the new pickers)
I can add it back to the typing manually but I don't think it's worth it

Same on other legacy range pickers

@@ -1,5 +1,6 @@
{
"props": {
"autoFocus": { "type": { "name": "bool" } },
Copy link
Member Author

Choose a reason for hiding this comment

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

DateCalendar already had this prop
No idea why the doc gen was not getting it

Same for DateRangeCalendar and all the pickers that use them

@@ -14,19 +15,25 @@
"disablePast": { "type": { "name": "bool" } },
"displayWeekNumber": { "type": { "name": "bool" } },
"fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" },
"focusedView": {
Copy link
Member Author

Choose a reason for hiding this comment

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

DateCalendar already had this prop
No idea why the doc gen was not getting it
Same for onFocusedViewChange

@@ -81,6 +82,12 @@
}
},
"value": { "type": { "name": "any" } },
"view": {
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 no idea how I missed it, but all the new pickers were missing the view prop

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 8, 2022
@github-actions
Copy link

github-actions bot commented Dec 8, 2022

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 8, 2022
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 12, 2022
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 13, 2022
@@ -496,7 +496,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar<TDate>(
{calendars === 1 ? (
<PickersCalendarHeader
views={['day']}
openView={'day'}
view={'day'}
Copy link
Member Author

Choose a reason for hiding this comment

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

PickersCalendarHeader is exposed via the theme
But the typing only contains classes so I would not count this one as a breaking change

@@ -44,45 +45,12 @@ export interface DateRangeCalendarSlotsComponentsProps<TDate>
>;
}

export interface DateRangeCalendarProps<TDate>
export interface ExportedDateRangeCalendarProps<TDate>
Copy link
Member Author

Choose a reason for hiding this comment

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

The logic before:

interface DateRangeCalendarProps = { ... }

interface ExportedDateRangeCalendarProps extends Omit<DateRangeCalendarProps, ...> {}

The logic after:

interface ExportedDateRangeCalendarProps { ... }

interface DateRangeCalendarProps extends ExportedDateRangeCalendarProps { ... }

@@ -36,7 +36,7 @@ export interface BaseDatePickerSlotsComponentsProps<TDate>
}

export interface BaseDatePickerProps<TDate>
extends ExportedDateCalendarProps<TDate>,
extends Omit<ExportedDateCalendarProps<TDate>, 'value' | 'onChange' | 'defaultValue'>,
Copy link
Member Author

Choose a reason for hiding this comment

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

The calendars have the same value / onChange / defaultValue as the new pickers
But for the legacy pickers, I have to omit here and re-define to avoid type conflicts

@@ -774,14 +774,6 @@ describe('<DesktopDatePicker />', () => {
});
});

it('should throw console warning when invalid `openTo` prop is provided', () => {
Copy link
Member Author

@flaviendelangle flaviendelangle Dec 13, 2022

Choose a reason for hiding this comment

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

That one is interesting

The warnOnlyOnce variables are not resetting between tests.
So the 2nd test failed.

I removed it since it's a legacy pickers.
But I don't know how we could cleanly test those warnings.
Maybe just export the variables from the internals and reset them to false after the test.

Copy link
Member

Choose a reason for hiding this comment

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

We could remove the warnOnce logic in test env

let warnedOnce = false;
if (!warnedOnce || process.env.NODE_ENV === 'test') {
  console.warn(...)
}

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'm afraid it would be logged several times and would make the test crash even with toWarnDev (which would only catch the first one)
To be tested

@@ -28,26 +27,13 @@ export type PickerViewRendererLookup<
/**
* Props used to handle the views that are common to all pickers.
*/
export interface UsePickerViewsBaseProps<TView extends DateOrTimeView> {
export interface UsePickerViewsBaseProps<TView extends DateOrTimeView>
extends Omit<UseViewsOptions<any, TView>, 'onChange' | 'onFocusedViewChange' | 'focusedView'> {
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 did not wanted to add controllable focused view on the picker on this PR.
But that would be very easy to do if we wanted to

@flaviendelangle flaviendelangle changed the title [pickers] Rework view internals [WIP] [pickers] Rework view internals Dec 13, 2022
@flaviendelangle flaviendelangle marked this pull request as ready for review December 13, 2022 13:45
Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

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

Nice that focus management get moved to the useView

@@ -61,7 +61,7 @@ export interface MonthCalendarProps<TDate>
disableHighlightToday?: boolean;
onMonthFocus?: (month: number) => void;
hasFocus?: boolean;
onFocusedViewChange?: (newHasFocus: boolean) => void;
onFocusedViewChange?: (hasFocus: boolean) => void;
Copy link
Member

Choose a reason for hiding this comment

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

With the "new" it sounds more obvious that the function has to be call when the focus is modified. Not a strong opinion

Copy link
Member Author

Choose a reason for hiding this comment

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

My main rational here was that on onChange we are always calling it value not newValue in the interface

(example from the base package)

onChange?: (event: React.SyntheticEvent, value: number | string) => void;

@flaviendelangle flaviendelangle merged commit 3f247e5 into mui:next Dec 16, 2022
@flaviendelangle flaviendelangle deleted the rework-views branch December 16, 2022 13:49
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!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants