Skip to content

Commit 6b06190

Browse files
authored
add onKeyDown Props that supports prevent default behavior (#138)
* add onKeyDown props and disableKey props * update readme and basic example * remove disableKey * update onkeydown preventDefaultBehaviors on Picker update readme update basic example * fix range picker onKeyDown fix preventDefaultBehaviors types * update picker input preventdefault (state to ref) update examples add test case for prevent default apply @kerm1it suggestions * update on key down event type rename all preventDefaultBehaviors to preventDefault apply @kerm1it suggestions * rename focuseventhandler and mouseeventhandler * update example caption for on keydown
1 parent bf3ef16 commit 6b06190

File tree

6 files changed

+67
-4
lines changed

6 files changed

+67
-4
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# rc-picker
1+
# rc-picker
22

33
[![NPM version][npm-image]][npm-url]
44
[![build status][github-actions-image]][github-actions-url]
@@ -76,8 +76,9 @@ render(<Picker />, mountNode);
7676
| getPopupContainer | function(trigger) | | to set the container of the floating layer, while the default is to create a div element in body |
7777
| onChange | Function(date: moment, dateString: string) | | a callback function, can be executed when the selected time is changing |
7878
| onOpenChange | Function(open:boolean) | | called when open/close picker |
79-
| onFocus | (evnet:React.FocusEventHandler<HTMLInputElement>) => void | | called like input's on focus |
80-
| onBlur | (evnet:React.FocusEventHandler<HTMLInputElement>) => void | | called like input's on blur |
79+
| onFocus | (event:React.FocusEvent<HTMLInputElement>) => void | | called like input's on focus |
80+
| onBlur | (event:React.FocusEvent<HTMLInputElement>) => void | | called like input's on blur |
81+
| onKeyDown | (event:React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void | | input on keydown event |
8182
| direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. |
8283

8384
### PickerPanel
@@ -102,7 +103,7 @@ render(<Picker />, mountNode);
102103
| renderExtraFooter | (mode) => React.Node | | extra footer |
103104
| onSelect | Function(date: moment) | | a callback function, can be executed when the selected time |
104105
| onPanelChange | Function(value: moment, mode) | | callback when picker panel mode is changed |
105-
| onMouseDown | (evnet:React.MouseEventHandler<HTMLInputElement>) => void | | callback when executed onMouseDown evnent |
106+
| onMouseDown | (event:React.MouseEvent<HTMLInputElement>) => void | | callback when executed onMouseDown evnent |
106107
| direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. |
107108

108109
### RangePicker

examples/basic.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ export default () => {
2929
onChange,
3030
};
3131

32+
const keyDown = (e, preventDefault) => {
33+
if (e.keyCode === 13) preventDefault();
34+
};
35+
3236
return (
3337
<div>
3438
<h1>Value: {value ? value.format('YYYY-MM-DD HH:mm:ss') : 'null'}</h1>
@@ -125,6 +129,10 @@ export default () => {
125129
<h3>Keyboard navigation (Tab key) disabled</h3>
126130
<Picker<Moment> {...sharedProps} locale={enUS} tabIndex={-1} />
127131
</div>
132+
<div style={{ margin: '0 8px' }}>
133+
<h3>Keyboard event with prevent default behaviors</h3>
134+
<Picker<Moment> {...sharedProps} locale={enUS} onKeyDown={keyDown} />
135+
</div>
128136
</div>
129137
</div>
130138
);

src/Picker.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export interface PickerSharedProps<DateType> extends React.AriaAttributes {
7777
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
7878
onClick?: React.MouseEventHandler<HTMLDivElement>;
7979
onContextMenu?: React.MouseEventHandler<HTMLDivElement>;
80+
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>, preventDefault: () => void) => void;
8081

8182
// Internal
8283
/** @private Internal usage, do not use in production mode!!! */
@@ -170,6 +171,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
170171
onMouseLeave,
171172
onContextMenu,
172173
onClick,
174+
onKeyDown,
173175
onSelect,
174176
direction,
175177
autoComplete = 'off',
@@ -310,6 +312,9 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
310312
setSelectedValue(mergedValue);
311313
resetText();
312314
},
315+
onKeyDown: (e, preventDefault) => {
316+
onKeyDown?.(e, preventDefault);
317+
},
313318
onFocus,
314319
onBlur,
315320
});

