Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 54 additions & 5 deletions src/PickerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import type { DateRender } from './panels/DatePanel/DateBody';
import DatetimePanel from './panels/DatetimePanel';
import DecadePanel from './panels/DecadePanel';
import MonthPanel from './panels/MonthPanel';
import type { MonthCellRender } from './panels/MonthPanel/MonthBody';
import { MONTH_COL_COUNT, type MonthCellRender } from './panels/MonthPanel/MonthBody';
import QuarterPanel from './panels/QuarterPanel';
import type { SharedTimeProps } from './panels/TimePanel';
import TimePanel from './panels/TimePanel';
import WeekPanel from './panels/WeekPanel';
import YearPanel from './panels/YearPanel';
import RangeContext from './RangeContext';
import { isEqual } from './utils/dateUtil';
import { isEqual, WEEK_DAY_COUNT } from './utils/dateUtil';
import getExtraFooter from './utils/getExtraFooter';
import getRanges from './utils/getRanges';
import { getLowerBoundTime, setDateTime, setTime } from './utils/timeUtil';
Expand Down Expand Up @@ -125,6 +125,9 @@ type MergedPickerPanelProps<DateType> = {
picker?: PickerMode;
} & OmitType<DateType>;

// Calendar picker type
const CALENDAR_PANEL_MODE: PanelMode[] = ['date', 'month'];

function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
const {
prefixCls = 'rc-picker',
Expand Down Expand Up @@ -297,9 +300,49 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
}
};

const isSelectable = (key) => {
if (CALENDAR_PANEL_MODE.includes(mergedMode)) {
let date;
let operationFnc;
const isDateMode = mergedMode === 'date';
if (key === KeyCode.PAGE_UP || key === KeyCode.PAGE_DOWN) {
operationFnc = isDateMode ? generateConfig.addMonth : generateConfig.addYear;
} else {
operationFnc = isDateMode ? generateConfig.addDate : generateConfig.addMonth;
}

switch (key) {
case KeyCode.LEFT:
case KeyCode.PAGE_UP:
date = operationFnc(viewDate, -1);
break;
case KeyCode.RIGHT:
case KeyCode.PAGE_DOWN:
date = operationFnc(viewDate, 1);
break;
case KeyCode.UP:
case KeyCode.DOWN:
date = operationFnc(
viewDate,
Number(
`${key === KeyCode.UP ? '-' : ''}${isDateMode ? WEEK_DAY_COUNT : MONTH_COL_COUNT}`,
),
);
break;
}

if (date) {
return !disabledDate?.(date);
}
}
return true;
};

// ========================= Interactive ==========================
const onInternalKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
if (panelRef.current && panelRef.current.onKeyDown) {
let selectable = true;
const { which } = e;
if (
[
KeyCode.LEFT,
Expand All @@ -309,11 +352,18 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
KeyCode.PAGE_UP,
KeyCode.PAGE_DOWN,
KeyCode.ENTER,
].includes(e.which)
].includes(which)
) {
e.preventDefault();
if (which !== KeyCode.ENTER && tabIndex === 0) {
selectable = isSelectable(which);
}
}

// Cannot use keyboard to select disabled date
if (selectable) {
return panelRef.current.onKeyDown(e);
}
return panelRef.current.onKeyDown(e);
}

/* istanbul ignore next */
Expand Down Expand Up @@ -379,7 +429,6 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
delete pickerProps.onChange;
delete pickerProps.onSelect;


switch (mergedMode) {
case 'decade':
panelNode = (
Expand Down
54 changes: 47 additions & 7 deletions tests/keyboard.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -534,16 +534,56 @@ describe('Picker.Keyboard', () => {
);

fireEvent.focus(document.querySelector('.rc-picker-panel'));

// 9-10 is disabled
// 9-02、9-04、9-10 is disabled
panelKeyDown(KeyCode.LEFT);
panelKeyDown(KeyCode.RIGHT);
panelKeyDown(KeyCode.DOWN);
expect(isSame(onSelect.mock.calls[0][0], '1990-09-10')).toBeTruthy();
expect(onChange).not.toHaveBeenCalled();
expect(onSelect).not.toHaveBeenCalled();

// 7-27、8-27 is enabled
panelKeyDown(KeyCode.UP);
expect(isSame(onSelect.mock.calls[0][0], '1990-08-27')).toBeTruthy();
onSelect.mockReset();
panelKeyDown(KeyCode.PAGE_UP);
expect(isSame(onSelect.mock.calls[0][0], '1990-07-27')).toBeTruthy();
onSelect.mockReset();
panelKeyDown(KeyCode.PAGE_DOWN);
expect(isSame(onSelect.mock.calls[0][0], '1990-08-27')).toBeTruthy();
});

it('month panel', () => {
const onChange = jest.fn();
const onSelect = jest.fn();
const now = new Date();
render(
<MomentPickerPanel
picker="month"
onSelect={onSelect}
onChange={onChange}
disabledDate={(date) => date.month() < now.getMonth()}
/>,
);

fireEvent.focus(document.querySelector('.rc-picker-panel'));

// 9-17 is enabled
// PAGE_UP and PAGE_DOWN do not trigger the select
panelKeyDown(KeyCode.PAGE_UP);
panelKeyDown(KeyCode.PAGE_DOWN);
expect(onSelect).not.toHaveBeenCalled();

// The disabled date is before August
panelKeyDown(KeyCode.LEFT);
panelKeyDown(KeyCode.UP);
expect(onSelect).not.toHaveBeenCalled();

// August and subsequent dates are enable
panelKeyDown(KeyCode.RIGHT);
expect(isSame(onSelect.mock.calls[0][0], '1990-10-03')).toBeTruthy();
onSelect.mockReset();
panelKeyDown(KeyCode.LEFT);
onSelect.mockReset();
panelKeyDown(KeyCode.DOWN);
expect(isSame(onSelect.mock.calls[1][0], '1990-09-17')).toBeTruthy();
expect(isSame(onChange.mock.calls[0][0], '1990-09-17')).toBeTruthy();
expect(isSame(onSelect.mock.calls[0][0], '1990-12-03')).toBeTruthy();
});
});
});