diff --git a/docs/data/date-pickers/rfc-calendar.md b/docs/data/date-pickers/rfc-calendar.md new file mode 100644 index 0000000000000..7863ed0f0d267 --- /dev/null +++ b/docs/data/date-pickers/rfc-calendar.md @@ -0,0 +1,1004 @@ +--- +productId: x-date-pickers +title: DX - Calendar +--- + +# Calendar + +

This page describes how people can use date views with Material UI and how they can build custom date views.

+ +:::success +This page extends the initial proposal made in [#15598](https://github.com/mui/mui-x/issues/15598) +::: + +## Usage with only days + +### Without Material UI + +The user can use the ``, ``, ``, ``, `` and `` components to create a grid of days: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + + {({ visibleDate }) => ( + +
+ + {visibleDate.format('MMMM YYYY')} + +
+ + + {({ days }) => + days.map((day) => ( + + )) + } + + + {({ weeks }) => + weeks.map((week) => ( + + {({ days }) => + days.map((day) => ( + + )) + } + + )) + } + + +
+ )} +
; +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the `` and limit the views: + +```tsx +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +; +``` + +## Usage with only months + +### Without Material UI + +#### List layout + +The user can use the `` and `` components to create a list of months and utility components like `` to create a header to navigate across the years: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + + {({ visibleDate }) => ( + +
+ + {visibleDate.format('YYYY')} + +
+ + {({ months }) => + months.map((month) => ( + + )) + } + +
+ )} +
; +``` + +#### Grid layout + +The user can use the `` and `` components to create a grid of months and utility components like `` to create a header to navigate across the years: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + + {({ visibleDate }) => ( + +
+ + {visibleDate.format('YYYY')} + +
+ + {({ months }) => + months.map((month) => ( + + )) + } + +
+ )} +
; +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the `` component: + +```tsx +import { MonthCalendar } from '@mui/x-date-pickers/MonthCalendar'; + + +``` + +:::success +The big limitation here is that the `` component does not have a header to navigate through the years. +Once the `Calendar.*` unstyled component is ready, the `` should probably be reworked to improve this (or removed in favor of always using ``). +::: + +## Usage with only years + +### Without Material UI + +#### List layout + +The user can use the `` and `` components to create a list of years: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + + + {({ years }) => + years.map((year) => ) + } + +; +``` + +#### Grid layout + +The user can use the `` and `` components to create a grid of years: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + + + {({ years }) => + years.map((year) => ) + } + +; +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the `` component: + +```tsx +import { YearCalendar } from '@mui/x-date-pickers/YearCalendar'; + + +``` + +:::success +The big limitation here is that the `` component does not have a header to navigate through the years. +Once the `Calendar.*` unstyled component is ready, the `` should probably be reworked to improve this (or removed in favor of always using ``). +::: + +## Day + month + years + +### Without Material UI + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function DateCalendar() { + const [value, setValue] = React.useState(null); + const [activeSection, setActiveSection] = React.useState<'day' | 'month' | 'year'>( + 'day', + ); + + const handleValueChange = (newValue, context) => { + if (context.section === 'month' || context.section === 'year') { + setActiveSection('day'); + } + + setValue(newValue); + }; + + return ( + +
{/** See calendar header documentation */}
+ {activeSection === 'day' && ( + + + {({ days }) => + days.map((day) => ( + + )) + } + + + {({ weeks }) => + weeks.map((week) => ( + + {({ days }) => + days.map((day) => ( + + )) + } + + )) + } + + + )} + {activeSection === 'month' && ( + + {({ months }) => + months.map((month) => ( + + )) + } + + )} + {activeSection === 'year' && ( + + {({ years }) => + years.map((year) => ( + + )) + } + + )} +
+ ); +} +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the `` component and add the month view: + +```tsx +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + + +``` + +:::success +When MD3 is supported, the default views of `` should probably be `['year', 'month', 'day']` +::: + +## Calendar header + +### Without Material UI + +The user can use the `` to build basically any kind of header they could think of: + +#### Very basic header (without month and year UI) + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarHeader() { + const { visibleDate } = useCalendarContext(); + + return ( +
+ + {visibleDate.format('MMMM YYYY')} + +
+ ); +} +``` + +#### MD2 header (MUI X implementation) + +```tsx +import { + Calendar, + useCalendarContext, +} from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarHeader(props: { + activeSection: 'day' | 'month' | 'year'; + onActiveSectionChange: (activeSection: 'day' | 'month' | 'year') => void; +}) { + const { activeSection, onActiveSectionChange } = props; + const { visibleDate } = useCalendarContext(); + + return ( +
+
+ onActiveSectionChange(activeSection === 'year' ? 'month' : 'year') + } + > + {visibleDate.format('MMMM YYYY')} + {activeSection === 'year' ? '▲' : '▼'} +
+ {activeSection === 'day' && ( +
+ + +
+ )} +
+ ); +} +``` + +The `activeSection` and `onActiveSectionChange` needs to be passed by the parent component: + +```tsx +function DateCalendar() { + const [activeSection, setActiveSection] = React.useState<'day' | 'month' | 'year'>( + 'day', + ); + return ( + +
+ {/** Rest of the UI */} + + ); +} +``` + +#### MD3 header + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarHeader(props: { + activeSection: 'day' | 'month' | 'year'; + onActiveSectionChange: (activeSection: 'day' | 'month' | 'year') => void; +}) { + const { activeSection, onActiveSectionChange } = props; + const { visibleDate } = useCalendarContext(); + + return ( +
+
+ {activeSection === 'day' && ( + + )} + + {activeSection === 'day' && ( + + )} +
+
+ {activeSection === 'day' && ( + + )} + + {activeSection === 'day' && ( + + )} +
+
+ ); +} +``` + +### With Material UI + +The user can use slots to override part of the UI in self-contained components: + +```tsx + +``` + +:::success +The concept of slots does not fit this use case very well, but the exploration of a better DX to override part of the UI in self-contained component is outside the scope of this documentation, so this RFC uses the tools currently available. +::: + +The `` component can be built in a few different ways: + +1. From scratch: + + This is mostly viable for components that don't interact a lot with the picker state. For example, if someone wants to build a custom header for their calendar that just displays the current month, they could do it from scratch: + + ```tsx + import { useCalendarContext } from '@base-ui-components/react-x-date-pickers/calendar'; + + function CustomCalendarHeader() { + const { currentMonth } = useCalendarContext(); + + return
{currentMonth.format('MMMM YYYY')}
; + } + ``` + + This is not the recommended way, but nothing prevents it. + + :::success + The `calendarHeader` slot does not receive `currentMonth` as a prop but instead access it using `useCalendarContext()`. + That way, the API is consistent with and without Material UI, and if we introduce a composable version with Material UI in the future it will work fine. + ::: + +2. Using the primitives exposed by `@base-ui-components/react-x-date-pickers/calendar`: + + If the user wants to totally own the styling of this part of the UI (because the UI is really different from the default one), he can use components like `` only for this part of the UI while still using `@mui/x-date-pickers` for everything he doesn't want to deeply customize: + + ```tsx + import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + function CustomCalendarHeader() { + const { visibleDate } = useCalendarContext(); + + return ( +
+ + {visibleDate.format('MMMM YYYY')} + +
+ ); + } + ``` + +3. Using the `PickerCalendarHeader*` components exposed by `@mui/x-date-pickers/PickerCalendarHeader`: + + ```tsx + import { + PickersCalendarHeaderRoot, + PickersCalendarHeaderLabel, + } from '@mui/x-date-pickers/PickersCalendarHeader'; + + function CustomCalendarHeader() { + return ( + + + + + + ); + } + ``` + + :::success + The components like `` would be built on top of their `@base-ui-components/react-x-date-pickers/Calendar` counterparts and would be used to build ``. The packages expose several version but they don't have logic duplication. + Internally, the code would look something like that: + + ```tsx + import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + export const PickerCalendarHeaderRoot = styled('div')({ + display: 'flex', + alignItems: 'center', + marginTop: 12, + marginBottom: 4, + paddingLeft: 24, + paddingRight: 12, + }); + + // This component is purely presentational and not present in `@base-ui-components/react-x-date-pickers/Calendar'. + export const PickerCalendarHeaderLabel = styled('span')({ + /** ... */ + }); + + // This component is purely presentational and not present in `@base-ui-components/react-x-date-pickers/Calendar'. + export const PickerCalendarHeaderLabelContainer = styled('div')({ + /** ... */ + }); + + export const PickerCalendarHeader = (props) => { + const { format, ...other } = props; + const { value } = useCalendarContext(); + + return ( + + + {value.format(format)} + + + }; + ``` + + ::: + + :::success + This one is unclear. + Maybe those composable but styled components should only be exposed for parts of the UI where the Material UI implementation has some complexity and people want to be able to use composition to customize it without going fully unstyled for this part of the UI. + + And if those composable but styled components are something worth doing, then they need to have a coherent export strategy. + Should it be: + + 1. `` like it would be today + 2. `` to match the exports from `@base-ui-components/react-x-date-pickers` + 3. Something else? + + ::: + +## Display multiple months + +### Without Material UI + +The user can use the `offset` prop of the `` component to render months with an offset compared to the currently visible month: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarGrid({ offset }) { + return ( + + + {({ days }) => + days.map((day) => ( + + )) + } + + + {({ weeks }) => + weeks.map((week) => ( + + {({ days }) => + days.map((day) => ( + + )) + } + + )) + } + + + ); +} + + +
{/** See demo below for the navigation with multiple months */}
+
+ + +
+
; +``` + +#### Month navigation with multiple months + +There is two way to navigate to the next / previous months: + +1. With the `` button +2. With the arrow navigation when the target is not in the current month + +When rendering multiple months, both those navigation technic only navigate one month at the time. +For example, if you were rendering May and June, pressing `` will render June and July. + +The user can use the `monthPageSize` prop on the `` component to customize this behavior. + +If the prop receives a number, it will move by the amount of month both for `` and for arrow navigation: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarHeader() { + const { visibleDate } = useCalendarContext(); + + return ( + +
+ + {visibleDate.format('MMMM YYYY')} + {' – '} + {visibleDate.add(1, 'month').format('MMMM YYYY')} + +
+ + +
+ ); +} +``` + +But the user can also distinguish both behaviors by providing an object: + +```tsx +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + +function CalendarHeader() { + const { visibleDate } = useCalendarContext(); + + return ( + +
+ + {visibleDate.format('MMMM YYYY')} + {' – '} + {visibleDate.add(1, 'month').format('MMMM YYYY')} + +
+ + +
+ ); +} +``` + +### With Material UI + +This is currently not doable. + +## Display week number + +### Without Material UI + +The user can add custom elements to add the week number to the grid: + +```tsx + + + {({ days }) => ( + + + # + + {days.map((day) => ( + + ))} + + )} + + + {({ weeks }) => + weeks.map((week) => ( + + {({ days }) => ( + + + {days[0].week()} + + {days.map((day) => ( + + ))} + + )} + + )) + } + + +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the `` with the `displayWeekNumber` prop: + +```tsx +import { DateCalendar } from '@mui/x-date-pickers/DateCalendar'; + +; +``` + +## Anatomy of `Calendar.*` + +### `Calendar.Root` + +Top level component that wraps the other components. + +#### Props + +- Extends `React.HTMLAttributes` + +- **Value props**: `value`, `defaultValue`, `referenceDate`, `onValueChange`, `onError` and `timezone`. + + Same typing and behavior as today (just `onChange` becomes `onValueChange`) + +- **Validation props**: `maxDate`, `minDate`, `disableFuture`, `disablePast`, `isDateInvalid`, `isMonthInvalid` and `isYearInvalid` (equivalent of the current `shouldDisableDate`, `shouldDisableMonth` and `shouldDisableYear`). + + Same typing and behavior as today. + +- **Form props**: `disabled`, `readOnly`. + + Same typing and behavior as today. + +- `autoFocus`: `boolean` + +- `monthPageSize`: `number | { keyboard: number, button: number }`, default: `1`. The amount of months to navigate by in the day grid when pressing `` or with arrow navigation. + +- `children`: `React.ReactNode | (contextValue: CalendarContextValue) => React.ReactNode` + +:::success +All the props that the picker can pass to the calendar (validation props, value props, etc...) are read both from the props and from `usePickerContext` so that the calendar can be used inside a picker built with composition. + +That way, users only have to pass the props specific to the calendar to the `Calendar.*` components: + +```tsx + + {/** See the field documentation */} + + + + + + {/** See demo above */} + + + + + +``` + +::: + +### `Calendar.SetVisibleMonth` + +Renders a button to go to the previous or the next month. +It does not modify the value it only navigates to the target month. + +#### Props + +- Extends `React.HTMLAttributes` + +- `target`: `'previous' | 'next' | PickerValidDate` + +:::success +TODO: Clarify the behavior when multiple calendars are rendered at once. +::: + +### `Calendar.SetVisibleYear` + +Renders a button to go to the previous or the next month. +It does not modify the value it only navigates to the target year. + +#### Props + +- Extends `React.HTMLAttributes` + +- `target`: `'previous' | 'next' | PickerValidDate` + +:::success +TODO: Clarify the behavior when multiple calendars are rendered at once. +::: + +### `Calendar.DaysGrid` + +Top level component to pick a day. + +#### Props + +- Extends `React.HTMLAttributes` + +- `fixedWeekNumber`: `number` + +### `Calendar.DaysGridHeader` + +Renders the header of the day grid. + +It expects a function as its children, which receives the list of days to render as a parameter: + +```tsx + + {({ days }) => + days.map((day) => ( + + )) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { days: PickerValidDate[] }) => React.ReactNode` + +### `Calendar.DaysGridBody` + +Renders the content all the days in a month (it is the DOM element that should contain all the weeks). + +It expects a function as its children, which receives the list of weeks to render as a parameter: + +```tsx + + {({ weeks }) => + weeks.map((week) => ) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { weeks: PickerValidDate[] }) => React.ReactNode` + +### `Calendar.DaysGridRow` + +Renders the content all the days in a week. + +It expects a function as its children, which receives the list of days to render and the week number as a parameter: + +```tsx + + {({ days }) => + days.map((day) => ) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `value`: `{ value: PickerValidDate }` - **required** + +- `children`: `(params: { days: PickerValidDate[], week: PickerValidDate }) => React.ReactNode` + +### `Calendar.DaysCell` + +Renders the cell for a single day. + +#### Props + +- Extends `React.HTMLAttributes` + +- `value`: `PickerValidDate` - **required** + +### `Calendar.MonthsList` + +Top level component to pick a month. + +It expects a function as its children, which receives the list of the months to render as a parameter: + +```tsx + + {({ months }) => + months.map((month) => ( + + )) + } + +``` + +This component takes care of the keyboard navigation (for example Arrow Up). + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { months: PickerValidDate[] }) => React.ReactNode` + +- `itemsOrder`: `'asc' | 'desc'`, default: `'asc'`. + +- `alwaysVisible`: `boolean`, default: `false`. By default this component is only rendered when the active section is `"month"`. + +### `Calendar.MonthsGrid` + +Top level component to pick a month, when the layout is a grid. + +It expects a function as its children, which receives the list of months to render as a parameter: + +```tsx + + {({ months }) => + months.map((month) => ( + + )) + } + +``` + +This component takes care of the keyboard navigation (for example Arrow Up). + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { months: PickerValidDate[] }) => React.ReactNode` + +- `cellsOrder`: `'asc' | 'desc'`, default: `'asc'`. + +- `cellsPerRow`: `number` **required**. + +### `Calendar.MonthsCell` + +Renders the cell for a single month. + +#### Props + +- Extends `React.HTMLAttributes` + +- `value`: `PickerValidDate` - **required**. + +### `Calendar.YearsList` + +Top level component to pick a year when the layout is a list. + +It expects a function as its children, which receives the list of years to render as a parameter: + +```tsx + + {({ years }) => + years.map((year) => ) + } + +``` + +This component takes care of the keyboard navigation (for example Arrow Up). + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { years: PickerValidDate[] }) => React.ReactNode` + +- `cellsOrder`: `'asc' | 'desc'`, default: `'asc'`. + +### `Calendar.YearsGrid` + +Top level component to pick a year when the layout is a grid. + +It expects a function as its children, which receives the list of years to render as a parameter: + +```tsx + + {({ years }) => + years.map((year) => ) + } + +``` + +This component takes care of the keyboard navigation (for example Arrow Up). + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { years: PickerValidDate[] }) => React.ReactNode` + +- `cellsOrder`: `'asc' | 'desc'`, default: `'asc'`. + +- `cellsPerRow`: `number` **required**. + +### `Calendar.YearsCell` + +Renders the cell for a single year. + +#### Props + +- Extends `React.HTMLAttributes` + +- `value`: `PickerValidDate` - **required**. diff --git a/docs/data/date-pickers/rfc-digital-clock.md b/docs/data/date-pickers/rfc-digital-clock.md new file mode 100644 index 0000000000000..69a5eee064122 --- /dev/null +++ b/docs/data/date-pickers/rfc-digital-clock.md @@ -0,0 +1,470 @@ +--- +productId: x-date-pickers +title: DX - Digital Clock +--- + +# Digital Clock + +

