From a6aaa0d51d14cba96fca4a6801f3eda646fb9f8a Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 4 Jun 2024 10:58:46 +0200 Subject: [PATCH 1/4] [pickers] Use useRtl instead of useTheme to access direction --- .../src/internals/utils/valueManagers.ts | 4 +-- .../src/DateCalendar/DayCalendar.tsx | 22 ++++++++-------- .../DateTimePicker/DateTimePickerToolbar.tsx | 16 ++++++------ .../src/MonthCalendar/MonthCalendar.tsx | 8 +++--- .../src/TimePicker/TimePickerToolbar.tsx | 13 +++++----- .../src/YearCalendar/YearCalendar.tsx | 8 +++--- .../PickersArrowSwitcher.tsx | 11 ++++---- .../hooks/useField/buildSectionsFromFormat.ts | 8 +++--- .../src/internals/hooks/useField/useField.ts | 9 +++---- .../hooks/useField/useField.types.ts | 4 +-- .../hooks/useField/useField.utils.ts | 6 ++--- .../internals/hooks/useField/useFieldState.ts | 13 +++++----- .../hooks/useField/useFieldV6TextField.ts | 25 +++++++++---------- 13 files changed, 73 insertions(+), 74 deletions(-) diff --git a/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts b/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts index b3dc56a8d2ce..54d0c7234c51 100644 --- a/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts +++ b/packages/x-date-pickers-pro/src/internals/utils/valueManagers.ts @@ -144,12 +144,12 @@ export const getRangeFieldValueManager = ({ ...dateRangeSections.endDate, ]); }, - getV6InputValueFromSections: (sections, localizedDigits, isRTL) => { + getV6InputValueFromSections: (sections, localizedDigits, isRtl) => { const dateRangeSections = splitDateRangeSections(sections); return createDateStrForV6InputFromSections( [...dateRangeSections.startDate, ...dateRangeSections.endDate], localizedDigits, - isRTL, + isRtl, ); }, parseValueStr: (valueStr, referenceValue, parseDate) => { diff --git a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx index de6365bc00af..3d68b6a08e95 100644 --- a/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx +++ b/packages/x-date-pickers/src/DateCalendar/DayCalendar.tsx @@ -2,7 +2,8 @@ import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; import Typography from '@mui/material/Typography'; import { useSlotProps, SlotComponentProps } from '@mui/base/utils'; -import { styled, useTheme, useThemeProps } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; +import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses, unstable_useControlled as useControlled, @@ -371,8 +372,7 @@ export function DayCalendar(inProps: DayCalendarP const now = useNow(timezone); const classes = useUtilityClasses(props); - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRtl = useRtl(); const isDateDisabled = useIsDateDisabled({ shouldDisableDate, @@ -428,14 +428,14 @@ export function DayCalendar(inProps: DayCalendarP event.preventDefault(); break; case 'ArrowLeft': { - const newFocusedDayDefault = utils.addDays(day, isRTL ? 1 : -1); - const nextAvailableMonth = utils.addMonths(day, isRTL ? 1 : -1); + const newFocusedDayDefault = utils.addDays(day, isRtl ? 1 : -1); + const nextAvailableMonth = utils.addMonths(day, isRtl ? 1 : -1); const closestDayToFocus = findClosestEnabledDate({ utils, date: newFocusedDayDefault, - minDate: isRTL ? newFocusedDayDefault : utils.startOfMonth(nextAvailableMonth), - maxDate: isRTL ? utils.endOfMonth(nextAvailableMonth) : newFocusedDayDefault, + minDate: isRtl ? newFocusedDayDefault : utils.startOfMonth(nextAvailableMonth), + maxDate: isRtl ? utils.endOfMonth(nextAvailableMonth) : newFocusedDayDefault, isDateDisabled, timezone, }); @@ -444,14 +444,14 @@ export function DayCalendar(inProps: DayCalendarP break; } case 'ArrowRight': { - const newFocusedDayDefault = utils.addDays(day, isRTL ? -1 : 1); - const nextAvailableMonth = utils.addMonths(day, isRTL ? -1 : 1); + const newFocusedDayDefault = utils.addDays(day, isRtl ? -1 : 1); + const nextAvailableMonth = utils.addMonths(day, isRtl ? -1 : 1); const closestDayToFocus = findClosestEnabledDate({ utils, date: newFocusedDayDefault, - minDate: isRTL ? utils.startOfMonth(nextAvailableMonth) : newFocusedDayDefault, - maxDate: isRTL ? newFocusedDayDefault : utils.endOfMonth(nextAvailableMonth), + minDate: isRtl ? utils.startOfMonth(nextAvailableMonth) : newFocusedDayDefault, + maxDate: isRtl ? newFocusedDayDefault : utils.endOfMonth(nextAvailableMonth), isDateDisabled, timezone, }); diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx index bf3de23a78fe..ecf9b6cb71ab 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { styled, useThemeProps, useTheme, Theme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; +import { styled, useThemeProps } from '@mui/material/styles'; import composeClasses from '@mui/utils/composeClasses'; import clsx from 'clsx'; import { PickersToolbarText } from '../internals/components/PickersToolbarText'; @@ -41,13 +42,15 @@ export interface DateTimePickerToolbarProps ampmInClock?: boolean; } -const useUtilityClasses = (ownerState: DateTimePickerToolbarProps & { theme: Theme }) => { - const { classes, theme, isLandscape } = ownerState; +const useUtilityClasses = (ownerState: DateTimePickerToolbarProps) => { + const isRtl = useRtl(); + const { classes, isLandscape } = ownerState; + const slots = { root: ['root'], dateContainer: ['dateContainer'], - timeContainer: ['timeContainer', theme.direction === 'rtl' && 'timeLabelReverse'], - timeDigitsContainer: ['timeDigitsContainer', theme.direction === 'rtl' && 'timeLabelReverse'], + timeContainer: ['timeContainer', isRtl && 'timeLabelReverse'], + timeDigitsContainer: ['timeDigitsContainer', isRtl && 'timeLabelReverse'], separator: ['separator'], ampmSelection: ['ampmSelection', isLandscape && 'ampmLandscape'], ampmLabel: ['ampmLabel'], @@ -244,8 +247,7 @@ function DateTimePickerToolbar( const isDesktop = toolbarVariant === 'desktop'; const localeText = useLocaleText(); - const theme = useTheme(); - const classes = useUtilityClasses({ ...ownerState, theme }); + const classes = useUtilityClasses(ownerState); const toolbarTitle = inToolbarTitle ?? localeText.dateTimePickerToolbarTitle; const formatHours = (time: TDate) => diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx index dfe775f65b00..dc82ef25fa3e 100644 --- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx +++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import { useTheme } from '@mui/system'; +import { useRtl } from '@mui/system/RtlProvider'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_useControlled as useControlled, @@ -119,7 +119,7 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar(timezone); - const theme = useTheme(); + const isRtl = useRtl(); const utils = useUtils(); const referenceDate = React.useMemo( @@ -236,12 +236,12 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar; } -const useUtilityClasses = (ownerState: TimePickerToolbarProps & { theme: Theme }) => { - const { theme, isLandscape, classes } = ownerState; +const useUtilityClasses = (ownerState: TimePickerToolbarProps) => { + const isRtl = useRtl(); + const { isLandscape, classes } = ownerState; const slots = { root: ['root'], @@ -42,7 +44,7 @@ const useUtilityClasses = (ownerState: TimePickerToolbarProps & { theme: Th hourMinuteLabel: [ 'hourMinuteLabel', isLandscape && 'hourMinuteLabelLandscape', - theme.direction === 'rtl' && 'hourMinuteLabelReverse', + isRtl && 'hourMinuteLabelReverse', ], ampmSelection: ['ampmSelection', isLandscape && 'ampmLandscape'], ampmLabel: ['ampmLabel'], @@ -158,7 +160,6 @@ function TimePickerToolbar(inProps: TimePickerToo const utils = useUtils(); const localeText = useLocaleText(); - const theme = useTheme(); const showAmPmControl = Boolean(ampm && !ampmInClock && views.includes('hours')); const { meridiemMode, handleMeridiemChange } = useMeridiemMode(value, ampm, onChange); @@ -166,7 +167,7 @@ function TimePickerToolbar(inProps: TimePickerToo ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); const ownerState = props; - const classes = useUtilityClasses({ ...ownerState, theme }); + const classes = useUtilityClasses(ownerState); const separator = ( (timezone); - const theme = useTheme(); + const isRtl = useRtl(); const utils = useUtils(); const referenceDate = React.useMemo( @@ -232,11 +232,11 @@ export const YearCalendar = React.forwardRef(function YearCalendar, ) { - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; - + const isRtl = useRtl(); const props = useThemeProps({ props: inProps, name: 'MuiPickersArrowSwitcher' }); const { @@ -163,7 +162,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch {...other} > - {isRTL ? ( + {isRtl ? ( ) : ( @@ -177,7 +176,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch )} - {isRTL ? ( + {isRtl ? ( ) : ( 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 63e05d31e776..40cf9cdb88dd 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/buildSectionsFromFormat.ts @@ -12,7 +12,7 @@ interface BuildSectionsFromFormatParams { utils: MuiPickersAdapter; format: string; formatDensity: 'dense' | 'spacious'; - isRTL: boolean; + isRtl: boolean; timezone: PickersTimezone; shouldRespectLeadingZeros: boolean; localeText: PickersLocaleText; @@ -278,7 +278,7 @@ const buildSections = ( }; const postProcessSections = ({ - isRTL, + isRtl, formatDensity, sections, }: BuildSectionsFromFormatParams & { @@ -287,7 +287,7 @@ const postProcessSections = ({ return sections.map((section) => { const cleanSeparator = (separator: string) => { let cleanedSeparator = separator; - if (isRTL && cleanedSeparator !== null && cleanedSeparator.includes(' ')) { + if (isRtl && cleanedSeparator !== null && cleanedSeparator.includes(' ')) { cleanedSeparator = `\u2069${cleanedSeparator}\u2066`; } @@ -309,7 +309,7 @@ export const buildSectionsFromFormat = ( params: BuildSectionsFromFormatParams, ) => { let expandedFormat = expandFormat(params); - if (params.isRTL && params.enableAccessibleFieldDOMStructure) { + if (params.isRtl && params.enableAccessibleFieldDOMStructure) { expandedFormat = expandedFormat.split(' ').reverse().join(' '); } diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts index cad6083d523d..330222121083 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import useEventCallback from '@mui/utils/useEventCallback'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { useValidation } from '../useValidation'; import { useUtils } from '../useUtils'; import { @@ -64,8 +64,7 @@ export const useField = < validator, } = params; - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRtl = useRtl(); const stateResponse = useFieldState(params); const { @@ -104,8 +103,8 @@ export const useField = < ) as UseFieldTextField; const sectionOrder = React.useMemo( - () => getSectionOrder(state.sections, isRTL && !enableAccessibleFieldDOMStructure), - [state.sections, isRTL, enableAccessibleFieldDOMStructure], + () => getSectionOrder(state.sections, isRtl && !enableAccessibleFieldDOMStructure), + [state.sections, isRtl, enableAccessibleFieldDOMStructure], ); const { returnedValue, interactions } = useFieldTextField({ diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts index 3b05171787ce..df0915e71b7f 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.types.ts @@ -309,13 +309,13 @@ export interface FieldValueManager< * @template TSection * @param {TSection[]} sections The current section list. * @param {string} localizedDigits The conversion table from localized to 0-9 digits. - * @param {boolean} isRTL `true` if the current orientation is "right to left" + * @param {boolean} isRtl `true` if the current orientation is "right to left" * @returns {string} The string value to render in the input. */ getV6InputValueFromSections: ( sections: TSection[], localizedDigits: string[], - isRTL: boolean, + isRtl: boolean, ) => string; /** * Creates the string value to render in the input based on the current section list. diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts index c12ffc2c1ab8..588d20ab5b8c 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts @@ -494,12 +494,12 @@ export const createDateStrForV7HiddenInputFromSections = (sections: FieldSection export const createDateStrForV6InputFromSections = ( sections: FieldSection[], localizedDigits: string[], - isRTL: boolean, + isRtl: boolean, ) => { const formattedSections = sections.map((section) => { const dateValue = getSectionVisibleValue( section, - isRTL ? 'input-rtl' : 'input-ltr', + isRtl ? 'input-rtl' : 'input-ltr', localizedDigits, ); @@ -508,7 +508,7 @@ export const createDateStrForV6InputFromSections = ( const dateStr = formattedSections.join(''); - if (!isRTL) { + if (!isRtl) { return dateStr; } diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts index 3ac32f3912ef..c6fadb4b23d2 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import useControlled from '@mui/utils/useControlled'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import { useUtils, useLocaleText, useLocalizationContext } from '../useUtils'; import { UseFieldInternalProps, @@ -88,8 +88,7 @@ export const useFieldState = < const utils = useUtils(); const localeText = useLocaleText(); const adapter = useLocalizationContext(); - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRtl = useRtl(); const { valueManager, @@ -144,7 +143,7 @@ export const useFieldState = < formatDensity, shouldRespectLeadingZeros, enableAccessibleFieldDOMStructure, - isRTL, + isRtl, }), ), [ @@ -152,7 +151,7 @@ export const useFieldState = < format, localeText, localizedDigits, - isRTL, + isRtl, shouldRespectLeadingZeros, utils, formatDensity, @@ -293,7 +292,7 @@ export const useFieldState = < formatDensity, shouldRespectLeadingZeros, enableAccessibleFieldDOMStructure, - isRTL, + isRtl, }); return mergeDateIntoReferenceDate(utils, timezone, date, sections, referenceDate, false); }; @@ -385,7 +384,7 @@ export const useFieldState = < ...prevState, sections, })); - }, [format, utils.locale, isRTL]); // eslint-disable-line react-hooks/exhaustive-deps + }, [format, utils.locale, isRtl]); // eslint-disable-line react-hooks/exhaustive-deps React.useEffect(() => { let shouldUpdate: boolean; diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV6TextField.ts b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV6TextField.ts index 35da5981c702..f382ec975758 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useFieldV6TextField.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useFieldV6TextField.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; +import { useRtl } from '@mui/system/RtlProvider'; import useEventCallback from '@mui/utils/useEventCallback'; import useForkRef from '@mui/utils/useForkRef'; import { UseFieldTextFieldInteractions, UseFieldTextField } from './useField.types'; @@ -33,17 +33,17 @@ const cleanString = (dirtyString: string) => dirtyString.replace(/[\u2066\u2067\ export const addPositionPropertiesToSections = ( sections: TSection[], localizedDigits: string[], - isRTL: boolean, + isRtl: boolean, ): FieldSectionWithPositions[] => { let position = 0; - let positionInInput = isRTL ? 1 : 0; + let positionInInput = isRtl ? 1 : 0; const newSections: FieldSectionWithPositions[] = []; for (let i = 0; i < sections.length; i += 1) { const section = sections[i]; const renderedValue = getSectionVisibleValue( section, - isRTL ? 'input-rtl' : 'input-ltr', + isRtl ? 'input-rtl' : 'input-ltr', localizedDigits, ); const sectionStr = `${section.startSeparator}${renderedValue}${section.endSeparator}`; @@ -75,8 +75,7 @@ export const addPositionPropertiesToSections = ( }; export const useFieldV6TextField: UseFieldTextField = (params) => { - const theme = useTheme(); - const isRTL = theme.direction === 'rtl'; + const isRtl = useRtl(); const focusTimeoutRef = React.useRef>(); const { @@ -111,8 +110,8 @@ export const useFieldV6TextField: UseFieldTextField = (params) => { const handleRef = useForkRef(inputRefProp, inputRef); const sections = React.useMemo( - () => addPositionPropertiesToSections(state.sections, localizedDigits, isRTL), - [state.sections, localizedDigits, isRTL], + () => addPositionPropertiesToSections(state.sections, localizedDigits, isRtl), + [state.sections, localizedDigits, isRtl], ); const interactions = React.useMemo( @@ -333,7 +332,7 @@ export const useFieldV6TextField: UseFieldTextField = (params) => { keyPressed = cleanValueStr; } else { const prevValueStr = cleanString( - fieldValueManager.getV6InputValueFromSections(sections, localizedDigits, isRTL), + fieldValueManager.getV6InputValueFromSections(sections, localizedDigits, isRtl), ); let startOfDiffIndex = -1; @@ -397,7 +396,7 @@ export const useFieldV6TextField: UseFieldTextField = (params) => { return fieldValueManager.getV6InputValueFromSections( getSectionsFromValue(valueManager.emptyValue), localizedDigits, - isRTL, + isRtl, ); }, [ inPlaceholder, @@ -405,14 +404,14 @@ export const useFieldV6TextField: UseFieldTextField = (params) => { getSectionsFromValue, valueManager.emptyValue, localizedDigits, - isRTL, + isRtl, ]); const valueStr = React.useMemo( () => state.tempValueStrAndroid ?? - fieldValueManager.getV6InputValueFromSections(state.sections, localizedDigits, isRTL), - [state.sections, fieldValueManager, state.tempValueStrAndroid, localizedDigits, isRTL], + fieldValueManager.getV6InputValueFromSections(state.sections, localizedDigits, isRtl), + [state.sections, fieldValueManager, state.tempValueStrAndroid, localizedDigits, isRtl], ); React.useEffect(() => { From 7c22c8b4717aff0b4070fcc4431e52c6de95e5b1 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 4 Jun 2024 13:52:37 +0200 Subject: [PATCH 2/4] Continue migration --- .../DateTimePicker/DateTimePickerToolbar.tsx | 90 +++++++++++-------- .../src/PickersLayout/PickersLayout.tsx | 28 ++++-- .../PickersInputBase/PickersInputBase.tsx | 15 +++- .../src/TimePicker/TimePickerToolbar.tsx | 28 +++--- 4 files changed, 105 insertions(+), 56 deletions(-) diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx index ecf9b6cb71ab..c8df143a0131 100644 --- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx @@ -42,9 +42,13 @@ export interface DateTimePickerToolbarProps ampmInClock?: boolean; } -const useUtilityClasses = (ownerState: DateTimePickerToolbarProps) => { - const isRtl = useRtl(); - const { classes, isLandscape } = ownerState; +interface DateTimePickerToolbarOwnerState + extends DateTimePickerToolbarProps { + isRtl: boolean; +} + +const useUtilityClasses = (ownerState: DateTimePickerToolbarOwnerState) => { + const { classes, isLandscape, isRtl } = ownerState; const slots = { root: ['root'], @@ -63,7 +67,7 @@ const DateTimePickerToolbarRoot = styled(PickersToolbar, { name: 'MuiDateTimePickerToolbar', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => ({ +})<{ ownerState: DateTimePickerToolbarOwnerState }>(({ theme }) => ({ paddingLeft: 16, paddingRight: 16, justifyContent: 'space-around', @@ -99,7 +103,7 @@ const DateTimePickerToolbarDateContainer = styled('div', { name: 'MuiDateTimePickerToolbar', slot: 'DateContainer', overridesResolver: (props, styles) => styles.dateContainer, -})<{ ownerState: DateTimePickerToolbarProps }>({ +})<{ ownerState: DateTimePickerToolbarOwnerState }>({ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', @@ -109,59 +113,67 @@ const DateTimePickerToolbarTimeContainer = styled('div', { name: 'MuiDateTimePickerToolbar', slot: 'TimeContainer', overridesResolver: (props, styles) => styles.timeContainer, -})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => { - return { - display: 'flex', - flexDirection: 'row', - ...(theme.direction === 'rtl' && { - flexDirection: 'row-reverse', - }), - variants: [ - { - props: ({ isLandscape, toolbarVariant }: DateTimePickerToolbarProps) => - isLandscape && toolbarVariant !== 'desktop', - style: { - flexDirection: 'column', - ...(theme.direction === 'rtl' && { - flexDirection: 'column-reverse', - }), - }, +})<{ ownerState: DateTimePickerToolbarOwnerState }>({ + display: 'flex', + flexDirection: 'row', + variants: [ + { + props: { isRtl: true }, + style: { + flexDirection: 'row-reverse', }, - { - props: { toolbarVariant: 'desktop', isLandscape: false }, - style: { - gap: 9, - marginRight: 4, - alignSelf: 'flex-end', - }, + }, + { + props: { toolbarVariant: 'desktop', isLandscape: false }, + style: { + gap: 9, + marginRight: 4, + alignSelf: 'flex-end', }, - ], - }; + }, + { + props: ({ isLandscape, toolbarVariant }: DateTimePickerToolbarOwnerState) => + isLandscape && toolbarVariant !== 'desktop', + style: { + flexDirection: 'column', + }, + }, + { + props: ({ isLandscape, toolbarVariant, isRtl }: DateTimePickerToolbarOwnerState) => + isLandscape && toolbarVariant !== 'desktop' && isRtl, + style: { + flexDirection: 'column-reverse', + }, + }, + ], }); const DateTimePickerToolbarTimeDigitsContainer = styled('div', { name: 'MuiDateTimePickerToolbar', slot: 'TimeDigitsContainer', overridesResolver: (props, styles) => styles.timeDigitsContainer, -})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => ({ +})<{ ownerState: DateTimePickerToolbarOwnerState }>({ display: 'flex', - ...(theme.direction === 'rtl' && { - flexDirection: 'row-reverse', - }), variants: [ + { + props: { isRtl: true }, + style: { + flexDirection: 'row-reverse', + }, + }, { props: { toolbarVariant: 'desktop' }, style: { gap: 1.5 }, }, ], -})); +}); const DateTimePickerToolbarSeparator = styled(PickersToolbarText, { name: 'MuiDateTimePickerToolbar', slot: 'Separator', overridesResolver: (props, styles) => styles.separator, })<{ - ownerState: DateTimePickerToolbarProps; + ownerState: DateTimePickerToolbarOwnerState; }>({ margin: '0 4px 0 2px', cursor: 'default', @@ -239,7 +251,9 @@ function DateTimePickerToolbar( className, ...other } = props; - const ownerState = props; + + const isRtl = useRtl(); + const ownerState: DateTimePickerToolbarOwnerState = { ...props, isRtl }; const utils = useUtils(); const { meridiemMode, handleMeridiemChange } = useMeridiemMode(value, ampm, onChange); diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 2b1f2d722dec..e989694c0514 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; +import { useRtl } from '@mui/system/RtlProvider'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { PickersLayoutProps } from './PickersLayout.types'; @@ -23,7 +24,7 @@ export const PickersLayoutRoot = styled('div', { name: 'MuiPickersLayout', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: { isLandscape: boolean } }>(({ theme }) => ({ +})<{ ownerState: { isLandscape: boolean; isRtl: boolean } }>({ display: 'grid', gridAutoColumns: 'max-content auto max-content', gridAutoRows: 'max-content auto max-content', @@ -33,24 +34,40 @@ export const PickersLayoutRoot = styled('div', { props: { isLandscape: true }, style: { [`& .${pickersLayoutClasses.toolbar}`]: { - gridColumn: theme.direction === 'rtl' ? 3 : 1, + gridColumn: 1, gridRow: '2 / 3', }, [`.${pickersLayoutClasses.shortcuts}`]: { gridColumn: '2 / 4', gridRow: 1 }, }, }, + { + props: { isLandscape: true, isRtl: true }, + style: { + [`& .${pickersLayoutClasses.toolbar}`]: { + gridColumn: 3, + }, + }, + }, { props: { isLandscape: false }, style: { [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2 / 4', gridRow: 1 }, [`& .${pickersLayoutClasses.shortcuts}`]: { - gridColumn: theme.direction === 'rtl' ? 3 : 1, + gridColumn: 1, gridRow: '2 / 3', }, }, }, + { + props: { isLandscape: false, isRtl: true }, + style: { + [`& .${pickersLayoutClasses.shortcuts}`]: { + gridColumn: 3, + }, + }, + }, ], -})); +}); export const PickersLayoutContentWrapper = styled('div', { name: 'MuiPickersLayout', @@ -78,11 +95,12 @@ const PickersLayout = function PickersLayout< TView extends DateOrTimeViewWithMeridiem, >(inProps: PickersLayoutProps) { const props = useThemeProps({ props: inProps, name: 'MuiPickersLayout' }); + const isRtl = useRtl(); const { toolbar, content, tabs, actionBar, shortcuts } = usePickerLayout(props); const { sx, className, isLandscape, ref, wrapperVariant } = props; - const ownerState = props; + const ownerState = { ...props, isRtl }; const classes = useUtilityClasses(ownerState); return ( diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx index 7d6618396890..7c118ea29b1a 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx @@ -8,6 +8,7 @@ import composeClasses from '@mui/utils/composeClasses'; import capitalize from '@mui/utils/capitalize'; import { useSlotProps } from '@mui/base/utils'; import visuallyHidden from '@mui/utils/visuallyHidden'; +import { useRtl } from '@mui/system/RtlProvider'; import { pickersInputBaseClasses, getPickersInputBaseUtilityClass, @@ -63,8 +64,13 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, letterSpacing: 'inherit', // Baseline behavior width: '182px', - ...(theme.direction === 'rtl' && { textAlign: 'right /*! @noflip */' as any }), variants: [ + { + props: { isRtl: true }, + style: { + textAlign: 'right /*! @noflip */' as any, + }, + }, { props: { size: 'small' }, style: { @@ -174,7 +180,9 @@ const useUtilityClasses = (ownerState: OwnerStateType) => { interface OwnerStateType extends FormControlState, - Omit {} + Omit { + isRtl: boolean; +} /** * @ignore - internal component. @@ -219,7 +227,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( const rootRef = React.useRef(null); const handleRootRef = useForkRef(ref, rootRef); const handleInputRef = useForkRef(inputProps?.ref, inputRef); - + const isRtl = useRtl(); const muiFormControl = useFormControl(); if (!muiFormControl) { throw new Error( @@ -259,6 +267,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( const ownerState: OwnerStateType = { ...(props as Omit), ...muiFormControl, + isRtl, }; const classes = useUtilityClasses(ownerState); diff --git a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx index 67290676b0db..a24f68cf5711 100644 --- a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx +++ b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx @@ -27,6 +27,11 @@ export interface TimePickerToolbarProps ampmInClock?: boolean; } +interface TimePickerToolbarOwnerState + extends TimePickerToolbarProps { + isRtl: boolean; +} + export interface ExportedTimePickerToolbarProps extends ExportedBaseToolbarProps { /** * Override or extend the styles applied to the component. @@ -34,9 +39,8 @@ export interface ExportedTimePickerToolbarProps extends ExportedBaseToolbarProps classes?: Partial; } -const useUtilityClasses = (ownerState: TimePickerToolbarProps) => { - const isRtl = useRtl(); - const { isLandscape, classes } = ownerState; +const useUtilityClasses = (ownerState: TimePickerToolbarOwnerState) => { + const { isLandscape, classes, isRtl } = ownerState; const slots = { root: ['root'], @@ -82,15 +86,18 @@ const TimePickerToolbarHourMinuteLabel = styled('div', { styles.hourMinuteLabel, ], })<{ - ownerState: TimePickerToolbarProps; -}>(({ theme }) => ({ + ownerState: TimePickerToolbarOwnerState; +}>({ display: 'flex', justifyContent: 'flex-end', alignItems: 'flex-end', - ...(theme.direction === 'rtl' && { - flexDirection: 'row-reverse', - }), variants: [ + { + props: { isRtl: true }, + style: { + flexDirection: 'row-reverse', + }, + }, { props: { isLandscape: true }, style: { @@ -98,7 +105,7 @@ const TimePickerToolbarHourMinuteLabel = styled('div', { }, }, ], -})); +}); const TimePickerToolbarAmPmSelection = styled('div', { name: 'MuiTimePickerToolbar', @@ -159,6 +166,7 @@ function TimePickerToolbar(inProps: TimePickerToo } = props; const utils = useUtils(); const localeText = useLocaleText(); + const isRtl = useRtl(); const showAmPmControl = Boolean(ampm && !ampmInClock && views.includes('hours')); const { meridiemMode, handleMeridiemChange } = useMeridiemMode(value, ampm, onChange); @@ -166,7 +174,7 @@ function TimePickerToolbar(inProps: TimePickerToo const formatHours = (time: TDate) => ampm ? utils.format(time, 'hours12h') : utils.format(time, 'hours24h'); - const ownerState = props; + const ownerState: TimePickerToolbarOwnerState = { ...props, isRtl }; const classes = useUtilityClasses(ownerState); const separator = ( From b3a0bebde487d975ff1dc12895b5e72bdb84e841 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 4 Jun 2024 14:08:14 +0200 Subject: [PATCH 3/4] Fix CI --- .../DesktopDateTimePickerLayout.tsx | 5 ++++- .../x-date-pickers/src/PickersLayout/PickersLayout.tsx | 9 +++------ .../src/PickersLayout/PickersLayout.types.ts | 4 ++++ .../internals/hooks/usePicker/usePickerLayoutProps.ts | 4 ++++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx index 58ac0d240bb3..fd71ce698ef0 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; +import { useRtl } from '@mui/system/RtlProvider'; import Divider from '@mui/material/Divider'; import { PickersLayoutContentWrapper, @@ -20,9 +21,11 @@ function DesktopDateTimePickerLayout< TDate extends PickerValidDate, TView extends DateOrTimeViewWithMeridiem, >(props: PickersLayoutProps) { + const isRtl = useRtl(); const { toolbar, tabs, content, actionBar, shortcuts } = usePickerLayout(props); const { sx, className, isLandscape, ref, classes } = props; const isActionBarVisible = actionBar && (actionBar.props.actions?.length ?? 0) > 0; + const ownerState = { ...props, isRtl }; return ( {isLandscape ? shortcuts : toolbar} {isLandscape ? toolbar : shortcuts} diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index e989694c0514..0c594e44d1e5 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import { useRtl } from '@mui/system/RtlProvider'; import { styled, useThemeProps } from '@mui/material/styles'; import { unstable_composeClasses as composeClasses } from '@mui/utils'; import { PickersLayoutProps } from './PickersLayout.types'; @@ -24,7 +23,7 @@ export const PickersLayoutRoot = styled('div', { name: 'MuiPickersLayout', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: { isLandscape: boolean; isRtl: boolean } }>({ +})<{ ownerState: PickersLayoutProps }>({ display: 'grid', gridAutoColumns: 'max-content auto max-content', gridAutoRows: 'max-content auto max-content', @@ -95,20 +94,18 @@ const PickersLayout = function PickersLayout< TView extends DateOrTimeViewWithMeridiem, >(inProps: PickersLayoutProps) { const props = useThemeProps({ props: inProps, name: 'MuiPickersLayout' }); - const isRtl = useRtl(); const { toolbar, content, tabs, actionBar, shortcuts } = usePickerLayout(props); const { sx, className, isLandscape, ref, wrapperVariant } = props; - const ownerState = { ...props, isRtl }; - const classes = useUtilityClasses(ownerState); + const classes = useUtilityClasses(props); return ( {isLandscape ? shortcuts : toolbar} {isLandscape ? toolbar : shortcuts} diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts index 32cb59af51f4..929776fbc6f5 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.types.ts @@ -137,6 +137,10 @@ export interface PickersLayoutProps< * @default {} */ slotProps?: PickersLayoutSlotProps; + /** + * `true` if the application is in right-to-left direction. + */ + isRtl: boolean; } export interface SubComponents { diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts index db3a329d9e8f..f4084f8b3222 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerLayoutProps.ts @@ -1,3 +1,4 @@ +import { useRtl } from '@mui/system/RtlProvider'; import { useIsLandscape } from '../useIsLandscape'; import { UsePickerValueLayoutResponse } from './usePickerValue.types'; import { UsePickerViewsLayoutResponse } from './usePickerViews'; @@ -23,6 +24,7 @@ export interface UsePickerLayoutPropsResponseLayoutProps< UsePickerViewsLayoutResponse, UsePickerLayoutProps { isLandscape: boolean; + isRtl: boolean; wrapperVariant: WrapperVariant; isValid: (value: TValue) => boolean; } @@ -49,11 +51,13 @@ export const usePickerLayoutProps = ): UsePickerLayoutPropsResponse => { const { orientation } = props; const isLandscape = useIsLandscape(propsFromPickerViews.views, orientation); + const isRtl = useRtl(); const layoutProps: UsePickerLayoutPropsResponseLayoutProps = { ...propsFromPickerViews, ...propsFromPickerValue, isLandscape, + isRtl, wrapperVariant, disabled: props.disabled, readOnly: props.readOnly, From 09a4af6731f6360604fa9a2a8caf2917bddb3019 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 4 Jun 2024 14:16:06 +0200 Subject: [PATCH 4/4] Fix --- docs/pages/x/api/date-pickers/pickers-layout.json | 1 + .../api-docs/date-pickers/pickers-layout/pickers-layout.json | 3 +++ .../src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx | 4 ++++ packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/docs/pages/x/api/date-pickers/pickers-layout.json b/docs/pages/x/api/date-pickers/pickers-layout.json index f340a4c17beb..d4786c77062e 100644 --- a/docs/pages/x/api/date-pickers/pickers-layout.json +++ b/docs/pages/x/api/date-pickers/pickers-layout.json @@ -1,5 +1,6 @@ { "props": { + "isRtl": { "type": { "name": "bool" }, "required": true }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "orientation": { "type": { "name": "enum", "description": "'landscape'
| 'portrait'" } diff --git a/docs/translations/api-docs/date-pickers/pickers-layout/pickers-layout.json b/docs/translations/api-docs/date-pickers/pickers-layout/pickers-layout.json index 1fc772c256d8..57a28904a850 100644 --- a/docs/translations/api-docs/date-pickers/pickers-layout/pickers-layout.json +++ b/docs/translations/api-docs/date-pickers/pickers-layout/pickers-layout.json @@ -2,6 +2,9 @@ "componentDescription": "", "propDescriptions": { "classes": { "description": "Override or extend the styles applied to the component." }, + "isRtl": { + "description": "true if the application is in right-to-left direction." + }, "orientation": { "description": "Force rendering in particular orientation." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, diff --git a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx index fd71ce698ef0..fca2a0f44898 100644 --- a/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx +++ b/packages/x-date-pickers/src/DesktopDateTimePicker/DesktopDateTimePickerLayout.tsx @@ -68,6 +68,10 @@ DesktopDateTimePickerLayout.propTypes = { className: PropTypes.string, disabled: PropTypes.bool, isLandscape: PropTypes.bool.isRequired, + /** + * `true` if the application is in right-to-left direction. + */ + isRtl: PropTypes.bool.isRequired, isValid: PropTypes.func.isRequired, onAccept: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx index 0c594e44d1e5..bece27f61de4 100644 --- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx +++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx @@ -140,6 +140,10 @@ PickersLayout.propTypes = { className: PropTypes.string, disabled: PropTypes.bool, isLandscape: PropTypes.bool.isRequired, + /** + * `true` if the application is in right-to-left direction. + */ + isRtl: PropTypes.bool.isRequired, isValid: PropTypes.func.isRequired, onAccept: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired,