diff --git a/docs/pages/x/api/date-pickers/date-range-picker-day.json b/docs/pages/x/api/date-pickers/date-range-picker-day.json
index fc19b9e50ec6..fa57a2557f2b 100644
--- a/docs/pages/x/api/date-pickers/date-range-picker-day.json
+++ b/docs/pages/x/api/date-pickers/date-range-picker-day.json
@@ -23,6 +23,7 @@
"disableMargin": { "type": { "name": "bool" }, "default": "false" },
"disableRipple": { "type": { "name": "bool" }, "default": "false" },
"disableTouchRipple": { "type": { "name": "bool" }, "default": "false" },
+ "draggable": { "type": { "name": "bool" }, "default": "false" },
"focusRipple": { "type": { "name": "bool" }, "default": "false" },
"focusVisibleClassName": { "type": { "name": "string" } },
"isVisuallySelected": { "type": { "name": "bool" } },
diff --git a/docs/translations/api-docs/date-pickers/date-range-picker-day/date-range-picker-day.json b/docs/translations/api-docs/date-pickers/date-range-picker-day/date-range-picker-day.json
index d24a2914f43b..56e31a43dd71 100644
--- a/docs/translations/api-docs/date-pickers/date-range-picker-day/date-range-picker-day.json
+++ b/docs/translations/api-docs/date-pickers/date-range-picker-day/date-range-picker-day.json
@@ -22,6 +22,9 @@
"disableTouchRipple": {
"description": "If true
, the touch ripple effect is disabled."
},
+ "draggable": {
+ "description": "If true
, the day can be dragged to change the current date range."
+ },
"focusRipple": {
"description": "If true
, the base button will have a keyboard focus ripple."
},
diff --git a/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx b/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx
index 29c0be8863b8..95ca252d165c 100644
--- a/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx
+++ b/packages/x-date-pickers-pro/src/DateRangePickerDay/DateRangePickerDay.tsx
@@ -50,6 +50,11 @@ export interface DateRangePickerDayProps
* Indicates if the day should be visually selected.
*/
isVisuallySelected?: boolean;
+ /**
+ * If `true`, the day can be dragged to change the current date range.
+ * @default false
+ */
+ draggable?: boolean;
}
type OwnerState = DateRangePickerDayProps & {
@@ -154,10 +159,11 @@ const DateRangePickerDayRoot = styled('div', {
},
styles.root,
],
-})<{ ownerState: OwnerState }>(({ theme, ownerState }) =>
- ownerState.isHiddenDayFiller
- ? {}
- : {
+})<{ ownerState: OwnerState }>(({ theme }) => ({
+ variants: [
+ {
+ props: { isHiddenDayFiller: false },
+ style: {
[`&:first-of-type .${dateRangePickerDayClasses.rangeIntervalDayPreview}`]: {
...startBorderStyle,
borderLeftColor: (theme.vars || theme).palette.divider,
@@ -166,25 +172,44 @@ const DateRangePickerDayRoot = styled('div', {
...endBorderStyle,
borderRightColor: (theme.vars || theme).palette.divider,
},
- ...(ownerState.isHighlighting && {
- borderRadius: 0,
- color: (theme.vars || theme).palette.primary.contrastText,
- backgroundColor: theme.vars
- ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.focusOpacity})`
- : alpha(theme.palette.primary.main, theme.palette.action.focusOpacity),
- '&:first-of-type': startBorderStyle,
- '&:last-of-type': endBorderStyle,
- }),
- ...((ownerState.isStartOfHighlighting || ownerState.isFirstVisibleCell) && {
- ...startBorderStyle,
- paddingLeft: 0,
- }),
- ...((ownerState.isEndOfHighlighting || ownerState.isLastVisibleCell) && {
- ...endBorderStyle,
- paddingRight: 0,
- }),
},
-);
+ },
+ {
+ props: { isHiddenDayFiller: false, isHighlighting: true },
+ style: {
+ borderRadius: 0,
+ color: (theme.vars || theme).palette.primary.contrastText,
+ backgroundColor: theme.vars
+ ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.focusOpacity})`
+ : alpha(theme.palette.primary.main, theme.palette.action.focusOpacity),
+ '&:first-of-type': startBorderStyle,
+ '&:last-of-type': endBorderStyle,
+ },
+ },
+ {
+ props: ({
+ ownerState: { isHiddenDayFiller, isStartOfHighlighting, isFirstVisibleCell },
+ }: {
+ ownerState: OwnerState;
+ }) => !isHiddenDayFiller && (isStartOfHighlighting || isFirstVisibleCell),
+ style: {
+ ...startBorderStyle,
+ paddingLeft: 0,
+ },
+ },
+ {
+ props: ({
+ ownerState: { isHiddenDayFiller, isEndOfHighlighting, isLastVisibleCell },
+ }: {
+ ownerState: OwnerState;
+ }) => !isHiddenDayFiller && (isEndOfHighlighting || isLastVisibleCell),
+ style: {
+ ...endBorderStyle,
+ paddingRight: 0,
+ },
+ },
+ ],
+}));
DateRangePickerDayRoot.propTypes = {
// ----------------------------- Warning --------------------------------
@@ -209,24 +234,42 @@ const DateRangePickerDayRangeIntervalPreview = styled('div', {
},
styles.rangeIntervalPreview,
],
-})<{ ownerState: OwnerState }>(({ theme, ownerState }) => ({
+})<{ ownerState: OwnerState }>(({ theme }) => ({
// replace default day component margin with transparent border to avoid jumping on preview
border: '2px solid transparent',
- ...(ownerState.isPreviewing &&
- !ownerState.isHiddenDayFiller && {
- borderRadius: 0,
- border: `2px dashed ${(theme.vars || theme).palette.divider}`,
- borderLeftColor: 'transparent',
- borderRightColor: 'transparent',
- ...((ownerState.isStartOfPreviewing || ownerState.isFirstVisibleCell) && {
+ variants: [
+ {
+ props: { isPreviewing: true, isHiddenDayFiller: false },
+ style: {
+ borderRadius: 0,
+ border: `2px dashed ${(theme.vars || theme).palette.divider}`,
+ borderLeftColor: 'transparent',
+ borderRightColor: 'transparent',
+ },
+ },
+ {
+ props: ({
+ ownerState: { isPreviewing, isHiddenDayFiller, isStartOfPreviewing, isFirstVisibleCell },
+ }: {
+ ownerState: OwnerState;
+ }) => isPreviewing && !isHiddenDayFiller && (isStartOfPreviewing || isFirstVisibleCell),
+ style: {
borderLeftColor: (theme.vars || theme).palette.divider,
...startBorderStyle,
- }),
- ...((ownerState.isEndOfPreviewing || ownerState.isLastVisibleCell) && {
+ },
+ },
+ {
+ props: ({
+ ownerState: { isPreviewing, isHiddenDayFiller, isEndOfPreviewing, isLastVisibleCell },
+ }: {
+ ownerState: OwnerState;
+ }) => isPreviewing && !isHiddenDayFiller && (isEndOfPreviewing || isLastVisibleCell),
+ style: {
borderRightColor: (theme.vars || theme).palette.divider,
...endBorderStyle,
- }),
- }),
+ },
+ },
+ ],
}));
DateRangePickerDayRangeIntervalPreview.propTypes = {
@@ -248,19 +291,22 @@ const DateRangePickerDayDay = styled(PickersDay, {
],
})<{
ownerState: OwnerState;
-}>(({ ownerState }) => ({
+}>({
// Required to overlap preview border
transform: 'scale(1.1)',
'& > *': {
transform: 'scale(0.9)',
},
- ...(ownerState.draggable && {
- cursor: 'grab',
- }),
- ...(ownerState.draggable && {
- touchAction: 'none',
- }),
-})) as unknown as (
+ variants: [
+ {
+ props: { draggable: true },
+ style: {
+ cursor: 'grab',
+ touchAction: 'none',
+ },
+ },
+ ],
+}) as unknown as (
props: PickersDayProps & { ownerState: OwnerState },
) => React.JSX.Element;
@@ -405,6 +451,11 @@ DateRangePickerDayRaw.propTypes = {
* @default false
*/
disableTouchRipple: PropTypes.bool,
+ /**
+ * If `true`, the day can be dragged to change the current date range.
+ * @default false
+ */
+ draggable: PropTypes.bool,
/**
* If `true`, the base button will have a keyboard focus ripple.
* @default false
diff --git a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx
index 32fbf3ec18ba..4d4c6155c38e 100644
--- a/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx
+++ b/packages/x-date-pickers-pro/src/DateTimeRangePicker/DateTimeRangePickerToolbar.tsx
@@ -76,24 +76,43 @@ const DateTimeRangePickerToolbarStart = styled(DateTimePickerToolbar, {
name: 'MuiDateTimeRangePickerToolbar',
slot: 'StartToolbar',
overridesResolver: (_, styles) => styles.startToolbar,
-})>(({ ownerState }) => ({
+})>({
borderBottom: 'none',
- ...(ownerState?.toolbarVariant !== 'desktop'
- ? {
+ variants: [
+ {
+ props: ({ toolbarVariant }: DateTimeRangePickerStartOrEndToolbarProps) =>
+ toolbarVariant !== 'desktop',
+ style: {
padding: '12px 8px 0 12px',
- }
- : {
+ },
+ },
+ {
+ props: { toolbarVariant: 'desktop' },
+ style: {
paddingBottom: 0,
- }),
-})) as DateTimeRangePickerStartOrEndToolbarComponent;
+ },
+ },
+ ],
+}) as DateTimeRangePickerStartOrEndToolbarComponent;
const DateTimeRangePickerToolbarEnd = styled(DateTimePickerToolbar, {
name: 'MuiDateTimeRangePickerToolbar',
slot: 'EndToolbar',
overridesResolver: (_, styles) => styles.endToolbar,
-})>(({ ownerState }) => ({
- padding: ownerState?.toolbarVariant !== 'desktop' ? '12px 8px 12px 12px' : undefined,
-})) as DateTimeRangePickerStartOrEndToolbarComponent;
+})>({
+ variants: [
+ {
+ props: ({
+ ownerState: { toolbarVariant },
+ }: {
+ ownerState: DateTimeRangePickerStartOrEndToolbarProps;
+ }) => toolbarVariant !== 'desktop',
+ style: {
+ padding: '12px 8px 12px 12px',
+ },
+ },
+ ],
+}) as DateTimeRangePickerStartOrEndToolbarComponent;
const DateTimeRangePickerToolbar = React.forwardRef(function DateTimeRangePickerToolbar<
TDate extends PickerValidDate,
diff --git a/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx b/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx
index 820e0f5ed83a..9e0dbdba817d 100644
--- a/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx
+++ b/packages/x-date-pickers/src/DatePicker/DatePickerToolbar.tsx
@@ -45,11 +45,16 @@ const DatePickerToolbarTitle = styled(Typography, {
name: 'MuiDatePickerToolbar',
slot: 'Title',
overridesResolver: (_, styles) => styles.title,
-})<{ ownerState: DatePickerToolbarProps }>(({ ownerState }) => ({
- ...(ownerState.isLandscape && {
- margin: 'auto 16px auto auto',
- }),
-}));
+})<{ ownerState: DatePickerToolbarProps }>({
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ margin: 'auto 16px auto auto',
+ },
+ },
+ ],
+});
type DatePickerToolbarComponent = ((
props: DatePickerToolbarProps & React.RefAttributes,
diff --git a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx
index f100e3fbe33b..21593a3f6081 100644
--- a/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx
+++ b/packages/x-date-pickers/src/DateTimePicker/DateTimePickerToolbar.tsx
@@ -60,25 +60,36 @@ const DateTimePickerToolbarRoot = styled(PickersToolbar, {
name: 'MuiDateTimePickerToolbar',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: DateTimePickerToolbarProps }>(({ theme, ownerState }) => ({
- paddingLeft: ownerState.toolbarVariant === 'desktop' && !ownerState.isLandscape ? 24 : 16,
- paddingRight: ownerState.toolbarVariant === 'desktop' && !ownerState.isLandscape ? 0 : 16,
- borderBottom:
- ownerState.toolbarVariant === 'desktop'
- ? `1px solid ${(theme.vars || theme).palette.divider}`
- : undefined,
- borderRight:
- ownerState.toolbarVariant === 'desktop' && ownerState.isLandscape
- ? `1px solid ${(theme.vars || theme).palette.divider}`
- : undefined,
+})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => ({
+ paddingLeft: 16,
+ paddingRight: 16,
justifyContent: 'space-around',
position: 'relative',
- ...(ownerState.toolbarVariant === 'desktop' && {
- [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: {
- color: (theme.vars || theme).palette.primary.main,
- fontWeight: theme.typography.fontWeightBold,
+ variants: [
+ {
+ props: { toolbarVariant: 'desktop' },
+ style: {
+ borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`,
+ [`& .${pickersToolbarClasses.content} .${pickersToolbarTextClasses.selected}`]: {
+ color: (theme.vars || theme).palette.primary.main,
+ fontWeight: theme.typography.fontWeightBold,
+ },
+ },
},
- }),
+ {
+ props: { toolbarVariant: 'desktop', isLandscape: true },
+ style: {
+ borderRight: `1px solid ${(theme.vars || theme).palette.divider}`,
+ },
+ },
+ {
+ props: { toolbarVariant: 'desktop', isLandscape: false },
+ style: {
+ paddingLeft: 24,
+ paddingRight: 0,
+ },
+ },
+ ],
}));
DateTimePickerToolbarRoot.propTypes = {
@@ -117,22 +128,33 @@ const DateTimePickerToolbarTimeContainer = styled('div', {
name: 'MuiDateTimePickerToolbar',
slot: 'TimeContainer',
overridesResolver: (props, styles) => styles.timeContainer,
-})<{ ownerState: DateTimePickerToolbarProps }>(({ theme, ownerState }) => {
- const direction =
- ownerState.isLandscape && ownerState.toolbarVariant !== 'desktop' ? 'column' : 'row';
+})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => {
return {
display: 'flex',
- flexDirection: direction,
- ...(ownerState.toolbarVariant === 'desktop' && {
- ...(!ownerState.isLandscape && {
- gap: 9,
- marginRight: 4,
- alignSelf: 'flex-end',
- }),
- }),
+ flexDirection: 'row',
...(theme.direction === 'rtl' && {
- flexDirection: `${direction}-reverse`,
+ flexDirection: 'row-reverse',
}),
+ variants: [
+ {
+ props: ({ isLandscape, toolbarVariant }: DateTimePickerToolbarProps) =>
+ isLandscape && toolbarVariant !== 'desktop',
+ style: {
+ flexDirection: 'column',
+ ...(theme.direction === 'rtl' && {
+ flexDirection: 'column-reverse',
+ }),
+ },
+ },
+ {
+ props: { toolbarVariant: 'desktop', isLandscape: false },
+ style: {
+ gap: 9,
+ marginRight: 4,
+ alignSelf: 'flex-end',
+ },
+ },
+ ],
};
});
@@ -140,12 +162,17 @@ const DateTimePickerToolbarTimeDigitsContainer = styled('div', {
name: 'MuiDateTimePickerToolbar',
slot: 'TimeDigitsContainer',
overridesResolver: (props, styles) => styles.timeDigitsContainer,
-})<{ ownerState: DateTimePickerToolbarProps }>(({ theme, ownerState }) => ({
+})<{ ownerState: DateTimePickerToolbarProps }>(({ theme }) => ({
display: 'flex',
- ...(ownerState.toolbarVariant === 'desktop' && { gap: 1.5 }),
...(theme.direction === 'rtl' && {
flexDirection: 'row-reverse',
}),
+ variants: [
+ {
+ props: { toolbarVariant: 'desktop' },
+ style: { gap: 1.5 },
+ },
+ ],
}));
DateTimePickerToolbarTimeContainer.propTypes = {
@@ -168,10 +195,18 @@ const DateTimePickerToolbarSeparator = styled(PickersToolbarText, {
overridesResolver: (props, styles) => styles.separator,
})<{
ownerState: DateTimePickerToolbarProps;
-}>(({ ownerState }) => ({
- margin: ownerState.toolbarVariant === 'desktop' ? 0 : '0 4px 0 2px',
+}>({
+ margin: '0 4px 0 2px',
cursor: 'default',
-}));
+ variants: [
+ {
+ props: { toolbarVariant: 'desktop' },
+ style: {
+ margin: 0,
+ },
+ },
+ ],
+});
// Taken from TimePickerToolbar
const DateTimePickerToolbarAmPmSelection = styled('div', {
@@ -184,21 +219,26 @@ const DateTimePickerToolbarAmPmSelection = styled('div', {
],
})<{
ownerState: DateTimePickerToolbarProps;
-}>(({ ownerState }) => ({
+}>({
display: 'flex',
flexDirection: 'column',
marginRight: 'auto',
marginLeft: 12,
- ...(ownerState.isLandscape && {
- margin: '4px 0 auto',
- flexDirection: 'row',
- justifyContent: 'space-around',
- width: '100%',
- }),
[`& .${dateTimePickerToolbarClasses.ampmLabel}`]: {
fontSize: 17,
},
-}));
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ margin: '4px 0 auto',
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ width: '100%',
+ },
+ },
+ ],
+});
/**
* Demos:
diff --git a/packages/x-date-pickers/src/DayCalendarSkeleton/DayCalendarSkeleton.tsx b/packages/x-date-pickers/src/DayCalendarSkeleton/DayCalendarSkeleton.tsx
index cca99858f8ae..1af619f65904 100644
--- a/packages/x-date-pickers/src/DayCalendarSkeleton/DayCalendarSkeleton.tsx
+++ b/packages/x-date-pickers/src/DayCalendarSkeleton/DayCalendarSkeleton.tsx
@@ -58,12 +58,15 @@ const DayCalendarSkeletonDay = styled(Skeleton, {
name: 'MuiDayCalendarSkeleton',
slot: 'DaySkeleton',
overridesResolver: (props, styles) => styles.daySkeleton,
-})<{ ownerState: { day: number } }>(({ ownerState }) => ({
+})<{ ownerState: { day: number } }>({
margin: `0 ${DAY_MARGIN}px`,
- ...(ownerState.day === 0 && {
- visibility: 'hidden',
- }),
-}));
+ variants: [
+ {
+ props: { day: 0 },
+ style: { visibility: 'hidden' },
+ },
+ ],
+});
DayCalendarSkeletonDay.propTypes = {
// ----------------------------- Warning --------------------------------
diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
index e3824be36907..19b45e4c99a2 100644
--- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
+++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
@@ -35,14 +35,24 @@ const DigitalClockRoot = styled(PickerViewRoot, {
name: 'MuiDigitalClock',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: DigitalClockProps & { alreadyRendered: boolean } }>(({ ownerState }) => ({
+})<{ ownerState: DigitalClockProps & { alreadyRendered: boolean } }>({
overflowY: 'auto',
width: '100%',
'@media (prefers-reduced-motion: no-preference)': {
- scrollBehavior: ownerState.alreadyRendered ? 'smooth' : 'auto',
+ scrollBehavior: 'auto',
},
maxHeight: DIGITAL_CLOCK_VIEW_HEIGHT,
-}));
+ variants: [
+ {
+ props: { alreadyRendered: true },
+ style: {
+ '@media (prefers-reduced-motion: no-preference)': {
+ scrollBehavior: 'smooth',
+ },
+ },
+ },
+ ],
+});
const DigitalClockList = styled(MenuList, {
name: 'MuiDigitalClock',
diff --git a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx
index bbb4bcb1db97..daae053f66c4 100644
--- a/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx
+++ b/packages/x-date-pickers/src/MonthCalendar/PickersMonth.tsx
@@ -47,12 +47,13 @@ const PickersMonthRoot = styled('div', {
overridesResolver: (_, styles) => [styles.root],
})<{
ownerState: PickersMonthProps;
-}>(({ ownerState }) => ({
- flexBasis: ownerState.monthsPerRow === 3 ? '33.3%' : '25%',
+}>({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
-}));
+ flexBasis: '33.3%',
+ variants: [{ props: { monthsPerRow: 4 }, style: { flexBasis: '25%' } }],
+});
const PickersMonthButton = styled('button', {
name: 'MuiPickersMonth',
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
index ced944954913..cbc6a60df7a0 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
@@ -53,13 +53,13 @@ const MultiSectionDigitalClockSectionRoot = styled(MenuList, {
slot: 'Root',
overridesResolver: (_, styles) => styles.root,
})<{ ownerState: MultiSectionDigitalClockSectionProps & { alreadyRendered: boolean } }>(
- ({ theme, ownerState }) => ({
+ ({ theme }) => ({
maxHeight: DIGITAL_CLOCK_VIEW_HEIGHT,
width: 56,
padding: 0,
overflow: 'hidden',
'@media (prefers-reduced-motion: no-preference)': {
- scrollBehavior: ownerState.alreadyRendered ? 'smooth' : 'auto',
+ scrollBehavior: 'auto',
},
'@media (pointer: fine)': {
'&:hover': {
@@ -78,6 +78,16 @@ const MultiSectionDigitalClockSectionRoot = styled(MenuList, {
// subtracting the height of one item, extra margin and borders to make sure the max height is correct
height: 'calc(100% - 40px - 6px)',
},
+ variants: [
+ {
+ props: { alreadyRendered: true },
+ style: {
+ '@media (prefers-reduced-motion: no-preference)': {
+ scrollBehavior: 'smooth',
+ },
+ },
+ },
+ ],
}),
);
diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
index a18d69b4540f..e7bbfe369dc5 100644
--- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
+++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
@@ -87,14 +87,19 @@ const PickersCalendarHeaderSwitchViewButton = styled(IconButton, {
overridesResolver: (_, styles) => styles.switchViewButton,
})<{
ownerState: PickersCalendarHeaderOwnerState;
-}>(({ ownerState }) => ({
+}>({
marginRight: 'auto',
- ...(ownerState.view === 'year' && {
- [`.${pickersCalendarHeaderClasses.switchViewIcon}`]: {
- transform: 'rotate(180deg)',
+ variants: [
+ {
+ props: { view: 'year' },
+ style: {
+ [`.${pickersCalendarHeaderClasses.switchViewIcon}`]: {
+ transform: 'rotate(180deg)',
+ },
+ },
},
- }),
-}));
+ ],
+});
const PickersCalendarHeaderSwitchViewIcon = styled(ArrowDropDownIcon, {
name: 'MuiPickersCalendarHeader',
diff --git a/packages/x-date-pickers/src/PickersDay/PickersDay.tsx b/packages/x-date-pickers/src/PickersDay/PickersDay.tsx
index b0ed7b3ac0eb..a614588756fd 100644
--- a/packages/x-date-pickers/src/PickersDay/PickersDay.tsx
+++ b/packages/x-date-pickers/src/PickersDay/PickersDay.tsx
@@ -127,7 +127,7 @@ const useUtilityClasses = (ownerState: PickersDayProps) => {
return composeClasses(slots, getPickersDayUtilityClass, classes);
};
-const styleArg = ({ theme, ownerState }: { theme: Theme; ownerState: OwnerState }) => ({
+const styleArg = ({ theme }: { theme: Theme }) => ({
...theme.typography.caption,
width: DAY_SIZE,
height: DAY_SIZE,
@@ -170,19 +170,28 @@ const styleArg = ({ theme, ownerState }: { theme: Theme; ownerState: OwnerState
[`&.${pickersDayClasses.disabled}&.${pickersDayClasses.selected}`]: {
opacity: 0.6,
},
- ...(!ownerState.disableMargin && {
- margin: `0 ${DAY_MARGIN}px`,
- }),
- ...(ownerState.outsideCurrentMonth &&
- ownerState.showDaysOutsideCurrentMonth && {
- color: (theme.vars || theme).palette.text.secondary,
- }),
- ...(!ownerState.disableHighlightToday &&
- ownerState.today && {
- [`&:not(.${pickersDayClasses.selected})`]: {
- border: `1px solid ${(theme.vars || theme).palette.text.secondary}`,
+ variants: [
+ {
+ props: { disableMargin: false },
+ style: {
+ margin: `0 ${DAY_MARGIN}px`,
},
- }),
+ },
+ {
+ props: { outsideCurrentMonth: true, showDaysOutsideCurrentMonth: true },
+ style: {
+ color: (theme.vars || theme).palette.text.secondary,
+ },
+ },
+ {
+ props: { disableHighlightToday: false, today: true },
+ style: {
+ [`&:not(.${pickersDayClasses.selected})`]: {
+ border: `1px solid ${(theme.vars || theme).palette.text.secondary}`,
+ },
+ },
+ },
+ ],
});
const overridesResolver = (
@@ -213,8 +222,8 @@ const PickersDayFiller = styled('div', {
name: 'MuiPickersDay',
slot: 'Root',
overridesResolver,
-})<{ ownerState: OwnerState }>(({ theme, ownerState }) => ({
- ...styleArg({ theme, ownerState }),
+})<{ ownerState: OwnerState }>(({ theme }) => ({
+ ...styleArg({ theme }),
// visibility: 'hidden' does not work here as it hides the element from screen readers as well
opacity: 0,
pointerEvents: 'none',
diff --git a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx
index ac97bf691f5d..0937bce1cb7f 100644
--- a/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx
+++ b/packages/x-date-pickers/src/PickersLayout/PickersLayout.tsx
@@ -23,23 +23,33 @@ const PickersLayoutRoot = styled('div', {
name: 'MuiPickersLayout',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: { isLandscape: boolean } }>(({ theme, ownerState }) => ({
+})<{ ownerState: { isLandscape: boolean } }>(({ theme }) => ({
display: 'grid',
gridAutoColumns: 'max-content auto max-content',
gridAutoRows: 'max-content auto max-content',
- [`& .${pickersLayoutClasses.toolbar}`]: ownerState.isLandscape
- ? {
- gridColumn: theme.direction === 'rtl' ? 3 : 1,
- gridRow: '2 / 3',
- }
- : { gridColumn: '2 / 4', gridRow: 1 },
- [`.${pickersLayoutClasses.shortcuts}`]: ownerState.isLandscape
- ? { gridColumn: '2 / 4', gridRow: 1 }
- : {
- gridColumn: theme.direction === 'rtl' ? 3 : 1,
- gridRow: '2 / 3',
- },
[`& .${pickersLayoutClasses.actionBar}`]: { gridColumn: '1 / 4', gridRow: 3 },
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ [`& .${pickersLayoutClasses.toolbar}`]: {
+ gridColumn: theme.direction === 'rtl' ? 3 : 1,
+ gridRow: '2 / 3',
+ },
+ [`.${pickersLayoutClasses.shortcuts}`]: { gridColumn: '2 / 4', gridRow: 1 },
+ },
+ },
+ {
+ props: { isLandscape: false },
+ style: {
+ [`& .${pickersLayoutClasses.toolbar}`]: { gridColumn: '2 / 4', gridRow: 1 },
+ [`& .${pickersLayoutClasses.shortcuts}`]: {
+ gridColumn: theme.direction === 'rtl' ? 3 : 1,
+ gridRow: '2 / 3',
+ },
+ },
+ },
+ ],
}));
PickersLayoutRoot.propTypes = {
diff --git a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx
index 95d9343c5893..e86c0556e22d 100644
--- a/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx
+++ b/packages/x-date-pickers/src/PickersTextField/PickersFilledInput/PickersFilledInput.tsx
@@ -2,6 +2,7 @@ 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';
import composeClasses from '@mui/utils/composeClasses';
import {
@@ -23,7 +24,8 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, {
name: 'MuiPickersFilledInput',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: OwnerStateType }>(({ theme, ownerState }) => {
+ shouldForwardProp: (prop) => shouldForwardProp(prop) && prop !== 'disableUnderline',
+})<{ ownerState: OwnerStateType }>(({ 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)';
@@ -51,65 +53,85 @@ const PickersFilledInputRoot = styled(PickersInputBaseRoot, {
[`&.${pickersFilledInputClasses.disabled}`]: {
backgroundColor: theme.vars ? theme.vars.palette.FilledInput.disabledBg : disabledBackground,
},
- ...(!ownerState.disableUnderline && {
- '&::after': {
- borderBottom: `2px solid ${
- (theme.vars || theme).palette[ownerState.color || 'primary']?.main
- }`,
- left: 0,
- bottom: 0,
- // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
- content: '""',
- position: 'absolute',
- right: 0,
- transform: 'scaleX(0)',
- transition: theme.transitions.create('transform', {
- duration: theme.transitions.duration.shorter,
- easing: theme.transitions.easing.easeOut,
- }),
- pointerEvents: 'none', // Transparent to the hover style.
- },
- [`&.${pickersFilledInputClasses.focused}:after`]: {
- // translateX(0) is a workaround for Safari transform scale bug
- // See https://github.com/mui/material-ui/issues/31766
- transform: 'scaleX(1) translateX(0)',
- },
- [`&.${pickersFilledInputClasses.error}`]: {
- '&:before, &:after': {
- borderBottomColor: (theme.vars || theme).palette.error.main,
+ variants: [
+ ...Object.keys((theme.vars ?? theme).palette)
+ // @ts-ignore
+ .filter((key) => (theme.vars ?? theme).palette[key].main)
+ .map((color) => ({
+ props: { color, disableUnderline: false },
+ style: {
+ '&::after': {
+ // @ts-ignore
+ borderBottom: `2px solid ${(theme.vars || theme).palette[color]?.main}`,
+ },
+ },
+ })),
+ {
+ props: { disableUnderline: false },
+ style: {
+ '&::after': {
+ left: 0,
+ bottom: 0,
+ // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
+ content: '""',
+ position: 'absolute',
+ right: 0,
+ transform: 'scaleX(0)',
+ transition: theme.transitions.create('transform', {
+ duration: theme.transitions.duration.shorter,
+ easing: theme.transitions.easing.easeOut,
+ }),
+ pointerEvents: 'none', // Transparent to the hover style.
+ },
+ [`&.${pickersFilledInputClasses.focused}:after`]: {
+ // translateX(0) is a workaround for Safari transform scale bug
+ // See https://github.com/mui/material-ui/issues/31766
+ transform: 'scaleX(1) translateX(0)',
+ },
+ [`&.${pickersFilledInputClasses.error}`]: {
+ '&:before, &:after': {
+ borderBottomColor: (theme.vars || theme).palette.error.main,
+ },
+ },
+ '&::before': {
+ borderBottom: `1px solid ${
+ theme.vars
+ ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})`
+ : bottomLineColor
+ }`,
+ left: 0,
+ bottom: 0,
+ // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
+ content: '"\\00a0"',
+ position: 'absolute',
+ right: 0,
+ transition: theme.transitions.create('border-bottom-color', {
+ duration: theme.transitions.duration.shorter,
+ }),
+ pointerEvents: 'none', // Transparent to the hover style.
+ },
+ [`&:hover:not(.${pickersFilledInputClasses.disabled}, .${pickersFilledInputClasses.error}):before`]:
+ {
+ borderBottom: `1px solid ${(theme.vars || theme).palette.text.primary}`,
+ },
+ [`&.${pickersFilledInputClasses.disabled}:before`]: {
+ borderBottomStyle: 'dotted',
+ },
},
},
- '&::before': {
- borderBottom: `1px solid ${
- theme.vars
- ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})`
- : bottomLineColor
- }`,
- left: 0,
- bottom: 0,
- // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
- content: '"\\00a0"',
- position: 'absolute',
- right: 0,
- transition: theme.transitions.create('border-bottom-color', {
- duration: theme.transitions.duration.shorter,
- }),
- pointerEvents: 'none', // Transparent to the hover style.
+ {
+ props: ({ startAdornment }: OwnerStateType) => !!startAdornment,
+ style: {
+ paddingLeft: 12,
+ },
},
- [`&:hover:not(.${pickersFilledInputClasses.disabled}, .${pickersFilledInputClasses.error}):before`]:
- {
- borderBottom: `1px solid ${(theme.vars || theme).palette.text.primary}`,
+ {
+ props: ({ endAdornment }: OwnerStateType) => !!endAdornment,
+ style: {
+ paddingRight: 12,
},
- [`&.${pickersFilledInputClasses.disabled}:before`]: {
- borderBottomStyle: 'dotted',
},
- }),
- ...(ownerState.startAdornment && {
- paddingLeft: 12,
- }),
- ...(ownerState.endAdornment && {
- paddingRight: 12,
- }),
+ ],
};
});
@@ -117,31 +139,47 @@ const PickersFilledSectionsContainer = styled(PickersInputBaseSectionsContainer,
name: 'MuiPickersFilledInput',
slot: 'sectionsContainer',
overridesResolver: (props, styles) => styles.sectionsContainer,
-})<{ ownerState: OwnerStateType }>(({ ownerState }) => ({
+})<{ ownerState: OwnerStateType }>({
paddingTop: 25,
paddingRight: 12,
paddingBottom: 8,
paddingLeft: 12,
- ...(ownerState.size === 'small' && {
- paddingTop: 21,
- paddingBottom: 4,
- }),
- ...(ownerState.startAdornment && {
- paddingLeft: 0,
- }),
- ...(ownerState.endAdornment && {
- paddingRight: 0,
- }),
- ...(ownerState.hiddenLabel && {
- paddingTop: 16,
- paddingBottom: 17,
- }),
- ...(ownerState.hiddenLabel &&
- ownerState.size === 'small' && {
- paddingTop: 8,
- paddingBottom: 9,
- }),
-}));
+ variants: [
+ {
+ props: { size: 'small' },
+ style: {
+ paddingTop: 21,
+ paddingBottom: 4,
+ },
+ },
+ {
+ props: ({ startAdornment }: OwnerStateType) => !!startAdornment,
+ style: {
+ paddingLeft: 0,
+ },
+ },
+ {
+ props: ({ endAdornment }: OwnerStateType) => !!endAdornment,
+ style: {
+ paddingRight: 0,
+ },
+ },
+ {
+ props: { hiddenLabel: true },
+ style: {
+ paddingTop: 16,
+ paddingBottom: 17,
+ },
+ },
+ {
+ props: { hiddenLabel: true, size: 'small' },
+ style: {
+ paddingTop: 8,
+ paddingBottom: 9,
+ },
+ },
+ ],
+});
const useUtilityClasses = (ownerState: OwnerStateType) => {
const { classes, disableUnderline } = ownerState;
@@ -175,7 +213,13 @@ const PickersFilledInput = React.forwardRef(function PickersFilledInput(
name: 'MuiPickersFilledInput',
});
- const { label, autoFocus, ownerState: ownerStateProp, ...other } = props;
+ const {
+ label,
+ autoFocus,
+ disableUnderline = false,
+ ownerState: ownerStateProp,
+ ...other
+ } = props;
const muiFormControl = useFormControl();
@@ -190,6 +234,7 @@ const PickersFilledInput = React.forwardRef(function PickersFilledInput(
return (
styles.root,
-})<{ ownerState: OwnerStateType }>(({ theme, ownerState }) => {
+})<{ ownerState: OwnerStateType }>(({ 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) {
@@ -26,58 +26,73 @@ const PickersInputRoot = styled(PickersInputBaseRoot, {
'label + &': {
marginTop: 16,
},
- ...(!ownerState.disableUnderline && {
- '&::after': {
- background: 'red',
+ variants: [
+ ...Object.keys((theme.vars ?? theme).palette)
// @ts-ignore
- borderBottom: `2px solid ${(theme.vars || theme).palette[ownerState.color].main}`,
- left: 0,
- bottom: 0,
- // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
- content: '""',
- position: 'absolute',
- right: 0,
- transform: 'scaleX(0)',
- transition: theme.transitions.create('transform', {
- duration: theme.transitions.duration.shorter,
- easing: theme.transitions.easing.easeOut,
- }),
- pointerEvents: 'none', // Transparent to the hover style.
- },
- [`&.${pickersInputClasses.focused}:after`]: {
- // translateX(0) is a workaround for Safari transform scale bug
- // See https://github.com/mui/material-ui/issues/31766
- transform: 'scaleX(1) translateX(0)',
- },
- [`&.${pickersInputClasses.error}`]: {
- '&:before, &:after': {
- borderBottomColor: (theme.vars || theme).palette.error.main,
- },
- },
- '&::before': {
- borderBottom: `1px solid ${bottomLineColor}`,
- left: 0,
- bottom: 0,
- // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
- content: '"\\00a0"',
- position: 'absolute',
- right: 0,
- transition: theme.transitions.create('border-bottom-color', {
- duration: theme.transitions.duration.shorter,
- }),
- pointerEvents: 'none', // Transparent to the hover style.
- },
- [`&:hover:not(.${pickersInputClasses.disabled}, .${pickersInputClasses.error}):before`]: {
- borderBottom: `2px solid ${(theme.vars || theme).palette.text.primary}`,
- // Reset on touch devices, it doesn't add specificity
- '@media (hover: none)': {
- borderBottom: `1px solid ${bottomLineColor}`,
+ .filter((key) => (theme.vars ?? theme).palette[key].main)
+ .map((color) => ({
+ props: { color },
+ style: {
+ '&::after': {
+ // @ts-ignore
+ borderBottom: `2px solid ${(theme.vars || theme).palette[color].main}`,
+ },
+ },
+ })),
+ {
+ props: { disableUnderline: false },
+ style: {
+ '&::after': {
+ background: 'red',
+ left: 0,
+ bottom: 0,
+ // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
+ content: '""',
+ position: 'absolute',
+ right: 0,
+ transform: 'scaleX(0)',
+ transition: theme.transitions.create('transform', {
+ duration: theme.transitions.duration.shorter,
+ easing: theme.transitions.easing.easeOut,
+ }),
+ pointerEvents: 'none', // Transparent to the hover style.
+ },
+ [`&.${pickersInputClasses.focused}:after`]: {
+ // translateX(0) is a workaround for Safari transform scale bug
+ // See https://github.com/mui/material-ui/issues/31766
+ transform: 'scaleX(1) translateX(0)',
+ },
+ [`&.${pickersInputClasses.error}`]: {
+ '&:before, &:after': {
+ borderBottomColor: (theme.vars || theme).palette.error.main,
+ },
+ },
+ '&::before': {
+ borderBottom: `1px solid ${bottomLineColor}`,
+ left: 0,
+ bottom: 0,
+ // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
+ content: '"\\00a0"',
+ position: 'absolute',
+ right: 0,
+ transition: theme.transitions.create('border-bottom-color', {
+ duration: theme.transitions.duration.shorter,
+ }),
+ pointerEvents: 'none', // Transparent to the hover style.
+ },
+ [`&:hover:not(.${pickersInputClasses.disabled}, .${pickersInputClasses.error}):before`]: {
+ borderBottom: `2px solid ${(theme.vars || theme).palette.text.primary}`,
+ // Reset on touch devices, it doesn't add specificity
+ '@media (hover: none)': {
+ borderBottom: `1px solid ${bottomLineColor}`,
+ },
+ },
+ [`&.${pickersInputClasses.disabled}:before`]: {
+ borderBottomStyle: 'dotted',
+ },
},
},
- [`&.${pickersInputClasses.disabled}:before`]: {
- borderBottomStyle: 'dotted',
- },
- }),
+ ],
};
});
@@ -113,7 +128,13 @@ const PickersInput = React.forwardRef(function PickersInput(
name: 'MuiPickersInput',
});
- const { label, autoFocus, ownerState: ownerStateProp, ...other } = props;
+ const {
+ label,
+ autoFocus,
+ disableUnderline = false,
+ ownerState: ownerStateProp,
+ ...other
+ } = props;
const muiFormControl = useFormControl();
@@ -121,6 +142,7 @@ const PickersInput = React.forwardRef(function PickersInput(
...props,
...ownerStateProp,
...muiFormControl,
+ disableUnderline,
color: muiFormControl?.color || 'primary',
};
const classes = useUtilityClasses(ownerState);
@@ -198,6 +220,11 @@ PickersInput.propTypes = {
}),
}),
]),
+ /**
+ * The props used for each component slot.
+ * @default {}
+ */
+ slotProps: PropTypes.object,
/**
* The components used for each slot inside.
*
diff --git a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx
index 6d37ff718641..1ec0341917be 100644
--- a/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx
+++ b/packages/x-date-pickers/src/PickersTextField/PickersInputBase/PickersInputBase.tsx
@@ -6,6 +6,7 @@ import useForkRef from '@mui/utils/useForkRef';
import { refType } from '@mui/utils';
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 {
pickersInputBaseClasses,
@@ -26,7 +27,7 @@ export const PickersInputBaseRoot = styled('div', {
name: 'MuiPickersInputBase',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: OwnerStateType }>(({ theme, ownerState }) => ({
+})<{ ownerState: OwnerStateType }>(({ theme }) => ({
...theme.typography.body1,
color: (theme.vars || theme).palette.text.primary,
cursor: 'text',
@@ -37,16 +38,19 @@ export const PickersInputBaseRoot = styled('div', {
position: 'relative',
boxSizing: 'border-box', // Prevent padding issue with fullWidth.
letterSpacing: `${round(0.15 / 16)}em`,
- ...(ownerState.fullWidth && {
- width: '100%',
- }),
+ variants: [
+ {
+ props: { fullWidth: true },
+ style: { width: '100%' },
+ },
+ ],
}));
export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot, {
name: 'MuiPickersInputBase',
slot: 'SectionsContainer',
overridesResolver: (props, styles) => styles.sectionsContainer,
-})<{ ownerState: OwnerStateType }>(({ theme, ownerState }) => ({
+})<{ ownerState: OwnerStateType }>(({ theme }) => ({
padding: '4px 0 5px',
fontFamily: theme.typography.fontFamily,
fontSize: 'inherit',
@@ -59,22 +63,34 @@ export const PickersInputBaseSectionsContainer = styled(PickersSectionListRoot,
letterSpacing: 'inherit',
// Baseline behavior
width: '182px',
- ...(ownerState.size === 'small' && {
- paddingTop: 1,
- }),
...(theme.direction === 'rtl' && { textAlign: 'right /*! @noflip */' as any }),
- ...(!(ownerState.adornedStart || ownerState.focused || ownerState.filled) && {
- color: 'currentColor',
- ...(ownerState.label == null &&
- (theme.vars
+ variants: [
+ {
+ props: { size: 'small' },
+ style: {
+ paddingTop: 1,
+ },
+ },
+ {
+ props: { adornedStart: false, focused: false, filled: false },
+ style: {
+ color: 'currentColor',
+ opacity: 0,
+ },
+ },
+ {
+ // Can't use the object notation because label can be null or undefined
+ props: ({ adornedStart, focused, filled, label }: OwnerStateType) =>
+ !adornedStart && !focused && !filled && label == null,
+ style: theme.vars
? {
opacity: theme.vars.opacity.inputPlaceholder,
}
: {
opacity: theme.palette.mode === 'light' ? 0.42 : 0.5,
- })),
- ...(ownerState.label != null && { opacity: 0 }),
- }),
+ },
+ },
+ ],
}));
const PickersInputBaseSection = styled(PickersSectionListSection, {
@@ -185,6 +201,7 @@ const PickersInputBase = React.forwardRef(function PickersInputBase(
startAdornment,
renderSuffix,
slots,
+ slotProps,
contentEditable,
tabIndex,
onInput,
@@ -247,16 +264,22 @@ const PickersInputBase = React.forwardRef(function PickersInputBase(
const classes = useUtilityClasses(ownerState);
const InputRoot = slots?.root || PickersInputBaseRoot;
+ const inputRootProps = useSlotProps({
+ elementType: InputRoot,
+ externalSlotProps: slotProps?.root,
+ externalForwardedProps: other,
+ additionalProps: {
+ 'aria-invalid': muiFormControl.error,
+ ref: handleRootRef,
+ },
+ className: classes.root,
+ ownerState,
+ });
+
const InputSectionsContainer = slots?.input || PickersInputBaseSectionsContainer;
return (
-
+
{startAdornment}
({
fontSize: 'inherit',
}));
-const OutlineLegend = styled('legend')<{ ownerState: any }>(({ ownerState, theme }) => ({
+const OutlineLegend = styled('legend')<{ ownerState: any }>(({ theme }) => ({
float: 'unset', // Fix conflict with bootstrap
width: 'auto', // Fix conflict with bootstrap
overflow: 'hidden', // Fix Horizontal scroll when label too long
- ...(!ownerState.withLabel && {
- padding: 0,
- lineHeight: '11px', // sync with `height` in `legend` styles
- transition: theme.transitions.create('width', {
- duration: 150,
- easing: theme.transitions.easing.easeOut,
- }),
- }),
- ...(ownerState.withLabel && {
- display: 'block', // Fix conflict with normalize.css and sanitize.css
- padding: 0,
- height: 11, // sync with `lineHeight` in `legend` styles
- fontSize: '0.75em',
- visibility: 'hidden',
- maxWidth: 0.01,
- transition: theme.transitions.create('max-width', {
- duration: 50,
- easing: theme.transitions.easing.easeOut,
- }),
- whiteSpace: 'nowrap',
- '& > span': {
- paddingLeft: 5,
- paddingRight: 5,
- display: 'inline-block',
- opacity: 0,
- visibility: 'visible',
+ variants: [
+ {
+ props: { withLabel: false },
+ style: {
+ padding: 0,
+ lineHeight: '11px', // sync with `height` in `legend` styles
+ transition: theme.transitions.create('width', {
+ duration: 150,
+ easing: theme.transitions.easing.easeOut,
+ }),
+ },
},
- ...(ownerState.notched && {
- maxWidth: '100%',
- transition: theme.transitions.create('max-width', {
- duration: 100,
- easing: theme.transitions.easing.easeOut,
- delay: 50,
- }),
- }),
- }),
+ {
+ props: { withLabel: true },
+ style: {
+ display: 'block', // Fix conflict with normalize.css and sanitize.css
+ padding: 0,
+ height: 11, // sync with `lineHeight` in `legend` styles
+ fontSize: '0.75em',
+ visibility: 'hidden',
+ maxWidth: 0.01,
+ transition: theme.transitions.create('max-width', {
+ duration: 50,
+ easing: theme.transitions.easing.easeOut,
+ }),
+ whiteSpace: 'nowrap',
+ '& > span': {
+ paddingLeft: 5,
+ paddingRight: 5,
+ display: 'inline-block',
+ opacity: 0,
+ visibility: 'visible',
+ },
+ },
+ },
+ {
+ props: { withLabel: true, notched: true },
+ style: {
+ maxWidth: '100%',
+ transition: theme.transitions.create('max-width', {
+ duration: 100,
+ easing: theme.transitions.easing.easeOut,
+ delay: 50,
+ }),
+ },
+ },
+ ],
}));
/**
diff --git a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx
index 2cca79b9691a..2dbcec6510a9 100644
--- a/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx
+++ b/packages/x-date-pickers/src/PickersTextField/PickersOutlinedInput/PickersOutlinedInput.tsx
@@ -23,7 +23,7 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, {
name: 'MuiPickersOutlinedInput',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
-})<{ ownerState: OwnerStateType }>(({ theme, ownerState }) => {
+})<{ ownerState: OwnerStateType }>(({ theme }) => {
const borderColor =
theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
return {
@@ -42,8 +42,6 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, {
},
[`&.${pickersOutlinedInputClasses.focused} .${pickersOutlinedInputClasses.notchedOutline}`]: {
borderStyle: 'solid',
- // @ts-ignore
- borderColor: (theme.vars || theme).palette[ownerState.color].main,
borderWidth: 2,
},
[`&.${pickersOutlinedInputClasses.disabled}`]: {
@@ -57,6 +55,19 @@ const PickersOutlinedInputRoot = styled(PickersInputBaseRoot, {
[`&.${pickersOutlinedInputClasses.error} .${pickersOutlinedInputClasses.notchedOutline}`]: {
borderColor: (theme.vars || theme).palette.error.main,
},
+ variants: Object.keys((theme.vars ?? theme).palette)
+ // @ts-ignore
+ .filter((key) => (theme.vars ?? theme).palette[key].main)
+ .map((color) => ({
+ props: { color },
+ style: {
+ [`&.${pickersOutlinedInputClasses.focused}:not(.${pickersOutlinedInputClasses.error}) .${pickersOutlinedInputClasses.notchedOutline}`]:
+ {
+ // @ts-ignore
+ borderColor: (theme.vars || theme).palette[color].main,
+ },
+ },
+ })),
};
});
@@ -64,12 +75,17 @@ const PickersOutlinedInputSectionsContainer = styled(PickersInputBaseSectionsCon
name: 'MuiPickersOutlinedInput',
slot: 'SectionsContainer',
overridesResolver: (props, styles) => styles.sectionsContainer,
-})<{ ownerState: OwnerStateType }>(({ ownerState }) => ({
+})<{ ownerState: OwnerStateType }>({
padding: '16.5px 0',
- ...(ownerState.size === 'small' && {
- padding: '8.5px 0',
- }),
-}));
+ variants: [
+ {
+ props: { size: 'small' },
+ style: {
+ padding: '8.5px 0',
+ },
+ },
+ ],
+});
const useUtilityClasses = (ownerState: OwnerStateType) => {
const { classes } = ownerState;
@@ -207,6 +223,11 @@ PickersOutlinedInput.propTypes = {
}),
}),
]),
+ /**
+ * The props used for each component slot.
+ * @default {}
+ */
+ slotProps: PropTypes.object,
/**
* The components used for each slot inside.
*
diff --git a/packages/x-date-pickers/src/TimeClock/Clock.tsx b/packages/x-date-pickers/src/TimeClock/Clock.tsx
index 8b1562440561..23a583f9dd71 100644
--- a/packages/x-date-pickers/src/TimeClock/Clock.tsx
+++ b/packages/x-date-pickers/src/TimeClock/Clock.tsx
@@ -104,7 +104,7 @@ const ClockSquareMask = styled('div', {
name: 'MuiClock',
slot: 'SquareMask',
overridesResolver: (_, styles) => styles.squareMask,
-})<{ ownerState: ClockSquareMaskOwnerState }>(({ ownerState }) => ({
+})<{ ownerState: ClockSquareMaskOwnerState }>({
width: '100%',
height: '100%',
position: 'absolute',
@@ -113,9 +113,10 @@ const ClockSquareMask = styled('div', {
// Disable scroll capabilities.
touchAction: 'none',
userSelect: 'none',
- ...(ownerState.disabled
- ? {}
- : {
+ variants: [
+ {
+ props: { disabled: false },
+ style: {
'@media (pointer: fine)': {
cursor: 'pointer',
borderRadius: '50%',
@@ -123,8 +124,10 @@ const ClockSquareMask = styled('div', {
'&:active': {
cursor: 'move',
},
- }),
-}));
+ },
+ },
+ ],
+});
const ClockPin = styled('div', {
name: 'MuiClock',
@@ -145,7 +148,7 @@ const ClockAmButton = styled(IconButton, {
name: 'MuiClock',
slot: 'AmButton',
overridesResolver: (_, styles) => styles.amButton,
-})<{ ownerState: ClockProps }>(({ theme, ownerState }) => ({
+})<{ ownerState: ClockProps }>(({ theme }) => ({
zIndex: 1,
position: 'absolute',
bottom: 8,
@@ -153,20 +156,25 @@ const ClockAmButton = styled(IconButton, {
paddingLeft: 4,
paddingRight: 4,
width: CLOCK_HOUR_WIDTH,
- ...(ownerState.meridiemMode === 'am' && {
- backgroundColor: (theme.vars || theme).palette.primary.main,
- color: (theme.vars || theme).palette.primary.contrastText,
- '&:hover': {
- backgroundColor: (theme.vars || theme).palette.primary.light,
+ variants: [
+ {
+ props: { meridiemMode: 'am' },
+ style: {
+ backgroundColor: (theme.vars || theme).palette.primary.main,
+ color: (theme.vars || theme).palette.primary.contrastText,
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.primary.light,
+ },
+ },
},
- }),
+ ],
}));
const ClockPmButton = styled(IconButton, {
name: 'MuiClock',
slot: 'PmButton',
overridesResolver: (_, styles) => styles.pmButton,
-})<{ ownerState: ClockProps }>(({ theme, ownerState }) => ({
+})<{ ownerState: ClockProps }>(({ theme }) => ({
zIndex: 1,
position: 'absolute',
bottom: 8,
@@ -174,13 +182,18 @@ const ClockPmButton = styled(IconButton, {
paddingLeft: 4,
paddingRight: 4,
width: CLOCK_HOUR_WIDTH,
- ...(ownerState.meridiemMode === 'pm' && {
- backgroundColor: (theme.vars || theme).palette.primary.main,
- color: (theme.vars || theme).palette.primary.contrastText,
- '&:hover': {
- backgroundColor: (theme.vars || theme).palette.primary.light,
+ variants: [
+ {
+ props: { meridiemMode: 'pm' },
+ style: {
+ backgroundColor: (theme.vars || theme).palette.primary.main,
+ color: (theme.vars || theme).palette.primary.contrastText,
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.primary.light,
+ },
+ },
},
- }),
+ ],
}));
const ClockMeridiemText = styled(Typography, {
@@ -212,7 +225,7 @@ export function Clock(inProps: ClockProps)
selectedId,
type,
viewValue,
- disabled,
+ disabled = false,
readOnly,
className,
} = props;
diff --git a/packages/x-date-pickers/src/TimeClock/ClockNumber.tsx b/packages/x-date-pickers/src/TimeClock/ClockNumber.tsx
index 90b48c09b5ba..bab778903644 100644
--- a/packages/x-date-pickers/src/TimeClock/ClockNumber.tsx
+++ b/packages/x-date-pickers/src/TimeClock/ClockNumber.tsx
@@ -40,7 +40,7 @@ const ClockNumberRoot = styled('span', {
{ [`&.${clockNumberClasses.disabled}`]: styles.disabled },
{ [`&.${clockNumberClasses.selected}`]: styles.selected },
],
-})<{ ownerState: ClockNumberProps }>(({ theme, ownerState }) => ({
+})<{ ownerState: ClockNumberProps }>(({ theme }) => ({
height: CLOCK_HOUR_WIDTH,
width: CLOCK_HOUR_WIDTH,
position: 'absolute',
@@ -61,10 +61,15 @@ const ClockNumberRoot = styled('span', {
pointerEvents: 'none',
color: (theme.vars || theme).palette.text.disabled,
},
- ...(ownerState.inner && {
- ...theme.typography.body2,
- color: (theme.vars || theme).palette.text.secondary,
- }),
+ variants: [
+ {
+ props: { inner: true },
+ style: {
+ ...theme.typography.body2,
+ color: (theme.vars || theme).palette.text.secondary,
+ },
+ },
+ ],
}));
/**
diff --git a/packages/x-date-pickers/src/TimeClock/ClockPointer.tsx b/packages/x-date-pickers/src/TimeClock/ClockPointer.tsx
index a77c40b32736..735b228846ec 100644
--- a/packages/x-date-pickers/src/TimeClock/ClockPointer.tsx
+++ b/packages/x-date-pickers/src/TimeClock/ClockPointer.tsx
@@ -34,16 +34,21 @@ const ClockPointerRoot = styled('div', {
overridesResolver: (_, styles) => styles.root,
})<{
ownerState: ClockPointerProps & ClockPointerState;
-}>(({ theme, ownerState }) => ({
+}>(({ theme }) => ({
width: 2,
backgroundColor: (theme.vars || theme).palette.primary.main,
position: 'absolute',
left: 'calc(50% - 1px)',
bottom: '50%',
transformOrigin: 'center bottom 0px',
- ...(ownerState.shouldAnimate && {
- transition: theme.transitions.create(['transform', 'height']),
- }),
+ variants: [
+ {
+ props: { shouldAnimate: true },
+ style: {
+ transition: theme.transitions.create(['transform', 'height']),
+ },
+ },
+ ],
}));
const ClockPointerThumb = styled('div', {
@@ -52,7 +57,7 @@ const ClockPointerThumb = styled('div', {
overridesResolver: (_, styles) => styles.thumb,
})<{
ownerState: ClockPointerProps & ClockPointerState;
-}>(({ theme, ownerState }) => ({
+}>(({ theme }) => ({
width: 4,
height: 4,
backgroundColor: (theme.vars || theme).palette.primary.contrastText,
@@ -62,9 +67,14 @@ const ClockPointerThumb = styled('div', {
left: `calc(50% - ${CLOCK_HOUR_WIDTH / 2}px)`,
border: `${(CLOCK_HOUR_WIDTH - 4) / 2}px solid ${(theme.vars || theme).palette.primary.main}`,
boxSizing: 'content-box',
- ...(ownerState.hasSelected && {
- backgroundColor: (theme.vars || theme).palette.primary.main,
- }),
+ variants: [
+ {
+ props: { hasSelected: true },
+ style: {
+ backgroundColor: (theme.vars || theme).palette.primary.main,
+ },
+ },
+ ],
}));
/**
diff --git a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx
index ba4fd2c6e61f..ff2bf30ac5fd 100644
--- a/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx
+++ b/packages/x-date-pickers/src/TimePicker/TimePickerToolbar.tsx
@@ -81,16 +81,21 @@ const TimePickerToolbarHourMinuteLabel = styled('div', {
],
})<{
ownerState: TimePickerToolbarProps;
-}>(({ theme, ownerState }) => ({
+}>(({ theme }) => ({
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'flex-end',
- ...(ownerState.isLandscape && {
- marginTop: 'auto',
- }),
...(theme.direction === 'rtl' && {
flexDirection: 'row-reverse',
}),
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ marginTop: 'auto',
+ },
+ },
+ ],
}));
TimePickerToolbarHourMinuteLabel.propTypes = {
@@ -117,21 +122,26 @@ const TimePickerToolbarAmPmSelection = styled('div', {
],
})<{
ownerState: TimePickerToolbarProps;
-}>(({ ownerState }) => ({
+}>({
display: 'flex',
flexDirection: 'column',
marginRight: 'auto',
marginLeft: 12,
- ...(ownerState.isLandscape && {
- margin: '4px 0 auto',
- flexDirection: 'row',
- justifyContent: 'space-around',
- flexBasis: '100%',
- }),
[`& .${timePickerToolbarClasses.ampmLabel}`]: {
fontSize: 17,
},
-}));
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ margin: '4px 0 auto',
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ flexBasis: '100%',
+ },
+ },
+ ],
+});
TimePickerToolbarAmPmSelection.propTypes = {
// ----------------------------- Warning --------------------------------
diff --git a/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx b/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx
index 8dce10be09ff..cc8248d37797 100644
--- a/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx
+++ b/packages/x-date-pickers/src/YearCalendar/PickersYear.tsx
@@ -43,12 +43,13 @@ const PickersYearRoot = styled('div', {
name: 'MuiPickersYear',
slot: 'Root',
overridesResolver: (_, styles) => [styles.root],
-})<{ ownerState: PickersYearProps }>(({ ownerState }) => ({
- flexBasis: ownerState.yearsPerRow === 3 ? '33.3%' : '25%',
+})<{ ownerState: PickersYearProps }>({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
-}));
+ flexBasis: '33.3%',
+ variants: [{ props: { yearsPerRow: 4 }, style: { flexBasis: '25%' } }],
+});
const PickersYearButton = styled('button', {
name: 'MuiPickersYear',
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 926e68a1c033..6ade141f2f38 100644
--- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx
@@ -38,11 +38,14 @@ const PickersArrowSwitcherButton = styled(IconButton, {
overridesResolver: (props, styles) => styles.button,
})<{
ownerState: PickersArrowSwitcherProps;
-}>(({ ownerState }) => ({
- ...(ownerState.hidden && {
- visibility: 'hidden',
- }),
-}));
+}>({
+ variants: [
+ {
+ props: { hidden: true },
+ style: { visibility: 'hidden' },
+ },
+ ],
+});
const useUtilityClasses = (ownerState: PickersArrowSwitcherOwnerState) => {
const { classes } = ownerState;
diff --git a/packages/x-date-pickers/src/internals/components/PickersPopper.tsx b/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
index 5e472471459b..6ad3bdedcdfb 100644
--- a/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
@@ -112,13 +112,19 @@ const PickersPopperPaper = styled(MuiPaper, {
overridesResolver: (_, styles) => styles.paper,
})<{
ownerState: PickersPopperOwnerState;
-}>(({ ownerState }) => ({
+}>({
outline: 0,
transformOrigin: 'top center',
- ...(ownerState.placement.includes('top') && {
- transformOrigin: 'bottom center',
- }),
-}));
+ variants: [
+ {
+ props: ({ placement }: PickersPopperOwnerState) =>
+ ['top', 'top-start', 'top-end'].includes(placement),
+ style: {
+ transformOrigin: 'bottom center',
+ },
+ },
+ ],
+});
function clickedRootScrollbar(event: MouseEvent, doc: Document) {
return (
diff --git a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx
index 97b41ca9b0f4..780756015029 100644
--- a/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersToolbar.tsx
@@ -32,19 +32,24 @@ const PickersToolbarRoot = styled('div', {
overridesResolver: (props, styles) => styles.root,
})<{
ownerState: PickersToolbarProps;
-}>(({ theme, ownerState }) => ({
+}>(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'space-between',
padding: theme.spacing(2, 3),
- ...(ownerState.isLandscape && {
- height: 'auto',
- maxWidth: 160,
- padding: 16,
- justifyContent: 'flex-start',
- flexWrap: 'wrap',
- }),
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ height: 'auto',
+ maxWidth: 160,
+ padding: 16,
+ justifyContent: 'flex-start',
+ flexWrap: 'wrap',
+ },
+ },
+ ],
}));
const PickersToolbarContent = styled('div', {
@@ -53,15 +58,31 @@ const PickersToolbarContent = styled('div', {
overridesResolver: (props, styles) => styles.content,
})<{
ownerState: PickersToolbarProps;
-}>(({ ownerState }) => ({
+}>({
display: 'flex',
flexWrap: 'wrap',
width: '100%',
- justifyContent: ownerState.isLandscape ? 'flex-start' : 'space-between',
- flexDirection: ownerState.isLandscape ? ownerState.landscapeDirection ?? 'column' : 'row',
flex: 1,
- alignItems: ownerState.isLandscape ? 'flex-start' : 'center',
-}));
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ flexDirection: 'row',
+ variants: [
+ {
+ props: { isLandscape: true },
+ style: {
+ justifyContent: 'flex-start',
+ alignItems: 'flex-start',
+ flexDirection: 'column',
+ },
+ },
+ {
+ props: { isLandscape: true, landscapeDirection: 'row' },
+ style: {
+ flexDirection: 'row',
+ },
+ },
+ ],
+});
type PickersToolbarComponent = ((
props: React.PropsWithChildren> &