onSelect(value)}
- onKeyDown={onSpaceOrEnter(() => onSelect(value))}
+ onClick={(event) => onClick(event, value)}
+ onKeyDown={(event) => onKeyDown(event, value)}
className={clsx(classes.yearButton, {
[classes.disabled]: disabled,
[classes.selected]: selected,
diff --git a/packages/material-ui-lab/src/YearPicker/YearPicker.test.tsx b/packages/material-ui-lab/src/YearPicker/YearPicker.test.tsx
index efeb587d0088c8..730767a2f23f94 100644
--- a/packages/material-ui-lab/src/YearPicker/YearPicker.test.tsx
+++ b/packages/material-ui-lab/src/YearPicker/YearPicker.test.tsx
@@ -46,7 +46,7 @@ describe('
', () => {
}),
);
- it('allows to pick year standalone', () => {
+ it('allows to pick year standalone by click, `Enter` and `Space`', () => {
const onChangeMock = spy();
render(
', () => {
onChange={onChangeMock}
/>,
);
+ const targetYear = screen.getByRole('button', { name: '2025' });
+
+ // A native button implies Enter and Space keydown behavior
+ // These keydown events only trigger click behavior if they're trusted (programmatically dispatched events aren't trusted).
+ // If this breaks, make sure to add tests for
+ // - fireEvent.keyDown(targetDay, { key: 'Enter' })
+ // - fireEvent.keyUp(targetDay, { key: 'Space' })
+ expect(targetYear.tagName).to.equal('BUTTON');
+
+ fireEvent.click(targetYear);
- fireEvent.click(screen.getByText('2025', { selector: 'button' }));
expect(onChangeMock.callCount).to.equal(1);
expect(onChangeMock.args[0][0]).toEqualDateTime(adapterToUse.date('2025-02-02T00:00:00.000'));
});
diff --git a/packages/material-ui-lab/src/YearPicker/YearPicker.tsx b/packages/material-ui-lab/src/YearPicker/YearPicker.tsx
index ed6dff71b50449..7655010438cd49 100644
--- a/packages/material-ui-lab/src/YearPicker/YearPicker.tsx
+++ b/packages/material-ui-lab/src/YearPicker/YearPicker.tsx
@@ -8,7 +8,6 @@ import { PickerOnChangeFn } from '../internal/pickers/hooks/useViews';
import { findClosestEnabledDate } from '../internal/pickers/date-utils';
import { PickerSelectionState } from '../internal/pickers/hooks/usePickerState';
import { WrapperVariantContext } from '../internal/pickers/wrappers/WrapperVariantContext';
-import { useGlobalKeyDown, keycode as keys } from '../internal/pickers/hooks/useKeyDown';
export interface ExportedYearPickerProps
{
/**
@@ -78,51 +77,40 @@ const YearPicker = React.forwardRef(function YearPicker(
const selectedYearRef = React.useRef(null);
const [focusedYear, setFocusedYear] = React.useState(currentYear);
- const handleYearSelection = React.useCallback(
- (year: number, isFinish: PickerSelectionState = 'finish') => {
- const submitDate = (newDate: TDate) => {
- onChange(newDate, isFinish);
-
- if (onFocusedDayChange) {
- onFocusedDayChange(newDate || now);
- }
-
- if (onYearChange) {
- onYearChange(newDate);
- }
- };
-
- const newDate = utils.setYear(selectedDate, year);
- if (isDateDisabled(newDate)) {
- const closestEnabledDate = findClosestEnabledDate({
- utils,
- date: newDate,
- minDate,
- maxDate,
- disablePast: Boolean(disablePast),
- disableFuture: Boolean(disableFuture),
- shouldDisableDate: isDateDisabled,
- });
-
- submitDate(closestEnabledDate || now);
- } else {
- submitDate(newDate);
+ const handleYearSelection = (
+ event: React.SyntheticEvent,
+ year: number,
+ isFinish: PickerSelectionState = 'finish',
+ ) => {
+ const submitDate = (newDate: TDate) => {
+ onChange(newDate, isFinish);
+
+ if (onFocusedDayChange) {
+ onFocusedDayChange(newDate || now);
}
- },
- [
- utils,
- now,
- selectedDate,
- isDateDisabled,
- onChange,
- onFocusedDayChange,
- onYearChange,
- minDate,
- maxDate,
- disablePast,
- disableFuture,
- ],
- );
+
+ if (onYearChange) {
+ onYearChange(newDate);
+ }
+ };
+
+ const newDate = utils.setYear(selectedDate, year);
+ if (isDateDisabled(newDate)) {
+ const closestEnabledDate = findClosestEnabledDate({
+ utils,
+ date: newDate,
+ minDate,
+ maxDate,
+ disablePast: Boolean(disablePast),
+ disableFuture: Boolean(disableFuture),
+ shouldDisableDate: isDateDisabled,
+ });
+
+ submitDate(closestEnabledDate || now);
+ } else {
+ submitDate(newDate);
+ }
+ };
const focusYear = React.useCallback(
(year: number) => {
@@ -134,13 +122,32 @@ const YearPicker = React.forwardRef(function YearPicker(
);
const yearsInRow = wrapperVariant === 'desktop' ? 4 : 3;
- const nowFocusedYear = focusedYear || currentYear;
- useGlobalKeyDown(Boolean(allowKeyboardControl), {
- [keys.ArrowUp]: () => focusYear(nowFocusedYear - yearsInRow),
- [keys.ArrowDown]: () => focusYear(nowFocusedYear + yearsInRow),
- [keys.ArrowLeft]: () => focusYear(nowFocusedYear + (theme.direction === 'ltr' ? -1 : 1)),
- [keys.ArrowRight]: () => focusYear(nowFocusedYear + (theme.direction === 'ltr' ? 1 : -1)),
- });
+
+ const handleKeyDown = (event: React.KeyboardEvent, year: number) => {
+ if (!allowKeyboardControl) {
+ return;
+ }
+ switch (event.key) {
+ case 'ArrowUp':
+ focusYear(year - yearsInRow);
+ event.preventDefault();
+ break;
+ case 'ArrowDown':
+ focusYear(year + yearsInRow);
+ event.preventDefault();
+ break;
+ case 'ArrowLeft':
+ focusYear(year + (theme.direction === 'ltr' ? -1 : 1));
+ event.preventDefault();
+ break;
+ case 'ArrowRight':
+ focusYear(year + (theme.direction === 'ltr' ? 1 : -1));
+ event.preventDefault();
+ break;
+ default:
+ break;
+ }
+ };
return (
@@ -153,9 +160,9 @@ const YearPicker = React.forwardRef(function YearPicker
(
key={utils.format(year, 'year')}
selected={selected}
value={yearNumber}
- onSelect={handleYearSelection}
- allowKeyboardControl={allowKeyboardControl}
- focused={yearNumber === focusedYear}
+ onClick={handleYearSelection}
+ onKeyDown={handleKeyDown}
+ autoFocus={allowKeyboardControl && yearNumber === focusedYear}
ref={selected ? selectedYearRef : undefined}
disabled={
(disablePast && utils.isBeforeYear(year, now)) ||
diff --git a/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx b/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
index 45dff15d344102..241bc97073ed49 100644
--- a/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
@@ -6,7 +6,7 @@ import Popper, { PopperProps as MuiPopperProps } from '@material-ui/core/Popper'
import TrapFocus, {
TrapFocusProps as MuiTrapFocusProps,
} from '@material-ui/core/Unstable_TrapFocus';
-import { useForkRef, setRef, useEventCallback, ownerDocument } from '@material-ui/core/utils';
+import { useForkRef, useEventCallback, ownerDocument } from '@material-ui/core/utils';
import { MuiStyles, StyleRules, WithStyles, withStyles } from '@material-ui/core/styles';
import { TransitionProps as MuiTransitionProps } from '@material-ui/core/transitions';
import { useGlobalKeyDown, keycode } from './hooks/useKeyDown';
@@ -29,7 +29,6 @@ export interface PickerPopperProps extends ExportedPickerPopperProps, MuiPaperPr
open: MuiPopperProps['open'];
containerRef?: React.Ref;
onClose: () => void;
- onOpen: () => void;
}
export type PickersPopperClassKey = 'root' | 'paper' | 'topTransition';
@@ -171,7 +170,6 @@ const PickersPopper: React.FC> = (
classes,
containerRef = null,
onClose,
- onOpen,
open,
PopperProps,
role,
@@ -202,15 +200,7 @@ const PickersPopper: React.FC> = (
const [clickAwayRef, onPaperClick, onPaperTouchStart] = useClickAwayListener(open, onClose);
const paperRef = React.useRef(null);
const handleRef = useForkRef(paperRef, containerRef);
-
- const handlePaperRef = useEventCallback((node: HTMLElement) => {
- setRef(handleRef, node);
- setRef(clickAwayRef, node);
-
- if (node) {
- onOpen();
- }
- });
+ const handlePaperRef = useForkRef(handleRef, clickAwayRef);
return (
React.useContext(CanAutoFocusContext);
-
-export function useAutoFocusControl(open: boolean) {
- const [canAutoFocus, setCanAutoFocus] = React.useState(false);
-
- React.useEffect(() => {
- if (!open) {
- setCanAutoFocus(false);
- }
- }, [open]);
-
- // TODO rething approach. It is a temporal fix to allow tests that are rendering Popper to update the state using
- if (process.env.NODE_ENV === 'test') {
- return {
- canAutoFocus: true,
- onOpen: () => {},
- };
- }
-
- return {
- canAutoFocus,
- onOpen: () => setCanAutoFocus(true),
- };
-}
diff --git a/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopTooltipWrapper.tsx b/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopTooltipWrapper.tsx
index 2fbc8839b28cd4..04e1219964773a 100644
--- a/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopTooltipWrapper.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopTooltipWrapper.tsx
@@ -3,7 +3,6 @@ import { WrapperVariantContext } from './WrapperVariantContext';
import { KeyboardDateInput } from '../KeyboardDateInput';
import { executeInTheNextEventLoopTick } from '../utils';
import PickersPopper from '../PickersPopper';
-import { CanAutoFocusContext, useAutoFocusControl } from '../hooks/useCanAutoFocus';
import { PrivateWrapperProps, DesktopWrapperProps } from './WrapperProps';
const DesktopTooltipWrapper: React.FC = (props) => {
@@ -18,7 +17,6 @@ const DesktopTooltipWrapper: React.FC
} = props;
const inputRef = React.useRef(null);
const popperRef = React.useRef(null);
- const { canAutoFocus, onOpen } = useAutoFocusControl(open);
const handleBlur = () => {
executeInTheNextEventLoopTick(() => {
@@ -35,26 +33,19 @@ const DesktopTooltipWrapper: React.FC
return (
-
-
-
- {children}
-
-
+
+
+ {children}
+
);
};
diff --git a/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopWrapper.tsx b/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopWrapper.tsx
index 53ed6c9d10bfce..ec66b93afebe96 100644
--- a/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopWrapper.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/wrappers/DesktopWrapper.tsx
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import { WrapperVariantContext } from './WrapperVariantContext';
import { KeyboardDateInput } from '../KeyboardDateInput';
import PickersPopper from '../PickersPopper';
-import { CanAutoFocusContext, useAutoFocusControl } from '../hooks/useCanAutoFocus';
import { PrivateWrapperProps, DesktopWrapperProps } from './WrapperProps';
const DesktopWrapper: React.FC = (props) => {
@@ -17,24 +16,20 @@ const DesktopWrapper: React.FC = (pro
TransitionComponent,
} = props;
const inputRef = React.useRef(null);
- const { canAutoFocus, onOpen } = useAutoFocusControl(open);
return (
-
-
-
- {children}
-
-
+
+
+ {children}
+
);
};