src/RangePicker.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
210210
onFocus,
211211
onBlur,
212212
onOk,
213+
onKeyDown,
213214
components,
214215
order,
215216
direction,
@@ -610,12 +611,18 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
610611
...getSharedInputHookProps(0, resetStartText),
611612
open: startOpen,
612613
value: startText,
614+
onKeyDown: (e, preventDefault) => {
615+
onKeyDown?.(e, preventDefault);
616+
},
613617
});
614618

615619
const [endInputProps, { focused: endFocused, typing: endTyping }] = usePickerInput({
616620
...getSharedInputHookProps(1, resetEndText),
617621
open: endOpen,
618622
value: endText,
623+
onKeyDown: (e, preventDefault) => {
624+
onKeyDown?.(e, preventDefault);
625+
},
619626
});
620627

621628
// ========================== Click Picker ==========================

src/hooks/usePickerInput.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default function usePickerInput({
99
isClickOutside,
1010
triggerOpen,
1111
forwardKeyDown,
12+
onKeyDown,
1213
blurToCancel,
1314
onSubmit,
1415
onCancel,
@@ -20,6 +21,10 @@ export default function usePickerInput({
2021
isClickOutside: (clickElement: EventTarget | null) => boolean;
2122
triggerOpen: (open: boolean) => void;
2223
forwardKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => boolean;
24+
onKeyDown: (
25+
e: React.KeyboardEvent<HTMLInputElement>,
26+
preventDefault: () => void,
27+
) => void;
2328
blurToCancel?: boolean;
2429
onSubmit: () => void | boolean;
2530
onCancel: () => void;
@@ -37,12 +42,22 @@ export default function usePickerInput({
3742

3843
const valueChangedRef = useRef<boolean>(false);
3944

45+
const preventDefaultRef = useRef<boolean>(false);
46+
4047
const inputProps: React.DOMAttributes<HTMLInputElement> = {
4148
onMouseDown: () => {
4249
setTyping(true);
4350
triggerOpen(true);
4451
},
4552
onKeyDown: e => {
53+
const preventDefault = (): void => {
54+
preventDefaultRef.current = true;
55+
};
56+
57+
onKeyDown(e, preventDefault);
58+
59+
if (preventDefaultRef.current) return;
60+
4661
switch (e.which) {
4762
case KeyCode.ENTER: {
4863
if (!open) {

tests/picker.spec.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,4 +866,31 @@ describe('Picker.Basic', () => {
866866
wrapper.unmount();
867867
});
868868
});
869+
870+
describe('prevent default on keydown', () => {
871+
it('should open picker panel if no prevent default', () => {
872+
const keyDown = jest.fn();
873+
const wrapper = mount(<MomentPicker onKeyDown={keyDown} />);
874+
875+
wrapper.closePicker();
876+
wrapper.keyDown(KeyCode.ENTER);
877+
expect(wrapper.isOpen()).toBeTruthy();
878+
});
879+
880+
it('should not open if prevent default is called', () => {
881+
const keyDown = jest.fn(({ which }, preventDefault) => {
882+
if(which === 13) preventDefault();
883+
});
884+
const wrapper = mount(<MomentPicker onKeyDown={keyDown} />);
885+
886+
wrapper.openPicker();
887+
expect(wrapper.isOpen()).toBeTruthy();
888+
889+
wrapper.keyDown(KeyCode.ESC);
890+
expect(wrapper.isOpen()).toBeFalsy();
891+
892+
wrapper.keyDown(KeyCode.ENTER);
893+
expect(wrapper.isOpen()).toBeFalsy();
894+
});
895+
})
869896
});

0 commit comments

Comments
 (0)