diff --git a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
index b3f59b8078769..41042aaf6049f 100644
--- a/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
+++ b/packages/x-date-pickers/src/DateCalendar/tests/DateCalendar.test.tsx
@@ -183,14 +183,17 @@ describe('', () => {
render(
,
);
+ // should make the reference day firstly focusable
+ expect(screen.getByRole('gridcell', { name: '17' })).to.have.attribute('tabindex', '0');
+
userEvent.mousePress(screen.getByRole('gridcell', { name: '2' }));
expect(onChange.callCount).to.equal(1);
- expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2018, 0, 2, 12, 30));
+ expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2022, 3, 2, 12, 30));
});
it('should not use `referenceDate` when a value is defined', () => {
diff --git a/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx b/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx
index 1754dc47f8ac6..440fa628f4dd6 100644
--- a/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx
+++ b/packages/x-date-pickers/src/DateCalendar/useCalendarState.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import useEventCallback from '@mui/utils/useEventCallback';
import { SlideDirection } from './PickersSlideTransition';
import { useIsDateDisabled } from './useIsDateDisabled';
-import { useUtils, useNow } from '../internals/hooks/useUtils';
+import { useUtils } from '../internals/hooks/useUtils';
import { MuiPickersAdapter, PickersTimezone } from '../models';
import { DateCalendarDefaultizedProps } from './DateCalendar.types';
import { singleItemValueManager } from '../internals/utils/valueManagers';
@@ -127,7 +127,6 @@ export const useCalendarState = (params: UseCalendarState
timezone,
} = params;
- const now = useNow(timezone);
const utils = useUtils();
const reducerFn = React.useRef(
@@ -162,7 +161,7 @@ export const useCalendarState = (params: UseCalendarState
const [calendarState, dispatch] = React.useReducer(reducerFn, {
isMonthSwitchingAnimating: false,
- focusedDay: value || now,
+ focusedDay: referenceDate,
currentMonth: utils.startOfMonth(referenceDate),
slideDirection: 'left',
});
diff --git a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx
index 7ed56f2cf6156..7259992a7c8dd 100644
--- a/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx
+++ b/packages/x-date-pickers/src/DesktopTimePicker/tests/describes.DesktopTimePicker.test.tsx
@@ -10,6 +10,7 @@ import {
describeValidation,
describeValue,
describePicker,
+ formatFullTimeValue,
} from 'test/utils/pickers';
import { DesktopTimePicker } from '@mui/x-date-pickers/DesktopTimePicker';
@@ -68,9 +69,7 @@ describe(' - Describes', () => {
}
expectInputValue(
input,
- expectedValue
- ? adapterToUse.format(expectedValue, hasMeridiem ? 'fullTime12h' : 'fullTime24h')
- : '',
+ expectedValue ? formatFullTimeValue(adapterToUse, expectedValue) : '',
);
},
setNewValue: (value, { isOpened, applySameValue, selectSection }) => {
diff --git a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
index 67dda956330bb..720f52747c141 100644
--- a/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
+++ b/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx
@@ -202,14 +202,17 @@ export const DigitalClock = React.forwardRef(function DigitalClock(
- '[role="listbox"] [role="option"][aria-selected="true"]',
+ const activeItem = containerRef.current.querySelector(
+ '[role="listbox"] [role="option"][tabindex="0"], [role="listbox"] [role="option"][aria-selected="true"]',
);
- if (!selectedItem) {
+ if (!activeItem) {
return;
}
- const offsetTop = selectedItem.offsetTop;
+ const offsetTop = activeItem.offsetTop;
+ if (autoFocus || !!focusedView) {
+ activeItem.focus();
+ }
// Subtracting the 4px of extra margin intended for the first visible section item
containerRef.current.scrollTop = offsetTop - 4;
@@ -281,6 +284,10 @@ export const DigitalClock = React.forwardRef(function DigitalClock
+ utils.isEqual(option, valueOrReferenceDate),
+ );
+
return (
- {timeOptions.map((option) => {
+ {timeOptions.map((option, index) => {
if (skipDisabled && isTimeDisabled(option)) {
return null;
}
const isSelected = utils.isEqual(option, value);
+ const tabIndex =
+ focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0) ? 0 : -1;
return (
{utils.format(option, ampm ? 'fullTime12h' : 'fullTime24h')}
diff --git a/packages/x-date-pickers/src/DigitalClock/tests/DigitalClock.test.tsx b/packages/x-date-pickers/src/DigitalClock/tests/DigitalClock.test.tsx
index 0df3c3fee7472..6002e825f08ef 100644
--- a/packages/x-date-pickers/src/DigitalClock/tests/DigitalClock.test.tsx
+++ b/packages/x-date-pickers/src/DigitalClock/tests/DigitalClock.test.tsx
@@ -2,7 +2,13 @@ import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { DigitalClock } from '@mui/x-date-pickers/DigitalClock';
-import { adapterToUse, createPickerRenderer, digitalClockHandler } from 'test/utils/pickers';
+import {
+ adapterToUse,
+ createPickerRenderer,
+ digitalClockHandler,
+ formatFullTimeValue,
+} from 'test/utils/pickers';
+import { screen } from '@mui-internal/test-utils';
describe('', () => {
const { render } = createPickerRenderer();
@@ -10,13 +16,22 @@ describe('', () => {
describe('Reference date', () => {
it('should use `referenceDate` when no value defined', () => {
const onChange = spy();
+ const referenceDate = new Date(2018, 0, 1, 12, 30);
- render(
- ,
- );
+ render();
+
+ // the first item should not be initially focusable when `referenceDate` is defined
+ expect(
+ screen.getByRole('option', {
+ name: formatFullTimeValue(adapterToUse, new Date(2018, 0, 1, 0, 0, 0)),
+ }),
+ ).to.have.attribute('tabindex', '-1');
+ // check that the relevant time based on the `referenceDate` is focusable
+ expect(
+ screen.getByRole('option', {
+ name: formatFullTimeValue(adapterToUse, referenceDate),
+ }),
+ ).to.have.attribute('tabindex', '0');
digitalClockHandler.setViewValue(
adapterToUse,
@@ -26,6 +41,18 @@ describe('', () => {
expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2018, 0, 1, 15, 30));
});
+ it('should fallback to making the first entry focusable when `referenceDate` does not map to any option', () => {
+ const referenceDate = new Date(2018, 0, 1, 12, 33);
+
+ render();
+
+ expect(
+ screen.getByRole('option', {
+ name: formatFullTimeValue(adapterToUse, new Date(2018, 0, 1, 0, 0, 0)),
+ }),
+ ).to.have.attribute('tabindex', '0');
+ });
+
it('should not use `referenceDate` when a value is defined', () => {
const onChange = spy();
diff --git a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx
index 32ef3633fe3b4..45050c55ae149 100644
--- a/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx
+++ b/packages/x-date-pickers/src/DigitalClock/tests/describes.DigitalClock.test.tsx
@@ -8,6 +8,7 @@ import {
digitalClockHandler,
describeValidation,
describeValue,
+ formatFullTimeValue,
} from 'test/utils/pickers';
import { DigitalClock } from '@mui/x-date-pickers/DigitalClock';
@@ -56,14 +57,11 @@ describe(' - Describes', () => {
emptyValue: null,
clock,
assertRenderedValue: (expectedValue: any) => {
- const hasMeridiem = adapterToUse.is12HourCycleInCurrentLocale();
const selectedItem = screen.queryByRole('option', { selected: true });
if (!expectedValue) {
expect(selectedItem).to.equal(null);
} else {
- expect(selectedItem).to.have.text(
- adapterToUse.format(expectedValue, hasMeridiem ? 'fullTime12h' : 'fullTime24h'),
- );
+ expect(selectedItem).to.have.text(formatFullTimeValue(adapterToUse, expectedValue));
}
},
setNewValue: (value) => {
diff --git a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx
index 4ea3654013c26..7d06143444916 100644
--- a/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx
+++ b/packages/x-date-pickers/src/MobileTimePicker/tests/describes.MobileTimePicker.test.tsx
@@ -17,6 +17,7 @@ import {
describeValidation,
describeValue,
describePicker,
+ formatFullTimeValue,
} from 'test/utils/pickers';
import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker';
@@ -73,7 +74,7 @@ describe(' - Describes', () => {
expectInputPlaceholder(input, hasMeridiem ? 'hh:mm aa' : 'hh:mm');
}
const expectedValueStr = expectedValue
- ? adapterToUse.format(expectedValue, hasMeridiem ? 'fullTime12h' : 'fullTime24h')
+ ? formatFullTimeValue(adapterToUse, expectedValue)
: '';
expectInputValue(input, expectedValueStr);
diff --git a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx
index a884d19452aa7..2ee5130f4226b 100644
--- a/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx
+++ b/packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx
@@ -144,13 +144,11 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar(
return utils.getMonth(value);
}
- if (disableHighlightToday) {
- return null;
- }
-
- return utils.getMonth(referenceDate);
- }, [value, utils, disableHighlightToday, referenceDate]);
- const [focusedMonth, setFocusedMonth] = React.useState(() => selectedMonth || todayMonth);
+ return null;
+ }, [value, utils]);
+ const [focusedMonth, setFocusedMonth] = React.useState(
+ () => selectedMonth || utils.getMonth(referenceDate),
+ );
const [internalHasFocus, setInternalHasFocus] = useControlled({
name: 'MonthCalendar',
diff --git a/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx b/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
index 398e6c51f78b2..4bcf96e6fbe47 100644
--- a/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
+++ b/packages/x-date-pickers/src/MonthCalendar/tests/MonthCalendar.test.tsx
@@ -169,5 +169,11 @@ describe('', () => {
expect(january).not.to.have.attribute('disabled');
expect(february).to.have.attribute('disabled');
});
+
+ it('should not mark the `referenceDate` month as selected', () => {
+ render();
+
+ expect(screen.getByRole('radio', { name: 'February', checked: false })).to.not.equal(null);
+ });
});
});
diff --git a/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx b/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx
index 89ddd554b862e..8cd311f7422b9 100644
--- a/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx
+++ b/packages/x-date-pickers/src/MonthCalendar/tests/describes.MonthCalendar.test.tsx
@@ -8,11 +8,7 @@ import {
describeValidation,
describeValue,
} from 'test/utils/pickers';
-import {
- MonthCalendar,
- monthCalendarClasses as classes,
- pickersMonthClasses,
-} from '@mui/x-date-pickers/MonthCalendar';
+import { MonthCalendar, monthCalendarClasses as classes } from '@mui/x-date-pickers/MonthCalendar';
describe(' - Describes', () => {
const { render, clock } = createPickerRenderer({ clock: 'fake' });
@@ -42,17 +38,19 @@ describe(' - Describes', () => {
emptyValue: null,
clock,
assertRenderedValue: (expectedValue: any) => {
- const selectedCells = document.querySelectorAll(`.${pickersMonthClasses.selected}`);
+ const activeMonth = screen
+ .queryAllByRole('radio')
+ .find((cell) => cell.getAttribute('tabindex') === '0');
+ expect(activeMonth).not.to.equal(null);
if (expectedValue == null) {
- expect(selectedCells).to.have.length(1);
- expect(selectedCells[0]).to.have.text(
+ expect(activeMonth).to.have.text(
adapterToUse.format(adapterToUse.date(), 'monthShort').toString(),
);
} else {
- expect(selectedCells).to.have.length(1);
- expect(selectedCells[0]).to.have.text(
+ expect(activeMonth).to.have.text(
adapterToUse.format(expectedValue, 'monthShort').toString(),
);
+ expect(activeMonth).to.have.attribute('aria-checked', 'true');
}
},
setNewValue: (value) => {
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx
index 30f2d2a3a190f..9f083eac67783 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx
@@ -302,6 +302,7 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi
isDisabled: (hours) => disabled || isTimeDisabled(hours, 'hours'),
timeStep: timeSteps.hours,
resolveAriaLabel: localeText.hoursClockNumberText,
+ valueOrReferenceDate,
}),
};
}
@@ -348,12 +349,14 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi
value: 'am',
label: amLabel,
isSelected: () => !!value && meridiemMode === 'am',
+ isFocused: () => !!valueOrReferenceDate && meridiemMode === 'am',
ariaLabel: amLabel,
},
{
value: 'pm',
label: pmLabel,
isSelected: () => !!value && meridiemMode === 'pm',
+ isFocused: () => !!valueOrReferenceDate && meridiemMode === 'pm',
ariaLabel: pmLabel,
},
],
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts
index 6c378405a841a..ac0b3e6aa4f2b 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.types.ts
@@ -12,6 +12,7 @@ import { TimeViewWithMeridiem } from '../internals/models';
export interface MultiSectionDigitalClockOption {
isDisabled?: (value: TValue) => boolean;
isSelected: (value: TValue) => boolean;
+ isFocused: (value: TValue) => boolean;
label: string;
value: TValue;
ariaLabel: string;
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts
index da44fac419543..25ed52dfd2046 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.utils.ts
@@ -9,6 +9,7 @@ interface IGetHoursSectionOptions {
isDisabled: (value: number) => boolean;
timeStep: number;
resolveAriaLabel: (value: string) => string;
+ valueOrReferenceDate: TDate;
}
export const getHourSectionOptions = ({
@@ -19,25 +20,31 @@ export const getHourSectionOptions = ({
isDisabled,
resolveAriaLabel,
timeStep,
+ valueOrReferenceDate,
}: IGetHoursSectionOptions): MultiSectionDigitalClockOption[] => {
const currentHours = value ? utils.getHours(value) : null;
const result: MultiSectionDigitalClockOption[] = [];
- const isSelected = (hour: number) => {
- if (currentHours === null) {
+ const isSelected = (hour: number, overriddenCurrentHours?: number) => {
+ const resolvedCurrentHours = overriddenCurrentHours ?? currentHours;
+ if (resolvedCurrentHours === null) {
return false;
}
if (ampm) {
if (hour === 12) {
- return currentHours === 12 || currentHours === 0;
+ return resolvedCurrentHours === 12 || resolvedCurrentHours === 0;
}
- return currentHours === hour || currentHours - 12 === hour;
+ return resolvedCurrentHours === hour || resolvedCurrentHours - 12 === hour;
}
- return currentHours === hour;
+ return resolvedCurrentHours === hour;
+ };
+
+ const isFocused = (hour: number) => {
+ return isSelected(hour, utils.getHours(valueOrReferenceDate));
};
const endHour = ampm ? 11 : 23;
@@ -52,6 +59,7 @@ export const getHourSectionOptions = ({
label,
isSelected,
isDisabled,
+ isFocused,
ariaLabel,
});
}
@@ -83,6 +91,10 @@ export const getTimeSectionOptions = ({
return hasValue && value === timeValue;
};
+ const isFocused = (timeValue: number) => {
+ return value === timeValue;
+ };
+
return [
...Array.from({ length: Math.ceil(60 / timeStep) }, (_, index) => {
const timeValue = timeStep * index;
@@ -91,6 +103,7 @@ export const getTimeSectionOptions = ({
label: resolveLabel(timeValue),
isDisabled,
isSelected,
+ isFocused,
ariaLabel: resolveAriaLabel(timeValue.toString()),
};
}),
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
index a81d4bd167faf..becbdcf81de64 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClockSection.tsx
@@ -121,7 +121,7 @@ export const MultiSectionDigitalClockSection = React.forwardRef(
) {
const containerRef = React.useRef(null);
const handleRef = useForkRef(ref, containerRef);
- const previousSelected = React.useRef(null);
+ const previousActive = React.useRef(null);
const props = useThemeProps({
props: inProps,
@@ -154,26 +154,28 @@ export const MultiSectionDigitalClockSection = React.forwardRef(
if (containerRef.current === null) {
return;
}
- const selectedItem = containerRef.current.querySelector(
- '[role="option"][aria-selected="true"]',
+ const activeItem = containerRef.current.querySelector(
+ '[role="option"][tabindex="0"], [role="option"][aria-selected="true"]',
);
- if (!selectedItem || previousSelected.current === selectedItem) {
+ if (!activeItem || previousActive.current === activeItem) {
// Handle setting the ref to null if the selected item is ever reset via UI
- if (previousSelected.current !== selectedItem) {
- previousSelected.current = selectedItem;
+ if (previousActive.current !== activeItem) {
+ previousActive.current = activeItem;
}
return;
}
- previousSelected.current = selectedItem;
+ previousActive.current = activeItem;
if (active && autoFocus) {
- selectedItem.focus();
+ activeItem.focus();
}
- const offsetTop = selectedItem.offsetTop;
+ const offsetTop = activeItem.offsetTop;
// Subtracting the 4px of extra margin intended for the first visible section item
containerRef.current.scrollTop = offsetTop - 4;
});
+ const focusedOptionIndex = items.findIndex((item) => item.isFocused(item.value));
+
return (
- {items.map((option) => {
+ {items.map((option, index) => {
if (skipDisabled && option.isDisabled?.(option.value)) {
return null;
}
const isSelected = option.isSelected(option.value);
+ const tabIndex =
+ focusedOptionIndex === index || (focusedOptionIndex === -1 && index === 0) ? 0 : -1;
return (
{option.label}
diff --git a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/MultiSectionDigitalClock.test.tsx b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/MultiSectionDigitalClock.test.tsx
index ec9da34386c2a..1b5fea603f38d 100644
--- a/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/MultiSectionDigitalClock.test.tsx
+++ b/packages/x-date-pickers/src/MultiSectionDigitalClock/tests/MultiSectionDigitalClock.test.tsx
@@ -10,6 +10,7 @@ import {
adapterToUse,
multiSectionDigitalClockHandler,
} from 'test/utils/pickers';
+import { screen } from '@mui-internal/test-utils';
describe('', () => {
const { render } = createPickerRenderer();
@@ -17,14 +18,24 @@ describe('', () => {
describe('Reference date', () => {
it('should use `referenceDate` when no value defined', () => {
const onChange = spy();
+ const referenceDate = new Date(2018, 0, 1, 13, 30);
render(
,
);
+ // the first section items should not be initially focusable when `referenceDate` is defined
+ expect(screen.getByRole('option', { name: '12 hours' })).to.have.attribute('tabindex', '-1');
+ expect(screen.getByRole('option', { name: '0 minutes' })).to.have.attribute('tabindex', '-1');
+ expect(screen.getByRole('option', { name: 'AM' })).to.have.attribute('tabindex', '-1');
+ // check that the relevant time based on the `referenceDate` is focusable
+ expect(screen.getByRole('option', { name: '1 hours' })).to.have.attribute('tabindex', '0');
+ expect(screen.getByRole('option', { name: '30 minutes' })).to.have.attribute('tabindex', '0');
+ expect(screen.getByRole('option', { name: 'PM' })).to.have.attribute('tabindex', '0');
+
multiSectionDigitalClockHandler.setViewValue(
adapterToUse,
adapterToUse.setMinutes(adapterToUse.setHours(adapterToUse.date(), 15), 30),
@@ -33,6 +44,14 @@ describe('', () => {
expect(onChange.lastCall.firstArg).toEqualDateTime(new Date(2018, 0, 1, 15, 30));
});
+ it('should fallback to making the first entry focusable when `referenceDate` does not map to an option', () => {
+ const referenceDate = new Date(2018, 0, 1, 13, 33);
+
+ render();
+
+ expect(screen.getByRole('option', { name: '0 minutes' })).to.have.attribute('tabindex', '0');
+ });
+
it('should not use `referenceDate` when a value is defined', () => {
const onChange = spy();
diff --git a/packages/x-date-pickers/src/TimeField/tests/describes.TimeField.test.tsx b/packages/x-date-pickers/src/TimeField/tests/describes.TimeField.test.tsx
index f114972a5fb5d..04b67aaa2975c 100644
--- a/packages/x-date-pickers/src/TimeField/tests/describes.TimeField.test.tsx
+++ b/packages/x-date-pickers/src/TimeField/tests/describes.TimeField.test.tsx
@@ -7,6 +7,7 @@ import {
getTextbox,
describeValidation,
describeValue,
+ formatFullTimeValue,
} from 'test/utils/pickers';
import { TimeField } from '@mui/x-date-pickers/TimeField';
@@ -33,7 +34,7 @@ describe(' - Describes', () => {
expectInputPlaceholder(input, hasMeridiem ? 'hh:mm aa' : 'hh:mm');
}
const expectedValueStr = expectedValue
- ? adapterToUse.format(expectedValue, hasMeridiem ? 'fullTime12h' : 'fullTime24h')
+ ? formatFullTimeValue(adapterToUse, expectedValue)
: '';
expectInputValue(input, expectedValueStr);
},
diff --git a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx
index bf6b925ac9c38..38752aba87560 100644
--- a/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx
+++ b/packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx
@@ -148,15 +148,12 @@ export const YearCalendar = React.forwardRef(function YearCalendar(
if (value != null) {
return utils.getYear(value);
}
+ return null;
+ }, [value, utils]);
- if (disableHighlightToday) {
- return null;
- }
-
- return utils.getYear(referenceDate);
- }, [value, utils, disableHighlightToday, referenceDate]);
-
- const [focusedYear, setFocusedYear] = React.useState(() => selectedYear || todayYear);
+ const [focusedYear, setFocusedYear] = React.useState(
+ () => selectedYear || utils.getYear(referenceDate),
+ );
const [internalHasFocus, setInternalHasFocus] = useControlled({
name: 'YearCalendar',
diff --git a/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx b/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
index 3d979bd7f2ce8..17528fb8c8bba 100644
--- a/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
+++ b/packages/x-date-pickers/src/YearCalendar/tests/YearCalendar.test.tsx
@@ -169,4 +169,10 @@ describe('', () => {
expect(year2019).not.to.have.attribute('disabled');
expect(year2020).to.have.attribute('disabled');
});
+
+ it('should not mark the `referenceDate` year as selected', () => {
+ render();
+
+ expect(screen.getByRole('radio', { name: '2018', checked: false })).to.not.equal(null);
+ });
});
diff --git a/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx b/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx
index 7aaf18d0752a0..a46fee1e629b0 100644
--- a/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx
+++ b/packages/x-date-pickers/src/YearCalendar/tests/describes.YearCalendar.test.tsx
@@ -1,11 +1,7 @@
import * as React from 'react';
import { expect } from 'chai';
import { userEvent, screen, describeConformance } from '@mui-internal/test-utils';
-import {
- pickersYearClasses,
- YearCalendar,
- yearCalendarClasses as classes,
-} from '@mui/x-date-pickers/YearCalendar';
+import { YearCalendar, yearCalendarClasses as classes } from '@mui/x-date-pickers/YearCalendar';
import {
wrapPickerMount,
createPickerRenderer,
@@ -44,13 +40,15 @@ describe(' - Describes', () => {
emptyValue: null,
clock,
assertRenderedValue: (expectedValue: any) => {
- const selectedCells = document.querySelectorAll(`.${pickersYearClasses.selected}`);
+ const activeYear = screen
+ .queryAllByRole('radio')
+ .find((cell) => cell.getAttribute('tabindex') === '0');
+ expect(activeYear).not.to.equal(null);
if (expectedValue == null) {
- expect(selectedCells).to.have.length(1);
- expect(selectedCells[0]).to.have.text(adapterToUse.getYear(adapterToUse.date()).toString());
+ expect(activeYear).to.have.text(adapterToUse.getYear(adapterToUse.date()).toString());
} else {
- expect(selectedCells).to.have.length(1);
- expect(selectedCells[0]).to.have.text(adapterToUse.getYear(expectedValue).toString());
+ expect(activeYear).to.have.text(adapterToUse.getYear(expectedValue).toString());
+ expect(activeYear).to.have.attribute('aria-checked', 'true');
}
},
setNewValue: (value) => {
diff --git a/test/utils/pickers/misc.ts b/test/utils/pickers/misc.ts
index 49f70d50991fd..97a08af557017 100644
--- a/test/utils/pickers/misc.ts
+++ b/test/utils/pickers/misc.ts
@@ -56,3 +56,11 @@ export const getDateOffset = (
const cleanUtcHour = utcHour > 12 ? 24 - utcHour : -utcHour;
return cleanUtcHour * 60;
};
+
+export const formatFullTimeValue = (
+ adapter: MuiPickersAdapter,
+ value: TDate,
+) => {
+ const hasMeridiem = adapter.is12HourCycleInCurrentLocale();
+ return adapter.format(value, hasMeridiem ? 'fullTime12h' : 'fullTime24h');
+};
diff --git a/test/utils/pickers/viewHandlers.ts b/test/utils/pickers/viewHandlers.ts
index 0496eab0ef774..8a723c2bf2c7f 100644
--- a/test/utils/pickers/viewHandlers.ts
+++ b/test/utils/pickers/viewHandlers.ts
@@ -1,5 +1,5 @@
import { fireTouchChangedEvent, userEvent, screen } from '@mui-internal/test-utils';
-import { getClockTouchEvent } from 'test/utils/pickers';
+import { getClockTouchEvent, formatFullTimeValue } from 'test/utils/pickers';
import { MuiPickersAdapter, TimeView } from '@mui/x-date-pickers/models';
import { formatMeridiem } from '@mui/x-date-pickers/internals/utils/date-utils';
@@ -35,9 +35,7 @@ export const timeClockHandler: ViewHandler = {
export const digitalClockHandler: ViewHandler = {
setViewValue: (adapter, value) => {
- const hasMeridiem = adapter.is12HourCycleInCurrentLocale();
- const formattedLabel = adapter.format(value, hasMeridiem ? 'fullTime12h' : 'fullTime24h');
- userEvent.mousePress(screen.getByRole('option', { name: formattedLabel }));
+ userEvent.mousePress(screen.getByRole('option', { name: formatFullTimeValue(adapter, value) }));
},
};