-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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 unstyled component: Calendar #15598
Comments
In that example, will |
Would |
If you want to change month, then you can wrap it as follow: <Calendar.Navigation.SetView target="month">
<Calendar.Header.Label format="MMMM" />
</Calendar.Navigation.SetView> And then when the month view is handled by <Calendar.Root>
<Calendar.Header.Root>
<div>
<Calendar.Navigation.SetMonth target="previous" />
<Calendar.Navigation.SetView target="month">
<Calendar.Header.Label format="MMMM" />
</Calendar.Navigation.SetView>
<Calendar.Navigation.SetMonth target="next" />
</div>
<div>
<Calendar.Navigation.SetYear target="previous" />
<Calendar.Navigation.SetView target="year">
<Calendar.Header.Label format="YYYY" />
</Calendar.Navigation.SetView>
<Calendar.Navigation.SetYear target="next" />
</div>
</Calendar.Header.Root>
<Calendar.Days.DefaultLayout>
{value => <Calendar.Days.Cell value={value} />}
</Calendar.Days.DefaultLayout>
<Calendar.Months.Root>
{value => <Calendar.Months.Cell value={value} />}
</Calendar.Months.Root>
<Calendar.Years.Root>
{value => <Calendar.Years.Cell value={value} />}
</Calendar.Years.Root>
</Calendar.Root> If you don't want a month view but instead you want to render some month picking UI inside a drop down in the header, you could do something like the following (I did not check the DX of the Base UI Popover in depth, it's just to get the idea): <Popover.Root>
<Calendar.Header.Label format="MMMM" render={<Popover.Trigger />} />
<Popover.Popup>
<Calendar.Months.Root>
{month => <Calendar.Months.Cell value={month} />}
<Calendar.Months.Root>
</Popover.Popup>
</Popover.Root> Since it's the DX of the unstyled component, I'm trying to be as little optionated as possible about the end UX. |
For me any component built for composition in an unstyled package should follow some common DX and the So yes for me we would be able to do: const MyCustomDay = styled('button')({}) // or any other way of creating and styling a component
<Calendar.Days.DefaultLayout>
{value => <Calendar.Days.Cell value={value} render={<MyCustomDay />} />}
</Calendar.Days.DefaultLayout> but also: const MyCustomDay = styled(Calendar.Days.Cell)({});
<Calendar.Days.DefaultLayout>
{value => <MyCustomDay />}
</Calendar.Days.DefaultLayout> but also: <Calendar.Days.DefaultLayout>
{value => <Calendar.Days.Cell className={state => clsx('day', state.selected && 'day-selected')} />}
</Calendar.Days.DefaultLayout> Here I'm following 100% the Base UI DX (or at least what I understand of it, I might get some things wrong) |
What's the purpose of |
React Aria supports two DX:
I'm proposing to also have this shortcut notation (because it makes the composition easier to get started with). But I'm proposing to split the two DX into two distinct components to simplify the explanation for each one of those (that's clearly debatable and purely a product topic, on the engineering side both are easily doable). So:
I guess we have three ways of doing it:
I like 3. because it could allow us to create some shared nomenclature for the few components that have a richer DOM structure (I'm thinking about the virtualization engine of the Tree View of perhaps the grid if we have composition someday). |
Got it. I like this option. With any more than 1 DOM element per component, we have the same customization issues that we are trying to solve with composition, right? |
Yes But the question here would more be: should we only provide the version where 1 component = 1 DOM element or are there use cases where providing both the 1 component = 1 DOM element and slightly higher level component make sense? If we are not sure its bring value, we can definitely wait before adding it to see if there is traction. |
Agree with this 👍 . And yeah, the React Aria approach is restrictive. I'm strongly in favor of only supporting 1 component = 1 DOM for our composable components. It's less to maintain and less to document. And with less API to document, less confusion for users as they only have to learn one way to do things. |
I can remove I'll update the document 👍 |
I do quite like how the components are broken down into subcomponents e.g. <Calendar.Root>
<Calendar.Header>
<Calendar.SetMonth target="previous" />
<Calendar.HeaderLabel />
<Calendar.SetMonth target="next" />
</Calendar.Header>
<Calendar.Days>
<Calendar.DaysHeader>
{value => <Calendar.DaysLabel value={value} />}
</Calendar.DaysHeader>
<Calendar.DaysContent>
{weekValue => (
<Calendar.DaysWeekLine value={weekValue}>
{dayValue => <Calendar.DaysCell value={dayValue} />}
</Calendar.DaysWeekLine>
)}
</Calendar.DaysContent>
</Calendar.Days>
</Calendar.Root> This would be more in line with how they name things on Base UI, e.g. <NumberField.ScrubArea>
<NumberField.ScrubAreaCursor />
</NumberField.ScrubArea> Granted, there are fewer parts to their components. Perhaps the third level works for components with more parts, but I would be curious to get their thoughts on this in particular. |
On a similar note, does having a mega component mean that tree shaking won't work? In the context of data grid, if a user doesn't want a toolbar (composed with We spoke about having the data grid components under separate imports to get around this. Something like: import * as Toolbar from '@mui/x-data-grid/Toolbar'; |
It's one of the main DX question I'd like to answer.
I think it does tree shake. At least for Base UI from what I understood tree shaking of components should work. With that being said, for a component like
Just in case, Base UI was using |
It does tree shake if the package has import { Calendar } from '@mui/x-date-pickers';
// or
import { Toolbar } from '@mui/x-data-grid'; This is the same problem that is described in https://mui.com/material-ui/guides/minimizing-bundle-size/#when-and-how-to-use-tree-shaking
In Base UI each component has its own import path: https://base-ui.com/components/react-accordion import { Accordion } from '@base-ui-components/react/accordion'; I believe this is done to solve the slow dev mode issue I mentioned above. |
For me we are more talking of being able to tree shake For the tree shaking of the root, I fully agree with everything you said 😆 |
Part of #15558
This component would be the Base-UI-DX component to edit day, month and year for a single date.
It would the fundation for
<MonthCalendar />
,<YearCalendar />
and<DateCalendar />
on the MUI X version.Basic examples
Most basic example (only day view, simple header)
Basic example with the day, month and year view
I need to clarify how we handle the view switch.
Basic example of
Calendar.Header.*
Example of
Calendar.Header.*
with month and year navigationHere is the structure that would be used to recreate the navigation of the MD3 Date Picker:
Basic example of
Calendar.Days.*
Component list
Misc:
Calendar.*
<Calendar.Root />
offset
Props:
Value props:
value
,defaultValue
,onChange
,referenceDate
,timezone
View props:
view
,defaultView
,onViewChange
Validation props:
minDate
,maxDate
,shouldDisableDate
etc...Form props:
disabled
,readOnly
Focus props:
autoFocus
(focusedView
,openTo
andonFocusedViewChange
need to be clarified)fixedWeekNumber
Header:
Calendar.Header.*
<Calendar.Header.Root />
<Calendar.Header.Label />
Pops:
format
${utils.formats.month} ${utils.formats.year}
string
Day view:
Calendar.Days.*
<Calendar.Days.Root />
Props:
fixedWeekNumber
displayWeekNumber
false
<Calendar.Days.Content />
<Calendar.Days.WeekLine />
Props:
value
{ date: PickerValidDate }
<Calendar.Days.Cell />
Props:
value
{ type: 'day', date: PickerValidDate } | { type: 'weekNumber' }
Month view:
Calendar.Months.*
<Calendar.Months.Root />
<Calendar.Months.Cell />
Props:
value
{ date: PickerValidDate }
Year view:
Calendar.Years.*
<Calendar.Years.Root />
<Calendar.Years.View />
Props:
value
{ date: PickerValidDate }
Navigation:
Calendar.Navigation.*
Tip
I'm not prefixing the components below with
Calendar.Header
because people could use those buttons outside the header, it just need to be inside<Calendar.Root />
. We could imagine having a view switch inside a footer.<Calendar.Navigation.SetMonth />
Props:
target
"previous" | "next"
<Calendar.Navigation.SetYear />
Props:
target
"previous" | "next"
<Calendar.Navigation.SetView />
Props:
target
"year" | "month" | "day"
Props that will remain in the MUI X layer
The following props won't be present in the Base UI X component but only on the MUI X one because they only apply the style:
monthsPerRow
yearsPerRow
disableHighlightToday
(<Calendar.Days.Cell />
will set adata-today
attribute on the right day, month and year)showDaysOutsideCurrentMonth
(<Calendar.Days.Cell />
will set adata-outside-current-month
attribute, name tdb on the right days)renderLoading
reduceAnimations
loading
To clarify
How to handle multiple month visible at once (React Aria spec)? It would be a great addition to the
Calendar
component, currently only<DateRangeCalendar />
supports multiple calendars. When implementing it, we should be careful with the navigation (see thepageBehavior
in React Aria)Should it be
Calendar.Days.*
orCalendar.DayView.*
? (same forMonths
andYears
).The problem with
Calendar.DayView
is that when you have only the "day" view (which is a super common use case), the concept of "view" is just a distraction.Should the components be
<Calendar.Header.Label />
or<Calendar.HeaderLabel />
? (same for all the others). AFAIK Base UI avoids deep nesting like<Calendar.Header.Label />
, but maybe we are big enough to justify adding this level of depth.How do we handle keyboard navigation in
Calendar.Months.*
andCalendar.Years.*
without being optionated on the layout? People should be able to design a list (like in MD3) or a grid (like we currently have). Maybe we can keep themonthsPerRow
/yearsPerRow
props on the Base UI X version but use it only for keyboard navigation purpose.The focus part is very unclear for now (which props? which DX?)
Planned work
This is very early stage but here is a basic idea of what the migration could look like:
@mui/x-date-pickers/internals/base-ui/Calendar
(no public doc, only private one). Requires to have Base UI as a dep of our package so we need to wait for the stable release (or at the very least the beta)@mui/x-date-pickers/DateCalendar
@mui/x-date-pickers/DateCalendar
to use the new component@base-ui/x-date-pickers
package)Search keywords:
The text was updated successfully, but these errors were encountered: