From 0e6270e05c3b18c3539ac26f889f339f225667a1 Mon Sep 17 00:00:00 2001 From: flavien Date: Tue, 29 Oct 2024 17:44:30 +0100 Subject: [PATCH] [pickers] Use the new ownerState in DateCalendar, DateRangeCalendar, MonthCalendar and YearCalendar --- .../DateRangeCalendar/DateRangeCalendar.tsx | 27 ++++++++---- .../DateRangeCalendar.types.ts | 17 +++----- .../src/DateCalendar/DateCalendar.tsx | 19 +++++---- .../src/DateCalendar/DateCalendar.types.ts | 4 +- .../src/DateCalendar/DayCalendar.tsx | 35 +++++++++------- .../x-date-pickers/src/DateCalendar/index.ts | 1 + .../src/MonthCalendar/MonthCalendar.tsx | 16 +++---- .../src/MonthCalendar/MonthCalendar.types.ts | 10 +++-- .../src/MonthCalendar/PickersMonth.tsx | 42 +++++++++++++------ .../src/YearCalendar/PickersYear.tsx | 42 +++++++++++++------ .../src/YearCalendar/YearCalendar.tsx | 16 +++---- .../src/YearCalendar/YearCalendar.types.ts | 10 +++-- .../x-date-pickers/src/internals/index.ts | 1 + 13 files changed, 148 insertions(+), 92 deletions(-) diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx index e41859e4304f6..606fb3fb0398b 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx @@ -25,11 +25,13 @@ import { DEFAULT_DESKTOP_MODE_MEDIA_QUERY, useControlledValueWithTimezone, useViews, + usePickersPrivateContext, } from '@mui/x-date-pickers/internals'; import { warnOnce } from '@mui/x-internals/warning'; import { PickerValidDate } from '@mui/x-date-pickers/models'; import { getReleaseInfo } from '../internals/utils/releaseInfo'; import { + DateRangeCalendarClasses, dateRangeCalendarClasses, getDateRangeCalendarUtilityClass, } from './dateRangeCalendarClasses'; @@ -62,7 +64,7 @@ const DateRangeCalendarRoot = styled('div', { name: 'MuiDateRangeCalendar', slot: 'Root', overridesResolver: (_, styles) => styles.root, -})<{ ownerState: DateRangeCalendarOwnerState }>({ +})<{ ownerState: DateRangeCalendarOwnerState }>({ display: 'flex', flexDirection: 'row', }); @@ -133,12 +135,14 @@ function useDateRangeCalendarDefaultizedProps( }; } -const useUtilityClasses = (ownerState: DateRangeCalendarOwnerState) => { - const { classes, isDragging } = ownerState; +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: DateRangeCalendarOwnerState, +) => { const slots = { root: ['root'], monthContainer: ['monthContainer'], - dayCalendar: [isDragging && 'dayDragging'], + dayCalendar: [ownerState.isDraggingDay && 'dayDragging'], }; return composeClasses(slots, getDateRangeCalendarUtilityClass, classes); @@ -172,6 +176,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< referenceDate, onChange, className, + classes: classesProp, disableFuture, disablePast, minDate, @@ -299,8 +304,12 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< timezone, }); - const ownerState = { ...props, isDragging }; - const classes = useUtilityClasses(ownerState); + const { ownerState: pickersOwnerState } = usePickersPrivateContext(); + const ownerState: DateRangeCalendarOwnerState = { + ...pickersOwnerState, + isDraggingDay: isDragging, + }; + const classes = useUtilityClasses(classesProp, ownerState); const draggingRange = React.useMemo>(() => { if (!valueDayRange[0] || !valueDayRange[1] || !rangeDragDay) { @@ -370,7 +379,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< slots, slotProps, }, - ownerState: props, + ownerState, }); const prevValue = React.useRef | null>(null); @@ -455,7 +464,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< const slotPropsForDayCalendar = { ...slotProps, day: (dayOwnerState) => { - const { day } = dayOwnerState; + const { day, isDaySelected } = dayOwnerState; const isSelectedStartDate = isStartOfRange(utils, day, valueDayRange); const isSelectedEndDate = isEndOfRange(utils, day, valueDayRange); const shouldInitDragging = !shouldDisableDragEditing && valueDayRange[0] && valueDayRange[1]; @@ -488,7 +497,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar< onMouseEnter: shouldHavePreview ? handleDayMouseEnter : undefined, // apply selected styling to the dragging start or end day isVisuallySelected: - dayOwnerState.selected || (isDragging && (isStartOfHighlighting || isEndOfHighlighting)), + isDaySelected || (isDragging && (isStartOfHighlighting || isEndOfHighlighting)), 'data-position': datePosition, ...dragEventHandlers, draggable: isElementDraggable ? true : undefined, diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts index ac56c4d441496..3be13a15764ee 100644 --- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts +++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.types.ts @@ -2,12 +2,13 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; import { SlotComponentProps } from '@mui/utils'; import { Theme } from '@mui/material/styles'; -import { PickerValidDate, TimezoneProps } from '@mui/x-date-pickers/models'; +import { PickerOwnerState, PickerValidDate, TimezoneProps } from '@mui/x-date-pickers/models'; import { PickersCalendarHeader, PickersCalendarHeaderSlots, PickersCalendarHeaderSlotProps, } from '@mui/x-date-pickers/PickersCalendarHeader'; +import { PickersDayOwnerState } from '@mui/x-date-pickers/DateCalendar'; import { BaseDateValidationProps, DefaultizedProps, @@ -16,7 +17,6 @@ import { DayCalendarSlotProps, PickersArrowSwitcherSlots, PickersArrowSwitcherSlotProps, - DayCalendarProps, ExportedUseViewsOptions, } from '@mui/x-date-pickers/internals'; import { DayRangeValidationProps } from '../internals/models/dateRange'; @@ -51,13 +51,9 @@ export interface DateRangeCalendarSlotProps calendarHeader?: SlotComponentProps< typeof PickersCalendarHeader, {}, - DateRangeCalendarProps - >; - day?: SlotComponentProps< - typeof DateRangePickerDay, - {}, - DayCalendarProps & { day: TDate; selected: boolean } + DateRangeCalendarOwnerState >; + day?: SlotComponentProps; } export interface ExportedDateRangeCalendarProps @@ -156,9 +152,8 @@ export interface DateRangeCalendarProps availableRangePositions?: RangePosition[]; } -export interface DateRangeCalendarOwnerState - extends DateRangeCalendarProps { - isDragging: boolean; +export interface DateRangeCalendarOwnerState extends PickerOwnerState { + isDraggingDay: boolean; } export type DateRangeCalendarDefaultizedProps = DefaultizedProps< diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx index 77af1660e28fa..edaa6b21f8dbe 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx @@ -25,15 +25,15 @@ import { } from '../internals/utils/date-utils'; import { PickerViewRoot } from '../internals/components/PickerViewRoot'; import { useDefaultReduceAnimations } from '../internals/hooks/useDefaultReduceAnimations'; -import { getDateCalendarUtilityClass } from './dateCalendarClasses'; +import { DateCalendarClasses, getDateCalendarUtilityClass } from './dateCalendarClasses'; import { BaseDateValidationProps } from '../internals/models/validation'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { singleItemValueManager } from '../internals/utils/valueManagers'; import { VIEW_HEIGHT } from '../internals/constants/dimensions'; -import { PickerValidDate } from '../models'; +import { PickerOwnerState, PickerValidDate } from '../models'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; -const useUtilityClasses = (ownerState: DateCalendarProps) => { - const { classes } = ownerState; +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], viewTransitionContainer: ['viewTransitionContainer'], @@ -73,7 +73,7 @@ const DateCalendarRoot = styled(PickerViewRoot, { name: 'MuiDateCalendar', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: DateCalendarProps }>({ +})<{ ownerState: PickerOwnerState }>({ display: 'flex', flexDirection: 'column', height: VIEW_HEIGHT, @@ -83,7 +83,7 @@ const DateCalendarViewTransitionContainer = styled(PickersFadeTransitionGroup, { name: 'MuiDateCalendar', slot: 'ViewTransitionContainer', overridesResolver: (props, styles) => styles.viewTransitionContainer, -})<{ ownerState: DateCalendarProps }>({}); +})<{ ownerState: PickerOwnerState }>({}); type DateCalendarComponent = (( props: DateCalendarProps & React.RefAttributes, @@ -105,6 +105,7 @@ export const DateCalendar = React.forwardRef(function DateCalendar, ) { const utils = useUtils(); + const { ownerState } = usePickersPrivateContext(); const id = useId(); const props = useDateCalendarDefaultizedProps(inProps, 'MuiDateCalendar'); @@ -127,6 +128,7 @@ export const DateCalendar = React.forwardRef(function DateCalendar { @@ -295,8 +297,7 @@ export const DateCalendar = React.forwardRef(function DateCalendar> = { disablePast, diff --git a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts index cc378565575de..8a872742b850d 100644 --- a/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts +++ b/packages/x-date-pickers/src/DateCalendar/DateCalendar.types.ts @@ -17,7 +17,7 @@ import { DayValidationProps, } from '../internals/models/validation'; import { ExportedUseViewsOptions } from '../internals/hooks/useViews'; -import { DateView, PickerValidDate, TimezoneProps } from '../models'; +import { DateView, PickerOwnerState, PickerValidDate, TimezoneProps } from '../models'; import { DefaultizedProps } from '../internals/models/helpers'; import { ExportedYearCalendarProps, @@ -48,7 +48,7 @@ export interface DateCalendarSlotProps DayCalendarSlotProps, MonthCalendarSlotProps, YearCalendarSlotProps { - calendarHeader?: SlotComponentProps>; + calendarHeader?: SlotComponentProps; } export interface ExportedDateCalendarProps diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index 5348469f3c848..6e3ad31bc52ca 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -28,8 +28,10 @@ import { import { useIsDateDisabled } from './useIsDateDisabled'; import { findClosestEnabledDate, getWeekdays } from '../internals/utils/date-utils'; import { DayCalendarClasses, getDayCalendarUtilityClass } from './dayCalendarClasses'; -import { PickerValidDate, TimezoneProps } from '../models'; +import { PickerOwnerState, PickerValidDate, TimezoneProps } from '../models'; import { DefaultizedProps, SlotComponentPropsFromProps } from '../internals/models/helpers'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; +import { DateCalendarClasses } from './dateCalendarClasses'; export interface DayCalendarSlots { /** @@ -41,11 +43,13 @@ export interface DayCalendarSlots { } export interface DayCalendarSlotProps { - day?: SlotComponentPropsFromProps< - PickersDayProps, - {}, - DayCalendarProps & { day: TDate; selected: boolean } - >; + day?: SlotComponentPropsFromProps, {}, PickersDayOwnerState>; +} + +export interface PickersDayOwnerState extends PickerOwnerState { + isDaySelected: boolean; + isDayDisabled: boolean; + day: TDate; } export interface ExportedDayCalendarProps @@ -120,8 +124,7 @@ export interface DayCalendarProps slotProps?: DayCalendarSlotProps; } -const useUtilityClasses = (ownerState: DayCalendarProps) => { - const { classes } = ownerState; +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], header: ['header'], @@ -267,11 +270,17 @@ function WrappedDay({ const utils = useUtils(); const now = useNow(timezone); + const { ownerState } = usePickersPrivateContext(); const isFocusableDay = focusableDay !== null && utils.isSameDay(day, focusableDay); const isSelected = selectedDays.some((selectedDay) => utils.isSameDay(selectedDay, day)); const isToday = utils.isSameDay(day, now); + const isDisabled = React.useMemo( + () => disabled || isDateDisabled(day), + [disabled, isDateDisabled, day], + ); + const Day = slots?.day ?? PickersDay; // We don't want to pass to ownerState down, to avoid re-rendering all the day whenever a prop changes. const { ownerState: dayOwnerState, ...dayProps } = useSlotProps({ @@ -286,14 +295,9 @@ function WrappedDay({ 'data-timestamp': utils.toJsDate(day).valueOf(), ...other, }, - ownerState: { ...parentProps, day, selected: isSelected }, + ownerState: { ...ownerState, day, isDayDisabled: isDisabled, isDaySelected: isSelected }, }); - const isDisabled = React.useMemo( - () => disabled || isDateDisabled(day), - [disabled, isDateDisabled, day], - ); - const outsideCurrentMonth = React.useMemo( () => utils.getMonth(day) !== currentMonthNumber, [utils, day, currentMonthNumber], @@ -343,6 +347,7 @@ export function DayCalendar(inProps: DayCalendarP const { onFocusedDayChange, className, + classes: classesProp, currentMonth, selectedDays, focusedDay, @@ -372,7 +377,7 @@ export function DayCalendar(inProps: DayCalendarP } = props; const now = useNow(timezone); - const classes = useUtilityClasses(props); + const classes = useUtilityClasses(classesProp); const isRtl = useRtl(); const isDateDisabled = useIsDateDisabled({ diff --git a/packages/x-date-pickers/src/DateCalendar/index.ts b/packages/x-date-pickers/src/DateCalendar/index.ts index 8e33e9e81f2a8..fcc80b87c4bb9 100644 --- a/packages/x-date-pickers/src/DateCalendar/index.ts +++ b/packages/x-date-pickers/src/DateCalendar/index.ts @@ -4,6 +4,7 @@ export type { DateCalendarSlots, DateCalendarSlotProps, } from './DateCalendar.types'; +export type { PickersDayOwnerState } from './DayCalendar'; export { getDateCalendarUtilityClass, dateCalendarClasses } from './dateCalendarClasses'; export type { DateCalendarClassKey, DateCalendarClasses } from './dateCalendarClasses'; diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx index c4e8e501391e0..e4f1d636085fd 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx @@ -11,7 +11,7 @@ import { } from '@mui/utils'; import { PickersMonth } from './PickersMonth'; import { useUtils, useNow, useDefaultDates } from '../internals/hooks/useUtils'; -import { getMonthCalendarUtilityClass } from './monthCalendarClasses'; +import { getMonthCalendarUtilityClass, MonthCalendarClasses } from './monthCalendarClasses'; import { applyDefaultDate, getMonthsInYear } from '../internals/utils/date-utils'; import { DefaultizedProps } from '../internals/models/helpers'; import { MonthCalendarProps } from './MonthCalendar.types'; @@ -19,11 +19,10 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { DIALOG_WIDTH } from '../internals/constants/dimensions'; -import { PickerValidDate } from '../models'; - -const useUtilityClasses = (ownerState: MonthCalendarProps) => { - const { classes } = ownerState; +import { PickerOwnerState, PickerValidDate } from '../models'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], }; @@ -58,7 +57,7 @@ const MonthCalendarRoot = styled('div', { name: 'MuiMonthCalendar', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: MonthCalendarProps }>({ +})<{ ownerState: PickerOwnerState }>({ display: 'flex', flexWrap: 'wrap', alignContent: 'stretch', @@ -88,6 +87,7 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar(timezone); const isRtl = useRtl(); const utils = useUtils(); + const { ownerState } = usePickersPrivateContext(); const referenceDate = React.useMemo( () => @@ -138,8 +139,7 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar utils.getMonth(now), [utils, now]); diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts index f6e79866d913b..4716d3bb9bb03 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.types.ts @@ -3,10 +3,14 @@ import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; import { MonthCalendarClasses } from './monthCalendarClasses'; import { BaseDateValidationProps, MonthValidationProps } from '../internals/models/validation'; -import { PickerValidDate, TimezoneProps } from '../models'; -import type { PickersMonthProps } from './PickersMonth'; +import { PickerOwnerState, PickerValidDate, TimezoneProps } from '../models'; import { SlotComponentPropsFromProps } from '../internals/models/helpers'; +export interface PickersMonthOwnerState extends PickerOwnerState { + isMonthSelected: boolean; + isMonthDisabled: boolean; +} + export interface MonthCalendarSlots { /** * Button displayed to render a single month in the `month` view. @@ -19,7 +23,7 @@ export interface MonthCalendarSlotProps { monthButton?: SlotComponentPropsFromProps< React.HTMLAttributes & { sx: SxProps }, {}, - PickersMonthProps + PickersMonthOwnerState >; } diff --git a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx index 996df34b165b8..6803955353e61 100644 --- a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx @@ -9,7 +9,12 @@ import { pickersMonthClasses, PickersMonthClasses, } from './pickersMonthClasses'; -import { MonthCalendarSlotProps, MonthCalendarSlots } from './MonthCalendar.types'; +import { + MonthCalendarSlotProps, + MonthCalendarSlots, + PickersMonthOwnerState, +} from './MonthCalendar.types'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; export interface ExportedPickersMonthProps { classes?: Partial; @@ -34,12 +39,17 @@ export interface PickersMonthProps extends ExportedPickersMonthProps { slotProps?: MonthCalendarSlotProps; } -const useUtilityClasses = (ownerState: PickersMonthProps) => { - const { disabled, selected, classes } = ownerState; - +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersMonthOwnerState, +) => { const slots = { root: ['root'], - monthButton: ['monthButton', disabled && 'disabled', selected && 'selected'], + monthButton: [ + 'monthButton', + ownerState.isMonthDisabled && 'disabled', + ownerState.isMonthSelected && 'selected', + ], }; return composeClasses(slots, getPickersMonthUtilityClass, classes); @@ -50,7 +60,7 @@ const PickersMonthRoot = styled('div', { slot: 'Root', overridesResolver: (_, styles) => [styles.root], })<{ - ownerState: PickersMonthProps; + ownerState: PickersMonthOwnerState; }>({ display: 'flex', alignItems: 'center', @@ -68,7 +78,7 @@ const MonthCalendarButton = styled('button', { { [`&.${pickersMonthClasses.selected}`]: styles.selected }, ], })<{ - ownerState?: PickersMonthProps; + ownerState?: PickersMonthOwnerState; }>(({ theme }) => ({ color: 'unset', backgroundColor: 'transparent', @@ -117,9 +127,10 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon const { autoFocus, className, + classes: classesProp, children, - disabled, - selected, + disabled = false, + selected = false, value, tabIndex, onClick, @@ -136,7 +147,14 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon } = props; const ref = React.useRef(null); - const classes = useUtilityClasses(props); + const { ownerState: pickersOwnerState } = usePickersPrivateContext(); + const ownerState: PickersMonthOwnerState = { + ...pickersOwnerState, + isMonthDisabled: disabled, + isMonthSelected: selected, + }; + + const classes = useUtilityClasses(classesProp, ownerState); // We can't forward the `autoFocus` to the button because it is a native button, not a MUI Button useEnhancedEffect(() => { @@ -165,7 +183,7 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon onFocus: (event: React.FocusEvent) => onFocus(event, value), onBlur: (event: React.FocusEvent) => onBlur(event, value), }, - ownerState: props, + ownerState, className: classes.monthButton, }); @@ -173,7 +191,7 @@ export const PickersMonth = React.memo(function PickersMonth(inProps: PickersMon diff --git a/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx b/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx index 6425f9936431a..182b71503969a 100644 --- a/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx +++ b/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx @@ -9,7 +9,13 @@ import { pickersYearClasses, PickersYearClasses, } from './pickersYearClasses'; -import { YearCalendarSlotProps, YearCalendarSlots } from './YearCalendar.types'; +import { + PickersYearOwnerState, + YearCalendarSlotProps, + YearCalendarSlots, +} from './YearCalendar.types'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; +import { PickerOwnerState } from '../models/pickers'; export interface ExportedPickersYearProps { classes?: Partial; @@ -33,12 +39,17 @@ export interface PickersYearProps extends ExportedPickersYearProps { slotProps?: YearCalendarSlotProps; } -const useUtilityClasses = (ownerState: PickersYearProps) => { - const { disabled, selected, classes } = ownerState; - +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersYearOwnerState, +) => { const slots = { root: ['root'], - yearButton: ['yearButton', disabled && 'disabled', selected && 'selected'], + yearButton: [ + 'yearButton', + ownerState.isYearDisabled && 'disabled', + ownerState.isYearSelected && 'selected', + ], }; return composeClasses(slots, getPickersYearUtilityClass, classes); @@ -48,7 +59,7 @@ const PickersYearRoot = styled('div', { name: 'MuiPickersYear', slot: 'Root', overridesResolver: (_, styles) => [styles.root], -})<{ ownerState: PickersYearProps }>({ +})<{ ownerState: PickerOwnerState }>({ display: 'flex', alignItems: 'center', justifyContent: 'center', @@ -64,7 +75,7 @@ const YearCalendarButton = styled('button', { { [`&.${pickersYearClasses.disabled}`]: styles.disabled }, { [`&.${pickersYearClasses.selected}`]: styles.selected }, ], -})<{ ownerState: PickersYearProps }>(({ theme }) => ({ +})<{ ownerState: PickerOwnerState }>(({ theme }) => ({ color: 'unset', backgroundColor: 'transparent', border: 0, @@ -112,9 +123,10 @@ export const PickersYear = React.memo(function PickersYear(inProps: PickersYearP const { autoFocus, className, + classes: classesProp, children, - disabled, - selected, + disabled = false, + selected = false, value, tabIndex, onClick, @@ -130,7 +142,13 @@ export const PickersYear = React.memo(function PickersYear(inProps: PickersYearP } = props; const ref = React.useRef(null); - const classes = useUtilityClasses(props); + const { ownerState: pickersOwnerState } = usePickersPrivateContext(); + const ownerState: PickersYearOwnerState = { + ...pickersOwnerState, + isYearDisabled: disabled, + isYearSelected: selected, + }; + const classes = useUtilityClasses(classesProp, ownerState); // We can't forward the `autoFocus` to the button because it is a native button, not a MUI Button useEnhancedEffect(() => { @@ -158,7 +176,7 @@ export const PickersYear = React.memo(function PickersYear(inProps: PickersYearP onFocus: (event: React.FocusEvent) => onFocus(event, value), onBlur: (event: React.FocusEvent) => onBlur(event, value), }, - ownerState: props, + ownerState, className: classes.yearButton, }); @@ -166,7 +184,7 @@ export const PickersYear = React.memo(function PickersYear(inProps: PickersYearP diff --git a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx index 54ba0510d32c1..130d4f5f65d5a 100644 --- a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx +++ b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx @@ -12,7 +12,7 @@ import { } from '@mui/utils'; import { PickersYear } from './PickersYear'; import { useUtils, useNow, useDefaultDates } from '../internals/hooks/useUtils'; -import { getYearCalendarUtilityClass } from './yearCalendarClasses'; +import { getYearCalendarUtilityClass, YearCalendarClasses } from './yearCalendarClasses'; import { DefaultizedProps } from '../internals/models/helpers'; import { applyDefaultDate } from '../internals/utils/date-utils'; import { YearCalendarProps } from './YearCalendar.types'; @@ -20,11 +20,10 @@ import { singleItemValueManager } from '../internals/utils/valueManagers'; import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate'; import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone'; import { DIALOG_WIDTH, MAX_CALENDAR_HEIGHT } from '../internals/constants/dimensions'; -import { PickerValidDate } from '../models'; - -const useUtilityClasses = (ownerState: YearCalendarProps) => { - const { classes } = ownerState; +import { PickerOwnerState, PickerValidDate } from '../models'; +import { usePickersPrivateContext } from '../internals/hooks/usePickersPrivateContext'; +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], }; @@ -60,7 +59,7 @@ const YearCalendarRoot = styled('div', { name: 'MuiYearCalendar', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: YearCalendarProps }>({ +})<{ ownerState: PickerOwnerState }>({ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', @@ -97,6 +96,7 @@ export const YearCalendar = React.forwardRef(function YearCalendar(timezone); const isRtl = useRtl(); const utils = useUtils(); + const { ownerState } = usePickersPrivateContext(); const referenceDate = React.useMemo( () => @@ -147,8 +148,7 @@ export const YearCalendar = React.forwardRef(function YearCalendar utils.getYear(now), [utils, now]); const selectedYear = React.useMemo(() => { diff --git a/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts b/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts index 8a3d3a94d946c..70846ec992592 100644 --- a/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts +++ b/packages/x-date-pickers/src/YearCalendar/YearCalendar.types.ts @@ -3,10 +3,14 @@ import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; import { YearCalendarClasses } from './yearCalendarClasses'; import { BaseDateValidationProps, YearValidationProps } from '../internals/models/validation'; -import { PickerValidDate, TimezoneProps } from '../models'; -import type { PickersYearProps } from './PickersYear'; +import { PickerOwnerState, PickerValidDate, TimezoneProps } from '../models'; import { SlotComponentPropsFromProps } from '../internals/models/helpers'; +export interface PickersYearOwnerState extends PickerOwnerState { + isYearSelected: boolean; + isYearDisabled: boolean; +} + export interface YearCalendarSlots { /** * Button displayed to render a single year in the `year` view. @@ -19,7 +23,7 @@ export interface YearCalendarSlotProps { yearButton?: SlotComponentPropsFromProps< React.HTMLAttributes & { sx: SxProps }, {}, - PickersYearProps + PickersYearOwnerState >; } diff --git a/packages/x-date-pickers/src/internals/index.ts b/packages/x-date-pickers/src/internals/index.ts index 49700d3461341..b37548997c4f7 100644 --- a/packages/x-date-pickers/src/internals/index.ts +++ b/packages/x-date-pickers/src/internals/index.ts @@ -84,6 +84,7 @@ export type { PickerViewRenderer, UsePickerViewsProps, } from './hooks/usePicker/usePickerViews'; +export { usePickersPrivateContext } from './hooks/usePickersPrivateContext'; export { useStaticPicker } from './hooks/useStaticPicker'; export type { StaticOnlyPickerProps,