This page describes how people can use time views with Material UI and how they can build custom time views.

+ +## Multi section - without meridiem + +### Without Material UI + +The user can use the `` and `` components to list all the time options with one column per section: + +```tsx + + + {({ hours }) => + hours.map((hour) => ) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + +``` + +### With Material UI + +TODO + +## Multi section - with meridiem + +### Without Material UI + +The user can use the `` component to add a column to edit this section. +It should be used in combination with the `` component: + +```tsx + + + {({ hours }) => + hours.map((hour) => ) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + + {({ meridiems }) => + meridiems.map((meridiem) => ( + + )) + } + + +``` + +:::success +We could also skip `` and instead add a `ampm` prop on ``. +But I like the idea of having two distinct components that could host different props in the future. +::: + +### With Material UI + +TODO + +## Multi section - auto meridiem + +### Without Material UI + +The user can use the `useIs12HourCycleInCurrentLocale()` hook to know if the meridiem should be enabled based on the current locale and build the UI accordingly: + +```tsx +function App(props) { + const defaultAmpm = useIs12HourCycleInCurrentLocale(); + + const { ampm = defaultAmpm, ...other } = props; + + return ( + + {ampm ? ( + + {({ hours }) => + hours.map((hour) => ( + + )) + } + + ) : ( + + {({ hours }) => + hours.map((hour) => ( + + )) + } + + )} + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + {ampm && ( + + {({ meridiems }) => + meridiems.map((meridiem) => ( + + )) + } + + )} + + ); +} +``` + +### With Material UI + +TODO + +## Multi section - with seconds + +### Without Material UI + +The user can use the `` component to add a column to edit this section: + +```tsx + + + {({ hours }) => + hours.map((hour) => ) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + + {({ seconds }) => + seconds.map((second) => ( + + )) + } + + +``` + +### With Material UI + +TODO + +## Multi section - custom steps + +### Without Material UI + +The ``, ``, `` and `` components take a `step` prop that allow to customize the step between two consecutive options. +By default, the step is of `1` for the hours and `5` for the minutes and seconds: + +```tsx + + + {({ hours }) => + hours.map((hour) => ) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + +``` + +```tsx + + + {({ hours }) => + hours.map((hour) => ) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + + +``` + +### With Material UI + +TODO + +## Multi section - custom format + +### Without Material UI + +By default, the `` uses a default format provided by its parent (for example ``). +The user can override this format using the `format` prop: + +```tsx + + + {({ hours }) => + hours.map((hour) => ( + + )) + } + + +``` + +### With Material UI + +TODO + +## Single section + +### Without Material UI + +The user can use the `` component to manually list options: + +```tsx + + + + + + + +``` + +:::succcess +Do we think it would be interesting to have a component for single-section but where we own the list generation? +Something like: + +```tsx + + + {' '} + // Very unclear DX for the `step` prop + {({ option }) => } + + +``` + +I think it's not a requirement for an MVP. +::: + +### With Material UI + +TODO + +## Anatomy of `DigitalClock.*` + +### `DigitalClock.Root` + +Top level component that wraps the other components. + +#### Props + +- Extends `React.HTMLAttributes` + +- **Value props**: `value`, `defaultValue`, `referenceDate`, `onValueChange`, `onError` and `timezone`. + + Same typing and behavior as today. + +- **Validation props**: `maxTime`, `minTime`, `disableFuture`, `disablePast`, `isTimeInvalid` (equivalent of the current `shouldDisableTime`). + + Same typing and behavior as today. + +- **Form props**: `disabled`, `readOnly`. + + Same typing and behavior as today. + +- `autoFocus`: `boolean` + +:::success +All the props that the picker can pass to the calendar (validation props, value props, etc...) are read both from the props and from `usePickerContext` so that the calendar can be used inside a picker built with composition. + +That way, users only have to pass the props specific to the calendar to the `DigitalClock.*` components: + +```tsx + + {/** See the field documentation */} + + + + + {/** See demo above */} + + + + +``` + +::: + +### `DigitalClock.Options` + +Renders a list of options. + +#### Props + +- Extends `React.HTMLAttributes` + +TODO + +### `DigitalClock.HourOptions` + +Renders a list of options to select the hours of the current value. + +It expects a function as its children, which receives the list of hours as a parameter: + +```tsx + + {({ hours }) => + hours.map((hour) => ) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { hours: PickerValidDate[] }) => React.ReactNode` + +- `skipInvalid`: `boolean`, default: `false` + If `true`, the invalid options are not rendered + +### `DigitalClock.HoursWithMeridiemOptions` + +Renders a list of options to select the hours of the current value. +The options will only be hours inside the same meridiem as the one currently selected, this component needs to be used in combination with ``. + +It expects a function as its children, which receives the list of hours as a parameter: + +```tsx + + {({ hours }) => + hours.map((hour) => ) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { hours: PickerValidDate[] }) => React.ReactNode` + +- `skipInvalid`: `boolean`, default: `false` + If `true`, the invalid options are not rendered + +### `DigitalClock.MeridiemOptions` + +Renders a list of options to select the meridiem of the current value. + +It expects a function as its children, which receives the list of meridiems as a parameter: + +```tsx + + {({ meridiems }) => + meridiems.map((meridiem) => ( + + )) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { meridiems: PickerValidDate[] }) => React.ReactNode` + +- `skipInvalid`: `boolean`, default: `false` + If `true`, the invalid options are not rendered + +### `DigitalClock.MinuteOptions` + +Renders a list of options to select the minutes of the current value. + +It expects a function as its children, which receives the list of minutes as a parameter: + +```tsx + + {({ minutes }) => + minutes.map((minute) => ( + + )) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { hours: PickerValidDate[] }) => React.ReactNode` + +- `skipInvalid`: `boolean`, default: `false` + If `true`, the invalid options are not rendered + +### `DigitalClock.SecondOptions` + +Renders a list of options to select the seconds of the current value. + +It expects a function as its children, which receives the list of seconds as a parameter: + +```tsx + + {({ seconds }) => + seconds.map((second) => ( + + )) + } + +``` + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `(params: { seconds: PickerValidDate[] }) => React.ReactNode` + +- `skipInvalid`: `boolean`, default: `false` + If `true`, the invalid options are not rendered + +### `DigitalClock.Option` + +Renders the button for a single option + +#### Props + +- Extends `React.HTMLAttributes` + +- `value`: `PickerValidDate` **required** + +- `format`: `string`, default: provided by the parent diff --git a/docs/data/date-pickers/rfc-field.md b/docs/data/date-pickers/rfc-field.md new file mode 100644 index 0000000000000..b2b938a21bafa --- /dev/null +++ b/docs/data/date-pickers/rfc-field.md @@ -0,0 +1,426 @@ +--- +productId: x-date-pickers +title: DX - Field +--- + +# Field + +

