From 8bf4c02c8dae53eb8951d8cfa6a39677d12f407d Mon Sep 17 00:00:00 2001 From: flavien Date: Thu, 12 Dec 2024 12:24:31 +0100 Subject: [PATCH 1/5] [pickers] Use the new ownerState object on the PickersTextField component --- .../PickersSectionList/PickersSectionList.tsx | 21 +-- .../PickersSectionList.types.ts | 18 +- .../PickersFilledInput/PickersFilledInput.tsx | 46 ++--- .../pickersFilledInputClasses.ts | 5 +- .../PickersInput/PickersInput.tsx | 37 ++-- .../PickersInput/pickersInputClasses.ts | 5 +- .../PickersInputBase/PickersInputBase.tsx | 90 +++++----- .../PickersInputBase.types.ts | 1 + .../PickersOutlinedInput/Outline.tsx | 32 ++-- .../PickersOutlinedInput.tsx | 39 ++-- .../src/PickersTextField/PickersTextField.tsx | 170 +++++++++++------- .../PickersTextField.types.ts | 51 +++++- .../usePickerTextFieldOwnerState.ts | 19 ++ .../PickersArrowSwitcher.tsx | 6 +- .../PickersArrowSwitcher.types.tsx | 2 +- .../src/internals/hooks/useFieldOwnerState.ts | 10 +- packages/x-date-pickers/src/models/fields.ts | 12 +- 17 files changed, 327 insertions(+), 237 deletions(-) create mode 100644 packages/x-date-pickers/src/PickersTextField/usePickerTextFieldOwnerState.ts diff --git a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx index ae8db0f9ee84..ac7a86aec588 100644 --- a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx +++ b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.tsx @@ -11,6 +11,7 @@ import { PickersSectionListClasses, } from './pickersSectionListClasses'; import { PickersSectionListProps, PickersSectionElement } from './PickersSectionList.types'; +import { usePickerPrivateContext } from '../internals/hooks/usePickerPrivateContext'; export const PickersSectionListRoot = styled('div', { name: 'MuiPickersSectionList', @@ -43,9 +44,7 @@ export const PickersSectionListSectionContent = styled('span', { outline: 'none', }); -const useUtilityClasses = (ownerState: PickersSectionListProps) => { - const { classes } = ownerState; - +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], section: ['section'], @@ -62,6 +61,7 @@ interface PickersSectionProps extends Pick(null); const handleRootRef = useForkRef(ref, rootRef); @@ -216,7 +217,7 @@ const PickersSectionList = React.forwardRef(function PickersSectionList( suppressContentEditableWarning: true, }, className: classes.root, - ownerState: {}, + ownerState, }); return ( diff --git a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.types.ts b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.types.ts index 99781b259a84..62ceafeb5c7f 100644 --- a/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.types.ts +++ b/packages/x-date-pickers/src/PickersSectionList/PickersSectionList.types.ts @@ -1,6 +1,7 @@ import * as React from 'react'; import { SlotComponentProps } from '@mui/utils'; import { PickersSectionListClasses } from './pickersSectionListClasses'; +import { PickerOwnerState } from '../models'; export interface PickersSectionListSlots { root: React.ElementType; @@ -9,11 +10,20 @@ export interface PickersSectionListSlots { sectionContent: React.ElementType; } +export interface PickerSectionSeparatorOwnerState extends PickerOwnerState { + /** + * The position of the separator. + * `before` if the separator is rendered before the section content. + * `after` if the separator is rendered after the section content. + */ + separatorPosition: 'before' | 'after'; +} + export interface PickersSectionListSlotProps { - root?: SlotComponentProps<'div', {}, {}>; - section?: SlotComponentProps<'span', {}, {}>; - sectionSeparator?: SlotComponentProps<'span', {}, { position: 'before' | 'after' }>; - sectionContent?: SlotComponentProps<'span', {}, {}>; + root?: SlotComponentProps<'div', {}, PickerOwnerState>; + section?: SlotComponentProps<'span', {}, PickerOwnerState>; + sectionSeparator?: SlotComponentProps<'span', {}, PickerSectionSeparatorOwnerState>; + sectionContent?: SlotComponentProps<'span', {}, PickerOwnerState>; } export interface PickersSectionElement { diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx index 74e10a3bd050..6a0f1423894c 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { FormControlState, useFormControl } from '@mui/material/FormControl'; import { styled, useThemeProps } from '@mui/material/styles'; import { shouldForwardProp } from '@mui/system'; import { refType } from '@mui/utils'; @@ -8,12 +7,14 @@ import composeClasses from '@mui/utils/composeClasses'; import { pickersFilledInputClasses, getPickersFilledInputUtilityClass, + PickersFilledInputClasses, } from './pickersFilledInputClasses'; import { PickersInputBaseProps, PickersInputBase } from '../PickersInputBase'; import { PickersInputBaseRoot, PickersInputBaseSectionsContainer, } from '../PickersInputBase/PickersInputBase'; +import { PickersTextFieldOwnerState } from '../PickersTextField.types'; export interface PickersFilledInputProps extends PickersInputBaseProps { disableUnderline?: boolean; @@ -25,7 +26,7 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, { slot: 'Root', overridesResolver: (props, styles) => styles.root, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', -})<{ ownerState: OwnerStateType }>(({ theme }) => { +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; const backgroundColor = light ? 'rgba(0, 0, 0, 0.06)' : 'rgba(255, 255, 255, 0.09)'; @@ -58,7 +59,7 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, { // @ts-ignore .filter((key) => (theme.vars ?? theme).palette[key].main) .map((color) => ({ - props: { color, disableUnderline: false }, + props: { inputColor: color, disableUnderline: false }, style: { '&::after': { // @ts-ignore @@ -120,13 +121,13 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, { }, }, { - props: ({ startAdornment }: OwnerStateType) => !!startAdornment, + props: { isInputAdornedStart: true }, style: { paddingLeft: 12, }, }, { - props: ({ endAdornment }: OwnerStateType) => !!endAdornment, + props: { isInputAdornedEnd: true }, style: { paddingRight: 12, }, @@ -139,27 +140,28 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, name: 'MuiPickersFilledInput', slot: 'sectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, -})<{ ownerState: OwnerStateType }>({ + shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'hiddenLabel', +})<{ ownerState: PickersTextFieldOwnerState }>({ paddingTop: 25, paddingRight: 12, paddingBottom: 8, paddingLeft: 12, variants: [ { - props: { size: 'small' }, + props: { inputSize: 'small' }, style: { paddingTop: 21, paddingBottom: 4, }, }, { - props: ({ startAdornment }: OwnerStateType) => !!startAdornment, + props: { isInputAdornedStart: true }, style: { paddingLeft: 0, }, }, { - props: ({ endAdornment }: OwnerStateType) => !!endAdornment, + props: { isInputAdornedEnd: true }, style: { paddingRight: 0, }, @@ -172,7 +174,7 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, }, }, { - props: { hiddenLabel: true, size: 'small' }, + props: { hiddenLabel: true, inputSize: 'small' }, style: { paddingTop: 8, paddingBottom: 9, @@ -181,11 +183,9 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, ], }); -const useUtilityClasses = (ownerState: OwnerStateType) => { - const { classes, disableUnderline } = ownerState; - +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { - root: ['root', !disableUnderline && 'underline'], + root: ['root'], input: ['input'], }; @@ -197,10 +197,6 @@ const useUtilityClasses = (ownerState: OwnerStateType) => { }; }; -interface OwnerStateType - extends FormControlState, - Omit {} - /** * @ignore - internal component. */ @@ -217,24 +213,18 @@ const PickersFilledInput = React.forwardRef(function PickersFilledInput( label, autoFocus, disableUnderline = false, + hiddenLabel = false, + classes: classesProp, ownerState: ownerStateProp, ...other } = props; - const muiFormControl = useFormControl(); - - const ownerState = { - ...props, - ...ownerStateProp, - ...muiFormControl, - color: muiFormControl?.color || 'primary', - }; - const classes = useUtilityClasses(ownerState); + const classes = useUtilityClasses(classesProp); return ( styles.root, -})<{ ownerState: OwnerStateType }>(({ theme }) => { + shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; let bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; if (theme.vars) { @@ -31,7 +37,7 @@ const PickersInputRoot = styled(PickersInputBaseRoot, { // @ts-ignore .filter((key) => (theme.vars ?? theme).palette[key].main) .map((color) => ({ - props: { color }, + props: { inputColor: color }, style: { '&::after': { // @ts-ignore @@ -96,11 +102,9 @@ const PickersInputRoot = styled(PickersInputBaseRoot, { }; }); -const useUtilityClasses = (ownerState: OwnerStateType) => { - const { classes, disableUnderline } = ownerState; - +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { - root: ['root', !disableUnderline && 'underline'], + root: ['root'], input: ['input'], }; @@ -112,10 +116,6 @@ const useUtilityClasses = (ownerState: OwnerStateType) => { }; }; -interface OwnerStateType - extends FormControlState, - Omit {} - /** * @ignore - internal component. */ @@ -133,23 +133,16 @@ const PickersInput = React.forwardRef(function PickersInput( autoFocus, disableUnderline = false, ownerState: ownerStateProp, + classes: classesProp, ...other } = props; - const muiFormControl = useFormControl(); - - const ownerState = { - ...props, - ...ownerStateProp, - ...muiFormControl, - disableUnderline, - color: muiFormControl?.color || 'primary', - }; - const classes = useUtilityClasses(ownerState); + const classes = useUtilityClasses(classesProp); return ( Math.round(value * 1e5) / 1e5; @@ -28,7 +30,7 @@ export const PickersInputBaseRoot = styled('div', { name: 'MuiPickersInputBase', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: OwnerStateType }>(({ theme }) => ({ +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => ({ ...theme.typography.body1, color: (theme.vars || theme).palette.text.primary, cursor: 'text', @@ -41,7 +43,7 @@ export const PickersInputBaseRoot = styled('div', { letterSpacing: `${round(0.15 / 16)}em`, variants: [ { - props: { fullWidth: true }, + props: { inputFullWidth: true }, style: { width: '100%' }, }, ], @@ -51,7 +53,7 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, name: 'MuiPickersInputBase', slot: 'SectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, -})<{ ownerState: OwnerStateType }>(({ theme }) => ({ +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => ({ padding: '4px 0 5px', fontFamily: theme.typography.fontFamily, fontSize: 'inherit', @@ -66,19 +68,19 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, width: '182px', variants: [ { - props: { isRtl: true }, + props: { fieldDirection: 'rtl' }, style: { textAlign: 'right /*! @noflip */' as any, }, }, { - props: { size: 'small' }, + props: { inputSize: 'small' }, style: { paddingTop: 1, }, }, { - props: { adornedStart: false, focused: false, filled: false }, + props: { isInputAdornedStart: false, isFieldFocused: false, isFieldValueEmpty: true }, style: { color: 'currentColor', opacity: 0, @@ -86,8 +88,12 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, }, { // Can't use the object notation because label can be null or undefined - props: ({ adornedStart, focused, filled, label }: OwnerStateType) => - !adornedStart && !focused && !filled && label == null, + props: { + isInputAdornedStart: false, + isFieldFocused: false, + isFieldValueEmpty: true, + inputHasLabel: false, + }, style: theme.vars ? { opacity: theme.vars.opacity.inputPlaceholder, @@ -140,32 +146,34 @@ const PickersInputBaseInput = styled('input', { ...visuallyHidden, }); -const useUtilityClasses = (ownerState: OwnerStateType) => { +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersTextFieldOwnerState, +) => { const { - focused, - disabled, - error, - classes, - fullWidth, - readOnly, - color, - size, - endAdornment, - startAdornment, + isFieldFocused, + isFieldDisabled, + isFieldReadOnly, + hasFieldError, + inputSize, + inputFullWidth, + inputColor, + isInputAdornedStart, + isInputAdornedEnd, } = ownerState; const slots = { root: [ 'root', - focused && !disabled && 'focused', - disabled && 'disabled', - readOnly && 'readOnly', - error && 'error', - fullWidth && 'fullWidth', - `color${capitalize(color!)}`, - size === 'small' && 'inputSizeSmall', - Boolean(startAdornment) && 'adornedStart', - Boolean(endAdornment) && 'adornedEnd', + isFieldFocused && !isFieldDisabled && 'focused', + isFieldDisabled && 'disabled', + isFieldReadOnly && 'readOnly', + hasFieldError && 'error', + inputFullWidth && 'fullWidth', + `color${capitalize(inputColor!)}`, + inputSize === 'small' && 'inputSizeSmall', + isInputAdornedStart && 'adornedStart', + isInputAdornedEnd && 'adornedEnd', ], notchedOutline: ['notchedOutline'], input: ['input'], @@ -178,12 +186,6 @@ const useUtilityClasses = (ownerState: OwnerStateType) => { return composeClasses(slots, getPickersInputBaseUtilityClass, classes); }; -interface OwnerStateType - extends FormControlState, - Omit { - isRtl: boolean; -} - /** * @ignore - internal component. */ @@ -195,6 +197,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( props: inProps, name: 'MuiPickersInputBase', }); + const ownerState = usePickerTextFieldOwnerState(); const { elements, @@ -223,13 +226,13 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( sectionListRef, onFocus, onBlur, + classes: classesProp, ...other } = props; 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( @@ -265,13 +268,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( } }, [muiFormControl, areAllSectionsEmpty]); - const ownerState: OwnerStateType = { - ...(props as Omit), - ...muiFormControl, - isRtl, - }; - - const classes = useUtilityClasses(ownerState); + const classes = useUtilityClasses(classesProp, ownerState); const InputRoot = slots?.root || PickersInputBaseRoot; const inputRootProps = useSlotProps({ @@ -310,12 +307,13 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( }} slotProps={{ root: { + ...slotProps?.input, ownerState, } as any, sectionContent: { className: pickersInputBaseClasses.sectionContent }, - sectionSeparator: ({ position }) => ({ + sectionSeparator: ({ separatorPosition }) => ({ className: - position === 'before' + separatorPosition === 'before' ? pickersInputBaseClasses.sectionBefore : pickersInputBaseClasses.sectionAfter, }), diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts index ba7c90dd39a7..56b540e1c8cf 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts @@ -65,5 +65,6 @@ export interface PickersInputBaseProps */ slotProps?: { root?: any; + input?: any; }; } diff --git a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx index 9195cb4bc84a..7c3f10d654e1 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx @@ -1,22 +1,20 @@ import * as React from 'react'; import { styled } from '@mui/material/styles'; +import { shouldForwardProp } from '@mui/system/createStyled'; +import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; +import { PickersTextFieldOwnerState } from '../PickersTextField.types'; interface OutlineProps extends React.HTMLAttributes { notched: boolean; shrink: boolean; label: React.ReactNode; - ownerState: any; -} - -interface OutlineOwnerState extends OutlineProps { - withLabel: boolean; } const OutlineRoot = styled('fieldset', { name: 'MuiPickersOutlinedInput', slot: 'NotchedOutline', overridesResolver: (props, styles) => styles.notchedOutline, -})<{ ownerState: OutlineOwnerState }>(({ theme }) => { +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'; return { @@ -39,18 +37,21 @@ const OutlineRoot = styled('fieldset', { : borderColor, }; }); + const OutlineLabel = styled('span')(({ theme }) => ({ fontFamily: theme.typography.fontFamily, fontSize: 'inherit', })); -const OutlineLegend = styled('legend')<{ ownerState: any }>(({ theme }) => ({ +const OutlineLegend = styled('legend', { + shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'notched', +})<{ ownerState: PickersTextFieldOwnerState; notched: boolean }>(({ theme }) => ({ float: 'unset', // Fix conflict with bootstrap width: 'auto', // Fix conflict with bootstrap overflow: 'hidden', // Fix Horizontal scroll when label too long variants: [ { - props: { withLabel: false }, + props: { inputHasLabel: false }, style: { padding: 0, lineHeight: '11px', // sync with `height` in `legend` styles @@ -61,7 +62,7 @@ const OutlineLegend = styled('legend')<{ ownerState: any }>(({ theme }) => ({ }, }, { - props: { withLabel: true }, + props: { inputHasLabel: true }, style: { display: 'block', // Fix conflict with normalize.css and sanitize.css padding: 0, @@ -84,7 +85,7 @@ const OutlineLegend = styled('legend')<{ ownerState: any }>(({ theme }) => ({ }, }, { - props: { withLabel: true, notched: true }, + props: { inputHasLabel: true, notched: true }, style: { maxWidth: '100%', transition: theme.transitions.create('max-width', { @@ -102,16 +103,13 @@ const OutlineLegend = styled('legend')<{ ownerState: any }>(({ theme }) => ({ */ export default function Outline(props: OutlineProps) { const { children, className, label, notched, shrink, ...other } = props; - const withLabel = label != null && label !== ''; - const ownerState = { - ...props, - withLabel, - }; + const ownerState = usePickerTextFieldOwnerState(); + return ( - + {/* Use the nominal use case of the legend, avoid rendering artefacts. */} - {withLabel ? ( + {label ? ( {label} ) : ( // notranslate needed while Google Translate will not fix zero-width space issue diff --git a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx index 9ab29a6dfb61..bbd2f7739ca9 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx @@ -1,12 +1,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { FormControlState, useFormControl } from '@mui/material/FormControl'; +import { useFormControl } from '@mui/material/FormControl'; import { styled, useThemeProps } from '@mui/material/styles'; import { refType } from '@mui/utils'; import composeClasses from '@mui/utils/composeClasses'; import { pickersOutlinedInputClasses, getPickersOutlinedInputUtilityClass, + PickersOutlinedInputClasses, } from './pickersOutlinedInputClasses'; import Outline from './Outline'; import { PickersInputBase, PickersInputBaseProps } from '../PickersInputBase'; @@ -14,6 +15,7 @@ import { PickersInputBaseRoot, PickersInputBaseSectionsContainer, } from '../PickersInputBase/PickersInputBase'; +import { PickersTextFieldOwnerState } from '../PickersTextField.types'; export interface PickersOutlinedInputProps extends PickersInputBaseProps { notched?: boolean; @@ -23,7 +25,7 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, { name: 'MuiPickersOutlinedInput', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: OwnerStateType }>(({ theme }) => { +})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'; return { @@ -59,7 +61,7 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, { // @ts-ignore .filter((key) => (theme.vars ?? theme).palette[key]?.main ?? false) .map((color) => ({ - props: { color }, + props: { inputColor: color }, style: { [`&.${pickersOutlinedInputClasses.focused}:not(.${pickersOutlinedInputClasses.error}) .${pickersOutlinedInputClasses.notchedOutline}`]: { @@ -75,11 +77,11 @@ const PickersOutlinedInputSectionsContainer = styled(PickersInputBaseSectionsCon name: 'MuiPickersOutlinedInput', slot: 'SectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, -})<{ ownerState: OwnerStateType }>({ +})<{ ownerState: PickersTextFieldOwnerState }>({ padding: '16.5px 0', variants: [ { - props: { size: 'small' }, + props: { inputSize: 'small' }, style: { padding: '8.5px 0', }, @@ -87,9 +89,7 @@ const PickersOutlinedInputSectionsContainer = styled(PickersInputBaseSectionsCon ], }); -const useUtilityClasses = (ownerState: OwnerStateType) => { - const { classes } = ownerState; - +const useUtilityClasses = (classes: Partial | undefined) => { const slots = { root: ['root'], notchedOutline: ['notchedOutline'], @@ -104,10 +104,6 @@ const useUtilityClasses = (ownerState: OwnerStateType) => { }; }; -interface OwnerStateType - extends FormControlState, - Omit {} - /** * @ignore - internal component. */ @@ -120,17 +116,17 @@ const PickersOutlinedInput = React.forwardRef(function PickersOutlinedInput( name: 'MuiPickersOutlinedInput', }); - const { label, autoFocus, ownerState: ownerStateProp, notched, ...other } = props; + const { + label, + autoFocus, + ownerState: ownerStateProp, + classes: classesProp, + notched, + ...other + } = props; const muiFormControl = useFormControl(); - - const ownerState = { - ...props, - ...ownerStateProp, - ...muiFormControl, - color: muiFormControl?.color || 'primary', - }; - const classes = useUtilityClasses(ownerState); + const classes = useUtilityClasses(classesProp); return ( )} {...other} diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx index 6969a67b254b..e39727e4987b 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx @@ -10,11 +10,16 @@ import useId from '@mui/utils/useId'; import InputLabel from '@mui/material/InputLabel'; import FormHelperText from '@mui/material/FormHelperText'; import FormControl from '@mui/material/FormControl'; -import { getPickersTextFieldUtilityClass } from './pickersTextFieldClasses'; -import { PickersTextFieldProps } from './PickersTextField.types'; +import { + getPickersTextFieldUtilityClass, + PickersTextFieldClasses, +} from './pickersTextFieldClasses'; +import { PickersTextFieldOwnerState, PickersTextFieldProps } from './PickersTextField.types'; import { PickersOutlinedInput } from './PickersOutlinedInput'; import { PickersFilledInput } from './PickersFilledInput'; import { PickersInput } from './PickersInput'; +import { useFieldOwnerState } from '../internals/hooks/useFieldOwnerState'; +import { PickerTextFieldOwnerStateContext } from './usePickerTextFieldOwnerState'; const VARIANT_COMPONENT = { standard: PickersInput, @@ -26,25 +31,26 @@ const PickersTextFieldRoot = styled(FormControl, { name: 'MuiPickersTextField', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: OwnerStateType }>({}); +})<{ ownerState: PickersTextFieldOwnerState }>({}); -const useUtilityClasses = (ownerState: PickersTextFieldProps) => { - const { focused, disabled, classes, required } = ownerState; +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersTextFieldOwnerState, +) => { + const { isFieldFocused, isFieldDisabled, isFieldRequired } = ownerState; const slots = { root: [ 'root', - focused && !disabled && 'focused', - disabled && 'disabled', - required && 'required', + isFieldFocused && !isFieldDisabled && 'focused', + isFieldDisabled && 'disabled', + isFieldRequired && 'required', ], }; return composeClasses(slots, getPickersTextFieldUtilityClass, classes); }; -type OwnerStateType = Partial; - const PickersTextField = React.forwardRef(function PickersTextField( inProps: PickersTextFieldProps, ref: React.Ref, @@ -59,6 +65,7 @@ const PickersTextField = React.forwardRef(function PickersTextField( onFocus, onBlur, className, + classes: classesProp, color = 'primary', disabled = false, error = false, @@ -102,70 +109,95 @@ const PickersTextField = React.forwardRef(function PickersTextField( const helperTextId = helperText && id ? `${id}-helper-text` : undefined; const inputLabelId = label && id ? `${id}-label` : undefined; - const ownerState = { - ...props, - color, - disabled, - error, - focused, - required, - variant, - }; - - const classes = useUtilityClasses(ownerState); + const fieldOwnerState = useFieldOwnerState({ + disabled: props.disabled, + required: props.required, + readOnly: InputProps?.readOnly, + }); + const ownerState = React.useMemo( + () => ({ + ...fieldOwnerState, + isFieldValueEmpty: areAllSectionsEmpty, + isFieldFocused: focused ?? false, + hasFieldError: error ?? false, + inputSize: props.size ?? 'medium', + inputColor: color ?? 'primary', + inputFullWidth: fullWidth ?? false, + isInputAdornedStart: Boolean(startAdornment ?? InputProps?.startAdornment), + isInputAdornedEnd: Boolean(endAdornment ?? InputProps?.endAdornment), + inputHasLabel: !!label, + }), + [ + fieldOwnerState, + areAllSectionsEmpty, + focused, + error, + props.size, + color, + fullWidth, + startAdornment, + endAdornment, + InputProps?.startAdornment, + InputProps?.endAdornment, + label, + ], + ); + const classes = useUtilityClasses(classesProp, ownerState); const PickersInputComponent = VARIANT_COMPONENT[variant]; return ( - - - {label} - - + - {helperText && ( - - {helperText} - - )} - + required={required} + ownerState={ownerState} + {...other} + > + + {label} + + + {helperText && ( + + {helperText} + + )} + + ); }); diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts b/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts index ceb5909d56d5..7abd3b4f3467 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts @@ -1,12 +1,13 @@ import * as React from 'react'; -import { FormControlProps } from '@mui/material/FormControl'; +import { FormControlOwnProps, FormControlProps } from '@mui/material/FormControl'; import { FormHelperTextProps } from '@mui/material/FormHelperText'; import { InputLabelProps } from '@mui/material/InputLabel'; import { TextFieldVariants } from '@mui/material/TextField'; import { PickersInputPropsUsedByField } from './PickersInputBase/PickersInputBase.types'; -import { PickersInputProps } from './PickersInput'; -import { PickersOutlinedInputProps } from './PickersOutlinedInput'; -import { PickersFilledInputProps } from './PickersFilledInput'; +import type { PickersInputProps } from './PickersInput'; +import type { PickersOutlinedInputProps } from './PickersOutlinedInput'; +import type { PickersFilledInputProps } from './PickersFilledInput'; +import { FieldOwnerState } from '../models'; interface PickersTextFieldPropsUsedByField { onFocus: React.FocusEventHandler; @@ -79,3 +80,45 @@ export type PickersTextFieldProps; + /** + * The color of the input. + */ + inputColor: Exclude; + /** + * `true` if the input takes up the full width of its container. + */ + inputFullWidth: boolean; + /** + * `true` if the input has a start adornment, `false` otherwise. + */ + isInputAdornedStart: boolean; + /** + * `true` if the input has an end adornment, `false` otherwise. + */ + isInputAdornedEnd: boolean; + /** + * `true` if the input has a label, `false` otherwise. + */ + inputHasLabel: boolean; +} diff --git a/packages/x-date-pickers/src/PickersTextField/usePickerTextFieldOwnerState.ts b/packages/x-date-pickers/src/PickersTextField/usePickerTextFieldOwnerState.ts new file mode 100644 index 000000000000..95ff078654e3 --- /dev/null +++ b/packages/x-date-pickers/src/PickersTextField/usePickerTextFieldOwnerState.ts @@ -0,0 +1,19 @@ +'use client'; +import * as React from 'react'; +import { PickersTextFieldOwnerState } from './PickersTextField.types'; + +export const PickerTextFieldOwnerStateContext = + React.createContext(null); + +export const usePickerTextFieldOwnerState = () => { + const value = React.useContext(PickerTextFieldOwnerStateContext); + if (value == null) { + throw new Error( + [ + 'MUI X: The `usePickerTextFieldOwnerState` can only be called in components that are used inside a PickerTextField component', + ].join('\n'), + ); + } + + return value; +}; diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx index 65bea5a6bb71..48455438b411 100644 --- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx @@ -44,7 +44,7 @@ const PickersArrowSwitcherButton = styled(IconButton, { }>({ variants: [ { - props: { hidden: true }, + props: { isButtonHidden: true }, style: { visibility: 'hidden' }, }, ], @@ -119,7 +119,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch edge: 'end', onClick: previousProps.goTo, }, - ownerState: { ...ownerState, hidden: previousProps.isHidden ?? false }, + ownerState: { ...ownerState, isButtonHidden: previousProps.isHidden ?? false }, className: clsx(classes.button, classes.previousIconButton), }); @@ -135,7 +135,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch edge: 'start', onClick: nextProps.goTo, }, - ownerState: { ...ownerState, hidden: nextProps.isHidden ?? false }, + ownerState: { ...ownerState, isButtonHidden: nextProps.isHidden ?? false }, className: clsx(classes.button, classes.nextIconButton), }); diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx index 725f070b1750..0df4d813ea96 100644 --- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx +++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx @@ -46,7 +46,7 @@ export interface PickersArrowSwitcherOwnerState extends PickerOwnerState { /** * If `true`, this button should be hidden. */ - hidden: boolean; + isButtonHidden: boolean; } export interface PickersArrowSwitcherSlotPropsOverrides {} diff --git a/packages/x-date-pickers/src/internals/hooks/useFieldOwnerState.ts b/packages/x-date-pickers/src/internals/hooks/useFieldOwnerState.ts index bc1c326465dd..9ec96ac340d7 100644 --- a/packages/x-date-pickers/src/internals/hooks/useFieldOwnerState.ts +++ b/packages/x-date-pickers/src/internals/hooks/useFieldOwnerState.ts @@ -1,19 +1,25 @@ import * as React from 'react'; +import { useRtl } from '@mui/system/RtlProvider'; import { FieldOwnerState } from '../../models'; import { FormProps } from '../models'; import { usePickerPrivateContext } from './usePickerPrivateContext'; export function useFieldOwnerState(parameters: UseFieldOwnerStateParameters) { const { ownerState: pickerOwnerState } = usePickerPrivateContext(); + const isRtl = useRtl(); return React.useMemo( () => ({ ...pickerOwnerState, isFieldDisabled: parameters.disabled ?? false, isFieldReadOnly: parameters.readOnly ?? false, + isFieldRequired: parameters.required ?? false, + fieldDirection: isRtl ? 'rtl' : 'ltr', }), - [pickerOwnerState, parameters.disabled, parameters.readOnly], + [pickerOwnerState, parameters.disabled, parameters.readOnly, parameters.required, isRtl], ); } -interface UseFieldOwnerStateParameters extends FormProps {} +interface UseFieldOwnerStateParameters extends FormProps { + required?: boolean; +} diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index 05c0c4e0460f..f256b6164814 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -4,7 +4,7 @@ import type { ExportedUseClearableFieldProps, UseClearableFieldResponse, } from '../hooks/useClearableField'; -import { ExportedPickersSectionListProps } from '../PickersSectionList'; +import type { ExportedPickersSectionListProps } from '../PickersSectionList'; import type { UseFieldInternalProps, UseFieldResponse } from '../internals/hooks/useField'; import type { PickersTextFieldProps } from '../PickersTextField'; import { @@ -142,6 +142,16 @@ export interface FieldOwnerState extends PickerOwnerState { * `true` if the field is read-only, `false` otherwise. */ isFieldReadOnly: boolean; + /** + * `true` if the field is required, `false` otherwise. + */ + isFieldRequired: boolean; + /** + * The direction of the field. + * Is equal to "ltr" when the toolbar is in left-to-right direction. + * Is equal to "rtl" when the toolbar is in right-to-left direction. + */ + fieldDirection: 'ltr' | 'rtl'; } /** From c550ee9b46a080f48ea89845151047b4780d1637 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 13 Dec 2024 11:28:30 +0100 Subject: [PATCH 2/5] Work --- .../PickersFilledInput/PickersFilledInput.tsx | 30 +++++++++++++++---- .../pickersFilledInputClasses.ts | 6 ++-- .../PickersInput/PickersInput.tsx | 26 +++++++++++++--- .../PickersInput/pickersInputClasses.ts | 13 ++++---- .../PickersInputBase/PickersInputBase.tsx | 5 +++- .../PickersInputBase.types.ts | 6 +++- 6 files changed, 65 insertions(+), 21 deletions(-) diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx index 6a0f1423894c..e12f5335f4ca 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx @@ -15,18 +15,26 @@ import { PickersInputBaseSectionsContainer, } from '../PickersInputBase/PickersInputBase'; import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; export interface PickersFilledInputProps extends PickersInputBaseProps { disableUnderline?: boolean; hiddenLabel?: boolean; } +export interface PickersFilledInputOwnerState extends PickersTextFieldOwnerState { + /** + * If `true`, the input have an underline, `false` otherwise. + */ + inputHasUnderline: boolean; +} + const PickersFilledInputRoot = styled(PickersInputBaseRoot, { name: 'MuiPickersFilledInput', slot: 'Root', overridesResolver: (props, styles) => styles.root, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { +})<{ ownerState: PickersFilledInputOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; const backgroundColor = light ? 'rgba(0, 0, 0, 0.06)' : 'rgba(255, 255, 255, 0.09)'; @@ -141,7 +149,7 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, slot: 'sectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'hiddenLabel', -})<{ ownerState: PickersTextFieldOwnerState }>({ +})<{ ownerState: PickersFilledInputOwnerState }>({ paddingTop: 25, paddingRight: 12, paddingBottom: 8, @@ -183,9 +191,14 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, ], }); -const useUtilityClasses = (classes: Partial | undefined) => { +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersFilledInputOwnerState, +) => { + const { disableUnderline } = ownerState; + const slots = { - root: ['root'], + root: ['root', !disableUnderline && 'underline'], input: ['input'], }; @@ -215,11 +228,15 @@ const PickersFilledInput = React.forwardRef(function PickersFilledInput( disableUnderline = false, hiddenLabel = false, classes: classesProp, - ownerState: ownerStateProp, ...other } = props; - const classes = useUtilityClasses(classesProp); + const pickerTextFieldOwnerState = usePickerTextFieldOwnerState(); + const ownerState: PickersFilledInputOwnerState = { + ...pickerTextFieldOwnerState, + inputHasUnderline: !disableUnderline, + }; + const classes = useUtilityClasses(classesProp, ownerState); return ( ); }); diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/pickersFilledInputClasses.ts b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/pickersFilledInputClasses.ts index c135b0dd6fb5..fc5150048ff1 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/pickersFilledInputClasses.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/pickersFilledInputClasses.ts @@ -2,8 +2,10 @@ import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; import generateUtilityClass from '@mui/utils/generateUtilityClass'; import { PickersInputBaseClasses, pickersInputBaseClasses } from '../PickersInputBase'; -export interface PickersFilledInputClasses extends PickersInputBaseClasses {} - +export interface PickersFilledInputClasses extends PickersInputBaseClasses { + /** Styles applied to the root element unless `disableUnderline={true}`. */ + underline: string; +} export type PickersFilledInputClassKey = keyof PickersFilledInputClasses; export function getPickersFilledInputUtilityClass(slot: string) { diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx index 7f471d03f5df..862203256a27 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx @@ -12,17 +12,25 @@ import { import { PickersInputBase, PickersInputBaseProps } from '../PickersInputBase'; import { PickersInputBaseRoot } from '../PickersInputBase/PickersInputBase'; import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; export interface PickersInputProps extends PickersInputBaseProps { disableUnderline?: boolean; } +interface PickersInputOwnerState extends PickersTextFieldOwnerState { + /** + * If `true`, the input have an underline, `false` otherwise. + */ + inputHasUnderline: boolean; +} + const PickersInputRoot = styled(PickersInputBaseRoot, { name: 'MuiPickersInput', slot: 'Root', overridesResolver: (props, styles) => styles.root, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { +})<{ ownerState: PickersInputOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; let bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; if (theme.vars) { @@ -102,9 +110,14 @@ const PickersInputRoot = styled(PickersInputBaseRoot, { }; }); -const useUtilityClasses = (classes: Partial | undefined) => { +const useUtilityClasses = ( + classes: Partial | undefined, + ownerState: PickersInputOwnerState, +) => { + const { inputHasUnderline } = ownerState; + const slots = { - root: ['root'], + root: ['root', !inputHasUnderline && 'underline'], input: ['input'], }; @@ -137,7 +150,12 @@ const PickersInput = React.forwardRef(function PickersInput( ...other } = props; - const classes = useUtilityClasses(classesProp); + const pickerTextFieldOwnerState = usePickerTextFieldOwnerState(); + const ownerState: PickersInputOwnerState = { + ...pickerTextFieldOwnerState, + inputHasUnderline: !disableUnderline, + }; + const classes = useUtilityClasses(classesProp, ownerState); return ( ('MuiPickersInput', ['root', 'input']), + ...generateUtilityClasses('MuiPickersInput', ['root', 'underline', 'input']), }; diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx index 51c028b68e60..201988fbd4a0 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx @@ -197,7 +197,6 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( props: inProps, name: 'MuiPickersInputBase', }); - const ownerState = usePickerTextFieldOwnerState(); const { elements, @@ -227,9 +226,11 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( onFocus, onBlur, classes: classesProp, + ownerState: ownerStateProp, ...other } = props; + const ownerStateCtx = usePickerTextFieldOwnerState(); const rootRef = React.useRef(null); const handleRootRef = useForkRef(ref, rootRef); const handleInputRef = useForkRef(inputProps?.ref, inputRef); @@ -240,6 +241,8 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( ); } + const ownerState = ownerStateProp ?? ownerStateCtx; + const handleInputFocus = (event: React.FocusEvent) => { muiFormControl.onFocus?.(event); onFocus?.(event); diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts index 56b540e1c8cf..66462384ac66 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts @@ -1,6 +1,7 @@ import * as React from 'react'; import { BoxProps } from '@mui/material/Box'; import { PickersSectionListProps } from '../../PickersSectionList'; +import { PickersTextFieldOwnerState } from '../PickersTextField.types'; export interface PickersInputPropsUsedByField extends Pick< @@ -38,7 +39,10 @@ export interface PickersInputPropsUsedByField export interface PickersInputBaseProps extends Omit, PickersInputPropsUsedByField { - ownerState?: any; + /** + * The ownerState to use if it's not PickersTextFieldOwnerState + */ + ownerState?: PickersTextFieldOwnerState & Record; margin?: 'dense' | 'none' | 'normal'; renderSuffix?: (state: { disabled?: boolean; From b7d5af07a0609ea007f48e5c867c62fd779168c5 Mon Sep 17 00:00:00 2001 From: flavien Date: Fri, 13 Dec 2024 11:53:46 +0100 Subject: [PATCH 3/5] Fix --- .../PickersFilledInput/PickersFilledInput.tsx | 4 ++-- .../PickersInputBase/PickersInputBase.types.ts | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx index e12f5335f4ca..0bb6d8ff1319 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx @@ -195,10 +195,10 @@ const useUtilityClasses = ( classes: Partial | undefined, ownerState: PickersFilledInputOwnerState, ) => { - const { disableUnderline } = ownerState; + const { inputHasUnderline } = ownerState; const slots = { - root: ['root', !disableUnderline && 'underline'], + root: ['root', inputHasUnderline && 'underline'], input: ['input'], }; diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts index 66462384ac66..56b540e1c8cf 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.types.ts @@ -1,7 +1,6 @@ import * as React from 'react'; import { BoxProps } from '@mui/material/Box'; import { PickersSectionListProps } from '../../PickersSectionList'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; export interface PickersInputPropsUsedByField extends Pick< @@ -39,10 +38,7 @@ export interface PickersInputPropsUsedByField export interface PickersInputBaseProps extends Omit, PickersInputPropsUsedByField { - /** - * The ownerState to use if it's not PickersTextFieldOwnerState - */ - ownerState?: PickersTextFieldOwnerState & Record; + ownerState?: any; margin?: 'dense' | 'none' | 'normal'; renderSuffix?: (state: { disabled?: boolean; From 3fc06f5252668a4cbb7e58716e900324b41ea431 Mon Sep 17 00:00:00 2001 From: flavien Date: Tue, 17 Dec 2024 09:35:15 +0100 Subject: [PATCH 4/5] Review Lukas and Michel --- .../PickersFilledInput/PickersFilledInput.tsx | 22 ++++++------- .../PickersInput/PickersInput.tsx | 12 +++---- .../PickersInputBase/PickersInputBase.tsx | 31 +++++++++---------- .../PickersOutlinedInput.tsx | 6 ++-- .../src/PickersTextField/PickersTextField.tsx | 6 ++-- .../PickersTextField.types.ts | 8 ++--- .../usePickerTextFieldOwnerState.ts | 4 +-- packages/x-date-pickers/src/models/fields.ts | 4 +-- 8 files changed, 46 insertions(+), 47 deletions(-) diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx index 0bb6d8ff1319..5f8e95e6e12d 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx @@ -14,7 +14,7 @@ import { PickersInputBaseRoot, PickersInputBaseSectionsContainer, } from '../PickersInputBase/PickersInputBase'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { PickerTextFieldOwnerState } from '../PickersTextField.types'; import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; export interface PickersFilledInputProps extends PickersInputBaseProps { @@ -22,9 +22,9 @@ export interface PickersFilledInputProps extends PickersInputBaseProps { hiddenLabel?: boolean; } -export interface PickersFilledInputOwnerState extends PickersTextFieldOwnerState { +export interface PickerFilledInputOwnerState extends PickerTextFieldOwnerState { /** - * If `true`, the input have an underline, `false` otherwise. + * `true` if the input has an underline, `false` otherwise. */ inputHasUnderline: boolean; } @@ -34,7 +34,7 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, { slot: 'Root', overridesResolver: (props, styles) => styles.root, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', -})<{ ownerState: PickersFilledInputOwnerState }>(({ theme }) => { +})<{ ownerState: PickerFilledInputOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; const backgroundColor = light ? 'rgba(0, 0, 0, 0.06)' : 'rgba(255, 255, 255, 0.09)'; @@ -129,13 +129,13 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, { }, }, { - props: { isInputAdornedStart: true }, + props: { hasStartAdornment: true }, style: { paddingLeft: 12, }, }, { - props: { isInputAdornedEnd: true }, + props: { hasEndAdornment: true }, style: { paddingRight: 12, }, @@ -149,7 +149,7 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, slot: 'sectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'hiddenLabel', -})<{ ownerState: PickersFilledInputOwnerState }>({ +})<{ ownerState: PickerFilledInputOwnerState }>({ paddingTop: 25, paddingRight: 12, paddingBottom: 8, @@ -163,13 +163,13 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, }, }, { - props: { isInputAdornedStart: true }, + props: { hasStartAdornment: true }, style: { paddingLeft: 0, }, }, { - props: { isInputAdornedEnd: true }, + props: { hasEndAdornment: true }, style: { paddingRight: 0, }, @@ -193,7 +193,7 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer, const useUtilityClasses = ( classes: Partial | undefined, - ownerState: PickersFilledInputOwnerState, + ownerState: PickerFilledInputOwnerState, ) => { const { inputHasUnderline } = ownerState; @@ -232,7 +232,7 @@ const PickersFilledInput = React.forwardRef(function PickersFilledInput( } = props; const pickerTextFieldOwnerState = usePickerTextFieldOwnerState(); - const ownerState: PickersFilledInputOwnerState = { + const ownerState: PickerFilledInputOwnerState = { ...pickerTextFieldOwnerState, inputHasUnderline: !disableUnderline, }; diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx index 862203256a27..15faf794f47f 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersInput/PickersInput.tsx @@ -11,16 +11,16 @@ import { } from './pickersInputClasses'; import { PickersInputBase, PickersInputBaseProps } from '../PickersInputBase'; import { PickersInputBaseRoot } from '../PickersInputBase/PickersInputBase'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { PickerTextFieldOwnerState } from '../PickersTextField.types'; import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; export interface PickersInputProps extends PickersInputBaseProps { disableUnderline?: boolean; } -interface PickersInputOwnerState extends PickersTextFieldOwnerState { +interface PickerInputOwnerState extends PickerTextFieldOwnerState { /** - * If `true`, the input have an underline, `false` otherwise. + * `true` if the input has an underline, `false` otherwise. */ inputHasUnderline: boolean; } @@ -30,7 +30,7 @@ const PickersInputRoot = styled(PickersInputBaseRoot, { slot: 'Root', overridesResolver: (props, styles) => styles.root, shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline', -})<{ ownerState: PickersInputOwnerState }>(({ theme }) => { +})<{ ownerState: PickerInputOwnerState }>(({ theme }) => { const light = theme.palette.mode === 'light'; let bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; if (theme.vars) { @@ -112,7 +112,7 @@ const PickersInputRoot = styled(PickersInputBaseRoot, { const useUtilityClasses = ( classes: Partial | undefined, - ownerState: PickersInputOwnerState, + ownerState: PickerInputOwnerState, ) => { const { inputHasUnderline } = ownerState; @@ -151,7 +151,7 @@ const PickersInput = React.forwardRef(function PickersInput( } = props; const pickerTextFieldOwnerState = usePickerTextFieldOwnerState(); - const ownerState: PickersInputOwnerState = { + const ownerState: PickerInputOwnerState = { ...pickerTextFieldOwnerState, inputHasUnderline: !disableUnderline, }; diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx index 201988fbd4a0..4ea33c8b59b7 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx @@ -22,7 +22,7 @@ import { Unstable_PickersSectionListSectionContent as PickersSectionListSectionContent, } from '../../PickersSectionList'; import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { PickerTextFieldOwnerState } from '../PickersTextField.types'; const round = (value: number) => Math.round(value * 1e5) / 1e5; @@ -30,7 +30,7 @@ export const PickersInputBaseRoot = styled('div', { name: 'MuiPickersInputBase', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => ({ +})<{ ownerState: PickerTextFieldOwnerState }>(({ theme }) => ({ ...theme.typography.body1, color: (theme.vars || theme).palette.text.primary, cursor: 'text', @@ -43,7 +43,7 @@ export const PickersInputBaseRoot = styled('div', { letterSpacing: `${round(0.15 / 16)}em`, variants: [ { - props: { inputFullWidth: true }, + props: { isInputInFullWidth: true }, style: { width: '100%' }, }, ], @@ -53,7 +53,7 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, name: 'MuiPickersInputBase', slot: 'SectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => ({ +})<{ ownerState: PickerTextFieldOwnerState }>(({ theme }) => ({ padding: '4px 0 5px', fontFamily: theme.typography.fontFamily, fontSize: 'inherit', @@ -80,16 +80,15 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, }, }, { - props: { isInputAdornedStart: false, isFieldFocused: false, isFieldValueEmpty: true }, + props: { hasStartAdornment: false, isFieldFocused: false, isFieldValueEmpty: true }, style: { color: 'currentColor', opacity: 0, }, }, { - // Can't use the object notation because label can be null or undefined props: { - isInputAdornedStart: false, + hasStartAdornment: false, isFieldFocused: false, isFieldValueEmpty: true, inputHasLabel: false, @@ -148,7 +147,7 @@ const PickersInputBaseInput = styled('input', { const useUtilityClasses = ( classes: Partial | undefined, - ownerState: PickersTextFieldOwnerState, + ownerState: PickerTextFieldOwnerState, ) => { const { isFieldFocused, @@ -156,10 +155,10 @@ const useUtilityClasses = ( isFieldReadOnly, hasFieldError, inputSize, - inputFullWidth, + isInputInFullWidth, inputColor, - isInputAdornedStart, - isInputAdornedEnd, + hasStartAdornment, + hasEndAdornment, } = ownerState; const slots = { @@ -169,11 +168,11 @@ const useUtilityClasses = ( isFieldDisabled && 'disabled', isFieldReadOnly && 'readOnly', hasFieldError && 'error', - inputFullWidth && 'fullWidth', + isInputInFullWidth && 'fullWidth', `color${capitalize(inputColor!)}`, inputSize === 'small' && 'inputSizeSmall', - isInputAdornedStart && 'adornedStart', - isInputAdornedEnd && 'adornedEnd', + hasStartAdornment && 'adornedStart', + hasEndAdornment && 'adornedEnd', ], notchedOutline: ['notchedOutline'], input: ['input'], @@ -230,7 +229,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( ...other } = props; - const ownerStateCtx = usePickerTextFieldOwnerState(); + const ownerStateContext = usePickerTextFieldOwnerState(); const rootRef = React.useRef(null); const handleRootRef = useForkRef(ref, rootRef); const handleInputRef = useForkRef(inputProps?.ref, inputRef); @@ -241,7 +240,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase( ); } - const ownerState = ownerStateProp ?? ownerStateCtx; + const ownerState = ownerStateProp ?? ownerStateContext; const handleInputFocus = (event: React.FocusEvent) => { muiFormControl.onFocus?.(event); diff --git a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx index bbd2f7739ca9..c9e28dc5257e 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx @@ -15,7 +15,7 @@ import { PickersInputBaseRoot, PickersInputBaseSectionsContainer, } from '../PickersInputBase/PickersInputBase'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { PickerTextFieldOwnerState } from '../PickersTextField.types'; export interface PickersOutlinedInputProps extends PickersInputBaseProps { notched?: boolean; @@ -25,7 +25,7 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, { name: 'MuiPickersOutlinedInput', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { +})<{ ownerState: PickerTextFieldOwnerState }>(({ theme }) => { const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'; return { @@ -77,7 +77,7 @@ const PickersOutlinedInputSectionsContainer = styled(PickersInputBaseSectionsCon name: 'MuiPickersOutlinedInput', slot: 'SectionsContainer', overridesResolver: (props, styles) => styles.sectionsContainer, -})<{ ownerState: PickersTextFieldOwnerState }>({ +})<{ ownerState: PickerTextFieldOwnerState }>({ padding: '16.5px 0', variants: [ { diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx index e39727e4987b..de33608978ee 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx @@ -122,9 +122,9 @@ const PickersTextField = React.forwardRef(function PickersTextField( hasFieldError: error ?? false, inputSize: props.size ?? 'medium', inputColor: color ?? 'primary', - inputFullWidth: fullWidth ?? false, - isInputAdornedStart: Boolean(startAdornment ?? InputProps?.startAdornment), - isInputAdornedEnd: Boolean(endAdornment ?? InputProps?.endAdornment), + isInputInFullWidth: fullWidth ?? false, + hasStartAdornment: Boolean(startAdornment ?? InputProps?.startAdornment), + hasEndAdornment: Boolean(endAdornment ?? InputProps?.endAdornment), inputHasLabel: !!label, }), [ diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts b/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts index 7abd3b4f3467..494a039adc77 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts +++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.types.ts @@ -81,7 +81,7 @@ export type PickersTextFieldProps(null); + React.createContext(null); export const usePickerTextFieldOwnerState = () => { const value = React.useContext(PickerTextFieldOwnerStateContext); diff --git a/packages/x-date-pickers/src/models/fields.ts b/packages/x-date-pickers/src/models/fields.ts index f256b6164814..eac8aedd90db 100644 --- a/packages/x-date-pickers/src/models/fields.ts +++ b/packages/x-date-pickers/src/models/fields.ts @@ -148,8 +148,8 @@ export interface FieldOwnerState extends PickerOwnerState { isFieldRequired: boolean; /** * The direction of the field. - * Is equal to "ltr" when the toolbar is in left-to-right direction. - * Is equal to "rtl" when the toolbar is in right-to-left direction. + * Is equal to "ltr" when the field is in left-to-right direction. + * Is equal to "rtl" when the field is in right-to-left direction. */ fieldDirection: 'ltr' | 'rtl'; } From b83b47ce94b270c01410a04978488d67189fee79 Mon Sep 17 00:00:00 2001 From: flavien Date: Tue, 17 Dec 2024 11:23:35 +0100 Subject: [PATCH 5/5] Fix --- .../src/PickersTextField/PickersOutlinedInput/Outline.tsx | 6 +++--- .../src/PickersTextField/PickersTextField.tsx | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx index 7c3f10d654e1..58178c087262 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/Outline.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { styled } from '@mui/material/styles'; import { shouldForwardProp } from '@mui/system/createStyled'; import { usePickerTextFieldOwnerState } from '../usePickerTextFieldOwnerState'; -import { PickersTextFieldOwnerState } from '../PickersTextField.types'; +import { PickerTextFieldOwnerState } from '../PickersTextField.types'; interface OutlineProps extends React.HTMLAttributes { notched: boolean; @@ -14,7 +14,7 @@ const OutlineRoot = styled('fieldset', { name: 'MuiPickersOutlinedInput', slot: 'NotchedOutline', overridesResolver: (props, styles) => styles.notchedOutline, -})<{ ownerState: PickersTextFieldOwnerState }>(({ theme }) => { +})<{ ownerState: PickerTextFieldOwnerState }>(({ theme }) => { const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'; return { @@ -45,7 +45,7 @@ const OutlineLabel = styled('span')(({ theme }) => ({ const OutlineLegend = styled('legend', { shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'notched', -})<{ ownerState: PickersTextFieldOwnerState; notched: boolean }>(({ theme }) => ({ +})<{ ownerState: PickerTextFieldOwnerState; notched: boolean }>(({ theme }) => ({ float: 'unset', // Fix conflict with bootstrap width: 'auto', // Fix conflict with bootstrap overflow: 'hidden', // Fix Horizontal scroll when label too long diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx index de33608978ee..daccf5ec262b 100644 --- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx +++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx @@ -14,7 +14,7 @@ import { getPickersTextFieldUtilityClass, PickersTextFieldClasses, } from './pickersTextFieldClasses'; -import { PickersTextFieldOwnerState, PickersTextFieldProps } from './PickersTextField.types'; +import { PickerTextFieldOwnerState, PickersTextFieldProps } from './PickersTextField.types'; import { PickersOutlinedInput } from './PickersOutlinedInput'; import { PickersFilledInput } from './PickersFilledInput'; import { PickersInput } from './PickersInput'; @@ -31,11 +31,11 @@ const PickersTextFieldRoot = styled(FormControl, { name: 'MuiPickersTextField', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: PickersTextFieldOwnerState }>({}); +})<{ ownerState: PickerTextFieldOwnerState }>({}); const useUtilityClasses = ( classes: Partial | undefined, - ownerState: PickersTextFieldOwnerState, + ownerState: PickerTextFieldOwnerState, ) => { const { isFieldFocused, isFieldDisabled, isFieldRequired } = ownerState; @@ -114,7 +114,7 @@ const PickersTextField = React.forwardRef(function PickersTextField( required: props.required, readOnly: InputProps?.readOnly, }); - const ownerState = React.useMemo( + const ownerState = React.useMemo( () => ({ ...fieldOwnerState, isFieldValueEmpty: areAllSectionsEmpty,