Skip to content

Commit a32eb6e

Browse files
authored
Fix disabled (#49)
* fix datePicker disabled keyboard * test case
1 parent 3c1cecb commit a32eb6e

File tree

4 files changed

+52
-47
lines changed

4 files changed

+52
-47
lines changed

src/Picker.tsx

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@ import { isEqual } from './utils/dateUtil';
2626
import getDataOrAriaProps, { toArray } from './utils/miscUtil';
2727
import PanelContext, { ContextOperationRefProps } from './PanelContext';
2828
import { PickerMode } from './interface';
29-
import {
30-
getDefaultFormat,
31-
getInputSize,
32-
elementsContains,
33-
} from './utils/uiUtil';
29+
import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil';
3430
import usePickerInput from './hooks/usePickerInput';
3531
import useTextValueMapping from './hooks/useTextValueMapping';
3632
import useValueTexts from './hooks/useValueTexts';
@@ -120,9 +116,7 @@ export type PickerProps<DateType> =
120116

121117
interface MergedPickerProps<DateType>
122118
extends Omit<
123-
PickerBaseProps<DateType> &
124-
PickerDateProps<DateType> &
125-
PickerTimeProps<DateType>,
119+
PickerBaseProps<DateType> & PickerDateProps<DateType> & PickerTimeProps<DateType>,
126120
'picker'
127121
> {
128122
picker?: PickerMode;
@@ -173,13 +167,10 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
173167

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

176-
const needConfirmButton: boolean =
177-
(picker === 'date' && !!showTime) || picker === 'time';
170+
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
178171

179172
// ============================= State =============================
180-
const formatList = toArray(
181-
getDefaultFormat(format, picker, showTime, use12Hours),
182-
);
173+
const formatList = toArray(getDefaultFormat(format, picker, showTime, use12Hours));
183174

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

194185
// Selected value
195-
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(
196-
mergedValue,
197-
);
186+
const [selectedValue, setSelectedValue] = React.useState<DateType | null>(mergedValue);
198187

199188
// Operation ref
200189
const operationRef: React.MutableRefObject<ContextOperationRefProps | null> = React.useRef<
@@ -227,11 +216,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
227216
const [text, triggerTextChange, resetText] = useTextValueMapping({
228217
valueTexts,
229218
onTextChange: newText => {
230-
const inputDate = generateConfig.locale.parse(
231-
locale.locale,
232-
newText,
233-
formatList,
234-
);
219+
const inputDate = generateConfig.locale.parse(locale.locale, newText, formatList);
235220
if (inputDate && (!disabledDate || !disabledDate(inputDate))) {
236221
setSelectedValue(inputDate);
237222
}
@@ -246,17 +231,12 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
246231
if (onChange && !isEqual(generateConfig, mergedValue, newValue)) {
247232
onChange(
248233
newValue,
249-
newValue
250-
? generateConfig.locale.format(locale.locale, newValue, formatList[0])
251-
: '',
234+
newValue ? generateConfig.locale.format(locale.locale, newValue, formatList[0]) : '',
252235
);
253236
}
254237
};
255238

256-
const triggerOpen = (
257-
newOpen: boolean,
258-
preventChangeEvent: boolean = false,
259-
) => {
239+
const triggerOpen = (newOpen: boolean, preventChangeEvent: boolean = false) => {
260240
triggerInnerOpen(newOpen);
261241
if (!newOpen && !preventChangeEvent) {
262242
triggerChange(selectedValue);
@@ -280,9 +260,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
280260
}
281261
};
282262

283-
const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (
284-
...args
285-
) => {
263+
const onInternalMouseUp: React.MouseEventHandler<HTMLDivElement> = (...args) => {
286264
if (onMouseUp) {
287265
onMouseUp(...args);
288266
}
@@ -300,14 +278,16 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
300278
triggerOpen,
301279
forwardKeyDown,
302280
isClickOutside: target =>
303-
!elementsContains(
304-
[panelDivRef.current, inputDivRef.current],
305-
target as HTMLElement,
306-
),
281+
!elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement),
307282
onSubmit: () => {
283+
if (disabledDate && disabledDate(selectedValue)) {
284+
return false;
285+
}
286+
308287
triggerChange(selectedValue);
309288
triggerOpen(false, true);
310289
resetText();
290+
return true;
311291
},
312292
onCancel: () => {
313293
triggerOpen(false, true);
@@ -428,10 +408,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
428408
}
429409

430410
// ============================ Return =============================
431-
const onContextSelect = (
432-
date: DateType,
433-
type: 'key' | 'mouse' | 'submit',
434-
) => {
411+
const onContextSelect = (date: DateType, type: 'key' | 'mouse' | 'submit') => {
435412
if (type === 'submit' || (type !== 'key' && !needConfirmButton)) {
436413
// triggerChange will also update selected values
437414
triggerChange(date);

src/PickerPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
440440
prefixCls,
441441
components,
442442
needConfirmButton,
443-
okDisabled: !mergedValue,
443+
okDisabled: !mergedValue || (disabledDate && disabledDate(mergedValue)),
444444
locale,
445445
onNow:
446446
needConfirmButton &&

src/hooks/usePickerInput.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@ export default function usePickerInput({
1818
triggerOpen: (open: boolean) => void;
1919
forwardKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => boolean;
2020
blurToCancel?: boolean;
21-
onSubmit: () => void;
21+
onSubmit: () => void | boolean;
2222
onCancel: () => void;
2323
onFocus?: React.FocusEventHandler<HTMLInputElement>;
2424
onBlur?: React.FocusEventHandler<HTMLInputElement>;
25-
}): [
26-
React.DOMAttributes<HTMLInputElement>,
27-
{ focused: boolean; typing: boolean },
28-
] {
25+
}): [React.DOMAttributes<HTMLInputElement>, { focused: boolean; typing: boolean }] {
2926
const [typing, setTyping] = React.useState(false);
3027
const [focused, setFocused] = React.useState(false);
3128

@@ -45,8 +42,7 @@ export default function usePickerInput({
4542
case KeyCode.ENTER: {
4643
if (!open) {
4744
triggerOpen(true);
48-
} else {
49-
onSubmit();
45+
} else if (onSubmit() !== false) {
5046
setTyping(true);
5147
}
5248

tests/keyboard.spec.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,4 +455,36 @@ describe('Picker.Keyboard', () => {
455455

456456
expect(preventDefault).toHaveBeenCalled();
457457
});
458+
459+
it('keyboard should not trigger on disabledDate', () => {
460+
const onChange = jest.fn();
461+
const onSelect = jest.fn();
462+
const wrapper = mount(
463+
<MomentPicker
464+
showTime
465+
onSelect={onSelect}
466+
onChange={onChange}
467+
disabledDate={date => date.date() % 2 === 0}
468+
/>,
469+
);
470+
wrapper.find('input').simulate('focus');
471+
wrapper.keyDown(KeyCode.ENTER);
472+
wrapper.keyDown(KeyCode.TAB);
473+
wrapper.keyDown(KeyCode.TAB);
474+
wrapper.keyDown(KeyCode.DOWN);
475+
expect(isSame(onSelect.mock.calls[0][0], '1990-09-10')).toBeTruthy();
476+
477+
// Not enter to change
478+
wrapper.keyDown(KeyCode.ENTER);
479+
expect(onChange).not.toHaveBeenCalled();
480+
481+
// Not button enabled
482+
expect(wrapper.find('.rc-picker-ok button').props().disabled).toBeTruthy();
483+
484+
// Another can be enter
485+
wrapper.keyDown(KeyCode.RIGHT);
486+
expect(wrapper.find('.rc-picker-ok button').props().disabled).toBeFalsy();
487+
wrapper.keyDown(KeyCode.ENTER);
488+
expect(onChange).toHaveBeenCalled();
489+
});
458490
});

0 commit comments

Comments
 (0)