This page describes how people can use field with Material UI and how they can build custom fields while keeping the built-in editing behavior.

+ +:::success +This page extends the initial proposal made in [this GitHub comment](https://github.com/mui/mui-x/issues/14496#issuecomment-2348917294) +::: + +## Basic standalone usage + +### Without Material UI + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field'; + +function CustomDateField(props) { + const manager = useDateManager(); + + return ( + + + {({ sections }) => + sections.map((section) => ( + + + + + + )) + } + + + ); +} +``` + +The field can then be rendered just like the Material UI fields: + +```tsx + +``` + +### With Material UI + +The `@mui/x-date-pickers` package exposes one field per value type. +Those components are self-contained components (meaning they don't use composition). + +Here is a basic example of a ``: + +```tsx +import { DateField } from '@mui/x-date-pickers/DateField'; + +; +``` + +The behavior is the same for all the other fields: + +```tsx +; + +; + +; + +; + +; +``` + +:::success +This RFC proposes to rename `` into `` for concision when the single input range fields become the default and when the multi input range fields are gathered into a single component. +::: + +:::success +All these self-contained components are built on top of `PickerField`. +An intermediary internal component is needed to only create the component once and then have each field pass its `manager` to it. +::: + +## Basic usage inside a picker + +### Without Material UI + +#### Add a trigger to open the picker + +To be able to open the picker using its field, the user has to add a trigger button for the Popover or the Modal that is used inside the picker. +You can find more demos on the picker documentation on how to handle mobile and responsive pickers. + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field'; + +function CustomDateField(props) { + const manager = useDateManager(); + + return ( + + {/** See demo above */} + 📅 + + ); +} +``` + +:::success +If requested, a new utility hook could be added to easily check if the field is inside a picker. This would allow the same field component to be used as standalone and inside a picker: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { useIsInsidePicker } from '@base-ui-components/react-x-date-pickers/hooks'; +import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field'; + +function CustomDateField(props) { + const manager = useDateManager(); + const isInsidePicker = useIsInsidePicker(); + + return ( + + {/** See demo above */} + {isInsidePicker && 📅} + + ); +} +``` + +::: + +#### Inside a picker from `@mui/x-date-pickers` + +Even if most applications with a custom field probably want to remove `@mui/material` entirely, using these custom fields inside a self contained picker component from `@mui/x-date-pickers/DatePicker` is totally doable. +This can be useful for application using Material UI but with some specific needs for the fields or to allow for a gradual migration away from Material UI. + +```tsx +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +; +``` + +:::success +The concept of slots does not fit this use case very well, but the exploration of a better DX to override part of the UI in self-contained component is outside the scope of this documentation, so this RFC uses the tools currently available. +::: + +#### Inside an unstyled picker + +The custom field can also be used inside a picker built with the composable `Picker.*` component from `@base-ui-components/react-x-date-pickers/picker`: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + +function CustomDatePicker(props) { + const manager = useDateManager(); + + return ( + + + + + {/** See picker documentation */} + + + ); +} +``` + +The user can also inline their field if they want: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + +function CustomDatePicker(props) { + const manager = useDateManager(); + + return ( + + + + {/** See demo above */} + 📅 + + + {/** See picker documentation */} + + + ); +} +``` + +:::success +When doing that, the `` component doesn't have to receive props like `minDate` because they are accessed using `usePickerContext()` (or maybe a dedicated `usePickerValidationContext()`). This makes composition viable between the picker and the field (same for the views). +::: + +### With Material UI + +:::success +No DX change here compared to today. +The only change is that the field component are detecting if there is a picker around them and adding an opening button if so (instead of having the picker pass a prop to define this opening button). +::: + +The field exposed by `@mui/x-date-pickers` and `@mui/x-date-pickers` automatically + +```tsx +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +; +``` + +:::success +The concept of slots does not fit this use case very well, but the exploration of a better DX to override part of the UI in self-contained component is outside the scope of this documentation, so this RFC uses the tools currently available. +::: + +## Basic usage (multi input picker) + +### Without Material UI + +:::warning +This is not planned for now. +`Picker.*` could contain some additional components that would be the building blocks for `` but it does not seem to be the priority for now. +::: + +### With Material UI + +The `@mui/x-date-pickers` package also exposes a component to create multi input range fields as follow: + +```tsx +import { useDateRangeManager } from '@mui/x-date-pickers/managers'; +import { MultiInputRangeField } from '@mui/x-date-pickers/MultiInputRangeField'; + +function MultiInputDateTimeRangeField(props: MultiInputDateTimeRangeFieldProps) { + const manager = useDateTimeRangeManager(props); + + return ; +} +``` + +When used inside a picker, `` can be passed directly and uses the `manager` exposed by `usePickerContext`: + +```tsx + +``` + +:::success +There is a POC of this in [#15505](https://github.com/mui/mui-x/pull/15505). +::: + +## Clearable field + +### Without Material UI + +The user can use the `` component to add a button to clear the value: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { PickerField } from '@base-ui-components/react-x-date-pickers/picker-field'; + +function CustomDateField(props) { + const manager = useDateManager(); + + return ( + + {/** See demo above */} + + + + + ); +} +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +```tsx + + + +``` + +## Anatomy of `PickerField.*` + +### `PickerField.Root` + +Top level component that wraps the other components. +It would expend `Field.Root` from `@base-ui-components/react/Field`. + +#### Props + +- Extends `Field.Root.Props` + +- `manager`: `PickerManager` - **required for standalone fields** + + :::success + See [#15395](https://github.com/mui/mui-x/issues/15395) for context. + ::: + +- **Value props**: `value`, `defaultValue`, `referenceDate`, `onChange`, `onError` and `timezone`. + + Same typing and behavior as today. + +- **Validation props**: list based on the `manager` prop + + For `useDateManager()` it would be `maxDate`, `minDate`, `disableFuture`, `disablePast`, `shouldDisableDate`, `shouldDisableMonth`, `shouldDisableYear`. + + Same typing and behavior as today. + +- **Form props**: `disabled`, `readOnly`. + + Same typing and behavior as today. + +- `format`: `string` (default value applied by the `manager`). + +- `formatDensity`: `'dense' | 'spacious'`, default: `'dense'`. + +- `shouldRespectLeadingZeros`: `boolean`, default: `false`. + +- `selectedSections`: `FieldSelectedSections` + +- `onSelectedSectionsChange`: `(newValue: FieldSelectedSections) => void` + +- `unstableFieldRef`: `React.Ref>` + + This one may not be needed. If its only used for internal purpose, it can probably be made internal (the picker would pass a ref using a private context instead of a prop). + + Keeping it unstable makes removing it easy. + +- `autoFocus`: `boolean` + +:::success +All the props that the picker can pass to the field (validation props, value props, etc...) are read both from the props and from `usePickerContext` so that the field can be used inside a picker built with composition. + +That way, users only have to pass the props specific to the field to the `PickerField.*` components: + +```tsx + + + {/** See demo above */} + + {/** See picker documentation */} + +``` + +::: + +### `PickerField.Content` + +It would expend `Field.Control` from `@base-ui-components/react/Field`. + +It expects a function as its children, which receives the list of sections to render as a parameter: + +```tsx + + {({ sections }) => + sections.map((section) => ( + + )) + } + +``` + +It also renders a hidden input which contains the stringified value and can be used for form submission and testing. + +#### Props + +- Extends `Field.Control.Props` + +- `children`: `(section: InferFieldSection) => React.ReactNode` + +### `PickerField.Section` + +Renders a single section (for instance the year of the hour of the current value). + +#### Props + +- Extends `React.HTMLAttributes` +- `section`: `InferFieldSection` (can be `FieldSection` or `FieldRangeSection`) - **required**. + +### `PickerField.SectionContent` + +Renders the content of a single section. + +#### Props + +- Extends `React.HTMLAttributes` + +### `PickerField.SectionSeparator` + +Renders the separator to display before or after the current section. + +```tsx + +``` + +#### Props + +- Extends `React.HTMLAttributes` +- `position`: `'before' | 'after'` - **required**. + +### `PickerField.Clear` + +Renders the button to clear the value of the field. + +#### Props + +- Extends `React.HTMLAttributes` + +- `children`: `React.ReactNode` + +- `onClear`: `React.MouseEventHandler` + + :::success + The new DX is a good opportunity to discuss the behavior of this prop. + The behavior should either be: + + 1. `onClear` is defined on ``. It is also fired when doing Ctrl + A and then Backspace. + 2. `onClear` is defined on `` (or not defined at all and people just use `onClick`). It is only fired when clicking on this button. + + ::: diff --git a/docs/data/date-pickers/rfc-overview.md b/docs/data/date-pickers/rfc-overview.md new file mode 100644 index 0000000000000..98eaf706aa8ab --- /dev/null +++ b/docs/data/date-pickers/rfc-overview.md @@ -0,0 +1,87 @@ +--- +productId: x-date-pickers +title: DX - Overview +--- + +# Overview + +

This page describes the main principles of the new DX.

+ +## General principles + +### Composition + +All the components displayed in the pages below are following the Base UI DX which means: + +- One component = one HTML element (except for elements like hidden ``) + +- Every component can receive a `render` prop to override the rendered element: + + ```tsx + import List from '@mui/material/List'; + import ListItem from '@mui/material/ListItem'; + import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + }> + {({ months }) => + months.map((month) => ( + } + /> + )) + } + ; + ``` + + This `render` prop can also accept a function that receives the `props` and the `state` of the component (equivalent of our `ownerState`): + + ```tsx + import List from '@mui/material/List'; + import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; + + ( + + )} + > + {/** See demo above */} + ; + ``` + +- Every component can receive a `className` prop, they don't have any `className` by default: + + ```tsx + // Will always have the class "day" + + + // Will always have the class "day" + // Will only have the class "day-selected" when the day is selected + clsx("day", state.isDaySelected && "day-selected")} + /> + ``` + + :::success + For most use-cases, people should use the `data-attr` instead of creating custom classes. + The state of the Date and Time Pickers is quite big so we won't add one `data-attr` for each property in it on each component. + We will probably add the most useful one (`data-selected` on the `` component for example) and people can use the `className` prop for more advanced use cases. + ::: + +- Components can have `data-attr` to allow conditional styling + + ```tsx + + ``` + + ```css + .day { + background-color: red; + } + + .day[data-selected] { + background-color: green; + } + ``` diff --git a/docs/data/date-pickers/rfc-picker.md b/docs/data/date-pickers/rfc-picker.md new file mode 100644 index 0000000000000..e300aa2dc957b --- /dev/null +++ b/docs/data/date-pickers/rfc-picker.md @@ -0,0 +1,579 @@ +--- +productId: x-date-pickers +title: DX - Picker +--- + +# Picker + +

This page describes how people can use picker with Material UI and how they can build custom pickers.

+ +:::success +This page extends the initial proposal made in [#14718](https://github.com/mui/mui-x/issues/14718) +::: + +:::success +We might need a `RangePicker.*` component that would expose additional tools like the range position. +::: + +## Usage in a Popover + +### Without Material UI + +#### With Base UI `Popover.*` components + +The user can use the `Picker.*` components in combination with the `Popover.*` components from `@base-ui-components/react` to build a picker: + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + +function DesktopDatePicker(props) { + const manager = useDateManager(); + + return ( + + {({ open, setOpen }) => ( + + + {/** See field documentation */} + 📅 + + + + + {/** See calendar documentation */} + + + + )} + + ); +} + +; +``` + +#### With React Aria `` components + +Even if Base UI will be the solution presented in the doc to connect the field and the view, nothing prevents the user from using another library: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Dialog, DialogTrigger, Button, Popover } from 'react-aria-components'; + +function DesktopDatePicker(props) { + const manager = useDateManager(); + + return ( + + {({ open, setOpen }) => ( + + + {/** See field documentation */} + + + + + {/** See calendar documentation */} + + + + )} + + ); +} + +; +``` + +### With Material UI + +The user can use the `` component: + +```tsx +import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker'; + +; +``` + +:::success +This component could be renamed `` to better match its behavior. +::: + +## Usage in a Dialog + +### Without Material UI + +#### With Base UI `Dialog.*` components + +The user can use the `Picker.*` components in combination with the `Dialog.*` components from `@base-ui-components/react` to build a picker: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Dialog } from '@base-ui-components/react/dialog'; + +function MobileDatePicker(props) { + const manager = useDateManager(); + + return ( + + {({ open, setOpen }) => ( + + + {/** See field documentation */} + 📅 + + + + {/** See calendar documentation */} + + + )} + + ); +} + +; +``` + +#### With Mantine `` component + +The user can use a Modal that expect different props for its lifecycle: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Modal, Button } from '@mantine/core'; + +function MobileDatePicker(props) { + const manager = useDateManager(); + + return ( + + {({ open, openPicker, closePicker }) => ( + + + {/** See field documentation */} + + + + + {/** See calendar documentation */} + + + + )} + + ); +} + +; +``` + +### With Material UI + +```tsx +import { MobileDatePicker } from '@mui/x-date-pickers/MobileDatePicker'; + +; +``` + +:::success +This component could be renamed `` to better match its behavior. +::: + +## Responsive usage + +### Without Material UI + +If the library does not provide any higher level utilities to create a responsive picker and sticks with "1 React component = 1 DOM element", here is what a responsive picker could look like: + +```tsx +import { useDateManager } from '@base-ui-components/react-x-date-pickers/managers'; +import { useMediaQuery } from '@base-ui-components/react-utils/useMediaQuery'; // not sure how the util package will be named +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Popover } from '@base-ui-components/react/popover'; + +function DatePicker(props) { + const isDesktop = useMediaQuery('@media (pointer: fine)'); + + const field = ( + + {/** See field documentation **/} + {isDesktop + ? 📅 + : 📅 + } + + ); + + const view = {/** See calendar documentation */}; + + if (isDesktop) { + return ( + + {({ open, setOpen }) => ( + + {field} + + + {view} + + + )} + + ); + } + + return ( + + {({ open, setOpen }) => ( + + {field} + + {view} + + )} + + ); +} + + +``` + +### With Material UI + +The user can use the `` component: + +```tsx +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +; +``` + +## Usage with date and time + +### Without Material UI + +The user can use both the `Calendar.*` and the `DigitalClock.*` components together to render the date and the time picking UI side by side. + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; +import { DigitalClock } from '@base-ui-components/react-x-date-pickers/digital-clock'; + +function PickerView() { + const [activeSection, setActiveSection] = React.useState('day'); + + return ( + + {/** See calendar documentation */} + {/** See digital clock documentation */} + + ); +} +``` + +:::success +One big things to still clarify here is how we can provide the right tools for focus management without adding a view management system into our components. +::: + +If the user wants to set the UI to select the date, then the time, he can conditionally render the view component based on some external state: + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Calendar } from '@base-ui-components/react-x-date-pickers/calendar'; +import { DigitalClock } from '@base-ui-components/react-x-date-pickers/digital-clock'; + +function PickerView() { + const [activeSection, setActiveSection] = React.useState('day'); + + return ( + + {['day', 'month', 'year'].includes(activeSection) ? ( + {/** See calendar documentation */} + ) : ( + + {/** See digital clock documentation */} + + )} + + ); +} +``` + +### With Material UI + +TODO + +## Add an action bar + +### Without Material UI + +The user can use the ``, `` and `` components to create an action bar and interact with the value: + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + + + {/** See calendar documentation */} +
+ Clear + Today + Accept + Cancel + Close +
+
+``` + +### With Material UI + +TODO + +## Add a toolbar + +### Without Material UI + +The user can use the the `usePickerContext()` hook to access to information like the current value and create a toolbar above the view content: + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { usePickerContext } from '@base-ui-components/react-x-date-pickers/hooks'; + +function PickerView() { + const { value } = usePickerContext(); + + return ( + +
{value.format('MMMM YYYY')}
+ {/** See calendar documentation */} +
+ ); +} +``` + +This toolbar can also be used to switch between sections if the parent component has a state to decide which one is currently rendered: + +```tsx +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { usePickerContext } from '@base-ui-components/react-x-date-pickers/hooks'; + +function PickerView() { + const [activeSection, setActiveSection] = React.useState('day'); + const { value } = usePickerContext(); + + return ( + +
+ + +
+ {/** See calendar documentation */} +
+ ); +} +``` + +### With Material UI + +TODO + +## Add tabs + +### Without Material UI + +The user can also build a `Tabs` component using the same tools and the toolbar: + +The example below uses the `Tabs` component from Base UI as an example: + +```tsx +import { Tabs } from '@base-ui-components/react/tabs'; +import { Popover } from '@base-ui-components/react/popover'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + +functon PickerViews() { + const [activeSection, setActiveSection] = React.useState('day'); + + return ( + + + + onActiveSectionChange('day')}> + Date + + onActiveSectionChange('hours')}> + Time + + + + {/** See calendar documentation */} + + ) +} +``` + +### With Material UI + +TODO + +## Add shortcuts + +### Without Material UI + +The user can use the `` component to create a shortcut UI: + +```tsx +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; +import { Popover } from '@base-ui-components/react/popover'; + + +
+ + New Year's Day + + + Independence Day + +
+ {/** See calendar documentation */} +
; +``` + +:::success +To support the `isValid` param of the Material UI shortcut, a `useIsValidValue` hook could be added. +Without it, it's not trivial to use `useValidation` since it requires a value and params like the validation props or the timezone. + +```tsx +import { useIsValueValid } from'@base-ui-components/react-x-date-pickers/hooks'; +import { Picker } from '@base-ui-components/react-x-date-pickers/picker'; + +const isValueValid = useIsValueValid(); + +const newAvailableSaturday = React.useMemo(() => { + const today = dayjs(); + const nextSaturday = + today.day() <= 6 + ? today.add(6 - today.day(), 'day') + : today.add(7 + 6 - today.day(), 'day'); + + let maxAttempts = 50; + let solution: Dayjs = nextSaturday; + while (maxAttempts > 0 && !isValueValid(solution)) { + solution = solution.add(7, 'day'); + maxAttempts -= 1; + } + + return solution; +}, [isValueValid]); + +return ( + Next available saturday +); +``` + +::: + +### With Material UI + +TODO + +## Anatomy of `Picker.*` + +### `Picker.Root` + +Top level component that wraps the other components. + +It expects a function as its children, which receives the context value as a parameter: + +```tsx + + {({ open, setOpen }) => } + +``` + +#### Props + +- `manager`: `PickerManager` - **required** + + :::success + See [#15395](https://github.com/mui/mui-x/issues/15395) for context. + ::: + +- `children`: `(contextValue: PickerContextValue) => React.ReactNode` + +- **Value props**: `value`, `defaultValue`, `referenceDate`, `onValueChange`, `onError` and `timezone`. + + Same typing and behavior as today. + +- **Validation props**: list based on the `manager` prop + + For `useDateManager()` it would be `maxDate`, `minDate`, `disableFuture`, `disablePast`, `isDateInvalid`, `isMonthInvalid`, `isYearInvalid`. + + Same typing and behavior as today. + +- **Form props**: `disabled`, `readOnly`. + + Same typing and behavior as today. + +- **Open props**: `open`, `onOpenChange` + + The `onOpenChange` replaces the `onOpen` and `onClose` props in the current implementation + +### `Picker.SetValue` + +Renders a button to set the current value. + +#### Props + +- Extends `React.HTMLAttributes` + +- `target`: `PickerValidDate` - **required** + +- `skipValidation`: `boolean`, default: `false` (by default the button is disabled is the target value is not passing validation) + +- `changeImportance`: `'set' | 'accept'`, default: `'accept'` + +- `skipPublicationIfPristine`: `boolean`, default: `false` + +#### Usages in the styled version + +- The List Item of `` (people creating custom UIs can also use this component) + +- The Button of `` that sets the value to today or clear the value + +### `Picker.AcceptValue` + +Renders a button to accept the current value. + +#### Props + +- Extends `React.HTMLAttributes` + +#### Usages in the styled version + +- The Button of `` that accepts the value + +### `Picker.CancelValue` + +Renders a button to cancel the current value. + +#### Props + +- Extends `React.HTMLAttributes` + +#### Usages in the styled version + +- The Button of `` that cancels the value diff --git a/docs/data/date-pickers/rfc-range-calendar.md b/docs/data/date-pickers/rfc-range-calendar.md new file mode 100644 index 0000000000000..e338b28b29637 --- /dev/null +++ b/docs/data/date-pickers/rfc-range-calendar.md @@ -0,0 +1,70 @@ +--- +productId: x-date-pickers +title: DX - RangeCalendar +--- + +# Range Calendar + +

This page describes how people can use date range views with Material UI and how they can build custom date range views.

+ +:::success +Almost all the components of `RangeCalendar.*` are the same as their `Calendar.*` counterpart. +::: + +## Usage with only days + +### Without Material UI + +The user can use the ``, ``, ``, ``, `` and `` components to create a grid of days: + +```tsx +import { RangeCalendar } from '@base-ui-components/react-x-date-pickers-pro/range-calendar'; + + + {({ visibleMonth }) => ( + +
+ + {visibleMonth.format('MMMM YYYY')} + +
+ + + {({ days }) => + days.map((day) => ( + + )) + } + + + {({ weeks }) => + weeks.map((week) => ( + + {({ days }) => + days.map((day) => ( + + )) + } + + )) + } + + +
+ )} +
; +``` + +### With Material UI + +:::success +No DX change here compared to today +::: + +The user can use the ``: + +```tsx +import { DateRangeCalendar } from '@mui/x-date-pickers/DateCalendar'; + +; +``` diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 5def15ccecfdc..5a7d0db8dba03 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -259,6 +259,22 @@ const pages: MuiPage[] = [ }, ], }, + { + pathname: '/x/react-date-pickers/rfc', + title: 'Date and Time Pickers - new DX', + children: [ + { pathname: '/x/react-date-pickers/rfc-overview', title: 'Overview' }, + { pathname: '/x/react-date-pickers/rfc-field', title: 'Field' }, + { pathname: '/x/react-date-pickers/rfc-calendar', title: 'Calendar' }, + { + pathname: '/x/react-date-pickers/rfc-range-calendar', + title: 'Range Calendar', + plan: 'pro', + }, + { pathname: '/x/react-date-pickers/rfc-digital-clock', title: 'Digital Clock' }, + { pathname: '/x/react-date-pickers/rfc-picker', title: 'Picker' }, + ], + }, { pathname: '/x/react-date-pickers-group', title: 'Date and Time Pickers', diff --git a/docs/pages/x/react-date-pickers/rfc-calendar.js b/docs/pages/x/react-date-pickers/rfc-calendar.js new file mode 100644 index 0000000000000..702b6d21560ee --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-calendar.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-calendar.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/x/react-date-pickers/rfc-digital-clock.js b/docs/pages/x/react-date-pickers/rfc-digital-clock.js new file mode 100644 index 0000000000000..9126fc2941f66 --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-digital-clock.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-digital-clock.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/x/react-date-pickers/rfc-field.js b/docs/pages/x/react-date-pickers/rfc-field.js new file mode 100644 index 0000000000000..afb95e4a78d36 --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-field.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-field.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/x/react-date-pickers/rfc-overview.js b/docs/pages/x/react-date-pickers/rfc-overview.js new file mode 100644 index 0000000000000..18b5089b4fa77 --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-overview.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-overview.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/x/react-date-pickers/rfc-picker.js b/docs/pages/x/react-date-pickers/rfc-picker.js new file mode 100644 index 0000000000000..fe3714e044859 --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-picker.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-picker.md?muiMarkdown'; + +export default function Page() { + return ; +} diff --git a/docs/pages/x/react-date-pickers/rfc-range-calendar.js b/docs/pages/x/react-date-pickers/rfc-range-calendar.js new file mode 100644 index 0000000000000..5c62aa41ee64d --- /dev/null +++ b/docs/pages/x/react-date-pickers/rfc-range-calendar.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docsx/data/date-pickers/rfc-range-calendar.md?muiMarkdown'; + +export default function Page() { + return ; +}