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
55 changes: 16 additions & 39 deletions src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ import { isEqual } from './utils/dateUtil';
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
import PanelContext, { ContextOperationRefProps } from './PanelContext';
import { PickerMode } from './interface';
import {
getDefaultFormat,
getInputSize,
elementsContains,
} from './utils/uiUtil';
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
import usePickerInput from './hooks/usePickerInput';
import useTextValueMapping from './hooks/useTextValueMapping';
import useValueTexts from './hooks/useValueTexts';
Expand Down Expand Up @@ -120,9 +116,7 @@ export type PickerProps<DateType> =

interface MergedPickerProps<DateType>
extends Omit<
PickerBaseProps<DateType> &
PickerDateProps<DateType> &
PickerTimeProps<DateType>,
PickerBaseProps<DateType> & PickerDateProps<DateType> & PickerTimeProps<DateType>,
'picker'
> {
picker?: PickerMode;
Expand Down Expand Up @@ -173,13 +167,10 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {

const inputRef = React.useRef<HTMLInputElement>(null);

const needConfirmButton: boolean =
(picker === 'date' && !!showTime) || picker === 'time';
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';

// ============================= State =============================
const formatList = toArray(
getDefaultFormat(format, picker, showTime, use12Hours),
);
const formatList = toArray(getDefaultFormat(format, picker, showTime, use12Hours));

// Panel ref
const panelDivRef = React.useRef<HTMLDivElement>(null);
Expand All @@ -192,9 +183,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
});

// Selected value
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(
mergedValue,
);
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(mergedValue);

// Operation ref
const operationRef: React.MutableRefObject<ContextOperationRefProps | null> = React.useRef<
Expand Down Expand Up @@ -227,11 +216,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
const [text, triggerTextChange, resetText] = useTextValueMapping({
valueTexts,
onTextChange: newText => {
const inputDate = generateConfig.locale.parse(
locale.locale,
newText,
formatList,
);
const inputDate = generateConfig.locale.parse(locale.locale, newText, formatList);
if (inputDate && (!disabledDate || !disabledDate(inputDate))) {
setSelectedValue(inputDate);
}
Expand All @@ -246,17 +231,12 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
if (onChange && !isEqual(generateConfig, mergedValue, newValue)) {
onChange(
newValue,
newValue
? generateConfig.locale.format(locale.locale, newValue, formatList[0])
: '',
newValue ? generateConfig.locale.format(locale.locale, newValue, formatList[0]) : '',
);
}
};

const triggerOpen = (
newOpen: boolean,
preventChangeEvent: boolean = false,
) => {
const triggerOpen = (newOpen: boolean, preventChangeEvent: boolean = false) => {
triggerInnerOpen(newOpen);
if (!newOpen && !preventChangeEvent) {
triggerChange(selectedValue);
Expand All @@ -280,9 +260,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
}
};

const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (
...args
) => {
const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (...args) => {
if (onMouseUp) {
onMouseUp(...args);
}
Expand All @@ -300,14 +278,16 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
triggerOpen,
forwardKeyDown,
isClickOutside: target =>
!elementsContains(
[panelDivRef.current, inputDivRef.current],
target as HTMLElement,
),
!elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement),
onSubmit: () => {
if (disabledDate && disabledDate(selectedValue)) {
return false;
}

triggerChange(selectedValue);
triggerOpen(false, true);
resetText();
return true;
},
onCancel: () => {
triggerOpen(false, true);
Expand Down Expand Up @@ -428,10 +408,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
}

// ============================ Return =============================
const onContextSelect = (
date: DateType,
type: 'key' | 'mouse' | 'submit',
) => {
const onContextSelect = (date: DateType, type: 'key' | 'mouse' | 'submit') => {
if (type === 'submit' || (type !== 'key' && !needConfirmButton)) {
// triggerChange will also update selected values
triggerChange(date);
Expand Down
2 changes: 1 addition & 1 deletion src/PickerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
prefixCls,
components,
needConfirmButton,
okDisabled: !mergedValue,
okDisabled: !mergedValue || (disabledDate && disabledDate(mergedValue)),
locale,
onNow:
needConfirmButton &&
Expand Down
10 changes: 3 additions & 7 deletions src/hooks/usePickerInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,11 @@ export default function usePickerInput({
triggerOpen: (open: boolean) => void;
forwardKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => boolean;
blurToCancel?: boolean;
onSubmit: () => void;
onSubmit: () => void | boolean;
onCancel: () => void;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
}): [
React.DOMAttributes<HTMLInputElement>,
{ focused: boolean; typing: boolean },
] {
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
const [typing, setTyping] = React.useState(false);
const [focused, setFocused] = React.useState(false);

Expand All @@ -45,8 +42,7 @@ export default function usePickerInput({
case KeyCode.ENTER: {
if (!open) {
triggerOpen(true);
} else {
onSubmit();
} else if (onSubmit() !== false) {
setTyping(true);
}

Expand Down
32 changes: 32 additions & 0 deletions tests/keyboard.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -455,4 +455,36 @@ describe('Picker.Keyboard', () => {

expect(preventDefault).toHaveBeenCalled();
});

it('keyboard should not trigger on disabledDate', () => {
const onChange = jest.fn();
const onSelect = jest.fn();
const wrapper = mount(
<MomentPicker
showTime
onSelect={onSelect}
onChange={onChange}
disabledDate={date => date.date() % 2 === 0}
/>,
);
wrapper.find('input').simulate('focus');
wrapper.keyDown(KeyCode.ENTER);
wrapper.keyDown(KeyCode.TAB);
wrapper.keyDown(KeyCode.TAB);
wrapper.keyDown(KeyCode.DOWN);
expect(isSame(onSelect.mock.calls[0][0], '1990-09-10')).toBeTruthy();

// Not enter to change
wrapper.keyDown(KeyCode.ENTER);
expect(onChange).not.toHaveBeenCalled();

// Not button enabled
expect(wrapper.find('.rc-picker-ok button').props().disabled).toBeTruthy();

// Another can be enter
wrapper.keyDown(KeyCode.RIGHT);
expect(wrapper.find('.rc-picker-ok button').props().disabled).toBeFalsy();
wrapper.keyDown(KeyCode.ENTER);
expect(onChange).toHaveBeenCalled();
});
});