From 4f815d952acb876ad196d43a804c04badc93d8ce Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 23 Jun 2023 09:19:19 +0200 Subject: [PATCH 01/74] [pickers] New component: TimeRangePicker --- .eslintrc.js | 1 + .../DesktopTimeRangePicker.tsx | 381 ++++++++++++++++++ .../DesktopTimeRangePicker.types.ts | 51 +++ .../src/DesktopTimeRangePicker/index.ts | 6 + .../src/TimeRangePicker/shared.tsx | 145 +++++++ .../timeRangeViewRenderers.tsx | 22 + .../x-date-pickers/src/internals/index.ts | 3 +- 7 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx create mode 100644 packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts create mode 100644 packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx create mode 100644 packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx diff --git a/.eslintrc.js b/.eslintrc.js index e438b28918126..333097adef3a4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -155,6 +155,7 @@ module.exports = { 'useTimePickerDefaultizedProps', 'useDateTimePickerDefaultizedProps', 'useDateRangePickerDefaultizedProps', + 'useTimeRangePickerDefaultizedProps', 'useDateCalendarDefaultizedProps', 'useMonthCalendarDefaultizedProps', 'useYearCalendarDefaultizedProps', diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx new file mode 100644 index 0000000000000..077a4e1ce5a46 --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -0,0 +1,381 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { extractValidationProps, PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; +import { resolveComponentProps } from '@mui/base/utils'; +import { rangeValueManager } from '../internal/utils/valueManagers'; +import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; +import { useDateRangePickerDefaultizedProps } from '../DateRangePicker/shared'; +import { renderDateRangeViewCalendar } from '@mui/x-date-pickers/timeViewRenderers'; +import { MultiInputDateRangeField } from '../MultiInputDateRangeField'; +import { useDesktopRangePicker } from '../internal/hooks/useDesktopRangePicker'; +import { validateDateRange } from '../internal/utils/validation/validateDateRange'; +import { DateRange } from '../internal/models'; + +type DesktopTimeRangePickerComponent = (( + props: DesktopTimeRangePickerProps & React.RefAttributes, +) => JSX.Element) & { propTypes?: any }; + +const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker( + inProps: DesktopTimeRangePickerProps, + ref: React.Ref, +) { + // Props with the default values common to all date time pickers + const defaultizedProps = useDateRangePickerDefaultizedProps< + TDate, + DesktopTimeRangePickerProps + >(inProps, 'MuiDesktopTimeRangePicker'); + + const viewRenderers: PickerViewRendererLookup, 'day', any, {}> = { + day: renderDateRangeViewCalendar, + ...defaultizedProps.viewRenderers, + }; + + const props = { + ...defaultizedProps, + viewRenderers, + calendars: defaultizedProps.calendars ?? 2, + views: ['day'] as const, + openTo: 'day' as const, + slots: { + field: MultiInputDateRangeField, + ...defaultizedProps.slots, + }, + slotProps: { + ...defaultizedProps.slotProps, + field: (ownerState: any) => ({ + ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), + ...extractValidationProps(defaultizedProps), + ref, + }), + toolbar: { + hidden: true, + ...defaultizedProps.slotProps?.toolbar, + }, + }, + }; + + const { renderPicker } = useDesktopRangePicker({ + props, + valueManager: rangeValueManager, + valueType: 'date', + validator: validateDateRange, + }); + + return renderPicker(); +}) as DesktopTimeRangePickerComponent; + +DesktopTimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + /** + * The number of calendars to render on **desktop**. + * @default 2 + */ + calendars: PropTypes.oneOf([1, 2, 3]), + /** + * Class name applied to the root element. + */ + className: PropTypes.string, + /** + * If `true`, the popover or modal will close after submitting the full date. + * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + */ + closeOnSelect: PropTypes.bool, + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components: PropTypes.object, + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps: PropTypes.object, + /** + * Position the current month is rendered in. + * @default 1 + */ + currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), + /** + * Formats the day of week displayed in the calendar header. + * @param {string} day The day of week provided by the adapter's method `getWeekdays`. + * @returns {string} The name to display. + * @default (day) => day.charAt(0).toUpperCase() + */ + dayOfWeekFormatter: PropTypes.func, + /** + * Default calendar month displayed when `value={[null, null]}`. + */ + defaultCalendarMonth: PropTypes.any, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.any), + /** + * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. + * @default false + */ + disableAutoMonthSwitching: PropTypes.bool, + /** + * If `true`, the picker and text field are disabled. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, editing dates by dragging is disabled. + * @default false + */ + disableDragEditing: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * If `true`, today's date is rendering without highlighting with circle. + * @default false + */ + disableHighlightToday: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * If `true`, the week number will be display in the calendar. + */ + displayWeekNumber: PropTypes.bool, + /** + * Calendar will show more weeks in order to match this value. + * Put it to 6 for having fix number of week in Gregorian calendars + * @default undefined + */ + fixedWeekNumber: PropTypes.number, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + current: PropTypes.object, + }), + ]), + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * If `true`, calls `renderLoading` instead of rendering the day calendar. + * Can be used to preload information and show it in calendar. + * @default false + */ + loading: PropTypes.bool, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable date. + */ + maxDate: PropTypes.any, + /** + * Minimal selectable date. + */ + minDate: PropTypes.any, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated to the current value changes. + * If the error has a non-null value, then the `TextField` will be rendered in `error` state. + * + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TError} error The new error describing why the current value is not valid. + * @param {TValue} value The value associated to the error. + */ + onError: PropTypes.func, + /** + * Callback fired on month change. + * @template TDate + * @param {TDate} month The new month. + */ + onMonthChange: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + readOnly: PropTypes.bool, + /** + * Disable heavy animations. + * @default typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent) + */ + reduceAnimations: PropTypes.bool, + /** + * Component displaying when passed `loading` true. + * @returns {React.ReactNode} The node to render when loading. + * @default () => "..." + */ + renderLoading: PropTypes.func, + /** + * The currently selected sections. + * This prop accept four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If an object with a `startIndex` and `endIndex` properties are provided, the sections between those two indexes will be selected. + * 3. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 4. If `null` is provided, no section will be selected + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + PropTypes.shape({ + endIndex: PropTypes.number.isRequired, + startIndex: PropTypes.number.isRequired, + }), + ]), + /** + * Disable specific date. + * @template TDate + * @param {TDate} day The date to test. + * @param {string} position The date to test, 'start' or 'end'. + * @returns {boolean} Returns `true` if the date should be disabled. + */ + shouldDisableDate: PropTypes.func, + /** + * If `true`, days outside the current month are rendered: + * + * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. + * + * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. + * + * - ignored if `calendars` equals more than `1` on range pickers. + * @default false + */ + showDaysOutsideCurrentMonth: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documention} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.any), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + day: PropTypes.func, + }), +} as any; + +export { DesktopTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts new file mode 100644 index 0000000000000..2a08d6f87ee6d --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts @@ -0,0 +1,51 @@ +import { MakeOptional, UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { + UseDesktopRangePickerSlotsComponent, + UseDesktopRangePickerSlotsComponentsProps, + DesktopRangeOnlyPickerProps, +} from '../internal/hooks/useDesktopRangePicker'; +import { + BaseDateRangePickerProps, + BaseDateRangePickerSlotsComponent, + BaseDateRangePickerSlotsComponentsProps, +} from '../DateRangePicker/shared'; + +export interface DesktopTimeRangePickerSlotsComponent + extends BaseDateRangePickerSlotsComponent, + MakeOptional, 'Field'> {} + +export interface DesktopTimeRangePickerSlotsComponentsProps + extends BaseDateRangePickerSlotsComponentsProps, + UseDesktopRangePickerSlotsComponentsProps {} + +export interface DesktopTimeRangePickerProps + extends BaseDateRangePickerProps, + DesktopRangeOnlyPickerProps { + /** + * The number of calendars to render on **desktop**. + * @default 2 + */ + calendars?: 1 | 2 | 3; + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components?: DesktopTimeRangePickerSlotsComponent; + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps?: DesktopTimeRangePickerSlotsComponentsProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: UncapitalizeObjectKeys>; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: DesktopTimeRangePickerSlotsComponentsProps; +} diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts new file mode 100644 index 0000000000000..18ec2c7a105e1 --- /dev/null +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/index.ts @@ -0,0 +1,6 @@ +export { DesktopTimeRangePicker } from './DesktopTimeRangePicker'; +export type { + DesktopTimeRangePickerProps, + DesktopTimeRangePickerSlotsComponent, + DesktopTimeRangePickerSlotsComponentsProps, +} from './DesktopTimeRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx new file mode 100644 index 0000000000000..5d10d56705f31 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -0,0 +1,145 @@ +import * as React from 'react'; +import { useThemeProps } from '@mui/material/styles'; +import { LocalizedComponent, PickersInputLocaleText } from '@mui/x-date-pickers/locales'; +import { + DefaultizedProps, + BasePickerInputProps, + PickerViewRendererLookup, + UncapitalizeObjectKeys, + uncapitalizeObjectKeys, + BaseTimeValidationProps, + BaseClockProps, + ExportedBaseClockProps, + TimeViewWithMeridiem, + useUtils, +} from '@mui/x-date-pickers/internals'; +import { + TimeClockSlotsComponent, + TimeClockSlotsComponentsProps, +} from '@mui/x-date-pickers/TimeClock'; +import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; +// TODO: Fix nested import +import { + TimePickerToolbar, + TimePickerToolbarProps, + ExportedTimePickerToolbarProps, +} from '@mui/x-date-pickers/TimePicker/TimePickerToolbar'; +import { TimeRangeValidationError } from '../models'; +import { DateRange } from '../internal/models'; + +export interface BaseTimeRangePickerSlotsComponent extends TimeClockSlotsComponent { + /** + * Custom component for the toolbar rendered above the views. + * @default DateTimePickerToolbar + */ + Toolbar?: React.JSXElementConstructor>; +} + +export interface BaseTimeRangePickerSlotsComponentsProps extends TimeClockSlotsComponentsProps { + toolbar?: ExportedTimePickerToolbarProps; +} + +export interface BaseTimeRangePickerProps + extends Omit< + BasePickerInputProps, TDate, TView, TimeRangeValidationError>, + 'view' | 'views' | 'openTo' | 'onViewChange' | 'orientation' + >, + ExportedBaseClockProps { + /** + * Display ampm controls under the clock (instead of in the toolbar). + * @default true on desktop, false on mobile + */ + ampmInClock?: boolean; + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components?: BaseTimeRangePickerSlotsComponent; + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps?: BaseTimeRangePickerSlotsComponentsProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: UncapitalizeObjectKeys>; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: BaseTimeRangePickerSlotsComponentsProps; + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers?: Partial< + PickerViewRendererLookup< + DateRange, + TView, + TimeViewRendererProps>, + {} + > + >; +} + +type UseTimeRangePickerDefaultizedProps< + TDate, + TView extends TimeViewWithMeridiem, + Props extends BaseTimeRangePickerProps, +> = LocalizedComponent>; + +export function useTimeRangePickerDefaultizedProps< + TDate, + TView extends TimeViewWithMeridiem, + Props extends BaseTimeRangePickerProps, +>( + props: Props, + name: string, +): UseTimeRangePickerDefaultizedProps> { + const utils = useUtils(); + + const themeProps = useThemeProps({ + props, + name, + }); + + const ampm = themeProps.ampm ?? utils.is12HourCycleInCurrentLocale(); + + const localeText = React.useMemo | undefined>(() => { + if (themeProps.localeText?.toolbarTitle == null) { + return themeProps.localeText; + } + + return { + ...themeProps.localeText, + dateRangePickerToolbarTitle: themeProps.localeText.toolbarTitle, + }; + }, [themeProps.localeText]); + + const slots = themeProps.slots ?? uncapitalizeObjectKeys(themeProps.components); + const slotProps = themeProps.slotProps ?? themeProps.componentsProps; + + return { + ...themeProps, + localeText, + disableFuture: themeProps.disableFuture ?? false, + disablePast: themeProps.disablePast ?? false, + slots: { + toolbar: TimePickerToolbar, + ...slots, + }, + slotProps: { + ...slotProps, + toolbar: { + ampm, + ampmInClock: themeProps.ampmInClock, + ...slotProps?.toolbar, + }, + }, + }; +} diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx new file mode 100644 index 0000000000000..57c6312c78637 --- /dev/null +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -0,0 +1,22 @@ +import { BaseClockProps, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; +import { + DigitalClockProps, + TimePickerProps, +} from '@mui/x-date-pickers/DigitalClock'; +import { TimeView } from '@mui/x-date-pickers/models' + +export type TimeRangeViewRendererProps< + TView extends TimeViewWithMeridiem, + TComponentProps extends BaseClockProps, +> = Omit & { + view: TView; + onViewChange?: (view: TView) => void; + views: readonly TView[]; +}; + +export const renderDigitalClockTimeRangeView = ({}: TimeRangeViewRendererProps< + Extract, + Omit, 'timeStep'> & Pick, 'timeSteps'> +>) => { + return
HELLO
; +}; diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 2bdbbe3054e70..5e5e5ed2437fc 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -104,9 +104,10 @@ export type { BasePickerInputProps, BaseNonStaticPickerProps, } from './models/props/basePickerProps'; +export type { BaseClockProps, ExportedBaseClockProps } from './models/props/clock'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; export type { DefaultizedProps, MakeOptional } from './models/helpers'; -export type { WrapperVariant } from './models/common'; +export type { WrapperVariant, TimeViewWithMeridiem } from './models/common'; export type { BaseDateValidationProps, BaseTimeValidationProps, From e6be6892493b8bf91757c920ae2d923bbe62d72b Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 12 Sep 2023 09:00:59 +0200 Subject: [PATCH 02/74] Work --- docs/data/date-pickers/localization/data.json | 124 +++++++------- .../DesktopTimeRangePicker.tsx | 55 +++++-- .../DesktopTimeRangePicker.types.ts | 38 +++-- .../TimeRangePicker/TimeRangePicker.types.ts | 43 +++++ .../TimeRangePickerToolbar.tsx | 151 ++++++++++++++++++ .../src/TimeRangePicker/index.ts | 14 ++ .../src/TimeRangePicker/shared.tsx | 35 ++-- .../timeRangePickerToolbarClasses.ts | 22 +++ .../hooks/useDesktopRangePicker/index.ts | 1 + .../useDesktopRangePicker.types.ts | 11 +- .../src/timeRangeViewRenderers/index.ts | 1 + .../timeRangeViewRenderers.tsx | 44 ++++- .../x-date-pickers/src/internals/index.ts | 7 +- packages/x-date-pickers/src/locales/beBY.ts | 1 + packages/x-date-pickers/src/locales/caES.ts | 1 + packages/x-date-pickers/src/locales/csCZ.ts | 1 + packages/x-date-pickers/src/locales/daDK.ts | 1 + packages/x-date-pickers/src/locales/deDE.ts | 1 + packages/x-date-pickers/src/locales/elGR.ts | 1 + packages/x-date-pickers/src/locales/enUS.ts | 1 + packages/x-date-pickers/src/locales/esES.ts | 1 + packages/x-date-pickers/src/locales/faIR.ts | 1 + packages/x-date-pickers/src/locales/fiFI.ts | 1 + packages/x-date-pickers/src/locales/frFR.ts | 1 + packages/x-date-pickers/src/locales/heIL.ts | 1 + packages/x-date-pickers/src/locales/huHU.ts | 1 + packages/x-date-pickers/src/locales/isIS.ts | 1 + packages/x-date-pickers/src/locales/itIT.ts | 1 + packages/x-date-pickers/src/locales/jaJP.ts | 1 + packages/x-date-pickers/src/locales/koKR.ts | 1 + packages/x-date-pickers/src/locales/kzKZ.ts | 1 + packages/x-date-pickers/src/locales/nbNO.ts | 1 + packages/x-date-pickers/src/locales/nlNL.ts | 1 + packages/x-date-pickers/src/locales/plPL.ts | 1 + packages/x-date-pickers/src/locales/ptBR.ts | 1 + packages/x-date-pickers/src/locales/roRO.ts | 1 + packages/x-date-pickers/src/locales/ruRU.ts | 1 + packages/x-date-pickers/src/locales/skSK.ts | 1 + packages/x-date-pickers/src/locales/svSE.ts | 1 + packages/x-date-pickers/src/locales/trTR.ts | 1 + packages/x-date-pickers/src/locales/ukUA.ts | 1 + packages/x-date-pickers/src/locales/urPK.ts | 1 + .../src/locales/utils/pickersLocaleTextApi.ts | 5 + packages/x-date-pickers/src/locales/viVN.ts | 1 + packages/x-date-pickers/src/locales/zhCN.ts | 1 + packages/x-date-pickers/src/locales/zhHK.ts | 1 + .../timeViewRenderers/timeViewRenderers.tsx | 2 +- 47 files changed, 468 insertions(+), 117 deletions(-) create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/index.ts create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts create mode 100644 packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index df35a1aa34ebf..1b52b8eae2544 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -3,248 +3,248 @@ "languageTag": "be-BY", "importName": "beBY", "localeName": "Belarusian", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/beBY.ts" }, { "languageTag": "ca-ES", "importName": "caES", "localeName": "Catalan", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/caES.ts" }, { "languageTag": "zh-HK", "importName": "zhHK", "localeName": "Chinese (Hong Kong)", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhHK.ts" }, { "languageTag": "zh-CN", "importName": "zhCN", "localeName": "Chinese (Simplified)", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhCN.ts" }, { "languageTag": "cs-CZ", "importName": "csCZ", "localeName": "Czech", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/csCZ.ts" }, { "languageTag": "da-DK", "importName": "daDK", "localeName": "Danish", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/daDK.ts" }, { "languageTag": "nl-NL", "importName": "nlNL", "localeName": "Dutch", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nlNL.ts" }, { "languageTag": "fi-FI", "importName": "fiFI", "localeName": "Finnish", - "missingKeysCount": 8, - "totalKeysCount": 36, + "missingKeysCount": 9, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/fiFI.ts" }, { "languageTag": "fr-FR", "importName": "frFR", "localeName": "French", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/frFR.ts" }, { "languageTag": "de-DE", "importName": "deDE", "localeName": "German", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/deDE.ts" }, { "languageTag": "el-GR", "importName": "elGR", "localeName": "Greek", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/elGR.ts" }, { "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/heIL.ts" }, { "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/huHU.ts" }, { "languageTag": "is-IS", "importName": "isIS", "localeName": "Icelandic", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/isIS.ts" }, { "languageTag": "it-IT", "importName": "itIT", "localeName": "Italian", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/itIT.ts" }, { "languageTag": "ja-JP", "importName": "jaJP", "localeName": "Japanese", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/jaJP.ts" }, { "languageTag": "kz-KZ", "importName": "kzKZ", "localeName": "Kazakh", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/kzKZ.ts" }, { "languageTag": "ko-KR", "importName": "koKR", "localeName": "Korean", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/koKR.ts" }, { "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nbNO.ts" }, { "languageTag": "fa-IR", "importName": "faIR", "localeName": "Persian", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/faIR.ts" }, { "languageTag": "pl-PL", "importName": "plPL", "localeName": "Polish", - "missingKeysCount": 8, - "totalKeysCount": 36, + "missingKeysCount": 9, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/plPL.ts" }, { "languageTag": "pt-BR", "importName": "ptBR", "localeName": "Portuguese (Brazil)", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptBR.ts" }, { "languageTag": "ro-RO", "importName": "roRO", "localeName": "Romanian", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/roRO.ts" }, { "languageTag": "ru-RU", "importName": "ruRU", "localeName": "Russian", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ruRU.ts" }, { "languageTag": "sk-SK", "importName": "skSK", "localeName": "Slovak", - "missingKeysCount": 1, - "totalKeysCount": 36, + "missingKeysCount": 2, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/skSK.ts" }, { "languageTag": "es-ES", "importName": "esES", "localeName": "Spanish", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/esES.ts" }, { "languageTag": "sv-SE", "importName": "svSE", "localeName": "Swedish", - "missingKeysCount": 8, - "totalKeysCount": 36, + "missingKeysCount": 9, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/svSE.ts" }, { "languageTag": "tr-TR", "importName": "trTR", "localeName": "Turkish", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/trTR.ts" }, { "languageTag": "uk-UA", "importName": "ukUA", "localeName": "Ukrainian", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ukUA.ts" }, { "languageTag": "ur-PK", "importName": "urPK", "localeName": "Urdu (Pakistan)", - "missingKeysCount": 8, - "totalKeysCount": 36, + "missingKeysCount": 9, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/urPK.ts" }, { "languageTag": "vi-VN", "importName": "viVN", "localeName": "Vietnamese", - "missingKeysCount": 0, - "totalKeysCount": 36, + "missingKeysCount": 1, + "totalKeysCount": 37, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/viVN.ts" } ] diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 077a4e1ce5a46..a8b38c70bfd7e 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -1,15 +1,20 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { extractValidationProps, PickerViewRendererLookup } from '@mui/x-date-pickers/internals'; import { resolveComponentProps } from '@mui/base/utils'; -import { rangeValueManager } from '../internal/utils/valueManagers'; +import { + extractValidationProps, + PickerViewRendererLookup, + TimeViewWithMeridiem, +} from '@mui/x-date-pickers/internals'; +import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/timeViewRenderers'; +import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; -import { useDateRangePickerDefaultizedProps } from '../DateRangePicker/shared'; -import { renderDateRangeViewCalendar } from '@mui/x-date-pickers/timeViewRenderers'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; import { MultiInputDateRangeField } from '../MultiInputDateRangeField'; -import { useDesktopRangePicker } from '../internal/hooks/useDesktopRangePicker'; -import { validateDateRange } from '../internal/utils/validation/validateDateRange'; -import { DateRange } from '../internal/models'; +import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; +import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; +import { DateRange } from '../internals/models'; +import { renderDigitalClockTimeRangeView } from '../timeRangeViewRenderers'; type DesktopTimeRangePickerComponent = (( props: DesktopTimeRangePickerProps & React.RefAttributes, @@ -20,22 +25,40 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< ref: React.Ref, ) { // Props with the default values common to all date time pickers - const defaultizedProps = useDateRangePickerDefaultizedProps< + const defaultizedProps = useTimeRangePickerDefaultizedProps< TDate, + TimeViewWithMeridiem, DesktopTimeRangePickerProps >(inProps, 'MuiDesktopTimeRangePicker'); - const viewRenderers: PickerViewRendererLookup, 'day', any, {}> = { - day: renderDateRangeViewCalendar, + // const thresholdToRenderTimeInASingleColumn = + // defaultizedProps.thresholdToRenderTimeInASingleColumn ?? 24; + // const timeSteps = { hours: 1, minutes: 5, seconds: 5, ...defaultizedProps.timeSteps }; + const shouldRenderTimeInASingleColumn = true; // (24 * 60) / (timeSteps.hours * timeSteps.minutes) <= thresholdToRenderTimeInASingleColumn; + + const renderTimeView = shouldRenderTimeInASingleColumn + ? renderDigitalClockTimeRangeView + : renderMultiSectionDigitalClockTimeView; + + const viewRenderers: PickerViewRendererLookup, TimeViewWithMeridiem, any, {}> = { + hours: renderTimeView, + minutes: renderTimeView, + seconds: renderTimeView, + meridiem: renderTimeView, ...defaultizedProps.viewRenderers, }; + const shouldHoursRendererContainMeridiemView = + viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeView.name; + const views: readonly TimeViewWithMeridiem[] = + defaultizedProps.ampm && shouldHoursRendererContainMeridiemView + ? [...defaultizedProps.views, 'meridiem'] + : defaultizedProps.views; + const props = { ...defaultizedProps, viewRenderers, - calendars: defaultizedProps.calendars ?? 2, - views: ['day'] as const, - openTo: 'day' as const, + views: shouldRenderTimeInASingleColumn ? ['hours' as TimeViewWithMeridiem] : views, slots: { field: MultiInputDateRangeField, ...defaultizedProps.slots, @@ -54,11 +77,11 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }, }; - const { renderPicker } = useDesktopRangePicker({ + const { renderPicker } = useDesktopRangePicker({ props, valueManager: rangeValueManager, - valueType: 'date', - validator: validateDateRange, + valueType: 'time', + validator: validateTimeRange, }); return renderPicker(); diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts index 2a08d6f87ee6d..7c1f8e8128959 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts @@ -1,31 +1,37 @@ -import { MakeOptional, UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { TimeView } from '@mui/x-date-pickers/models'; +import { + MakeOptional, + UncapitalizeObjectKeys, + DesktopOnlyTimePickerProps, + TimeViewWithMeridiem, +} from '@mui/x-date-pickers/internals'; import { UseDesktopRangePickerSlotsComponent, - UseDesktopRangePickerSlotsComponentsProps, + ExportedUseDesktopRangePickerSlotsComponentsProps, DesktopRangeOnlyPickerProps, -} from '../internal/hooks/useDesktopRangePicker'; +} from '../internals/hooks/useDesktopRangePicker'; import { - BaseDateRangePickerProps, - BaseDateRangePickerSlotsComponent, - BaseDateRangePickerSlotsComponentsProps, -} from '../DateRangePicker/shared'; + BaseTimeRangePickerProps, + BaseTimeRangePickerSlotsComponent, + BaseTimeRangePickerSlotsComponentsProps, +} from '../TimeRangePicker/shared'; export interface DesktopTimeRangePickerSlotsComponent - extends BaseDateRangePickerSlotsComponent, - MakeOptional, 'Field'> {} + extends BaseTimeRangePickerSlotsComponent, + MakeOptional, 'Field'> {} export interface DesktopTimeRangePickerSlotsComponentsProps - extends BaseDateRangePickerSlotsComponentsProps, - UseDesktopRangePickerSlotsComponentsProps {} + extends BaseTimeRangePickerSlotsComponentsProps, + ExportedUseDesktopRangePickerSlotsComponentsProps {} export interface DesktopTimeRangePickerProps - extends BaseDateRangePickerProps, - DesktopRangeOnlyPickerProps { + extends BaseTimeRangePickerProps, + DesktopRangeOnlyPickerProps, + DesktopOnlyTimePickerProps { /** - * The number of calendars to render on **desktop**. - * @default 2 + * Available views. */ - calendars?: 1 | 2 | 3; + views?: readonly TimeView[]; /** * Overridable components. * @default {} diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts new file mode 100644 index 0000000000000..3aa14d11aada9 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts @@ -0,0 +1,43 @@ +import { UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { + DesktopTimeRangePickerProps, + DesktopTimeRangePickerSlotsComponent, + DesktopTimeRangePickerSlotsComponentsProps, +} from '../DesktopTimeRangePicker'; + +export interface TimeRangePickerSlotsComponents + extends DesktopTimeRangePickerSlotsComponent {} + +export interface TimeRangePickerSlotsComponentsProps + extends DesktopTimeRangePickerSlotsComponentsProps {} + +export interface TimeRangePickerProps extends DesktopTimeRangePickerProps { + /** + * CSS media query when `Mobile` mode will be changed to `Desktop`. + * @default '@media (pointer: fine)' + * @example '@media (min-width: 720px)' or theme.breakpoints.up("sm") + */ + desktopModeMediaQuery?: string; + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components?: TimeRangePickerSlotsComponents; + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps?: TimeRangePickerSlotsComponentsProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: UncapitalizeObjectKeys>; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: TimeRangePickerSlotsComponentsProps; +} diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx new file mode 100644 index 0000000000000..4c788ddbb22c8 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -0,0 +1,151 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import Typography from '@mui/material/Typography'; +import { styled, useThemeProps } from '@mui/material/styles'; +import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import { + PickersToolbar, + PickersToolbarButton, + useUtils, + BaseToolbarProps, + useLocaleText, + ExportedBaseToolbarProps, + TimeViewWithMeridiem, +} from '@mui/x-date-pickers/internals'; +import { DateRange } from '../internals/models'; +import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; +import { + TimeRangePickerToolbarClasses, + getTimeRangePickerToolbarUtilityClass, +} from './timeRangePickerToolbarClasses'; + +const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { + const { classes } = ownerState; + const slots = { + root: ['root'], + container: ['container'], + }; + + return composeClasses(slots, getTimeRangePickerToolbarUtilityClass, classes); +}; + +export interface TimeRangePickerToolbarProps + extends Omit< + BaseToolbarProps, TimeViewWithMeridiem>, + 'views' | 'view' | 'onViewChange' | 'onChange' | 'isLandscape' + >, + Pick { + classes?: Partial; +} + +export interface ExportedTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { + ampm?: boolean; + ampmInClock?: boolean; +} + +const TimeRangePickerToolbarRoot = styled(PickersToolbar, { + name: 'MuiTimeRangePickerToolbar', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})<{ + ownerState: TimeRangePickerToolbarProps; +}>({}); + +const TimeRangePickerToolbarContainer = styled('div', { + name: 'MuiTimeRangePickerToolbar', + slot: 'Container', + overridesResolver: (_, styles) => styles.container, +})({ + display: 'flex', +}); + +const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< + TDate extends unknown, +>(inProps: TimeRangePickerToolbarProps, ref: React.Ref) { + const utils = useUtils(); + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); + + const { + value: [start, end], + rangePosition, + onRangePositionChange, + toolbarFormat, + className, + ...other + } = props; + + const localeText = useLocaleText(); + + const startDateValue = start + ? utils.formatByString(start, toolbarFormat || utils.formats.shortDate) + : localeText.start; + + const endDateValue = end + ? utils.formatByString(end, toolbarFormat || utils.formats.shortDate) + : localeText.end; + + const ownerState = props; + const classes = useUtilityClasses(ownerState); + + return ( + + + onRangePositionChange('start')} + /> +  {'–'}  + onRangePositionChange('end')} + /> + + + ); +}); + +TimeRangePickerToolbar.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + classes: PropTypes.object, + /** + * className applied to the root component. + */ + className: PropTypes.string, + disabled: PropTypes.bool, + /** + * If `true`, show the toolbar even in desktop mode. + * @default `true` for Desktop, `false` for Mobile. + */ + hidden: PropTypes.bool, + onRangePositionChange: PropTypes.func.isRequired, + rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, + readOnly: PropTypes.bool, + titleId: PropTypes.string, + /** + * Toolbar date format. + */ + toolbarFormat: PropTypes.string, + /** + * Toolbar value placeholder—it is displayed when the value is empty. + * @default "––" + */ + toolbarPlaceholder: PropTypes.node, + value: PropTypes.arrayOf(PropTypes.any).isRequired, +} as any; + +export { TimeRangePickerToolbar }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts new file mode 100644 index 0000000000000..dc8ea7e268431 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts @@ -0,0 +1,14 @@ +// export { TimeRangePicker } from './TimeRangePicker'; +export type { + TimeRangePickerProps, + TimeRangePickerSlotsComponents, + TimeRangePickerSlotsComponentsProps, +} from './TimeRangePicker.types'; + +export { TimeRangePickerToolbar } from './TimeRangePickerToolbar'; +export type { TimeRangePickerToolbarProps } from './TimeRangePickerToolbar'; +export { timeRangePickerToolbarClasses } from './timeRangePickerToolbarClasses'; +export type { + TimeRangePickerToolbarClassKey, + TimeRangePickerToolbarClasses, +} from './timeRangePickerToolbarClasses'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index 5d10d56705f31..2298b66e3f6f6 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -12,37 +12,37 @@ import { ExportedBaseClockProps, TimeViewWithMeridiem, useUtils, + applyDefaultViewProps, } from '@mui/x-date-pickers/internals'; import { TimeClockSlotsComponent, TimeClockSlotsComponentsProps, } from '@mui/x-date-pickers/TimeClock'; import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; -// TODO: Fix nested import import { - TimePickerToolbar, - TimePickerToolbarProps, - ExportedTimePickerToolbarProps, -} from '@mui/x-date-pickers/TimePicker/TimePickerToolbar'; + TimeRangePickerToolbar, + TimeRangePickerToolbarProps, + ExportedTimeRangePickerToolbarProps, +} from './TimeRangePickerToolbar'; import { TimeRangeValidationError } from '../models'; -import { DateRange } from '../internal/models'; +import { DateRange } from '../internals/models'; export interface BaseTimeRangePickerSlotsComponent extends TimeClockSlotsComponent { /** * Custom component for the toolbar rendered above the views. * @default DateTimePickerToolbar */ - Toolbar?: React.JSXElementConstructor>; + Toolbar?: React.JSXElementConstructor>; } export interface BaseTimeRangePickerSlotsComponentsProps extends TimeClockSlotsComponentsProps { - toolbar?: ExportedTimePickerToolbarProps; + toolbar?: ExportedTimeRangePickerToolbarProps; } export interface BaseTimeRangePickerProps extends Omit< BasePickerInputProps, TDate, TView, TimeRangeValidationError>, - 'view' | 'views' | 'openTo' | 'onViewChange' | 'orientation' + 'orientation' >, ExportedBaseClockProps { /** @@ -91,7 +91,13 @@ type UseTimeRangePickerDefaultizedProps< TDate, TView extends TimeViewWithMeridiem, Props extends BaseTimeRangePickerProps, -> = LocalizedComponent>; +> = Omit< + LocalizedComponent< + TDate, + DefaultizedProps + >, + 'components' | 'componentsProps' +>; export function useTimeRangePickerDefaultizedProps< TDate, @@ -126,11 +132,18 @@ export function useTimeRangePickerDefaultizedProps< return { ...themeProps, + ampm, localeText, + ...applyDefaultViewProps({ + views: themeProps.views, + openTo: themeProps.openTo, + defaultViews: ['hours', 'minutes'] as TView[], + defaultOpenTo: 'hours' as TView, + }), disableFuture: themeProps.disableFuture ?? false, disablePast: themeProps.disablePast ?? false, slots: { - toolbar: TimePickerToolbar, + toolbar: TimeRangePickerToolbar, ...slots, }, slotProps: { diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts new file mode 100644 index 0000000000000..74e589afffa52 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts @@ -0,0 +1,22 @@ +import { + unstable_generateUtilityClass as generateUtilityClass, + unstable_generateUtilityClasses as generateUtilityClasses, +} from '@mui/utils'; + +export interface TimeRangePickerToolbarClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the container element. */ + container: string; +} + +export type TimeRangePickerToolbarClassKey = keyof TimeRangePickerToolbarClasses; + +export function getTimeRangePickerToolbarUtilityClass(slot: string) { + return generateUtilityClass('MuiTimeRangePickerToolbar', slot); +} + +export const timeRangePickerToolbarClasses: TimeRangePickerToolbarClasses = generateUtilityClasses( + 'MuiTimeRangePickerToolbar', + ['root', 'container'], +); diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/index.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/index.ts index 9f3edadde78b2..de15bc0243780 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/index.ts @@ -2,5 +2,6 @@ export { useDesktopRangePicker } from './useDesktopRangePicker'; export type { UseDesktopRangePickerSlotsComponent, UseDesktopRangePickerSlotsComponentsProps, + ExportedUseDesktopRangePickerSlotsComponentsProps, DesktopRangeOnlyPickerProps, } from './useDesktopRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts index cf012f9e28174..8a6ece9878927 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts @@ -32,12 +32,17 @@ export interface UseDesktopRangePickerSlotsComponent< export interface UseDesktopRangePickerSlotsComponentsProps< TDate, TView extends DateOrTimeViewWithMeridiem, -> extends PickersPopperSlotsComponentsProps, - ExportedPickersLayoutSlotsComponentsProps, TDate, TView>, - RangePickerFieldSlotsComponentsProps { +> extends ExportedUseDesktopRangePickerSlotsComponentsProps { toolbar?: ExportedBaseToolbarProps; } +export interface ExportedUseDesktopRangePickerSlotsComponentsProps< + TDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersPopperSlotsComponentsProps, + ExportedPickersLayoutSlotsComponentsProps, TDate, TView>, + RangePickerFieldSlotsComponentsProps {} + export interface DesktopRangeOnlyPickerProps extends BaseNonStaticPickerProps, UsePickerValueNonStaticProps, diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts new file mode 100644 index 0000000000000..cdf2269467357 --- /dev/null +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts @@ -0,0 +1 @@ +export { renderDigitalClockTimeRangeView } from './timeRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 57c6312c78637..0b40e11a45a3f 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -1,9 +1,7 @@ import { BaseClockProps, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; -import { - DigitalClockProps, - TimePickerProps, -} from '@mui/x-date-pickers/DigitalClock'; -import { TimeView } from '@mui/x-date-pickers/models' +import { DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; +import { TimeView } from '@mui/x-date-pickers/models'; +import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; export type TimeRangeViewRendererProps< TView extends TimeViewWithMeridiem, @@ -14,9 +12,41 @@ export type TimeRangeViewRendererProps< views: readonly TView[]; }; -export const renderDigitalClockTimeRangeView = ({}: TimeRangeViewRendererProps< +export const renderDigitalClockTimeRangeView = ({ + view, + onViewChange, + focusedView, + onFocusedViewChange, + views, + value, + defaultValue, + referenceDate, + onChange, + className, + classes, + disableFuture, + disablePast, + minTime, + maxTime, + shouldDisableTime, + shouldDisableClock, + minutesStep, + ampm, + components, + componentsProps, + slots, + slotProps, + readOnly, + disabled, + sx, + autoFocus, + disableIgnoringDatePartForTimeValidation, + timeSteps, + skipDisabled, + timezone, +}: TimeRangeViewRendererProps< Extract, - Omit, 'timeStep'> & Pick, 'timeSteps'> + Omit, 'timeStep'> & Pick, 'timeSteps'> >) => { return
HELLO
; }; diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 7638f66eaa332..1818bd8d70a59 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -104,7 +104,11 @@ export type { BasePickerInputProps, BaseNonStaticPickerProps, } from './models/props/basePickerProps'; -export type { BaseClockProps, ExportedBaseClockProps } from './models/props/clock'; +export type { + BaseClockProps, + ExportedBaseClockProps, + DesktopOnlyTimePickerProps, +} from './models/props/clock'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; export type { DefaultizedProps, MakeOptional } from './models/helpers'; export type { WrapperVariant, TimeViewWithMeridiem } from './models/common'; @@ -137,6 +141,7 @@ export { extractValidationProps } from './utils/validation/extractValidationProp export { validateDate } from './utils/validation/validateDate'; export { validateDateTime } from './utils/validation/validateDateTime'; export { validateTime } from './utils/validation/validateTime'; +export { applyDefaultViewProps } from './utils/views'; export { buildDeprecatedPropsWarning, buildWarning } from './utils/warning'; export { uncapitalizeObjectKeys } from './utils/slots-migration'; export type { UncapitalizeObjectKeys, SlotsAndSlotProps } from './utils/slots-migration'; diff --git a/packages/x-date-pickers/src/locales/beBY.ts b/packages/x-date-pickers/src/locales/beBY.ts index 76004e920f7ad..a8d82303961bc 100644 --- a/packages/x-date-pickers/src/locales/beBY.ts +++ b/packages/x-date-pickers/src/locales/beBY.ts @@ -38,6 +38,7 @@ const beBYPickers: Partial> = { dateTimePickerToolbarTitle: 'Абраць дату і час', timePickerToolbarTitle: 'Абраць час', dateRangePickerToolbarTitle: 'Абраць каляндарны перыяд', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/caES.ts b/packages/x-date-pickers/src/locales/caES.ts index 4253843313b34..674eb859cc348 100644 --- a/packages/x-date-pickers/src/locales/caES.ts +++ b/packages/x-date-pickers/src/locales/caES.ts @@ -37,6 +37,7 @@ const caESPickers: Partial> = { dateTimePickerToolbarTitle: 'Seleccionar data i hora', timePickerToolbarTitle: 'Seleccionar hora', dateRangePickerToolbarTitle: 'Seleccionar rang de dates', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/csCZ.ts b/packages/x-date-pickers/src/locales/csCZ.ts index 9630ed8fd5be3..b74e33483fdcc 100644 --- a/packages/x-date-pickers/src/locales/csCZ.ts +++ b/packages/x-date-pickers/src/locales/csCZ.ts @@ -38,6 +38,7 @@ const csCZPickers: Partial> = { dateTimePickerToolbarTitle: 'Vyberte datum a čas', timePickerToolbarTitle: 'Vyberte čas', dateRangePickerToolbarTitle: 'Vyberete rozmezí dat', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/daDK.ts b/packages/x-date-pickers/src/locales/daDK.ts index f46f0b28a7972..4dc3cb8a59a20 100644 --- a/packages/x-date-pickers/src/locales/daDK.ts +++ b/packages/x-date-pickers/src/locales/daDK.ts @@ -38,6 +38,7 @@ const daDKPickers: Partial> = { dateTimePickerToolbarTitle: 'Vælg dato & tidspunkt', timePickerToolbarTitle: 'Vælg tidspunkt', dateRangePickerToolbarTitle: 'Vælg datointerval', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/deDE.ts b/packages/x-date-pickers/src/locales/deDE.ts index 8319f063b1b88..9f91680eab21e 100644 --- a/packages/x-date-pickers/src/locales/deDE.ts +++ b/packages/x-date-pickers/src/locales/deDE.ts @@ -38,6 +38,7 @@ const deDEPickers: Partial> = { dateTimePickerToolbarTitle: 'Datum & Uhrzeit auswählen', timePickerToolbarTitle: 'Uhrzeit auswählen', dateRangePickerToolbarTitle: 'Datumsbereich auswählen', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/elGR.ts b/packages/x-date-pickers/src/locales/elGR.ts index 7a15dc49987d3..c0f49d89f1ec7 100644 --- a/packages/x-date-pickers/src/locales/elGR.ts +++ b/packages/x-date-pickers/src/locales/elGR.ts @@ -37,6 +37,7 @@ const elGRPickers: Partial> = { dateTimePickerToolbarTitle: 'Επιλέξτε ημερομηνία και ώρα', timePickerToolbarTitle: 'Επιλέξτε ώρα', dateRangePickerToolbarTitle: 'Επιλέξτε εύρος ημερομηνιών', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 53fce05b2081b..7ddacd161a69e 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -31,6 +31,7 @@ const enUSPickers: PickersLocaleText = { dateTimePickerToolbarTitle: 'Select date & time', timePickerToolbarTitle: 'Select time', dateRangePickerToolbarTitle: 'Select date range', + timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/esES.ts b/packages/x-date-pickers/src/locales/esES.ts index b5fec0ff00d6e..c0c1f0e36a9e0 100644 --- a/packages/x-date-pickers/src/locales/esES.ts +++ b/packages/x-date-pickers/src/locales/esES.ts @@ -37,6 +37,7 @@ const esESPickers: Partial> = { dateTimePickerToolbarTitle: 'Seleccionar fecha y hora', timePickerToolbarTitle: 'Seleccionar hora', dateRangePickerToolbarTitle: 'Seleccionar rango de fecha', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/faIR.ts b/packages/x-date-pickers/src/locales/faIR.ts index 5a748c92810dc..7db97bfa1c609 100644 --- a/packages/x-date-pickers/src/locales/faIR.ts +++ b/packages/x-date-pickers/src/locales/faIR.ts @@ -37,6 +37,7 @@ const faIRPickers: Partial> = { dateTimePickerToolbarTitle: 'تاریخ و ساعت را انتخاب کنید', timePickerToolbarTitle: 'ساعت را انتخاب کنید', dateRangePickerToolbarTitle: 'محدوده تاریخ را انتخاب کنید', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/fiFI.ts b/packages/x-date-pickers/src/locales/fiFI.ts index 5d83726d14534..97266cbb75f5e 100644 --- a/packages/x-date-pickers/src/locales/fiFI.ts +++ b/packages/x-date-pickers/src/locales/fiFI.ts @@ -37,6 +37,7 @@ const fiFIPickers: Partial> = { dateTimePickerToolbarTitle: 'Valitse päivä ja aika', timePickerToolbarTitle: 'Valitse aika', dateRangePickerToolbarTitle: 'Valitse aikaväli', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/frFR.ts b/packages/x-date-pickers/src/locales/frFR.ts index 14ac7e7d7dbc4..183a98ad7f20e 100644 --- a/packages/x-date-pickers/src/locales/frFR.ts +++ b/packages/x-date-pickers/src/locales/frFR.ts @@ -37,6 +37,7 @@ const frFRPickers: Partial> = { dateTimePickerToolbarTitle: "Choisir la date et l'heure", timePickerToolbarTitle: "Choisir l'heure", dateRangePickerToolbarTitle: 'Choisir la plage de dates', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/heIL.ts b/packages/x-date-pickers/src/locales/heIL.ts index dceedbbff2b61..b147311735f73 100644 --- a/packages/x-date-pickers/src/locales/heIL.ts +++ b/packages/x-date-pickers/src/locales/heIL.ts @@ -37,6 +37,7 @@ const heILPickers: Partial> = { dateTimePickerToolbarTitle: 'בחירת תאריך ושעה', timePickerToolbarTitle: 'בחירת שעה', dateRangePickerToolbarTitle: 'בחירת טווח תאריכים', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/huHU.ts b/packages/x-date-pickers/src/locales/huHU.ts index 86fc0a23469c8..928e229651974 100644 --- a/packages/x-date-pickers/src/locales/huHU.ts +++ b/packages/x-date-pickers/src/locales/huHU.ts @@ -38,6 +38,7 @@ const huHUPickers: Partial> = { dateTimePickerToolbarTitle: 'Dátum és idő kiválasztása', timePickerToolbarTitle: 'Idő kiválasztása', dateRangePickerToolbarTitle: 'Dátumhatárok kiválasztása', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/isIS.ts b/packages/x-date-pickers/src/locales/isIS.ts index cfdfa2124e29a..61ef3b8aeeddd 100644 --- a/packages/x-date-pickers/src/locales/isIS.ts +++ b/packages/x-date-pickers/src/locales/isIS.ts @@ -37,6 +37,7 @@ const isISPickers: Partial> = { dateTimePickerToolbarTitle: 'Velja dagsetningu og tíma', timePickerToolbarTitle: 'Velja tíma', dateRangePickerToolbarTitle: 'Velja tímabil', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/itIT.ts b/packages/x-date-pickers/src/locales/itIT.ts index feb675cc5fcce..a76473a867c81 100644 --- a/packages/x-date-pickers/src/locales/itIT.ts +++ b/packages/x-date-pickers/src/locales/itIT.ts @@ -37,6 +37,7 @@ const itITPickers: Partial> = { dateTimePickerToolbarTitle: 'Seleziona data e orario', timePickerToolbarTitle: 'Seleziona orario', dateRangePickerToolbarTitle: 'Seleziona intervallo di date', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/jaJP.ts b/packages/x-date-pickers/src/locales/jaJP.ts index 74aa23834109a..ce315167d3590 100644 --- a/packages/x-date-pickers/src/locales/jaJP.ts +++ b/packages/x-date-pickers/src/locales/jaJP.ts @@ -38,6 +38,7 @@ const jaJPPickers: Partial> = { dateTimePickerToolbarTitle: '日時を選択', timePickerToolbarTitle: '時間を選択', dateRangePickerToolbarTitle: '日付の範囲を選択', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/koKR.ts b/packages/x-date-pickers/src/locales/koKR.ts index a44d3c2182918..456d4d7748d62 100644 --- a/packages/x-date-pickers/src/locales/koKR.ts +++ b/packages/x-date-pickers/src/locales/koKR.ts @@ -37,6 +37,7 @@ const koKRPickers: Partial> = { dateTimePickerToolbarTitle: '날짜 & 시간 선택하기', timePickerToolbarTitle: '시간 선택하기', dateRangePickerToolbarTitle: '날짜 범위 선택하기', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/kzKZ.ts b/packages/x-date-pickers/src/locales/kzKZ.ts index bb43a39e2ae7d..6636f98f4ebe4 100644 --- a/packages/x-date-pickers/src/locales/kzKZ.ts +++ b/packages/x-date-pickers/src/locales/kzKZ.ts @@ -38,6 +38,7 @@ const kzKZPickers: Partial> = { dateTimePickerToolbarTitle: 'Күн мен уақытты таңдау', timePickerToolbarTitle: 'Уақытты таңдау', dateRangePickerToolbarTitle: 'Кезеңді таңдаңыз', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/nbNO.ts b/packages/x-date-pickers/src/locales/nbNO.ts index 8679592b861e9..5f9d4a967bbd8 100644 --- a/packages/x-date-pickers/src/locales/nbNO.ts +++ b/packages/x-date-pickers/src/locales/nbNO.ts @@ -37,6 +37,7 @@ const nbNOPickers: Partial> = { dateTimePickerToolbarTitle: 'Velg dato & klokkeslett', timePickerToolbarTitle: 'Velg klokkeslett', dateRangePickerToolbarTitle: 'Velg datoperiode', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/nlNL.ts b/packages/x-date-pickers/src/locales/nlNL.ts index 3d73af4c05952..9b74335bed851 100644 --- a/packages/x-date-pickers/src/locales/nlNL.ts +++ b/packages/x-date-pickers/src/locales/nlNL.ts @@ -37,6 +37,7 @@ const nlNLPickers: Partial> = { dateTimePickerToolbarTitle: 'Selecteer datum & tijd', timePickerToolbarTitle: 'Selecteer tijd', dateRangePickerToolbarTitle: 'Selecteer datumbereik', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/plPL.ts b/packages/x-date-pickers/src/locales/plPL.ts index 6b7720e969c32..4df763b821cb9 100644 --- a/packages/x-date-pickers/src/locales/plPL.ts +++ b/packages/x-date-pickers/src/locales/plPL.ts @@ -37,6 +37,7 @@ const plPLPickers: Partial> = { dateTimePickerToolbarTitle: 'Wybierz datę i czas', timePickerToolbarTitle: 'Wybierz czas', dateRangePickerToolbarTitle: 'Wybierz zakres dat', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/ptBR.ts b/packages/x-date-pickers/src/locales/ptBR.ts index 032c8ccfccf0d..974730ea0c7ba 100644 --- a/packages/x-date-pickers/src/locales/ptBR.ts +++ b/packages/x-date-pickers/src/locales/ptBR.ts @@ -37,6 +37,7 @@ const ptBRPickers: Partial> = { dateTimePickerToolbarTitle: 'Selecione data e hora', timePickerToolbarTitle: 'Selecione a hora', dateRangePickerToolbarTitle: 'Selecione o intervalo entre datas', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/roRO.ts b/packages/x-date-pickers/src/locales/roRO.ts index 7c24c4a6b6806..bba09930dd8ca 100644 --- a/packages/x-date-pickers/src/locales/roRO.ts +++ b/packages/x-date-pickers/src/locales/roRO.ts @@ -38,6 +38,7 @@ const roROPickers: Partial> = { dateTimePickerToolbarTitle: 'Selectați data și ora', timePickerToolbarTitle: 'Selectați ora', dateRangePickerToolbarTitle: 'Selectați intervalul de date', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/ruRU.ts b/packages/x-date-pickers/src/locales/ruRU.ts index d947bcd5b2538..99df842c92062 100644 --- a/packages/x-date-pickers/src/locales/ruRU.ts +++ b/packages/x-date-pickers/src/locales/ruRU.ts @@ -38,6 +38,7 @@ const ruRUPickers: Partial> = { dateTimePickerToolbarTitle: 'Выбрать дату и время', timePickerToolbarTitle: 'Выбрать время', dateRangePickerToolbarTitle: 'Выбрать период', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/skSK.ts b/packages/x-date-pickers/src/locales/skSK.ts index 22ab6650219ec..15af9fc2268ed 100644 --- a/packages/x-date-pickers/src/locales/skSK.ts +++ b/packages/x-date-pickers/src/locales/skSK.ts @@ -38,6 +38,7 @@ const skSKPickers: Partial> = { dateTimePickerToolbarTitle: 'Vyberte dátum a čas', timePickerToolbarTitle: 'Vyberte čas', dateRangePickerToolbarTitle: 'Vyberete rozmedzie dátumov', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/svSE.ts b/packages/x-date-pickers/src/locales/svSE.ts index b8296507ce945..afb0e6b909093 100644 --- a/packages/x-date-pickers/src/locales/svSE.ts +++ b/packages/x-date-pickers/src/locales/svSE.ts @@ -37,6 +37,7 @@ const svSEPickers: Partial> = { dateTimePickerToolbarTitle: 'Välj datum & tid', timePickerToolbarTitle: 'Välj tid', dateRangePickerToolbarTitle: 'Välj datumintervall', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/trTR.ts b/packages/x-date-pickers/src/locales/trTR.ts index a640746cadf61..b8fef841870f3 100644 --- a/packages/x-date-pickers/src/locales/trTR.ts +++ b/packages/x-date-pickers/src/locales/trTR.ts @@ -37,6 +37,7 @@ const trTRPickers: Partial> = { dateTimePickerToolbarTitle: 'Tarih & Saat seç', timePickerToolbarTitle: 'Saat seç', dateRangePickerToolbarTitle: 'Tarih aralığı seçin', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/ukUA.ts b/packages/x-date-pickers/src/locales/ukUA.ts index 45242cabee79f..1e8197f9804d6 100644 --- a/packages/x-date-pickers/src/locales/ukUA.ts +++ b/packages/x-date-pickers/src/locales/ukUA.ts @@ -37,6 +37,7 @@ const ukUAPickers: Partial> = { dateTimePickerToolbarTitle: 'Вибрати дату і час', timePickerToolbarTitle: 'Вибрати час', dateRangePickerToolbarTitle: 'Вибрати календарний період', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/urPK.ts b/packages/x-date-pickers/src/locales/urPK.ts index 1c73d41e999b2..a5f7ad418a209 100644 --- a/packages/x-date-pickers/src/locales/urPK.ts +++ b/packages/x-date-pickers/src/locales/urPK.ts @@ -37,6 +37,7 @@ const urPKPickers: Partial> = { dateTimePickerToolbarTitle: 'تاریخ اور وقت منتخب کریں', timePickerToolbarTitle: 'وقت منتخب کریں', dateRangePickerToolbarTitle: 'تاریخوں کی رینج منتخب کریں', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index a2acb4fa27bf7..a2bb36884011f 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -22,6 +22,11 @@ export interface PickersComponentSpecificLocaleText { * Will be overridden by the `toolbarTitle` translation key passed directly on the picker. */ dateRangePickerToolbarTitle: string; + /** + * Title displayed in the toolbar of the `TimeRangePicker` and its variants. + * Will be overridden by the `toolbarTitle` translation key passed directly on the picker. + */ + timeRangePickerToolbarTitle: string; } export interface PickersComponentAgnosticLocaleText { diff --git a/packages/x-date-pickers/src/locales/viVN.ts b/packages/x-date-pickers/src/locales/viVN.ts index f238b31ea5f54..d6e07e7b6cbdb 100644 --- a/packages/x-date-pickers/src/locales/viVN.ts +++ b/packages/x-date-pickers/src/locales/viVN.ts @@ -37,6 +37,7 @@ const viVNPickers: Partial> = { dateTimePickerToolbarTitle: 'Chọn ngày và giờ', timePickerToolbarTitle: 'Chọn giờ', dateRangePickerToolbarTitle: 'Chọn khoảng ngày', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/zhCN.ts b/packages/x-date-pickers/src/locales/zhCN.ts index 544b6d23c1bd0..d80a75e6f15b1 100644 --- a/packages/x-date-pickers/src/locales/zhCN.ts +++ b/packages/x-date-pickers/src/locales/zhCN.ts @@ -35,6 +35,7 @@ const zhCNPickers: Partial> = { dateTimePickerToolbarTitle: '选择日期和时间', timePickerToolbarTitle: '选择时间', dateRangePickerToolbarTitle: '选择时间范围', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/locales/zhHK.ts b/packages/x-date-pickers/src/locales/zhHK.ts index 8c454b92a8e31..a9937046dc73a 100644 --- a/packages/x-date-pickers/src/locales/zhHK.ts +++ b/packages/x-date-pickers/src/locales/zhHK.ts @@ -35,6 +35,7 @@ const zhHKPickers: Partial> = { dateTimePickerToolbarTitle: '選擇日期和時間', timePickerToolbarTitle: '選擇時間', dateRangePickerToolbarTitle: '選擇時間範圍', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, time, adapter) => diff --git a/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx b/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx index aef235e1a4c72..6afba83115e94 100644 --- a/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx +++ b/packages/x-date-pickers/src/timeViewRenderers/timeViewRenderers.tsx @@ -52,7 +52,7 @@ export const renderTimeViewClock = ({ showViewSwitcher, disableIgnoringDatePartForTimeValidation, timezone, -}: TimeViewRendererProps>) => ( +}: TimeViewRendererProps>) => ( view={view} onViewChange={onViewChange} From 5f4d574f06a16fa21257c2041c986441582ae2a6 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 12 Sep 2023 09:11:00 +0200 Subject: [PATCH 03/74] Work --- .../timeRangeViewRenderers.tsx | 56 +++++++++++++++++-- .../x-date-pickers/src/internals/index.ts | 1 + 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 0b40e11a45a3f..6b4508ab2c401 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -1,12 +1,17 @@ -import { BaseClockProps, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; -import { DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; +import * as React from 'react'; +import { BaseClockProps, TimeViewWithMeridiem, isTimeView } from '@mui/x-date-pickers/internals'; +import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; +import Stack from '@mui/material/Stack'; import { TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; +import { DateRange } from '../internals/models'; export type TimeRangeViewRendererProps< + TDate, TView extends TimeViewWithMeridiem, - TComponentProps extends BaseClockProps, + TComponentProps extends Omit, 'value' | 'onChange'>, > = Omit & { + value: DateRange; view: TView; onViewChange?: (view: TView) => void; views: readonly TView[]; @@ -19,7 +24,6 @@ export const renderDigitalClockTimeRangeView = ({ onFocusedViewChange, views, value, - defaultValue, referenceDate, onChange, className, @@ -45,8 +49,48 @@ export const renderDigitalClockTimeRangeView = ({ skipDisabled, timezone, }: TimeRangeViewRendererProps< + TDate, Extract, - Omit, 'timeStep'> & Pick, 'timeSteps'> + Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & + Pick, 'timeSteps'> & { + value: DateRange; + onChange: (value: DateRange) => void; + } >) => { - return
HELLO
; + return ( + + + view={view} + onViewChange={onViewChange} + focusedView={focusedView} + onFocusedViewChange={onFocusedViewChange} + views={views.filter(isTimeView)} + value={value[0]} + referenceDate={referenceDate} + onChange={(newValue) => onChange?.([newValue, value[1]])} + className={className} + classes={classes} + disableFuture={disableFuture} + disablePast={disablePast} + minTime={minTime} + maxTime={maxTime} + shouldDisableTime={shouldDisableTime} + shouldDisableClock={shouldDisableClock} + minutesStep={minutesStep} + ampm={ampm} + components={components} + componentsProps={componentsProps} + slots={slots} + slotProps={slotProps} + readOnly={readOnly} + disabled={disabled} + sx={sx} + autoFocus={autoFocus} + disableIgnoringDatePartForTimeValidation={disableIgnoringDatePartForTimeValidation} + timeStep={timeSteps?.minutes} + skipDisabled={skipDisabled} + timezone={timezone} + /> + + ); }; diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 1818bd8d70a59..ce3378c2a69af 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -130,6 +130,7 @@ export { } from './utils/date-utils'; export { splitFieldInternalAndForwardedProps } from './utils/fields'; export { getDefaultReferenceDate } from './utils/getDefaultReferenceDate'; +export { isTimeView } from './utils/time-utils'; export { executeInTheNextEventLoopTick, getActiveElement, From 29a57ce2fc8eb6cb697cfac269fc40ef9dec73ef Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 12 Sep 2023 13:16:29 +0200 Subject: [PATCH 04/74] Work --- .../DesktopTimeRangePicker.tsx | 5 ++++ .../timeRangeViewRenderers.tsx | 25 +++++++++++++++---- .../src/DateCalendar/DayCalendar.tsx | 2 ++ .../x-date-pickers/src/internals/index.ts | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index a8b38c70bfd7e..ada6605c65729 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -5,6 +5,8 @@ import { extractValidationProps, PickerViewRendererLookup, TimeViewWithMeridiem, + useUtils, + resolveTimeFormat, } from '@mui/x-date-pickers/internals'; import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/timeViewRenderers'; import { rangeValueManager } from '../internals/utils/valueManagers'; @@ -24,6 +26,8 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< inProps: DesktopTimeRangePickerProps, ref: React.Ref, ) { + const utils = useUtils(); + // Props with the default values common to all date time pickers const defaultizedProps = useTimeRangePickerDefaultizedProps< TDate, @@ -58,6 +62,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< const props = { ...defaultizedProps, viewRenderers, + format: resolveTimeFormat(utils, defaultizedProps), views: shouldRenderTimeInASingleColumn ? ['hours' as TimeViewWithMeridiem] : views, slots: { field: MultiInputDateRangeField, diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 6b4508ab2c401..21a08e38f495a 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -1,10 +1,15 @@ import * as React from 'react'; -import { BaseClockProps, TimeViewWithMeridiem, isTimeView } from '@mui/x-date-pickers/internals'; +import { + BaseClockProps, + TimeViewWithMeridiem, + isTimeView, + PickerSelectionState, +} from '@mui/x-date-pickers/internals'; import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; import Stack from '@mui/material/Stack'; import { TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; -import { DateRange } from '../internals/models'; +import { DateRange, RangePosition } from '../internals/models'; export type TimeRangeViewRendererProps< TDate, @@ -48,15 +53,25 @@ export const renderDigitalClockTimeRangeView = ({ timeSteps, skipDisabled, timezone, + rangePosition, }: TimeRangeViewRendererProps< TDate, Extract, Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & Pick, 'timeSteps'> & { value: DateRange; - onChange: (value: DateRange) => void; + onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; + rangePosition: RangePosition; } >) => { + const viewValue = rangePosition === 'start' ? value[0] : value[1]; + + const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => + onChange( + rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], + selectionState, + ); + return ( @@ -65,9 +80,9 @@ export const renderDigitalClockTimeRangeView = ({ focusedView={focusedView} onFocusedViewChange={onFocusedViewChange} views={views.filter(isTimeView)} - value={value[0]} + value={viewValue} referenceDate={referenceDate} - onChange={(newValue) => onChange?.([newValue, value[1]])} + onChange={handleChange} className={className} classes={classes} disableFuture={disableFuture} diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index a256dff17dcc3..f4dc5cf5b4df7 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -540,6 +540,8 @@ export function DayCalendar(inProps: DayCalendarProps) { return toDisplay; }, [currentMonth, fixedWeekNumber, utils, timezone]); + console.log(weeksToDisplay); + return (
diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index ce3378c2a69af..31b5d31c105f0 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -130,7 +130,7 @@ export { } from './utils/date-utils'; export { splitFieldInternalAndForwardedProps } from './utils/fields'; export { getDefaultReferenceDate } from './utils/getDefaultReferenceDate'; -export { isTimeView } from './utils/time-utils'; +export { isTimeView, resolveTimeFormat } from './utils/time-utils'; export { executeInTheNextEventLoopTick, getActiveElement, From 8cb651903a57da98280dfeb95db329e1bb1a95c4 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 12 Sep 2023 13:47:38 +0200 Subject: [PATCH 05/74] Work --- docs/data/date-pickers-component-api-pages.ts | 10 + .../date-pickers/desktop-time-range-picker.js | 23 ++ .../desktop-time-range-picker.json | 264 +++++++++++++++++ .../date-pickers/time-range-picker-toolbar.js | 23 ++ .../time-range-picker-toolbar.json | 21 ++ .../desktop-time-range-picker.json | 279 ++++++++++++++++++ .../time-range-picker-toolbar.json | 33 +++ .../DesktopDateRangePicker.tsx | 1 + .../DesktopTimeRangePicker.tsx | 169 ++++++----- packages/x-date-pickers-pro/src/index.ts | 2 + .../useDesktopRangePicker.tsx | 2 + .../useDesktopRangePicker.types.ts | 5 + .../hooks/useEnrichedRangePickerFieldProps.ts | 10 +- .../timeRangeViewRenderers.tsx | 15 +- scripts/x-date-pickers-pro.exports.json | 12 + 15 files changed, 783 insertions(+), 86 deletions(-) create mode 100644 docs/pages/x/api/date-pickers/desktop-time-range-picker.js create mode 100644 docs/pages/x/api/date-pickers/desktop-time-range-picker.json create mode 100644 docs/pages/x/api/date-pickers/time-range-picker-toolbar.js create mode 100644 docs/pages/x/api/date-pickers/time-range-picker-toolbar.json create mode 100644 docs/translations/api-docs/date-pickers/desktop-time-range-picker.json create mode 100644 docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json diff --git a/docs/data/date-pickers-component-api-pages.ts b/docs/data/date-pickers-component-api-pages.ts index 91448100bee33..8490b16921276 100644 --- a/docs/data/date-pickers-component-api-pages.ts +++ b/docs/data/date-pickers-component-api-pages.ts @@ -30,6 +30,11 @@ export default [ }, { pathname: '/x/api/date-pickers/desktop-date-time-picker', title: 'DesktopDateTimePicker' }, { pathname: '/x/api/date-pickers/desktop-time-picker', title: 'DesktopTimePicker' }, + { + pathname: '/x/api/date-pickers/desktop-time-range-picker', + title: 'DesktopTimeRangePicker', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/digital-clock', title: 'DigitalClock' }, { pathname: '/x/api/date-pickers/localization-provider', title: 'LocalizationProvider' }, { pathname: '/x/api/date-pickers/mobile-date-picker', title: 'MobileDatePicker' }, @@ -92,5 +97,10 @@ export default [ { pathname: '/x/api/date-pickers/time-field', title: 'TimeField' }, { pathname: '/x/api/date-pickers/time-picker', title: 'TimePicker' }, { pathname: '/x/api/date-pickers/time-picker-toolbar', title: 'TimePickerToolbar' }, + { + pathname: '/x/api/date-pickers/time-range-picker-toolbar', + title: 'TimeRangePickerToolbar', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/year-calendar', title: 'YearCalendar' }, ] as MuiPage[]; diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.js b/docs/pages/x/api/date-pickers/desktop-time-range-picker.js new file mode 100644 index 0000000000000..c886599a1a170 --- /dev/null +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './desktop-time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers', + false, + /\.\/desktop-time-range-picker(-[a-z]{2})?\.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json new file mode 100644 index 0000000000000..05b5109ee615c --- /dev/null +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -0,0 +1,264 @@ +{ + "props": { + "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, + "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, + "autoFocus": { "type": { "name": "bool" } }, + "className": { "type": { "name": "string" } }, + "closeOnSelect": { + "type": { "name": "bool" }, + "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." + }, + "components": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slots." + }, + "componentsProps": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slotProps." + }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
| 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "disabled": { "type": { "name": "bool" } }, + "disableFuture": { "type": { "name": "bool" } }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" } }, + "disableOpenPicker": { "type": { "name": "bool" } }, + "disablePast": { "type": { "name": "bool" } }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
| 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { + "type": { "name": "union", "description": "func
| { current?: object }" } + }, + "label": { "type": { "name": "node" } }, + "localeText": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "any" } }, + "minTime": { "type": { "name": "any" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, + "onAccept": { + "type": { "name": "func" }, + "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "open": { "type": { "name": "bool" } }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
| 'meridiem'
| 'minutes'
| 'seconds'" + } + }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
| 'start'" } }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "any" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
| 'day'
| 'hours'
| 'meridiem'
| 'minutes'
| 'month'
| 'seconds'
| 'weekDay'
| 'year'
| number
| { endIndex: number, startIndex: number }" + } + }, + "shouldDisableClock": { + "type": { "name": "func" }, + "deprecated": true, + "deprecationInfo": "Consider using shouldDisableTime.", + "signature": { + "type": "function(clockValue: number, view: TimeView) => boolean", + "describedArgs": ["clockValue", "view"], + "returned": "boolean" + } + }, + "shouldDisableTime": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], + "returned": "boolean" + } + }, + "skipDisabled": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { "type": { "name": "object" }, "default": "{}" }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise." + }, + "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
| 'meridiem'
| 'minutes'
| 'seconds'" + } + }, + "viewRenderers": { + "type": { + "name": "shape", + "description": "{ hours?: func, meridiem?: func, minutes?: func, seconds?: func }" + } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
| 'minutes'
| 'seconds'>" + } + } + }, + "slots": [ + { + "class": null, + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar" + }, + { + "class": null, + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper" + }, + { + "class": null, + "name": "desktopTransition", + "description": "Custom component for the desktop popper Transition.", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`." + }, + { + "class": null, + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "FocusTrap from '@mui/base'." + }, + { "class": null, "name": "field", "description": "" }, + { + "class": null, + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + }, + { + "class": null, + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft" + }, + { + "class": null, + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton" + }, + { + "class": null, + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'." + }, + { + "class": null, + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton" + }, + { + "class": null, + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight" + }, + { + "class": null, + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts" + }, + { + "class": null, + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "default": "TextField from '@mui/material'" + }, + { + "class": null, + "name": "toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "DateTimePickerToolbar" + } + ], + "name": "DesktopTimeRangePicker", + "imports": [ + "import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker';", + "import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "styles": { "classes": [], "globalClasses": {}, "name": "MuiDesktopTimeRangePicker" }, + "filename": "/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx", + "demos": "
    " +} diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js new file mode 100644 index 0000000000000..778e5b8bc9075 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker-toolbar.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers', + false, + /\.\/time-range-picker-toolbar(-[a-z]{2})?\.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json new file mode 100644 index 0000000000000..2b99d49fa32ae --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -0,0 +1,21 @@ +{ + "props": { + "className": { "type": { "name": "string" } }, + "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, + "toolbarFormat": { "type": { "name": "string" } }, + "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"––\"" } + }, + "slots": [], + "name": "TimeRangePickerToolbar", + "imports": [ + "import { TimeRangePickerToolbar } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePickerToolbar } from '@mui/x-date-pickers-pro';" + ], + "styles": { + "classes": ["root", "container"], + "globalClasses": {}, + "name": "MuiTimeRangePickerToolbar" + }, + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx", + "demos": "
      " +} diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json new file mode 100644 index 0000000000000..066560d8e8384 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json @@ -0,0 +1,279 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { + "description": "12h/24h view for hour selection clock.", + "deprecated": "", + "typeDescriptions": {} + }, + "ampmInClock": { + "description": "Display ampm controls under the clock (instead of in the toolbar).", + "deprecated": "", + "typeDescriptions": {} + }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "components": { + "description": "Overridable components.", + "deprecated": "", + "typeDescriptions": {} + }, + "componentsProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minutesStep": { + "description": "Step over minutes.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableClock": { + "description": "Disable specific clock time.", + "deprecated": "", + "typeDescriptions": { + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "deprecated": "", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "The time steps between two time unit options. For example, if timeStep.minutes = 8, then the available minute options will be [0, 8, 16, 24, 32, 40, 48, 56]. When single column time renderer is used, only timeStep.minutes will be used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
      See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "field": "", + "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "leftArrowIcon": "Icon displayed in the left view switch button.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json new file mode 100644 index 0000000000000..c4215f3080afa --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "", + "propDescriptions": { + "className": { + "description": "className applied to the root component.", + "deprecated": "", + "typeDescriptions": {} + }, + "hidden": { + "description": "If true, show the toolbar even in desktop mode.", + "deprecated": "", + "typeDescriptions": {} + }, + "toolbarFormat": { + "description": "Toolbar date format.", + "deprecated": "", + "typeDescriptions": {} + }, + "toolbarPlaceholder": { + "description": "Toolbar value placeholder—it is displayed when the value is empty.", + "deprecated": "", + "typeDescriptions": {} + } + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "container": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the container element" + } + }, + "slotDescriptions": {} +} diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx index a079f1edb8ec6..d8884f218aa5a 100644 --- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx @@ -60,6 +60,7 @@ const DesktopDateRangePicker = React.forwardRef(function DesktopDateRangePicker< valueManager: rangeValueManager, valueType: 'date', validator: validateDateRange, + shouldMovePopperToFocusedInput: false, }); return renderPicker(); diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index ada6605c65729..8112b6fd0f0e5 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -12,7 +12,7 @@ import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/time import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; -import { MultiInputDateRangeField } from '../MultiInputDateRangeField'; +import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; import { DateRange } from '../internals/models'; @@ -65,7 +65,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< format: resolveTimeFormat(utils, defaultizedProps), views: shouldRenderTimeInASingleColumn ? ['hours' as TimeViewWithMeridiem] : views, slots: { - field: MultiInputDateRangeField, + field: MultiInputTimeRangeField, ...defaultizedProps.slots, }, slotProps: { @@ -87,6 +87,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< valueManager: rangeValueManager, valueType: 'time', validator: validateTimeRange, + shouldMovePopperToFocusedInput: true, }); return renderPicker(); @@ -97,6 +98,16 @@ DesktopTimeRangePicker.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default `utils.is12HourCycleInCurrentLocale()` + */ + ampm: PropTypes.bool, + /** + * Display ampm controls under the clock (instead of in the toolbar). + * @default true on desktop, false on mobile + */ + ampmInClock: PropTypes.bool, /** * If `true`, the main element is focused during the first mount. * This main element is: @@ -104,11 +115,6 @@ DesktopTimeRangePicker.propTypes = { * - the `input` element if there is a field rendered. */ autoFocus: PropTypes.bool, - /** - * The number of calendars to render on **desktop**. - * @default 2 - */ - calendars: PropTypes.oneOf([1, 2, 3]), /** * Class name applied to the root element. */ @@ -130,22 +136,6 @@ DesktopTimeRangePicker.propTypes = { * @deprecated Please use `slotProps`. */ componentsProps: PropTypes.object, - /** - * Position the current month is rendered in. - * @default 1 - */ - currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), - /** - * Formats the day of week displayed in the calendar header. - * @param {string} day The day of week provided by the adapter's method `getWeekdays`. - * @returns {string} The name to display. - * @default (day) => day.charAt(0).toUpperCase() - */ - dayOfWeekFormatter: PropTypes.func, - /** - * Default calendar month displayed when `value={[null, null]}`. - */ - defaultCalendarMonth: PropTypes.any, /** * The initial position in the edited date range. * Used when the component is not controlled. @@ -157,31 +147,21 @@ DesktopTimeRangePicker.propTypes = { * Used when the component is not controlled. */ defaultValue: PropTypes.arrayOf(PropTypes.any), - /** - * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. - * @default false - */ - disableAutoMonthSwitching: PropTypes.bool, /** * If `true`, the picker and text field are disabled. * @default false */ disabled: PropTypes.bool, - /** - * If `true`, editing dates by dragging is disabled. - * @default false - */ - disableDragEditing: PropTypes.bool, /** * If `true`, disable values after the current date for date components, time for time components and both for date time components. * @default false */ disableFuture: PropTypes.bool, /** - * If `true`, today's date is rendering without highlighting with circle. + * Do not ignore date part when validating min/max time. * @default false */ - disableHighlightToday: PropTypes.bool, + disableIgnoringDatePartForTimeValidation: PropTypes.bool, /** * If `true`, the open picker button will not be rendered (renders only the field). * @default false @@ -192,16 +172,6 @@ DesktopTimeRangePicker.propTypes = { * @default false */ disablePast: PropTypes.bool, - /** - * If `true`, the week number will be display in the calendar. - */ - displayWeekNumber: PropTypes.bool, - /** - * Calendar will show more weeks in order to match this value. - * Put it to 6 for having fix number of week in Gregorian calendars - * @default undefined - */ - fixedWeekNumber: PropTypes.number, /** * Format of the date when rendered in the input(s). * Defaults to localized format based on the used `views`. @@ -228,25 +198,26 @@ DesktopTimeRangePicker.propTypes = { * Ignored if the field has several inputs. */ label: PropTypes.node, - /** - * If `true`, calls `renderLoading` instead of rendering the day calendar. - * Can be used to preload information and show it in calendar. - * @default false - */ - loading: PropTypes.bool, /** * Locale for components texts. * Allows overriding texts coming from `LocalizationProvider` and `theme`. */ localeText: PropTypes.object, /** - * Maximal selectable date. + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + maxTime: PropTypes.any, + /** + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxDate: PropTypes.any, + minTime: PropTypes.any, /** - * Minimal selectable date. + * Step over minutes. + * @default 1 */ - minDate: PropTypes.any, + minutesStep: PropTypes.number, /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -276,12 +247,6 @@ DesktopTimeRangePicker.propTypes = { * @param {TValue} value The value associated to the error. */ onError: PropTypes.func, - /** - * Callback fired on month change. - * @template TDate - * @param {TDate} month The new month. - */ - onMonthChange: PropTypes.func, /** * Callback fired when the popup requests to be opened. * Use in controlled mode (see `open`). @@ -297,11 +262,23 @@ DesktopTimeRangePicker.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, /** * Control the popup or dialog open state. * @default false */ open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), /** * The position in the currently edited date range. * Used when the component position is controlled. @@ -309,16 +286,15 @@ DesktopTimeRangePicker.propTypes = { rangePosition: PropTypes.oneOf(['end', 'start']), readOnly: PropTypes.bool, /** - * Disable heavy animations. - * @default typeof navigator !== 'undefined' && /(android)/i.test(navigator.userAgent) + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 */ reduceAnimations: PropTypes.bool, /** - * Component displaying when passed `loading` true. - * @returns {React.ReactNode} The node to render when loading. - * @default () => "..." + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ - renderLoading: PropTypes.func, + referenceDate: PropTypes.any, /** * The currently selected sections. * This prop accept four formats: @@ -347,24 +323,26 @@ DesktopTimeRangePicker.propTypes = { }), ]), /** - * Disable specific date. + * Disable specific clock time. + * @param {number} clockValue The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + * @deprecated Consider using `shouldDisableTime`. + */ + shouldDisableClock: PropTypes.func, + /** + * Disable specific time. * @template TDate - * @param {TDate} day The date to test. - * @param {string} position The date to test, 'start' or 'end'. - * @returns {boolean} Returns `true` if the date should be disabled. + * @param {TDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. */ - shouldDisableDate: PropTypes.func, + shouldDisableTime: PropTypes.func, /** - * If `true`, days outside the current month are rendered: - * - * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. - * - * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. - * - * - ignored if `calendars` equals more than `1` on range pickers. + * If `true`, disabled digital clock items will not be rendered. * @default false */ - showDaysOutsideCurrentMonth: PropTypes.bool, + skipDisabled: PropTypes.bool, /** * The props used for each component slot. * @default {} @@ -383,6 +361,22 @@ DesktopTimeRangePicker.propTypes = { PropTypes.func, PropTypes.object, ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * The time steps between two time unit options. + * For example, if `timeStep.minutes = 8`, then the available minute options will be `[0, 8, 16, 24, 32, 40, 48, 56]`. + * When single column time renderer is used, only `timeStep.minutes` will be used. + * @default{ hours: 1, minutes: 5, seconds: 5 } + */ + timeSteps: PropTypes.shape({ + hours: PropTypes.number, + minutes: PropTypes.number, + seconds: PropTypes.number, + }), /** * Choose which timezone to use for the value. * Example: "default", "system", "UTC", "America/New_York". @@ -396,14 +390,27 @@ DesktopTimeRangePicker.propTypes = { * Used when the component is controlled. */ value: PropTypes.arrayOf(PropTypes.any), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. * If `undefined`, internally defined view will be the used. */ viewRenderers: PropTypes.shape({ - day: PropTypes.func, + hours: PropTypes.func, + meridiem: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), } as any; export { DesktopTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/index.ts b/packages/x-date-pickers-pro/src/index.ts index f790a9fbb65ee..cc54ea1cfc274 100644 --- a/packages/x-date-pickers-pro/src/index.ts +++ b/packages/x-date-pickers-pro/src/index.ts @@ -24,6 +24,8 @@ export * from './DateRangePicker'; export * from './DesktopDateRangePicker'; export * from './MobileDateRangePicker'; export * from './StaticDateRangePicker'; +export * from './TimeRangePicker'; +export * from './DesktopTimeRangePicker'; // View renderers export * from './dateRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index 030cbc42272fd..231488aa93065 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -35,6 +35,7 @@ export const useDesktopRangePicker = < TExternalProps extends UseDesktopRangePickerProps, >({ props, + shouldMovePopperToFocusedInput, ...pickerParams }: UseDesktopRangePickerParams) => { useLicenseVerifier('x-date-pickers-pro', releaseInfo); @@ -149,6 +150,7 @@ export const useDesktopRangePicker = < pickerSlots: slots, fieldProps, anchorRef, + shouldMovePopperToFocusedInput, }); const slotPropsForLayout: PickersLayoutSlotsComponentsProps, TDate, TView> = { diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts index 8a6ece9878927..63121346fa622 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts @@ -100,4 +100,9 @@ export interface UseDesktopRangePickerParams< 'valueManager' | 'valueType' | 'validator' > { props: TExternalProps; + /** + * If `true`, the popper will always be aligned on the currently focused input. + * This is helpful when the view only renders information about one of the dates. + */ + shouldMovePopperToFocusedInput: boolean; } diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index 0bb6dccd50e2b..caeeaabfc5796 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -96,6 +96,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< pickerSlots: UncapitalizeObjectKeys | undefined; fieldProps: FieldProps; anchorRef?: React.Ref; + shouldMovePopperToFocusedInput: boolean; } const useMultiInputFieldSlotProps = ({ @@ -113,6 +114,7 @@ const useMultiInputFieldSlotProps = ({ skipDisabled, timezone, rangePosition, + onRangePositionChange, }: TimeRangeViewRendererProps< TDate, Extract, Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & - Pick, 'timeSteps'> & { + Pick, 'timeSteps'> & + UseRangePositionProps & { value: DateRange; onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; - rangePosition: RangePosition; } >) => { const viewValue = rangePosition === 'start' ? value[0] : value[1]; - const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => + const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + if (rangePosition === 'start') { + onRangePositionChange?.('end'); + } + onChange( rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], - selectionState, + rangePosition === 'start' ? 'partial' : selectionState, ); + }; return ( diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index d1a333c4baa12..da7b20b17a5b9 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -117,6 +117,10 @@ { "name": "DesktopTimePickerProps", "kind": "Interface" }, { "name": "DesktopTimePickerSlotsComponent", "kind": "Interface" }, { "name": "DesktopTimePickerSlotsComponentsProps", "kind": "Interface" }, + { "name": "DesktopTimeRangePicker", "kind": "Variable" }, + { "name": "DesktopTimeRangePickerProps", "kind": "Interface" }, + { "name": "DesktopTimeRangePickerSlotsComponent", "kind": "Interface" }, + { "name": "DesktopTimeRangePickerSlotsComponentsProps", "kind": "Interface" }, { "name": "DigitalClock", "kind": "Variable" }, { "name": "digitalClockClasses", "kind": "Variable" }, { "name": "DigitalClockClasses", "kind": "Interface" }, @@ -321,6 +325,14 @@ { "name": "TimePickerToolbarClasses", "kind": "Interface" }, { "name": "TimePickerToolbarClassKey", "kind": "TypeAlias" }, { "name": "TimePickerToolbarProps", "kind": "Interface" }, + { "name": "TimeRangePickerProps", "kind": "Interface" }, + { "name": "TimeRangePickerSlotsComponents", "kind": "Interface" }, + { "name": "TimeRangePickerSlotsComponentsProps", "kind": "Interface" }, + { "name": "TimeRangePickerToolbar", "kind": "Variable" }, + { "name": "timeRangePickerToolbarClasses", "kind": "Variable" }, + { "name": "TimeRangePickerToolbarClasses", "kind": "Interface" }, + { "name": "TimeRangePickerToolbarClassKey", "kind": "TypeAlias" }, + { "name": "TimeRangePickerToolbarProps", "kind": "Interface" }, { "name": "TimeRangeValidationError", "kind": "TypeAlias" }, { "name": "TimeStepOptions", "kind": "Interface" }, { "name": "TimeValidationError", "kind": "TypeAlias" }, From d3336ae51e794e59de5305ad98965b3b6b0ab5af Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 12 Sep 2023 14:00:19 +0200 Subject: [PATCH 06/74] Create very basic doc --- .../time-range-picker/BasicTimeRangePicker.js | 15 + .../BasicTimeRangePicker.tsx | 15 + .../BasicTimeRangePicker.tsx.preview | 1 + .../time-range-picker/time-range-picker.md | 88 ++++- docs/data/pages.ts | 3 +- .../src/TimeRangePicker/TimeRangePicker.tsx | 351 ++++++++++++++++++ .../src/TimeRangePicker/index.ts | 2 +- .../useDesktopRangePicker.tsx | 9 +- .../hooks/useEnrichedRangePickerFieldProps.ts | 10 +- 9 files changed, 479 insertions(+), 15 deletions(-) create mode 100644 docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js create mode 100644 docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx create mode 100644 docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js new file mode 100644 index 0000000000000..1f911ef628352 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro'; +import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function BasicTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx new file mode 100644 index 0000000000000..1f911ef628352 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro'; +import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function BasicTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview new file mode 100644 index 0000000000000..b06e812ca6771 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 87a3929b566f3..11a50cb8e99ec 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -1,19 +1,95 @@ --- productId: x-date-pickers title: React Time Range Picker component -githubLabel: 'component: TimeRangePicker' +components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, StaticTimeRangePicker +githubLabel: 'component: DateRangePicker' packageName: '@mui/x-date-pickers-pro' materialDesign: https://m2.material.io/components/date-pickers --- -# Time Range Picker [](/x/introduction/licensing/#pro-plan 'Pro plan')🚧 +# Time Range Picker [](/x/introduction/licensing/#pro-plan 'Pro plan') -

      The Time Range Picker let the user select a range of time.

      +

      The Time Range Picker let the user select a range of times.

      + +## Basic usage + +{{"demo": "BasicTimeRangePicker.js"}} + +## Component composition + +The component is built using the `MultiInputTimeRangeField` for the keyboard editing, the `DigitalClock` for the desktop view editing, and the `TimeClock` for the mobile view editing. +All the documented props of those two components can also be passed to the Time Range Picker component. + +Check-out their documentation page for more information: + +- [Time Range Field](/x/react-date-pickers/time-range-field/) +- [Digital Clock](/x/react-date-pickers/digital-clock/) +- [Time Clock](/x/react-date-pickers/time-clock/) + +## Uncontrolled vs. controlled value + +The value of the component can be uncontrolled or controlled. + +[//]: # '{{"demo": "TimeRangePickerValue.js"}}' + +:::info + +- The value is **controlled** when its parent manages it by providing a `value` prop. +- The value is **uncontrolled** when it is managed by the component's own internal state. This state can be initialized using the `defaultValue` prop. + +Learn more about the _Controlled and uncontrolled_ pattern in the [React documentation](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components). +::: + +## Available components + +:::warning +NOT READY +::: + +The component is available in four variants: + +- The `DesktopTimeRangePicker` component which works best for mouse devices and large screens. + It renders the views inside a popover and allows editing values directly inside the field. + +- The `MobileTimeRangePicker` component which works best for touch devices and small screens. + It renders the view inside a modal and does not allow editing values directly inside the field. + +- The `TimeRangePicker` component which renders `DesktopTimeRangePicker` or `MobileTimeRangePicker` depending on the device it runs on. + +- The `StaticTimeRangePicker` component which renders without the popover/modal and field. + +[//]: # '{{"demo": "ResponsiveDateRangePickers.js"}}' + +By default, the `DateRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. +This can be customized with the `desktopModeMediaQuery` prop. + +:::warning +Responsive components can suffer some inconsistencies between testing environments if media query is not supported. +Please refer to [this section](/x/react-date-pickers/base-concepts/#testing-caveats) for solutions. +::: + +## Form props + +The component can be disabled or read-only. + +[//]: # '{{"demo": "FormPropsTimeRangePickers.js"}}' + +## Customization + +### Use a single input field :::warning -This feature isn't implemented yet. It's coming. +NOT READY +::: + +You can pass the `SingleInputTimeRangeField` component to the Date Range Picker to use it for keyboard editing: -👍 Upvote [issue #4460](https://github.com/mui/mui-x/issues/4460) if you want to see it land faster. +[//]: # '{{"demo": "SingleInputDateRangePicker.js"}}' -Don't hesitate to leave a comment on the same issue to influence what gets built. Especially if you already have a use case for this component, or if you are facing a pain point with your current solution. +:::info +For more information, check out the [Custom field](/x/react-date-pickers/custom-field/#use-single-input-fields-on-range-pickers) page. ::: + +## Validation + +You can find the documentation in the [Validation page](/x/react-date-pickers/validation/). diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 5e356999efdec..9843cec88ea4b 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -271,7 +271,8 @@ const pages: MuiPage[] = [ children: [ { pathname: '/x/react-date-pickers/time-range-picker', - title: 'Time Range Picker 🚧', + title: 'Time Range Picker', + newFeature: true, }, { pathname: '/x/react-date-pickers/time-range-field', diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx new file mode 100644 index 0000000000000..8026e7abe57a3 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -0,0 +1,351 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useThemeProps } from '@mui/material/styles'; +import { refType } from '@mui/utils'; +import { DesktopTimeRangePicker } from '../DesktopTimeRangePicker'; +import { TimeRangePickerProps } from './TimeRangePicker.types'; + +type TimePickerComponent = (( + props: TimeRangePickerProps & React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +const TimeRangePicker = React.forwardRef(function TimeRangePicker( + inProps: TimeRangePickerProps, + ref: React.Ref, +) { + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePicker' }); + + const { desktopModeMediaQuery = '@media (pointer: fine)', ...other } = props; + + // defaults to `true` in environments where `window.matchMedia` would not be available (i.e. test/jsdom) + const isDesktop = useMediaQuery(desktopModeMediaQuery, { defaultMatches: true }); + + if (isDesktop) { + return ; + } + + return
      TOTO
      ; +}) as TimePickerComponent; + +TimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + /** + * The number of calendars to render on **desktop**. + * @default 2 + */ + calendars: PropTypes.oneOf([1, 2, 3]), + /** + * Class name applied to the root element. + */ + className: PropTypes.string, + /** + * If `true`, the popover or modal will close after submitting the full date. + * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + */ + closeOnSelect: PropTypes.bool, + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components: PropTypes.object, + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps: PropTypes.object, + /** + * Position the current month is rendered in. + * @default 1 + */ + currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), + /** + * Formats the day of week displayed in the calendar header. + * @param {string} day The day of week provided by the adapter's method `getWeekdays`. + * @returns {string} The name to display. + * @default (day) => day.charAt(0).toUpperCase() + */ + dayOfWeekFormatter: PropTypes.func, + /** + * Default calendar month displayed when `value={[null, null]}`. + */ + defaultCalendarMonth: PropTypes.any, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.any), + /** + * CSS media query when `Mobile` mode will be changed to `Desktop`. + * @default '@media (pointer: fine)' + * @example '@media (min-width: 720px)' or theme.breakpoints.up("sm") + */ + desktopModeMediaQuery: PropTypes.string, + /** + * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. + * @default false + */ + disableAutoMonthSwitching: PropTypes.bool, + /** + * If `true`, the picker and text field are disabled. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, editing dates by dragging is disabled. + * @default false + */ + disableDragEditing: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * If `true`, today's date is rendering without highlighting with circle. + * @default false + */ + disableHighlightToday: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * If `true`, the week number will be display in the calendar. + */ + displayWeekNumber: PropTypes.bool, + /** + * Calendar will show more weeks in order to match this value. + * Put it to 6 for having fix number of week in Gregorian calendars + * @default undefined + */ + fixedWeekNumber: PropTypes.number, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: refType, + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * If `true`, calls `renderLoading` instead of rendering the day calendar. + * Can be used to preload information and show it in calendar. + * @default false + */ + loading: PropTypes.bool, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable date. + */ + maxDate: PropTypes.any, + /** + * Minimal selectable date. + */ + minDate: PropTypes.any, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated to the current value changes. + * If the error has a non-null value, then the `TextField` will be rendered in `error` state. + * + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TError} error The new error describing why the current value is not valid. + * @param {TValue} value The value associated to the error. + */ + onError: PropTypes.func, + /** + * Callback fired on month change. + * @template TDate + * @param {TDate} month The new month. + */ + onMonthChange: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + readOnly: PropTypes.bool, + /** + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 + */ + reduceAnimations: PropTypes.bool, + /** + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. + */ + referenceDate: PropTypes.any, + /** + * Component displaying when passed `loading` true. + * @returns {React.ReactNode} The node to render when loading. + * @default () => "..." + */ + renderLoading: PropTypes.func, + /** + * The currently selected sections. + * This prop accept four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If an object with a `startIndex` and `endIndex` properties are provided, the sections between those two indexes will be selected. + * 3. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 4. If `null` is provided, no section will be selected + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + PropTypes.shape({ + endIndex: PropTypes.number.isRequired, + startIndex: PropTypes.number.isRequired, + }), + ]), + /** + * Disable specific date. + * @template TDate + * @param {TDate} day The date to test. + * @param {string} position The date to test, 'start' or 'end'. + * @returns {boolean} Returns `true` if the date should be disabled. + */ + shouldDisableDate: PropTypes.func, + /** + * If `true`, days outside the current month are rendered: + * + * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. + * + * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. + * + * - ignored if `calendars` equals more than `1` on range pickers. + * @default false + */ + showDaysOutsideCurrentMonth: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documention} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.any), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + day: PropTypes.func, + }), +} as any; + +export { TimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts index dc8ea7e268431..327afa9da48f9 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts @@ -1,4 +1,4 @@ -// export { TimeRangePicker } from './TimeRangePicker'; +export { TimeRangePicker } from './TimeRangePicker'; export type { TimeRangePickerProps, TimeRangePickerSlotsComponents, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index 231488aa93065..eb5b1f22594df 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -60,6 +60,7 @@ export const useDesktopRangePicker = < const fieldContainerRef = React.useRef(null); const anchorRef = React.useRef(null); + const anchorRefEndDate = React.useRef(null); const popperRef = React.useRef(null); const { rangePosition, onRangePositionChange, singleInputFieldRef } = useRangePosition(props); @@ -150,7 +151,7 @@ export const useDesktopRangePicker = < pickerSlots: slots, fieldProps, anchorRef, - shouldMovePopperToFocusedInput, + anchorRefEndDate, }); const slotPropsForLayout: PickersLayoutSlotsComponentsProps, TDate, TView> = { @@ -170,7 +171,11 @@ export const useDesktopRangePicker = < role="tooltip" placement="bottom-start" containerRef={popperRef} - anchorEl={anchorRef.current} + anchorEl={ + shouldMovePopperToFocusedInput && rangePosition === 'end' + ? anchorRefEndDate.current + : anchorRef.current + } onBlur={handleBlur} {...actions} open={open} diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index caeeaabfc5796..5478125b47379 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -96,7 +96,7 @@ export interface UseEnrichedRangePickerFieldPropsParams< pickerSlots: UncapitalizeObjectKeys | undefined; fieldProps: FieldProps; anchorRef?: React.Ref; - shouldMovePopperToFocusedInput: boolean; + anchorRefEndDate?: React.Ref; } const useMultiInputFieldSlotProps = ({ @@ -114,7 +114,7 @@ const useMultiInputFieldSlotProps = Date: Tue, 12 Sep 2023 14:11:46 +0200 Subject: [PATCH 07/74] Fix --- docs/data/date-pickers-component-api-pages.ts | 1 + .../desktop-time-range-picker.json | 2 +- .../x/api/date-pickers/time-range-picker.js | 23 ++ .../x/api/date-pickers/time-range-picker.json | 266 ++++++++++++++++ .../date-pickers/time-range-picker.json | 284 ++++++++++++++++++ .../src/TimeRangePicker/TimeRangePicker.tsx | 159 +++++----- .../timeRangeViewRenderers.tsx | 4 +- .../src/DateCalendar/DayCalendar.tsx | 2 - scripts/x-date-pickers-pro.exports.json | 1 + 9 files changed, 658 insertions(+), 84 deletions(-) create mode 100644 docs/pages/x/api/date-pickers/time-range-picker.js create mode 100644 docs/pages/x/api/date-pickers/time-range-picker.json create mode 100644 docs/translations/api-docs/date-pickers/time-range-picker.json diff --git a/docs/data/date-pickers-component-api-pages.ts b/docs/data/date-pickers-component-api-pages.ts index 8490b16921276..774be4a830e31 100644 --- a/docs/data/date-pickers-component-api-pages.ts +++ b/docs/data/date-pickers-component-api-pages.ts @@ -97,6 +97,7 @@ export default [ { pathname: '/x/api/date-pickers/time-field', title: 'TimeField' }, { pathname: '/x/api/date-pickers/time-picker', title: 'TimePicker' }, { pathname: '/x/api/date-pickers/time-picker-toolbar', title: 'TimePickerToolbar' }, + { pathname: '/x/api/date-pickers/time-range-picker', title: 'TimeRangePicker', plan: 'pro' }, { pathname: '/x/api/date-pickers/time-range-picker-toolbar', title: 'TimeRangePickerToolbar', diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 05b5109ee615c..4a6fcbc66b4ee 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -260,5 +260,5 @@ ], "styles": { "classes": [], "globalClasses": {}, "name": "MuiDesktopTimeRangePicker" }, "filename": "/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx", - "demos": "
        " + "demos": "" } diff --git a/docs/pages/x/api/date-pickers/time-range-picker.js b/docs/pages/x/api/date-pickers/time-range-picker.js new file mode 100644 index 0000000000000..90a7ed6edb765 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers', + false, + /\.\/time-range-picker(-[a-z]{2})?\.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json new file mode 100644 index 0000000000000..b7dd38f2a6bb0 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -0,0 +1,266 @@ +{ + "props": { + "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, + "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, + "autoFocus": { "type": { "name": "bool" } }, + "className": { "type": { "name": "string" } }, + "closeOnSelect": { + "type": { "name": "bool" }, + "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." + }, + "components": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slots." + }, + "componentsProps": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slotProps." + }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
        | 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "desktopModeMediaQuery": { + "type": { "name": "string" }, + "default": "'@media (pointer: fine)'" + }, + "disabled": { "type": { "name": "bool" } }, + "disableFuture": { "type": { "name": "bool" } }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" } }, + "disableOpenPicker": { "type": { "name": "bool" } }, + "disablePast": { "type": { "name": "bool" } }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
        | 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { "type": { "name": "custom", "description": "ref" } }, + "label": { "type": { "name": "node" } }, + "localeText": { "type": { "name": "object" } }, + "maxTime": { "type": { "name": "any" } }, + "minTime": { "type": { "name": "any" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, + "onAccept": { + "type": { "name": "func" }, + "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "open": { "type": { "name": "bool" } }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" + } + }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "any" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
        | 'day'
        | 'hours'
        | 'meridiem'
        | 'minutes'
        | 'month'
        | 'seconds'
        | 'weekDay'
        | 'year'
        | number
        | { endIndex: number, startIndex: number }" + } + }, + "shouldDisableClock": { + "type": { "name": "func" }, + "deprecated": true, + "deprecationInfo": "Consider using shouldDisableTime.", + "signature": { + "type": "function(clockValue: number, view: TimeView) => boolean", + "describedArgs": ["clockValue", "view"], + "returned": "boolean" + } + }, + "shouldDisableTime": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], + "returned": "boolean" + } + }, + "skipDisabled": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { "type": { "name": "object" }, "default": "{}" }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
        | object
        | bool>
        | func
        | object" + }, + "additionalInfo": { "sx": true } + }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise." + }, + "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" + } + }, + "viewRenderers": { + "type": { + "name": "shape", + "description": "{ hours?: func, meridiem?: func, minutes?: func, seconds?: func }" + } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
        | 'minutes'
        | 'seconds'>" + } + } + }, + "slots": [ + { + "class": null, + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar" + }, + { + "class": null, + "name": "desktopPaper", + "description": "Custom component for the paper rendered inside the desktop picker's Popper.", + "default": "PickersPopperPaper" + }, + { + "class": null, + "name": "desktopTransition", + "description": "Custom component for the desktop popper Transition.", + "default": "Grow or Fade from '@mui/material' when `reduceAnimations` is `true`." + }, + { + "class": null, + "name": "desktopTrapFocus", + "description": "Custom component for trapping the focus inside the views on desktop.", + "default": "FocusTrap from '@mui/base'." + }, + { "class": null, "name": "field", "description": "" }, + { + "class": null, + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + }, + { + "class": null, + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft" + }, + { + "class": null, + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton" + }, + { + "class": null, + "name": "popper", + "description": "Custom component for the popper inside which the views are rendered on desktop.", + "default": "Popper from '@mui/material'." + }, + { + "class": null, + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton" + }, + { + "class": null, + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight" + }, + { + "class": null, + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts" + }, + { + "class": null, + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "default": "TextField from '@mui/material'" + }, + { + "class": null, + "name": "toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "DateTimePickerToolbar" + } + ], + "name": "TimeRangePicker", + "imports": [ + "import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "styles": { "classes": [], "globalClasses": {}, "name": "MuiTimeRangePicker" }, + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx", + "demos": "" +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json new file mode 100644 index 0000000000000..bb90c0db9d6b2 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -0,0 +1,284 @@ +{ + "componentDescription": "", + "propDescriptions": { + "ampm": { + "description": "12h/24h view for hour selection clock.", + "deprecated": "", + "typeDescriptions": {} + }, + "ampmInClock": { + "description": "Display ampm controls under the clock (instead of in the toolbar).", + "deprecated": "", + "typeDescriptions": {} + }, + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "components": { + "description": "Overridable components.", + "deprecated": "", + "typeDescriptions": {} + }, + "componentsProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "desktopModeMediaQuery": { + "description": "CSS media query when Mobile mode will be changed to Desktop.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", + "deprecated": "", + "typeDescriptions": {} + }, + "minutesStep": { + "description": "Step over minutes.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableClock": { + "description": "Disable specific clock time.", + "deprecated": "", + "typeDescriptions": { + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "shouldDisableTime": { + "description": "Disable specific time.", + "deprecated": "", + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } + }, + "skipDisabled": { + "description": "If true, disabled digital clock items will not be rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "The time steps between two time unit options. For example, if timeStep.minutes = 8, then the available minute options will be [0, 8, 16, 24, 32, 40, 48, 56]. When single column time renderer is used, only timeStep.minutes will be used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
        See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", + "desktopTransition": "Custom component for the desktop popper Transition.", + "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "field": "", + "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "leftArrowIcon": "Icon displayed in the left view switch button.", + "nextIconButton": "Button allowing to switch to the right view.", + "popper": "Custom component for the popper inside which the views are rendered on desktop.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 8026e7abe57a3..2ac049a9242e9 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -33,6 +33,16 @@ TimeRangePicker.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default `utils.is12HourCycleInCurrentLocale()` + */ + ampm: PropTypes.bool, + /** + * Display ampm controls under the clock (instead of in the toolbar). + * @default true on desktop, false on mobile + */ + ampmInClock: PropTypes.bool, /** * If `true`, the main element is focused during the first mount. * This main element is: @@ -40,11 +50,6 @@ TimeRangePicker.propTypes = { * - the `input` element if there is a field rendered. */ autoFocus: PropTypes.bool, - /** - * The number of calendars to render on **desktop**. - * @default 2 - */ - calendars: PropTypes.oneOf([1, 2, 3]), /** * Class name applied to the root element. */ @@ -66,22 +71,6 @@ TimeRangePicker.propTypes = { * @deprecated Please use `slotProps`. */ componentsProps: PropTypes.object, - /** - * Position the current month is rendered in. - * @default 1 - */ - currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), - /** - * Formats the day of week displayed in the calendar header. - * @param {string} day The day of week provided by the adapter's method `getWeekdays`. - * @returns {string} The name to display. - * @default (day) => day.charAt(0).toUpperCase() - */ - dayOfWeekFormatter: PropTypes.func, - /** - * Default calendar month displayed when `value={[null, null]}`. - */ - defaultCalendarMonth: PropTypes.any, /** * The initial position in the edited date range. * Used when the component is not controlled. @@ -99,31 +88,21 @@ TimeRangePicker.propTypes = { * @example '@media (min-width: 720px)' or theme.breakpoints.up("sm") */ desktopModeMediaQuery: PropTypes.string, - /** - * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. - * @default false - */ - disableAutoMonthSwitching: PropTypes.bool, /** * If `true`, the picker and text field are disabled. * @default false */ disabled: PropTypes.bool, - /** - * If `true`, editing dates by dragging is disabled. - * @default false - */ - disableDragEditing: PropTypes.bool, /** * If `true`, disable values after the current date for date components, time for time components and both for date time components. * @default false */ disableFuture: PropTypes.bool, /** - * If `true`, today's date is rendering without highlighting with circle. + * Do not ignore date part when validating min/max time. * @default false */ - disableHighlightToday: PropTypes.bool, + disableIgnoringDatePartForTimeValidation: PropTypes.bool, /** * If `true`, the open picker button will not be rendered (renders only the field). * @default false @@ -134,16 +113,6 @@ TimeRangePicker.propTypes = { * @default false */ disablePast: PropTypes.bool, - /** - * If `true`, the week number will be display in the calendar. - */ - displayWeekNumber: PropTypes.bool, - /** - * Calendar will show more weeks in order to match this value. - * Put it to 6 for having fix number of week in Gregorian calendars - * @default undefined - */ - fixedWeekNumber: PropTypes.number, /** * Format of the date when rendered in the input(s). * Defaults to localized format based on the used `views`. @@ -165,25 +134,26 @@ TimeRangePicker.propTypes = { * Ignored if the field has several inputs. */ label: PropTypes.node, - /** - * If `true`, calls `renderLoading` instead of rendering the day calendar. - * Can be used to preload information and show it in calendar. - * @default false - */ - loading: PropTypes.bool, /** * Locale for components texts. * Allows overriding texts coming from `LocalizationProvider` and `theme`. */ localeText: PropTypes.object, /** - * Maximal selectable date. + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxDate: PropTypes.any, + maxTime: PropTypes.any, /** - * Minimal selectable date. + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - minDate: PropTypes.any, + minTime: PropTypes.any, + /** + * Step over minutes. + * @default 1 + */ + minutesStep: PropTypes.number, /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -213,12 +183,6 @@ TimeRangePicker.propTypes = { * @param {TValue} value The value associated to the error. */ onError: PropTypes.func, - /** - * Callback fired on month change. - * @template TDate - * @param {TDate} month The new month. - */ - onMonthChange: PropTypes.func, /** * Callback fired when the popup requests to be opened. * Use in controlled mode (see `open`). @@ -234,11 +198,23 @@ TimeRangePicker.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, /** * Control the popup or dialog open state. * @default false */ open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), /** * The position in the currently edited date range. * Used when the component position is controlled. @@ -255,12 +231,6 @@ TimeRangePicker.propTypes = { * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ referenceDate: PropTypes.any, - /** - * Component displaying when passed `loading` true. - * @returns {React.ReactNode} The node to render when loading. - * @default () => "..." - */ - renderLoading: PropTypes.func, /** * The currently selected sections. * This prop accept four formats: @@ -289,24 +259,26 @@ TimeRangePicker.propTypes = { }), ]), /** - * Disable specific date. + * Disable specific clock time. + * @param {number} clockValue The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + * @deprecated Consider using `shouldDisableTime`. + */ + shouldDisableClock: PropTypes.func, + /** + * Disable specific time. * @template TDate - * @param {TDate} day The date to test. - * @param {string} position The date to test, 'start' or 'end'. - * @returns {boolean} Returns `true` if the date should be disabled. + * @param {TDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. */ - shouldDisableDate: PropTypes.func, + shouldDisableTime: PropTypes.func, /** - * If `true`, days outside the current month are rendered: - * - * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. - * - * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. - * - * - ignored if `calendars` equals more than `1` on range pickers. + * If `true`, disabled digital clock items will not be rendered. * @default false */ - showDaysOutsideCurrentMonth: PropTypes.bool, + skipDisabled: PropTypes.bool, /** * The props used for each component slot. * @default {} @@ -325,6 +297,22 @@ TimeRangePicker.propTypes = { PropTypes.func, PropTypes.object, ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * The time steps between two time unit options. + * For example, if `timeStep.minutes = 8`, then the available minute options will be `[0, 8, 16, 24, 32, 40, 48, 56]`. + * When single column time renderer is used, only `timeStep.minutes` will be used. + * @default{ hours: 1, minutes: 5, seconds: 5 } + */ + timeSteps: PropTypes.shape({ + hours: PropTypes.number, + minutes: PropTypes.number, + seconds: PropTypes.number, + }), /** * Choose which timezone to use for the value. * Example: "default", "system", "UTC", "America/New_York". @@ -338,14 +326,27 @@ TimeRangePicker.propTypes = { * Used when the component is controlled. */ value: PropTypes.arrayOf(PropTypes.any), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. * If `undefined`, internally defined view will be the used. */ viewRenderers: PropTypes.shape({ - day: PropTypes.func, + hours: PropTypes.func, + meridiem: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), } as any; export { TimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 3adf08b8b3068..b335fab622b35 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -9,8 +9,8 @@ import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalCloc import Stack from '@mui/material/Stack'; import { TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; -import { DateRange, RangePosition } from '../internals/models'; -import { UseRangePositionProps } from '@mui/x-date-pickers-pro/internals/hooks/useRangePosition'; +import { DateRange } from '../internals/models'; +import { UseRangePositionProps } from '../internals/hooks/useRangePosition'; export type TimeRangeViewRendererProps< TDate, diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index f4dc5cf5b4df7..a256dff17dcc3 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -540,8 +540,6 @@ export function DayCalendar(inProps: DayCalendarProps) { return toDisplay; }, [currentMonth, fixedWeekNumber, utils, timezone]); - console.log(weeksToDisplay); - return (
        diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index da7b20b17a5b9..f335a69ad19cb 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -325,6 +325,7 @@ { "name": "TimePickerToolbarClasses", "kind": "Interface" }, { "name": "TimePickerToolbarClassKey", "kind": "TypeAlias" }, { "name": "TimePickerToolbarProps", "kind": "Interface" }, + { "name": "TimeRangePicker", "kind": "Variable" }, { "name": "TimeRangePickerProps", "kind": "Interface" }, { "name": "TimeRangePickerSlotsComponents", "kind": "Interface" }, { "name": "TimeRangePickerSlotsComponentsProps", "kind": "Interface" }, From 00e01491c5c011cff57f29c6978f1cd1a1293162 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 08:17:59 +0200 Subject: [PATCH 08/74] Add mobile time range picker --- .../FormPropsTimeRangePickers.js | 20 + .../FormPropsTimeRangePickers.tsx | 20 + .../FormPropsTimeRangePickers.tsx.preview | 6 + .../ResponsiveTimeRangePickers.js | 50 +++ .../ResponsiveTimeRangePickers.tsx | 51 +++ .../time-range-picker/TimeRangePickerValue.js | 32 ++ .../TimeRangePickerValue.tsx | 32 ++ .../TimeRangePickerValue.tsx.preview | 11 + .../time-range-picker/time-range-picker.md | 6 +- .../x/api/date-pickers/time-range-picker.json | 18 + .../date-pickers/time-range-picker.json | 3 + .../MobileTimeRangePicker.tsx | 393 ++++++++++++++++++ .../MobileTimeRangePicker.types.ts | 55 +++ .../src/MobileTimeRangePicker/index.ts | 6 + .../tests/MobileDateRangePicker.test.tsx | 276 ++++++++++++ .../describes.MobileDateRangePicker.test.tsx | 114 +++++ .../src/TimeRangePicker/TimeRangePicker.tsx | 3 +- .../TimeRangePicker/TimeRangePicker.types.ts | 17 +- .../TimeRangePickerToolbar.tsx | 32 +- .../src/TimeRangePicker/shared.tsx | 6 - .../hooks/useMobileRangePicker/index.ts | 1 + .../useMobileRangePicker.types.ts | 11 +- .../src/timeRangeViewRenderers/index.ts | 5 +- .../timeRangeViewRenderers.tsx | 166 ++++++-- 24 files changed, 1267 insertions(+), 67 deletions(-) create mode 100644 docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js create mode 100644 docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx create mode 100644 docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview create mode 100644 docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js create mode 100644 docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx create mode 100644 docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js create mode 100644 docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx create mode 100644 docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview create mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx create mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts create mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts create mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx create mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js new file mode 100644 index 0000000000000..e3d2728ea9302 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.js @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function FormPropsTimeRangePickers() { + return ( + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx new file mode 100644 index 0000000000000..e3d2728ea9302 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function FormPropsTimeRangePickers() { + return ( + + + + + + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview new file mode 100644 index 0000000000000..c2dacbc862092 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/FormPropsTimeRangePickers.tsx.preview @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js new file mode 100644 index 0000000000000..2f8d7c4b8b9a6 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js @@ -0,0 +1,50 @@ +import * as React from 'react'; +import dayjs from 'dayjs'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; +import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; +// import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; + +export default function ResponsiveTimeRangePickers() { + return ( + + + + + + + + + + + + {/* */} + {/* */} + {/* */} + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx new file mode 100644 index 0000000000000..c0a79ed2b2e72 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import dayjs from 'dayjs'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; +import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; +// import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; +import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; + +export default function ResponsiveTimeRangePickers() { + return ( + + + + + + + + + + + + {/* */} + {/* */} + {/* */} + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js new file mode 100644 index 0000000000000..5dde2e2df763c --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.js @@ -0,0 +1,32 @@ +import * as React from 'react'; +import dayjs from 'dayjs'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; + +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function TimeRangePickerValue() { + const [value, setValue] = React.useState([ + dayjs('2022-04-17T15:30'), + dayjs('2022-04-17T18:30'), + ]); + + return ( + + + + + + + setValue(newValue)} + /> + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx new file mode 100644 index 0000000000000..5866b7e77bbf9 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx @@ -0,0 +1,32 @@ +import * as React from 'react'; +import dayjs, { Dayjs } from 'dayjs'; +import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { DateRange } from '@mui/x-date-pickers-pro'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; + +export default function TimeRangePickerValue() { + const [value, setValue] = React.useState>([ + dayjs('2022-04-17T15:30'), + dayjs('2022-04-17T18:30'), + ]); + + return ( + + + + + + + setValue(newValue)} + /> + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview new file mode 100644 index 0000000000000..dd3b16e70f9c3 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx.preview @@ -0,0 +1,11 @@ + + + + + setValue(newValue)} + /> + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 11a50cb8e99ec..22a29df1be1e4 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -30,7 +30,7 @@ Check-out their documentation page for more information: The value of the component can be uncontrolled or controlled. -[//]: # '{{"demo": "TimeRangePickerValue.js"}}' +{{"demo": "TimeRangePickerValue.js"}} :::info @@ -58,7 +58,7 @@ The component is available in four variants: - The `StaticTimeRangePicker` component which renders without the popover/modal and field. -[//]: # '{{"demo": "ResponsiveDateRangePickers.js"}}' +{{"demo": "ResponsiveTimeRangePickers.js"}} By default, the `DateRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. This can be customized with the `desktopModeMediaQuery` prop. @@ -72,7 +72,7 @@ Please refer to [this section](/x/react-date-pickers/base-concepts/#testing-cave The component can be disabled or read-only. -[//]: # '{{"demo": "FormPropsTimeRangePickers.js"}}' +{{"demo": "FormPropsTimeRangePickers.js"}} ## Customization diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index b7dd38f2a6bb0..7a7fd925f0022 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -190,6 +190,12 @@ "description": "Custom component for trapping the focus inside the views on desktop.", "default": "FocusTrap from '@mui/base'." }, + { + "class": null, + "name": "dialog", + "description": "Custom component for the dialog inside which the views are rendered on mobile.", + "default": "PickersModalDialogRoot" + }, { "class": null, "name": "field", "description": "" }, { "class": null, @@ -212,6 +218,18 @@ "description": "Icon displayed in the left view switch button.", "default": "ArrowLeft" }, + { + "class": null, + "name": "mobilePaper", + "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "default": "Paper from '@mui/material'." + }, + { + "class": null, + "name": "mobileTransition", + "description": "Custom component for the mobile dialog Transition.", + "default": "Fade from '@mui/material'." + }, { "class": null, "name": "nextIconButton", diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json index bb90c0db9d6b2..9ad23d18a94f3 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -268,11 +268,14 @@ "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "", "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", "nextIconButton": "Button allowing to switch to the right view.", "popper": "Custom component for the popper inside which the views are rendered on desktop.", "previousIconButton": "Button allowing to switch to the left view.", diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx new file mode 100644 index 0000000000000..06836afbe875a --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -0,0 +1,393 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { TimeView } from '@mui/x-date-pickers/models'; +import { + extractValidationProps, + PickerViewRendererLookup, + resolveTimeFormat, + useUtils, +} from '@mui/x-date-pickers/internals'; +import { resolveComponentProps } from '@mui/base/utils'; +import { refType } from '@mui/utils'; +import { rangeValueManager } from '../internals/utils/valueManagers'; +import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; +import { renderTimeRangeViewClock } from '../timeRangeViewRenderers'; +import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; +import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; +import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; +import { DateRange } from '../internals/models'; + +type MobileTimeRangePickerComponent = (( + props: MobileTimeRangePickerProps & React.RefAttributes, +) => React.JSX.Element) & { propTypes?: any }; + +const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker( + inProps: MobileTimeRangePickerProps, + ref: React.Ref, +) { + const utils = useUtils(); + + // Props with the default values common to all date time pickers + const defaultizedProps = useTimeRangePickerDefaultizedProps< + TDate, + TimeView, + MobileTimeRangePickerProps + >(inProps, 'MuiMobileTimeRangePicker'); + + const viewRenderers: PickerViewRendererLookup, TimeView, any, {}> = { + hours: renderTimeRangeViewClock, + minutes: renderTimeRangeViewClock, + seconds: renderTimeRangeViewClock, + ...defaultizedProps.viewRenderers, + }; + + const props = { + ...defaultizedProps, + // TODO: Do we want the toolbar to support AM/PM switch on mobile? + ampmInClock: true, + viewRenderers, + format: resolveTimeFormat(utils, defaultizedProps), + slots: { + field: MultiInputTimeRangeField, + ...defaultizedProps.slots, + }, + slotProps: { + ...defaultizedProps.slotProps, + field: (ownerState: any) => ({ + ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), + ...extractValidationProps(defaultizedProps), + ref, + }), + toolbar: { + hidden: false, + ...defaultizedProps.slotProps?.toolbar, + }, + }, + }; + + const { renderPicker } = useMobileRangePicker({ + props, + valueManager: rangeValueManager, + valueType: 'time', + validator: validateTimeRange, + }); + + return renderPicker(); +}) as MobileTimeRangePickerComponent; + +MobileTimeRangePicker.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * If `true`, the main element is focused during the first mount. + * This main element is: + * - the element chosen by the visible view if any (i.e: the selected day on the `day` view). + * - the `input` element if there is a field rendered. + */ + autoFocus: PropTypes.bool, + /** + * The number of calendars to render on **desktop**. + * @default 2 + */ + calendars: PropTypes.oneOf([1, 2, 3]), + /** + * Class name applied to the root element. + */ + className: PropTypes.string, + /** + * If `true`, the popover or modal will close after submitting the full date. + * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + */ + closeOnSelect: PropTypes.bool, + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components: PropTypes.object, + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps: PropTypes.object, + /** + * Position the current month is rendered in. + * @default 1 + */ + currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), + /** + * Formats the day of week displayed in the calendar header. + * @param {string} day The day of week provided by the adapter's method `getWeekdays`. + * @returns {string} The name to display. + * @default (day) => day.charAt(0).toUpperCase() + */ + dayOfWeekFormatter: PropTypes.func, + /** + * Default calendar month displayed when `value={[null, null]}`. + */ + defaultCalendarMonth: PropTypes.any, + /** + * The initial position in the edited date range. + * Used when the component is not controlled. + * @default 'start' + */ + defaultRangePosition: PropTypes.oneOf(['end', 'start']), + /** + * The default value. + * Used when the component is not controlled. + */ + defaultValue: PropTypes.arrayOf(PropTypes.any), + /** + * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. + * @default false + */ + disableAutoMonthSwitching: PropTypes.bool, + /** + * If `true`, the picker and text field are disabled. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, editing dates by dragging is disabled. + * @default false + */ + disableDragEditing: PropTypes.bool, + /** + * If `true`, disable values after the current date for date components, time for time components and both for date time components. + * @default false + */ + disableFuture: PropTypes.bool, + /** + * If `true`, today's date is rendering without highlighting with circle. + * @default false + */ + disableHighlightToday: PropTypes.bool, + /** + * If `true`, the open picker button will not be rendered (renders only the field). + * @default false + */ + disableOpenPicker: PropTypes.bool, + /** + * If `true`, disable values before the current date for date components, time for time components and both for date time components. + * @default false + */ + disablePast: PropTypes.bool, + /** + * If `true`, the week number will be display in the calendar. + */ + displayWeekNumber: PropTypes.bool, + /** + * Calendar will show more weeks in order to match this value. + * Put it to 6 for having fix number of week in Gregorian calendars + * @default undefined + */ + fixedWeekNumber: PropTypes.number, + /** + * Format of the date when rendered in the input(s). + * Defaults to localized format based on the used `views`. + */ + format: PropTypes.string, + /** + * Density of the format when rendered in the input. + * Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character. + * @default "dense" + */ + formatDensity: PropTypes.oneOf(['dense', 'spacious']), + /** + * Pass a ref to the `input` element. + * Ignored if the field has several inputs. + */ + inputRef: refType, + /** + * The label content. + * Ignored if the field has several inputs. + */ + label: PropTypes.node, + /** + * If `true`, calls `renderLoading` instead of rendering the day calendar. + * Can be used to preload information and show it in calendar. + * @default false + */ + loading: PropTypes.bool, + /** + * Locale for components texts. + * Allows overriding texts coming from `LocalizationProvider` and `theme`. + */ + localeText: PropTypes.object, + /** + * Maximal selectable date. + */ + maxDate: PropTypes.any, + /** + * Minimal selectable date. + */ + minDate: PropTypes.any, + /** + * Callback fired when the value is accepted. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The value that was just accepted. + */ + onAccept: PropTypes.func, + /** + * Callback fired when the value changes. + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TValue} value The new value. + * @param {FieldChangeHandlerContext} context The context containing the validation result of the current value. + */ + onChange: PropTypes.func, + /** + * Callback fired when the popup requests to be closed. + * Use in controlled mode (see `open`). + */ + onClose: PropTypes.func, + /** + * Callback fired when the error associated to the current value changes. + * If the error has a non-null value, then the `TextField` will be rendered in `error` state. + * + * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. + * @template TError The validation error type. Will be either `string` or a `null`. Can be in `[start, end]` format in case of range value. + * @param {TError} error The new error describing why the current value is not valid. + * @param {TValue} value The value associated to the error. + */ + onError: PropTypes.func, + /** + * Callback fired on month change. + * @template TDate + * @param {TDate} month The new month. + */ + onMonthChange: PropTypes.func, + /** + * Callback fired when the popup requests to be opened. + * Use in controlled mode (see `open`). + */ + onOpen: PropTypes.func, + /** + * Callback fired when the range position changes. + * @param {RangePosition} rangePosition The new range position. + */ + onRangePositionChange: PropTypes.func, + /** + * Callback fired when the selected sections change. + * @param {FieldSelectedSections} newValue The new selected sections. + */ + onSelectedSectionsChange: PropTypes.func, + /** + * Control the popup or dialog open state. + * @default false + */ + open: PropTypes.bool, + /** + * The position in the currently edited date range. + * Used when the component position is controlled. + */ + rangePosition: PropTypes.oneOf(['end', 'start']), + readOnly: PropTypes.bool, + /** + * If `true`, disable heavy animations. + * @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13 + */ + reduceAnimations: PropTypes.bool, + /** + * The date used to generate the new value when both `value` and `defaultValue` are empty. + * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. + */ + referenceDate: PropTypes.any, + /** + * Component displaying when passed `loading` true. + * @returns {React.ReactNode} The node to render when loading. + * @default () => "..." + */ + renderLoading: PropTypes.func, + /** + * The currently selected sections. + * This prop accept four formats: + * 1. If a number is provided, the section at this index will be selected. + * 2. If an object with a `startIndex` and `endIndex` properties are provided, the sections between those two indexes will be selected. + * 3. If a string of type `FieldSectionType` is provided, the first section with that name will be selected. + * 4. If `null` is provided, no section will be selected + * If not provided, the selected sections will be handled internally. + */ + selectedSections: PropTypes.oneOfType([ + PropTypes.oneOf([ + 'all', + 'day', + 'hours', + 'meridiem', + 'minutes', + 'month', + 'seconds', + 'weekDay', + 'year', + ]), + PropTypes.number, + PropTypes.shape({ + endIndex: PropTypes.number.isRequired, + startIndex: PropTypes.number.isRequired, + }), + ]), + /** + * Disable specific date. + * @template TDate + * @param {TDate} day The date to test. + * @param {string} position The date to test, 'start' or 'end'. + * @returns {boolean} Returns `true` if the date should be disabled. + */ + shouldDisableDate: PropTypes.func, + /** + * If `true`, days outside the current month are rendered: + * + * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. + * + * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. + * + * - ignored if `calendars` equals more than `1` on range pickers. + * @default false + */ + showDaysOutsideCurrentMonth: PropTypes.bool, + /** + * The props used for each component slot. + * @default {} + */ + slotProps: PropTypes.object, + /** + * Overridable component slots. + * @default {} + */ + slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Choose which timezone to use for the value. + * Example: "default", "system", "UTC", "America/New_York". + * If you pass values from other timezones to some props, they will be converted to this timezone before being used. + * @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documention} for more details. + * @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise. + */ + timezone: PropTypes.string, + /** + * The selected value. + * Used when the component is controlled. + */ + value: PropTypes.arrayOf(PropTypes.any), + /** + * Define custom view renderers for each section. + * If `null`, the section will only have field editing. + * If `undefined`, internally defined view will be the used. + */ + viewRenderers: PropTypes.shape({ + day: PropTypes.func, + }), +} as any; + +export { MobileTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts new file mode 100644 index 0000000000000..ff2f5da8d5759 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts @@ -0,0 +1,55 @@ +import { TimeView } from '@mui/x-date-pickers/models'; +import { + MakeOptional, + TimeViewWithMeridiem, + UncapitalizeObjectKeys, +} from '@mui/x-date-pickers/internals'; +import { + UseMobileRangePickerSlotsComponent, + ExportedUseMobileRangePickerSlotsComponentsProps, + MobileRangeOnlyPickerProps, +} from '../internals/hooks/useMobileRangePicker'; +import { + BaseTimeRangePickerProps, + BaseTimeRangePickerSlotsComponent, + BaseTimeRangePickerSlotsComponentsProps, +} from '../TimeRangePicker/shared'; + +export interface MobileTimeRangePickerSlotsComponent< + TDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends BaseTimeRangePickerSlotsComponent, + MakeOptional, 'Field'> {} + +export interface MobileTimeRangePickerSlotsComponentsProps< + TDate, + TView extends TimeViewWithMeridiem = TimeView, +> extends BaseTimeRangePickerSlotsComponentsProps, + ExportedUseMobileRangePickerSlotsComponentsProps {} + +export interface MobileTimeRangePickerProps + extends BaseTimeRangePickerProps, + MobileRangeOnlyPickerProps { + /** + * Overridable components. + * @default {} + * @deprecated Please use `slots`. + */ + components?: MobileTimeRangePickerSlotsComponent; + /** + * The props used for each component slot. + * @default {} + * @deprecated Please use `slotProps`. + */ + componentsProps?: MobileTimeRangePickerSlotsComponentsProps; + /** + * Overridable component slots. + * @default {} + */ + slots?: UncapitalizeObjectKeys>; + /** + * The props used for each component slot. + * @default {} + */ + slotProps?: MobileTimeRangePickerSlotsComponentsProps; +} diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts new file mode 100644 index 0000000000000..52965aebf4513 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/index.ts @@ -0,0 +1,6 @@ +export { MobileTimeRangePicker } from './MobileTimeRangePicker'; +export type { + MobileTimeRangePickerProps, + MobileTimeRangePickerSlotsComponent, + MobileTimeRangePickerSlotsComponentsProps, +} from './MobileTimeRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx new file mode 100644 index 0000000000000..4228c4d358356 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx @@ -0,0 +1,276 @@ +import * as React from 'react'; +import { spy } from 'sinon'; +import { expect } from 'chai'; +import { screen, userEvent, fireEvent } from '@mui/monorepo/test/utils'; +import { MobileDateRangePicker } from '@mui/x-date-pickers-pro/MobileDateRangePicker'; +import { createPickerRenderer, adapterToUse, openPicker } from 'test/utils/pickers'; +import { DateRange } from '@mui/x-date-pickers-pro'; + +describe('', () => { + const { render } = createPickerRenderer({ clock: 'fake' }); + + describe('picker state', () => { + it('should open when focusing the start input', () => { + const onOpen = spy(); + + render(); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + + expect(onOpen.callCount).to.equal(1); + expect(screen.queryByRole('dialog')).toBeVisible(); + }); + + it('should open when focusing the end input', () => { + const onOpen = spy(); + + render(); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + + expect(onOpen.callCount).to.equal(1); + expect(screen.queryByRole('dialog')).toBeVisible(); + }); + + it('should call onChange with updated start date then call onChange with updated end date when opening from start input', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + // Open the picker + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + expect(onChange.callCount).to.equal(0); + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Change the start date + userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + expect(onChange.callCount).to.equal(1); + expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); + expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); + + // Change the end date + userEvent.mousePress(screen.getByRole('gridcell', { name: '5' })); + expect(onChange.callCount).to.equal(2); + expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); + expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 5)); + + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + }); + + it('should call onChange with updated end date when opening from end input', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + // Open the picker + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + expect(onChange.callCount).to.equal(0); + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + + // Change the end date + userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + expect(onChange.callCount).to.equal(1); + expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); + expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(0); + }); + + it('should call onClose and onAccept when selecting the end date if props.closeOnSelect = true', () => { + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); + + // Change the end date + userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + + expect(onAccept.callCount).to.equal(1); + expect(onAccept.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); + expect(onAccept.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); + expect(onClose.callCount).to.equal(1); + }); + + it('should call onClose and onChange with the initial value when clicking "Cancel" button', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + + // Change the start date (already tested) + userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + + // Cancel the modifications + userEvent.mousePress(screen.getByText(/cancel/i)); + expect(onChange.callCount).to.equal(2); // Start date change + reset + expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); + expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(1); + }); + + it('should call onClose and onAccept with the live value and onAccept with the live value when clicking the "OK"', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + + // Change the start date (already tested) + userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); + + // Accept the modifications + userEvent.mousePress(screen.getByText(/ok/i)); + expect(onChange.callCount).to.equal(1); // Start date change + expect(onAccept.callCount).to.equal(1); + expect(onAccept.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); + expect(onAccept.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); + expect(onClose.callCount).to.equal(1); + }); + + it('should call onClose, onChange with empty value and onAccept with empty value when pressing the "Clear" button', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + const defaultValue: DateRange = [ + adapterToUse.date(new Date(2018, 0, 1)), + adapterToUse.date(new Date(2018, 0, 6)), + ]; + + render( + , + ); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + + // Clear the date + userEvent.mousePress(screen.getByText(/clear/i)); + expect(onChange.callCount).to.equal(1); // Start date change + expect(onChange.lastCall.args[0]).to.deep.equal([null, null]); + expect(onAccept.callCount).to.equal(1); + expect(onAccept.lastCall.args[0]).to.deep.equal([null, null]); + expect(onClose.callCount).to.equal(1); + }); + + it('should not call onChange or onAccept when pressing "Clear" button with an already null value', () => { + const onChange = spy(); + const onAccept = spy(); + const onClose = spy(); + + render( + , + ); + + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + + // Clear the date + userEvent.mousePress(screen.getByText(/clear/i)); + expect(onChange.callCount).to.equal(0); + expect(onAccept.callCount).to.equal(0); + expect(onClose.callCount).to.equal(1); + }); + + it('should correctly set focused styles when input is focused', () => { + render(); + + const firstInput = screen.getAllByRole('textbox')[0]; + fireEvent.focus(firstInput); + + expect(screen.getByText('Start', { selector: 'label' })).to.have.class('Mui-focused'); + }); + + it('should render "readonly" input elements', () => { + render(); + + screen.getAllByRole('textbox').forEach((input) => { + expect(input).to.have.attribute('readonly'); + }); + }); + }); + + // TODO: Write test + // it('should call onClose and onAccept with the live value when clicking outside of the picker', () => { + // }) +}); diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx new file mode 100644 index 0000000000000..3b7a7bc5f36f4 --- /dev/null +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx @@ -0,0 +1,114 @@ +import * as React from 'react'; +import { + describeConformance, + screen, + userEvent, + fireDiscreteEvent, +} from '@mui/monorepo/test/utils'; +import { MobileDateRangePicker } from '@mui/x-date-pickers-pro/MobileDateRangePicker'; +import { describeRangeValidation } from '@mui/x-date-pickers-pro/tests/describeRangeValidation'; +import { describeValue } from '@mui/x-date-pickers/tests/describeValue'; +import { describePicker } from '@mui/x-date-pickers/tests/describePicker'; +import { + adapterToUse, + createPickerRenderer, + wrapPickerMount, + openPicker, + expectInputPlaceholder, + expectInputValue, +} from 'test/utils/pickers'; + +describe(' - Describes', () => { + const { render, clock } = createPickerRenderer({ + clock: 'fake', + clockConfig: new Date(2018, 0, 1, 0, 0, 0, 0), + }); + + describePicker(MobileDateRangePicker, { render, fieldType: 'multi-input', variant: 'mobile' }); + + describeRangeValidation(MobileDateRangePicker, () => ({ + render, + clock, + componentFamily: 'picker', + views: ['day'], + variant: 'mobile', + })); + + describeConformance(, () => ({ + classes: {} as any, + render, + muiName: 'MuiMobileDateRangePicker', + wrapMount: wrapPickerMount, + refInstanceof: window.HTMLDivElement, + skip: [ + 'componentProp', + 'componentsProp', + 'themeDefaultProps', + 'themeStyleOverrides', + 'themeVariants', + 'mergeClassName', + 'propsSpread', + 'rootClass', + 'reactTestRenderer', + ], + })); + + describeValue(MobileDateRangePicker, () => ({ + render, + componentFamily: 'picker', + type: 'date-range', + variant: 'mobile', + initialFocus: 'start', + clock, + values: [ + // initial start and end dates + [adapterToUse.date(new Date(2018, 0, 1)), adapterToUse.date(new Date(2018, 0, 4))], + // start and end dates after `setNewValue` + [adapterToUse.date(new Date(2018, 0, 2)), adapterToUse.date(new Date(2018, 0, 5))], + ], + emptyValue: [null, null], + assertRenderedValue: (expectedValues: any[]) => { + // `getAllByRole('textbox')` does not work here, because inputs are `readonly` + const textBoxes: HTMLInputElement[] = [ + screen.getByLabelText('Start'), + screen.getByLabelText('End'), + ]; + expectedValues.forEach((value, index) => { + const input = textBoxes[index]; + // TODO: Support single range input + if (!value) { + expectInputPlaceholder(input, 'MM/DD/YYYY'); + } + expectInputValue(input, value ? adapterToUse.format(value, 'keyboardDate') : ''); + }); + }, + setNewValue: (value, { isOpened, applySameValue, setEndDate = false }) => { + let newValue: any[]; + if (applySameValue) { + newValue = value; + } else if (setEndDate) { + newValue = [value[0], adapterToUse.addDays(value[1], 1)]; + } else { + newValue = [adapterToUse.addDays(value[0], 1), value[1]]; + } + + if (!isOpened) { + openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); + } + + userEvent.mousePress( + screen.getAllByRole('gridcell', { + name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), + })[0], + ); + + // Close the picker + if (!isOpened) { + fireDiscreteEvent.keyDown(document.activeElement!, { key: 'Escape' }); + clock.runToLast(); + } + + return newValue; + }, + })); +}); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 2ac049a9242e9..a98107f40616e 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -4,6 +4,7 @@ import useMediaQuery from '@mui/material/useMediaQuery'; import { useThemeProps } from '@mui/material/styles'; import { refType } from '@mui/utils'; import { DesktopTimeRangePicker } from '../DesktopTimeRangePicker'; +import { MobileTimeRangePicker } from '../MobileTimeRangePicker'; import { TimeRangePickerProps } from './TimeRangePicker.types'; type TimePickerComponent = (( @@ -25,7 +26,7 @@ const TimeRangePicker = React.forwardRef(function TimeRangePicker( return ; } - return
        TOTO
        ; + return ; }) as TimePickerComponent; TimeRangePicker.propTypes = { diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts index 3aa14d11aada9..e6d25b7417e95 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts @@ -1,17 +1,26 @@ -import { UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { TimeViewWithMeridiem, UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; import { DesktopTimeRangePickerProps, DesktopTimeRangePickerSlotsComponent, DesktopTimeRangePickerSlotsComponentsProps, } from '../DesktopTimeRangePicker'; +import { + MobileTimeRangePickerProps, + MobileTimeRangePickerSlotsComponent, + MobileTimeRangePickerSlotsComponentsProps, +} from '../MobileTimeRangePicker'; export interface TimeRangePickerSlotsComponents - extends DesktopTimeRangePickerSlotsComponent {} + extends DesktopTimeRangePickerSlotsComponent, + MobileTimeRangePickerSlotsComponent {} export interface TimeRangePickerSlotsComponentsProps - extends DesktopTimeRangePickerSlotsComponentsProps {} + extends DesktopTimeRangePickerSlotsComponentsProps, + MobileTimeRangePickerSlotsComponentsProps {} -export interface TimeRangePickerProps extends DesktopTimeRangePickerProps { +export interface TimeRangePickerProps + extends DesktopTimeRangePickerProps, + Omit, 'views'> { /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 4c788ddbb22c8..495ac3b6fe8e2 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -4,6 +4,7 @@ import clsx from 'clsx'; import Typography from '@mui/material/Typography'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import { TimeView } from '@mui/x-date-pickers/models'; import { PickersToolbar, PickersToolbarButton, @@ -12,6 +13,7 @@ import { useLocaleText, ExportedBaseToolbarProps, TimeViewWithMeridiem, + resolveTimeFormat, } from '@mui/x-date-pickers/internals'; import { DateRange } from '../internals/models'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; @@ -31,17 +33,16 @@ const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { }; export interface TimeRangePickerToolbarProps - extends Omit< - BaseToolbarProps, TimeViewWithMeridiem>, - 'views' | 'view' | 'onViewChange' | 'onChange' | 'isLandscape' - >, + extends BaseToolbarProps, TimeViewWithMeridiem>, Pick { + ampm: boolean; + ampmInClock: boolean; classes?: Partial; } export interface ExportedTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { - ampm?: boolean; - ampmInClock?: boolean; + ampm: boolean; + ampmInClock: boolean; } const TimeRangePickerToolbarRoot = styled(PickersToolbar, { @@ -72,18 +73,25 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< onRangePositionChange, toolbarFormat, className, + ampm, + ampmInClock, + views, ...other } = props; const localeText = useLocaleText(); - const startDateValue = start - ? utils.formatByString(start, toolbarFormat || utils.formats.shortDate) - : localeText.start; + const format = React.useMemo(() => { + if (toolbarFormat) { + return toolbarFormat; + } - const endDateValue = end - ? utils.formatByString(end, toolbarFormat || utils.formats.shortDate) - : localeText.end; + return resolveTimeFormat(utils, { format: undefined, ampm, views: views as TimeView[] }); + }, [toolbarFormat]); + + const startDateValue = start ? utils.formatByString(start, format) : localeText.start; + + const endDateValue = end ? utils.formatByString(end, format) : localeText.end; const ownerState = props; const classes = useUtilityClasses(ownerState); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index 2298b66e3f6f6..fc2f597d912e5 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -45,11 +45,6 @@ export interface BaseTimeRangePickerProps, ExportedBaseClockProps { - /** - * Display ampm controls under the clock (instead of in the toolbar). - * @default true on desktop, false on mobile - */ - ampmInClock?: boolean; /** * Overridable components. * @default {} @@ -150,7 +145,6 @@ export function useTimeRangePickerDefaultizedProps< ...slotProps, toolbar: { ampm, - ampmInClock: themeProps.ampmInClock, ...slotProps?.toolbar, }, }, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/index.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/index.ts index 0000263101ef9..7e31ae771060d 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/index.ts @@ -2,5 +2,6 @@ export { useMobileRangePicker } from './useMobileRangePicker'; export type { UseMobileRangePickerSlotsComponent, UseMobileRangePickerSlotsComponentsProps, + ExportedUseMobileRangePickerSlotsComponentsProps, MobileRangeOnlyPickerProps, } from './useMobileRangePicker.types'; diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts index 0d48aa056e5c2..f93b184f978df 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts @@ -30,12 +30,17 @@ export interface UseMobileRangePickerSlotsComponent extends PickersModalDialogSlotsComponentsProps, - ExportedPickersLayoutSlotsComponentsProps, TDate, TView>, - RangePickerFieldSlotsComponentsProps { +> extends ExportedUseMobileRangePickerSlotsComponentsProps { toolbar?: ExportedBaseToolbarProps; } +export interface ExportedUseMobileRangePickerSlotsComponentsProps< + TDate, + TView extends DateOrTimeViewWithMeridiem, +> extends PickersModalDialogSlotsComponentsProps, + ExportedPickersLayoutSlotsComponentsProps, TDate, TView>, + RangePickerFieldSlotsComponentsProps {} + export interface MobileRangeOnlyPickerProps extends BaseNonStaticPickerProps, UsePickerValueNonStaticProps, diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts index cdf2269467357..6d831e6ec11fd 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts @@ -1 +1,4 @@ -export { renderDigitalClockTimeRangeView } from './timeRangeViewRenderers'; +export { + renderDigitalClockTimeRangeView, + renderTimeRangeViewClock, +} from './timeRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index b335fab622b35..8dbb9f3679491 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -6,7 +6,7 @@ import { PickerSelectionState, } from '@mui/x-date-pickers/internals'; import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; -import Stack from '@mui/material/Stack'; +import { TimeClock, TimeClockProps } from '@mui/x-date-pickers/TimeClock'; import { TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; import { DateRange } from '../internals/models'; @@ -23,6 +23,99 @@ export type TimeRangeViewRendererProps< views: readonly TView[]; }; +export const renderTimeRangeViewClock = ({ + view, + onViewChange, + focusedView, + onFocusedViewChange, + views, + value, + referenceDate, + onChange, + className, + classes, + disableFuture, + disablePast, + minTime, + maxTime, + shouldDisableTime, + shouldDisableClock, + minutesStep, + ampm, + ampmInClock, + components, + componentsProps, + slots, + slotProps, + readOnly, + disabled, + sx, + autoFocus, + showViewSwitcher, + disableIgnoringDatePartForTimeValidation, + timezone, + rangePosition, + onRangePositionChange, +}: TimeRangeViewRendererProps< + TDate, + TimeView, + Omit, 'value' | 'onChange'> & + Pick, 'timeSteps'> & + UseRangePositionProps & { + value: DateRange; + onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; + } +>) => { + const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; + + const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + if (selectionState === 'finish' && rangePosition === 'start') { + onRangePositionChange?.('end'); + onViewChange?.(views[0]); + } + + onChange( + rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], + rangePosition === 'start' ? 'partial' : selectionState, + ); + }; + + return ( + + view={view} + onViewChange={onViewChange} + focusedView={focusedView && isTimeView(focusedView) ? focusedView : null} + onFocusedViewChange={onFocusedViewChange} + views={views.filter(isTimeView)} + value={valueForCurrentView} + referenceDate={referenceDate} + onChange={handleChange} + className={className} + classes={classes} + disableFuture={disableFuture} + disablePast={disablePast} + minTime={minTime} + maxTime={maxTime} + shouldDisableTime={shouldDisableTime} + shouldDisableClock={shouldDisableClock} + minutesStep={minutesStep} + ampm={ampm} + ampmInClock={ampmInClock} + components={components} + componentsProps={componentsProps} + slots={slots} + slotProps={slotProps} + readOnly={readOnly} + disabled={disabled} + sx={sx} + autoFocus={autoFocus} + showViewSwitcher={showViewSwitcher} + disableIgnoringDatePartForTimeValidation={disableIgnoringDatePartForTimeValidation} + timezone={timezone} + /> + ); +}; + export const renderDigitalClockTimeRangeView = ({ view, onViewChange, @@ -66,11 +159,12 @@ export const renderDigitalClockTimeRangeView = ({ onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; } >) => { - const viewValue = rangePosition === 'start' ? value[0] : value[1]; + const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { - if (rangePosition === 'start') { + if (selectionState === 'finish' && rangePosition === 'start') { onRangePositionChange?.('end'); + onViewChange?.(views[0]); } onChange( @@ -80,39 +174,37 @@ export const renderDigitalClockTimeRangeView = ({ }; return ( - - - view={view} - onViewChange={onViewChange} - focusedView={focusedView} - onFocusedViewChange={onFocusedViewChange} - views={views.filter(isTimeView)} - value={viewValue} - referenceDate={referenceDate} - onChange={handleChange} - className={className} - classes={classes} - disableFuture={disableFuture} - disablePast={disablePast} - minTime={minTime} - maxTime={maxTime} - shouldDisableTime={shouldDisableTime} - shouldDisableClock={shouldDisableClock} - minutesStep={minutesStep} - ampm={ampm} - components={components} - componentsProps={componentsProps} - slots={slots} - slotProps={slotProps} - readOnly={readOnly} - disabled={disabled} - sx={sx} - autoFocus={autoFocus} - disableIgnoringDatePartForTimeValidation={disableIgnoringDatePartForTimeValidation} - timeStep={timeSteps?.minutes} - skipDisabled={skipDisabled} - timezone={timezone} - /> - + + view={view} + onViewChange={onViewChange} + focusedView={focusedView} + onFocusedViewChange={onFocusedViewChange} + views={views.filter(isTimeView)} + value={valueForCurrentView} + referenceDate={referenceDate} + onChange={handleChange} + className={className} + classes={classes} + disableFuture={disableFuture} + disablePast={disablePast} + minTime={minTime} + maxTime={maxTime} + shouldDisableTime={shouldDisableTime} + shouldDisableClock={shouldDisableClock} + minutesStep={minutesStep} + ampm={ampm} + components={components} + componentsProps={componentsProps} + slots={slots} + slotProps={slotProps} + readOnly={readOnly} + disabled={disabled} + sx={sx} + autoFocus={autoFocus} + disableIgnoringDatePartForTimeValidation={disableIgnoringDatePartForTimeValidation} + timeStep={timeSteps?.minutes} + skipDisabled={skipDisabled} + timezone={timezone} + /> ); }; From 5a1ed1a91796ff20a69a3ccccfb0240dae42fa69 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 08:30:49 +0200 Subject: [PATCH 09/74] Work --- .../MobileTimeRangePicker/MobileTimeRangePicker.types.ts | 6 +++--- .../src/TimeRangePicker/TimeRangePicker.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts index ff2f5da8d5759..c959fedec34a1 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts @@ -35,7 +35,7 @@ export interface MobileTimeRangePickerProps; + components?: MobileTimeRangePickerSlotsComponent; /** * The props used for each component slot. * @default {} @@ -46,10 +46,10 @@ export interface MobileTimeRangePickerProps>; + slots?: UncapitalizeObjectKeys>; /** * The props used for each component slot. * @default {} */ - slotProps?: MobileTimeRangePickerSlotsComponentsProps; + slotProps?: MobileTimeRangePickerSlotsComponentsProps; } diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index a98107f40616e..06f4955efd5e2 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -4,7 +4,7 @@ import useMediaQuery from '@mui/material/useMediaQuery'; import { useThemeProps } from '@mui/material/styles'; import { refType } from '@mui/utils'; import { DesktopTimeRangePicker } from '../DesktopTimeRangePicker'; -import { MobileTimeRangePicker } from '../MobileTimeRangePicker'; +import { MobileTimeRangePicker, MobileTimeRangePickerProps } from '../MobileTimeRangePicker'; import { TimeRangePickerProps } from './TimeRangePicker.types'; type TimePickerComponent = (( @@ -26,7 +26,7 @@ const TimeRangePicker = React.forwardRef(function TimeRangePicker( return ; } - return ; + return )} />; }) as TimePickerComponent; TimeRangePicker.propTypes = { From fc45f35127d2ecac8e9dd2401f2a114eebd4aec9 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 08:34:08 +0200 Subject: [PATCH 10/74] Work --- .../date-pickers/desktop-time-range-picker.json | 1 - .../date-pickers/time-range-picker-toolbar.json | 12 ++++++++++++ .../x/api/date-pickers/time-range-picker.json | 1 - .../date-pickers/desktop-time-range-picker.json | 5 ----- .../date-pickers/time-range-picker-toolbar.json | 10 ++++++++++ .../api-docs/date-pickers/time-range-picker.json | 5 ----- .../DesktopTimeRangePicker.tsx | 5 ----- .../src/TimeRangePicker/TimeRangePicker.tsx | 5 ----- .../TimeRangePicker/TimeRangePickerToolbar.tsx | 16 ++++++++++++++++ 9 files changed, 38 insertions(+), 22 deletions(-) diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 4a6fcbc66b4ee..674fac4903368 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -1,7 +1,6 @@ { "props": { "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, - "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, "className": { "type": { "name": "string" } }, "closeOnSelect": { diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index 2b99d49fa32ae..2f512c3b92a6e 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -1,5 +1,17 @@ { "props": { + "onViewChange": { + "type": { "name": "func" }, + "required": true, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" + }, + "required": true + }, "className": { "type": { "name": "string" } }, "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, "toolbarFormat": { "type": { "name": "string" } }, diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index 7a7fd925f0022..8e7ce0990a785 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -1,7 +1,6 @@ { "props": { "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, - "ampmInClock": { "type": { "name": "bool" }, "default": "true on desktop, false on mobile" }, "autoFocus": { "type": { "name": "bool" } }, "className": { "type": { "name": "string" } }, "closeOnSelect": { diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json index 066560d8e8384..a5a22550defa9 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json @@ -6,11 +6,6 @@ "deprecated": "", "typeDescriptions": {} }, - "ampmInClock": { - "description": "Display ampm controls under the clock (instead of in the toolbar).", - "deprecated": "", - "typeDescriptions": {} - }, "autoFocus": { "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", "deprecated": "", diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json index c4215f3080afa..1c1c780fe217f 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar.json @@ -11,6 +11,11 @@ "deprecated": "", "typeDescriptions": {} }, + "onViewChange": { + "description": "Callback called when a toolbar is clicked", + "deprecated": "", + "typeDescriptions": { "view": "The view to open" } + }, "toolbarFormat": { "description": "Toolbar date format.", "deprecated": "", @@ -20,6 +25,11 @@ "description": "Toolbar value placeholder—it is displayed when the value is empty.", "deprecated": "", "typeDescriptions": {} + }, + "view": { + "description": "Currently visible picker view.", + "deprecated": "", + "typeDescriptions": {} } }, "classDescriptions": { diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json index 9ad23d18a94f3..01b0c9bb83ed6 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -6,11 +6,6 @@ "deprecated": "", "typeDescriptions": {} }, - "ampmInClock": { - "description": "Display ampm controls under the clock (instead of in the toolbar).", - "deprecated": "", - "typeDescriptions": {} - }, "autoFocus": { "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", "deprecated": "", diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 8112b6fd0f0e5..2d4824d1fe6e4 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -103,11 +103,6 @@ DesktopTimeRangePicker.propTypes = { * @default `utils.is12HourCycleInCurrentLocale()` */ ampm: PropTypes.bool, - /** - * Display ampm controls under the clock (instead of in the toolbar). - * @default true on desktop, false on mobile - */ - ampmInClock: PropTypes.bool, /** * If `true`, the main element is focused during the first mount. * This main element is: diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 06f4955efd5e2..3e5614461463d 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -39,11 +39,6 @@ TimeRangePicker.propTypes = { * @default `utils.is12HourCycleInCurrentLocale()` */ ampm: PropTypes.bool, - /** - * Display ampm controls under the clock (instead of in the toolbar). - * @default true on desktop, false on mobile - */ - ampmInClock: PropTypes.bool, /** * If `true`, the main element is focused during the first mount. * This main element is: diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 495ac3b6fe8e2..5db87e1b308f8 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -129,6 +129,8 @@ TimeRangePickerToolbar.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + ampm: PropTypes.bool.isRequired, + ampmInClock: PropTypes.bool.isRequired, classes: PropTypes.object, /** * className applied to the root component. @@ -140,7 +142,15 @@ TimeRangePickerToolbar.propTypes = { * @default `true` for Desktop, `false` for Mobile. */ hidden: PropTypes.bool, + isLandscape: PropTypes.bool.isRequired, + onChange: PropTypes.func.isRequired, onRangePositionChange: PropTypes.func.isRequired, + /** + * Callback called when a toolbar is clicked + * @template TView + * @param {TView} view The view to open + */ + onViewChange: PropTypes.func.isRequired, rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, readOnly: PropTypes.bool, titleId: PropTypes.string, @@ -154,6 +164,12 @@ TimeRangePickerToolbar.propTypes = { */ toolbarPlaceholder: PropTypes.node, value: PropTypes.arrayOf(PropTypes.any).isRequired, + /** + * Currently visible picker view. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired, + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired) + .isRequired, } as any; export { TimeRangePickerToolbar }; From 3496cdca6a06210842732104378f330c686ffc8c Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 08:42:33 +0200 Subject: [PATCH 11/74] Fix --- .../time-range-picker/ResponsiveTimeRangePickers.js | 1 + .../time-range-picker/ResponsiveTimeRangePickers.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js index 2f8d7c4b8b9a6..57de3648a80e9 100644 --- a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js @@ -7,6 +7,7 @@ import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; // import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; +// import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; export default function ResponsiveTimeRangePickers() { return ( diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx index c0a79ed2b2e72..57de3648a80e9 100644 --- a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx @@ -7,7 +7,7 @@ import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; // import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; -import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; +// import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; export default function ResponsiveTimeRangePickers() { return ( From 080de37a5636e7e9aae160e0a66849a36c4f138b Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 09:11:11 +0200 Subject: [PATCH 12/74] Fix --- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 5db87e1b308f8..c330af3e35984 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -87,7 +87,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< } return resolveTimeFormat(utils, { format: undefined, ampm, views: views as TimeView[] }); - }, [toolbarFormat]); + }, [utils, toolbarFormat, ampm, views]); const startDateValue = start ? utils.formatByString(start, format) : localeText.start; From 0dd8572468c73f3b4b46f73e821172e133887541 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 13:00:17 +0200 Subject: [PATCH 13/74] Work --- .../SingleInputTimeRangePicker.js | 16 ++++++++++++++++ .../SingleInputTimeRangePicker.tsx | 16 ++++++++++++++++ .../SingleInputTimeRangePicker.tsx.preview | 1 + .../time-range-picker/time-range-picker.md | 8 ++++---- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js create mode 100644 docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx create mode 100644 docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js new file mode 100644 index 0000000000000..aafc5fbc882b7 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.js @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; + +export default function SingleInputTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx new file mode 100644 index 0000000000000..aafc5fbc882b7 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; + +export default function SingleInputTimeRangePicker() { + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview new file mode 100644 index 0000000000000..26a29226e182d --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/SingleInputTimeRangePicker.tsx.preview @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 22a29df1be1e4..3a49d9fab2bf0 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -2,7 +2,7 @@ productId: x-date-pickers title: React Time Range Picker component components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, StaticTimeRangePicker -githubLabel: 'component: DateRangePicker' +githubLabel: 'component: TimeRangePicker' packageName: '@mui/x-date-pickers-pro' materialDesign: https://m2.material.io/components/date-pickers --- @@ -60,7 +60,7 @@ The component is available in four variants: {{"demo": "ResponsiveTimeRangePickers.js"}} -By default, the `DateRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. +By default, the `TimeRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. This can be customized with the `desktopModeMediaQuery` prop. :::warning @@ -82,9 +82,9 @@ The component can be disabled or read-only. NOT READY ::: -You can pass the `SingleInputTimeRangeField` component to the Date Range Picker to use it for keyboard editing: +You can pass the `SingleInputTimeRangeField` component to the Time Range Picker to use it for keyboard editing: -[//]: # '{{"demo": "SingleInputDateRangePicker.js"}}' +{{"demo": "SingleInputTimeRangePicker.js"}} :::info For more information, check out the [Custom field](/x/react-date-pickers/custom-field/#use-single-input-fields-on-range-pickers) page. From 09b31e1f755e6f231147842ccda65dd5e333f35a Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 13 Sep 2023 13:04:43 +0200 Subject: [PATCH 14/74] Work --- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index c330af3e35984..dfb82a5cc7493 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -59,6 +59,8 @@ const TimeRangePickerToolbarContainer = styled('div', { overridesResolver: (_, styles) => styles.container, })({ display: 'flex', + justifyContent: 'space-between', + width: '100%', }); const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< From 6a80d6d84d1bf1035e8f957676ed231c0346ef3e Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 14 Sep 2023 15:26:21 +0200 Subject: [PATCH 15/74] Code review: Lukas --- docs/data/date-pickers-component-api-pages.ts | 5 + .../time-range-picker/BasicTimeRangePicker.js | 2 +- .../BasicTimeRangePicker.tsx | 2 +- .../date-pickers/mobile-time-range-picker.js | 23 ++ .../mobile-time-range-picker.json | 244 +++++++++++++++ .../mobile-time-range-picker.json | 286 ++++++++++++++++++ .../DesktopTimeRangePicker.tsx | 22 +- .../MobileTimeRangePicker.tsx | 136 ++++----- .../src/TimeRangePicker/shared.tsx | 2 +- packages/x-date-pickers-pro/src/index.ts | 1 + .../src/timeRangeViewRenderers/index.ts | 1 + .../timeRangeViewRenderers.tsx | 120 ++++++-- scripts/x-date-pickers-pro.exports.json | 4 + 13 files changed, 739 insertions(+), 109 deletions(-) create mode 100644 docs/pages/x/api/date-pickers/mobile-time-range-picker.js create mode 100644 docs/pages/x/api/date-pickers/mobile-time-range-picker.json create mode 100644 docs/translations/api-docs/date-pickers/mobile-time-range-picker.json diff --git a/docs/data/date-pickers-component-api-pages.ts b/docs/data/date-pickers-component-api-pages.ts index 774be4a830e31..bf088f954abb7 100644 --- a/docs/data/date-pickers-component-api-pages.ts +++ b/docs/data/date-pickers-component-api-pages.ts @@ -45,6 +45,11 @@ export default [ }, { pathname: '/x/api/date-pickers/mobile-date-time-picker', title: 'MobileDateTimePicker' }, { pathname: '/x/api/date-pickers/mobile-time-picker', title: 'MobileTimePicker' }, + { + pathname: '/x/api/date-pickers/mobile-time-range-picker', + title: 'MobileTimeRangePicker', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/month-calendar', title: 'MonthCalendar' }, { pathname: '/x/api/date-pickers/multi-input-date-range-field', diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js index 1f911ef628352..af806f48e36e5 100644 --- a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js @@ -7,7 +7,7 @@ import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; export default function BasicTimeRangePicker() { return ( - + diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx index 1f911ef628352..af806f48e36e5 100644 --- a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx @@ -7,7 +7,7 @@ import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; export default function BasicTimeRangePicker() { return ( - + diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.js b/docs/pages/x/api/date-pickers/mobile-time-range-picker.js new file mode 100644 index 0000000000000..a55ff4ab132bb --- /dev/null +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './mobile-time-range-picker.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers', + false, + /\.\/mobile-time-range-picker(-[a-z]{2})?\.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json new file mode 100644 index 0000000000000..586c5b0716fb5 --- /dev/null +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -0,0 +1,244 @@ +{ + "props": { + "autoFocus": { "type": { "name": "bool" } }, + "calendars": { + "type": { "name": "enum", "description": "1
        | 2
        | 3" }, + "default": "2" + }, + "className": { "type": { "name": "string" } }, + "closeOnSelect": { + "type": { "name": "bool" }, + "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." + }, + "components": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slots." + }, + "componentsProps": { + "type": { "name": "object" }, + "default": "{}", + "deprecated": true, + "deprecationInfo": "Please use slotProps." + }, + "currentMonthCalendarPosition": { + "type": { "name": "enum", "description": "1
        | 2
        | 3" }, + "default": "1" + }, + "dayOfWeekFormatter": { + "type": { "name": "func" }, + "default": "(day) => day.charAt(0).toUpperCase()", + "signature": { + "type": "function(day: string) => string", + "describedArgs": ["day"], + "returned": "string" + } + }, + "defaultCalendarMonth": { "type": { "name": "any" } }, + "defaultRangePosition": { + "type": { "name": "enum", "description": "'end'
        | 'start'" }, + "default": "'start'" + }, + "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "disableAutoMonthSwitching": { "type": { "name": "bool" } }, + "disabled": { "type": { "name": "bool" } }, + "disableDragEditing": { "type": { "name": "bool" } }, + "disableFuture": { "type": { "name": "bool" } }, + "disableHighlightToday": { "type": { "name": "bool" } }, + "disableOpenPicker": { "type": { "name": "bool" } }, + "disablePast": { "type": { "name": "bool" } }, + "displayWeekNumber": { "type": { "name": "bool" } }, + "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, + "format": { "type": { "name": "string" } }, + "formatDensity": { + "type": { "name": "enum", "description": "'dense'
        | 'spacious'" }, + "default": "\"dense\"" + }, + "inputRef": { "type": { "name": "custom", "description": "ref" } }, + "label": { "type": { "name": "node" } }, + "loading": { "type": { "name": "bool" } }, + "localeText": { "type": { "name": "object" } }, + "maxDate": { "type": { "name": "any" } }, + "minDate": { "type": { "name": "any" } }, + "onAccept": { + "type": { "name": "func" }, + "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } + }, + "onChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(value: TValue, context: FieldChangeHandlerContext) => void", + "describedArgs": ["value", "context"] + } + }, + "onClose": { "type": { "name": "func" } }, + "onError": { + "type": { "name": "func" }, + "signature": { + "type": "function(error: TError, value: TValue) => void", + "describedArgs": ["error", "value"] + } + }, + "onMonthChange": { + "type": { "name": "func" }, + "signature": { "type": "function(month: TDate) => void", "describedArgs": ["month"] } + }, + "onOpen": { "type": { "name": "func" } }, + "onRangePositionChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(rangePosition: RangePosition) => void", + "describedArgs": ["rangePosition"] + } + }, + "onSelectedSectionsChange": { + "type": { "name": "func" }, + "signature": { + "type": "function(newValue: FieldSelectedSections) => void", + "describedArgs": ["newValue"] + } + }, + "open": { "type": { "name": "bool" } }, + "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, + "reduceAnimations": { + "type": { "name": "bool" }, + "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" + }, + "referenceDate": { + "type": { "name": "any" }, + "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." + }, + "renderLoading": { + "type": { "name": "func" }, + "default": "() => \"...\"", + "signature": { + "type": "function() => React.ReactNode", + "describedArgs": [], + "returned": "React.ReactNode" + } + }, + "selectedSections": { + "type": { + "name": "union", + "description": "'all'
        | 'day'
        | 'hours'
        | 'meridiem'
        | 'minutes'
        | 'month'
        | 'seconds'
        | 'weekDay'
        | 'year'
        | number
        | { endIndex: number, startIndex: number }" + } + }, + "shouldDisableDate": { + "type": { "name": "func" }, + "signature": { + "type": "function(day: TDate, position: string) => boolean", + "describedArgs": ["day", "position"], + "returned": "boolean" + } + }, + "showDaysOutsideCurrentMonth": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { "type": { "name": "object" }, "default": "{}" }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
        | object
        | bool>
        | func
        | object" + }, + "additionalInfo": { "sx": true } + }, + "timezone": { + "type": { "name": "string" }, + "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise." + }, + "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, + "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } + }, + "slots": [ + { + "class": null, + "name": "actionBar", + "description": "Custom component for the action bar, it is placed below the picker views.", + "default": "PickersActionBar" + }, + { + "class": null, + "name": "dialog", + "description": "Custom component for the dialog inside which the views are rendered on mobile.", + "default": "PickersModalDialogRoot" + }, + { "class": null, "name": "field", "description": "" }, + { + "class": null, + "name": "fieldRoot", + "description": "Element rendered at the root.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "fieldSeparator", + "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + }, + { + "class": null, + "name": "layout", + "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + }, + { + "class": null, + "name": "leftArrowIcon", + "description": "Icon displayed in the left view switch button.", + "default": "ArrowLeft" + }, + { + "class": null, + "name": "mobilePaper", + "description": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "default": "Paper from '@mui/material'." + }, + { + "class": null, + "name": "mobileTransition", + "description": "Custom component for the mobile dialog Transition.", + "default": "Fade from '@mui/material'." + }, + { + "class": null, + "name": "nextIconButton", + "description": "Button allowing to switch to the right view.", + "default": "IconButton" + }, + { + "class": null, + "name": "previousIconButton", + "description": "Button allowing to switch to the left view.", + "default": "IconButton" + }, + { + "class": null, + "name": "rightArrowIcon", + "description": "Icon displayed in the right view switch button.", + "default": "ArrowRight" + }, + { + "class": null, + "name": "shortcuts", + "description": "Custom component for the shortcuts.", + "default": "PickersShortcuts" + }, + { + "class": null, + "name": "textField", + "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "default": "TextField from '@mui/material'" + }, + { + "class": null, + "name": "toolbar", + "description": "Custom component for the toolbar rendered above the views.", + "default": "DateTimePickerToolbar" + } + ], + "name": "MobileTimeRangePicker", + "imports": [ + "import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker';", + "import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro';" + ], + "styles": { "classes": [], "globalClasses": {}, "name": "MuiMobileTimeRangePicker" }, + "filename": "/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx", + "demos": "" +} diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json new file mode 100644 index 0000000000000..55ba8011a8c9f --- /dev/null +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -0,0 +1,286 @@ +{ + "componentDescription": "", + "propDescriptions": { + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "deprecated": "", + "typeDescriptions": {} + }, + "calendars": { + "description": "The number of calendars to render on desktop.", + "deprecated": "", + "typeDescriptions": {} + }, + "className": { + "description": "Class name applied to the root element.", + "deprecated": "", + "typeDescriptions": {} + }, + "closeOnSelect": { + "description": "If true, the popover or modal will close after submitting the full date.", + "deprecated": "", + "typeDescriptions": {} + }, + "components": { + "description": "Overridable components.", + "deprecated": "", + "typeDescriptions": {} + }, + "componentsProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "currentMonthCalendarPosition": { + "description": "Position the current month is rendered in.", + "deprecated": "", + "typeDescriptions": {} + }, + "dayOfWeekFormatter": { + "description": "Formats the day of week displayed in the calendar header.", + "deprecated": "", + "typeDescriptions": { + "day": "The day of week provided by the adapter's method getWeekdays.", + "string": "The name to display." + } + }, + "defaultCalendarMonth": { + "description": "Default calendar month displayed when value={[null, null]}.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultRangePosition": { + "description": "The initial position in the edited date range. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "defaultValue": { + "description": "The default value. Used when the component is not controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableAutoMonthSwitching": { + "description": "If true, after selecting start date calendar will not automatically switch to the month of end date.", + "deprecated": "", + "typeDescriptions": {} + }, + "disabled": { + "description": "If true, the picker and text field are disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableDragEditing": { + "description": "If true, editing dates by dragging is disabled.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableFuture": { + "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableHighlightToday": { + "description": "If true, today's date is rendering without highlighting with circle.", + "deprecated": "", + "typeDescriptions": {} + }, + "disableOpenPicker": { + "description": "If true, the open picker button will not be rendered (renders only the field).", + "deprecated": "", + "typeDescriptions": {} + }, + "disablePast": { + "description": "If true, disable values before the current date for date components, time for time components and both for date time components.", + "deprecated": "", + "typeDescriptions": {} + }, + "displayWeekNumber": { + "description": "If true, the week number will be display in the calendar.", + "deprecated": "", + "typeDescriptions": {} + }, + "fixedWeekNumber": { + "description": "Calendar will show more weeks in order to match this value. Put it to 6 for having fix number of week in Gregorian calendars", + "deprecated": "", + "typeDescriptions": {} + }, + "format": { + "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", + "deprecated": "", + "typeDescriptions": {} + }, + "formatDensity": { + "description": "Density of the format when rendered in the input. Setting formatDensity to "spacious" will add a space before and after each /, - and . character.", + "deprecated": "", + "typeDescriptions": {} + }, + "inputRef": { + "description": "Pass a ref to the input element. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "label": { + "description": "The label content. Ignored if the field has several inputs.", + "deprecated": "", + "typeDescriptions": {} + }, + "loading": { + "description": "If true, calls renderLoading instead of rendering the day calendar. Can be used to preload information and show it in calendar.", + "deprecated": "", + "typeDescriptions": {} + }, + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "deprecated": "", + "typeDescriptions": {} + }, + "maxDate": { + "description": "Maximal selectable date.", + "deprecated": "", + "typeDescriptions": {} + }, + "minDate": { + "description": "Minimal selectable date.", + "deprecated": "", + "typeDescriptions": {} + }, + "onAccept": { + "description": "Callback fired when the value is accepted.", + "deprecated": "", + "typeDescriptions": { "value": "The value that was just accepted." } + }, + "onChange": { + "description": "Callback fired when the value changes.", + "deprecated": "", + "typeDescriptions": { + "value": "The new value.", + "context": "The context containing the validation result of the current value." + } + }, + "onClose": { + "description": "Callback fired when the popup requests to be closed. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onError": { + "description": "Callback fired when the error associated to the current value changes. If the error has a non-null value, then the TextField will be rendered in error state.", + "deprecated": "", + "typeDescriptions": { + "error": "The new error describing why the current value is not valid.", + "value": "The value associated to the error." + } + }, + "onMonthChange": { + "description": "Callback fired on month change.", + "deprecated": "", + "typeDescriptions": { "month": "The new month." } + }, + "onOpen": { + "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", + "deprecated": "", + "typeDescriptions": {} + }, + "onRangePositionChange": { + "description": "Callback fired when the range position changes.", + "deprecated": "", + "typeDescriptions": { "rangePosition": "The new range position." } + }, + "onSelectedSectionsChange": { + "description": "Callback fired when the selected sections change.", + "deprecated": "", + "typeDescriptions": { "newValue": "The new selected sections." } + }, + "open": { + "description": "Control the popup or dialog open state.", + "deprecated": "", + "typeDescriptions": {} + }, + "rangePosition": { + "description": "The position in the currently edited date range. Used when the component position is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "reduceAnimations": { + "description": "If true, disable heavy animations.", + "deprecated": "", + "typeDescriptions": {} + }, + "referenceDate": { + "description": "The date used to generate the new value when both value and defaultValue are empty.", + "deprecated": "", + "typeDescriptions": {} + }, + "renderLoading": { + "description": "Component displaying when passed loading true.", + "deprecated": "", + "typeDescriptions": { "React.ReactNode": "The node to render when loading." } + }, + "selectedSections": { + "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", + "deprecated": "", + "typeDescriptions": {} + }, + "shouldDisableDate": { + "description": "Disable specific date.", + "deprecated": "", + "typeDescriptions": { + "day": "The date to test.", + "position": "The date to test, 'start' or 'end'.", + "boolean": "Returns true if the date should be disabled." + } + }, + "showDaysOutsideCurrentMonth": { + "description": "If true, days outside the current month are rendered:
        - if fixedWeekNumber is defined, renders days to have the weeks requested.
        - if fixedWeekNumber is not defined, renders day to fill the first and last week of the current month.
        - ignored if calendars equals more than 1 on range pickers.", + "deprecated": "", + "typeDescriptions": {} + }, + "slotProps": { + "description": "The props used for each component slot.", + "deprecated": "", + "typeDescriptions": {} + }, + "slots": { + "description": "Overridable component slots.", + "deprecated": "", + "typeDescriptions": {} + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles.", + "deprecated": "", + "typeDescriptions": {} + }, + "timezone": { + "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
        See the timezones documention for more details.", + "deprecated": "", + "typeDescriptions": {} + }, + "value": { + "description": "The selected value. Used when the component is controlled.", + "deprecated": "", + "typeDescriptions": {} + }, + "viewRenderers": { + "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", + "deprecated": "", + "typeDescriptions": {} + } + }, + "classDescriptions": {}, + "slotDescriptions": { + "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", + "field": "", + "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", + "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "leftArrowIcon": "Icon displayed in the left view switch button.", + "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", + "mobileTransition": "Custom component for the mobile dialog Transition.", + "nextIconButton": "Button allowing to switch to the right view.", + "previousIconButton": "Button allowing to switch to the left view.", + "rightArrowIcon": "Icon displayed in the right view switch button.", + "shortcuts": "Custom component for the shortcuts.", + "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "toolbar": "Custom component for the toolbar rendered above the views." + } +} diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 2d4824d1fe6e4..674905813b7cb 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -8,7 +8,6 @@ import { useUtils, resolveTimeFormat, } from '@mui/x-date-pickers/internals'; -import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/timeViewRenderers'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; @@ -16,7 +15,10 @@ import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; import { DateRange } from '../internals/models'; -import { renderDigitalClockTimeRangeView } from '../timeRangeViewRenderers'; +import { + renderDigitalClockTimeRangeView, + renderMultiSectionDigitalClockTimeRangeView, +} from '../timeRangeViewRenderers'; type DesktopTimeRangePickerComponent = (( props: DesktopTimeRangePickerProps & React.RefAttributes, @@ -35,14 +37,15 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< DesktopTimeRangePickerProps >(inProps, 'MuiDesktopTimeRangePicker'); - // const thresholdToRenderTimeInASingleColumn = - // defaultizedProps.thresholdToRenderTimeInASingleColumn ?? 24; - // const timeSteps = { hours: 1, minutes: 5, seconds: 5, ...defaultizedProps.timeSteps }; - const shouldRenderTimeInASingleColumn = true; // (24 * 60) / (timeSteps.hours * timeSteps.minutes) <= thresholdToRenderTimeInASingleColumn; + const thresholdToRenderTimeInASingleColumn = + defaultizedProps.thresholdToRenderTimeInASingleColumn ?? 24; + const timeSteps = { hours: 1, minutes: 5, seconds: 5, ...defaultizedProps.timeSteps }; + const shouldRenderTimeInASingleColumn = + (24 * 60) / (timeSteps.hours * timeSteps.minutes) <= thresholdToRenderTimeInASingleColumn; const renderTimeView = shouldRenderTimeInASingleColumn ? renderDigitalClockTimeRangeView - : renderMultiSectionDigitalClockTimeView; + : renderMultiSectionDigitalClockTimeRangeView; const viewRenderers: PickerViewRendererLookup, TimeViewWithMeridiem, any, {}> = { hours: renderTimeView, @@ -53,7 +56,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }; const shouldHoursRendererContainMeridiemView = - viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeView.name; + viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeRangeView.name; const views: readonly TimeViewWithMeridiem[] = defaultizedProps.ampm && shouldHoursRendererContainMeridiemView ? [...defaultizedProps.views, 'meridiem'] @@ -61,6 +64,8 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< const props = { ...defaultizedProps, + ampmInClock: true, + timeSteps, viewRenderers, format: resolveTimeFormat(utils, defaultizedProps), views: shouldRenderTimeInASingleColumn ? ['hours' as TimeViewWithMeridiem] : views, @@ -77,6 +82,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }), toolbar: { hidden: true, + ampmInClock: true, ...defaultizedProps.slotProps?.toolbar, }, }, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 06836afbe875a..fac507b0c4cc3 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -81,6 +81,11 @@ MobileTimeRangePicker.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * 12h/24h view for hour selection clock. + * @default `utils.is12HourCycleInCurrentLocale()` + */ + ampm: PropTypes.bool, /** * If `true`, the main element is focused during the first mount. * This main element is: @@ -88,11 +93,6 @@ MobileTimeRangePicker.propTypes = { * - the `input` element if there is a field rendered. */ autoFocus: PropTypes.bool, - /** - * The number of calendars to render on **desktop**. - * @default 2 - */ - calendars: PropTypes.oneOf([1, 2, 3]), /** * Class name applied to the root element. */ @@ -114,22 +114,6 @@ MobileTimeRangePicker.propTypes = { * @deprecated Please use `slotProps`. */ componentsProps: PropTypes.object, - /** - * Position the current month is rendered in. - * @default 1 - */ - currentMonthCalendarPosition: PropTypes.oneOf([1, 2, 3]), - /** - * Formats the day of week displayed in the calendar header. - * @param {string} day The day of week provided by the adapter's method `getWeekdays`. - * @returns {string} The name to display. - * @default (day) => day.charAt(0).toUpperCase() - */ - dayOfWeekFormatter: PropTypes.func, - /** - * Default calendar month displayed when `value={[null, null]}`. - */ - defaultCalendarMonth: PropTypes.any, /** * The initial position in the edited date range. * Used when the component is not controlled. @@ -141,31 +125,21 @@ MobileTimeRangePicker.propTypes = { * Used when the component is not controlled. */ defaultValue: PropTypes.arrayOf(PropTypes.any), - /** - * If `true`, after selecting `start` date calendar will not automatically switch to the month of `end` date. - * @default false - */ - disableAutoMonthSwitching: PropTypes.bool, /** * If `true`, the picker and text field are disabled. * @default false */ disabled: PropTypes.bool, - /** - * If `true`, editing dates by dragging is disabled. - * @default false - */ - disableDragEditing: PropTypes.bool, /** * If `true`, disable values after the current date for date components, time for time components and both for date time components. * @default false */ disableFuture: PropTypes.bool, /** - * If `true`, today's date is rendering without highlighting with circle. + * Do not ignore date part when validating min/max time. * @default false */ - disableHighlightToday: PropTypes.bool, + disableIgnoringDatePartForTimeValidation: PropTypes.bool, /** * If `true`, the open picker button will not be rendered (renders only the field). * @default false @@ -176,16 +150,6 @@ MobileTimeRangePicker.propTypes = { * @default false */ disablePast: PropTypes.bool, - /** - * If `true`, the week number will be display in the calendar. - */ - displayWeekNumber: PropTypes.bool, - /** - * Calendar will show more weeks in order to match this value. - * Put it to 6 for having fix number of week in Gregorian calendars - * @default undefined - */ - fixedWeekNumber: PropTypes.number, /** * Format of the date when rendered in the input(s). * Defaults to localized format based on the used `views`. @@ -207,25 +171,26 @@ MobileTimeRangePicker.propTypes = { * Ignored if the field has several inputs. */ label: PropTypes.node, - /** - * If `true`, calls `renderLoading` instead of rendering the day calendar. - * Can be used to preload information and show it in calendar. - * @default false - */ - loading: PropTypes.bool, /** * Locale for components texts. * Allows overriding texts coming from `LocalizationProvider` and `theme`. */ localeText: PropTypes.object, /** - * Maximal selectable date. + * Maximal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. + */ + maxTime: PropTypes.any, + /** + * Minimal selectable time. + * The date part of the object will be ignored unless `props.disableIgnoringDatePartForTimeValidation === true`. */ - maxDate: PropTypes.any, + minTime: PropTypes.any, /** - * Minimal selectable date. + * Step over minutes. + * @default 1 */ - minDate: PropTypes.any, + minutesStep: PropTypes.number, /** * Callback fired when the value is accepted. * @template TValue The value type. Will be either the same type as `value` or `null`. Can be in `[start, end]` format in case of range value. @@ -255,12 +220,6 @@ MobileTimeRangePicker.propTypes = { * @param {TValue} value The value associated to the error. */ onError: PropTypes.func, - /** - * Callback fired on month change. - * @template TDate - * @param {TDate} month The new month. - */ - onMonthChange: PropTypes.func, /** * Callback fired when the popup requests to be opened. * Use in controlled mode (see `open`). @@ -276,11 +235,23 @@ MobileTimeRangePicker.propTypes = { * @param {FieldSelectedSections} newValue The new selected sections. */ onSelectedSectionsChange: PropTypes.func, + /** + * Callback fired on view change. + * @template TView + * @param {TView} view The new view. + */ + onViewChange: PropTypes.func, /** * Control the popup or dialog open state. * @default false */ open: PropTypes.bool, + /** + * The default visible view. + * Used when the component view is not controlled. + * Must be a valid option from `views` list. + */ + openTo: PropTypes.oneOf(['hours', 'minutes', 'seconds']), /** * The position in the currently edited date range. * Used when the component position is controlled. @@ -297,12 +268,6 @@ MobileTimeRangePicker.propTypes = { * @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`. */ referenceDate: PropTypes.any, - /** - * Component displaying when passed `loading` true. - * @returns {React.ReactNode} The node to render when loading. - * @default () => "..." - */ - renderLoading: PropTypes.func, /** * The currently selected sections. * This prop accept four formats: @@ -331,24 +296,21 @@ MobileTimeRangePicker.propTypes = { }), ]), /** - * Disable specific date. - * @template TDate - * @param {TDate} day The date to test. - * @param {string} position The date to test, 'start' or 'end'. - * @returns {boolean} Returns `true` if the date should be disabled. + * Disable specific clock time. + * @param {number} clockValue The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. + * @deprecated Consider using `shouldDisableTime`. */ - shouldDisableDate: PropTypes.func, + shouldDisableClock: PropTypes.func, /** - * If `true`, days outside the current month are rendered: - * - * - if `fixedWeekNumber` is defined, renders days to have the weeks requested. - * - * - if `fixedWeekNumber` is not defined, renders day to fill the first and last week of the current month. - * - * - ignored if `calendars` equals more than `1` on range pickers. - * @default false + * Disable specific time. + * @template TDate + * @param {TDate} value The value to check. + * @param {TimeView} view The clock type of the timeValue. + * @returns {boolean} If `true` the time will be disabled. */ - showDaysOutsideCurrentMonth: PropTypes.bool, + shouldDisableTime: PropTypes.func, /** * The props used for each component slot. * @default {} @@ -380,14 +342,26 @@ MobileTimeRangePicker.propTypes = { * Used when the component is controlled. */ value: PropTypes.arrayOf(PropTypes.any), + /** + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. + */ + view: PropTypes.oneOf(['hours', 'minutes', 'seconds']), /** * Define custom view renderers for each section. * If `null`, the section will only have field editing. * If `undefined`, internally defined view will be the used. */ viewRenderers: PropTypes.shape({ - day: PropTypes.func, + hours: PropTypes.func, + minutes: PropTypes.func, + seconds: PropTypes.func, }), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired), } as any; export { MobileTimeRangePicker }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index fc2f597d912e5..a710b11dc61fa 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -118,7 +118,7 @@ export function useTimeRangePickerDefaultizedProps< return { ...themeProps.localeText, - dateRangePickerToolbarTitle: themeProps.localeText.toolbarTitle, + timeRangePickerToolbarTitle: themeProps.localeText.toolbarTitle, }; }, [themeProps.localeText]); diff --git a/packages/x-date-pickers-pro/src/index.ts b/packages/x-date-pickers-pro/src/index.ts index cc54ea1cfc274..9b80661f41add 100644 --- a/packages/x-date-pickers-pro/src/index.ts +++ b/packages/x-date-pickers-pro/src/index.ts @@ -26,6 +26,7 @@ export * from './MobileDateRangePicker'; export * from './StaticDateRangePicker'; export * from './TimeRangePicker'; export * from './DesktopTimeRangePicker'; +export * from './MobileTimeRangePicker'; // View renderers export * from './dateRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts index 6d831e6ec11fd..189ea75fb1808 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts @@ -1,4 +1,5 @@ export { renderDigitalClockTimeRangeView, + renderMultiSectionDigitalClockTimeRangeView, renderTimeRangeViewClock, } from './timeRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 8dbb9f3679491..7b15c4a4e58fe 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -6,6 +6,10 @@ import { PickerSelectionState, } from '@mui/x-date-pickers/internals'; import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; +import { + MultiSectionDigitalClock, + MultiSectionDigitalClockProps, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; import { TimeClock, TimeClockProps } from '@mui/x-date-pickers/TimeClock'; import { TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; @@ -16,12 +20,14 @@ export type TimeRangeViewRendererProps< TDate, TView extends TimeViewWithMeridiem, TComponentProps extends Omit, 'value' | 'onChange'>, -> = Omit & { - value: DateRange; - view: TView; - onViewChange?: (view: TView) => void; - views: readonly TView[]; -}; +> = Omit & + UseRangePositionProps & { + value: DateRange; + onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; + view: TView; + onViewChange?: (view: TView) => void; + views: readonly TView[]; + }; export const renderTimeRangeViewClock = ({ view, @@ -59,12 +65,7 @@ export const renderTimeRangeViewClock = ({ }: TimeRangeViewRendererProps< TDate, TimeView, - Omit, 'value' | 'onChange'> & - Pick, 'timeSteps'> & - UseRangePositionProps & { - value: DateRange; - onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; - } + Omit, 'value' | 'onChange'> & Pick, 'timeSteps'> >) => { const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; @@ -153,11 +154,7 @@ export const renderDigitalClockTimeRangeView = ({ TDate, Extract, Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & - Pick, 'timeSteps'> & - UseRangePositionProps & { - value: DateRange; - onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; - } + Pick, 'timeSteps'> >) => { const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; @@ -208,3 +205,92 @@ export const renderDigitalClockTimeRangeView = ({ /> ); }; + +export const renderMultiSectionDigitalClockTimeRangeView = ({ + view, + onViewChange, + focusedView, + onFocusedViewChange, + views, + value, + referenceDate, + onChange, + className, + classes, + disableFuture, + disablePast, + minTime, + maxTime, + shouldDisableTime, + shouldDisableClock, + minutesStep, + ampm, + components, + componentsProps, + slots, + slotProps, + readOnly, + disabled, + sx, + autoFocus, + disableIgnoringDatePartForTimeValidation, + timeSteps, + skipDisabled, + timezone, + rangePosition, + onRangePositionChange, +}: TimeRangeViewRendererProps< + TDate, + TimeViewWithMeridiem, + Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & + Pick, 'timeSteps'> +>) => { + const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; + + const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + if (selectionState === 'finish' && rangePosition === 'start') { + onRangePositionChange?.('end'); + onViewChange?.(views[0]); + } + + onChange( + rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], + rangePosition === 'start' ? 'partial' : selectionState, + ); + }; + + return ( + + view={view} + onViewChange={onViewChange} + focusedView={focusedView} + onFocusedViewChange={onFocusedViewChange} + views={views.filter(isTimeView)} + value={valueForCurrentView} + referenceDate={referenceDate} + onChange={handleChange} + className={className} + classes={classes} + disableFuture={disableFuture} + disablePast={disablePast} + minTime={minTime} + maxTime={maxTime} + shouldDisableTime={shouldDisableTime} + shouldDisableClock={shouldDisableClock} + minutesStep={minutesStep} + ampm={ampm} + components={components} + componentsProps={componentsProps} + slots={slots} + slotProps={slotProps} + readOnly={readOnly} + disabled={disabled} + sx={sx} + autoFocus={autoFocus} + disableIgnoringDatePartForTimeValidation={disableIgnoringDatePartForTimeValidation} + timeSteps={timeSteps} + skipDisabled={skipDisabled} + timezone={timezone} + /> + ); +}; diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index f335a69ad19cb..d99ab54bcbee4 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -191,6 +191,10 @@ { "name": "MobileTimePickerProps", "kind": "Interface" }, { "name": "MobileTimePickerSlotsComponent", "kind": "Interface" }, { "name": "MobileTimePickerSlotsComponentsProps", "kind": "Interface" }, + { "name": "MobileTimeRangePicker", "kind": "Variable" }, + { "name": "MobileTimeRangePickerProps", "kind": "Interface" }, + { "name": "MobileTimeRangePickerSlotsComponent", "kind": "Interface" }, + { "name": "MobileTimeRangePickerSlotsComponentsProps", "kind": "Interface" }, { "name": "MonthCalendar", "kind": "Variable" }, { "name": "monthCalendarClasses", "kind": "Variable" }, { "name": "MonthCalendarClasses", "kind": "Interface" }, From f0566abaf8695700a2e8b71730d45a0007f212ac Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 14 Sep 2023 15:41:12 +0200 Subject: [PATCH 16/74] Fix --- .../mobile-time-range-picker.json | 87 +++++++------ .../mobile-time-range-picker.json | 114 +++++++----------- 2 files changed, 86 insertions(+), 115 deletions(-) diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index 586c5b0716fb5..8d39549c50337 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -1,10 +1,7 @@ { "props": { + "ampm": { "type": { "name": "bool" }, "default": "`utils.is12HourCycleInCurrentLocale()`" }, "autoFocus": { "type": { "name": "bool" } }, - "calendars": { - "type": { "name": "enum", "description": "1
        | 2
        | 3" }, - "default": "2" - }, "className": { "type": { "name": "string" } }, "closeOnSelect": { "type": { "name": "bool" }, @@ -22,34 +19,16 @@ "deprecated": true, "deprecationInfo": "Please use slotProps." }, - "currentMonthCalendarPosition": { - "type": { "name": "enum", "description": "1
        | 2
        | 3" }, - "default": "1" - }, - "dayOfWeekFormatter": { - "type": { "name": "func" }, - "default": "(day) => day.charAt(0).toUpperCase()", - "signature": { - "type": "function(day: string) => string", - "describedArgs": ["day"], - "returned": "string" - } - }, - "defaultCalendarMonth": { "type": { "name": "any" } }, "defaultRangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" }, "default": "'start'" }, "defaultValue": { "type": { "name": "arrayOf", "description": "Array<any>" } }, - "disableAutoMonthSwitching": { "type": { "name": "bool" } }, "disabled": { "type": { "name": "bool" } }, - "disableDragEditing": { "type": { "name": "bool" } }, "disableFuture": { "type": { "name": "bool" } }, - "disableHighlightToday": { "type": { "name": "bool" } }, + "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" } }, "disableOpenPicker": { "type": { "name": "bool" } }, "disablePast": { "type": { "name": "bool" } }, - "displayWeekNumber": { "type": { "name": "bool" } }, - "fixedWeekNumber": { "type": { "name": "number" }, "default": "undefined" }, "format": { "type": { "name": "string" } }, "formatDensity": { "type": { "name": "enum", "description": "'dense'
        | 'spacious'" }, @@ -57,10 +36,10 @@ }, "inputRef": { "type": { "name": "custom", "description": "ref" } }, "label": { "type": { "name": "node" } }, - "loading": { "type": { "name": "bool" } }, "localeText": { "type": { "name": "object" } }, - "maxDate": { "type": { "name": "any" } }, - "minDate": { "type": { "name": "any" } }, + "maxTime": { "type": { "name": "any" } }, + "minTime": { "type": { "name": "any" } }, + "minutesStep": { "type": { "name": "number" }, "default": "1" }, "onAccept": { "type": { "name": "func" }, "signature": { "type": "function(value: TValue) => void", "describedArgs": ["value"] } @@ -80,10 +59,6 @@ "describedArgs": ["error", "value"] } }, - "onMonthChange": { - "type": { "name": "func" }, - "signature": { "type": "function(month: TDate) => void", "describedArgs": ["month"] } - }, "onOpen": { "type": { "name": "func" } }, "onRangePositionChange": { "type": { "name": "func" }, @@ -99,7 +74,17 @@ "describedArgs": ["newValue"] } }, + "onViewChange": { + "type": { "name": "func" }, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, "open": { "type": { "name": "bool" } }, + "openTo": { + "type": { + "name": "enum", + "description": "'hours'
        | 'minutes'
        | 'seconds'" + } + }, "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, "reduceAnimations": { "type": { "name": "bool" }, @@ -109,30 +94,30 @@ "type": { "name": "any" }, "default": "The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`." }, - "renderLoading": { - "type": { "name": "func" }, - "default": "() => \"...\"", - "signature": { - "type": "function() => React.ReactNode", - "describedArgs": [], - "returned": "React.ReactNode" - } - }, "selectedSections": { "type": { "name": "union", "description": "'all'
        | 'day'
        | 'hours'
        | 'meridiem'
        | 'minutes'
        | 'month'
        | 'seconds'
        | 'weekDay'
        | 'year'
        | number
        | { endIndex: number, startIndex: number }" } }, - "shouldDisableDate": { + "shouldDisableClock": { + "type": { "name": "func" }, + "deprecated": true, + "deprecationInfo": "Consider using shouldDisableTime.", + "signature": { + "type": "function(clockValue: number, view: TimeView) => boolean", + "describedArgs": ["clockValue", "view"], + "returned": "boolean" + } + }, + "shouldDisableTime": { "type": { "name": "func" }, "signature": { - "type": "function(day: TDate, position: string) => boolean", - "describedArgs": ["day", "position"], + "type": "function(value: TDate, view: TimeView) => boolean", + "describedArgs": ["value", "view"], "returned": "boolean" } }, - "showDaysOutsideCurrentMonth": { "type": { "name": "bool" } }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { "type": { "name": "object" }, "default": "{}" }, "sx": { @@ -147,7 +132,21 @@ "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise." }, "value": { "type": { "name": "arrayOf", "description": "Array<any>" } }, - "viewRenderers": { "type": { "name": "shape", "description": "{ day?: func }" } } + "view": { + "type": { + "name": "enum", + "description": "'hours'
        | 'minutes'
        | 'seconds'" + } + }, + "viewRenderers": { + "type": { "name": "shape", "description": "{ hours?: func, minutes?: func, seconds?: func }" } + }, + "views": { + "type": { + "name": "arrayOf", + "description": "Array<'hours'
        | 'minutes'
        | 'seconds'>" + } + } }, "slots": [ { diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json index 55ba8011a8c9f..4286c5a25c8bd 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -1,13 +1,13 @@ { "componentDescription": "", "propDescriptions": { - "autoFocus": { - "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", + "ampm": { + "description": "12h/24h view for hour selection clock.", "deprecated": "", "typeDescriptions": {} }, - "calendars": { - "description": "The number of calendars to render on desktop.", + "autoFocus": { + "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered.", "deprecated": "", "typeDescriptions": {} }, @@ -31,24 +31,6 @@ "deprecated": "", "typeDescriptions": {} }, - "currentMonthCalendarPosition": { - "description": "Position the current month is rendered in.", - "deprecated": "", - "typeDescriptions": {} - }, - "dayOfWeekFormatter": { - "description": "Formats the day of week displayed in the calendar header.", - "deprecated": "", - "typeDescriptions": { - "day": "The day of week provided by the adapter's method getWeekdays.", - "string": "The name to display." - } - }, - "defaultCalendarMonth": { - "description": "Default calendar month displayed when value={[null, null]}.", - "deprecated": "", - "typeDescriptions": {} - }, "defaultRangePosition": { "description": "The initial position in the edited date range. Used when the component is not controlled.", "deprecated": "", @@ -59,28 +41,18 @@ "deprecated": "", "typeDescriptions": {} }, - "disableAutoMonthSwitching": { - "description": "If true, after selecting start date calendar will not automatically switch to the month of end date.", - "deprecated": "", - "typeDescriptions": {} - }, "disabled": { "description": "If true, the picker and text field are disabled.", "deprecated": "", "typeDescriptions": {} }, - "disableDragEditing": { - "description": "If true, editing dates by dragging is disabled.", - "deprecated": "", - "typeDescriptions": {} - }, "disableFuture": { "description": "If true, disable values after the current date for date components, time for time components and both for date time components.", "deprecated": "", "typeDescriptions": {} }, - "disableHighlightToday": { - "description": "If true, today's date is rendering without highlighting with circle.", + "disableIgnoringDatePartForTimeValidation": { + "description": "Do not ignore date part when validating min/max time.", "deprecated": "", "typeDescriptions": {} }, @@ -94,16 +66,6 @@ "deprecated": "", "typeDescriptions": {} }, - "displayWeekNumber": { - "description": "If true, the week number will be display in the calendar.", - "deprecated": "", - "typeDescriptions": {} - }, - "fixedWeekNumber": { - "description": "Calendar will show more weeks in order to match this value. Put it to 6 for having fix number of week in Gregorian calendars", - "deprecated": "", - "typeDescriptions": {} - }, "format": { "description": "Format of the date when rendered in the input(s). Defaults to localized format based on the used views.", "deprecated": "", @@ -124,23 +86,23 @@ "deprecated": "", "typeDescriptions": {} }, - "loading": { - "description": "If true, calls renderLoading instead of rendering the day calendar. Can be used to preload information and show it in calendar.", + "localeText": { + "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", "deprecated": "", "typeDescriptions": {} }, - "localeText": { - "description": "Locale for components texts. Allows overriding texts coming from LocalizationProvider and theme.", + "maxTime": { + "description": "Maximal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", "deprecated": "", "typeDescriptions": {} }, - "maxDate": { - "description": "Maximal selectable date.", + "minTime": { + "description": "Minimal selectable time. The date part of the object will be ignored unless props.disableIgnoringDatePartForTimeValidation === true.", "deprecated": "", "typeDescriptions": {} }, - "minDate": { - "description": "Minimal selectable date.", + "minutesStep": { + "description": "Step over minutes.", "deprecated": "", "typeDescriptions": {} }, @@ -170,11 +132,6 @@ "value": "The value associated to the error." } }, - "onMonthChange": { - "description": "Callback fired on month change.", - "deprecated": "", - "typeDescriptions": { "month": "The new month." } - }, "onOpen": { "description": "Callback fired when the popup requests to be opened. Use in controlled mode (see open).", "deprecated": "", @@ -190,11 +147,21 @@ "deprecated": "", "typeDescriptions": { "newValue": "The new selected sections." } }, + "onViewChange": { + "description": "Callback fired on view change.", + "deprecated": "", + "typeDescriptions": { "view": "The new view." } + }, "open": { "description": "Control the popup or dialog open state.", "deprecated": "", "typeDescriptions": {} }, + "openTo": { + "description": "The default visible view. Used when the component view is not controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, "rangePosition": { "description": "The position in the currently edited date range. Used when the component position is controlled.", "deprecated": "", @@ -210,29 +177,28 @@ "deprecated": "", "typeDescriptions": {} }, - "renderLoading": { - "description": "Component displaying when passed loading true.", - "deprecated": "", - "typeDescriptions": { "React.ReactNode": "The node to render when loading." } - }, "selectedSections": { "description": "The currently selected sections. This prop accept four formats: 1. If a number is provided, the section at this index will be selected. 2. If an object with a startIndex and endIndex properties are provided, the sections between those two indexes will be selected. 3. If a string of type FieldSectionType is provided, the first section with that name will be selected. 4. If null is provided, no section will be selected If not provided, the selected sections will be handled internally.", "deprecated": "", "typeDescriptions": {} }, - "shouldDisableDate": { - "description": "Disable specific date.", + "shouldDisableClock": { + "description": "Disable specific clock time.", "deprecated": "", "typeDescriptions": { - "day": "The date to test.", - "position": "The date to test, 'start' or 'end'.", - "boolean": "Returns true if the date should be disabled." + "clockValue": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." } }, - "showDaysOutsideCurrentMonth": { - "description": "If true, days outside the current month are rendered:
        - if fixedWeekNumber is defined, renders days to have the weeks requested.
        - if fixedWeekNumber is not defined, renders day to fill the first and last week of the current month.
        - ignored if calendars equals more than 1 on range pickers.", + "shouldDisableTime": { + "description": "Disable specific time.", "deprecated": "", - "typeDescriptions": {} + "typeDescriptions": { + "value": "The value to check.", + "view": "The clock type of the timeValue.", + "boolean": "If true the time will be disabled." + } }, "slotProps": { "description": "The props used for each component slot.", @@ -259,11 +225,17 @@ "deprecated": "", "typeDescriptions": {} }, + "view": { + "description": "The visible view. Used when the component view is controlled. Must be a valid option from views list.", + "deprecated": "", + "typeDescriptions": {} + }, "viewRenderers": { "description": "Define custom view renderers for each section. If null, the section will only have field editing. If undefined, internally defined view will be the used.", "deprecated": "", "typeDescriptions": {} - } + }, + "views": { "description": "Available views.", "deprecated": "", "typeDescriptions": {} } }, "classDescriptions": {}, "slotDescriptions": { From 0b8d736bf9c52a10b1624be85f3612adbff33e78 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 26 Sep 2023 15:31:31 +0200 Subject: [PATCH 17/74] Fix --- .../x/api/date-pickers/desktop-time-range-picker.json | 8 ++++---- .../x/api/date-pickers/mobile-time-range-picker.json | 8 ++++---- docs/pages/x/api/date-pickers/time-range-picker.json | 8 ++++---- .../api-docs/date-pickers/desktop-time-range-picker.json | 8 ++++---- .../api-docs/date-pickers/mobile-time-range-picker.json | 8 ++++---- .../api-docs/date-pickers/time-range-picker.json | 8 ++++---- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 5 +++++ 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 674fac4903368..0ebf3b6eba182 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -191,17 +191,17 @@ { "class": null, "name": "fieldRoot", - "description": "Element rendered at the root.\nIgnored if the field has only one input." + "description": "Element rendered at the root. Ignored if the field has only one input." }, { "class": null, "name": "fieldSeparator", - "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + "description": "Element rendered between the two inputs. Ignored if the field has only one input." }, { "class": null, "name": "layout", - "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + "description": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts." }, { "class": null, @@ -242,7 +242,7 @@ { "class": null, "name": "textField", - "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "description": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "default": "TextField from '@mui/material'" }, { diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index 8d39549c50337..673ae2431fb09 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -165,17 +165,17 @@ { "class": null, "name": "fieldRoot", - "description": "Element rendered at the root.\nIgnored if the field has only one input." + "description": "Element rendered at the root. Ignored if the field has only one input." }, { "class": null, "name": "fieldSeparator", - "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + "description": "Element rendered between the two inputs. Ignored if the field has only one input." }, { "class": null, "name": "layout", - "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + "description": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts." }, { "class": null, @@ -222,7 +222,7 @@ { "class": null, "name": "textField", - "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "description": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "default": "TextField from '@mui/material'" }, { diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index 8e7ce0990a785..f6f8d2abc6d47 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -199,17 +199,17 @@ { "class": null, "name": "fieldRoot", - "description": "Element rendered at the root.\nIgnored if the field has only one input." + "description": "Element rendered at the root. Ignored if the field has only one input." }, { "class": null, "name": "fieldSeparator", - "description": "Element rendered between the two inputs.\nIgnored if the field has only one input." + "description": "Element rendered between the two inputs. Ignored if the field has only one input." }, { "class": null, "name": "layout", - "description": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts." + "description": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts." }, { "class": null, @@ -262,7 +262,7 @@ { "class": null, "name": "textField", - "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "description": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "default": "TextField from '@mui/material'" }, { diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json index a5a22550defa9..ac6ee6ae819cf 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json @@ -259,16 +259,16 @@ "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", "field": "", - "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", - "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", - "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", "nextIconButton": "Button allowing to switch to the right view.", "popper": "Custom component for the popper inside which the views are rendered on desktop.", "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", - "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "toolbar": "Custom component for the toolbar rendered above the views." } } diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json index 4286c5a25c8bd..96af2eb025fed 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -242,9 +242,9 @@ "actionBar": "Custom component for the action bar, it is placed below the picker views.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "", - "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", - "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", - "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", @@ -252,7 +252,7 @@ "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", - "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "toolbar": "Custom component for the toolbar rendered above the views." } } diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json index 01b0c9bb83ed6..2fcca8ffc39bc 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -265,9 +265,9 @@ "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "", - "fieldRoot": "Element rendered at the root.\nIgnored if the field has only one input.", - "fieldSeparator": "Element rendered between the two inputs.\nIgnored if the field has only one input.", - "layout": "Custom component for wrapping the layout.\nIt wraps the toolbar, views, action bar, and shortcuts.", + "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", + "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", + "layout": "Custom component for wrapping the layout. It wraps the toolbar, views, action bar, and shortcuts.", "leftArrowIcon": "Icon displayed in the left view switch button.", "mobilePaper": "Custom component for the paper rendered inside the mobile picker's Dialog.", "mobileTransition": "Custom component for the mobile dialog Transition.", @@ -276,7 +276,7 @@ "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", - "textField": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.\nReceives the same props as @mui/material/TextField.", + "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element. Receives the same props as @mui/material/TextField.", "toolbar": "Custom component for the toolbar rendered above the views." } } diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index dfb82a5cc7493..e838d1f622599 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -155,6 +155,11 @@ TimeRangePickerToolbar.propTypes = { onViewChange: PropTypes.func.isRequired, rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, readOnly: PropTypes.bool, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), titleId: PropTypes.string, /** * Toolbar date format. From 0fdf3f0713be24039c970b63c50c65484a2bc79c Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 28 Sep 2023 09:16:15 +0200 Subject: [PATCH 18/74] Work --- .../ResponsiveTimeRangePickers.tsx | 21 ++++--------------- .../DesktopTimeRangePicker.tsx | 10 ++++----- .../MobileTimeRangePicker.tsx | 21 +++++++++++++++---- .../SingleInputDateTimeRangeField.types.ts | 3 +-- .../SingleInputTimeRangeField.types.ts | 3 +-- .../TimeRangePickerToolbar.tsx | 4 +++- .../src/TimeRangePicker/shared.tsx | 13 ++++++++++++ .../dateRangeViewRenderers.tsx | 2 +- .../useDesktopRangePicker.tsx | 2 +- .../useDesktopRangePicker.types.ts | 2 +- .../hooks/useEnrichedRangePickerFieldProps.ts | 2 +- .../useMobileRangePicker.tsx | 2 +- .../useMobileRangePicker.types.ts | 2 +- .../useStaticRangePicker.tsx | 8 +++++-- .../useStaticRangePicker.types.ts | 2 +- .../timeRangeViewRenderers.tsx | 1 + .../MultiSectionDigitalClock.tsx | 2 ++ .../MultiSectionDigitalClock.types.ts | 4 ++++ .../MultiSectionDigitalClockSection.tsx | 14 +++++++++---- .../src/PickersLayout/PickersLayout.tsx | 2 +- .../x-date-pickers/src/internals/index.ts | 6 +++++- packages/x-date-pickers/src/locales/enUS.ts | 4 ++++ .../src/locales/utils/pickersLocaleTextApi.ts | 4 ++++ 23 files changed, 88 insertions(+), 46 deletions(-) diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx index 57de3648a80e9..39019af1b4763 100644 --- a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx @@ -6,8 +6,6 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; -// import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; -// import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; export default function ResponsiveTimeRangePickers() { return ( @@ -16,35 +14,24 @@ export default function ResponsiveTimeRangePickers() { components={[ 'TimeRangePicker', 'MobileTimeRangePicker', - 'DesktopDateRangePicker', - 'StaticTimeRangePicker', + 'DesktopTimeRangePicker', ]} > - + - + - + - {/* */} - {/* */} - {/* */} ); diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 674905813b7cb..535e5407ee5c9 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -43,15 +43,15 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< const shouldRenderTimeInASingleColumn = (24 * 60) / (timeSteps.hours * timeSteps.minutes) <= thresholdToRenderTimeInASingleColumn; - const renderTimeView = shouldRenderTimeInASingleColumn + const renderTimeRangeView = shouldRenderTimeInASingleColumn ? renderDigitalClockTimeRangeView : renderMultiSectionDigitalClockTimeRangeView; const viewRenderers: PickerViewRendererLookup, TimeViewWithMeridiem, any, {}> = { - hours: renderTimeView, - minutes: renderTimeView, - seconds: renderTimeView, - meridiem: renderTimeView, + hours: renderTimeRangeView, + minutes: renderTimeRangeView, + seconds: renderTimeRangeView, + meridiem: renderTimeRangeView, ...defaultizedProps.viewRenderers, }; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index fac507b0c4cc3..592a22a7626e3 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -12,7 +12,10 @@ import { refType } from '@mui/utils'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; -import { renderTimeRangeViewClock } from '../timeRangeViewRenderers'; +import { + renderDigitalClockTimeRangeView, + renderMultiSectionDigitalClockTimeRangeView, +} from '../timeRangeViewRenderers'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; @@ -35,10 +38,20 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker >(inProps, 'MuiMobileTimeRangePicker'); + const thresholdToRenderTimeInASingleColumn = + defaultizedProps.thresholdToRenderTimeInASingleColumn ?? 24; + const timeSteps = { hours: 1, minutes: 5, seconds: 5, ...defaultizedProps.timeSteps }; + const shouldRenderTimeInASingleColumn = + (24 * 60) / (timeSteps.hours * timeSteps.minutes) <= thresholdToRenderTimeInASingleColumn; + + const renderTimeRangeView = shouldRenderTimeInASingleColumn + ? renderDigitalClockTimeRangeView + : renderMultiSectionDigitalClockTimeRangeView; + const viewRenderers: PickerViewRendererLookup, TimeView, any, {}> = { - hours: renderTimeRangeViewClock, - minutes: renderTimeRangeViewClock, - seconds: renderTimeRangeViewClock, + hours: renderTimeRangeView, + minutes: renderTimeRangeView, + seconds: renderTimeRangeView, ...defaultizedProps.viewRenderers, }; diff --git a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts index 0b72006f6fe93..baafdb73282c2 100644 --- a/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputDateTimeRangeField/SingleInputDateTimeRangeField.types.ts @@ -1,8 +1,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; -import { FieldsTextFieldProps } from '@mui/x-date-pickers/internals/models/fields'; -import { UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { UncapitalizeObjectKeys, FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; import { UseDateTimeRangeFieldDefaultizedProps, UseDateTimeRangeFieldProps, diff --git a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts index 6ce1602f23a32..05583a97584f7 100644 --- a/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts +++ b/packages/x-date-pickers-pro/src/SingleInputTimeRangeField/SingleInputTimeRangeField.types.ts @@ -1,8 +1,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/base/utils'; import TextField from '@mui/material/TextField'; -import { FieldsTextFieldProps } from '@mui/x-date-pickers/internals/models/fields'; -import { UncapitalizeObjectKeys } from '@mui/x-date-pickers/internals'; +import { UncapitalizeObjectKeys, FieldsTextFieldProps } from '@mui/x-date-pickers/internals'; import { UseTimeRangeFieldDefaultizedProps, UseTimeRangeFieldProps } from '../internals/models'; export interface UseSingleInputTimeRangeFieldParams { diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index e838d1f622599..247baa999f199 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -51,7 +51,9 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { overridesResolver: (_, styles) => styles.root, })<{ ownerState: TimeRangePickerToolbarProps; -}>({}); +}>(({ theme }) => ({ + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, +})); const TimeRangePickerToolbarContainer = styled('div', { name: 'MuiTimeRangePickerToolbar', diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index a710b11dc61fa..b9874687e8f99 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -26,6 +26,7 @@ import { } from './TimeRangePickerToolbar'; import { TimeRangeValidationError } from '../models'; import { DateRange } from '../internals/models'; +import { TimeStepOptions } from '@mui/x-date-pickers'; export interface BaseTimeRangePickerSlotsComponent extends TimeClockSlotsComponent { /** @@ -80,6 +81,18 @@ export interface BaseTimeRangePickerProps >; + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn?: number; + /** + * The time steps between two time unit options. + * For example, if `timeStep.minutes = 8`, then the available minute options will be `[0, 8, 16, 24, 32, 40, 48, 56]`. + * When single column time renderer is used, only `timeStep.minutes` will be used. + * @default{ hours: 1, minutes: 5, seconds: 5 } + */ + timeSteps?: TimeStepOptions; } type UseTimeRangePickerDefaultizedProps< diff --git a/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx index 8722b3cf2fdce..5f31852b1ba97 100644 --- a/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/dateRangeViewRenderers/dateRangeViewRenderers.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; +import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { DateRangeCalendar, DateRangeCalendarProps } from '../DateRangeCalendar'; export interface DateRangeViewRendererProps diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index eb5b1f22594df..65f7bb870aef7 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -14,8 +14,8 @@ import { InferError, ExportedBaseToolbarProps, BaseFieldProps, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; import { DesktopRangePickerAdditionalViewProps, UseDesktopRangePickerParams, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts index 63121346fa622..9eb2823ae84ee 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts @@ -9,8 +9,8 @@ import { BaseNonStaticPickerProps, UsePickerValueNonStaticProps, UsePickerViewsNonStaticProps, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; import { ExportedPickersLayoutSlotsComponent, ExportedPickersLayoutSlotsComponentsProps, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index 5478125b47379..fd10ec9b61140 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -6,7 +6,7 @@ import { resolveComponentProps, SlotComponentProps } from '@mui/base/utils'; import useEventCallback from '@mui/utils/useEventCallback'; import useForkRef from '@mui/utils/useForkRef'; import { BaseSingleInputFieldProps, FieldSelectedSections } from '@mui/x-date-pickers/models'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; +import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { PickersInputLocaleText } from '@mui/x-date-pickers/locales'; import { BaseFieldProps, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx index 59231d7011a9b..b0a7f6d7c3966 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.tsx @@ -12,9 +12,9 @@ import { InferError, ExportedBaseToolbarProps, useLocaleText, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; import useId from '@mui/utils/useId'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; import { MobileRangePickerAdditionalViewProps, UseMobileRangePickerParams, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts index f93b184f978df..212fdade3664c 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useMobileRangePicker/useMobileRangePicker.types.ts @@ -9,12 +9,12 @@ import { BaseNonStaticPickerProps, UsePickerValueNonStaticProps, UsePickerViewsNonStaticProps, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; import { ExportedPickersLayoutSlotsComponent, ExportedPickersLayoutSlotsComponentsProps, } from '@mui/x-date-pickers/PickersLayout'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; import { DateRange, RangeFieldSection, BaseRangeNonStaticPickerProps } from '../../models'; import { UseRangePositionProps, UseRangePositionResponse } from '../useRangePosition'; import { diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx index a1a97ab8aa6fe..ca4ed3f77a27a 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.tsx @@ -6,8 +6,12 @@ import { PickersLayout, PickersLayoutSlotsComponentsProps, } from '@mui/x-date-pickers/PickersLayout'; -import { usePicker, DIALOG_WIDTH, ExportedBaseToolbarProps } from '@mui/x-date-pickers/internals'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; +import { + usePicker, + DIALOG_WIDTH, + ExportedBaseToolbarProps, + DateOrTimeViewWithMeridiem, +} from '@mui/x-date-pickers/internals'; import { UseStaticRangePickerParams, UseStaticRangePickerProps, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts index c68398447ffda..15b874c7169e5 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useStaticRangePicker/useStaticRangePicker.types.ts @@ -5,12 +5,12 @@ import { ExportedBaseToolbarProps, StaticOnlyPickerProps, UncapitalizeObjectKeys, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; import { ExportedPickersLayoutSlotsComponent, ExportedPickersLayoutSlotsComponentsProps, } from '@mui/x-date-pickers/PickersLayout'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals/models'; import { DateRange } from '../../models/range'; import { UseRangePositionProps } from '../useRangePosition'; import { RangeFieldSection } from '../../models/fields'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 7b15c4a4e58fe..145f224384828 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -290,6 +290,7 @@ export const renderMultiSectionDigitalClockTimeRangeView = ); diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx index 0917ad29c1b08..c930f114f4ba7 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx @@ -88,6 +88,7 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi disabled, readOnly, skipDisabled = false, + fitWidth = false, timezone: timezoneProp, ...other } = props; @@ -405,6 +406,7 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi slots={slots ?? components} slotProps={slotProps ?? componentsProps} skipDisabled={skipDisabled} + fitWidth={fitWidth} aria-label={localeText.selectViewText(timeView as TimeViewWithMeridiem)} /> ))} diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts index bc51ef50d49f7..d0fd79ecbfea2 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts @@ -66,4 +66,8 @@ export interface MultiSectionDigitalClockProps * @default {} */ slotProps?: MultiSectionDigitalClockSlotsComponentsProps; + /** + * If `true`, the component will take all the width of its parent. + */ + fitWidth?: boolean; } diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx index c0dfd8b959c6a..f7db521dce695 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx @@ -36,6 +36,7 @@ export interface MultiSectionDigitalClockSectionProps onChange: (value: TValue) => void; active?: boolean; skipDisabled?: boolean; + fitWidth?: boolean; role?: string; } @@ -56,9 +57,10 @@ const MultiSectionDigitalClockSectionRoot = styled(MenuList, { })<{ ownerState: MultiSectionDigitalClockSectionProps & { alreadyRendered: boolean } }>( ({ theme, ownerState }) => ({ maxHeight: DIGITAL_CLOCK_VIEW_HEIGHT, - width: 56, + ...(ownerState.fitWidth + ? { flex: '1 1 100%', overflow: 'auto' } + : { width: 56, overflow: 'hidden' }), padding: 0, - overflow: 'hidden', '@media (prefers-reduced-motion: no-preference)': { scrollBehavior: ownerState.alreadyRendered ? 'smooth' : 'auto', }, @@ -81,10 +83,12 @@ const MultiSectionDigitalClockSectionItem = styled(MenuItem, { name: 'MuiMultiSectionDigitalClockSection', slot: 'Item', overridesResolver: (_, styles) => styles.item, -})(({ theme }) => ({ +})<{ ownerState: MultiSectionDigitalClockSectionProps }>(({ theme, ownerState }) => ({ padding: 8, margin: '2px 4px', - width: MULTI_SECTION_CLOCK_SECTION_WIDTH, + ...(ownerState.fitWidth + ? { width: 'calc(100% - 8px)' } + : { width: MULTI_SECTION_CLOCK_SECTION_WIDTH }), justifyContent: 'center', '&:first-of-type': { marginTop: 4, @@ -140,6 +144,7 @@ export const MultiSectionDigitalClockSection = React.forwardRef( slots, slotProps, skipDisabled, + fitWidth, ...other } = props; @@ -201,6 +206,7 @@ export const MultiSectionDigitalClockSection = React.forwardRef( aria-disabled={readOnly} aria-label={option.ariaLabel} aria-selected={isSelected} + ownerState={ownerState} {...slotProps?.digitalClockSectionItem} > {option.label} diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index d27bf3fde8730..c5658cbc42eb5 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -64,7 +64,7 @@ export const PickersLayoutContentWrapper = styled('div', { slot: 'ContentWrapper', overridesResolver: (props, styles) => styles.contentWrapper, })({ - gridColumn: 2, + gridColumn: '2 / 4', gridRow: 2, display: 'flex', flexDirection: 'column', diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 31b5d31c105f0..a90dd03b0ba24 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -111,7 +111,11 @@ export type { } from './models/props/clock'; export type { BaseToolbarProps, ExportedBaseToolbarProps } from './models/props/toolbar'; export type { DefaultizedProps, MakeOptional } from './models/helpers'; -export type { WrapperVariant, TimeViewWithMeridiem } from './models/common'; +export type { + WrapperVariant, + TimeViewWithMeridiem, + DateOrTimeViewWithMeridiem, +} from './models/common'; export type { BaseDateValidationProps, BaseTimeValidationProps, diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 7ddacd161a69e..22b9c8f0fbca9 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -20,6 +20,10 @@ const enUSPickers: PickersLocaleText = { start: 'Start', end: 'End', + // Generic range placeholders + from: 'From', + to: 'To', + // Action bar cancelButtonLabel: 'Cancel', clearButtonLabel: 'Clear', diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index a2bb36884011f..d91469e3ec7e5 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -49,6 +49,10 @@ export interface PickersComponentAgnosticLocaleText { start: string; end: string; + // Generic range placeholders + from: string; + to: string; + // Action bar cancelButtonLabel: string; clearButtonLabel: string; From c7e17d001f9806f213150669ce09b4cc7c9c3ce2 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 28 Sep 2023 09:17:10 +0200 Subject: [PATCH 19/74] Work --- .../MobileTimeRangePicker.tsx | 16 ++++++++++++++++ .../MultiSectionDigitalClock.tsx | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 592a22a7626e3..0b5ad1055582c 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -342,6 +342,22 @@ MobileTimeRangePicker.propTypes = { PropTypes.func, PropTypes.object, ]), + /** + * Amount of time options below or at which the single column time renderer is used. + * @default 24 + */ + thresholdToRenderTimeInASingleColumn: PropTypes.number, + /** + * The time steps between two time unit options. + * For example, if `timeStep.minutes = 8`, then the available minute options will be `[0, 8, 16, 24, 32, 40, 48, 56]`. + * When single column time renderer is used, only `timeStep.minutes` will be used. + * @default{ hours: 1, minutes: 5, seconds: 5 } + */ + timeSteps: PropTypes.shape({ + hours: PropTypes.number, + minutes: PropTypes.number, + seconds: PropTypes.number, + }), /** * Choose which timezone to use for the value. * Example: "default", "system", "UTC", "America/New_York". diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx index c930f114f4ba7..3cb961a98cf0d 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx @@ -473,6 +473,10 @@ MultiSectionDigitalClock.propTypes = { * @default false */ disablePast: PropTypes.bool, + /** + * If `true`, the component will take all the width of its parent. + */ + fitWidth: PropTypes.bool, /** * Controlled focused view. */ From 89bf6297715b83e354b97303fd5daebf56be5642 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 28 Sep 2023 09:20:56 +0200 Subject: [PATCH 20/74] Work --- .../time-range-picker/time-range-picker.md | 4 +--- .../x/api/date-pickers/mobile-time-range-picker.json | 8 ++++++++ .../api/date-pickers/multi-section-digital-clock.json | 1 + .../date-pickers/mobile-time-range-picker.json | 10 ++++++++++ .../date-pickers/multi-section-digital-clock.json | 5 +++++ .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 5 ++--- .../x-date-pickers-pro/src/TimeRangePicker/shared.tsx | 2 +- 7 files changed, 28 insertions(+), 7 deletions(-) diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 3a49d9fab2bf0..0d4356cb40452 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -1,7 +1,7 @@ --- productId: x-date-pickers title: React Time Range Picker component -components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, StaticTimeRangePicker +components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker githubLabel: 'component: TimeRangePicker' packageName: '@mui/x-date-pickers-pro' materialDesign: https://m2.material.io/components/date-pickers @@ -56,8 +56,6 @@ The component is available in four variants: - The `TimeRangePicker` component which renders `DesktopTimeRangePicker` or `MobileTimeRangePicker` depending on the device it runs on. -- The `StaticTimeRangePicker` component which renders without the popover/modal and field. - {{"demo": "ResponsiveTimeRangePickers.js"}} By default, the `TimeRangePicker` component renders the desktop version if the media query [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) matches. diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index 673ae2431fb09..d160bfc5ffcc2 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -127,6 +127,14 @@ }, "additionalInfo": { "sx": true } }, + "thresholdToRenderTimeInASingleColumn": { "type": { "name": "number" }, "default": "24" }, + "timeSteps": { + "type": { + "name": "shape", + "description": "{ hours?: number, minutes?: number, seconds?: number }" + }, + "default": "{ hours: 1, minutes: 5, seconds: 5 }" + }, "timezone": { "type": { "name": "string" }, "default": "The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise." diff --git a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json index 256d1589acc80..593bd7712dc79 100644 --- a/docs/pages/x/api/date-pickers/multi-section-digital-clock.json +++ b/docs/pages/x/api/date-pickers/multi-section-digital-clock.json @@ -20,6 +20,7 @@ "disableFuture": { "type": { "name": "bool" } }, "disableIgnoringDatePartForTimeValidation": { "type": { "name": "bool" } }, "disablePast": { "type": { "name": "bool" } }, + "fitWidth": { "type": { "name": "bool" } }, "focusedView": { "type": { "name": "enum", diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json index 96af2eb025fed..fcea6bd978add 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -215,6 +215,16 @@ "deprecated": "", "typeDescriptions": {} }, + "thresholdToRenderTimeInASingleColumn": { + "description": "Amount of time options below or at which the single column time renderer is used.", + "deprecated": "", + "typeDescriptions": {} + }, + "timeSteps": { + "description": "The time steps between two time unit options. For example, if timeStep.minutes = 8, then the available minute options will be [0, 8, 16, 24, 32, 40, 48, 56]. When single column time renderer is used, only timeStep.minutes will be used.", + "deprecated": "", + "typeDescriptions": {} + }, "timezone": { "description": "Choose which timezone to use for the value. Example: "default", "system", "UTC", "America/New_York". If you pass values from other timezones to some props, they will be converted to this timezone before being used.
        See the timezones documention for more details.", "deprecated": "", diff --git a/docs/translations/api-docs/date-pickers/multi-section-digital-clock.json b/docs/translations/api-docs/date-pickers/multi-section-digital-clock.json index fa580e7ea58b5..b21e3edad9cb8 100644 --- a/docs/translations/api-docs/date-pickers/multi-section-digital-clock.json +++ b/docs/translations/api-docs/date-pickers/multi-section-digital-clock.json @@ -51,6 +51,11 @@ "deprecated": "", "typeDescriptions": {} }, + "fitWidth": { + "description": "If true, the component will take all the width of its parent.", + "deprecated": "", + "typeDescriptions": {} + }, "focusedView": { "description": "Controlled focused view.", "deprecated": "", diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 247baa999f199..bc1166c47d2d5 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -41,8 +41,8 @@ export interface TimeRangePickerToolbarProps } export interface ExportedTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { - ampm: boolean; - ampmInClock: boolean; + ampm?: boolean; + ampmInClock?: boolean; } const TimeRangePickerToolbarRoot = styled(PickersToolbar, { @@ -104,7 +104,6 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< extends TimeClockSlotsComponent { /** From 30c7d4da34dc56f43f90f533aa11ab6f23fdae4f Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 28 Sep 2023 09:34:23 +0200 Subject: [PATCH 21/74] Work --- .../DesktopTimeRangePicker.tsx | 1 + .../MobileTimeRangePicker.tsx | 1 + .../TimeRangePickerToolbar.tsx | 60 +++++++++++++++++-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 535e5407ee5c9..224a8206c35f2 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -82,6 +82,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }), toolbar: { hidden: true, + toolbarVariant: 'desktop', ampmInClock: true, ...defaultizedProps.slotProps?.toolbar, }, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 0b5ad1055582c..6dc56e3906bc8 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -74,6 +74,7 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker Pick { ampm: boolean; ampmInClock: boolean; + toolbarVariant?: WrapperVariant; classes?: Partial; } @@ -51,8 +53,10 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { overridesResolver: (_, styles) => styles.root, })<{ ownerState: TimeRangePickerToolbarProps; -}>(({ theme }) => ({ - borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, +}>(({ theme, ownerState }) => ({ + ...(ownerState.toolbarVariant === 'mobile' + ? { borderBottom: `1px solid ${(theme.vars || theme).palette.divider}` } + : { padding: 0 }), })); const TimeRangePickerToolbarContainer = styled('div', { @@ -65,6 +69,12 @@ const TimeRangePickerToolbarContainer = styled('div', { width: '100%', }); +const TimeRangePickerToolbarMobileRoot = styled('div', { + name: 'MuiTimeRangePickerToolbar', + slot: 'MobileRoot', + overridesResolver: (_, styles) => styles.container, +})({ padding: '16px 24px' }); + const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< TDate extends unknown, >(inProps: TimeRangePickerToolbarProps, ref: React.Ref) { @@ -80,6 +90,8 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< ampm, ampmInClock, views, + toolbarVariant = 'mobile', + toolbarPlaceholder = '--:--', ...other } = props; @@ -93,13 +105,48 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< return resolveTimeFormat(utils, { format: undefined, ampm, views: views as TimeView[] }); }, [utils, toolbarFormat, ampm, views]); - const startDateValue = start ? utils.formatByString(start, format) : localeText.start; - - const endDateValue = end ? utils.formatByString(end, format) : localeText.end; - const ownerState = props; const classes = useUtilityClasses(ownerState); + if (toolbarVariant === 'desktop') { + const startDateValue = start ? utils.formatByString(start, format) : toolbarPlaceholder; + const endDateValue = end ? utils.formatByString(end, format) : toolbarPlaceholder; + + return ( + + + onRangePositionChange('start')} + /> + + + onRangePositionChange('end')} + /> + + + ); + } + + const startDateValue = start ? utils.formatByString(start, format) : localeText.start; + const endDateValue = end ? utils.formatByString(end, format) : localeText.end; + return ( Date: Thu, 28 Sep 2023 09:45:40 +0200 Subject: [PATCH 22/74] Work --- .../ResponsiveTimeRangePickers.js | 21 ++++--------------- .../ResponsiveTimeRangePickers.tsx.preview | 15 +++++++++++++ .../hooks/useEnrichedRangePickerFieldProps.ts | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js index 57de3648a80e9..39019af1b4763 100644 --- a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.js @@ -6,8 +6,6 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; import { MobileTimeRangePicker } from '@mui/x-date-pickers-pro/MobileTimeRangePicker'; import { DesktopTimeRangePicker } from '@mui/x-date-pickers-pro/DesktopTimeRangePicker'; -// import { StaticTimeRangePicker } from '@mui/x-date-pickers-pro/StaticTimeRangePicker'; -// import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout'; export default function ResponsiveTimeRangePickers() { return ( @@ -16,35 +14,24 @@ export default function ResponsiveTimeRangePickers() { components={[ 'TimeRangePicker', 'MobileTimeRangePicker', - 'DesktopDateRangePicker', - 'StaticTimeRangePicker', + 'DesktopTimeRangePicker', ]} > - + - + - + - {/* */} - {/* */} - {/* */} ); diff --git a/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview new file mode 100644 index 0000000000000..f1fa97d72d143 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/ResponsiveTimeRangePickers.tsx.preview @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index fd10ec9b61140..ed80c23c5ab14 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -6,7 +6,6 @@ import { resolveComponentProps, SlotComponentProps } from '@mui/base/utils'; import useEventCallback from '@mui/utils/useEventCallback'; import useForkRef from '@mui/utils/useForkRef'; import { BaseSingleInputFieldProps, FieldSelectedSections } from '@mui/x-date-pickers/models'; -import { DateOrTimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { PickersInputLocaleText } from '@mui/x-date-pickers/locales'; import { BaseFieldProps, @@ -17,6 +16,7 @@ import { UncapitalizeObjectKeys, UsePickerProps, getActiveElement, + DateOrTimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; import { BaseMultiInputFieldProps, From 40233241685834455342ff91f52816354eb90489 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 29 Sep 2023 08:55:40 +0200 Subject: [PATCH 23/74] Fix --- docs/data/date-pickers/localization/data.json | 124 ++++---- .../tests/MobileDateRangePicker.test.tsx | 276 ------------------ .../describes.MobileDateRangePicker.test.tsx | 114 -------- packages/x-date-pickers/src/locales/beBY.ts | 4 + packages/x-date-pickers/src/locales/caES.ts | 4 + packages/x-date-pickers/src/locales/csCZ.ts | 4 + packages/x-date-pickers/src/locales/daDK.ts | 4 + packages/x-date-pickers/src/locales/deDE.ts | 4 + packages/x-date-pickers/src/locales/elGR.ts | 4 + packages/x-date-pickers/src/locales/esES.ts | 4 + packages/x-date-pickers/src/locales/faIR.ts | 4 + packages/x-date-pickers/src/locales/fiFI.ts | 4 + packages/x-date-pickers/src/locales/frFR.ts | 4 + packages/x-date-pickers/src/locales/heIL.ts | 4 + packages/x-date-pickers/src/locales/huHU.ts | 4 + packages/x-date-pickers/src/locales/isIS.ts | 4 + packages/x-date-pickers/src/locales/itIT.ts | 4 + packages/x-date-pickers/src/locales/jaJP.ts | 4 + packages/x-date-pickers/src/locales/koKR.ts | 4 + packages/x-date-pickers/src/locales/kzKZ.ts | 4 + packages/x-date-pickers/src/locales/nbNO.ts | 4 + packages/x-date-pickers/src/locales/nlNL.ts | 4 + packages/x-date-pickers/src/locales/plPL.ts | 4 + packages/x-date-pickers/src/locales/ptBR.ts | 4 + packages/x-date-pickers/src/locales/roRO.ts | 4 + packages/x-date-pickers/src/locales/ruRU.ts | 4 + packages/x-date-pickers/src/locales/skSK.ts | 4 + packages/x-date-pickers/src/locales/svSE.ts | 4 + packages/x-date-pickers/src/locales/trTR.ts | 4 + packages/x-date-pickers/src/locales/ukUA.ts | 4 + packages/x-date-pickers/src/locales/urPK.ts | 4 + packages/x-date-pickers/src/locales/viVN.ts | 4 + packages/x-date-pickers/src/locales/zhCN.ts | 4 + packages/x-date-pickers/src/locales/zhHK.ts | 4 + 34 files changed, 186 insertions(+), 452 deletions(-) delete mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx delete mode 100644 packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index 7ce443b34901b..285cc6cc67b0e 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -3,248 +3,248 @@ "languageTag": "be-BY", "importName": "beBY", "localeName": "Belarusian", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/beBY.ts" }, { "languageTag": "ca-ES", "importName": "caES", "localeName": "Catalan", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/caES.ts" }, { "languageTag": "zh-HK", "importName": "zhHK", "localeName": "Chinese (Hong Kong)", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhHK.ts" }, { "languageTag": "zh-CN", "importName": "zhCN", "localeName": "Chinese (Simplified)", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhCN.ts" }, { "languageTag": "cs-CZ", "importName": "csCZ", "localeName": "Czech", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/csCZ.ts" }, { "languageTag": "da-DK", "importName": "daDK", "localeName": "Danish", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/daDK.ts" }, { "languageTag": "nl-NL", "importName": "nlNL", "localeName": "Dutch", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nlNL.ts" }, { "languageTag": "fi-FI", "importName": "fiFI", "localeName": "Finnish", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/fiFI.ts" }, { "languageTag": "fr-FR", "importName": "frFR", "localeName": "French", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/frFR.ts" }, { "languageTag": "de-DE", "importName": "deDE", "localeName": "German", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/deDE.ts" }, { "languageTag": "el-GR", "importName": "elGR", "localeName": "Greek", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/elGR.ts" }, { "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/heIL.ts" }, { "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/huHU.ts" }, { "languageTag": "is-IS", "importName": "isIS", "localeName": "Icelandic", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/isIS.ts" }, { "languageTag": "it-IT", "importName": "itIT", "localeName": "Italian", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/itIT.ts" }, { "languageTag": "ja-JP", "importName": "jaJP", "localeName": "Japanese", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/jaJP.ts" }, { "languageTag": "kz-KZ", "importName": "kzKZ", "localeName": "Kazakh", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/kzKZ.ts" }, { "languageTag": "ko-KR", "importName": "koKR", "localeName": "Korean", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/koKR.ts" }, { "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nbNO.ts" }, { "languageTag": "fa-IR", "importName": "faIR", "localeName": "Persian", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/faIR.ts" }, { "languageTag": "pl-PL", "importName": "plPL", "localeName": "Polish", - "missingKeysCount": 9, - "totalKeysCount": 37, + "missingKeysCount": 12, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/plPL.ts" }, { "languageTag": "pt-BR", "importName": "ptBR", "localeName": "Portuguese (Brazil)", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptBR.ts" }, { "languageTag": "ro-RO", "importName": "roRO", "localeName": "Romanian", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/roRO.ts" }, { "languageTag": "ru-RU", "importName": "ruRU", "localeName": "Russian", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ruRU.ts" }, { "languageTag": "sk-SK", "importName": "skSK", "localeName": "Slovak", - "missingKeysCount": 2, - "totalKeysCount": 37, + "missingKeysCount": 5, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/skSK.ts" }, { "languageTag": "es-ES", "importName": "esES", "localeName": "Spanish", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/esES.ts" }, { "languageTag": "sv-SE", "importName": "svSE", "localeName": "Swedish", - "missingKeysCount": 9, - "totalKeysCount": 37, + "missingKeysCount": 12, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/svSE.ts" }, { "languageTag": "tr-TR", "importName": "trTR", "localeName": "Turkish", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/trTR.ts" }, { "languageTag": "uk-UA", "importName": "ukUA", "localeName": "Ukrainian", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ukUA.ts" }, { "languageTag": "ur-PK", "importName": "urPK", "localeName": "Urdu (Pakistan)", - "missingKeysCount": 9, - "totalKeysCount": 37, + "missingKeysCount": 12, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/urPK.ts" }, { "languageTag": "vi-VN", "importName": "viVN", "localeName": "Vietnamese", - "missingKeysCount": 1, - "totalKeysCount": 37, + "missingKeysCount": 4, + "totalKeysCount": 40, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/viVN.ts" } ] diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx deleted file mode 100644 index 4228c4d358356..0000000000000 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/MobileDateRangePicker.test.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import * as React from 'react'; -import { spy } from 'sinon'; -import { expect } from 'chai'; -import { screen, userEvent, fireEvent } from '@mui/monorepo/test/utils'; -import { MobileDateRangePicker } from '@mui/x-date-pickers-pro/MobileDateRangePicker'; -import { createPickerRenderer, adapterToUse, openPicker } from 'test/utils/pickers'; -import { DateRange } from '@mui/x-date-pickers-pro'; - -describe('', () => { - const { render } = createPickerRenderer({ clock: 'fake' }); - - describe('picker state', () => { - it('should open when focusing the start input', () => { - const onOpen = spy(); - - render(); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - - expect(onOpen.callCount).to.equal(1); - expect(screen.queryByRole('dialog')).toBeVisible(); - }); - - it('should open when focusing the end input', () => { - const onOpen = spy(); - - render(); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); - - expect(onOpen.callCount).to.equal(1); - expect(screen.queryByRole('dialog')).toBeVisible(); - }); - - it('should call onChange with updated start date then call onChange with updated end date when opening from start input', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - // Open the picker - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - expect(onChange.callCount).to.equal(0); - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(0); - - // Change the start date - userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - expect(onChange.callCount).to.equal(1); - expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); - expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); - - // Change the end date - userEvent.mousePress(screen.getByRole('gridcell', { name: '5' })); - expect(onChange.callCount).to.equal(2); - expect(onChange.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); - expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 5)); - - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(0); - }); - - it('should call onChange with updated end date when opening from end input', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - // Open the picker - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); - expect(onChange.callCount).to.equal(0); - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(0); - - // Change the end date - userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - expect(onChange.callCount).to.equal(1); - expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); - expect(onChange.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(0); - }); - - it('should call onClose and onAccept when selecting the end date if props.closeOnSelect = true', () => { - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'end' }); - - // Change the end date - userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - - expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); - expect(onAccept.lastCall.args[0][1]).toEqualDateTime(new Date(2018, 0, 3)); - expect(onClose.callCount).to.equal(1); - }); - - it('should call onClose and onChange with the initial value when clicking "Cancel" button', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - - // Change the start date (already tested) - userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - - // Cancel the modifications - userEvent.mousePress(screen.getByText(/cancel/i)); - expect(onChange.callCount).to.equal(2); // Start date change + reset - expect(onChange.lastCall.args[0][0]).toEqualDateTime(defaultValue[0]); - expect(onChange.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(1); - }); - - it('should call onClose and onAccept with the live value and onAccept with the live value when clicking the "OK"', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - - // Change the start date (already tested) - userEvent.mousePress(screen.getByRole('gridcell', { name: '3' })); - - // Accept the modifications - userEvent.mousePress(screen.getByText(/ok/i)); - expect(onChange.callCount).to.equal(1); // Start date change - expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0][0]).toEqualDateTime(new Date(2018, 0, 3)); - expect(onAccept.lastCall.args[0][1]).toEqualDateTime(defaultValue[1]); - expect(onClose.callCount).to.equal(1); - }); - - it('should call onClose, onChange with empty value and onAccept with empty value when pressing the "Clear" button', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - const defaultValue: DateRange = [ - adapterToUse.date(new Date(2018, 0, 1)), - adapterToUse.date(new Date(2018, 0, 6)), - ]; - - render( - , - ); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - - // Clear the date - userEvent.mousePress(screen.getByText(/clear/i)); - expect(onChange.callCount).to.equal(1); // Start date change - expect(onChange.lastCall.args[0]).to.deep.equal([null, null]); - expect(onAccept.callCount).to.equal(1); - expect(onAccept.lastCall.args[0]).to.deep.equal([null, null]); - expect(onClose.callCount).to.equal(1); - }); - - it('should not call onChange or onAccept when pressing "Clear" button with an already null value', () => { - const onChange = spy(); - const onAccept = spy(); - const onClose = spy(); - - render( - , - ); - - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - - // Clear the date - userEvent.mousePress(screen.getByText(/clear/i)); - expect(onChange.callCount).to.equal(0); - expect(onAccept.callCount).to.equal(0); - expect(onClose.callCount).to.equal(1); - }); - - it('should correctly set focused styles when input is focused', () => { - render(); - - const firstInput = screen.getAllByRole('textbox')[0]; - fireEvent.focus(firstInput); - - expect(screen.getByText('Start', { selector: 'label' })).to.have.class('Mui-focused'); - }); - - it('should render "readonly" input elements', () => { - render(); - - screen.getAllByRole('textbox').forEach((input) => { - expect(input).to.have.attribute('readonly'); - }); - }); - }); - - // TODO: Write test - // it('should call onClose and onAccept with the live value when clicking outside of the picker', () => { - // }) -}); diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx deleted file mode 100644 index 3b7a7bc5f36f4..0000000000000 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/tests/describes.MobileDateRangePicker.test.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import * as React from 'react'; -import { - describeConformance, - screen, - userEvent, - fireDiscreteEvent, -} from '@mui/monorepo/test/utils'; -import { MobileDateRangePicker } from '@mui/x-date-pickers-pro/MobileDateRangePicker'; -import { describeRangeValidation } from '@mui/x-date-pickers-pro/tests/describeRangeValidation'; -import { describeValue } from '@mui/x-date-pickers/tests/describeValue'; -import { describePicker } from '@mui/x-date-pickers/tests/describePicker'; -import { - adapterToUse, - createPickerRenderer, - wrapPickerMount, - openPicker, - expectInputPlaceholder, - expectInputValue, -} from 'test/utils/pickers'; - -describe(' - Describes', () => { - const { render, clock } = createPickerRenderer({ - clock: 'fake', - clockConfig: new Date(2018, 0, 1, 0, 0, 0, 0), - }); - - describePicker(MobileDateRangePicker, { render, fieldType: 'multi-input', variant: 'mobile' }); - - describeRangeValidation(MobileDateRangePicker, () => ({ - render, - clock, - componentFamily: 'picker', - views: ['day'], - variant: 'mobile', - })); - - describeConformance(, () => ({ - classes: {} as any, - render, - muiName: 'MuiMobileDateRangePicker', - wrapMount: wrapPickerMount, - refInstanceof: window.HTMLDivElement, - skip: [ - 'componentProp', - 'componentsProp', - 'themeDefaultProps', - 'themeStyleOverrides', - 'themeVariants', - 'mergeClassName', - 'propsSpread', - 'rootClass', - 'reactTestRenderer', - ], - })); - - describeValue(MobileDateRangePicker, () => ({ - render, - componentFamily: 'picker', - type: 'date-range', - variant: 'mobile', - initialFocus: 'start', - clock, - values: [ - // initial start and end dates - [adapterToUse.date(new Date(2018, 0, 1)), adapterToUse.date(new Date(2018, 0, 4))], - // start and end dates after `setNewValue` - [adapterToUse.date(new Date(2018, 0, 2)), adapterToUse.date(new Date(2018, 0, 5))], - ], - emptyValue: [null, null], - assertRenderedValue: (expectedValues: any[]) => { - // `getAllByRole('textbox')` does not work here, because inputs are `readonly` - const textBoxes: HTMLInputElement[] = [ - screen.getByLabelText('Start'), - screen.getByLabelText('End'), - ]; - expectedValues.forEach((value, index) => { - const input = textBoxes[index]; - // TODO: Support single range input - if (!value) { - expectInputPlaceholder(input, 'MM/DD/YYYY'); - } - expectInputValue(input, value ? adapterToUse.format(value, 'keyboardDate') : ''); - }); - }, - setNewValue: (value, { isOpened, applySameValue, setEndDate = false }) => { - let newValue: any[]; - if (applySameValue) { - newValue = value; - } else if (setEndDate) { - newValue = [value[0], adapterToUse.addDays(value[1], 1)]; - } else { - newValue = [adapterToUse.addDays(value[0], 1), value[1]]; - } - - if (!isOpened) { - openPicker({ type: 'date-range', variant: 'mobile', initialFocus: 'start' }); - } - - userEvent.mousePress( - screen.getAllByRole('gridcell', { - name: adapterToUse.getDate(newValue[setEndDate ? 1 : 0]).toString(), - })[0], - ); - - // Close the picker - if (!isOpened) { - fireDiscreteEvent.keyDown(document.activeElement!, { key: 'Escape' }); - clock.runToLast(); - } - - return newValue; - }, - })); -}); diff --git a/packages/x-date-pickers/src/locales/beBY.ts b/packages/x-date-pickers/src/locales/beBY.ts index c60096586fe8d..56a9e01f6db52 100644 --- a/packages/x-date-pickers/src/locales/beBY.ts +++ b/packages/x-date-pickers/src/locales/beBY.ts @@ -27,6 +27,10 @@ const beBYPickers: Partial> = { start: 'Пачатак', end: 'Канец', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Адмена', clearButtonLabel: 'Ачысціць', diff --git a/packages/x-date-pickers/src/locales/caES.ts b/packages/x-date-pickers/src/locales/caES.ts index 0985d8d5ea7b6..f41e7262a0918 100644 --- a/packages/x-date-pickers/src/locales/caES.ts +++ b/packages/x-date-pickers/src/locales/caES.ts @@ -26,6 +26,10 @@ const caESPickers: Partial> = { start: 'Començar', end: 'Terminar', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Cancel·lar', clearButtonLabel: 'Netejar', diff --git a/packages/x-date-pickers/src/locales/csCZ.ts b/packages/x-date-pickers/src/locales/csCZ.ts index 9a96093a5ed78..8b7e2d3d178af 100644 --- a/packages/x-date-pickers/src/locales/csCZ.ts +++ b/packages/x-date-pickers/src/locales/csCZ.ts @@ -27,6 +27,10 @@ const csCZPickers: Partial> = { start: 'Začátek', end: 'Konec', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Zrušit', clearButtonLabel: 'Vymazat', diff --git a/packages/x-date-pickers/src/locales/daDK.ts b/packages/x-date-pickers/src/locales/daDK.ts index 5c5eb37627919..8f0a785941008 100644 --- a/packages/x-date-pickers/src/locales/daDK.ts +++ b/packages/x-date-pickers/src/locales/daDK.ts @@ -27,6 +27,10 @@ const daDKPickers: Partial> = { start: 'Start', end: 'Slut', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Annuller', clearButtonLabel: 'Ryd', diff --git a/packages/x-date-pickers/src/locales/deDE.ts b/packages/x-date-pickers/src/locales/deDE.ts index 09c18375e5c8f..569f2e7e174b2 100644 --- a/packages/x-date-pickers/src/locales/deDE.ts +++ b/packages/x-date-pickers/src/locales/deDE.ts @@ -27,6 +27,10 @@ const deDEPickers: Partial> = { start: 'Beginn', end: 'Ende', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Abbrechen', clearButtonLabel: 'Löschen', diff --git a/packages/x-date-pickers/src/locales/elGR.ts b/packages/x-date-pickers/src/locales/elGR.ts index 89be8d692b71b..cdbbd97d022eb 100644 --- a/packages/x-date-pickers/src/locales/elGR.ts +++ b/packages/x-date-pickers/src/locales/elGR.ts @@ -26,6 +26,10 @@ const elGRPickers: Partial> = { start: 'Αρχή', end: 'Τέλος', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Άκυρο', clearButtonLabel: 'Καθαρισμός', diff --git a/packages/x-date-pickers/src/locales/esES.ts b/packages/x-date-pickers/src/locales/esES.ts index 5e239109838b6..be49ad02265a4 100644 --- a/packages/x-date-pickers/src/locales/esES.ts +++ b/packages/x-date-pickers/src/locales/esES.ts @@ -26,6 +26,10 @@ const esESPickers: Partial> = { start: 'Empezar', end: 'Terminar', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Cancelar', clearButtonLabel: 'Limpiar', diff --git a/packages/x-date-pickers/src/locales/faIR.ts b/packages/x-date-pickers/src/locales/faIR.ts index e1bf37fe0e928..03f6d8788991c 100644 --- a/packages/x-date-pickers/src/locales/faIR.ts +++ b/packages/x-date-pickers/src/locales/faIR.ts @@ -26,6 +26,10 @@ const faIRPickers: Partial> = { start: 'شروع', end: 'پایان', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'لغو', clearButtonLabel: 'پاک کردن', diff --git a/packages/x-date-pickers/src/locales/fiFI.ts b/packages/x-date-pickers/src/locales/fiFI.ts index ca3236ebbdb46..217fc8a6a7f44 100644 --- a/packages/x-date-pickers/src/locales/fiFI.ts +++ b/packages/x-date-pickers/src/locales/fiFI.ts @@ -26,6 +26,10 @@ const fiFIPickers: Partial> = { start: 'Alku', end: 'Loppu', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Peruuta', clearButtonLabel: 'Tyhjennä', diff --git a/packages/x-date-pickers/src/locales/frFR.ts b/packages/x-date-pickers/src/locales/frFR.ts index 4ccb548a66e52..1b9e7bf9f22ff 100644 --- a/packages/x-date-pickers/src/locales/frFR.ts +++ b/packages/x-date-pickers/src/locales/frFR.ts @@ -26,6 +26,10 @@ const frFRPickers: Partial> = { start: 'Début', end: 'Fin', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Annuler', clearButtonLabel: 'Vider', diff --git a/packages/x-date-pickers/src/locales/heIL.ts b/packages/x-date-pickers/src/locales/heIL.ts index 7e22ba07b9526..7ef88d16a8568 100644 --- a/packages/x-date-pickers/src/locales/heIL.ts +++ b/packages/x-date-pickers/src/locales/heIL.ts @@ -26,6 +26,10 @@ const heILPickers: Partial> = { start: 'תחילה', end: 'סיום', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'ביטול', clearButtonLabel: 'ניקוי', diff --git a/packages/x-date-pickers/src/locales/huHU.ts b/packages/x-date-pickers/src/locales/huHU.ts index bf9c062111203..b0711bbff5965 100644 --- a/packages/x-date-pickers/src/locales/huHU.ts +++ b/packages/x-date-pickers/src/locales/huHU.ts @@ -27,6 +27,10 @@ const huHUPickers: Partial> = { start: 'Kezdő dátum', end: 'Záró dátum', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Mégse', clearButtonLabel: 'Törlés', diff --git a/packages/x-date-pickers/src/locales/isIS.ts b/packages/x-date-pickers/src/locales/isIS.ts index 77c46b3ed01e2..70c2f37031cd4 100644 --- a/packages/x-date-pickers/src/locales/isIS.ts +++ b/packages/x-date-pickers/src/locales/isIS.ts @@ -26,6 +26,10 @@ const isISPickers: Partial> = { start: 'Upphaf', end: 'Endir', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Hætta við', clearButtonLabel: 'Hreinsa', diff --git a/packages/x-date-pickers/src/locales/itIT.ts b/packages/x-date-pickers/src/locales/itIT.ts index 9cd3950d33f67..0f6e9e07796b5 100644 --- a/packages/x-date-pickers/src/locales/itIT.ts +++ b/packages/x-date-pickers/src/locales/itIT.ts @@ -26,6 +26,10 @@ const itITPickers: Partial> = { start: 'Inizio', end: 'Fine', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Cancellare', clearButtonLabel: 'Sgomberare', diff --git a/packages/x-date-pickers/src/locales/jaJP.ts b/packages/x-date-pickers/src/locales/jaJP.ts index 6850cd31b5e79..9bd4050f2fc25 100644 --- a/packages/x-date-pickers/src/locales/jaJP.ts +++ b/packages/x-date-pickers/src/locales/jaJP.ts @@ -27,6 +27,10 @@ const jaJPPickers: Partial> = { start: '開始', end: '終了', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'キャンセル', clearButtonLabel: 'クリア', diff --git a/packages/x-date-pickers/src/locales/koKR.ts b/packages/x-date-pickers/src/locales/koKR.ts index 7ad4123d2d010..d708f02c82aff 100644 --- a/packages/x-date-pickers/src/locales/koKR.ts +++ b/packages/x-date-pickers/src/locales/koKR.ts @@ -26,6 +26,10 @@ const koKRPickers: Partial> = { start: '시작', end: '종료', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: '취소', clearButtonLabel: '초기화', diff --git a/packages/x-date-pickers/src/locales/kzKZ.ts b/packages/x-date-pickers/src/locales/kzKZ.ts index b314d543935db..9dca31f1fb107 100644 --- a/packages/x-date-pickers/src/locales/kzKZ.ts +++ b/packages/x-date-pickers/src/locales/kzKZ.ts @@ -27,6 +27,10 @@ const kzKZPickers: Partial> = { start: 'Бастау', end: 'Cоңы', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Бас тарту', clearButtonLabel: 'Тазарту', diff --git a/packages/x-date-pickers/src/locales/nbNO.ts b/packages/x-date-pickers/src/locales/nbNO.ts index 037b6bbef1d83..2574d18915e2d 100644 --- a/packages/x-date-pickers/src/locales/nbNO.ts +++ b/packages/x-date-pickers/src/locales/nbNO.ts @@ -26,6 +26,10 @@ const nbNOPickers: Partial> = { start: 'Start', end: 'Slutt', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Avbryt', clearButtonLabel: 'Fjern', diff --git a/packages/x-date-pickers/src/locales/nlNL.ts b/packages/x-date-pickers/src/locales/nlNL.ts index 7ed39745e58ed..b8ae3b7a88245 100644 --- a/packages/x-date-pickers/src/locales/nlNL.ts +++ b/packages/x-date-pickers/src/locales/nlNL.ts @@ -26,6 +26,10 @@ const nlNLPickers: Partial> = { start: 'Start', end: 'Einde', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Annuleren', clearButtonLabel: 'Resetten', diff --git a/packages/x-date-pickers/src/locales/plPL.ts b/packages/x-date-pickers/src/locales/plPL.ts index 7ede4121f041a..9357007e6c427 100644 --- a/packages/x-date-pickers/src/locales/plPL.ts +++ b/packages/x-date-pickers/src/locales/plPL.ts @@ -26,6 +26,10 @@ const plPLPickers: Partial> = { start: 'Początek', end: 'Koniec', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Anuluj', clearButtonLabel: 'Wyczyść', diff --git a/packages/x-date-pickers/src/locales/ptBR.ts b/packages/x-date-pickers/src/locales/ptBR.ts index c099b9bfbbf75..ff1af8b247f26 100644 --- a/packages/x-date-pickers/src/locales/ptBR.ts +++ b/packages/x-date-pickers/src/locales/ptBR.ts @@ -26,6 +26,10 @@ const ptBRPickers: Partial> = { start: 'Início', end: 'Fim', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Cancelar', clearButtonLabel: 'Limpar', diff --git a/packages/x-date-pickers/src/locales/roRO.ts b/packages/x-date-pickers/src/locales/roRO.ts index a6df32fb4cf32..d264958e2b523 100644 --- a/packages/x-date-pickers/src/locales/roRO.ts +++ b/packages/x-date-pickers/src/locales/roRO.ts @@ -27,6 +27,10 @@ const roROPickers: Partial> = { start: 'Început', end: 'Sfârșit', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Anulare', clearButtonLabel: 'Ștergere', diff --git a/packages/x-date-pickers/src/locales/ruRU.ts b/packages/x-date-pickers/src/locales/ruRU.ts index 31d07704c35c5..a8bbd98b7c83d 100644 --- a/packages/x-date-pickers/src/locales/ruRU.ts +++ b/packages/x-date-pickers/src/locales/ruRU.ts @@ -27,6 +27,10 @@ const ruRUPickers: Partial> = { start: 'Начало', end: 'Конец', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Отмена', clearButtonLabel: 'Очистить', diff --git a/packages/x-date-pickers/src/locales/skSK.ts b/packages/x-date-pickers/src/locales/skSK.ts index 85c57855363c9..c1d3230a7f2a3 100644 --- a/packages/x-date-pickers/src/locales/skSK.ts +++ b/packages/x-date-pickers/src/locales/skSK.ts @@ -27,6 +27,10 @@ const skSKPickers: Partial> = { start: 'Začiatok', end: 'Koniec', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Zrušiť', clearButtonLabel: 'Vymazať', diff --git a/packages/x-date-pickers/src/locales/svSE.ts b/packages/x-date-pickers/src/locales/svSE.ts index 6c4a605b04cc9..a441795275a87 100644 --- a/packages/x-date-pickers/src/locales/svSE.ts +++ b/packages/x-date-pickers/src/locales/svSE.ts @@ -26,6 +26,10 @@ const svSEPickers: Partial> = { start: 'Start', end: 'Slut', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Avbryt', clearButtonLabel: 'Rensa', diff --git a/packages/x-date-pickers/src/locales/trTR.ts b/packages/x-date-pickers/src/locales/trTR.ts index 1f2eab4a1b370..a4d3c584ec17e 100644 --- a/packages/x-date-pickers/src/locales/trTR.ts +++ b/packages/x-date-pickers/src/locales/trTR.ts @@ -26,6 +26,10 @@ const trTRPickers: Partial> = { start: 'Başlangıç', end: 'Bitiş', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'iptal', clearButtonLabel: 'Temizle', diff --git a/packages/x-date-pickers/src/locales/ukUA.ts b/packages/x-date-pickers/src/locales/ukUA.ts index e7ca90ada888d..998268b821589 100644 --- a/packages/x-date-pickers/src/locales/ukUA.ts +++ b/packages/x-date-pickers/src/locales/ukUA.ts @@ -26,6 +26,10 @@ const ukUAPickers: Partial> = { start: 'Початок', end: 'Кінець', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Відміна', clearButtonLabel: 'Очистити', diff --git a/packages/x-date-pickers/src/locales/urPK.ts b/packages/x-date-pickers/src/locales/urPK.ts index 76a77f7d8d83e..86f355fe094e0 100644 --- a/packages/x-date-pickers/src/locales/urPK.ts +++ b/packages/x-date-pickers/src/locales/urPK.ts @@ -26,6 +26,10 @@ const urPKPickers: Partial> = { start: 'شروع', end: 'ختم', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'کینسل', clearButtonLabel: 'کلئیر', diff --git a/packages/x-date-pickers/src/locales/viVN.ts b/packages/x-date-pickers/src/locales/viVN.ts index 946fc53f3f9c2..da4bab477a26b 100644 --- a/packages/x-date-pickers/src/locales/viVN.ts +++ b/packages/x-date-pickers/src/locales/viVN.ts @@ -26,6 +26,10 @@ const viVNPickers: Partial> = { start: 'Bắt đầu', end: 'Kết thúc', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: 'Hủy', clearButtonLabel: 'Xóa', diff --git a/packages/x-date-pickers/src/locales/zhCN.ts b/packages/x-date-pickers/src/locales/zhCN.ts index 55e2a6477d10c..058416a9466ce 100644 --- a/packages/x-date-pickers/src/locales/zhCN.ts +++ b/packages/x-date-pickers/src/locales/zhCN.ts @@ -24,6 +24,10 @@ const zhCNPickers: Partial> = { start: '开始', end: '结束', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: '取消', clearButtonLabel: '清除', diff --git a/packages/x-date-pickers/src/locales/zhHK.ts b/packages/x-date-pickers/src/locales/zhHK.ts index 756ee012a628a..0c00c33e07184 100644 --- a/packages/x-date-pickers/src/locales/zhHK.ts +++ b/packages/x-date-pickers/src/locales/zhHK.ts @@ -24,6 +24,10 @@ const zhHKPickers: Partial> = { start: '開始', end: '結束', + // Generic range placeholders + // from: 'From', + // to: 'To', + // Action bar cancelButtonLabel: '取消', clearButtonLabel: '清除', From f385a01fbfc19d660c5cf86b32254a396a0bb0e2 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 29 Sep 2023 11:20:19 +0200 Subject: [PATCH 24/74] Fix --- .../api/date-pickers/desktop-time-range-picker.json | 12 ++++++++++++ .../x/api/date-pickers/mobile-time-range-picker.json | 12 ++++++++++++ docs/pages/x/api/date-pickers/time-range-picker.json | 12 ++++++++++++ .../date-pickers/desktop-time-range-picker.json | 2 ++ .../date-pickers/mobile-time-range-picker.json | 2 ++ .../api-docs/date-pickers/time-range-picker.json | 2 ++ 6 files changed, 42 insertions(+) diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 0ebf3b6eba182..d7334165e5ffb 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -169,6 +169,18 @@ "description": "Custom component for the action bar, it is placed below the picker views.", "default": "PickersActionBar" }, + { + "class": null, + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton" + }, + { + "class": null, + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon" + }, { "class": null, "name": "desktopPaper", diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index d160bfc5ffcc2..37341d9f6ae83 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -163,6 +163,18 @@ "description": "Custom component for the action bar, it is placed below the picker views.", "default": "PickersActionBar" }, + { + "class": null, + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton" + }, + { + "class": null, + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon" + }, { "class": null, "name": "dialog", diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index f6f8d2abc6d47..f24430ca0fb2d 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -171,6 +171,18 @@ "description": "Custom component for the action bar, it is placed below the picker views.", "default": "PickersActionBar" }, + { + "class": null, + "name": "clearButton", + "description": "Button to clear the value.", + "default": "IconButton" + }, + { + "class": null, + "name": "clearIcon", + "description": "Icon to display inside the clear button.", + "default": "ClearIcon" + }, { "class": null, "name": "desktopPaper", diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json index ac6ee6ae819cf..153dc5bb7c402 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker.json @@ -255,6 +255,8 @@ "classDescriptions": {}, "slotDescriptions": { "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json index fcea6bd978add..866133a10fd42 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker.json @@ -250,6 +250,8 @@ "classDescriptions": {}, "slotDescriptions": { "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", "field": "", "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", diff --git a/docs/translations/api-docs/date-pickers/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker.json index 2fcca8ffc39bc..5ddefcda19ac1 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker.json @@ -260,6 +260,8 @@ "classDescriptions": {}, "slotDescriptions": { "actionBar": "Custom component for the action bar, it is placed below the picker views.", + "clearButton": "Button to clear the value.", + "clearIcon": "Icon to display inside the clear button.", "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", From a0ec6021fe1ccad7618d60b199aaed0da6f24eb8 Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 16 Oct 2023 09:36:54 +0200 Subject: [PATCH 25/74] Work --- .../timeRangeViewRenderers/timeRangeViewRenderers.tsx | 1 - .../MultiSectionDigitalClock.tsx | 6 ------ .../MultiSectionDigitalClock.types.ts | 4 ---- .../MultiSectionDigitalClockSection.tsx | 11 +++-------- .../src/PickersLayout/PickersLayout.tsx | 2 +- 5 files changed, 4 insertions(+), 20 deletions(-) diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 145f224384828..7b15c4a4e58fe 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -290,7 +290,6 @@ export const renderMultiSectionDigitalClockTimeRangeView = ); diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx index 3cb961a98cf0d..0917ad29c1b08 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx @@ -88,7 +88,6 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi disabled, readOnly, skipDisabled = false, - fitWidth = false, timezone: timezoneProp, ...other } = props; @@ -406,7 +405,6 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi slots={slots ?? components} slotProps={slotProps ?? componentsProps} skipDisabled={skipDisabled} - fitWidth={fitWidth} aria-label={localeText.selectViewText(timeView as TimeViewWithMeridiem)} /> ))} @@ -473,10 +471,6 @@ MultiSectionDigitalClock.propTypes = { * @default false */ disablePast: PropTypes.bool, - /** - * If `true`, the component will take all the width of its parent. - */ - fitWidth: PropTypes.bool, /** * Controlled focused view. */ diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts index d0fd79ecbfea2..bc51ef50d49f7 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts @@ -66,8 +66,4 @@ export interface MultiSectionDigitalClockProps * @default {} */ slotProps?: MultiSectionDigitalClockSlotsComponentsProps; - /** - * If `true`, the component will take all the width of its parent. - */ - fitWidth?: boolean; } diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx index f7db521dce695..a1010748a73b2 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx @@ -36,7 +36,6 @@ export interface MultiSectionDigitalClockSectionProps onChange: (value: TValue) => void; active?: boolean; skipDisabled?: boolean; - fitWidth?: boolean; role?: string; } @@ -57,9 +56,8 @@ const MultiSectionDigitalClockSectionRoot = styled(MenuList, { })<{ ownerState: MultiSectionDigitalClockSectionProps & { alreadyRendered: boolean } }>( ({ theme, ownerState }) => ({ maxHeight: DIGITAL_CLOCK_VIEW_HEIGHT, - ...(ownerState.fitWidth - ? { flex: '1 1 100%', overflow: 'auto' } - : { width: 56, overflow: 'hidden' }), + width: 56, + overflow: 'hidden', padding: 0, '@media (prefers-reduced-motion: no-preference)': { scrollBehavior: ownerState.alreadyRendered ? 'smooth' : 'auto', @@ -86,9 +84,7 @@ const MultiSectionDigitalClockSectionItem = styled(MenuItem, { })<{ ownerState: MultiSectionDigitalClockSectionProps }>(({ theme, ownerState }) => ({ padding: 8, margin: '2px 4px', - ...(ownerState.fitWidth - ? { width: 'calc(100% - 8px)' } - : { width: MULTI_SECTION_CLOCK_SECTION_WIDTH }), + width: MULTI_SECTION_CLOCK_SECTION_WIDTH, justifyContent: 'center', '&:first-of-type': { marginTop: 4, @@ -144,7 +140,6 @@ export const MultiSectionDigitalClockSection = React.forwardRef( slots, slotProps, skipDisabled, - fitWidth, ...other } = props; diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index c5658cbc42eb5..d27bf3fde8730 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -64,7 +64,7 @@ export const PickersLayoutContentWrapper = styled('div', { slot: 'ContentWrapper', overridesResolver: (props, styles) => styles.contentWrapper, })({ - gridColumn: '2 / 4', + gridColumn: 2, gridRow: 2, display: 'flex', flexDirection: 'column', From a36483b55fd4cbec275967ac79e29d705e537cfc Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 15 Nov 2023 15:10:28 +0100 Subject: [PATCH 26/74] Fix --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 07b2c3caa22a1..2090d941c9e6f 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -22,7 +22,7 @@ import { type DesktopTimeRangePickerComponent = (( props: DesktopTimeRangePickerProps & React.RefAttributes, -) => JSX.Element) & { propTypes?: any }; +) => React.JSX.Element) & { propTypes?: any }; const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker( inProps: DesktopTimeRangePickerProps, From f2e794f9d8337e5c0ecb3d8ba6483b282ec3f424 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 15 Nov 2023 15:13:03 +0100 Subject: [PATCH 27/74] Fix --- .../src/TimeRangePicker/shared.tsx | 23 ++++++------------- .../timeRangeViewRenderers.tsx | 4 ---- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index be2ad30dfdb79..a6e225d4cd3f6 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -85,22 +85,16 @@ type UseTimeRangePickerDefaultizedProps< TDate, TView extends TimeViewWithMeridiem, Props extends BaseTimeRangePickerProps, -> = Omit< - LocalizedComponent< - TDate, - DefaultizedProps - >, - 'components' | 'componentsProps' +> = LocalizedComponent< + TDate, + DefaultizedProps >; export function useTimeRangePickerDefaultizedProps< TDate, TView extends TimeViewWithMeridiem, Props extends BaseTimeRangePickerProps, ->( - props: Props, - name: string, -): UseTimeRangePickerDefaultizedProps> { +>(props: Props, name: string): UseTimeRangePickerDefaultizedProps { const utils = useUtils(); const themeProps = useThemeProps({ @@ -121,9 +115,6 @@ export function useTimeRangePickerDefaultizedProps< }; }, [themeProps.localeText]); - const slots = themeProps.slots ?? uncapitalizeObjectKeys(themeProps.components); - const slotProps = themeProps.slotProps ?? themeProps.componentsProps; - return { ...themeProps, ampm, @@ -138,13 +129,13 @@ export function useTimeRangePickerDefaultizedProps< disablePast: themeProps.disablePast ?? false, slots: { toolbar: TimeRangePickerToolbar, - ...slots, + ...themeProps.slots, }, slotProps: { - ...slotProps, + ...themeProps.slotProps, toolbar: { ampm, - ...slotProps?.toolbar, + ...themeProps.slotProps?.toolbar, }, }, }; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 7b15c4a4e58fe..20af5fcd4aeb4 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -49,8 +49,6 @@ export const renderTimeRangeViewClock = ({ minutesStep, ampm, ampmInClock, - components, - componentsProps, slots, slotProps, readOnly, @@ -102,8 +100,6 @@ export const renderTimeRangeViewClock = ({ minutesStep={minutesStep} ampm={ampm} ampmInClock={ampmInClock} - components={components} - componentsProps={componentsProps} slots={slots} slotProps={slotProps} readOnly={readOnly} From c4d98e1b80e15f47c019a9dd7ee682b1930f4247 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 25 Apr 2024 11:59:53 +0200 Subject: [PATCH 28/74] Fix --- docs/data/date-pickers/time-range-picker/time-range-picker.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 96b6e7b130dd1..63fd21cc29811 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -18,7 +18,6 @@ materialDesign: https://m2.material.io/components/date-pickers ## Component composition The component is built using the `MultiInputTimeRangeField` for the keyboard editing, the `DigitalClock` for the desktop view editing, and the `TimeClock` for the mobile view editing. -All the documented props of those two components can also be passed to the Time Range Picker component. Check-out their documentation page for more information: From 2dde567bf836988373940ef2e4b1cf3958dc92a6 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 17 May 2024 18:07:11 +0300 Subject: [PATCH 29/74] Run `l10n` --- docs/data/date-pickers/localization/data.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index 786350aa8cc02..c5634f68c94a3 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -99,7 +99,7 @@ "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 1, + "missingKeysCount": 4, "totalKeysCount": 53, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/heIL.ts" }, @@ -107,7 +107,7 @@ "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 0, + "missingKeysCount": 3, "totalKeysCount": 53, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/huHU.ts" }, From 93ce845bbe3176024a76c4fc8fbd5c3d3c6e6ff3 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 17 May 2024 19:14:07 +0300 Subject: [PATCH 30/74] Run `pnpm proptypes` after merge --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 2 +- .../src/MobileTimeRangePicker/MobileTimeRangePicker.tsx | 2 +- .../x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx | 2 +- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 46c8851188efa..787d9b2030e02 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -108,7 +108,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< DesktopTimeRangePicker.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "yarn proptypes" | + // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** * 12h/24h view for hour selection clock. diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index fcc191e12ee1b..358a093e9255c 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -101,7 +101,7 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< MobileTimeRangePicker.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "yarn proptypes" | + // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** * 12h/24h view for hour selection clock. diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 272480921c72a..04e186c71db23 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -40,7 +40,7 @@ const TimeRangePicker = React.forwardRef(function TimeRangePicker< TimeRangePicker.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "yarn proptypes" | + // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** * 12h/24h view for hour selection clock. diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 10acf78b9b710..d898170c5f5f8 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -176,7 +176,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< TimeRangePickerToolbar.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "yarn proptypes" | + // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- ampm: PropTypes.bool.isRequired, ampmInClock: PropTypes.bool.isRequired, From 4628c67b4258a0eb75d9dba0341df8916e820b40 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 17 May 2024 19:30:09 +0300 Subject: [PATCH 31/74] Add component level comment --- .../src/TimeRangePicker/TimeRangePicker.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 04e186c71db23..b7f82c643990a 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -16,6 +16,16 @@ type TimePickerComponent = (< React.RefAttributes, ) => React.JSX.Element) & { propTypes?: any }; +/** + * Demos: + * + * - [TimeRangePicker](https://mui.com/x/react-date-pickers/time-range-picker/) + * - [Validation](https://mui.com/x/react-date-pickers/validation/) + * + * API: + * + * - [TimeRangePicker API](https://mui.com/x/api/date-pickers/time-range-picker/) + */ const TimeRangePicker = React.forwardRef(function TimeRangePicker< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean = false, From 74347fb87094d3d97b43ec0ce5de5753c911cb5f Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 20 May 2024 15:56:01 +0300 Subject: [PATCH 32/74] Fix eslint issues --- .../data/date-pickers/time-range-picker/BasicTimeRangePicker.js | 2 +- .../date-pickers/time-range-picker/BasicTimeRangePicker.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js index af806f48e36e5..10df879e6592c 100644 --- a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; -import { LocalizationProvider } from '@mui/x-date-pickers-pro'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; diff --git a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx index af806f48e36e5..10df879e6592c 100644 --- a/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx +++ b/docs/data/date-pickers/time-range-picker/BasicTimeRangePicker.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; -import { LocalizationProvider } from '@mui/x-date-pickers-pro'; +import { LocalizationProvider } from '@mui/x-date-pickers-pro/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs'; import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; From 3cec781fc9a178a64d4bfc06d2d4c02e11a292e3 Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 20 May 2024 15:56:31 +0300 Subject: [PATCH 33/74] Remove unused `ownerState` --- .../MultiSectionDigitalClockSection.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx index 0e0b6a5783298..aa9e881d853c7 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx @@ -95,7 +95,7 @@ const MultiSectionDigitalClockSectionItem = styled(MenuItem, { name: 'MuiMultiSectionDigitalClockSection', slot: 'Item', overridesResolver: (_, styles) => styles.item, -})<{ ownerState: MultiSectionDigitalClockSectionProps }>(({ theme, ownerState }) => ({ +})(({ theme }) => ({ padding: 8, margin: '2px 4px', width: MULTI_SECTION_CLOCK_SECTION_WIDTH, @@ -217,7 +217,6 @@ export const MultiSectionDigitalClockSection = React.forwardRef( aria-disabled={readOnly || isDisabled || undefined} aria-label={option.ariaLabel} aria-selected={isSelected} - ownerState={ownerState} tabIndex={tabIndex} className={classes.item} {...slotProps?.digitalClockSectionItem} From 299c073fc29500c55b32070ac192dc058e12887c Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 21 May 2024 11:31:01 +0300 Subject: [PATCH 34/74] Use `rendererInterceptor` on MobileTimeRangePicker --- .../MobileTimeRangePicker.tsx | 110 ++++++++++++++++-- 1 file changed, 98 insertions(+), 12 deletions(-) diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 358a093e9255c..79988cafd912f 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -2,26 +2,111 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { PickerValidDate } from '@mui/x-date-pickers/models'; import { + DefaultizedProps, + DIALOG_WIDTH, extractValidationProps, + isInternalTimeView, + PickerViewRenderer, + PickerViewsRendererProps, resolveTimeFormat, TimeViewWithMeridiem, useUtils, + VIEW_HEIGHT, } from '@mui/x-date-pickers/internals'; import { resolveComponentProps } from '@mui/base/utils'; import refType from '@mui/utils/refType'; +import { + multiSectionDigitalClockClasses, + multiSectionDigitalClockSectionClasses, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; +import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; +import { + renderDigitalClockTimeView, + renderMultiSectionDigitalClockTimeView, +} from '@mui/x-date-pickers/timeViewRenderers'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; import { TimeRangePickerRenderers, useTimeRangePickerDefaultizedProps, } from '../TimeRangePicker/shared'; -import { - renderDigitalClockTimeRangeView, - renderMultiSectionDigitalClockTimeRangeView, -} from '../timeRangeViewRenderers'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; -import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; +import { + useMobileRangePicker, + UseMobileRangePickerProps, +} from '../internals/hooks/useMobileRangePicker'; import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; +import { DateRange } from '../models'; +import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeRangePickerTimeWrapper'; + +const rendererInterceptor = function rendererInterceptor< + TDate extends PickerValidDate, + TEnableAccessibleFieldDOMStructure extends boolean, +>( + inViewRenderers: TimeRangePickerRenderers, + popperView: TimeViewWithMeridiem, + rendererProps: PickerViewsRendererProps< + DateRange, + TimeViewWithMeridiem, + DefaultizedProps< + UseMobileRangePickerProps< + TDate, + TimeViewWithMeridiem, + TEnableAccessibleFieldDOMStructure, + any, + any + >, + 'rangePosition' | 'onRangePositionChange' | 'openTo' + >, + {} + >, +) { + const { view, openTo, rangePosition, ...otherRendererProps } = rendererProps; + const finalProps = { + ...otherRendererProps, + rangePosition, + focusedView: null, + sx: [ + { + width: DIALOG_WIDTH, + [`.${multiSectionDigitalClockSectionClasses.root}`]: { + flex: 1, + // account for the border on `MultiSectionDigitalClock` + maxHeight: VIEW_HEIGHT - 1, + [`.${multiSectionDigitalClockSectionClasses.item}`]: { + width: 'auto', + }, + }, + [`&.${digitalClockClasses.root}`]: { + maxHeight: RANGE_VIEW_HEIGHT, + [`.${digitalClockClasses.item}`]: { + justifyContent: 'center', + }, + }, + [`&.${multiSectionDigitalClockClasses.root}, .${multiSectionDigitalClockSectionClasses.root}`]: + { + maxHeight: RANGE_VIEW_HEIGHT - 1, + }, + }, + ], + }; + const viewRenderer = inViewRenderers[popperView]; + if (!viewRenderer) { + return null; + } + return ( + , TimeViewWithMeridiem, any, {}> + } + view={view && isInternalTimeView(view) ? view : 'hours'} + views={finalProps.views as TimeViewWithMeridiem[]} + openTo={isInternalTimeView(openTo) ? openTo : 'hours'} + /> + ); +}; type MobileTimeRangePickerComponent = (< TDate extends PickerValidDate, @@ -46,15 +131,15 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< MobileTimeRangePickerProps >(inProps, 'MuiMobileTimeRangePicker'); - const renderTimeRangeView = defaultizedProps.shouldRenderTimeInASingleColumn - ? renderDigitalClockTimeRangeView - : renderMultiSectionDigitalClockTimeRangeView; + const renderTimeView = defaultizedProps.shouldRenderTimeInASingleColumn + ? renderDigitalClockTimeView + : renderMultiSectionDigitalClockTimeView; const viewRenderers: TimeRangePickerRenderers = { - hours: renderTimeRangeView, - minutes: renderTimeRangeView, - seconds: renderTimeRangeView, - meridiem: renderTimeRangeView, + hours: renderTimeView, + minutes: renderTimeView, + seconds: renderTimeView, + meridiem: renderTimeView, ...defaultizedProps.viewRenderers, }; @@ -93,6 +178,7 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< valueManager: rangeValueManager, valueType: 'time', validator: validateTimeRange, + rendererInterceptor, }); return renderPicker(); From 0d549817e1b5fa6b54be47b39f061f7fe66ff39f Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 21 May 2024 14:14:42 +0300 Subject: [PATCH 35/74] Refactor `TimeRangePickerToolbar` --- .../DateTimeRangePickerToolbar.tsx | 5 ++- .../TimeRangePickerToolbar.tsx | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index f2ff988c224c0..e779fd0bb21e3 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -23,6 +23,7 @@ import { getDateTimeRangePickerToolbarUtilityClass, } from './dateTimeRangePickerToolbarClasses'; import { calculateRangeChange } from '../internals/utils/date-range-manager'; +import { DateTimeRangePickerView } from '../internals/models'; const useUtilityClasses = (ownerState: DateTimeRangePickerToolbarProps) => { const { classes } = ownerState; @@ -35,10 +36,8 @@ const useUtilityClasses = (ownerState: DateTimeRangePickerToolbarProps) => return composeClasses(slots, getDateTimeRangePickerToolbarUtilityClass, classes); }; -type DateTimeRangeViews = Exclude; - export interface DateTimeRangePickerToolbarProps - extends BaseToolbarProps, DateTimeRangeViews>, + extends BaseToolbarProps, DateTimeRangePickerView>, Pick, ExportedDateTimeRangePickerToolbarProps { ampm?: boolean; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index d898170c5f5f8..2e34bd38ba3f4 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -14,6 +14,7 @@ import { ExportedBaseToolbarProps, resolveTimeFormat, WrapperVariant, + TimeViewWithMeridiem, } from '@mui/x-date-pickers/internals'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { @@ -33,29 +34,39 @@ const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { }; export interface TimeRangePickerToolbarProps - extends BaseToolbarProps, TimeView>, - Pick { + extends BaseToolbarProps, TimeViewWithMeridiem>, + Pick, + ExportedTimeRangePickerToolbarProps { ampm: boolean; - ampmInClock: boolean; toolbarVariant?: WrapperVariant; - classes?: Partial; } export interface ExportedTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { - ampm?: boolean; - ampmInClock?: boolean; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; } const TimeRangePickerToolbarRoot = styled(PickersToolbar, { name: 'MuiTimeRangePickerToolbar', slot: 'Root', overridesResolver: (_, styles) => styles.root, -})<{ - ownerState: TimeRangePickerToolbarProps; -}>(({ theme, ownerState }) => ({ - ...(ownerState.toolbarVariant === 'mobile' - ? { borderBottom: `1px solid ${(theme.vars || theme).palette.divider}` } - : { padding: 0 }), +})<{ ownerState: TimeRangePickerToolbarProps }>(({ theme }) => ({ + variants: [ + { + props: { toolbarVariant: 'mobile' }, + style: { + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + { + props: { toolbarVariant: 'desktop' }, + style: { + padding: 0, + }, + }, + ], })); const TimeRangePickerToolbarContainer = styled('div', { @@ -87,7 +98,6 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< toolbarFormat, className, ampm, - ampmInClock, views, toolbarVariant = 'mobile', toolbarPlaceholder = '--:--', From b18e17ba4f0236bc3ed5a7764d1dfcb65432332a Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 21 May 2024 14:15:27 +0300 Subject: [PATCH 36/74] scripts --- .../x/api/date-pickers/time-range-picker-toolbar.json | 5 +++-- .../time-range-picker-toolbar.json | 1 + .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index bb7fa50b69d64..0ac37346c0c3b 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -8,17 +8,18 @@ "view": { "type": { "name": "enum", - "description": "'hours'
        | 'minutes'
        | 'seconds'" + "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" }, "required": true }, "views": { "type": { "name": "arrayOf", - "description": "Array<'hours'
        | 'minutes'
        | 'seconds'>" + "description": "Array<'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'>" }, "required": true }, + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, "sx": { "type": { diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json index deb2b000ca84b..6198bb709b0e6 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -1,6 +1,7 @@ { "componentDescription": "", "propDescriptions": { + "classes": { "description": "Override or extend the styles applied to the component." }, "hidden": { "description": "If true, show the toolbar even in desktop mode." }, "onViewChange": { "description": "Callback called when a toolbar is clicked", diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 2e34bd38ba3f4..d610a3b703a97 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -189,7 +189,9 @@ TimeRangePickerToolbar.propTypes = { // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- ampm: PropTypes.bool.isRequired, - ampmInClock: PropTypes.bool.isRequired, + /** + * Override or extend the styles applied to the component. + */ classes: PropTypes.object, className: PropTypes.string, disabled: PropTypes.bool, @@ -232,11 +234,12 @@ TimeRangePickerToolbar.propTypes = { /** * Currently visible picker view. */ - view: PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired, + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired, /** * Available views. */ - views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'minutes', 'seconds']).isRequired).isRequired, + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired) + .isRequired, } as any; export { TimeRangePickerToolbar }; From 4559f0c44f72793d7586b09c7cb198fd0780a801 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 22 May 2024 12:55:50 +0300 Subject: [PATCH 37/74] Align `TimeRangePickerToolbar` with `DateTimeRangePickerToolbar` --- .../TimeRangePickerToolbar.tsx | 241 ++++++++++++------ .../timeRangePickerToolbarClasses.ts | 6 +- .../components/PickersToolbarButton.tsx | 2 +- .../x-date-pickers/src/internals/index.ts | 3 +- 4 files changed, 168 insertions(+), 84 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index d610a3b703a97..177518c193e6c 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -1,10 +1,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import Typography from '@mui/material/Typography'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; -import { PickerValidDate, TimeView } from '@mui/x-date-pickers/models'; +import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { PickersToolbar, PickersToolbarButton, @@ -12,9 +11,14 @@ import { BaseToolbarProps, useLocaleText, ExportedBaseToolbarProps, - resolveTimeFormat, WrapperVariant, TimeViewWithMeridiem, + PickersToolbarText, + getMeridiem, + formatMeridiem, + MakeOptional, + pickersToolbarClasses, + pickersToolbarTextClasses, } from '@mui/x-date-pickers/internals'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { @@ -28,20 +32,23 @@ const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { const slots = { root: ['root'], container: ['container'], + separator: ['separator'], + timeContainer: ['timeContainer'], }; return composeClasses(slots, getTimeRangePickerToolbarUtilityClass, classes); }; export interface TimeRangePickerToolbarProps - extends BaseToolbarProps, TimeViewWithMeridiem>, + extends Omit, TimeViewWithMeridiem>, 'toolbarFormat'>, Pick, ExportedTimeRangePickerToolbarProps { ampm: boolean; toolbarVariant?: WrapperVariant; } -export interface ExportedTimeRangePickerToolbarProps extends ExportedBaseToolbarProps { +export interface ExportedTimeRangePickerToolbarProps + extends Omit { /** * Override or extend the styles applied to the component. */ @@ -53,37 +60,126 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { slot: 'Root', overridesResolver: (_, styles) => styles.root, })<{ ownerState: TimeRangePickerToolbarProps }>(({ theme }) => ({ - variants: [ - { - props: { toolbarVariant: 'mobile' }, - style: { - borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, - }, - }, - { - props: { toolbarVariant: 'desktop' }, - style: { - padding: 0, - }, - }, - ], + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, + padding: '12px 0px 8px 0px', + [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: { + color: (theme.vars || theme).palette.primary.main, + fontWeight: theme.typography.fontWeightBold, + }, + '& > :first-child': { + paddingLeft: 12, + }, })); const TimeRangePickerToolbarContainer = styled('div', { name: 'MuiTimeRangePickerToolbar', slot: 'Container', overridesResolver: (_, styles) => styles.container, +})({ + display: 'flex', + flexDirection: 'column', + flex: 1, + rowGap: 8, +}); + +const TimeRangePickerToolbarTimeContainer = styled('div', { + name: 'MuiTimeRangePickerToolbar', + slot: 'TimeContainer', + overridesResolver: (_, styles) => styles.timeContainer, })({ display: 'flex', justifyContent: 'space-between', width: '100%', }); -const TimeRangePickerToolbarMobileRoot = styled('div', { +const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { name: 'MuiTimeRangePickerToolbar', - slot: 'MobileRoot', - overridesResolver: (_, styles) => styles.container, -})({ padding: '16px 24px' }); + slot: 'Separator', + overridesResolver: (props, styles) => styles.separator, +})({ + cursor: 'default', +}); + +type TimeRangePickerToolbarTimeElementProps = MakeOptional< + Pick< + TimeRangePickerToolbarProps, + 'ampm' | 'views' | 'onViewChange' | 'view' | 'toolbarPlaceholder' | 'toolbarVariant' + >, + 'view' +> & { + value: TDate | null; + utils: MuiPickersAdapter; + separatorClasses: string; +}; + +function TimeRangePickerToolbarTimeElement( + props: TimeRangePickerToolbarTimeElementProps, +) { + const { + value, + ampm, + views, + onViewChange, + view, + utils, + separatorClasses, + toolbarPlaceholder, + toolbarVariant, + } = props; + + const formatHours = (time: TDate) => + ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); + const meridiemMode = getMeridiem(value, utils); + const sectionWidth = toolbarVariant === 'desktop' ? 48 : '100%'; + + return ( + + {views.includes('hours') && ( + + onViewChange('hours')} + selected={view === 'hours'} + value={value ? formatHours(value) : toolbarPlaceholder} + /> + + onViewChange('minutes')} + selected={view === 'minutes' || (!views.includes('minutes') && view === 'hours')} + value={value ? utils.format(value, 'minutes') : toolbarPlaceholder} + disabled={!views.includes('minutes')} + /> + + )} + + {views.includes('seconds') && ( + + + onViewChange('seconds')} + selected={view === 'seconds'} + value={value ? utils.format(value, 'seconds') : toolbarPlaceholder} + /> + + )} + + {ampm && ( + onViewChange('meridiem')} + selected={view === 'meridiem'} + value={value && meridiemMode ? formatMeridiem(utils, meridiemMode) : toolbarPlaceholder} + width={sectionWidth} + /> + )} + + ); +} const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< TDate extends PickerValidDate, @@ -95,66 +191,40 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< value: [start, end], rangePosition, onRangePositionChange, - toolbarFormat, className, ampm, views, toolbarVariant = 'mobile', - toolbarPlaceholder = '--:--', + toolbarPlaceholder = '--', + onViewChange, + view, ...other } = props; const localeText = useLocaleText(); - const format = React.useMemo(() => { - if (toolbarFormat) { - return toolbarFormat; - } - - return resolveTimeFormat(utils, { format: undefined, ampm, views: views as TimeView[] }); - }, [utils, toolbarFormat, ampm, views]); - const ownerState = props; const classes = useUtilityClasses(ownerState); - if (toolbarVariant === 'desktop') { - const startDateValue = start ? utils.formatByString(start, format) : toolbarPlaceholder; - const endDateValue = end ? utils.formatByString(end, format) : toolbarPlaceholder; - - return ( - - - onRangePositionChange('start')} - /> - - - onRangePositionChange('end')} - /> - - - ); - } + const handleStartRangeViewChange = React.useCallback( + (newView: TimeViewWithMeridiem) => { + if (rangePosition !== 'start') { + onRangePositionChange('start'); + } + onViewChange(newView); + }, + [onRangePositionChange, onViewChange, rangePosition], + ); - const startDateValue = start ? utils.formatByString(start, format) : localeText.start; - const endDateValue = end ? utils.formatByString(end, format) : localeText.end; + const handleEndRangeViewChange = React.useCallback( + (newView: TimeViewWithMeridiem) => { + if (rangePosition !== 'end') { + onRangePositionChange('end'); + } + onViewChange(newView); + }, + [onRangePositionChange, onViewChange, rangePosition], + ); return ( - onRangePositionChange('start')} + -  {'–'}  - onRangePositionChange('end')} + diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts index 74e589afffa52..63d9869594cd2 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerToolbarClasses.ts @@ -8,6 +8,10 @@ export interface TimeRangePickerToolbarClasses { root: string; /** Styles applied to the container element. */ container: string; + /** Styles applied to the separator element. */ + separator: string; + /** Styles applied to the time container element. */ + timeContainer: string; } export type TimeRangePickerToolbarClassKey = keyof TimeRangePickerToolbarClasses; @@ -18,5 +22,5 @@ export function getTimeRangePickerToolbarUtilityClass(slot: string) { export const timeRangePickerToolbarClasses: TimeRangePickerToolbarClasses = generateUtilityClasses( 'MuiTimeRangePickerToolbar', - ['root', 'container'], + ['root', 'container', 'separator', 'timeContainer'], ); diff --git a/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx b/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx index f49ced45e02cc..6bced7b0fde70 100644 --- a/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersToolbarButton.tsx @@ -16,7 +16,7 @@ export interface PickersToolbarButtonProps extends ExtendMui; - width?: number; + width?: number | string; } const useUtilityClasses = (ownerState: PickersToolbarButtonProps) => { diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 5448722e20f76..23d352112bf13 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -24,6 +24,7 @@ export type { PickersToolbarButtonClassKey, PickersToolbarButtonClasses, } from './components/pickersToolbarButtonClasses'; +export { PickersToolbarText } from './components/PickersToolbarText'; export type { PickersToolbarTextProps, ExportedPickersToolbarTextProps, @@ -144,7 +145,7 @@ export { export { resolveTimeViewsResponse } from './utils/date-time-utils'; export { splitFieldInternalAndForwardedProps } from './utils/fields'; export { getDefaultReferenceDate } from './utils/getDefaultReferenceDate'; -export { isTimeView, isInternalTimeView, resolveTimeFormat } from './utils/time-utils'; +export { isTimeView, isInternalTimeView, resolveTimeFormat, getMeridiem } from './utils/time-utils'; export { resolveDateTimeFormat } from './utils/date-time-utils'; export { executeInTheNextEventLoopTick, From 5b88337a63d9f80a91aa39f105ab7082ac87a96b Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 22 May 2024 13:01:29 +0300 Subject: [PATCH 38/74] scripts --- .../api/date-pickers/time-range-picker-toolbar.json | 13 ++++++++++++- .../time-range-picker-toolbar.json | 11 +++++++++-- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 4 ---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index 0ac37346c0c3b..277e350744978 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -28,7 +28,6 @@ }, "additionalInfo": { "sx": true } }, - "toolbarFormat": { "type": { "name": "string" } }, "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"––\"" } }, "name": "TimeRangePickerToolbar", @@ -48,6 +47,18 @@ "className": "MuiTimeRangePickerToolbar-root", "description": "Styles applied to the root element.", "isGlobal": false + }, + { + "key": "separator", + "className": "MuiTimeRangePickerToolbar-separator", + "description": "Styles applied to the separator element.", + "isGlobal": false + }, + { + "key": "timeContainer", + "className": "MuiTimeRangePickerToolbar-timeContainer", + "description": "Styles applied to the time container element.", + "isGlobal": false } ], "muiName": "MuiTimeRangePickerToolbar", diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json index 6198bb709b0e6..5c4cf6beee932 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -10,7 +10,6 @@ "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, - "toolbarFormat": { "description": "Toolbar date format." }, "toolbarPlaceholder": { "description": "Toolbar value placeholder—it is displayed when the value is empty." }, @@ -22,6 +21,14 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the container element" }, - "root": { "description": "Styles applied to the root element." } + "root": { "description": "Styles applied to the root element." }, + "separator": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the separator element" + }, + "timeContainer": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the time container element" + } } } diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 177518c193e6c..8af9c1e5cd5f7 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -299,10 +299,6 @@ TimeRangePickerToolbar.propTypes = { PropTypes.object, ]), titleId: PropTypes.string, - /** - * Toolbar date format. - */ - toolbarFormat: PropTypes.string, /** * Toolbar value placeholder—it is displayed when the value is empty. * @default "––" From 2e9be2b049b61dcbafde734f40532d47e2ba9d6e Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 22 May 2024 13:10:17 +0300 Subject: [PATCH 39/74] Avoid the change in file --- .../MultiSectionDigitalClockSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx index aa9e881d853c7..cbc6a60df7a0b 100644 --- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx +++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx @@ -56,8 +56,8 @@ const MultiSectionDigitalClockSectionRoot = styled(MenuList, { ({ theme }) => ({ maxHeight: DIGITAL_CLOCK_VIEW_HEIGHT, width: 56, - overflow: 'hidden', padding: 0, + overflow: 'hidden', '@media (prefers-reduced-motion: no-preference)': { scrollBehavior: 'auto', }, From 5f2504d42ec13159b73aaa764f95e1b12c22f675 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 22 May 2024 14:35:01 +0300 Subject: [PATCH 40/74] Fix eslint --- .../date-pickers/time-range-picker/TimeRangePickerValue.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx index 5866b7e77bbf9..8c590ae31ab8f 100644 --- a/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx +++ b/docs/data/date-pickers/time-range-picker/TimeRangePickerValue.tsx @@ -3,7 +3,7 @@ import dayjs, { Dayjs } from 'dayjs'; import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { DateRange } from '@mui/x-date-pickers-pro'; +import { DateRange } from '@mui/x-date-pickers-pro/models'; import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; export default function TimeRangePickerValue() { From 7f6b2517f482ea5d1d95c26132540212abd27061 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 11 Sep 2024 18:36:57 +0300 Subject: [PATCH 41/74] Updates after latest changes --- .../DesktopTimeRangePicker.tsx | 12 ++++-------- .../MobileTimeRangePicker/MobileTimeRangePicker.tsx | 6 +++--- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 6 +++--- packages/x-date-pickers/src/internals/index.ts | 3 +-- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 7d4a92b996714..0c3e8456b51cb 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -1,13 +1,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { resolveComponentProps } from '@mui/base/utils'; +import resolveComponentProps from '@mui/utils/resolveComponentProps'; import { PickerValidDate } from '@mui/x-date-pickers/models'; -import { - extractValidationProps, - TimeViewWithMeridiem, - useUtils, - resolveTimeFormat, -} from '@mui/x-date-pickers/internals'; +import { TimeViewWithMeridiem, useUtils, resolveTimeFormat } from '@mui/x-date-pickers/internals'; +import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { @@ -16,7 +12,7 @@ import { } from '../TimeRangePicker/shared'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; -import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; +import { validateTimeRange } from '../validation/validateTimeRange'; import { renderDigitalClockTimeRangeView, renderMultiSectionDigitalClockTimeRangeView, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 37c95a67ef455..ad12cb1fa0ec1 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -4,7 +4,6 @@ import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DefaultizedProps, DIALOG_WIDTH, - extractValidationProps, isInternalTimeView, PickerViewRenderer, PickerViewsRendererProps, @@ -13,7 +12,7 @@ import { useUtils, VIEW_HEIGHT, } from '@mui/x-date-pickers/internals'; -import { resolveComponentProps } from '@mui/base/utils'; +import resolveComponentProps from '@mui/utils/resolveComponentProps'; import refType from '@mui/utils/refType'; import { multiSectionDigitalClockClasses, @@ -24,6 +23,7 @@ import { renderDigitalClockTimeView, renderMultiSectionDigitalClockTimeView, } from '@mui/x-date-pickers/timeViewRenderers'; +import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; import { @@ -35,7 +35,7 @@ import { useMobileRangePicker, UseMobileRangePickerProps, } from '../internals/hooks/useMobileRangePicker'; -import { validateTimeRange } from '../internals/utils/validation/validateTimeRange'; +import { validateTimeRange } from '../validation/validateTimeRange'; import { DateRange } from '../models'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeRangePickerTimeWrapper'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 8af9c1e5cd5f7..23ee3b56786e1 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -9,7 +9,6 @@ import { PickersToolbarButton, useUtils, BaseToolbarProps, - useLocaleText, ExportedBaseToolbarProps, WrapperVariant, TimeViewWithMeridiem, @@ -20,6 +19,7 @@ import { pickersToolbarClasses, pickersToolbarTextClasses, } from '@mui/x-date-pickers/internals'; +import { usePickersTranslations } from '@mui/x-date-pickers/hooks'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { TimeRangePickerToolbarClasses, @@ -201,7 +201,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< ...other } = props; - const localeText = useLocaleText(); + const translations = usePickersTranslations(); const ownerState = props; const classes = useUtilityClasses(ownerState); @@ -229,7 +229,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< return ( Date: Thu, 12 Sep 2024 10:04:50 +0300 Subject: [PATCH 42/74] buildRSC --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 1 + .../src/MobileTimeRangePicker/MobileTimeRangePicker.tsx | 1 + .../x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx | 1 + .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 0c3e8456b51cb..1425b31f3857d 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -1,3 +1,4 @@ +'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index ad12cb1fa0ec1..1ec0b53d61819 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -1,3 +1,4 @@ +'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import { PickerValidDate } from '@mui/x-date-pickers/models'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index b4ec08fe20d45..cf44162a6ebe7 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -1,3 +1,4 @@ +'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import useMediaQuery from '@mui/material/useMediaQuery'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 23ee3b56786e1..603c6c8b92e57 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -1,3 +1,4 @@ +'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; From fe949d6df517ba2ce5613ffcc8c70d9cd770de3a Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 19 Nov 2024 14:34:48 +0200 Subject: [PATCH 43/74] Remove `TDate` from new code --- .../DesktopTimeRangePicker.tsx | 21 ++---- .../DesktopTimeRangePicker.types.ts | 38 ++++------- .../MobileTimeRangePicker.tsx | 40 ++++-------- .../MobileTimeRangePicker.types.ts | 32 ++++----- .../src/TimeRangePicker/TimeRangePicker.tsx | 13 ++-- .../TimeRangePicker/TimeRangePicker.types.ts | 27 ++++---- .../TimeRangePickerToolbar.tsx | 39 ++++++----- .../src/TimeRangePicker/shared.tsx | 65 +++++++++---------- .../timeRangeViewRenderers.tsx | 51 ++++++++------- 9 files changed, 139 insertions(+), 187 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 1425b31f3857d..70538842c1c3c 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; -import { PickerValidDate } from '@mui/x-date-pickers/models'; import { TimeViewWithMeridiem, useUtils, resolveTimeFormat } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { rangeValueManager } from '../internals/utils/valueManagers'; @@ -19,34 +18,29 @@ import { renderMultiSectionDigitalClockTimeRangeView, } from '../timeRangeViewRenderers'; -type DesktopTimeRangePickerComponent = (< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, ->( - props: DesktopTimeRangePickerProps & +type DesktopTimeRangePickerComponent = (( + props: DesktopTimeRangePickerProps & React.RefAttributes, ) => React.JSX.Element) & { propTypes?: any }; const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, + TEnableAccessibleFieldDOMStructure extends boolean = true, >( - inProps: DesktopTimeRangePickerProps, + inProps: DesktopTimeRangePickerProps, ref: React.Ref, ) { - const utils = useUtils(); + const utils = useUtils(); // Props with the default values common to all date time pickers const defaultizedProps = useTimeRangePickerDefaultizedProps< - TDate, - DesktopTimeRangePickerProps + DesktopTimeRangePickerProps >(inProps, 'MuiDesktopTimeRangePicker'); const renderTimeRangeView = defaultizedProps.shouldRenderTimeInASingleColumn ? renderDigitalClockTimeRangeView : renderMultiSectionDigitalClockTimeRangeView; - const viewRenderers: TimeRangePickerRenderers = { + const viewRenderers: TimeRangePickerRenderers = { hours: renderTimeRangeView, minutes: renderTimeRangeView, seconds: renderTimeRangeView, @@ -87,7 +81,6 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }; const { renderPicker } = useDesktopRangePicker< - TDate, TimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure, typeof props diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts index 7fc6c041df6ec..7092b8b17e08a 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts @@ -1,9 +1,6 @@ -import { PickerValidDate, TimeView } from '@mui/x-date-pickers/models'; -import { - MakeOptional, - DesktopOnlyTimePickerProps, - TimeViewWithMeridiem, -} from '@mui/x-date-pickers/internals'; +import { MakeOptional } from '@mui/x-internals/types'; +import { TimeView } from '@mui/x-date-pickers/models'; +import { DesktopOnlyTimePickerProps, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { UseDesktopRangePickerSlots, UseDesktopRangePickerSlotProps, @@ -15,29 +12,22 @@ import { BaseTimeRangePickerSlotProps, } from '../TimeRangePicker/shared'; -export interface DesktopTimeRangePickerSlots - extends BaseTimeRangePickerSlots, - MakeOptional, 'field'> {} +export interface DesktopTimeRangePickerSlots + extends BaseTimeRangePickerSlots, + MakeOptional, 'field'> {} -export interface DesktopTimeRangePickerSlotProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean, -> extends BaseTimeRangePickerSlotProps, +export interface DesktopTimeRangePickerSlotProps + extends BaseTimeRangePickerSlotProps, Omit< - UseDesktopRangePickerSlotProps< - TDate, - TimeViewWithMeridiem, - TEnableAccessibleFieldDOMStructure - >, + UseDesktopRangePickerSlotProps, 'tabs' | 'toolbar' > {} export interface DesktopTimeRangePickerProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, -> extends BaseTimeRangePickerProps, + TEnableAccessibleFieldDOMStructure extends boolean = true, +> extends BaseTimeRangePickerProps, DesktopRangeOnlyPickerProps, - DesktopOnlyTimePickerProps { + DesktopOnlyTimePickerProps { /** * Available views. */ @@ -46,10 +36,10 @@ export interface DesktopTimeRangePickerProps< * Overridable component slots. * @default {} */ - slots?: DesktopTimeRangePickerSlots; + slots?: DesktopTimeRangePickerSlots; /** * The props used for each component slot. * @default {} */ - slotProps?: DesktopTimeRangePickerSlotProps; + slotProps?: DesktopTimeRangePickerSlotProps; } diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 1ec0b53d61819..40fc3f2143d18 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -1,11 +1,11 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { PickerValidDate } from '@mui/x-date-pickers/models'; +import { DefaultizedProps } from '@mui/x-internals/types'; import { - DefaultizedProps, DIALOG_WIDTH, isInternalTimeView, + PickerRangeValue, PickerViewRenderer, PickerViewsRendererProps, resolveTimeFormat, @@ -37,27 +37,19 @@ import { UseMobileRangePickerProps, } from '../internals/hooks/useMobileRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; -import { DateRange } from '../models'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeRangePickerTimeWrapper'; const rendererInterceptor = function rendererInterceptor< - TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean, >( - inViewRenderers: TimeRangePickerRenderers, + inViewRenderers: TimeRangePickerRenderers, popperView: TimeViewWithMeridiem, rendererProps: PickerViewsRendererProps< - DateRange, + PickerRangeValue, TimeViewWithMeridiem, DefaultizedProps< - UseMobileRangePickerProps< - TDate, - TimeViewWithMeridiem, - TEnableAccessibleFieldDOMStructure, - any, - any - >, + UseMobileRangePickerProps, 'rangePosition' | 'onRangePositionChange' | 'openTo' >, {} @@ -100,7 +92,7 @@ const rendererInterceptor = function rendererInterceptor< , TimeViewWithMeridiem, any, {}> + viewRenderer as PickerViewRenderer } view={view && isInternalTimeView(view) ? view : 'hours'} views={finalProps.views as TimeViewWithMeridiem[]} @@ -109,34 +101,29 @@ const rendererInterceptor = function rendererInterceptor< ); }; -type MobileTimeRangePickerComponent = (< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, ->( - props: MobileTimeRangePickerProps & +type MobileTimeRangePickerComponent = (( + props: MobileTimeRangePickerProps & React.RefAttributes, ) => React.JSX.Element) & { propTypes?: any }; const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, + TEnableAccessibleFieldDOMStructure extends boolean = true, >( - inProps: MobileTimeRangePickerProps, + inProps: MobileTimeRangePickerProps, ref: React.Ref, ) { - const utils = useUtils(); + const utils = useUtils(); // Props with the default values common to all date time pickers const defaultizedProps = useTimeRangePickerDefaultizedProps< - TDate, - MobileTimeRangePickerProps + MobileTimeRangePickerProps >(inProps, 'MuiMobileTimeRangePicker'); const renderTimeView = defaultizedProps.shouldRenderTimeInASingleColumn ? renderDigitalClockTimeView : renderMultiSectionDigitalClockTimeView; - const viewRenderers: TimeRangePickerRenderers = { + const viewRenderers: TimeRangePickerRenderers = { hours: renderTimeView, minutes: renderTimeView, seconds: renderTimeView, @@ -170,7 +157,6 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< }; const { renderPicker } = useMobileRangePicker< - TDate, TimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure, typeof props diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts index 32a3f6e1e5128..59f71d5ca3b0e 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts @@ -1,5 +1,5 @@ -import { PickerValidDate } from '@mui/x-date-pickers/models'; -import { MakeOptional, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; +import { MakeOptional } from '@mui/x-internals/types'; +import { TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { UseMobileRangePickerSlots, UseMobileRangePickerSlotProps, @@ -11,36 +11,28 @@ import { BaseTimeRangePickerSlotProps, } from '../TimeRangePicker/shared'; -export interface MobileTimeRangePickerSlots - extends BaseTimeRangePickerSlots, - MakeOptional, 'field'> {} +export interface MobileTimeRangePickerSlots + extends BaseTimeRangePickerSlots, + MakeOptional, 'field'> {} -export interface MobileTimeRangePickerSlotProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean, -> extends BaseTimeRangePickerSlotProps, +export interface MobileTimeRangePickerSlotProps + extends BaseTimeRangePickerSlotProps, Omit< - UseMobileRangePickerSlotProps< - TDate, - TimeViewWithMeridiem, - TEnableAccessibleFieldDOMStructure - >, + UseMobileRangePickerSlotProps, 'tabs' | 'toolbar' > {} -export interface MobileTimeRangePickerProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean, -> extends BaseTimeRangePickerProps, +export interface MobileTimeRangePickerProps + extends BaseTimeRangePickerProps, MobileRangeOnlyPickerProps { /** * Overridable component slots. * @default {} */ - slots?: MobileTimeRangePickerSlots; + slots?: MobileTimeRangePickerSlots; /** * The props used for each component slot. * @default {} */ - slotProps?: MobileTimeRangePickerSlotProps; + slotProps?: MobileTimeRangePickerSlotProps; } diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index cf44162a6ebe7..f22e41a36eac9 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -4,16 +4,12 @@ import PropTypes from 'prop-types'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useThemeProps } from '@mui/material/styles'; import refType from '@mui/utils/refType'; -import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopTimeRangePicker } from '../DesktopTimeRangePicker'; import { MobileTimeRangePicker } from '../MobileTimeRangePicker'; import { TimeRangePickerProps } from './TimeRangePicker.types'; -type TimePickerComponent = (< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, ->( - props: TimeRangePickerProps & +type TimePickerComponent = (( + props: TimeRangePickerProps & React.RefAttributes, ) => React.JSX.Element) & { propTypes?: any }; @@ -28,10 +24,9 @@ type TimePickerComponent = (< * - [TimeRangePicker API](https://mui.com/x/api/date-pickers/time-range-picker/) */ const TimeRangePicker = React.forwardRef(function TimeRangePicker< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, + TEnableAccessibleFieldDOMStructure extends boolean = true, >( - inProps: TimeRangePickerProps, + inProps: TimeRangePickerProps, ref: React.Ref, ) { const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePicker' }); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts index 51e6a799f7d84..de30676d8ab0d 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.types.ts @@ -1,4 +1,3 @@ -import { PickerValidDate } from '@mui/x-date-pickers/models'; import { DesktopTimeRangePickerProps, DesktopTimeRangePickerSlots, @@ -10,21 +9,17 @@ import { MobileTimeRangePickerSlotProps, } from '../MobileTimeRangePicker'; -export interface TimeRangePickerSlots - extends DesktopTimeRangePickerSlots, - MobileTimeRangePickerSlots {} +export interface TimeRangePickerSlots + extends DesktopTimeRangePickerSlots, + MobileTimeRangePickerSlots {} -export interface TimeRangePickerSlotProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean, -> extends DesktopTimeRangePickerSlotProps, - MobileTimeRangePickerSlotProps {} +export interface TimeRangePickerSlotProps + extends DesktopTimeRangePickerSlotProps, + MobileTimeRangePickerSlotProps {} -export interface TimeRangePickerProps< - TDate extends PickerValidDate, - TEnableAccessibleFieldDOMStructure extends boolean = false, -> extends DesktopTimeRangePickerProps, - Omit, 'views'> { +export interface TimeRangePickerProps + extends DesktopTimeRangePickerProps, + Omit, 'views'> { /** * CSS media query when `Mobile` mode will be changed to `Desktop`. * @default '@media (pointer: fine)' @@ -35,10 +30,10 @@ export interface TimeRangePickerProps< * Overridable component slots. * @default {} */ - slots?: TimeRangePickerSlots; + slots?: TimeRangePickerSlots; /** * The props used for each component slot. * @default {} */ - slotProps?: TimeRangePickerSlotProps; + slotProps?: TimeRangePickerSlotProps; } diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 603c6c8b92e57..fe37adfc7dbb9 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; +import { MakeOptional } from '@mui/x-internals/types'; import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { PickersToolbar, @@ -16,19 +17,18 @@ import { PickersToolbarText, getMeridiem, formatMeridiem, - MakeOptional, pickersToolbarClasses, pickersToolbarTextClasses, + PickerRangeValue, } from '@mui/x-date-pickers/internals'; -import { usePickersTranslations } from '@mui/x-date-pickers/hooks'; +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { TimeRangePickerToolbarClasses, getTimeRangePickerToolbarUtilityClass, } from './timeRangePickerToolbarClasses'; -import { DateRange } from '../models'; -const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { +const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { const { classes } = ownerState; const slots = { root: ['root'], @@ -40,8 +40,8 @@ const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { return composeClasses(slots, getTimeRangePickerToolbarUtilityClass, classes); }; -export interface TimeRangePickerToolbarProps - extends Omit, TimeViewWithMeridiem>, 'toolbarFormat'>, +export interface TimeRangePickerToolbarProps + extends Omit, 'toolbarFormat'>, Pick, ExportedTimeRangePickerToolbarProps { ampm: boolean; @@ -60,7 +60,7 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { name: 'MuiTimeRangePickerToolbar', slot: 'Root', overridesResolver: (_, styles) => styles.root, -})<{ ownerState: TimeRangePickerToolbarProps }>(({ theme }) => ({ +})<{ ownerState: TimeRangePickerToolbarProps }>(({ theme }) => ({ borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, padding: '12px 0px 8px 0px', [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: { @@ -101,21 +101,19 @@ const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { cursor: 'default', }); -type TimeRangePickerToolbarTimeElementProps = MakeOptional< +type TimeRangePickerToolbarTimeElementProps = MakeOptional< Pick< - TimeRangePickerToolbarProps, + TimeRangePickerToolbarProps, 'ampm' | 'views' | 'onViewChange' | 'view' | 'toolbarPlaceholder' | 'toolbarVariant' >, 'view' > & { - value: TDate | null; - utils: MuiPickersAdapter; + value: PickerValidDate | null; + utils: MuiPickersAdapter; separatorClasses: string; }; -function TimeRangePickerToolbarTimeElement( - props: TimeRangePickerToolbarTimeElementProps, -) { +function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElementProps) { const { value, ampm, @@ -128,7 +126,7 @@ function TimeRangePickerToolbarTimeElement( toolbarVariant, } = props; - const formatHours = (time: TDate) => + const formatHours = (time: PickerValidDate) => ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); const meridiemMode = getMeridiem(value, utils); const sectionWidth = toolbarVariant === 'desktop' ? 48 : '100%'; @@ -182,10 +180,11 @@ function TimeRangePickerToolbarTimeElement( ); } -const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< - TDate extends PickerValidDate, ->(inProps: TimeRangePickerToolbarProps, ref: React.Ref) { - const utils = useUtils(); +const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( + inProps: TimeRangePickerToolbarProps, + ref: React.Ref, +) { + const utils = useUtils(); const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); const { @@ -202,7 +201,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar< ...other } = props; - const translations = usePickersTranslations(); + const translations = usePickerTranslations(); const ownerState = props; const classes = useUtilityClasses(ownerState); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index f712fce8c4405..d45f813547b1c 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { useThemeProps } from '@mui/material/styles'; +import { DefaultizedProps } from '@mui/x-internals/types'; import { LocalizedComponent, PickersInputLocaleText } from '@mui/x-date-pickers/locales'; -import { PickerValidDate, TimeStepOptions, TimeView } from '@mui/x-date-pickers/models'; +import { TimeStepOptions, TimeView } from '@mui/x-date-pickers/models'; import { - DefaultizedProps, BasePickerInputProps, PickerViewRendererLookup, BaseTimeValidationProps, @@ -14,6 +14,7 @@ import { applyDefaultViewProps, resolveTimeViewsResponse, UseViewsOptions, + PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { TimeClockSlots, TimeClockSlotProps } from '@mui/x-date-pickers/TimeClock'; import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; @@ -22,14 +23,14 @@ import { TimeRangePickerToolbarProps, ExportedTimeRangePickerToolbarProps, } from './TimeRangePickerToolbar'; -import { DateRange, TimeRangeValidationError } from '../models'; +import { TimeRangeValidationError } from '../models'; -export interface BaseTimeRangePickerSlots extends TimeClockSlots { +export interface BaseTimeRangePickerSlots extends TimeClockSlots { /** * Custom component for the toolbar rendered above the views. * @default DateTimePickerToolbar */ - Toolbar?: React.JSXElementConstructor>; + Toolbar?: React.JSXElementConstructor; } export interface BaseTimeRangePickerSlotProps extends TimeClockSlotProps { @@ -37,30 +38,29 @@ export interface BaseTimeRangePickerSlotProps extends TimeClockSlotProps { } export type TimeRangePickerRenderers< - TDate extends PickerValidDate, TView extends TimeViewWithMeridiem, TAdditionalProps extends {} = {}, > = PickerViewRendererLookup< - DateRange, + PickerRangeValue, TView, - TimeViewRendererProps> & { + TimeViewRendererProps> & { view: TView; }, TAdditionalProps >; -export interface BaseTimeRangePickerProps +export interface BaseTimeRangePickerProps extends Omit< - BasePickerInputProps, TDate, TimeViewWithMeridiem, TimeRangeValidationError>, + BasePickerInputProps, 'orientation' | 'views' | 'openTo' >, - ExportedBaseClockProps, - Partial, TimeView>, 'openTo' | 'views'>> { + ExportedBaseClockProps, + Partial, 'openTo' | 'views'>> { /** * Overridable component slots. * @default {} */ - slots?: BaseTimeRangePickerSlots; + slots?: BaseTimeRangePickerSlots; /** * The props used for each component slot. * @default {} @@ -71,7 +71,7 @@ export interface BaseTimeRangePickerProps * If `null`, the section will only have field editing. * If `undefined`, internally defined view will be the used. */ - viewRenderers?: TimeRangePickerRenderers; + viewRenderers?: TimeRangePickerRenderers; /** * Amount of time options below or at which the single column time renderer is used. * @default 24 @@ -86,25 +86,22 @@ export interface BaseTimeRangePickerProps timeSteps?: TimeStepOptions; } -type UseTimeRangePickerDefaultizedProps< - TDate extends PickerValidDate, - Props extends BaseTimeRangePickerProps, -> = LocalizedComponent< - TDate, - Omit< - DefaultizedProps, - 'views' - > -> & { - shouldRenderTimeInASingleColumn: boolean; - views: readonly TimeViewWithMeridiem[]; -}; +type UseTimeRangePickerDefaultizedProps = + LocalizedComponent< + Omit< + DefaultizedProps, + 'views' + > + > & { + shouldRenderTimeInASingleColumn: boolean; + views: readonly TimeViewWithMeridiem[]; + }; -export function useTimeRangePickerDefaultizedProps< - TDate extends PickerValidDate, - Props extends BaseTimeRangePickerProps, ->(props: Props, name: string): UseTimeRangePickerDefaultizedProps { - const utils = useUtils(); +export function useTimeRangePickerDefaultizedProps( + props: Props, + name: string, +): UseTimeRangePickerDefaultizedProps { + const utils = useUtils(); const themeProps = useThemeProps({ props, @@ -119,7 +116,7 @@ export function useTimeRangePickerDefaultizedProps< defaultOpenTo: 'hours', }); - const localeText = React.useMemo | undefined>(() => { + const localeText = React.useMemo(() => { if (themeProps.localeText?.toolbarTitle == null) { return themeProps.localeText; } @@ -135,7 +132,7 @@ export function useTimeRangePickerDefaultizedProps< thresholdToRenderTimeInASingleColumn, views, timeSteps, - } = resolveTimeViewsResponse({ + } = resolveTimeViewsResponse({ thresholdToRenderTimeInASingleColumn: themeProps.thresholdToRenderTimeInASingleColumn, ampm, timeSteps: themeProps.timeSteps, diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index 0a8a7c6f4eb2e..bcc78c6e50273 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -4,6 +4,7 @@ import { TimeViewWithMeridiem, isTimeView, PickerSelectionState, + PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; import { @@ -13,23 +14,21 @@ import { import { TimeClock, TimeClockProps } from '@mui/x-date-pickers/TimeClock'; import { PickerValidDate, TimeView } from '@mui/x-date-pickers/models'; import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; -import { DateRange } from '../models'; import { UseRangePositionProps } from '../internals/hooks/useRangePosition'; export type TimeRangeViewRendererProps< - TDate extends PickerValidDate, TView extends TimeViewWithMeridiem, - TComponentProps extends Omit, 'value' | 'onChange'>, + TComponentProps extends Omit, 'value' | 'onChange'>, > = Omit & UseRangePositionProps & { - value: DateRange; - onChange: (value: DateRange, selectionState?: PickerSelectionState) => void; + value: PickerRangeValue; + onChange: (value: PickerRangeValue, selectionState?: PickerSelectionState) => void; view: TView; onViewChange?: (view: TView) => void; views: readonly TView[]; }; -export const renderTimeRangeViewClock = ({ +export const renderTimeRangeViewClock = ({ view, onViewChange, focusedView, @@ -60,14 +59,16 @@ export const renderTimeRangeViewClock = ({ rangePosition, onRangePositionChange, }: TimeRangeViewRendererProps< - TDate, TimeView, - Omit, 'value' | 'defaultValue' | 'onChange'> & - Pick, 'timeSteps'> + Omit, 'value' | 'defaultValue' | 'onChange'> & + Pick >) => { const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + const handleChange = ( + newValue: PickerValidDate | null, + selectionState?: PickerSelectionState, + ) => { if (selectionState === 'finish' && rangePosition === 'start') { onRangePositionChange?.('end'); onViewChange?.(views[0]); @@ -80,7 +81,7 @@ export const renderTimeRangeViewClock = ({ }; return ( - + ({ ); }; -export const renderDigitalClockTimeRangeView = ({ +export const renderDigitalClockTimeRangeView = ({ view, onViewChange, focusedView, @@ -143,14 +144,16 @@ export const renderDigitalClockTimeRangeView = ({ rangePosition, onRangePositionChange, }: TimeRangeViewRendererProps< - TDate, Extract, - Omit, 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & - Pick, 'timeSteps'> + Omit & + Pick >) => { const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + const handleChange = ( + newValue: PickerValidDate | null, + selectionState?: PickerSelectionState, + ) => { if (selectionState === 'finish' && rangePosition === 'start') { onRangePositionChange?.('end'); onViewChange?.(views[0]); @@ -163,7 +166,7 @@ export const renderDigitalClockTimeRangeView = ({ }; return ( - + ({ ); }; -export const renderMultiSectionDigitalClockTimeRangeView = ({ +export const renderMultiSectionDigitalClockTimeRangeView = ({ view, onViewChange, focusedView, @@ -226,14 +229,16 @@ export const renderMultiSectionDigitalClockTimeRangeView = , 'timeStep' | 'value' | 'defaultValue' | 'onChange'> & - Pick, 'timeSteps'> + Omit & + Pick >) => { const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - const handleChange = (newValue: TDate | null, selectionState?: PickerSelectionState) => { + const handleChange = ( + newValue: PickerValidDate | null, + selectionState?: PickerSelectionState, + ) => { if (selectionState === 'finish' && rangePosition === 'start') { onRangePositionChange?.('end'); onViewChange?.(views[0]); @@ -246,7 +251,7 @@ export const renderMultiSectionDigitalClockTimeRangeView = + Date: Tue, 19 Nov 2024 14:40:32 +0200 Subject: [PATCH 44/74] proptypes --- .../DesktopTimeRangePicker.tsx | 13 ++++-- .../MobileTimeRangePicker.tsx | 13 ++++-- .../src/TimeRangePicker/TimeRangePicker.tsx | 13 ++++-- .../TimeRangePickerToolbar.tsx | 42 +++++++++++++++++++ 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 70538842c1c3c..a5ab594475b5d 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -130,7 +130,8 @@ DesktopTimeRangePicker.propTypes = { */ defaultValue: PropTypes.arrayOf(PropTypes.object), /** - * If `true`, the picker and text field are disabled. + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. * @default false */ disabled: PropTypes.bool, @@ -155,7 +156,7 @@ DesktopTimeRangePicker.propTypes = { */ disablePast: PropTypes.bool, /** - * @default false + * @default true */ enableAccessibleFieldDOMStructure: PropTypes.any, /** @@ -277,6 +278,11 @@ DesktopTimeRangePicker.propTypes = { * Used when the component position is controlled. */ rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ readOnly: PropTypes.bool, /** * If `true`, disable heavy animations. @@ -314,8 +320,7 @@ DesktopTimeRangePicker.propTypes = { ]), /** * Disable specific time. - * @template TDate - * @param {TDate} value The value to check. + * @param {PickerValidDate} value The value to check. * @param {TimeView} view The clock type of the timeValue. * @returns {boolean} If `true` the time will be disabled. */ diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 40fc3f2143d18..0e67b02cc7ee3 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -206,7 +206,8 @@ MobileTimeRangePicker.propTypes = { */ defaultValue: PropTypes.arrayOf(PropTypes.object), /** - * If `true`, the picker and text field are disabled. + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. * @default false */ disabled: PropTypes.bool, @@ -231,7 +232,7 @@ MobileTimeRangePicker.propTypes = { */ disablePast: PropTypes.bool, /** - * @default false + * @default true */ enableAccessibleFieldDOMStructure: PropTypes.any, /** @@ -348,6 +349,11 @@ MobileTimeRangePicker.propTypes = { * Used when the component position is controlled. */ rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ readOnly: PropTypes.bool, /** * If `true`, disable heavy animations. @@ -385,8 +391,7 @@ MobileTimeRangePicker.propTypes = { ]), /** * Disable specific time. - * @template TDate - * @param {TDate} value The value to check. + * @param {PickerValidDate} value The value to check. * @param {TimeView} view The clock type of the timeValue. * @returns {boolean} If `true` the time will be disabled. */ diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index f22e41a36eac9..9d6494a65fc36 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -84,7 +84,8 @@ TimeRangePicker.propTypes = { */ desktopModeMediaQuery: PropTypes.string, /** - * If `true`, the picker and text field are disabled. + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. * @default false */ disabled: PropTypes.bool, @@ -109,7 +110,7 @@ TimeRangePicker.propTypes = { */ disablePast: PropTypes.bool, /** - * @default false + * @default true */ enableAccessibleFieldDOMStructure: PropTypes.any, /** @@ -226,6 +227,11 @@ TimeRangePicker.propTypes = { * Used when the component position is controlled. */ rangePosition: PropTypes.oneOf(['end', 'start']), + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ readOnly: PropTypes.bool, /** * If `true`, disable heavy animations. @@ -263,8 +269,7 @@ TimeRangePicker.propTypes = { ]), /** * Disable specific time. - * @template TDate - * @param {TDate} value The value to check. + * @param {PickerValidDate} value The value to check. * @param {TimeView} view The clock type of the timeValue. * @returns {boolean} If `true` the time will be disabled. */ diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index fe37adfc7dbb9..1b996fb9f7579 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -180,6 +180,38 @@ function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElem ); } +TimeRangePickerToolbarTimeElement.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + ampm: PropTypes.bool.isRequired, + /** + * Callback called when a toolbar is clicked + * @template TView + * @param {TView} view The view to open + */ + onViewChange: PropTypes.func.isRequired, + separatorClasses: PropTypes.string.isRequired, + /** + * Toolbar value placeholder—it is displayed when the value is empty. + * @default "––" + */ + toolbarPlaceholder: PropTypes.node, + toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), + utils: PropTypes.object.isRequired, + value: PropTypes.object, + /** + * Currently visible picker view. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), + /** + * Available views. + */ + views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired) + .isRequired, +} as any; + const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( inProps: TimeRangePickerToolbarProps, ref: React.Ref, @@ -273,6 +305,11 @@ TimeRangePickerToolbar.propTypes = { */ classes: PropTypes.object, className: PropTypes.string, + /** + * If `true`, the component is disabled. + * When disabled, the value cannot be changed and no interaction is possible. + * @default false + */ disabled: PropTypes.bool, /** * If `true`, show the toolbar even in desktop mode. @@ -289,6 +326,11 @@ TimeRangePickerToolbar.propTypes = { */ onViewChange: PropTypes.func.isRequired, rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, + /** + * If `true`, the component is read-only. + * When read-only, the value cannot be changed but the user can interact with the interface. + * @default false + */ readOnly: PropTypes.bool, /** * The system prop that allows defining system overrides as well as additional CSS styles. From 38c75333c595b265a1974589ab158722e78afe52 Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 19 Nov 2024 14:47:35 +0200 Subject: [PATCH 45/74] docs:api --- .../x/api/date-pickers/desktop-time-range-picker.json | 3 ++- .../pages/x/api/date-pickers/mobile-time-range-picker.json | 3 ++- .../x/api/date-pickers/time-range-picker-toolbar.json | 2 ++ docs/pages/x/api/date-pickers/time-range-picker.json | 3 ++- .../desktop-time-range-picker.json | 7 ++++++- .../mobile-time-range-picker/mobile-time-range-picker.json | 7 ++++++- .../time-range-picker-toolbar.json | 6 ++++++ .../date-pickers/time-range-picker/time-range-picker.json | 7 ++++++- 8 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 74a020213a4e4..693703f802ca7 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -79,6 +79,7 @@ } }, "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, "reduceAnimations": { "type": { "name": "bool" }, "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" @@ -96,7 +97,7 @@ "shouldDisableTime": { "type": { "name": "func" }, "signature": { - "type": "function(value: TDate, view: TimeView) => boolean", + "type": "function(value: PickerValidDate, view: TimeView) => boolean", "describedArgs": ["value", "view"], "returned": "boolean" } diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index 4418ea7e010dd..c9df6a7057859 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -77,6 +77,7 @@ } }, "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, "reduceAnimations": { "type": { "name": "bool" }, "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" @@ -94,7 +95,7 @@ "shouldDisableTime": { "type": { "name": "func" }, "signature": { - "type": "function(value: TDate, view: TimeView) => boolean", + "type": "function(value: PickerValidDate, view: TimeView) => boolean", "describedArgs": ["value", "view"], "returned": "boolean" } diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index 277e350744978..d46ec7d696c10 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -20,7 +20,9 @@ "required": true }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "disabled": { "type": { "name": "bool" }, "default": "false" }, "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, "sx": { "type": { "name": "union", diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index e74b9800b4f97..77f151fc714b5 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -81,6 +81,7 @@ } }, "rangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" } }, + "readOnly": { "type": { "name": "bool" }, "default": "false" }, "reduceAnimations": { "type": { "name": "bool" }, "default": "`@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13" @@ -98,7 +99,7 @@ "shouldDisableTime": { "type": { "name": "func" }, "signature": { - "type": "function(value: TDate, view: TimeView) => boolean", + "type": "function(value: PickerValidDate, view: TimeView) => boolean", "describedArgs": ["value", "view"], "returned": "boolean" } diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json index 229b2b2d410a3..c310fc581e299 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json @@ -14,7 +14,9 @@ "defaultValue": { "description": "The default value. Used when the component is not controlled." }, - "disabled": { "description": "If true, the picker and text field are disabled." }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, "disableFuture": { "description": "If true, disable values after the current date for date components, time for time components and both for date time components." }, @@ -96,6 +98,9 @@ "rangePosition": { "description": "The position in the currently edited date range. Used when the component position is controlled." }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, "reduceAnimations": { "description": "If true, disable heavy animations." }, "referenceDate": { "description": "The date used to generate the new value when both value and defaultValue are empty." diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json index b1a36be7ca796..d470e89cd7c6a 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json @@ -14,7 +14,9 @@ "defaultValue": { "description": "The default value. Used when the component is not controlled." }, - "disabled": { "description": "If true, the picker and text field are disabled." }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, "disableFuture": { "description": "If true, disable values after the current date for date components, time for time components and both for date time components." }, @@ -96,6 +98,9 @@ "rangePosition": { "description": "The position in the currently edited date range. Used when the component position is controlled." }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, "reduceAnimations": { "description": "If true, disable heavy animations." }, "referenceDate": { "description": "The date used to generate the new value when both value and defaultValue are empty." diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json index 5c4cf6beee932..2c05f75bd26e4 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -2,11 +2,17 @@ "componentDescription": "", "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, "hidden": { "description": "If true, show the toolbar even in desktop mode." }, "onViewChange": { "description": "Callback called when a toolbar is clicked", "typeDescriptions": { "view": "The view to open" } }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, diff --git a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json index dcbf98f499a8e..3b3c49e4309cf 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json @@ -17,7 +17,9 @@ "desktopModeMediaQuery": { "description": "CSS media query when Mobile mode will be changed to Desktop." }, - "disabled": { "description": "If true, the picker and text field are disabled." }, + "disabled": { + "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." + }, "disableFuture": { "description": "If true, disable values after the current date for date components, time for time components and both for date time components." }, @@ -99,6 +101,9 @@ "rangePosition": { "description": "The position in the currently edited date range. Used when the component position is controlled." }, + "readOnly": { + "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." + }, "reduceAnimations": { "description": "If true, disable heavy animations." }, "referenceDate": { "description": "The date used to generate the new value when both value and defaultValue are empty." From fa6c40c3dab8fcefede062166873980fe42ba2a2 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 20 Nov 2024 11:51:00 +0200 Subject: [PATCH 46/74] Add tabs component --- .../time-range-picker/time-range-picker.md | 2 +- docs/data/datePickersApiPages.ts | 5 + .../desktop-time-range-picker.json | 20 +- docs/pages/x/api/date-pickers/index.md | 7 + .../mobile-time-range-picker.json | 20 +- .../date-pickers/time-range-picker-tabs.js | 23 +++ .../date-pickers/time-range-picker-tabs.json | 53 +++++ .../x/api/date-pickers/time-range-picker.json | 20 +- .../desktop-time-range-picker.json | 3 + .../mobile-time-range-picker.json | 3 + .../time-range-picker-tabs.json | 20 ++ .../time-range-picker/time-range-picker.json | 3 + .../DesktopTimeRangePicker.tsx | 4 + .../MobileTimeRangePicker.tsx | 4 + .../TimeRangePicker/TimeRangePickerTabs.tsx | 187 ++++++++++++++++++ .../src/TimeRangePicker/index.ts | 12 ++ .../src/TimeRangePicker/shared.tsx | 35 +++- .../timeRangePickerTabsClasses.ts | 22 +++ scripts/x-date-pickers-pro.exports.json | 6 + 19 files changed, 442 insertions(+), 7 deletions(-) create mode 100644 docs/pages/x/api/date-pickers/time-range-picker-tabs.js create mode 100644 docs/pages/x/api/date-pickers/time-range-picker-tabs.json create mode 100644 docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/timeRangePickerTabsClasses.ts diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 63fd21cc29811..4c18ddd971ebb 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -1,7 +1,7 @@ --- productId: x-date-pickers title: React Time Range Picker component -components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, DigitalClock, MultiSectionDigitalClock, TimeRangePickerToolbar +components: TimeRangePicker, DesktopTimeRangePicker, MobileTimeRangePicker, DigitalClock, MultiSectionDigitalClock, TimeRangePickerTabs, TimeRangePickerToolbar githubLabel: 'component: TimeRangePicker' packageName: '@mui/x-date-pickers-pro' materialDesign: https://m2.material.io/components/date-pickers diff --git a/docs/data/datePickersApiPages.ts b/docs/data/datePickersApiPages.ts index 197b12bd64a4b..1efe4f86c55e0 100644 --- a/docs/data/datePickersApiPages.ts +++ b/docs/data/datePickersApiPages.ts @@ -243,6 +243,11 @@ const datePickersApiPages: MuiPage[] = [ title: 'TimeRangePicker', plan: 'pro', }, + { + pathname: '/x/api/date-pickers/time-range-picker-tabs', + title: 'TimeRangePickerTabs', + plan: 'pro', + }, { pathname: '/x/api/date-pickers/time-range-picker-toolbar', title: 'TimeRangePickerToolbar', diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index 693703f802ca7..b0cf669df5427 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -194,6 +194,18 @@ "default": "TrapFocus from '@mui/material'.", "class": null }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, { "name": "field", "description": "", "class": null }, { "name": "fieldRoot", @@ -246,6 +258,12 @@ "default": "PickersShortcuts", "class": null }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, { "name": "textField", "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", @@ -255,7 +273,7 @@ { "name": "Toolbar", "description": "Custom component for the toolbar rendered above the views.", - "default": "DateTimePickerToolbar", + "default": "TimeRangePickerToolbar", "class": null } ], diff --git a/docs/pages/x/api/date-pickers/index.md b/docs/pages/x/api/date-pickers/index.md index b7a2c00147dd9..0dce17dad6513 100644 --- a/docs/pages/x/api/date-pickers/index.md +++ b/docs/pages/x/api/date-pickers/index.md @@ -34,6 +34,12 @@ - [MobileDateRangePicker](/x/api/date-pickers/mobile-date-range-picker/) - [StaticDateRangePicker](/x/api/date-pickers/static-date-range-picker/) +#### Time Range Pickers + +- [TimeRangePicker](/x/api/date-pickers/time-range-picker/) +- [DesktopTimeRangePicker](/x/api/date-pickers/desktop-time-range-picker/) +- [MobileTimeRangePicker](/x/api/date-pickers/mobile-time-range-picker/) + #### Date Time Range Pickers - [DateTimeRangePicker](/x/api/date-pickers/date-time-range-picker/) @@ -77,6 +83,7 @@ - [DateRangePickerDay](/x/api/date-pickers/date-range-picker-day/) - [DateTimePickerTabs](/x/api/date-pickers/date-time-picker-tabs/) +- [TimeRangePickerTabs](/x/api/date-pickers/time-range-picker-tabs/) - [DateTimeRangePickerTabs](/x/api/date-pickers/date-time-range-picker-tabs/) - [DayCalendarSkeleton](/x/api/date-pickers/day-calendar-skeleton/) - [LocalizationProvider](/x/api/date-pickers/localization-provider/) diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index c9df6a7057859..a4cd5c5019327 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -179,6 +179,18 @@ "default": "PickersModalDialogRoot", "class": null }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, { "name": "field", "description": "", "class": null }, { "name": "fieldRoot", @@ -237,6 +249,12 @@ "default": "PickersShortcuts", "class": null }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, { "name": "textField", "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", @@ -246,7 +264,7 @@ { "name": "Toolbar", "description": "Custom component for the toolbar rendered above the views.", - "default": "DateTimePickerToolbar", + "default": "TimeRangePickerToolbar", "class": null } ], diff --git a/docs/pages/x/api/date-pickers/time-range-picker-tabs.js b/docs/pages/x/api/date-pickers/time-range-picker-tabs.js new file mode 100644 index 0000000000000..da2c4d34521e4 --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-tabs.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './time-range-picker-tabs.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docsx/translations/api-docs/date-pickers/time-range-picker-tabs', + false, + /\.\/time-range-picker-tabs.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/x/api/date-pickers/time-range-picker-tabs.json b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json new file mode 100644 index 0000000000000..0edf37a297a8a --- /dev/null +++ b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json @@ -0,0 +1,53 @@ +{ + "props": { + "onViewChange": { + "type": { "name": "func" }, + "required": true, + "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } + }, + "view": { + "type": { + "name": "enum", + "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" + }, + "required": true + }, + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "hidden": { + "type": { "name": "bool" }, + "default": "`window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker`" + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
        | object
        | bool>
        | func
        | object" + }, + "additionalInfo": { "sx": true } + }, + "timeIcon": { "type": { "name": "node" }, "default": "Time" } + }, + "name": "TimeRangePickerTabs", + "imports": [ + "import { TimeRangePickerTabs } from '@mui/x-date-pickers-pro/TimeRangePicker';", + "import { TimeRangePickerTabs } from '@mui/x-date-pickers-pro';" + ], + "classes": [ + { + "key": "root", + "className": "MuiTimeRangePickerTabs-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "tab", + "className": "MuiTimeRangePickerTabs-tab", + "description": "Styles applied to the tab element.", + "isGlobal": false + } + ], + "muiName": "MuiTimeRangePickerTabs", + "filename": "/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index 77f151fc714b5..e381143ccfdc7 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -202,6 +202,18 @@ "default": "PickersModalDialogRoot", "class": null }, + { + "name": "digitalClockItem", + "description": "Component responsible for rendering a single digital clock item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, + { + "name": "digitalClockSectionItem", + "description": "Component responsible for rendering a single multi section digital clock section item.", + "default": "MenuItem from '@mui/material'", + "class": null + }, { "name": "field", "description": "", "class": null }, { "name": "fieldRoot", @@ -266,6 +278,12 @@ "default": "PickersShortcuts", "class": null }, + { + "name": "tabs", + "description": "Tabs enabling toggling between start and end time.", + "default": "TimeRangePickerTabs", + "class": null + }, { "name": "textField", "description": "Form control with an input to render a date or time inside the default field.\nIt is rendered twice: once for the start element and once for the end element.", @@ -275,7 +293,7 @@ { "name": "Toolbar", "description": "Custom component for the toolbar rendered above the views.", - "default": "DateTimePickerToolbar", + "default": "TimeRangePickerToolbar", "class": null } ], diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json index c310fc581e299..93e5bf6955bbd 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json @@ -151,6 +151,8 @@ "desktopPaper": "Custom component for the paper rendered inside the desktop picker's Popper.", "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", "field": "", "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", @@ -161,6 +163,7 @@ "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", "Toolbar": "Custom component for the toolbar rendered above the views." } diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json index d470e89cd7c6a..fe0588fba5984 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json @@ -146,6 +146,8 @@ "clearButton": "Button to clear the value.", "clearIcon": "Icon to display inside the clear button.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", "field": "", "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", @@ -157,6 +159,7 @@ "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", "Toolbar": "Custom component for the toolbar rendered above the views." } diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json new file mode 100644 index 0000000000000..9ea9191d315d8 --- /dev/null +++ b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json @@ -0,0 +1,20 @@ +{ + "componentDescription": "", + "propDescriptions": { + "classes": { "description": "Override or extend the styles applied to the component." }, + "hidden": { "description": "Toggles visibility of the tabs allowing view switching." }, + "onViewChange": { + "description": "Callback called when a tab is clicked.", + "typeDescriptions": { "view": "The view to open" } + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles." + }, + "timeIcon": { "description": "Time tab icon." }, + "view": { "description": "Currently visible picker view." } + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "tab": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the tab element" } + } +} diff --git a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json index 3b3c49e4309cf..0b61862bc5539 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json @@ -155,6 +155,8 @@ "desktopTransition": "Custom component for the desktop popper Transition.", "desktopTrapFocus": "Custom component for trapping the focus inside the views on desktop.", "dialog": "Custom component for the dialog inside which the views are rendered on mobile.", + "digitalClockItem": "Component responsible for rendering a single digital clock item.", + "digitalClockSectionItem": "Component responsible for rendering a single multi section digital clock section item.", "field": "", "fieldRoot": "Element rendered at the root. Ignored if the field has only one input.", "fieldSeparator": "Element rendered between the two inputs. Ignored if the field has only one input.", @@ -167,6 +169,7 @@ "previousIconButton": "Button allowing to switch to the left view.", "rightArrowIcon": "Icon displayed in the right view switch button.", "shortcuts": "Custom component for the shortcuts.", + "tabs": "Tabs enabling toggling between start and end time.", "textField": "Form control with an input to render a date or time inside the default field. It is rendered twice: once for the start element and once for the end element.", "Toolbar": "Custom component for the toolbar rendered above the views." } diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index a5ab594475b5d..bc43e71fbd9ff 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -71,6 +71,10 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< ...extractValidationProps(defaultizedProps), ref, }), + tabs: { + hidden: true, + ...defaultizedProps.slotProps?.tabs, + }, toolbar: { hidden: true, toolbarVariant: 'desktop', diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 0e67b02cc7ee3..96481074e55f3 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -148,6 +148,10 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< ...extractValidationProps(defaultizedProps), ref, }), + tabs: { + hidden: false, + ...defaultizedProps.slotProps?.tabs, + }, toolbar: { hidden: false, toolbarVariant: 'mobile', diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx new file mode 100644 index 0000000000000..8d0b4356d5e87 --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx @@ -0,0 +1,187 @@ +'use client'; +import * as React from 'react'; +import clsx from 'clsx'; +import PropTypes from 'prop-types'; +import Tab from '@mui/material/Tab'; +import Tabs, { tabsClasses } from '@mui/material/Tabs'; +import { styled, useThemeProps } from '@mui/material/styles'; +import composeClasses from '@mui/utils/composeClasses'; +import { TimeIcon } from '@mui/x-date-pickers/icons'; +import { + BaseTabsProps, + ExportedBaseTabsProps, + TimeViewWithMeridiem, +} from '@mui/x-date-pickers/internals'; +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { + TimeRangePickerTabsClasses, + getTimeRangePickerTabsUtilityClass, +} from './timeRangePickerTabsClasses'; +import { RangePosition } from '../models'; +import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; + +export interface ExportedTimeRangePickerTabsProps extends ExportedBaseTabsProps { + /** + * Toggles visibility of the tabs allowing view switching. + * @default `window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker` + */ + hidden?: boolean; + /** + * Time tab icon. + * @default Time + */ + timeIcon?: React.ReactNode; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; +} + +export interface TimeRangePickerTabsProps + extends ExportedTimeRangePickerTabsProps, + BaseTabsProps, + Pick {} + +const useUtilityClasses = (ownerState: TimeRangePickerTabsProps) => { + const { classes } = ownerState; + const slots = { + root: ['root'], + tab: ['tab'], + }; + + return composeClasses(slots, getTimeRangePickerTabsUtilityClass, classes); +}; + +const TimeRangePickerTabsRoot = styled(Tabs, { + name: 'MuiTimeRangePickerTabs', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})<{ ownerState: TimeRangePickerTabsProps }>(({ theme }) => ({ + boxShadow: `0 -1px 0 0 inset ${(theme.vars || theme).palette.divider}`, + '&:last-child': { + boxShadow: `0 1px 0 0 inset ${(theme.vars || theme).palette.divider}`, + [`& .${tabsClasses.indicator}`]: { + bottom: 'auto', + top: 0, + }, + }, +})); + +const TimeRangePickerTab = styled(Tab, { + name: 'MuiTimeRangePickerTabs', + slot: 'Tab', + overridesResolver: (_, styles) => styles.tab, +})(({ theme }) => ({ + minHeight: '48px', + gap: theme.spacing(1), +})); + +/** + * Demos: + * + * - [TimeRangePicker](https://mui.com/x/react-date-pickers/time-range-picker/) + * - [Custom slots and subcomponents](https://mui.com/x/react-date-pickers/custom-components/) + * + * API: + * + * - [TimeRangePickerTabs API](https://mui.com/x/api/date-pickers/time-range-picker-tabs/) + */ +const TimeRangePickerTabs = function TimeRangePickerTabs(inProps: TimeRangePickerTabsProps) { + const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerTabs' }); + const { + view, + onViewChange, + timeIcon = , + rangePosition, + onRangePositionChange, + hidden = typeof window === 'undefined' || window.innerHeight < 667, + className, + sx, + } = props; + + const translations = usePickerTranslations(); + const classes = useUtilityClasses(props); + + const handleChange = (event: React.SyntheticEvent, value: RangePosition) => { + if (rangePosition !== value) { + onRangePositionChange(value); + } + if (view !== 'hours') { + onViewChange('hours'); + } + }; + + if (hidden) { + return null; + } + + return ( + + {timeIcon}} + label={translations.start} + className={classes.tab} + /> + {timeIcon}} + className={classes.tab} + /> + + ); +}; + +TimeRangePickerTabs.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + className: PropTypes.string, + /** + * Toggles visibility of the tabs allowing view switching. + * @default `window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker` + */ + hidden: PropTypes.bool, + onRangePositionChange: PropTypes.func.isRequired, + /** + * Callback called when a tab is clicked. + * @template TView + * @param {TView} view The view to open + */ + onViewChange: PropTypes.func.isRequired, + rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Time tab icon. + * @default Time + */ + timeIcon: PropTypes.node, + /** + * Currently visible picker view. + */ + view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired, +} as any; + +export { TimeRangePickerTabs }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts index 6852c98e6faff..09dc5b5ca9bbf 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/index.ts @@ -5,6 +5,18 @@ export type { TimeRangePickerSlotProps, } from './TimeRangePicker.types'; +export { TimeRangePickerTabs } from './TimeRangePickerTabs'; +export type { ExportedTimeRangePickerTabsProps } from './TimeRangePickerTabs'; + +export { + getTimeRangePickerTabsUtilityClass, + timeRangePickerTabsClasses, +} from './timeRangePickerTabsClasses'; +export type { + TimeRangePickerTabsClasses, + TimeRangePickerTabsClassKey, +} from './timeRangePickerTabsClasses'; + export { TimeRangePickerToolbar } from './TimeRangePickerToolbar'; export type { TimeRangePickerToolbarProps } from './TimeRangePickerToolbar'; export { timeRangePickerToolbarClasses } from './timeRangePickerToolbarClasses'; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx index d45f813547b1c..c819319af7544 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/shared.tsx @@ -17,6 +17,11 @@ import { PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { TimeClockSlots, TimeClockSlotProps } from '@mui/x-date-pickers/TimeClock'; +import { DigitalClockSlots, DigitalClockSlotProps } from '@mui/x-date-pickers/DigitalClock'; +import { + MultiSectionDigitalClockSlots, + MultiSectionDigitalClockSlotProps, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; import { TimeViewRendererProps } from '@mui/x-date-pickers/timeViewRenderers'; import { TimeRangePickerToolbar, @@ -24,16 +29,39 @@ import { ExportedTimeRangePickerToolbarProps, } from './TimeRangePickerToolbar'; import { TimeRangeValidationError } from '../models'; +import { + ExportedTimeRangePickerTabsProps, + TimeRangePickerTabs, + TimeRangePickerTabsProps, +} from './TimeRangePickerTabs'; -export interface BaseTimeRangePickerSlots extends TimeClockSlots { +export interface BaseTimeRangePickerSlots + extends TimeClockSlots, + DigitalClockSlots, + MultiSectionDigitalClockSlots { + /** + * Tabs enabling toggling between start and end time. + * @default TimeRangePickerTabs + */ + tabs?: React.ElementType; /** * Custom component for the toolbar rendered above the views. - * @default DateTimePickerToolbar + * @default TimeRangePickerToolbar */ Toolbar?: React.JSXElementConstructor; } -export interface BaseTimeRangePickerSlotProps extends TimeClockSlotProps { +export interface BaseTimeRangePickerSlotProps + extends TimeClockSlotProps, + DigitalClockSlotProps, + MultiSectionDigitalClockSlotProps { + /** + * Props passed down to the tabs component. + */ + tabs?: ExportedTimeRangePickerTabsProps; + /** + * Props passed down to the toolbar component. + */ toolbar?: ExportedTimeRangePickerToolbarProps; } @@ -151,6 +179,7 @@ export function useTimeRangePickerDefaultizedProps Date: Wed, 20 Nov 2024 16:58:15 +0200 Subject: [PATCH 47/74] Remove unused labels --- docs/data/date-pickers/localization/data.json | 148 +++++++++--------- packages/x-date-pickers/src/locales/beBY.ts | 4 - packages/x-date-pickers/src/locales/bgBG.ts | 4 - packages/x-date-pickers/src/locales/caES.ts | 4 - packages/x-date-pickers/src/locales/csCZ.ts | 4 - packages/x-date-pickers/src/locales/daDK.ts | 4 - packages/x-date-pickers/src/locales/deDE.ts | 4 - packages/x-date-pickers/src/locales/elGR.ts | 4 - packages/x-date-pickers/src/locales/enUS.ts | 4 - packages/x-date-pickers/src/locales/esES.ts | 4 - packages/x-date-pickers/src/locales/eu.ts | 4 - packages/x-date-pickers/src/locales/faIR.ts | 4 - packages/x-date-pickers/src/locales/fiFI.ts | 4 - packages/x-date-pickers/src/locales/frFR.ts | 4 - packages/x-date-pickers/src/locales/heIL.ts | 4 - packages/x-date-pickers/src/locales/hrHR.ts | 4 - packages/x-date-pickers/src/locales/huHU.ts | 4 - packages/x-date-pickers/src/locales/isIS.ts | 4 - packages/x-date-pickers/src/locales/itIT.ts | 4 - packages/x-date-pickers/src/locales/jaJP.ts | 4 - packages/x-date-pickers/src/locales/koKR.ts | 4 - packages/x-date-pickers/src/locales/kzKZ.ts | 4 - packages/x-date-pickers/src/locales/mk.ts | 4 - packages/x-date-pickers/src/locales/nbNO.ts | 4 - packages/x-date-pickers/src/locales/nlNL.ts | 4 - packages/x-date-pickers/src/locales/nnNO.ts | 4 - packages/x-date-pickers/src/locales/plPL.ts | 4 - packages/x-date-pickers/src/locales/ptBR.ts | 4 - packages/x-date-pickers/src/locales/ptPT.ts | 4 - packages/x-date-pickers/src/locales/roRO.ts | 4 - packages/x-date-pickers/src/locales/ruRU.ts | 4 - packages/x-date-pickers/src/locales/skSK.ts | 4 - packages/x-date-pickers/src/locales/svSE.ts | 4 - packages/x-date-pickers/src/locales/trTR.ts | 4 - packages/x-date-pickers/src/locales/ukUA.ts | 4 - packages/x-date-pickers/src/locales/urPK.ts | 4 - .../src/locales/utils/pickersLocaleTextApi.ts | 4 - packages/x-date-pickers/src/locales/viVN.ts | 4 - packages/x-date-pickers/src/locales/zhCN.ts | 4 - packages/x-date-pickers/src/locales/zhHK.ts | 4 - 40 files changed, 74 insertions(+), 230 deletions(-) diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index 244f9ec0fcc7b..9bfcbc35ed8d1 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -3,296 +3,296 @@ "languageTag": "eu", "importName": "eu", "localeName": "Basque", - "missingKeysCount": 16, - "totalKeysCount": 53, + "missingKeysCount": 14, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/eu.ts" }, { "languageTag": "be-BY", "importName": "beBY", "localeName": "Belarusian", - "missingKeysCount": 18, - "totalKeysCount": 53, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/beBY.ts" }, { "languageTag": "bg-BG", "importName": "bgBG", "localeName": "Bulgarian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/bgBG.ts" }, { "languageTag": "ca-ES", "importName": "caES", "localeName": "Catalan", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/caES.ts" }, { "languageTag": "zh-HK", "importName": "zhHK", "localeName": "Chinese (Hong Kong)", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhHK.ts" }, { "languageTag": "zh-CN", "importName": "zhCN", "localeName": "Chinese (Simplified)", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhCN.ts" }, { "languageTag": "hr-HR", "importName": "hrHR", "localeName": "Croatian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/hrHR.ts" }, { "languageTag": "cs-CZ", "importName": "csCZ", "localeName": "Czech", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/csCZ.ts" }, { "languageTag": "da-DK", "importName": "daDK", "localeName": "Danish", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/daDK.ts" }, { "languageTag": "nl-NL", "importName": "nlNL", "localeName": "Dutch", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nlNL.ts" }, { "languageTag": "fi-FI", "importName": "fiFI", "localeName": "Finnish", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/fiFI.ts" }, { "languageTag": "fr-FR", "importName": "frFR", "localeName": "French", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/frFR.ts" }, { "languageTag": "de-DE", "importName": "deDE", "localeName": "German", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/deDE.ts" }, { "languageTag": "el-GR", "importName": "elGR", "localeName": "Greek", - "missingKeysCount": 9, - "totalKeysCount": 53, + "missingKeysCount": 7, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/elGR.ts" }, { "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/heIL.ts" }, { "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/huHU.ts" }, { "languageTag": "is-IS", "importName": "isIS", "localeName": "Icelandic", - "missingKeysCount": 17, - "totalKeysCount": 53, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/isIS.ts" }, { "languageTag": "it-IT", "importName": "itIT", "localeName": "Italian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/itIT.ts" }, { "languageTag": "ja-JP", "importName": "jaJP", "localeName": "Japanese", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/jaJP.ts" }, { "languageTag": "kz-KZ", "importName": "kzKZ", "localeName": "Kazakh", - "missingKeysCount": 18, - "totalKeysCount": 53, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/kzKZ.ts" }, { "languageTag": "ko-KR", "importName": "koKR", "localeName": "Korean", - "missingKeysCount": 4, - "totalKeysCount": 53, + "missingKeysCount": 2, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/koKR.ts" }, { "languageTag": "mk", "importName": "mk", "localeName": "Macedonian", - "missingKeysCount": 16, - "totalKeysCount": 53, + "missingKeysCount": 14, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/mk.ts" }, { "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 17, - "totalKeysCount": 53, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nbNO.ts" }, { "languageTag": "nn-NO", "importName": "nnNO", "localeName": "Norwegian (Nynorsk)", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/nnNO.ts" }, { "languageTag": "fa-IR", "importName": "faIR", "localeName": "Persian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/faIR.ts" }, { "languageTag": "pl-PL", "importName": "plPL", "localeName": "Polish", - "missingKeysCount": 13, - "totalKeysCount": 53, + "missingKeysCount": 11, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/plPL.ts" }, { "languageTag": "pt-PT", "importName": "ptPT", "localeName": "Portuguese", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptPT.ts" }, { "languageTag": "pt-BR", "importName": "ptBR", "localeName": "Portuguese (Brazil)", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ptBR.ts" }, { "languageTag": "ro-RO", "importName": "roRO", "localeName": "Romanian", - "missingKeysCount": 17, - "totalKeysCount": 53, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/roRO.ts" }, { "languageTag": "ru-RU", "importName": "ruRU", "localeName": "Russian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ruRU.ts" }, { "languageTag": "sk-SK", "importName": "skSK", "localeName": "Slovak", - "missingKeysCount": 18, - "totalKeysCount": 53, + "missingKeysCount": 16, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/skSK.ts" }, { "languageTag": "es-ES", "importName": "esES", "localeName": "Spanish", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/esES.ts" }, { "languageTag": "sv-SE", "importName": "svSE", "localeName": "Swedish", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/svSE.ts" }, { "languageTag": "tr-TR", "importName": "trTR", "localeName": "Turkish", - "missingKeysCount": 17, - "totalKeysCount": 53, + "missingKeysCount": 15, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/trTR.ts" }, { "languageTag": "uk-UA", "importName": "ukUA", "localeName": "Ukrainian", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/ukUA.ts" }, { "languageTag": "ur-PK", "importName": "urPK", "localeName": "Urdu (Pakistan)", - "missingKeysCount": 25, - "totalKeysCount": 53, + "missingKeysCount": 23, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/urPK.ts" }, { "languageTag": "vi-VN", "importName": "viVN", "localeName": "Vietnamese", - "missingKeysCount": 3, - "totalKeysCount": 53, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/viVN.ts" } ] diff --git a/packages/x-date-pickers/src/locales/beBY.ts b/packages/x-date-pickers/src/locales/beBY.ts index c287c7e249de2..a7cfb3d61bc5b 100644 --- a/packages/x-date-pickers/src/locales/beBY.ts +++ b/packages/x-date-pickers/src/locales/beBY.ts @@ -31,10 +31,6 @@ const beBYPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Адмена', clearButtonLabel: 'Ачысціць', diff --git a/packages/x-date-pickers/src/locales/bgBG.ts b/packages/x-date-pickers/src/locales/bgBG.ts index 1ea51440ac815..06e69784550d5 100644 --- a/packages/x-date-pickers/src/locales/bgBG.ts +++ b/packages/x-date-pickers/src/locales/bgBG.ts @@ -30,10 +30,6 @@ const bgBGPickers: Partial = { endDate: 'Крайна дата', endTime: 'Краен час', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Отказ', clearButtonLabel: 'Изчисти', diff --git a/packages/x-date-pickers/src/locales/caES.ts b/packages/x-date-pickers/src/locales/caES.ts index 9619400367752..73f3a2a1b614a 100644 --- a/packages/x-date-pickers/src/locales/caES.ts +++ b/packages/x-date-pickers/src/locales/caES.ts @@ -30,10 +30,6 @@ const caESPickers: Partial = { endDate: 'Data final', endTime: 'Hora final', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Cancel·lar', clearButtonLabel: 'Netejar', diff --git a/packages/x-date-pickers/src/locales/csCZ.ts b/packages/x-date-pickers/src/locales/csCZ.ts index 8459f72b68aaa..5127d2dbe7eb6 100644 --- a/packages/x-date-pickers/src/locales/csCZ.ts +++ b/packages/x-date-pickers/src/locales/csCZ.ts @@ -31,10 +31,6 @@ const csCZPickers: Partial = { endDate: 'Datum konce', endTime: 'Čas konce', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Zrušit', clearButtonLabel: 'Vymazat', diff --git a/packages/x-date-pickers/src/locales/daDK.ts b/packages/x-date-pickers/src/locales/daDK.ts index f250ed668e311..f788b8e41ad08 100644 --- a/packages/x-date-pickers/src/locales/daDK.ts +++ b/packages/x-date-pickers/src/locales/daDK.ts @@ -31,10 +31,6 @@ const daDKPickers: Partial = { endDate: 'Slut date', endTime: 'Slut tid', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Annuller', clearButtonLabel: 'Ryd', diff --git a/packages/x-date-pickers/src/locales/deDE.ts b/packages/x-date-pickers/src/locales/deDE.ts index 8e393c4ad6cc7..b7b664653f312 100644 --- a/packages/x-date-pickers/src/locales/deDE.ts +++ b/packages/x-date-pickers/src/locales/deDE.ts @@ -31,10 +31,6 @@ const deDEPickers: Partial = { endDate: 'Enddatum', endTime: 'Endzeit', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Abbrechen', clearButtonLabel: 'Löschen', diff --git a/packages/x-date-pickers/src/locales/elGR.ts b/packages/x-date-pickers/src/locales/elGR.ts index a4a4a58e79525..b7812c487ce6f 100644 --- a/packages/x-date-pickers/src/locales/elGR.ts +++ b/packages/x-date-pickers/src/locales/elGR.ts @@ -30,10 +30,6 @@ const elGRPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Άκυρο', clearButtonLabel: 'Καθαρισμός', diff --git a/packages/x-date-pickers/src/locales/enUS.ts b/packages/x-date-pickers/src/locales/enUS.ts index 42a835e3e6bfb..48b69a7b98745 100644 --- a/packages/x-date-pickers/src/locales/enUS.ts +++ b/packages/x-date-pickers/src/locales/enUS.ts @@ -24,10 +24,6 @@ const enUSPickers: PickersLocaleText = { endDate: 'End date', endTime: 'End time', - // Generic range placeholders - from: 'From', - to: 'To', - // Action bar cancelButtonLabel: 'Cancel', clearButtonLabel: 'Clear', diff --git a/packages/x-date-pickers/src/locales/esES.ts b/packages/x-date-pickers/src/locales/esES.ts index 647cfb71b684c..a36f79e35a046 100644 --- a/packages/x-date-pickers/src/locales/esES.ts +++ b/packages/x-date-pickers/src/locales/esES.ts @@ -30,10 +30,6 @@ const esESPickers: Partial = { endDate: 'Fecha final', endTime: 'Hora final', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Cancelar', clearButtonLabel: 'Limpiar', diff --git a/packages/x-date-pickers/src/locales/eu.ts b/packages/x-date-pickers/src/locales/eu.ts index 687a4ef4bcd32..55748271d8533 100644 --- a/packages/x-date-pickers/src/locales/eu.ts +++ b/packages/x-date-pickers/src/locales/eu.ts @@ -30,10 +30,6 @@ const euPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Utxi', clearButtonLabel: 'Garbitu', diff --git a/packages/x-date-pickers/src/locales/faIR.ts b/packages/x-date-pickers/src/locales/faIR.ts index f5a28b55469be..a3b70e0ed696f 100644 --- a/packages/x-date-pickers/src/locales/faIR.ts +++ b/packages/x-date-pickers/src/locales/faIR.ts @@ -30,10 +30,6 @@ const faIRPickers: Partial = { endDate: 'تاریخ پایان', endTime: 'ساعت پایان', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'لغو', clearButtonLabel: 'پاک کردن', diff --git a/packages/x-date-pickers/src/locales/fiFI.ts b/packages/x-date-pickers/src/locales/fiFI.ts index 73f4976c7626e..cb0652d571ea7 100644 --- a/packages/x-date-pickers/src/locales/fiFI.ts +++ b/packages/x-date-pickers/src/locales/fiFI.ts @@ -30,10 +30,6 @@ const fiFIPickers: Partial = { endDate: 'Päättymispäivämäärä', endTime: 'Päättymisaika', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Peruuta', clearButtonLabel: 'Tyhjennä', diff --git a/packages/x-date-pickers/src/locales/frFR.ts b/packages/x-date-pickers/src/locales/frFR.ts index aa1abaae1c704..587dde7fcca4e 100644 --- a/packages/x-date-pickers/src/locales/frFR.ts +++ b/packages/x-date-pickers/src/locales/frFR.ts @@ -30,10 +30,6 @@ const frFRPickers: Partial = { endDate: 'Date de fin', endTime: 'Heure de fin', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Annuler', clearButtonLabel: 'Vider', diff --git a/packages/x-date-pickers/src/locales/heIL.ts b/packages/x-date-pickers/src/locales/heIL.ts index d3c69491a2624..00d6c8af6a4c6 100644 --- a/packages/x-date-pickers/src/locales/heIL.ts +++ b/packages/x-date-pickers/src/locales/heIL.ts @@ -30,10 +30,6 @@ const heILPickers: Partial = { endDate: 'תאריך סיום', endTime: 'שעת סיום', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'ביטול', clearButtonLabel: 'ניקוי', diff --git a/packages/x-date-pickers/src/locales/hrHR.ts b/packages/x-date-pickers/src/locales/hrHR.ts index d4fcd5f8a787c..83300d32fce02 100644 --- a/packages/x-date-pickers/src/locales/hrHR.ts +++ b/packages/x-date-pickers/src/locales/hrHR.ts @@ -31,10 +31,6 @@ const hrHRPickers: Partial = { endDate: 'Krajnji datum', endTime: 'Krajnje vrijeme', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Otkaži', clearButtonLabel: 'Izbriši', diff --git a/packages/x-date-pickers/src/locales/huHU.ts b/packages/x-date-pickers/src/locales/huHU.ts index 4e02d55e52698..69af4f171d4c0 100644 --- a/packages/x-date-pickers/src/locales/huHU.ts +++ b/packages/x-date-pickers/src/locales/huHU.ts @@ -31,10 +31,6 @@ const huHUPickers: Partial = { endDate: 'Záró dátum', endTime: 'Záró idő', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Mégse', clearButtonLabel: 'Törlés', diff --git a/packages/x-date-pickers/src/locales/isIS.ts b/packages/x-date-pickers/src/locales/isIS.ts index e48ca23b0197b..0d92255eb2efd 100644 --- a/packages/x-date-pickers/src/locales/isIS.ts +++ b/packages/x-date-pickers/src/locales/isIS.ts @@ -30,10 +30,6 @@ const isISPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Hætta við', clearButtonLabel: 'Hreinsa', diff --git a/packages/x-date-pickers/src/locales/itIT.ts b/packages/x-date-pickers/src/locales/itIT.ts index 7f7534960dfc3..0401cf0063288 100644 --- a/packages/x-date-pickers/src/locales/itIT.ts +++ b/packages/x-date-pickers/src/locales/itIT.ts @@ -30,10 +30,6 @@ const itITPickers: Partial = { endDate: 'Data di fine', endTime: 'Ora di fine', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Cancellare', clearButtonLabel: 'Sgomberare', diff --git a/packages/x-date-pickers/src/locales/jaJP.ts b/packages/x-date-pickers/src/locales/jaJP.ts index 66175ef07968a..5fbc7edea4920 100644 --- a/packages/x-date-pickers/src/locales/jaJP.ts +++ b/packages/x-date-pickers/src/locales/jaJP.ts @@ -31,10 +31,6 @@ const jaJPPickers: Partial = { endDate: '終了日', endTime: '終了時間', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'キャンセル', clearButtonLabel: 'クリア', diff --git a/packages/x-date-pickers/src/locales/koKR.ts b/packages/x-date-pickers/src/locales/koKR.ts index aba5ac659ec99..91f1e66a6c9d7 100644 --- a/packages/x-date-pickers/src/locales/koKR.ts +++ b/packages/x-date-pickers/src/locales/koKR.ts @@ -30,10 +30,6 @@ const koKRPickers: Partial = { endDate: '종료 날짜', endTime: '종료 시간', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: '취소', clearButtonLabel: '초기화', diff --git a/packages/x-date-pickers/src/locales/kzKZ.ts b/packages/x-date-pickers/src/locales/kzKZ.ts index 79de6014e79f4..eaa3b51a23367 100644 --- a/packages/x-date-pickers/src/locales/kzKZ.ts +++ b/packages/x-date-pickers/src/locales/kzKZ.ts @@ -31,10 +31,6 @@ const kzKZPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Бас тарту', clearButtonLabel: 'Тазарту', diff --git a/packages/x-date-pickers/src/locales/mk.ts b/packages/x-date-pickers/src/locales/mk.ts index aa9d2ef728112..889135808d6d8 100644 --- a/packages/x-date-pickers/src/locales/mk.ts +++ b/packages/x-date-pickers/src/locales/mk.ts @@ -24,10 +24,6 @@ const mkPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Откажи', clearButtonLabel: 'Избриши', diff --git a/packages/x-date-pickers/src/locales/nbNO.ts b/packages/x-date-pickers/src/locales/nbNO.ts index e04b8754d2be6..ecac71f08bb82 100644 --- a/packages/x-date-pickers/src/locales/nbNO.ts +++ b/packages/x-date-pickers/src/locales/nbNO.ts @@ -30,10 +30,6 @@ const nbNOPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Avbryt', clearButtonLabel: 'Fjern', diff --git a/packages/x-date-pickers/src/locales/nlNL.ts b/packages/x-date-pickers/src/locales/nlNL.ts index 89833eb1d3b68..47ec22b0f591e 100644 --- a/packages/x-date-pickers/src/locales/nlNL.ts +++ b/packages/x-date-pickers/src/locales/nlNL.ts @@ -30,10 +30,6 @@ const nlNLPickers: Partial = { endDate: 'Eind datum', endTime: 'Eind tijd', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Annuleren', clearButtonLabel: 'Resetten', diff --git a/packages/x-date-pickers/src/locales/nnNO.ts b/packages/x-date-pickers/src/locales/nnNO.ts index 3d3258b0daf97..5a12527d59a6b 100644 --- a/packages/x-date-pickers/src/locales/nnNO.ts +++ b/packages/x-date-pickers/src/locales/nnNO.ts @@ -30,10 +30,6 @@ const nnNOPickers: Partial = { endDate: 'Sluttdato', endTime: 'Slutttid', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Avbryt', clearButtonLabel: 'Fjern', diff --git a/packages/x-date-pickers/src/locales/plPL.ts b/packages/x-date-pickers/src/locales/plPL.ts index 228d56b556185..7baa52e28520c 100644 --- a/packages/x-date-pickers/src/locales/plPL.ts +++ b/packages/x-date-pickers/src/locales/plPL.ts @@ -30,10 +30,6 @@ const plPLPickers: Partial = { endDate: 'Data zakończenia', endTime: 'Czas zakończenia', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Anuluj', clearButtonLabel: 'Wyczyść', diff --git a/packages/x-date-pickers/src/locales/ptBR.ts b/packages/x-date-pickers/src/locales/ptBR.ts index 2e9839ec7f4af..2cfa858d0d290 100644 --- a/packages/x-date-pickers/src/locales/ptBR.ts +++ b/packages/x-date-pickers/src/locales/ptBR.ts @@ -30,10 +30,6 @@ const ptBRPickers: Partial = { endDate: 'Data de Término', endTime: 'Hora de Término', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Cancelar', clearButtonLabel: 'Limpar', diff --git a/packages/x-date-pickers/src/locales/ptPT.ts b/packages/x-date-pickers/src/locales/ptPT.ts index f6fc7568d4891..9ed9e5776f4e0 100644 --- a/packages/x-date-pickers/src/locales/ptPT.ts +++ b/packages/x-date-pickers/src/locales/ptPT.ts @@ -30,10 +30,6 @@ const ptPTPickers: Partial = { endDate: 'Data de fim', endTime: 'Hora de fim', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Cancelar', clearButtonLabel: 'Limpar', diff --git a/packages/x-date-pickers/src/locales/roRO.ts b/packages/x-date-pickers/src/locales/roRO.ts index dc223f5a1b9b9..0779a73477f45 100644 --- a/packages/x-date-pickers/src/locales/roRO.ts +++ b/packages/x-date-pickers/src/locales/roRO.ts @@ -31,10 +31,6 @@ const roROPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Anulare', clearButtonLabel: 'Ștergere', diff --git a/packages/x-date-pickers/src/locales/ruRU.ts b/packages/x-date-pickers/src/locales/ruRU.ts index d7106b250e6d0..d5f06e5b3e1f6 100644 --- a/packages/x-date-pickers/src/locales/ruRU.ts +++ b/packages/x-date-pickers/src/locales/ruRU.ts @@ -31,10 +31,6 @@ const ruRUPickers: Partial = { endDate: 'Конечная дата', endTime: 'Конечное время', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Отмена', clearButtonLabel: 'Очистить', diff --git a/packages/x-date-pickers/src/locales/skSK.ts b/packages/x-date-pickers/src/locales/skSK.ts index 541447de551fe..e2867ad8f561d 100644 --- a/packages/x-date-pickers/src/locales/skSK.ts +++ b/packages/x-date-pickers/src/locales/skSK.ts @@ -31,10 +31,6 @@ const skSKPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Zrušiť', clearButtonLabel: 'Vymazať', diff --git a/packages/x-date-pickers/src/locales/svSE.ts b/packages/x-date-pickers/src/locales/svSE.ts index 169ae67d48c1d..2dee9203e83d4 100644 --- a/packages/x-date-pickers/src/locales/svSE.ts +++ b/packages/x-date-pickers/src/locales/svSE.ts @@ -30,10 +30,6 @@ const svSEPickers: Partial = { endDate: 'Slutdatum', endTime: 'Sluttid', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Avbryt', clearButtonLabel: 'Rensa', diff --git a/packages/x-date-pickers/src/locales/trTR.ts b/packages/x-date-pickers/src/locales/trTR.ts index 28dba17b6969b..ed7a8bb6235b7 100644 --- a/packages/x-date-pickers/src/locales/trTR.ts +++ b/packages/x-date-pickers/src/locales/trTR.ts @@ -30,10 +30,6 @@ const trTRPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'iptal', clearButtonLabel: 'Temizle', diff --git a/packages/x-date-pickers/src/locales/ukUA.ts b/packages/x-date-pickers/src/locales/ukUA.ts index fe6f3d4769182..c896564b76139 100644 --- a/packages/x-date-pickers/src/locales/ukUA.ts +++ b/packages/x-date-pickers/src/locales/ukUA.ts @@ -30,10 +30,6 @@ const ukUAPickers: Partial = { endDate: 'День закінчення', endTime: 'Час закінчення', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Відміна', clearButtonLabel: 'Очистити', diff --git a/packages/x-date-pickers/src/locales/urPK.ts b/packages/x-date-pickers/src/locales/urPK.ts index 604fdefd9ed9d..e1c5a328f591d 100644 --- a/packages/x-date-pickers/src/locales/urPK.ts +++ b/packages/x-date-pickers/src/locales/urPK.ts @@ -30,10 +30,6 @@ const urPKPickers: Partial = { // endDate: 'End date', // endTime: 'End time', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'کینسل', clearButtonLabel: 'کلئیر', diff --git a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts index d6dd4a60d5ab0..b7582e073ff94 100644 --- a/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts +++ b/packages/x-date-pickers/src/locales/utils/pickersLocaleTextApi.ts @@ -53,10 +53,6 @@ export interface PickersComponentAgnosticLocaleText { endDate: string; endTime: string; - // Generic range placeholders - from: string; - to: string; - // Action bar cancelButtonLabel: string; clearButtonLabel: string; diff --git a/packages/x-date-pickers/src/locales/viVN.ts b/packages/x-date-pickers/src/locales/viVN.ts index 2ecf99ad9525c..740e4b34a030b 100644 --- a/packages/x-date-pickers/src/locales/viVN.ts +++ b/packages/x-date-pickers/src/locales/viVN.ts @@ -30,10 +30,6 @@ const viVNPickers: Partial = { endDate: 'Ngày kết thúc', endTime: 'Thời gian kết thúc', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: 'Hủy', clearButtonLabel: 'Xóa', diff --git a/packages/x-date-pickers/src/locales/zhCN.ts b/packages/x-date-pickers/src/locales/zhCN.ts index 71ca46d884ecd..1b278453849f2 100644 --- a/packages/x-date-pickers/src/locales/zhCN.ts +++ b/packages/x-date-pickers/src/locales/zhCN.ts @@ -28,10 +28,6 @@ const zhCNPickers: Partial = { endDate: '结束日期', endTime: '结束时间', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: '取消', clearButtonLabel: '清除', diff --git a/packages/x-date-pickers/src/locales/zhHK.ts b/packages/x-date-pickers/src/locales/zhHK.ts index 41af719dabca6..43bc4c879b43a 100644 --- a/packages/x-date-pickers/src/locales/zhHK.ts +++ b/packages/x-date-pickers/src/locales/zhHK.ts @@ -28,10 +28,6 @@ const zhHKPickers: Partial = { endDate: '結束日期', endTime: '結束時間', - // Generic range placeholders - // from: 'From', - // to: 'To', - // Action bar cancelButtonLabel: '取消', clearButtonLabel: '清除', From 01381707f1437874996392f3c2346e0211bc5de5 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 20 Nov 2024 17:57:51 +0200 Subject: [PATCH 48/74] Use 2 column layout on desktop --- .../DesktopTimeRangePicker.tsx | 85 ++++++++++++++++++- .../TimeRangePickerToolbar.tsx | 32 +++++-- .../useDesktopRangePicker.tsx | 7 +- .../useDesktopRangePicker.types.ts | 9 +- .../internals/components/PickersToolbar.tsx | 2 + .../components/pickersToolbarClasses.ts | 3 + .../x-date-pickers/src/internals/index.ts | 7 +- 7 files changed, 120 insertions(+), 25 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index bc43e71fbd9ff..2d50ca57e76cd 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -2,8 +2,22 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; -import { TimeViewWithMeridiem, useUtils, resolveTimeFormat } from '@mui/x-date-pickers/internals'; +import { DefaultizedProps } from '@mui/x-internals/types'; +import { + TimeViewWithMeridiem, + useUtils, + resolveTimeFormat, + PickerViewsRendererProps, + PickerRangeValue, +} from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; +import Divider from '@mui/material/Divider'; +import { + multiSectionDigitalClockClasses, + multiSectionDigitalClockSectionClasses, +} from '@mui/x-date-pickers/MultiSectionDigitalClock'; +import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; +import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { @@ -11,12 +25,76 @@ import { useTimeRangePickerDefaultizedProps, } from '../TimeRangePicker/shared'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; -import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; +import { + useDesktopRangePicker, + UseDesktopRangePickerProps, +} from '../internals/hooks/useDesktopRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; import { renderDigitalClockTimeRangeView, renderMultiSectionDigitalClockTimeRangeView, } from '../timeRangeViewRenderers'; +import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; + +const rendererInterceptor = function rendererInterceptor< + TEnableAccessibleFieldDOMStructure extends boolean, +>( + inViewRenderers: TimeRangePickerRenderers, + popperView: TimeViewWithMeridiem, + rendererProps: PickerViewsRendererProps< + PickerRangeValue, + TimeViewWithMeridiem, + DefaultizedProps< + Omit< + UseDesktopRangePickerProps< + TimeViewWithMeridiem, + TEnableAccessibleFieldDOMStructure, + any, + any + >, + 'onChange' | 'sx' | 'className' + >, + 'rangePosition' | 'onRangePositionChange' | 'openTo' + >, + {} + >, +) { + const { openTo, rangePosition, focusedView, ...otherProps } = rendererProps; + const finalProps = { + ...otherProps, + focusedView: null, + rangePosition, + sx: [ + { + [`&.${multiSectionDigitalClockClasses.root}`]: { + borderBottom: 0, + }, + [`&.${multiSectionDigitalClockClasses.root}, .${multiSectionDigitalClockSectionClasses.root}, &.${digitalClockClasses.root}`]: + { + maxHeight: RANGE_VIEW_HEIGHT, + }, + }, + ], + }; + const viewRenderer = inViewRenderers[popperView]; + return ( + + {viewRenderer?.({ + ...finalProps, + view: popperView, + rangePosition: 'start', + sx: [{ gridColumn: 1 }, ...finalProps.sx], + })} + + {viewRenderer?.({ + ...finalProps, + view: popperView, + rangePosition: 'end', + sx: [{ gridColumn: 3 }, ...finalProps.sx], + })} + + ); +}; type DesktopTimeRangePickerComponent = (( props: DesktopTimeRangePickerProps & @@ -62,6 +140,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< format: resolveTimeFormat(utils, defaultizedProps), slots: { field: MultiInputTimeRangeField, + layout: DesktopDateTimePickerLayout, ...defaultizedProps.slots, }, slotProps: { @@ -93,7 +172,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< valueManager: rangeValueManager, valueType: 'time', validator: validateTimeRange, - shouldMovePopperToFocusedInput: true, + rendererInterceptor, }); return renderPicker(); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 1b996fb9f7579..5d2d33d98edd6 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -20,6 +20,7 @@ import { pickersToolbarClasses, pickersToolbarTextClasses, PickerRangeValue, + MULTI_SECTION_CLOCK_SECTION_WIDTH, } from '@mui/x-date-pickers/internals'; import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; @@ -29,10 +30,10 @@ import { } from './timeRangePickerToolbarClasses'; const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { - const { classes } = ownerState; + const { classes, toolbarVariant } = ownerState; const slots = { root: ['root'], - container: ['container'], + container: ['container', toolbarVariant], separator: ['separator'], timeContainer: ['timeContainer'], }; @@ -67,7 +68,7 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { color: (theme.vars || theme).palette.primary.main, fontWeight: theme.typography.fontWeightBold, }, - '& > :first-child': { + [`& .${pickersToolbarClasses.title}`]: { paddingLeft: 12, }, })); @@ -75,12 +76,26 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { const TimeRangePickerToolbarContainer = styled('div', { name: 'MuiTimeRangePickerToolbar', slot: 'Container', + shouldForwardProp: (prop) => prop !== 'toolbarVariant', overridesResolver: (_, styles) => styles.container, -})({ +})<{ toolbarVariant: WrapperVariant }>({ display: 'flex', - flexDirection: 'column', flex: 1, rowGap: 8, + variants: [ + { + props: { toolbarVariant: 'mobile' }, + style: { + flexDirection: 'column', + }, + }, + { + props: { toolbarVariant: 'desktop' }, + style: { + flexDirection: 'row', + }, + }, + ], }); const TimeRangePickerToolbarTimeContainer = styled('div', { @@ -129,7 +144,7 @@ function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElem const formatHours = (time: PickerValidDate) => ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); const meridiemMode = getMeridiem(value, utils); - const sectionWidth = toolbarVariant === 'desktop' ? 48 : '100%'; + const sectionWidth = toolbarVariant === 'desktop' ? MULTI_SECTION_CLOCK_SECTION_WIDTH : '100%'; return ( @@ -266,7 +281,10 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( ownerState={ownerState} ref={ref} > - + , >({ props, - shouldMovePopperToFocusedInput, ...pickerParams }: UseDesktopRangePickerParams) => { useLicenseVerifier('x-date-pickers-pro', releaseInfo); @@ -211,11 +210,7 @@ export const useDesktopRangePicker = < role="tooltip" placement="bottom-start" containerRef={popperRef} - anchorEl={ - shouldMovePopperToFocusedInput && rangePosition === 'end' - ? anchorRefEndDate.current - : anchorRef.current - } + anchorEl={anchorRef.current} onBlur={handleBlur} {...actions} open={open} diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts index de832b1bb846b..3b49eff80e25b 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.types.ts @@ -64,11 +64,4 @@ export interface UseDesktopRangePickerParams< any, TExternalProps >, -> extends UseRangePickerParams { - /** - * If `true`, the popper will always be aligned on the currently focused input. - * This is helpful when the view only renders information about one of the dates. - * @default false - */ - shouldMovePopperToFocusedInput?: boolean; -} +> extends UseRangePickerParams {} diff --git a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx index 47a6e0fa53da0..ce04855f91337 100644 --- a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx @@ -19,6 +19,7 @@ const useUtilityClasses = (ownerState: PickersToolbarProps) => { const { classes, isLandscape } = ownerState; const slots = { root: ['root'], + title: ['title'], content: ['content'], penIconButton: ['penIconButton', isLandscape && 'penIconButtonLandscape'], }; @@ -129,6 +130,7 @@ export const PickersToolbar = React.forwardRef(function PickersToolbar< color="text.secondary" variant="overline" id={titleId} + className={classes.title} > {toolbarTitle} diff --git a/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts b/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts index 09ecae7d30cee..ed84de81ef44d 100644 --- a/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts +++ b/packages/x-date-pickers/src/internals/components/pickersToolbarClasses.ts @@ -6,6 +6,8 @@ import { export interface PickersToolbarClasses { /** Styles applied to the root element. */ root: string; + /** Styles applied to the title element. */ + title: string; /** Styles applied to the content element. */ content: string; } @@ -18,5 +20,6 @@ export function getPickersToolbarUtilityClass(slot: string) { export const pickersToolbarClasses = generateUtilityClasses('MuiPickersToolbar', [ 'root', + 'title', 'content', ]); diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index bdd25ccf53d81..b806f44a6cd11 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -48,7 +48,12 @@ export type { } from './components/pickersPopperClasses'; export { PickersToolbarButton } from './components/PickersToolbarButton'; -export { DAY_MARGIN, DIALOG_WIDTH, VIEW_HEIGHT } from './constants/dimensions'; +export { + DAY_MARGIN, + DIALOG_WIDTH, + VIEW_HEIGHT, + MULTI_SECTION_CLOCK_SECTION_WIDTH, +} from './constants/dimensions'; export { useControlledValueWithTimezone } from './hooks/useValueWithTimezone'; export type { DesktopOnlyPickerProps } from './hooks/useDesktopPicker'; From 03894b1c4e58c9cc6bbfb28d874569979ee367a9 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 21 Nov 2024 15:45:59 +0200 Subject: [PATCH 49/74] Adjust toolbar style in `portrait` mode --- packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 40574d573824a..b39305f03e652 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -50,7 +50,7 @@ export const PickersLayoutRoot = styled('div', { { props: { isLandscape: false }, style: { - [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2 / 4', gridRow: 1 }, + [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2', gridRow: 1 }, [`& .${pickersLayoutClasses.shortcuts}`]: { gridColumn: 1, gridRow: '2 / 3', From c412d358fe7d4c23b45b66ee918a8e41ee658a27 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 14:24:24 +0200 Subject: [PATCH 50/74] remove unexpected prop --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 2d50ca57e76cd..21e67ac440d5f 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -157,7 +157,6 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< toolbar: { hidden: true, toolbarVariant: 'desktop', - ampmInClock: true, ...defaultizedProps.slotProps?.toolbar, }, }, From 0ae56ffdfcd3f6a7a0517b513431172709db4b08 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 15:17:42 +0200 Subject: [PATCH 51/74] Add default actions --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 21e67ac440d5f..cec5a8e8488a9 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -18,6 +18,8 @@ import { } from '@mui/x-date-pickers/MultiSectionDigitalClock'; import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; +import { PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; +import { PickerLayoutOwnerState } from '@mui/x-date-pickers/PickersLayout'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { @@ -131,6 +133,8 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< const views = !shouldHoursRendererContainMeridiemView ? defaultizedProps.views.filter((view) => view !== 'meridiem') : defaultizedProps.views; + const actionBarActions: PickersActionBarAction[] = + defaultizedProps.shouldRenderTimeInASingleColumn ? [] : ['accept']; const props = { ...defaultizedProps, @@ -145,6 +149,10 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }, slotProps: { ...defaultizedProps.slotProps, + actionBar: (ownerState: PickerLayoutOwnerState) => ({ + actions: actionBarActions, + ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), + }), field: (ownerState: any) => ({ ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), ...extractValidationProps(defaultizedProps), From 5b2a7a1a3c9a8f373b01ba066acdaff896f0a9c4 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 15:17:54 +0200 Subject: [PATCH 52/74] Fix layout for `TimeRangePicker` --- .../src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx index 49157d68b8c68..6e8c4cbf120c8 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx @@ -46,7 +46,7 @@ const DesktopDateTimePickerLayout = React.forwardRef(function DesktopDateTimePic {isLandscape ? toolbar : shortcuts} {content} {tabs} From 8e6784c86f69612b15ea6eb923cf827166b8c15a Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 15:29:45 +0200 Subject: [PATCH 53/74] Properly fix grid layout --- .../src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx | 2 +- packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx index 6e8c4cbf120c8..49157d68b8c68 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx @@ -46,7 +46,7 @@ const DesktopDateTimePickerLayout = React.forwardRef(function DesktopDateTimePic {isLandscape ? toolbar : shortcuts} {content} {tabs} diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index b39305f03e652..db106ec1cb9eb 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -50,7 +50,7 @@ export const PickersLayoutRoot = styled('div', { { props: { isLandscape: false }, style: { - [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2', gridRow: 1 }, + [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2 / 4', gridRow: 1 }, [`& .${pickersLayoutClasses.shortcuts}`]: { gridColumn: 1, gridRow: '2 / 3', @@ -73,7 +73,7 @@ export const PickersLayoutContentWrapper = styled('div', { slot: 'ContentWrapper', overridesResolver: (props, styles) => styles.contentWrapper, })({ - gridColumn: 2, + gridColumn: '2 / 4', gridRow: 2, display: 'flex', flexDirection: 'column', From 810d4145e8466313c1e5b47c6a7e36d9a41aac21 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 15:31:38 +0200 Subject: [PATCH 54/74] Cleanup --- .../src/MobileTimeRangePicker/MobileTimeRangePicker.tsx | 1 - .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 96481074e55f3..2ceb29aa7de31 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -133,7 +133,6 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< const props = { ...defaultizedProps, - // TODO: Do we want the toolbar to support AM/PM switch on mobile? ampmInClock: true, viewRenderers, format: resolveTimeFormat(utils, defaultizedProps), diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 5d2d33d98edd6..17baeaebf539b 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -81,18 +81,19 @@ const TimeRangePickerToolbarContainer = styled('div', { })<{ toolbarVariant: WrapperVariant }>({ display: 'flex', flex: 1, - rowGap: 8, variants: [ { props: { toolbarVariant: 'mobile' }, style: { flexDirection: 'column', + rowGap: 8, }, }, { props: { toolbarVariant: 'desktop' }, style: { flexDirection: 'row', + gap: 1, }, }, ], @@ -104,8 +105,8 @@ const TimeRangePickerToolbarTimeContainer = styled('div', { overridesResolver: (_, styles) => styles.timeContainer, })({ display: 'flex', - justifyContent: 'space-between', - width: '100%', + justifyContent: 'space-around', + flex: 1, }); const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { From 5ad654d4b3bf5c135e2f2bcb9f84c07259952cf6 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 15:36:45 +0200 Subject: [PATCH 55/74] Add toolbar to API index --- docs/pages/x/api/date-pickers/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/x/api/date-pickers/index.md b/docs/pages/x/api/date-pickers/index.md index 0dce17dad6513..4a0cf73b291cb 100644 --- a/docs/pages/x/api/date-pickers/index.md +++ b/docs/pages/x/api/date-pickers/index.md @@ -77,6 +77,7 @@ - [TimePickerToolbar](/x/api/date-pickers/time-picker-toolbar/) - [DateTimePickerToolbar](/x/api/date-pickers/date-time-picker-toolbar/) - [DateRangePickerToolbar](/x/api/date-pickers/date-range-picker-toolbar/) +- [TimeRangePickerToolbar](/x/api/date-pickers/time-range-picker-toolbar/) - [DateTimeRangePickerToolbar](/x/api/date-pickers/date-time-range-picker-toolbar/) ### Others From 9897676560002ee908a2b91f089a5fb391996435 Mon Sep 17 00:00:00 2001 From: Lukas Date: Fri, 22 Nov 2024 17:38:57 +0200 Subject: [PATCH 56/74] Remove unwanted diffs --- .../useDesktopRangePicker/useDesktopRangePicker.tsx | 4 +--- .../hooks/useEnrichedRangePickerFieldProps.ts | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index 92f2794565c4d..34d4e46d8008a 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -8,8 +8,8 @@ import { usePicker, PickersPopper, ExportedBaseToolbarProps, - ExportedBaseTabsProps, DateOrTimeViewWithMeridiem, + ExportedBaseTabsProps, PickerProvider, PickerRangeValue, } from '@mui/x-date-pickers/internals'; @@ -68,7 +68,6 @@ export const useDesktopRangePicker = < const fieldContainerRef = React.useRef(null); const anchorRef = React.useRef(null); - const anchorRefEndDate = React.useRef(null); const popperRef = React.useRef(null); const startFieldRef = React.useRef>(null); const endFieldRef = React.useRef>(null); @@ -180,7 +179,6 @@ export const useDesktopRangePicker = < pickerSlots: slots, fieldProps, anchorRef, - anchorRefEndDate, startFieldRef, endFieldRef, currentView: layoutProps.view !== props.openTo ? layoutProps.view : undefined, diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts index 490a9291bf629..61849f28eacc6 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts +++ b/packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts @@ -122,7 +122,6 @@ export interface UseEnrichedRangePickerFieldPropsParams< TError >; anchorRef?: React.Ref; - anchorRefEndDate?: React.Ref; currentView?: TView | null; initialView?: TView; onViewChange?: (view: TView) => void; @@ -149,7 +148,6 @@ const useMultiInputFieldSlotProps = < pickerSlots, fieldProps, anchorRef, - anchorRefEndDate, currentView, initialView, onViewChange, @@ -243,8 +241,7 @@ const useMultiInputFieldSlotProps = < textField: (ownerState) => { const resolvedComponentProps = resolveComponentProps(pickerSlotProps?.textField, ownerState); let textFieldProps: MultiInputFieldSlotTextFieldProps; - let InputProps: MultiInputFieldSlotTextFieldProps['InputProps'] = - resolvedComponentProps?.InputProps; + let InputProps: MultiInputFieldSlotTextFieldProps['InputProps']; if (ownerState.position === 'start') { textFieldProps = { label: inLocaleText?.start ?? translations.start, @@ -273,12 +270,7 @@ const useMultiInputFieldSlotProps = < ...(!readOnly && !fieldProps.disabled && { onClick: openRangeEndSelection }), ...(variant === 'mobile' && { readOnly: true }), }; - if (anchorRefEndDate) { - InputProps = { - ...resolvedComponentProps?.InputProps, - ref: anchorRefEndDate, - }; - } + InputProps = resolvedComponentProps?.InputProps; } return { From fa127c816d94d2704bc9c5d34698b6e68b19c3ae Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 25 Nov 2024 11:53:27 +0200 Subject: [PATCH 57/74] rename type --- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 17baeaebf539b..dd537c90b80ec 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -12,7 +12,7 @@ import { useUtils, BaseToolbarProps, ExportedBaseToolbarProps, - WrapperVariant, + PickerVariant, TimeViewWithMeridiem, PickersToolbarText, getMeridiem, @@ -46,7 +46,7 @@ export interface TimeRangePickerToolbarProps Pick, ExportedTimeRangePickerToolbarProps { ampm: boolean; - toolbarVariant?: WrapperVariant; + toolbarVariant?: PickerVariant; } export interface ExportedTimeRangePickerToolbarProps @@ -78,7 +78,7 @@ const TimeRangePickerToolbarContainer = styled('div', { slot: 'Container', shouldForwardProp: (prop) => prop !== 'toolbarVariant', overridesResolver: (_, styles) => styles.container, -})<{ toolbarVariant: WrapperVariant }>({ +})<{ toolbarVariant: PickerVariant }>({ display: 'flex', flex: 1, variants: [ From f9b0fa587f3648f105d65722e76451249d195987 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 27 Nov 2024 14:14:28 +0200 Subject: [PATCH 58/74] Improve `DigitalClock` extensibility --- .../timeRangeViewRenderers.tsx | 9 ++++++++- .../src/DigitalClock/DigitalClock.tsx | 15 ++++++++++----- .../src/DigitalClock/DigitalClock.types.ts | 15 +++++++++++++-- packages/x-date-pickers/src/DigitalClock/index.ts | 3 ++- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx index bcc78c6e50273..72ddee5db2d26 100644 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx @@ -185,7 +185,13 @@ export const renderDigitalClockTimeRangeView = ({ minutesStep={minutesStep} ampm={ampm} slots={slots} - slotProps={slotProps} + slotProps={{ + ...slotProps, + digitalClockItem: { + 'data-range-position': rangePosition, + ...slotProps?.digitalClockItem, + } as any, + }} readOnly={readOnly} disabled={disabled} sx={sx} @@ -279,6 +285,7 @@ export const renderMultiSectionDigitalClockTimeRangeView = ({ timeSteps={timeSteps} skipDisabled={skipDisabled} timezone={timezone} + data-range-position={rangePosition} /> ); }; diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx index ed52313e052d6..f1cb97c05cdc0 100644 --- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx +++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx @@ -65,9 +65,10 @@ const DigitalClockList = styled(MenuList, { padding: 0, }); -const DigitalClockItem = styled(MenuItem, { +export const DigitalClockItem = styled(MenuItem, { name: 'MuiDigitalClock', slot: 'Item', + shouldForwardProp: (prop) => prop !== 'itemValue' && prop !== 'formattedValue', overridesResolver: (props, styles) => styles.item, })(({ theme }) => ({ padding: '8px 16px', @@ -343,25 +344,29 @@ export const DigitalClock = React.forwardRef(function DigitalClock( onKeyDown={handleKeyDown} > {timeOptions.map((option, index) => { - if (skipDisabled && isTimeDisabled(option)) { + const optionDisabled = isTimeDisabled(option); + if (skipDisabled && optionDisabled) { return null; } const isSelected = utils.isEqual(option, value); const formattedValue = utils.format(option, ampm ? 'fullTime12h' : 'fullTime24h'); - const tabIndex = - focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0) ? 0 : -1; + const isFocused = + focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0); + const tabIndex = isFocused ? 0 : -1; return ( !readOnly && handleItemSelect(option)} selected={isSelected} - disabled={disabled || isTimeDisabled(option)} + disabled={disabled || optionDisabled} disableRipple={readOnly} role="option" // aria-readonly is not supported here and does not have any effect aria-disabled={readOnly} aria-selected={isSelected} tabIndex={tabIndex} + itemValue={option} + formattedValue={formattedValue} {...clockItemProps} > {formattedValue} diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts index 926d926c3cf85..002b721c7b375 100644 --- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts +++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.types.ts @@ -7,7 +7,7 @@ import { DigitalClockOnlyProps, ExportedBaseClockProps, } from '../internals/models/props/time'; -import { TimeView } from '../models'; +import { TimeView, PickerValidDate } from '../models'; export interface ExportedDigitalClockProps extends ExportedBaseClockProps, DigitalClockOnlyProps {} @@ -16,7 +16,7 @@ export interface DigitalClockSlots { * Component responsible for rendering a single digital clock item. * @default MenuItem from '@mui/material' */ - digitalClockItem?: React.ElementType; + digitalClockItem?: React.JSXElementConstructor; } export interface DigitalClockSlotProps { @@ -46,3 +46,14 @@ export interface DigitalClockProps */ slotProps?: DigitalClockSlotProps; } + +export interface DigitalClockItemProps { + itemValue: PickerValidDate; + formattedValue: string; + onClick: () => void; + selected: boolean; + disabled: boolean; + readOnly?: boolean; + tabIndex: number; + [x: `data-${string}`]: string; +} diff --git a/packages/x-date-pickers/src/DigitalClock/index.ts b/packages/x-date-pickers/src/DigitalClock/index.ts index c3d13d39b9c6f..12bb8c3e71ada 100644 --- a/packages/x-date-pickers/src/DigitalClock/index.ts +++ b/packages/x-date-pickers/src/DigitalClock/index.ts @@ -1,9 +1,10 @@ -export { DigitalClock } from './DigitalClock'; +export { DigitalClock, DigitalClockItem } from './DigitalClock'; export type { DigitalClockProps, DigitalClockSlots, DigitalClockSlotProps, ExportedDigitalClockProps, + DigitalClockItemProps, } from './DigitalClock.types'; export { digitalClockClasses, getDigitalClockUtilityClass } from './digitalClockClasses'; From fb423b56a087853f7d9013739870a49afa8f7eb0 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 27 Nov 2024 14:28:59 +0200 Subject: [PATCH 59/74] Add customized example --- .../CustomizedBehaviorTimeRangePicker.js | 59 ++++++++++++++++ .../CustomizedBehaviorTimeRangePicker.tsx | 69 +++++++++++++++++++ .../time-range-picker/time-range-picker.md | 4 ++ 3 files changed, 132 insertions(+) create mode 100644 docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js create mode 100644 docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js new file mode 100644 index 0000000000000..b179581fde730 --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js @@ -0,0 +1,59 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { DigitalClockItem } from '@mui/x-date-pickers/DigitalClock'; + +function CustomDigitalClockItem(props) { + const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = + props; + if (selectedValue[0] && other?.['data-range-position'] === 'end') { + const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); + const timeDifferenceLabel = + timeDifference.minutes < 60 + ? timeDifference.toHuman() + : timeDifference.shiftTo('hours').toHuman(); + return ( + + {formattedValue} ({timeDifferenceLabel}) + + ); + } + return ; +} + +export default function CustomizedBehaviorTimeRangePicker() { + const [rangePosition, setRangePosition] = React.useState('start'); + const [value, setValue] = React.useState([null, null]); + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx new file mode 100644 index 0000000000000..348df7aad18fc --- /dev/null +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { TimeRangePicker } from '@mui/x-date-pickers-pro/TimeRangePicker'; +import { SingleInputTimeRangeField } from '@mui/x-date-pickers-pro/SingleInputTimeRangeField'; +import { DemoContainer } from '@mui/x-date-pickers/internals/demo'; +import { + DigitalClockItem, + DigitalClockItemProps, +} from '@mui/x-date-pickers/DigitalClock'; +import { DateTime } from 'luxon'; +import { DateRange, RangePosition } from '@mui/x-date-pickers-pro/models'; + +function CustomDigitalClockItem( + props: DigitalClockItemProps & { + rangePosition: RangePosition; + selectedValue: DateRange; + }, +) { + const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = + props; + if (selectedValue[0] && other?.['data-range-position'] === 'end') { + const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); + const timeDifferenceLabel = + timeDifference.minutes < 60 + ? timeDifference.toHuman() + : timeDifference.shiftTo('hours').toHuman(); + return ( + + {formattedValue} ({timeDifferenceLabel}) + + ); + } + return ; +} + +export default function CustomizedBehaviorTimeRangePicker() { + const [rangePosition, setRangePosition] = React.useState('start'); + const [value, setValue] = React.useState>([null, null]); + return ( + + + + + + ); +} diff --git a/docs/data/date-pickers/time-range-picker/time-range-picker.md b/docs/data/date-pickers/time-range-picker/time-range-picker.md index 4c18ddd971ebb..8599526fdebc8 100644 --- a/docs/data/date-pickers/time-range-picker/time-range-picker.md +++ b/docs/data/date-pickers/time-range-picker/time-range-picker.md @@ -87,6 +87,10 @@ You can pass the `SingleInputTimeRangeField` component to the Time Range Picker For more information, check out the [Custom field](/x/react-date-pickers/custom-field/#use-single-input-fields-on-range-pickers) page. ::: +### Change end time label + +{{"demo": "CustomizedBehaviorTimeRangePicker.js"}} + ## Validation You can find the documentation in the [Validation page](/x/react-date-pickers/validation/). From 6d7179d45855c8765577a11a89f1414f12cddd66 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 27 Nov 2024 15:28:04 +0200 Subject: [PATCH 60/74] Fix after merge --- packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 723111693afe6..c3acbbe641345 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -80,7 +80,7 @@ export const PickersLayoutContentWrapper = styled('div', { name: 'MuiPickersLayout', slot: 'ContentWrapper', overridesResolver: (props, styles) => styles.contentWrapper, -})({ +})<{ ownerState: PickerLayoutOwnerState }>({ gridColumn: '2 / 4', gridRow: 2, display: 'flex', From 60fb80924b543d3c8fba6391c38d1b5dc5d7d19a Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 27 Nov 2024 15:48:06 +0200 Subject: [PATCH 61/74] scripts --- .../api/date-pickers/time-range-picker-toolbar.json | 2 -- .../time-range-picker-toolbar.json | 6 ------ .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 12 ------------ scripts/x-date-pickers-pro.exports.json | 2 ++ scripts/x-date-pickers.exports.json | 2 ++ 5 files changed, 4 insertions(+), 20 deletions(-) diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index d46ec7d696c10..277e350744978 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -20,9 +20,7 @@ "required": true }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "disabled": { "type": { "name": "bool" }, "default": "false" }, "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, - "readOnly": { "type": { "name": "bool" }, "default": "false" }, "sx": { "type": { "name": "union", diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json index 2c05f75bd26e4..5c4cf6beee932 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -2,17 +2,11 @@ "componentDescription": "", "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, - "disabled": { - "description": "If true, the component is disabled. When disabled, the value cannot be changed and no interaction is possible." - }, "hidden": { "description": "If true, show the toolbar even in desktop mode." }, "onViewChange": { "description": "Callback called when a toolbar is clicked", "typeDescriptions": { "view": "The view to open" } }, - "readOnly": { - "description": "If true, the component is read-only. When read-only, the value cannot be changed but the user can interact with the interface." - }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index dd537c90b80ec..b261bc29856ab 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -324,12 +324,6 @@ TimeRangePickerToolbar.propTypes = { */ classes: PropTypes.object, className: PropTypes.string, - /** - * If `true`, the component is disabled. - * When disabled, the value cannot be changed and no interaction is possible. - * @default false - */ - disabled: PropTypes.bool, /** * If `true`, show the toolbar even in desktop mode. * @default `true` for Desktop, `false` for Mobile. @@ -345,12 +339,6 @@ TimeRangePickerToolbar.propTypes = { */ onViewChange: PropTypes.func.isRequired, rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, - /** - * If `true`, the component is read-only. - * When read-only, the value cannot be changed but the user can interact with the interface. - * @default false - */ - readOnly: PropTypes.bool, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/scripts/x-date-pickers-pro.exports.json b/scripts/x-date-pickers-pro.exports.json index a760ffc663726..952a5d87181b5 100644 --- a/scripts/x-date-pickers-pro.exports.json +++ b/scripts/x-date-pickers-pro.exports.json @@ -143,6 +143,8 @@ { "name": "digitalClockClasses", "kind": "Variable" }, { "name": "DigitalClockClasses", "kind": "Interface" }, { "name": "DigitalClockClassKey", "kind": "TypeAlias" }, + { "name": "DigitalClockItem", "kind": "Variable" }, + { "name": "DigitalClockItemProps", "kind": "Interface" }, { "name": "DigitalClockProps", "kind": "Interface" }, { "name": "DigitalClockSlotProps", "kind": "Interface" }, { "name": "DigitalClockSlots", "kind": "Interface" }, diff --git a/scripts/x-date-pickers.exports.json b/scripts/x-date-pickers.exports.json index 0a7b338d04d4c..7b1b3c431f24c 100644 --- a/scripts/x-date-pickers.exports.json +++ b/scripts/x-date-pickers.exports.json @@ -90,6 +90,8 @@ { "name": "digitalClockClasses", "kind": "Variable" }, { "name": "DigitalClockClasses", "kind": "Interface" }, { "name": "DigitalClockClassKey", "kind": "TypeAlias" }, + { "name": "DigitalClockItem", "kind": "Variable" }, + { "name": "DigitalClockItemProps", "kind": "Interface" }, { "name": "DigitalClockProps", "kind": "Interface" }, { "name": "DigitalClockSlotProps", "kind": "Interface" }, { "name": "DigitalClockSlots", "kind": "Interface" }, From 8b6b4c321eaacfa9c0dcb87600f0fe7ae2c23c3c Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 28 Nov 2024 12:00:56 +0200 Subject: [PATCH 62/74] Create `TimeRangePickerTimeWrapper` --- .../CustomizedBehaviorTimeRangePicker.tsx | 4 +- .../DesktopTimeRangePicker.tsx | 40 +-- .../MobileTimeRangePicker.tsx | 18 +- .../TimeRangePickerTimeWrapper.tsx | 106 +++++++ .../src/timeRangeViewRenderers/index.ts | 5 - .../timeRangeViewRenderers.tsx | 291 ------------------ 6 files changed, 127 insertions(+), 337 deletions(-) create mode 100644 packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx delete mode 100644 packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts delete mode 100644 packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx index 348df7aad18fc..9ff7d20a99e20 100644 --- a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.tsx @@ -19,7 +19,7 @@ function CustomDigitalClockItem( ) { const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = props; - if (selectedValue[0] && other?.['data-range-position'] === 'end') { + if (selectedValue[0] && rangePosition === 'end') { const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); const timeDifferenceLabel = timeDifference.minutes < 60 @@ -45,7 +45,7 @@ export default function CustomizedBehaviorTimeRangePicker() { timeSteps={{ minutes: 15 }} value={value} onChange={setValue} - minTime={value[0] ?? undefined} + minTime={rangePosition === 'end' && value[0] ? value[0] : undefined} rangePosition={rangePosition} skipDisabled onRangePositionChange={setRangePosition} diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index cec5a8e8488a9..bd9bb922e67fd 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -11,7 +11,6 @@ import { PickerRangeValue, } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; -import Divider from '@mui/material/Divider'; import { multiSectionDigitalClockClasses, multiSectionDigitalClockSectionClasses, @@ -20,6 +19,10 @@ import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; import { PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; import { PickerLayoutOwnerState } from '@mui/x-date-pickers/PickersLayout'; +import { + renderDigitalClockTimeView, + renderMultiSectionDigitalClockTimeView, +} from '@mui/x-date-pickers/timeViewRenderers'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; import { @@ -32,11 +35,8 @@ import { UseDesktopRangePickerProps, } from '../internals/hooks/useDesktopRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; -import { - renderDigitalClockTimeRangeView, - renderMultiSectionDigitalClockTimeRangeView, -} from '../timeRangeViewRenderers'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; +import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; const rendererInterceptor = function rendererInterceptor< TEnableAccessibleFieldDOMStructure extends boolean, @@ -64,8 +64,8 @@ const rendererInterceptor = function rendererInterceptor< const { openTo, rangePosition, focusedView, ...otherProps } = rendererProps; const finalProps = { ...otherProps, - focusedView: null, rangePosition, + focusedView: null, sx: [ { [`&.${multiSectionDigitalClockClasses.root}`]: { @@ -80,21 +80,13 @@ const rendererInterceptor = function rendererInterceptor< }; const viewRenderer = inViewRenderers[popperView]; return ( - - {viewRenderer?.({ - ...finalProps, - view: popperView, - rangePosition: 'start', - sx: [{ gridColumn: 1 }, ...finalProps.sx], - })} - - {viewRenderer?.({ - ...finalProps, - view: popperView, - rangePosition: 'end', - sx: [{ gridColumn: 3 }, ...finalProps.sx], - })} - + ); }; @@ -117,8 +109,8 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< >(inProps, 'MuiDesktopTimeRangePicker'); const renderTimeRangeView = defaultizedProps.shouldRenderTimeInASingleColumn - ? renderDigitalClockTimeRangeView - : renderMultiSectionDigitalClockTimeRangeView; + ? renderDigitalClockTimeView + : renderMultiSectionDigitalClockTimeView; const viewRenderers: TimeRangePickerRenderers = { hours: renderTimeRangeView, @@ -129,7 +121,7 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }; const shouldHoursRendererContainMeridiemView = - viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeRangeView.name; + viewRenderers.hours?.name === renderMultiSectionDigitalClockTimeView.name; const views = !shouldHoursRendererContainMeridiemView ? defaultizedProps.views.filter((view) => view !== 'meridiem') : defaultizedProps.views; diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 2ceb29aa7de31..4078f5b16a17e 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -4,9 +4,7 @@ import PropTypes from 'prop-types'; import { DefaultizedProps } from '@mui/x-internals/types'; import { DIALOG_WIDTH, - isInternalTimeView, PickerRangeValue, - PickerViewRenderer, PickerViewsRendererProps, resolveTimeFormat, TimeViewWithMeridiem, @@ -38,7 +36,7 @@ import { } from '../internals/hooks/useMobileRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; -import { DateTimeRangePickerTimeWrapper } from '../DateTimeRangePicker/DateTimeRangePickerTimeWrapper'; +import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; const rendererInterceptor = function rendererInterceptor< TEnableAccessibleFieldDOMStructure extends boolean, @@ -55,7 +53,7 @@ const rendererInterceptor = function rendererInterceptor< {} >, ) { - const { view, openTo, rangePosition, ...otherRendererProps } = rendererProps; + const { rangePosition, ...otherRendererProps } = rendererProps; const finalProps = { ...otherRendererProps, rangePosition, @@ -88,17 +86,7 @@ const rendererInterceptor = function rendererInterceptor< if (!viewRenderer) { return null; } - return ( - - } - view={view && isInternalTimeView(view) ? view : 'hours'} - views={finalProps.views as TimeViewWithMeridiem[]} - openTo={isInternalTimeView(openTo) ? openTo : 'hours'} - /> - ); + return ; }; type MobileTimeRangePickerComponent = (( diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx new file mode 100644 index 0000000000000..ec6dcae8b23fc --- /dev/null +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx @@ -0,0 +1,106 @@ +import * as React from 'react'; +import { DefaultizedProps } from '@mui/x-internals/types'; +import { + PickerSelectionState, + PickerViewRenderer, + useUtils, + TimeViewWithMeridiem, + BaseClockProps, + PickerRangeValue, +} from '@mui/x-date-pickers/internals'; +import { PickerValidDate } from '@mui/x-date-pickers/models'; +import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; +import { isRangeValid } from '../internals/utils/date-utils'; +import { calculateRangeChange } from '../internals/utils/date-range-manager'; + +export type TimeRangePickerTimeWrapperProps< + TView extends TimeViewWithMeridiem, + TComponentProps extends DefaultizedProps< + Omit, 'value' | 'defaultValue' | 'onChange'>, + 'views' + >, +> = Pick & + Omit< + TComponentProps, + 'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange' + > & { + view: TView; + onViewChange?: (view: TView) => void; + views: readonly TView[]; + value?: PickerRangeValue; + defaultValue?: PickerRangeValue; + onChange?: ( + value: PickerRangeValue, + selectionState: PickerSelectionState, + selectedView: TView, + ) => void; + viewRenderer: PickerViewRenderer | null; + openTo?: TView; + }; + +/** + * @ignore - internal component. + */ +function TimeRangePickerTimeWrapper< + TView extends TimeViewWithMeridiem, + TComponentProps extends DefaultizedProps< + Omit, 'value' | 'defaultValue' | 'onChange'>, + 'views' + >, +>(props: TimeRangePickerTimeWrapperProps, ref: React.Ref) { + const utils = useUtils(); + + const { + rangePosition, + onRangePositionChange, + viewRenderer, + value, + onChange, + defaultValue, + onViewChange, + views, + className, + ...other + } = props; + + if (!viewRenderer) { + return null; + } + + const currentValue = (rangePosition === 'start' ? value?.[0] : value?.[1]) ?? null; + const currentDefaultValue = + (rangePosition === 'start' ? defaultValue?.[0] : defaultValue?.[1]) ?? null; + const handleOnChange = ( + newDate: PickerValidDate | null, + selectionState: PickerSelectionState, + selectedView: TView, + ) => { + if (!onChange || !value) { + return; + } + const { newRange } = calculateRangeChange({ + newDate, + utils, + range: value, + rangePosition, + }); + const isFullRangeSelected = rangePosition === 'end' && isRangeValid(utils, newRange); + if (selectionState === 'finish') { + onRangePositionChange?.(rangePosition === 'start' ? 'end' : 'start'); + onViewChange?.(views[0]); + } + onChange(newRange, isFullRangeSelected ? 'finish' : 'partial', selectedView); + }; + + return viewRenderer({ + ...other, + ref, + views, + onViewChange, + value: currentValue, + onChange: handleOnChange, + defaultValue: currentDefaultValue, + }); +} + +export { TimeRangePickerTimeWrapper }; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts deleted file mode 100644 index 189ea75fb1808..0000000000000 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - renderDigitalClockTimeRangeView, - renderMultiSectionDigitalClockTimeRangeView, - renderTimeRangeViewClock, -} from './timeRangeViewRenderers'; diff --git a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx b/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx deleted file mode 100644 index 72ddee5db2d26..0000000000000 --- a/packages/x-date-pickers-pro/src/timeRangeViewRenderers/timeRangeViewRenderers.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import * as React from 'react'; -import { - BaseClockProps, - TimeViewWithMeridiem, - isTimeView, - PickerSelectionState, - PickerRangeValue, -} from '@mui/x-date-pickers/internals'; -import { DigitalClock, DigitalClockProps } from '@mui/x-date-pickers/DigitalClock'; -import { - MultiSectionDigitalClock, - MultiSectionDigitalClockProps, -} from '@mui/x-date-pickers/MultiSectionDigitalClock'; -import { TimeClock, TimeClockProps } from '@mui/x-date-pickers/TimeClock'; -import { PickerValidDate, TimeView } from '@mui/x-date-pickers/models'; -import type { TimeRangePickerProps } from '../TimeRangePicker/TimeRangePicker.types'; -import { UseRangePositionProps } from '../internals/hooks/useRangePosition'; - -export type TimeRangeViewRendererProps< - TView extends TimeViewWithMeridiem, - TComponentProps extends Omit, 'value' | 'onChange'>, -> = Omit & - UseRangePositionProps & { - value: PickerRangeValue; - onChange: (value: PickerRangeValue, selectionState?: PickerSelectionState) => void; - view: TView; - onViewChange?: (view: TView) => void; - views: readonly TView[]; - }; - -export const renderTimeRangeViewClock = ({ - view, - onViewChange, - focusedView, - onFocusedViewChange, - views, - value, - referenceDate, - onChange, - className, - classes, - disableFuture, - disablePast, - minTime, - maxTime, - shouldDisableTime, - minutesStep, - ampm, - ampmInClock, - slots, - slotProps, - readOnly, - disabled, - sx, - autoFocus, - showViewSwitcher, - disableIgnoringDatePartForTimeValidation, - timezone, - rangePosition, - onRangePositionChange, -}: TimeRangeViewRendererProps< - TimeView, - Omit, 'value' | 'defaultValue' | 'onChange'> & - Pick ->) => { - const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - - const handleChange = ( - newValue: PickerValidDate | null, - selectionState?: PickerSelectionState, - ) => { - if (selectionState === 'finish' && rangePosition === 'start') { - onRangePositionChange?.('end'); - onViewChange?.(views[0]); - } - - onChange( - rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], - rangePosition === 'start' ? 'partial' : selectionState, - ); - }; - - return ( - - ); -}; - -export const renderDigitalClockTimeRangeView = ({ - view, - onViewChange, - focusedView, - onFocusedViewChange, - views, - value, - referenceDate, - onChange, - className, - classes, - disableFuture, - disablePast, - minTime, - maxTime, - shouldDisableTime, - minutesStep, - ampm, - slots, - slotProps, - readOnly, - disabled, - sx, - autoFocus, - disableIgnoringDatePartForTimeValidation, - timeSteps, - skipDisabled, - timezone, - rangePosition, - onRangePositionChange, -}: TimeRangeViewRendererProps< - Extract, - Omit & - Pick ->) => { - const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - - const handleChange = ( - newValue: PickerValidDate | null, - selectionState?: PickerSelectionState, - ) => { - if (selectionState === 'finish' && rangePosition === 'start') { - onRangePositionChange?.('end'); - onViewChange?.(views[0]); - } - - onChange( - rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], - rangePosition === 'start' ? 'partial' : selectionState, - ); - }; - - return ( - - ); -}; - -export const renderMultiSectionDigitalClockTimeRangeView = ({ - view, - onViewChange, - focusedView, - onFocusedViewChange, - views, - value, - referenceDate, - onChange, - className, - classes, - disableFuture, - disablePast, - minTime, - maxTime, - shouldDisableTime, - minutesStep, - ampm, - slots, - slotProps, - readOnly, - disabled, - sx, - autoFocus, - disableIgnoringDatePartForTimeValidation, - timeSteps, - skipDisabled, - timezone, - rangePosition, - onRangePositionChange, -}: TimeRangeViewRendererProps< - TimeViewWithMeridiem, - Omit & - Pick ->) => { - const valueForCurrentView = rangePosition === 'start' ? value[0] : value[1]; - - const handleChange = ( - newValue: PickerValidDate | null, - selectionState?: PickerSelectionState, - ) => { - if (selectionState === 'finish' && rangePosition === 'start') { - onRangePositionChange?.('end'); - onViewChange?.(views[0]); - } - - onChange( - rangePosition === 'start' ? [newValue, value[1]] : [value[0], newValue], - rangePosition === 'start' ? 'partial' : selectionState, - ); - }; - - return ( - - ); -}; From 0f070d51b6577bf772efb54a6a77970d9e5d58f9 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 28 Nov 2024 12:28:26 +0200 Subject: [PATCH 63/74] docs:typescript:formatted --- .../time-range-picker/CustomizedBehaviorTimeRangePicker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js index b179581fde730..05857cde3ae34 100644 --- a/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js +++ b/docs/data/date-pickers/time-range-picker/CustomizedBehaviorTimeRangePicker.js @@ -9,7 +9,7 @@ import { DigitalClockItem } from '@mui/x-date-pickers/DigitalClock'; function CustomDigitalClockItem(props) { const { rangePosition, selectedValue, formattedValue, itemValue, ...other } = props; - if (selectedValue[0] && other?.['data-range-position'] === 'end') { + if (selectedValue[0] && rangePosition === 'end') { const timeDifference = itemValue.diff(selectedValue[0], ['minutes']); const timeDifferenceLabel = timeDifference.minutes < 60 @@ -35,7 +35,7 @@ export default function CustomizedBehaviorTimeRangePicker() { timeSteps={{ minutes: 15 }} value={value} onChange={setValue} - minTime={value[0] ?? undefined} + minTime={rangePosition === 'end' && value[0] ? value[0] : undefined} rangePosition={rangePosition} skipDisabled onRangePositionChange={setRangePosition} From 6aaa036b0b8afb559c0e65ce8de4bb6a27cd295e Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 15 Jan 2025 23:51:22 +0200 Subject: [PATCH 64/74] Refactor after merge --- .../DesktopTimeRangePicker.tsx | 47 +++-------- .../DesktopTimeRangePicker.types.ts | 9 +-- .../MobileTimeRangePicker.tsx | 39 +++------- .../MobileTimeRangePicker.types.ts | 8 +- .../TimeRangePicker/TimeRangePickerTabs.tsx | 32 +++----- .../TimeRangePickerTimeWrapper.tsx | 68 +++++++--------- .../TimeRangePickerToolbar.tsx | 77 +++++++++++-------- .../src/TimeRangePicker/shared.tsx | 17 ++-- 8 files changed, 117 insertions(+), 180 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index bd9bb922e67fd..231539ff7c188 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -2,13 +2,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import resolveComponentProps from '@mui/utils/resolveComponentProps'; -import { DefaultizedProps } from '@mui/x-internals/types'; import { TimeViewWithMeridiem, useUtils, resolveTimeFormat, - PickerViewsRendererProps, PickerRangeValue, + PickerRendererInterceptorProps, + PickerViewRendererLookup, } from '@mui/x-date-pickers/internals'; import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { @@ -25,46 +25,20 @@ import { } from '@mui/x-date-pickers/timeViewRenderers'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { DesktopTimeRangePickerProps } from './DesktopTimeRangePicker.types'; -import { - TimeRangePickerRenderers, - useTimeRangePickerDefaultizedProps, -} from '../TimeRangePicker/shared'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; -import { - useDesktopRangePicker, - UseDesktopRangePickerProps, -} from '../internals/hooks/useDesktopRangePicker'; +import { useDesktopRangePicker } from '../internals/hooks/useDesktopRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; -const rendererInterceptor = function rendererInterceptor< - TEnableAccessibleFieldDOMStructure extends boolean, ->( - inViewRenderers: TimeRangePickerRenderers, - popperView: TimeViewWithMeridiem, - rendererProps: PickerViewsRendererProps< - PickerRangeValue, - TimeViewWithMeridiem, - DefaultizedProps< - Omit< - UseDesktopRangePickerProps< - TimeViewWithMeridiem, - TEnableAccessibleFieldDOMStructure, - any, - any - >, - 'onChange' | 'sx' | 'className' - >, - 'rangePosition' | 'onRangePositionChange' | 'openTo' - >, - {} - >, +const rendererInterceptor = function RendererInterceptor( + props: PickerRendererInterceptorProps, ) { - const { openTo, rangePosition, focusedView, ...otherProps } = rendererProps; + const { viewRenderers, popperView, rendererProps } = props; + const { openTo, ...otherProps } = rendererProps; const finalProps = { ...otherProps, - rangePosition, focusedView: null, sx: [ { @@ -78,11 +52,10 @@ const rendererInterceptor = function rendererInterceptor< }, ], }; - const viewRenderer = inViewRenderers[popperView]; + const viewRenderer = viewRenderers[popperView]; return ( = { + const viewRenderers: PickerViewRendererLookup = { hours: renderTimeRangeView, minutes: renderTimeRangeView, seconds: renderTimeRangeView, diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts index 7092b8b17e08a..9610ba65d33e0 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.types.ts @@ -1,6 +1,6 @@ import { MakeOptional } from '@mui/x-internals/types'; import { TimeView } from '@mui/x-date-pickers/models'; -import { DesktopOnlyTimePickerProps, TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; +import { DesktopOnlyTimePickerProps } from '@mui/x-date-pickers/internals'; import { UseDesktopRangePickerSlots, UseDesktopRangePickerSlotProps, @@ -14,14 +14,11 @@ import { export interface DesktopTimeRangePickerSlots extends BaseTimeRangePickerSlots, - MakeOptional, 'field'> {} + MakeOptional {} export interface DesktopTimeRangePickerSlotProps extends BaseTimeRangePickerSlotProps, - Omit< - UseDesktopRangePickerSlotProps, - 'tabs' | 'toolbar' - > {} + Omit, 'tabs' | 'toolbar'> {} export interface DesktopTimeRangePickerProps< TEnableAccessibleFieldDOMStructure extends boolean = true, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 4078f5b16a17e..8a96ca38bc5bf 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -1,11 +1,11 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { DefaultizedProps } from '@mui/x-internals/types'; import { DIALOG_WIDTH, PickerRangeValue, - PickerViewsRendererProps, + PickerRendererInterceptorProps, + PickerViewRendererLookup, resolveTimeFormat, TimeViewWithMeridiem, useUtils, @@ -25,38 +25,19 @@ import { import { extractValidationProps } from '@mui/x-date-pickers/validation'; import { rangeValueManager } from '../internals/utils/valueManagers'; import { MobileTimeRangePickerProps } from './MobileTimeRangePicker.types'; -import { - TimeRangePickerRenderers, - useTimeRangePickerDefaultizedProps, -} from '../TimeRangePicker/shared'; +import { useTimeRangePickerDefaultizedProps } from '../TimeRangePicker/shared'; import { MultiInputTimeRangeField } from '../MultiInputTimeRangeField'; -import { - useMobileRangePicker, - UseMobileRangePickerProps, -} from '../internals/hooks/useMobileRangePicker'; +import { useMobileRangePicker } from '../internals/hooks/useMobileRangePicker'; import { validateTimeRange } from '../validation/validateTimeRange'; import { RANGE_VIEW_HEIGHT } from '../internals/constants/dimensions'; import { TimeRangePickerTimeWrapper } from '../TimeRangePicker/TimeRangePickerTimeWrapper'; -const rendererInterceptor = function rendererInterceptor< - TEnableAccessibleFieldDOMStructure extends boolean, ->( - inViewRenderers: TimeRangePickerRenderers, - popperView: TimeViewWithMeridiem, - rendererProps: PickerViewsRendererProps< - PickerRangeValue, - TimeViewWithMeridiem, - DefaultizedProps< - UseMobileRangePickerProps, - 'rangePosition' | 'onRangePositionChange' | 'openTo' - >, - {} - >, +const rendererInterceptor = function rendererInterceptor( + props: PickerRendererInterceptorProps, ) { - const { rangePosition, ...otherRendererProps } = rendererProps; + const { viewRenderers, popperView, rendererProps } = props; const finalProps = { - ...otherRendererProps, - rangePosition, + ...rendererProps, focusedView: null, sx: [ { @@ -82,7 +63,7 @@ const rendererInterceptor = function rendererInterceptor< }, ], }; - const viewRenderer = inViewRenderers[popperView]; + const viewRenderer = viewRenderers[popperView]; if (!viewRenderer) { return null; } @@ -111,7 +92,7 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< ? renderDigitalClockTimeView : renderMultiSectionDigitalClockTimeView; - const viewRenderers: TimeRangePickerRenderers = { + const viewRenderers: PickerViewRendererLookup = { hours: renderTimeView, minutes: renderTimeView, seconds: renderTimeView, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts index 59f71d5ca3b0e..c010eee10df04 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.types.ts @@ -1,5 +1,4 @@ import { MakeOptional } from '@mui/x-internals/types'; -import { TimeViewWithMeridiem } from '@mui/x-date-pickers/internals'; import { UseMobileRangePickerSlots, UseMobileRangePickerSlotProps, @@ -13,14 +12,11 @@ import { export interface MobileTimeRangePickerSlots extends BaseTimeRangePickerSlots, - MakeOptional, 'field'> {} + MakeOptional {} export interface MobileTimeRangePickerSlotProps extends BaseTimeRangePickerSlotProps, - Omit< - UseMobileRangePickerSlotProps, - 'tabs' | 'toolbar' - > {} + Omit, 'tabs' | 'toolbar'> {} export interface MobileTimeRangePickerProps extends BaseTimeRangePickerProps, diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx index 8d0b4356d5e87..38e867ef6dcaf 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx @@ -7,18 +7,14 @@ import Tabs, { tabsClasses } from '@mui/material/Tabs'; import { styled, useThemeProps } from '@mui/material/styles'; import composeClasses from '@mui/utils/composeClasses'; import { TimeIcon } from '@mui/x-date-pickers/icons'; -import { - BaseTabsProps, - ExportedBaseTabsProps, - TimeViewWithMeridiem, -} from '@mui/x-date-pickers/internals'; -import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { ExportedBaseTabsProps } from '@mui/x-date-pickers/internals'; +import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks'; import { TimeRangePickerTabsClasses, getTimeRangePickerTabsUtilityClass, } from './timeRangePickerTabsClasses'; import { RangePosition } from '../models'; -import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; +import { usePickerRangePositionContext } from '../hooks'; export interface ExportedTimeRangePickerTabsProps extends ExportedBaseTabsProps { /** @@ -37,13 +33,9 @@ export interface ExportedTimeRangePickerTabsProps extends ExportedBaseTabsProps classes?: Partial; } -export interface TimeRangePickerTabsProps - extends ExportedTimeRangePickerTabsProps, - BaseTabsProps, - Pick {} +export interface TimeRangePickerTabsProps extends ExportedTimeRangePickerTabsProps {} -const useUtilityClasses = (ownerState: TimeRangePickerTabsProps) => { - const { classes } = ownerState; +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], tab: ['tab'], @@ -56,7 +48,7 @@ const TimeRangePickerTabsRoot = styled(Tabs, { name: 'MuiTimeRangePickerTabs', slot: 'Root', overridesResolver: (_, styles) => styles.root, -})<{ ownerState: TimeRangePickerTabsProps }>(({ theme }) => ({ +})(({ theme }) => ({ boxShadow: `0 -1px 0 0 inset ${(theme.vars || theme).palette.divider}`, '&:last-child': { boxShadow: `0 1px 0 0 inset ${(theme.vars || theme).palette.divider}`, @@ -89,25 +81,24 @@ const TimeRangePickerTab = styled(Tab, { const TimeRangePickerTabs = function TimeRangePickerTabs(inProps: TimeRangePickerTabsProps) { const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerTabs' }); const { - view, - onViewChange, timeIcon = , - rangePosition, - onRangePositionChange, hidden = typeof window === 'undefined' || window.innerHeight < 667, className, sx, + classes: classesProp, } = props; const translations = usePickerTranslations(); - const classes = useUtilityClasses(props); + const { view, setView } = usePickerContext(); + const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); + const classes = useUtilityClasses(classesProp); const handleChange = (event: React.SyntheticEvent, value: RangePosition) => { if (rangePosition !== value) { onRangePositionChange(value); } if (view !== 'hours') { - onViewChange('hours'); + setView('hours'); } }; @@ -117,7 +108,6 @@ const TimeRangePickerTabs = function TimeRangePickerTabs(inProps: TimeRangePicke return ( , 'value' | 'defaultValue' | 'onChange'>, + Omit, 'value' | 'defaultValue' | 'onChange'>, 'views' >, -> = Pick & - Omit< - TComponentProps, - 'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange' - > & { - view: TView; - onViewChange?: (view: TView) => void; - views: readonly TView[]; - value?: PickerRangeValue; - defaultValue?: PickerRangeValue; - onChange?: ( - value: PickerRangeValue, - selectionState: PickerSelectionState, - selectedView: TView, - ) => void; - viewRenderer: PickerViewRenderer | null; - openTo?: TView; - }; +> = Omit< + TComponentProps, + 'views' | 'view' | 'onViewChange' | 'value' | 'defaultValue' | 'onChange' +> & { + view: TimeViewWithMeridiem; + onViewChange?: (view: TimeViewWithMeridiem) => void; + views: readonly TimeViewWithMeridiem[]; + value?: PickerRangeValue; + defaultValue?: PickerRangeValue; + onChange?: ( + value: PickerRangeValue, + selectionState: PickerSelectionState, + selectedView: TimeViewWithMeridiem, + ) => void; + viewRenderer: PickerViewRenderer | null; + openTo?: TimeViewWithMeridiem; +}; /** * @ignore - internal component. */ function TimeRangePickerTimeWrapper< - TView extends TimeViewWithMeridiem, TComponentProps extends DefaultizedProps< - Omit, 'value' | 'defaultValue' | 'onChange'>, + Omit, 'value' | 'defaultValue' | 'onChange'>, 'views' >, ->(props: TimeRangePickerTimeWrapperProps, ref: React.Ref) { +>(props: TimeRangePickerTimeWrapperProps) { const utils = useUtils(); - const { - rangePosition, - onRangePositionChange, - viewRenderer, - value, - onChange, - defaultValue, - onViewChange, - views, - className, - ...other - } = props; + const { viewRenderer, value, onChange, defaultValue, onViewChange, views, className, ...other } = + props; + + const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); if (!viewRenderer) { return null; @@ -73,7 +62,7 @@ function TimeRangePickerTimeWrapper< const handleOnChange = ( newDate: PickerValidDate | null, selectionState: PickerSelectionState, - selectedView: TView, + selectedView: TimeViewWithMeridiem, ) => { if (!onChange || !value) { return; @@ -94,13 +83,12 @@ function TimeRangePickerTimeWrapper< return viewRenderer({ ...other, - ref, views, onViewChange, value: currentValue, onChange: handleOnChange, defaultValue: currentDefaultValue, - }); + } as any as PickerViewsRendererProps); } export { TimeRangePickerTimeWrapper }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index b261bc29856ab..f98ad68225a44 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; -import { MakeOptional } from '@mui/x-internals/types'; +import { MakeRequired } from '@mui/x-internals/types'; import { MuiPickersAdapter, PickerValidDate } from '@mui/x-date-pickers/models'; import { PickersToolbar, @@ -21,19 +21,26 @@ import { pickersToolbarTextClasses, PickerRangeValue, MULTI_SECTION_CLOCK_SECTION_WIDTH, + UseViewsOptions, + useToolbarOwnerState, + PickerToolbarOwnerState, } from '@mui/x-date-pickers/internals'; -import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks'; import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { TimeRangePickerToolbarClasses, getTimeRangePickerToolbarUtilityClass, } from './timeRangePickerToolbarClasses'; +import { usePickerRangePositionContext } from '../hooks'; -const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { - const { classes, toolbarVariant } = ownerState; +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickerToolbarOwnerState, +) => { + const { pickerVariant } = ownerState; const slots = { root: ['root'], - container: ['container', toolbarVariant], + container: ['container', pickerVariant], separator: ['separator'], timeContainer: ['timeContainer'], }; @@ -42,7 +49,7 @@ const useUtilityClasses = (ownerState: TimeRangePickerToolbarProps) => { }; export interface TimeRangePickerToolbarProps - extends Omit, 'toolbarFormat'>, + extends Omit, Pick, ExportedTimeRangePickerToolbarProps { ampm: boolean; @@ -61,7 +68,7 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { name: 'MuiTimeRangePickerToolbar', slot: 'Root', overridesResolver: (_, styles) => styles.root, -})<{ ownerState: TimeRangePickerToolbarProps }>(({ theme }) => ({ +})<{ ownerState: PickerToolbarOwnerState }>(({ theme }) => ({ borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, padding: '12px 0px 8px 0px', [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: { @@ -117,17 +124,21 @@ const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { cursor: 'default', }); -type TimeRangePickerToolbarTimeElementProps = MakeOptional< - Pick< - TimeRangePickerToolbarProps, - 'ampm' | 'views' | 'onViewChange' | 'view' | 'toolbarPlaceholder' | 'toolbarVariant' - >, - 'view' -> & { - value: PickerValidDate | null; - utils: MuiPickersAdapter; - separatorClasses: string; -}; +type TimeRangePickerToolbarTimeElementProps = Pick< + TimeRangePickerToolbarProps, + 'ampm' | 'toolbarPlaceholder' | 'toolbarVariant' +> & + MakeRequired< + Pick< + UseViewsOptions, + 'view' | 'views' | 'onViewChange' + >, + 'onViewChange' + > & { + value: PickerValidDate | null; + utils: MuiPickersAdapter; + separatorClasses: string; + }; function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElementProps) { const { @@ -236,32 +247,32 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); const { - value: [start, end], - rangePosition, - onRangePositionChange, className, ampm, - views, toolbarVariant = 'mobile', toolbarPlaceholder = '--', - onViewChange, - view, + classes: classesProp, ...other } = props; + const { value, view, setView, views } = usePickerContext< + PickerRangeValue, + TimeViewWithMeridiem + >(); const translations = usePickerTranslations(); - - const ownerState = props; - const classes = useUtilityClasses(ownerState); + const ownerState = useToolbarOwnerState(); + const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); + const classes = useUtilityClasses(classesProp, ownerState); + const [start, end] = value; const handleStartRangeViewChange = React.useCallback( (newView: TimeViewWithMeridiem) => { if (rangePosition !== 'start') { onRangePositionChange('start'); } - onViewChange(newView); + setView(newView); }, - [onRangePositionChange, onViewChange, rangePosition], + [onRangePositionChange, setView, rangePosition], ); const handleEndRangeViewChange = React.useCallback( @@ -269,11 +280,15 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( if (rangePosition !== 'end') { onRangePositionChange('end'); } - onViewChange(newView); + setView(newView); }, - [onRangePositionChange, onViewChange, rangePosition], + [onRangePositionChange, setView, rangePosition], ); + if (!view) { + return null; + } + return ( = PickerViewRendererLookup< - PickerRangeValue, - TView, +export type TimeRangePickerRenderers = PickerViewRendererLookup< + PickerValue, + TimeViewWithMeridiem, TimeViewRendererProps> & { - view: TView; - }, - TAdditionalProps + view: TimeViewWithMeridiem; + } >; export interface BaseTimeRangePickerProps @@ -99,7 +96,7 @@ export interface BaseTimeRangePickerProps * If `null`, the section will only have field editing. * If `undefined`, internally defined view will be the used. */ - viewRenderers?: TimeRangePickerRenderers; + viewRenderers?: TimeRangePickerRenderers; /** * Amount of time options below or at which the single column time renderer is used. * @default 24 From 9b8a52b3451cafa737c601a2c9076d68126924cd Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 15 Jan 2025 23:51:27 +0200 Subject: [PATCH 65/74] Minor cleanup --- .../src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx | 1 - packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx index d1b4255453cfb..f31df55427846 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx @@ -87,7 +87,6 @@ const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePicker const { className, classes: classesProp, - classes: inClasses, ampm, hidden, toolbarFormat, diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx index b9a8076df20a5..1bcd76a6e5583 100644 --- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx +++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/shared.tsx @@ -76,7 +76,7 @@ export interface BaseDateTimeRangePickerSlotProps toolbar?: ExportedDateTimeRangePickerToolbarProps; } -export type DateTimeRangePickerRenderers = +type DateTimeRangePickerRenderers = PickerViewRendererLookup< PickerRangeValue, TView, From 125c386ada7db2c54a1b1ac68a55b3c2e222b7ac Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 15 Jan 2025 23:53:15 +0200 Subject: [PATCH 66/74] proptypes --- .../DesktopTimeRangePicker.tsx | 4 +-- .../MobileTimeRangePicker.tsx | 4 +-- .../src/TimeRangePicker/TimeRangePicker.tsx | 4 +-- .../TimeRangePicker/TimeRangePickerTabs.tsx | 12 --------- .../TimeRangePickerToolbar.tsx | 26 ++++--------------- 5 files changed, 11 insertions(+), 39 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 231539ff7c188..4734c037fe68c 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -169,8 +169,8 @@ DesktopTimeRangePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 8a96ca38bc5bf..6c9948c0c05d4 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -162,8 +162,8 @@ MobileTimeRangePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx index 9d6494a65fc36..4e710e6091fdf 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePicker.tsx @@ -62,8 +62,8 @@ TimeRangePicker.propTypes = { autoFocus: PropTypes.bool, className: PropTypes.string, /** - * If `true`, the popover or modal will close after submitting the full date. - * @default `true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop). + * If `true`, the Picker will close after submitting the full date. + * @default false */ closeOnSelect: PropTypes.bool, /** diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx index 38e867ef6dcaf..5991095d27cf0 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx @@ -147,14 +147,6 @@ TimeRangePickerTabs.propTypes = { * @default `window.innerHeight < 667` for `DesktopTimeRangePicker` and `MobileTimeRangePicker`, `displayStaticWrapperAs === 'desktop'` for `StaticTimeRangePicker` */ hidden: PropTypes.bool, - onRangePositionChange: PropTypes.func.isRequired, - /** - * Callback called when a tab is clicked. - * @template TView - * @param {TView} view The view to open - */ - onViewChange: PropTypes.func.isRequired, - rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ @@ -168,10 +160,6 @@ TimeRangePickerTabs.propTypes = { * @default Time */ timeIcon: PropTypes.node, - /** - * Currently visible picker view. - */ - view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired, } as any; export { TimeRangePickerTabs }; diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index f98ad68225a44..e35499d29eac1 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -214,9 +214,9 @@ TimeRangePickerToolbarTimeElement.propTypes = { // ---------------------------------------------------------------------- ampm: PropTypes.bool.isRequired, /** - * Callback called when a toolbar is clicked + * Callback fired on view change. * @template TView - * @param {TView} view The view to open + * @param {TView} view The new view. */ onViewChange: PropTypes.func.isRequired, separatorClasses: PropTypes.string.isRequired, @@ -229,7 +229,9 @@ TimeRangePickerToolbarTimeElement.propTypes = { utils: PropTypes.object.isRequired, value: PropTypes.object, /** - * Currently visible picker view. + * The visible view. + * Used when the component view is controlled. + * Must be a valid option from `views` list. */ view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']), /** @@ -344,15 +346,7 @@ TimeRangePickerToolbar.propTypes = { * @default `true` for Desktop, `false` for Mobile. */ hidden: PropTypes.bool, - isLandscape: PropTypes.bool.isRequired, - onChange: PropTypes.func.isRequired, onRangePositionChange: PropTypes.func.isRequired, - /** - * Callback called when a toolbar is clicked - * @template TView - * @param {TView} view The view to open - */ - onViewChange: PropTypes.func.isRequired, rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, /** * The system prop that allows defining system overrides as well as additional CSS styles. @@ -369,16 +363,6 @@ TimeRangePickerToolbar.propTypes = { */ toolbarPlaceholder: PropTypes.node, toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), - value: PropTypes.arrayOf(PropTypes.object).isRequired, - /** - * Currently visible picker view. - */ - view: PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired, - /** - * Available views. - */ - views: PropTypes.arrayOf(PropTypes.oneOf(['hours', 'meridiem', 'minutes', 'seconds']).isRequired) - .isRequired, } as any; export { TimeRangePickerToolbar }; From fdc7b75ad5a2ef10fb1ea5e417a1cde943a6e6b5 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 15 Jan 2025 23:54:19 +0200 Subject: [PATCH 67/74] docs:api --- .../desktop-time-range-picker.json | 5 +---- .../mobile-time-range-picker.json | 5 +---- .../date-pickers/time-range-picker-tabs.json | 12 ------------ .../time-range-picker-toolbar.json | 19 ------------------- .../x/api/date-pickers/time-range-picker.json | 5 +---- .../desktop-time-range-picker.json | 2 +- .../mobile-time-range-picker.json | 2 +- .../time-range-picker-tabs.json | 7 +------ .../time-range-picker-toolbar.json | 8 +------- .../time-range-picker/time-range-picker.json | 2 +- 10 files changed, 8 insertions(+), 59 deletions(-) diff --git a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json index b0cf669df5427..5893436b93af6 100644 --- a/docs/pages/x/api/date-pickers/desktop-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/desktop-time-range-picker.json @@ -2,10 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultRangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" }, "default": "'start'" diff --git a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json index a4cd5c5019327..942d4bc67ec50 100644 --- a/docs/pages/x/api/date-pickers/mobile-time-range-picker.json +++ b/docs/pages/x/api/date-pickers/mobile-time-range-picker.json @@ -2,10 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultRangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" }, "default": "'start'" diff --git a/docs/pages/x/api/date-pickers/time-range-picker-tabs.json b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json index 0edf37a297a8a..b806436219386 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-tabs.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-tabs.json @@ -1,17 +1,5 @@ { "props": { - "onViewChange": { - "type": { "name": "func" }, - "required": true, - "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } - }, - "view": { - "type": { - "name": "enum", - "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" - }, - "required": true - }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "hidden": { "type": { "name": "bool" }, diff --git a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json index 277e350744978..c82a7d9699e8f 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json +++ b/docs/pages/x/api/date-pickers/time-range-picker-toolbar.json @@ -1,24 +1,5 @@ { "props": { - "onViewChange": { - "type": { "name": "func" }, - "required": true, - "signature": { "type": "function(view: TView) => void", "describedArgs": ["view"] } - }, - "view": { - "type": { - "name": "enum", - "description": "'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'" - }, - "required": true - }, - "views": { - "type": { - "name": "arrayOf", - "description": "Array<'hours'
        | 'meridiem'
        | 'minutes'
        | 'seconds'>" - }, - "required": true - }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "hidden": { "type": { "name": "bool" }, "default": "`true` for Desktop, `false` for Mobile." }, "sx": { diff --git a/docs/pages/x/api/date-pickers/time-range-picker.json b/docs/pages/x/api/date-pickers/time-range-picker.json index e381143ccfdc7..09abd76060674 100644 --- a/docs/pages/x/api/date-pickers/time-range-picker.json +++ b/docs/pages/x/api/date-pickers/time-range-picker.json @@ -2,10 +2,7 @@ "props": { "ampm": { "type": { "name": "bool" }, "default": "utils.is12HourCycleInCurrentLocale()" }, "autoFocus": { "type": { "name": "bool" } }, - "closeOnSelect": { - "type": { "name": "bool" }, - "default": "`true` for desktop, `false` for mobile (based on the chosen wrapper and `desktopModeMediaQuery` prop)." - }, + "closeOnSelect": { "type": { "name": "bool" }, "default": "false" }, "defaultRangePosition": { "type": { "name": "enum", "description": "'end'
        | 'start'" }, "default": "'start'" diff --git a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json index 93e5bf6955bbd..be575adaaaa04 100644 --- a/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/desktop-time-range-picker/desktop-time-range-picker.json @@ -6,7 +6,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultRangePosition": { "description": "The initial position in the edited date range. Used when the component is not controlled." diff --git a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json index fe0588fba5984..33033b85f885c 100644 --- a/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/mobile-time-range-picker/mobile-time-range-picker.json @@ -6,7 +6,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultRangePosition": { "description": "The initial position in the edited date range. Used when the component is not controlled." diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json index 9ea9191d315d8..841ba6bb9bd51 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-tabs/time-range-picker-tabs.json @@ -3,15 +3,10 @@ "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, "hidden": { "description": "Toggles visibility of the tabs allowing view switching." }, - "onViewChange": { - "description": "Callback called when a tab is clicked.", - "typeDescriptions": { "view": "The view to open" } - }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, - "timeIcon": { "description": "Time tab icon." }, - "view": { "description": "Currently visible picker view." } + "timeIcon": { "description": "Time tab icon." } }, "classDescriptions": { "root": { "description": "Styles applied to the root element." }, diff --git a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json index 5c4cf6beee932..d659ba6b6e8c2 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker-toolbar/time-range-picker-toolbar.json @@ -3,18 +3,12 @@ "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, "hidden": { "description": "If true, show the toolbar even in desktop mode." }, - "onViewChange": { - "description": "Callback called when a toolbar is clicked", - "typeDescriptions": { "view": "The view to open" } - }, "sx": { "description": "The system prop that allows defining system overrides as well as additional CSS styles." }, "toolbarPlaceholder": { "description": "Toolbar value placeholder—it is displayed when the value is empty." - }, - "view": { "description": "Currently visible picker view." }, - "views": { "description": "Available views." } + } }, "classDescriptions": { "container": { diff --git a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json index 0b61862bc5539..24c6630dfd554 100644 --- a/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json +++ b/docs/translations/api-docs/date-pickers/time-range-picker/time-range-picker.json @@ -6,7 +6,7 @@ "description": "If true, the main element is focused during the first mount. This main element is: - the element chosen by the visible view if any (i.e: the selected day on the day view). - the input element if there is a field rendered." }, "closeOnSelect": { - "description": "If true, the popover or modal will close after submitting the full date." + "description": "If true, the Picker will close after submitting the full date." }, "defaultRangePosition": { "description": "The initial position in the edited date range. Used when the component is not controlled." From 47cf2ecb4ddb771452f2efa47b9bed7963a5cbfa Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 16 Jan 2025 11:01:20 +0200 Subject: [PATCH 68/74] Use `pickerVariant` from ownerState --- .../DesktopTimeRangePicker.tsx | 1 - .../MobileTimeRangePicker.tsx | 1 - .../TimeRangePickerToolbar.tsx | 34 +++++++------------ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index 4734c037fe68c..ae6d3de807a23 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -129,7 +129,6 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }, toolbar: { hidden: true, - toolbarVariant: 'desktop', ...defaultizedProps.slotProps?.toolbar, }, }, diff --git a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx index 6c9948c0c05d4..eb85ee4964781 100644 --- a/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/MobileTimeRangePicker/MobileTimeRangePicker.tsx @@ -122,7 +122,6 @@ const MobileTimeRangePicker = React.forwardRef(function MobileTimeRangePicker< }, toolbar: { hidden: false, - toolbarVariant: 'mobile', ...defaultizedProps.slotProps?.toolbar, }, }, diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index e35499d29eac1..7f8406179e75c 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -53,7 +53,6 @@ export interface TimeRangePickerToolbarProps Pick, ExportedTimeRangePickerToolbarProps { ampm: boolean; - toolbarVariant?: PickerVariant; } export interface ExportedTimeRangePickerToolbarProps @@ -83,21 +82,21 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { const TimeRangePickerToolbarContainer = styled('div', { name: 'MuiTimeRangePickerToolbar', slot: 'Container', - shouldForwardProp: (prop) => prop !== 'toolbarVariant', + shouldForwardProp: (prop) => prop !== 'pickerVariant', overridesResolver: (_, styles) => styles.container, -})<{ toolbarVariant: PickerVariant }>({ +})<{ pickerVariant: PickerVariant }>({ display: 'flex', flex: 1, variants: [ { - props: { toolbarVariant: 'mobile' }, + props: { pickerVariant: 'mobile' }, style: { flexDirection: 'column', rowGap: 8, }, }, { - props: { toolbarVariant: 'desktop' }, + props: { pickerVariant: 'desktop' }, style: { flexDirection: 'row', gap: 1, @@ -126,7 +125,7 @@ const TimeRangePickerToolbarSeparator = styled(PickersToolbarText, { type TimeRangePickerToolbarTimeElementProps = Pick< TimeRangePickerToolbarProps, - 'ampm' | 'toolbarPlaceholder' | 'toolbarVariant' + 'ampm' | 'toolbarPlaceholder' > & MakeRequired< Pick< @@ -138,6 +137,7 @@ type TimeRangePickerToolbarTimeElementProps = Pick< value: PickerValidDate | null; utils: MuiPickersAdapter; separatorClasses: string; + pickerVariant: PickerVariant; }; function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElementProps) { @@ -150,13 +150,13 @@ function TimeRangePickerToolbarTimeElement(props: TimeRangePickerToolbarTimeElem utils, separatorClasses, toolbarPlaceholder, - toolbarVariant, + pickerVariant, } = props; const formatHours = (time: PickerValidDate) => ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); const meridiemMode = getMeridiem(value, utils); - const sectionWidth = toolbarVariant === 'desktop' ? MULTI_SECTION_CLOCK_SECTION_WIDTH : '100%'; + const sectionWidth = pickerVariant === 'desktop' ? MULTI_SECTION_CLOCK_SECTION_WIDTH : '100%'; return ( @@ -219,13 +219,13 @@ TimeRangePickerToolbarTimeElement.propTypes = { * @param {TView} view The new view. */ onViewChange: PropTypes.func.isRequired, + pickerVariant: PropTypes.oneOf(['desktop', 'mobile']).isRequired, separatorClasses: PropTypes.string.isRequired, /** * Toolbar value placeholder—it is displayed when the value is empty. * @default "––" */ toolbarPlaceholder: PropTypes.node, - toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), utils: PropTypes.object.isRequired, value: PropTypes.object, /** @@ -248,14 +248,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( const utils = useUtils(); const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); - const { - className, - ampm, - toolbarVariant = 'mobile', - toolbarPlaceholder = '--', - classes: classesProp, - ...other - } = props; + const { className, ampm, toolbarPlaceholder = '--', classes: classesProp, ...other } = props; const { value, view, setView, views } = usePickerContext< PickerRangeValue, @@ -301,7 +294,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( >
        @@ -362,7 +355,6 @@ TimeRangePickerToolbar.propTypes = { * @default "––" */ toolbarPlaceholder: PropTypes.node, - toolbarVariant: PropTypes.oneOf(['desktop', 'mobile']), } as any; export { TimeRangePickerToolbar }; From 750937d03e05e14c3fffc80c9df14ac882242f45 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 16 Jan 2025 11:31:09 +0200 Subject: [PATCH 69/74] cleanup --- .../src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx index ae6d3de807a23..0ceac76f92dcf 100644 --- a/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/DesktopTimeRangePicker/DesktopTimeRangePicker.tsx @@ -17,8 +17,6 @@ import { } from '@mui/x-date-pickers/MultiSectionDigitalClock'; import { digitalClockClasses } from '@mui/x-date-pickers/DigitalClock'; import { DesktopDateTimePickerLayout } from '@mui/x-date-pickers/DesktopDateTimePicker'; -import { PickersActionBarAction } from '@mui/x-date-pickers/PickersActionBar'; -import { PickerLayoutOwnerState } from '@mui/x-date-pickers/PickersLayout'; import { renderDigitalClockTimeView, renderMultiSectionDigitalClockTimeView, @@ -98,8 +96,6 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< const views = !shouldHoursRendererContainMeridiemView ? defaultizedProps.views.filter((view) => view !== 'meridiem') : defaultizedProps.views; - const actionBarActions: PickersActionBarAction[] = - defaultizedProps.shouldRenderTimeInASingleColumn ? [] : ['accept']; const props = { ...defaultizedProps, @@ -114,10 +110,6 @@ const DesktopTimeRangePicker = React.forwardRef(function DesktopTimeRangePicker< }, slotProps: { ...defaultizedProps.slotProps, - actionBar: (ownerState: PickerLayoutOwnerState) => ({ - actions: actionBarActions, - ...resolveComponentProps(defaultizedProps.slotProps?.actionBar, ownerState), - }), field: (ownerState: any) => ({ ...resolveComponentProps(defaultizedProps.slotProps?.field, ownerState), ...extractValidationProps(defaultizedProps), From 8f066de149ef3b28d71c98657d34a4867bf1db78 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 16 Jan 2025 12:05:12 +0200 Subject: [PATCH 70/74] Fix toolbar selected style --- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 9 ++++----- .../src/DateTimePicker/DateTimePickerToolbar.tsx | 2 +- .../internals/components/pickersToolbarTextClasses.ts | 7 +------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 7f8406179e75c..710f7ad9193a7 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -70,7 +70,7 @@ const TimeRangePickerToolbarRoot = styled(PickersToolbar, { })<{ ownerState: PickerToolbarOwnerState }>(({ theme }) => ({ borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, padding: '12px 0px 8px 0px', - [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: { + [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.root}[data-selected]`]: { color: (theme.vars || theme).palette.primary.main, fontWeight: theme.typography.fontWeightBold, }, @@ -245,8 +245,8 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( inProps: TimeRangePickerToolbarProps, ref: React.Ref, ) { - const utils = useUtils(); const props = useThemeProps({ props: inProps, name: 'MuiTimeRangePickerToolbar' }); + const utils = useUtils(); const { className, ampm, toolbarPlaceholder = '--', classes: classesProp, ...other } = props; @@ -258,7 +258,6 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( const ownerState = useToolbarOwnerState(); const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); const classes = useUtilityClasses(classesProp, ownerState); - const [start, end] = value; const handleStartRangeViewChange = React.useCallback( (newView: TimeViewWithMeridiem) => { @@ -299,7 +298,7 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( Date: Thu, 16 Jan 2025 12:11:40 +0200 Subject: [PATCH 71/74] l10n --- docs/data/date-pickers/localization/data.json | 4 ++-- packages/x-date-pickers/src/locales/zhTW.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/data/date-pickers/localization/data.json b/docs/data/date-pickers/localization/data.json index f836883c4d41d..657f65aab33b7 100644 --- a/docs/data/date-pickers/localization/data.json +++ b/docs/data/date-pickers/localization/data.json @@ -51,8 +51,8 @@ "languageTag": "zh-TW", "importName": "zhTW", "localeName": "Chinese (Taiwan)", - "missingKeysCount": 0, - "totalKeysCount": 50, + "missingKeysCount": 1, + "totalKeysCount": 51, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/locales/zhTW.ts" }, { diff --git a/packages/x-date-pickers/src/locales/zhTW.ts b/packages/x-date-pickers/src/locales/zhTW.ts index 2c85c8c0bd518..28e844191b481 100644 --- a/packages/x-date-pickers/src/locales/zhTW.ts +++ b/packages/x-date-pickers/src/locales/zhTW.ts @@ -39,6 +39,7 @@ const zhTWPickers: Partial = { dateTimePickerToolbarTitle: '選擇日期和時間', timePickerToolbarTitle: '選擇時間', dateRangePickerToolbarTitle: '選擇時間範圍', + // timeRangePickerToolbarTitle: 'Select time range', // Clock labels clockLabelText: (view, formattedTime) => From 0ac8012b5ce8e5f507b59fa5651d2b01b8c0b7e6 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 16 Jan 2025 18:02:56 +0200 Subject: [PATCH 72/74] Adjust after merge --- .../src/TimeRangePicker/TimeRangePickerTabs.tsx | 4 ++-- .../TimeRangePicker/TimeRangePickerTimeWrapper.tsx | 4 ++-- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx index 5991095d27cf0..fe57a2937b5f7 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTabs.tsx @@ -90,12 +90,12 @@ const TimeRangePickerTabs = function TimeRangePickerTabs(inProps: TimeRangePicke const translations = usePickerTranslations(); const { view, setView } = usePickerContext(); - const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); const classes = useUtilityClasses(classesProp); const handleChange = (event: React.SyntheticEvent, value: RangePosition) => { if (rangePosition !== value) { - onRangePositionChange(value); + setRangePosition(value); } if (view !== 'hours') { setView('hours'); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx index 5ce12ca8cb4d2..def2e593593fd 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerTimeWrapper.tsx @@ -50,7 +50,7 @@ function TimeRangePickerTimeWrapper< const { viewRenderer, value, onChange, defaultValue, onViewChange, views, className, ...other } = props; - const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); if (!viewRenderer) { return null; @@ -75,7 +75,7 @@ function TimeRangePickerTimeWrapper< }); const isFullRangeSelected = rangePosition === 'end' && isRangeValid(utils, newRange); if (selectionState === 'finish') { - onRangePositionChange?.(rangePosition === 'start' ? 'end' : 'start'); + setRangePosition(rangePosition === 'start' ? 'end' : 'start'); onViewChange?.(views[0]); } onChange(newRange, isFullRangeSelected ? 'finish' : 'partial', selectedView); diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index 710f7ad9193a7..ce6e4ffc3a4b9 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -50,7 +50,7 @@ const useUtilityClasses = ( export interface TimeRangePickerToolbarProps extends Omit, - Pick, + UseRangePositionResponse, ExportedTimeRangePickerToolbarProps { ampm: boolean; } @@ -256,27 +256,27 @@ const TimeRangePickerToolbar = React.forwardRef(function TimeRangePickerToolbar( >(); const translations = usePickerTranslations(); const ownerState = useToolbarOwnerState(); - const { rangePosition, onRangePositionChange } = usePickerRangePositionContext(); + const { rangePosition, setRangePosition } = usePickerRangePositionContext(); const classes = useUtilityClasses(classesProp, ownerState); const handleStartRangeViewChange = React.useCallback( (newView: TimeViewWithMeridiem) => { if (rangePosition !== 'start') { - onRangePositionChange('start'); + setRangePosition('start'); } setView(newView); }, - [onRangePositionChange, setView, rangePosition], + [setRangePosition, setView, rangePosition], ); const handleEndRangeViewChange = React.useCallback( (newView: TimeViewWithMeridiem) => { if (rangePosition !== 'end') { - onRangePositionChange('end'); + setRangePosition('end'); } setView(newView); }, - [onRangePositionChange, setView, rangePosition], + [setRangePosition, setView, rangePosition], ); if (!view) { From 20d206f7918dabd003c81482e6429a7f6781bff5 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 16 Jan 2025 18:07:47 +0200 Subject: [PATCH 73/74] Remove not used props type --- .../src/TimeRangePicker/TimeRangePickerToolbar.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx index ce6e4ffc3a4b9..bd657231f2794 100644 --- a/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx +++ b/packages/x-date-pickers-pro/src/TimeRangePicker/TimeRangePickerToolbar.tsx @@ -26,7 +26,6 @@ import { PickerToolbarOwnerState, } from '@mui/x-date-pickers/internals'; import { usePickerContext, usePickerTranslations } from '@mui/x-date-pickers/hooks'; -import { UseRangePositionResponse } from '../internals/hooks/useRangePosition'; import { TimeRangePickerToolbarClasses, getTimeRangePickerToolbarUtilityClass, @@ -50,7 +49,6 @@ const useUtilityClasses = ( export interface TimeRangePickerToolbarProps extends Omit, - UseRangePositionResponse, ExportedTimeRangePickerToolbarProps { ampm: boolean; } @@ -338,8 +336,6 @@ TimeRangePickerToolbar.propTypes = { * @default `true` for Desktop, `false` for Mobile. */ hidden: PropTypes.bool, - onRangePositionChange: PropTypes.func.isRequired, - rangePosition: PropTypes.oneOf(['end', 'start']).isRequired, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ From 10c6c4ff3d6732ed0066dd573079d4b583b9090b Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 4 Feb 2025 14:09:00 +0200 Subject: [PATCH 74/74] Underline current range position --- .../useDesktopRangePicker.tsx | 7 +++++- .../PickersSectionList/PickersSectionList.tsx | 25 +++++++++++++++---- .../hooks/useField/buildSectionsFromFormat.ts | 1 + .../hooks/useField/useFieldV7TextField.ts | 4 +++ packages/x-date-pickers/src/models/fields.ts | 4 +++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx index f2daf37e94384..9c4d6d1a722ea 100644 --- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx +++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx @@ -159,7 +159,12 @@ export const useDesktopRangePicker = < > - + ({ + textDecoration: 'underline transparent', + textDecorationThickness: '3px', + textUnderlineOffset: '100%', + transition: theme.transitions.create('all', { + duration: theme.transitions.duration.standard, + }), + [`[data-active-range-position="start"] &[data-range-position="start"], + [data-active-range-position="end"] &[data-range-position="end"]`]: { + textDecorationColor: (theme.vars || theme).palette.primary.main, + }, +}); + export const PickersSectionListRoot = styled('div', { name: 'MuiPickersSectionList', slot: 'Root', @@ -32,17 +45,19 @@ export const PickersSectionListSectionSeparator = styled('span', { name: 'MuiPickersSectionList', slot: 'SectionSeparator', overridesResolver: (props, styles) => styles.sectionSeparator, -})({ +})(({ theme }) => ({ whiteSpace: 'pre', -}); + ...underlineStyle(theme), +})); export const PickersSectionListSectionContent = styled('span', { name: 'MuiPickersSectionList', slot: 'SectionContent', overridesResolver: (props, styles) => styles.sectionContent, -})({ +})(({ theme }) => ({ outline: 'none', -}); + ...underlineStyle(theme), +})); const useUtilityClasses = (classes: Partial | undefined) => { const slots = { diff --git a/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts b/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts index e4022303b6eea..36b0d59eb48b4 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts @@ -244,6 +244,7 @@ const buildSections = ( startSeparator += char; } else { sections[sections.length - 1].endSeparator += char; + sections[sections.length - 1].isEndFormatSeparator = true; } } diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts index d59c2ceea4adb..d9056a776482e 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV7TextField.ts @@ -13,6 +13,7 @@ import { getActiveElement } from '../../utils/utils'; import { PickersSectionElement, PickersSectionListRef } from '../../../PickersSectionList'; import { usePickerTranslations } from '../../../hooks/usePickerTranslations'; import { useUtils } from '../useUtils'; +import { FieldRangeSection } from '../../models'; export const useFieldV7TextField: UseFieldTextField = (params) => { const { @@ -421,6 +422,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { const elements = React.useMemo(() => { return state.sections.map((section, index) => { const isEditable = !isContainerEditable && !disabled && !readOnly; + const dateRangePosition = (section as FieldRangeSection).dateName || undefined; return { container: { 'data-sectionindex': index, @@ -431,6 +433,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { contentEditable: !isContainerEditable && !disabled && !readOnly, role: 'spinbutton', id: `${id}-${section.type}`, + 'data-range-position': dateRangePosition, 'aria-labelledby': `${id}-${section.type}`, 'aria-readonly': readOnly, 'aria-valuenow': getSectionValueNow(section, utils), @@ -460,6 +463,7 @@ export const useFieldV7TextField: UseFieldTextField = (params) => { }, after: { children: section.endSeparator, + 'data-range-position': section.isEndFormatSeparator ? dateRangePosition : undefined, }, }; }); diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 2002619cb4e25..05d47a5db5355 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -87,6 +87,10 @@ export interface FieldSection { * For example, on Day.js, the `year` section of the format `[year] YYYY` has a start separator equal to `[year]` */ endSeparator: string; + /** + * If `true`, the `endSeparator` is a format separator (i.e. ":" or "/"). + */ + isEndFormatSeparator?: boolean; } // If `PickerValidDate` contains `any`, then `TValue extends PickerRangeValue` will return true, so we have to handle this edge case first.