From 6415173589aa613210f9f294453225b1928e5774 Mon Sep 17 00:00:00 2001 From: Benny Date: Sat, 5 Sep 2020 13:28:52 +0800 Subject: [PATCH 1/9] add onKeyDown props and disableKey props --- src/Picker.tsx | 11 ++++++++++ src/RangePicker.tsx | 10 +++++++++ src/hooks/usePickerInput.ts | 42 ++++++++++++++++++++++++------------- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/Picker.tsx b/src/Picker.tsx index b4850ba54..9eadc9894 100644 --- a/src/Picker.tsx +++ b/src/Picker.tsx @@ -77,6 +77,11 @@ export interface PickerSharedProps extends React.AriaAttributes { onMouseLeave?: React.MouseEventHandler; onClick?: React.MouseEventHandler; onContextMenu?: React.MouseEventHandler; + onKeyDown?: (e) => void; + + // keyboard key disable options + // array => ['ENTER', 'TAB', 'ESC'] + disableKey?: Array; // Internal /** @private Internal usage, do not use in production mode!!! */ @@ -170,6 +175,8 @@ function InnerPicker(props: PickerProps) { onMouseLeave, onContextMenu, onClick, + onKeyDown, + disableKey, direction, autoComplete = 'off', } = props as MergedPickerProps; @@ -305,6 +312,10 @@ function InnerPicker(props: PickerProps) { setSelectedValue(mergedValue); resetText(); }, + onKeyDown: e => { + if (onKeyDown) onKeyDown(e); + }, + disableKey, onFocus, onBlur, }); diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index d994761ce..5977453b3 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -208,6 +208,8 @@ function InnerRangePicker(props: RangePickerProps) { onFocus, onBlur, onOk, + onKeyDown, + disableKey, components, order, direction, @@ -604,12 +606,20 @@ function InnerRangePicker(props: RangePickerProps) { ...getSharedInputHookProps(0, resetStartText), open: startOpen, value: startText, + onKeyDown: e => { + if (onKeyDown) onKeyDown(e); + }, + disableKey, }); const [endInputProps, { focused: endFocused, typing: endTyping }] = usePickerInput({ ...getSharedInputHookProps(1, resetEndText), open: endOpen, value: endText, + onKeyDown: e => { + if (onKeyDown) onKeyDown(e); + }, + disableKey, }); // ========================== Click Picker ========================== diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 9903baff3..230999521 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -9,6 +9,8 @@ export default function usePickerInput({ isClickOutside, triggerOpen, forwardKeyDown, + onKeyDown, + disableKey, blurToCancel, onSubmit, onCancel, @@ -20,6 +22,8 @@ export default function usePickerInput({ isClickOutside: (clickElement: EventTarget | null) => boolean; triggerOpen: (open: boolean) => void; forwardKeyDown: (e: React.KeyboardEvent) => boolean; + onKeyDown: (e: React.KeyboardEvent) => void; + disableKey?: Array; blurToCancel?: boolean; onSubmit: () => void | boolean; onCancel: () => void; @@ -43,34 +47,44 @@ export default function usePickerInput({ triggerOpen(true); }, onKeyDown: e => { + if (onKeyDown) { + onKeyDown(e); + } + switch (e.which) { case KeyCode.ENTER: { - if (!open) { - triggerOpen(true); - } else if (onSubmit() !== false) { - setTyping(true); - } + if (!disableKey || !disableKey.includes('ENTER')) { + if (!open) { + triggerOpen(true); + } else if (onSubmit() !== false) { + setTyping(true); + } - e.preventDefault(); + e.preventDefault(); + } return; } case KeyCode.TAB: { - if (typing && open && !e.shiftKey) { - setTyping(false); - e.preventDefault(); - } else if (!typing && open) { - if (!forwardKeyDown(e) && e.shiftKey) { - setTyping(true); + if (!disableKey || !disableKey.includes('TAB')) { + if (typing && open && !e.shiftKey) { + setTyping(false); e.preventDefault(); + } else if (!typing && open) { + if (!forwardKeyDown(e) && e.shiftKey) { + setTyping(true); + e.preventDefault(); + } } } return; } case KeyCode.ESC: { - setTyping(true); - onCancel(); + if (!disableKey || !disableKey.includes('ESC')) { + setTyping(true); + onCancel(); + } return; } } From c0f7575d9180905a916dc90aa975767dd22a0fbc Mon Sep 17 00:00:00 2001 From: Benny Date: Sat, 5 Sep 2020 13:31:04 +0800 Subject: [PATCH 2/9] update readme and basic example --- README.md | 8 +++++--- examples/basic.tsx | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6a071668d..6c7697e42 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,10 @@ render(, mountNode); | getPopupContainer | function(trigger) | | to set the container of the floating layer, while the default is to create a div element in body | | onChange | Function(date: moment, dateString: string) | | a callback function, can be executed when the selected time is changing | | onOpenChange | Function(open:boolean) | | called when open/close picker | -| onFocus | (evnet:React.FocusEventHandler) => void | | called like input's on focus | -| onBlur | (evnet:React.FocusEventHandler) => void | | called like input's on blur | +| onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | +| onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | +| onKeyDown | (event:React.KeyboardEventHandler) => void | | input on keydown event | +| disableKey | Array | | disable default key for keydown event, available only for key 'ENTER', 'TAB', & 'ESC' | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### PickerPanel @@ -102,7 +104,7 @@ render(, mountNode); | renderExtraFooter | (mode) => React.Node | | extra footer | | onSelect | Function(date: moment) | | a callback function, can be executed when the selected time | | onPanelChange | Function(value: moment, mode) | | callback when picker panel mode is changed | -| onMouseDown | (evnet:React.MouseEventHandler) => void | | callback when executed onMouseDown evnent | +| onMouseDown | (event:React.MouseEventHandler) => void | | callback when executed onMouseDown evnent | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### RangePicker diff --git a/examples/basic.tsx b/examples/basic.tsx index 7885a2ec1..2c4e81032 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -29,6 +29,10 @@ export default () => { onChange, }; + const keyDown = (e) => { + console.log(e.keyCode); + }; + return (

Value: {value ? value.format('YYYY-MM-DD HH:mm:ss') : 'null'}

@@ -125,6 +129,16 @@ export default () => {

Keyboard navigation (Tab key) disabled

{...sharedProps} locale={enUS} tabIndex={-1} />
+
+

Keyboard event with disabled key

+ + {...sharedProps} + locale={enUS} + onKeyDown={keyDown} + disableKey={['ENTER']} + tabIndex={-1} + /> +
); From 0393c4e4854d544e22e425c88fe97a29cece2e21 Mon Sep 17 00:00:00 2001 From: Benny Date: Sat, 5 Sep 2020 16:54:15 +0800 Subject: [PATCH 3/9] remove disableKey --- README.md | 1 - examples/basic.tsx | 10 ++-------- src/Picker.tsx | 6 ------ src/RangePicker.tsx | 3 --- src/hooks/usePickerInput.ts | 36 ++++++++++++++---------------------- 5 files changed, 16 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 6c7697e42..46fd50c87 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ render(, mountNode); | onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | | onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | | onKeyDown | (event:React.KeyboardEventHandler) => void | | input on keydown event | -| disableKey | Array | | disable default key for keydown event, available only for key 'ENTER', 'TAB', & 'ESC' | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### PickerPanel diff --git a/examples/basic.tsx b/examples/basic.tsx index 2c4e81032..7a2afc238 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -29,7 +29,7 @@ export default () => { onChange, }; - const keyDown = (e) => { + const keyDown = e => { console.log(e.keyCode); }; @@ -131,13 +131,7 @@ export default () => {

Keyboard event with disabled key

- - {...sharedProps} - locale={enUS} - onKeyDown={keyDown} - disableKey={['ENTER']} - tabIndex={-1} - /> + {...sharedProps} locale={enUS} onKeyDown={keyDown} tabIndex={-1} />
diff --git a/src/Picker.tsx b/src/Picker.tsx index 9eadc9894..3d28c1d95 100644 --- a/src/Picker.tsx +++ b/src/Picker.tsx @@ -79,10 +79,6 @@ export interface PickerSharedProps extends React.AriaAttributes { onContextMenu?: React.MouseEventHandler; onKeyDown?: (e) => void; - // keyboard key disable options - // array => ['ENTER', 'TAB', 'ESC'] - disableKey?: Array; - // Internal /** @private Internal usage, do not use in production mode!!! */ pickerRef?: React.MutableRefObject; @@ -176,7 +172,6 @@ function InnerPicker(props: PickerProps) { onContextMenu, onClick, onKeyDown, - disableKey, direction, autoComplete = 'off', } = props as MergedPickerProps; @@ -315,7 +310,6 @@ function InnerPicker(props: PickerProps) { onKeyDown: e => { if (onKeyDown) onKeyDown(e); }, - disableKey, onFocus, onBlur, }); diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index 5977453b3..507db74d6 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -209,7 +209,6 @@ function InnerRangePicker(props: RangePickerProps) { onBlur, onOk, onKeyDown, - disableKey, components, order, direction, @@ -609,7 +608,6 @@ function InnerRangePicker(props: RangePickerProps) { onKeyDown: e => { if (onKeyDown) onKeyDown(e); }, - disableKey, }); const [endInputProps, { focused: endFocused, typing: endTyping }] = usePickerInput({ @@ -619,7 +617,6 @@ function InnerRangePicker(props: RangePickerProps) { onKeyDown: e => { if (onKeyDown) onKeyDown(e); }, - disableKey, }); // ========================== Click Picker ========================== diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 230999521..2df98e81b 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -10,7 +10,6 @@ export default function usePickerInput({ triggerOpen, forwardKeyDown, onKeyDown, - disableKey, blurToCancel, onSubmit, onCancel, @@ -23,7 +22,6 @@ export default function usePickerInput({ triggerOpen: (open: boolean) => void; forwardKeyDown: (e: React.KeyboardEvent) => boolean; onKeyDown: (e: React.KeyboardEvent) => void; - disableKey?: Array; blurToCancel?: boolean; onSubmit: () => void | boolean; onCancel: () => void; @@ -53,38 +51,32 @@ export default function usePickerInput({ switch (e.which) { case KeyCode.ENTER: { - if (!disableKey || !disableKey.includes('ENTER')) { - if (!open) { - triggerOpen(true); - } else if (onSubmit() !== false) { - setTyping(true); - } - - e.preventDefault(); + if (!open) { + triggerOpen(true); + } else if (onSubmit() !== false) { + setTyping(true); } + + e.preventDefault(); return; } case KeyCode.TAB: { - if (!disableKey || !disableKey.includes('TAB')) { - if (typing && open && !e.shiftKey) { - setTyping(false); + if (typing && open && !e.shiftKey) { + setTyping(false); + e.preventDefault(); + } else if (!typing && open) { + if (!forwardKeyDown(e) && e.shiftKey) { + setTyping(true); e.preventDefault(); - } else if (!typing && open) { - if (!forwardKeyDown(e) && e.shiftKey) { - setTyping(true); - e.preventDefault(); - } } } return; } case KeyCode.ESC: { - if (!disableKey || !disableKey.includes('ESC')) { - setTyping(true); - onCancel(); - } + setTyping(true); + onCancel(); return; } } From f9e85f01dfc76a626176cabc51c090d432a33048 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 15 Sep 2020 10:07:58 +0800 Subject: [PATCH 4/9] update onkeydown preventDefaultBehaviors on Picker update readme update basic example --- README.md | 2 +- examples/basic.tsx | 5 +-- src/Picker.tsx | 22 ++++++------ src/hooks/usePickerInput.ts | 69 ++++++++++++++++++++----------------- 4 files changed, 53 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 46fd50c87..4094a8cc0 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ render(, mountNode); | onOpenChange | Function(open:boolean) | | called when open/close picker | | onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | | onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | -| onKeyDown | (event:React.KeyboardEventHandler) => void | | input on keydown event | +| onKeyDown | (event:React.KeyboardEventHandler, preventDefaultBehaviors:void) => void | | input on keydown event | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### PickerPanel diff --git a/examples/basic.tsx b/examples/basic.tsx index 7a2afc238..c0120b9f6 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -29,7 +29,8 @@ export default () => { onChange, }; - const keyDown = e => { + const keyDown = (e, preventDefaultBehaviors) => { + preventDefaultBehaviors(); console.log(e.keyCode); }; @@ -64,7 +65,7 @@ export default () => { defaultValue: moment('11:28:39', 'HH:mm:ss'), }} showToday - disabledTime={date => { + disabledTime={(date) => { if (date && date.isSame(defaultValue, 'date')) { return { disabledHours: () => [1, 3, 5, 7, 9, 11], diff --git a/src/Picker.tsx b/src/Picker.tsx index 3d28c1d95..7977a0179 100644 --- a/src/Picker.tsx +++ b/src/Picker.tsx @@ -77,7 +77,7 @@ export interface PickerSharedProps extends React.AriaAttributes { onMouseLeave?: React.MouseEventHandler; onClick?: React.MouseEventHandler; onContextMenu?: React.MouseEventHandler; - onKeyDown?: (e) => void; + onKeyDown?: (e, preventDefaultBehaviors) => void; // Internal /** @private Internal usage, do not use in production mode!!! */ @@ -205,8 +205,8 @@ function InnerPicker(props: PickerProps) { const [mergedOpen, triggerInnerOpen] = useMergedState(false, { value: open, defaultValue: defaultOpen, - postState: postOpen => (disabled ? false : postOpen), - onChange: newOpen => { + postState: (postOpen) => (disabled ? false : postOpen), + onChange: (newOpen) => { if (onOpenChange) { onOpenChange(newOpen); } @@ -226,7 +226,7 @@ function InnerPicker(props: PickerProps) { const [text, triggerTextChange, resetText] = useTextValueMapping({ valueTexts, - onTextChange: newText => { + onTextChange: (newText) => { const inputDate = generateConfig.locale.parse(locale.locale, newText, formatList); if (inputDate && (!disabledDate || !disabledDate(inputDate))) { setSelectedValue(inputDate); @@ -290,7 +290,7 @@ function InnerPicker(props: PickerProps) { value: text, triggerOpen, forwardKeyDown, - isClickOutside: target => + isClickOutside: (target) => !elementsContains([panelDivRef.current, inputDivRef.current], target as HTMLElement), onSubmit: () => { if (disabledDate && disabledDate(selectedValue)) { @@ -307,8 +307,8 @@ function InnerPicker(props: PickerProps) { setSelectedValue(mergedValue); resetText(); }, - onKeyDown: e => { - if (onKeyDown) onKeyDown(e); + onKeyDown: (e, preventDefaultBehaviors) => { + if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); }, onFocus, onBlur, @@ -389,7 +389,7 @@ function InnerPicker(props: PickerProps) { const panel = (
{ + onMouseDown={(e) => { e.preventDefault(); }} > @@ -406,11 +406,11 @@ function InnerPicker(props: PickerProps) { if (allowClear && mergedValue && !disabled) { clearNode = ( { + onMouseDown={(e) => { e.preventDefault(); e.stopPropagation(); }} - onMouseUp={e => { + onMouseUp={(e) => { e.preventDefault(); e.stopPropagation(); triggerChange(null); @@ -498,7 +498,7 @@ function InnerPicker(props: PickerProps) { disabled={disabled} readOnly={inputReadOnly || !typing} value={hoverValue || text} - onChange={e => { + onChange={(e) => { triggerTextChange(e.target.value); }} autoFocus={autoFocus} diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 2df98e81b..4800e88b4 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -21,7 +21,7 @@ export default function usePickerInput({ isClickOutside: (clickElement: EventTarget | null) => boolean; triggerOpen: (open: boolean) => void; forwardKeyDown: (e: React.KeyboardEvent) => boolean; - onKeyDown: (e: React.KeyboardEvent) => void; + onKeyDown: (e: React.KeyboardEvent, preventDefaultBehaviors) => void; blurToCancel?: boolean; onSubmit: () => void | boolean; onCancel: () => void; @@ -30,6 +30,7 @@ export default function usePickerInput({ }): [React.DOMAttributes, { focused: boolean; typing: boolean }] { const [typing, setTyping] = useState(false); const [focused, setFocused] = useState(false); + const [preventDefault, setPreventDefault] = useState(false); /** * We will prevent blur to handle open event when user click outside, @@ -46,46 +47,52 @@ export default function usePickerInput({ }, onKeyDown: e => { if (onKeyDown) { - onKeyDown(e); - } + const preventDefaultBehaviors = () => { + setPreventDefault(true); + }; - switch (e.which) { - case KeyCode.ENTER: { - if (!open) { - triggerOpen(true); - } else if (onSubmit() !== false) { - setTyping(true); - } + onKeyDown(e, preventDefaultBehaviors); + } - e.preventDefault(); - return; - } + if(preventDefault === false) { + switch (e.which) { + case KeyCode.ENTER: { + if (!open) { + triggerOpen(true); + } else if (onSubmit() !== false) { + setTyping(true); + } - case KeyCode.TAB: { - if (typing && open && !e.shiftKey) { - setTyping(false); e.preventDefault(); - } else if (!typing && open) { - if (!forwardKeyDown(e) && e.shiftKey) { - setTyping(true); + return; + } + + case KeyCode.TAB: { + if (typing && open && !e.shiftKey) { + setTyping(false); e.preventDefault(); + } else if (!typing && open) { + if (!forwardKeyDown(e) && e.shiftKey) { + setTyping(true); + e.preventDefault(); + } } + return; } - return; - } - case KeyCode.ESC: { - setTyping(true); - onCancel(); - return; + case KeyCode.ESC: { + setTyping(true); + onCancel(); + return; + } } - } - if (!open && ![KeyCode.SHIFT].includes(e.which)) { - triggerOpen(true); - } else if (!typing) { - // Let popup panel handle keyboard - forwardKeyDown(e); + if (!open && ![KeyCode.SHIFT].includes(e.which)) { + triggerOpen(true); + } else if (!typing) { + // Let popup panel handle keyboard + forwardKeyDown(e); + } } }, From d006cfc2b9be7491aadb42efc3a02a6d53e93c65 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 15 Sep 2020 11:10:32 +0800 Subject: [PATCH 5/9] fix range picker onKeyDown fix preventDefaultBehaviors types --- src/RangePicker.tsx | 8 ++++---- src/hooks/usePickerInput.ts | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index 37cd071e0..476b43f50 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -605,8 +605,8 @@ function InnerRangePicker(props: RangePickerProps) { ...getSharedInputHookProps(0, resetStartText), open: startOpen, value: startText, - onKeyDown: e => { - if (onKeyDown) onKeyDown(e); + onKeyDown: (e, preventDefaultBehaviors) => { + if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); }, }); @@ -614,8 +614,8 @@ function InnerRangePicker(props: RangePickerProps) { ...getSharedInputHookProps(1, resetEndText), open: endOpen, value: endText, - onKeyDown: e => { - if (onKeyDown) onKeyDown(e); + onKeyDown: (e, preventDefaultBehaviors) => { + if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); }, }); diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 4800e88b4..262b8c375 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -21,7 +21,10 @@ export default function usePickerInput({ isClickOutside: (clickElement: EventTarget | null) => boolean; triggerOpen: (open: boolean) => void; forwardKeyDown: (e: React.KeyboardEvent) => boolean; - onKeyDown: (e: React.KeyboardEvent, preventDefaultBehaviors) => void; + onKeyDown: ( + e: React.KeyboardEvent, + preventDefaultBehaviors: () => void, + ) => void; blurToCancel?: boolean; onSubmit: () => void | boolean; onCancel: () => void; @@ -47,14 +50,14 @@ export default function usePickerInput({ }, onKeyDown: e => { if (onKeyDown) { - const preventDefaultBehaviors = () => { + const preventDefaultBehaviors = (): void => { setPreventDefault(true); }; onKeyDown(e, preventDefaultBehaviors); } - if(preventDefault === false) { + if (preventDefault === false) { switch (e.which) { case KeyCode.ENTER: { if (!open) { From 5b298820a433b9101853c171dcee6d5fcb026251 Mon Sep 17 00:00:00 2001 From: Benny Date: Fri, 18 Dec 2020 11:36:15 +0800 Subject: [PATCH 6/9] update picker input preventdefault (state to ref) update examples add test case for prevent default apply @kerm1it suggestions --- README.md | 2 +- examples/basic.tsx | 7 ++-- src/Picker.tsx | 4 +-- src/RangePicker.tsx | 4 +-- src/hooks/usePickerInput.ts | 69 +++++++++++++++++++------------------ tests/picker.spec.tsx | 27 +++++++++++++++ 6 files changed, 70 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index e9b8d89f4..bae58c90e 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ render(, mountNode); | onOpenChange | Function(open:boolean) | | called when open/close picker | | onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | | onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | -| onKeyDown | (event:React.KeyboardEventHandler, preventDefaultBehaviors:void) => void | | input on keydown event | +| onKeyDown | (event:React.KeyboardEventHandler, preventDefault:void) => void | | input on keydown event | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### PickerPanel diff --git a/examples/basic.tsx b/examples/basic.tsx index c0120b9f6..52b986076 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -30,8 +30,7 @@ export default () => { }; const keyDown = (e, preventDefaultBehaviors) => { - preventDefaultBehaviors(); - console.log(e.keyCode); + if(e.keyCode === 13) preventDefaultBehaviors(); }; return ( @@ -65,7 +64,7 @@ export default () => { defaultValue: moment('11:28:39', 'HH:mm:ss'), }} showToday - disabledTime={(date) => { + disabledTime={date => { if (date && date.isSame(defaultValue, 'date')) { return { disabledHours: () => [1, 3, 5, 7, 9, 11], @@ -132,7 +131,7 @@ export default () => {

Keyboard event with disabled key

- {...sharedProps} locale={enUS} onKeyDown={keyDown} tabIndex={-1} /> + {...sharedProps} locale={enUS} onKeyDown={keyDown} />
diff --git a/src/Picker.tsx b/src/Picker.tsx index b6d8b440d..769c693a9 100644 --- a/src/Picker.tsx +++ b/src/Picker.tsx @@ -312,8 +312,8 @@ function InnerPicker(props: PickerProps) { setSelectedValue(mergedValue); resetText(); }, - onKeyDown: (e, preventDefaultBehaviors) => { - if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); + onKeyDown: (e, preventDefault) => { + onKeyDown?.(e, preventDefault); }, onFocus, onBlur, diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index 1b52cd590..d38a9232e 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -611,8 +611,8 @@ function InnerRangePicker(props: RangePickerProps) { ...getSharedInputHookProps(0, resetStartText), open: startOpen, value: startText, - onKeyDown: (e, preventDefaultBehaviors) => { - if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); + onKeyDown: (e, preventDefault) => { + onKeyDown?.(e, preventDefault); }, }); diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 262b8c375..8c78674d9 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -33,7 +33,6 @@ export default function usePickerInput({ }): [React.DOMAttributes, { focused: boolean; typing: boolean }] { const [typing, setTyping] = useState(false); const [focused, setFocused] = useState(false); - const [preventDefault, setPreventDefault] = useState(false); /** * We will prevent blur to handle open event when user click outside, @@ -43,6 +42,8 @@ export default function usePickerInput({ const valueChangedRef = useRef(false); + const preventDefaultRef = useRef(false); + const inputProps: React.DOMAttributes = { onMouseDown: () => { setTyping(true); @@ -50,53 +51,53 @@ export default function usePickerInput({ }, onKeyDown: e => { if (onKeyDown) { - const preventDefaultBehaviors = (): void => { - setPreventDefault(true); + const preventDefault = (): void => { + preventDefaultRef.current = true; }; - onKeyDown(e, preventDefaultBehaviors); + onKeyDown(e, preventDefault); } - if (preventDefault === false) { - switch (e.which) { - case KeyCode.ENTER: { - if (!open) { - triggerOpen(true); - } else if (onSubmit() !== false) { - setTyping(true); - } + if (preventDefaultRef.current) return; - e.preventDefault(); - return; + switch (e.which) { + case KeyCode.ENTER: { + if (!open) { + triggerOpen(true); + } else if (onSubmit() !== false) { + setTyping(true); } - case KeyCode.TAB: { - if (typing && open && !e.shiftKey) { - setTyping(false); + e.preventDefault(); + return; + } + + case KeyCode.TAB: { + if (typing && open && !e.shiftKey) { + setTyping(false); + e.preventDefault(); + } else if (!typing && open) { + if (!forwardKeyDown(e) && e.shiftKey) { + setTyping(true); e.preventDefault(); - } else if (!typing && open) { - if (!forwardKeyDown(e) && e.shiftKey) { - setTyping(true); - e.preventDefault(); - } } - return; - } - - case KeyCode.ESC: { - setTyping(true); - onCancel(); - return; } + return; } - if (!open && ![KeyCode.SHIFT].includes(e.which)) { - triggerOpen(true); - } else if (!typing) { - // Let popup panel handle keyboard - forwardKeyDown(e); + case KeyCode.ESC: { + setTyping(true); + onCancel(); + return; } } + + if (!open && ![KeyCode.SHIFT].includes(e.which)) { + triggerOpen(true); + } else if (!typing) { + // Let popup panel handle keyboard + forwardKeyDown(e); + } }, onFocus: e => { diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index a177aab0b..966322ff2 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -866,4 +866,31 @@ describe('Picker.Basic', () => { wrapper.unmount(); }); }); + + describe('prevent default on keydown', () => { + it('should open picker panel if no prevent default', () => { + const keyDown = jest.fn(); + const wrapper = mount(); + + wrapper.closePicker(); + wrapper.keyDown(KeyCode.ENTER); + expect(wrapper.isOpen()).toBeTruthy(); + }); + + it('should not open if prevent default is called', () => { + const keyDown = jest.fn(({ which }, preventDefault) => { + if(which === 13) preventDefault(); + }); + const wrapper = mount(); + + wrapper.openPicker(); + expect(wrapper.isOpen()).toBeTruthy(); + + wrapper.keyDown(KeyCode.ESC); + expect(wrapper.isOpen()).toBeFalsy(); + + wrapper.keyDown(KeyCode.ENTER); + expect(wrapper.isOpen()).toBeFalsy(); + }); + }) }); From b797c1ad4bce32294680f4b4ce43c46fbb1e156c Mon Sep 17 00:00:00 2001 From: Benny Date: Fri, 18 Dec 2020 15:48:52 +0800 Subject: [PATCH 7/9] update on key down event type rename all preventDefaultBehaviors to preventDefault apply @kerm1it suggestions --- README.md | 2 +- examples/basic.tsx | 4 ++-- src/Picker.tsx | 2 +- src/RangePicker.tsx | 4 ++-- src/hooks/usePickerInput.ts | 12 +++++------- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index bae58c90e..e0af3f08e 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ render(, mountNode); | onOpenChange | Function(open:boolean) | | called when open/close picker | | onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | | onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | -| onKeyDown | (event:React.KeyboardEventHandler, preventDefault:void) => void | | input on keydown event | +| onKeyDown | (event:React.KeyboardEvent, preventDefault: () => void) => void | | input on keydown event | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### PickerPanel diff --git a/examples/basic.tsx b/examples/basic.tsx index 52b986076..9e26bc8ff 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -29,8 +29,8 @@ export default () => { onChange, }; - const keyDown = (e, preventDefaultBehaviors) => { - if(e.keyCode === 13) preventDefaultBehaviors(); + const keyDown = (e, preventDefault) => { + if(e.keyCode === 13) preventDefault(); }; return ( diff --git a/src/Picker.tsx b/src/Picker.tsx index 769c693a9..6201b91b6 100644 --- a/src/Picker.tsx +++ b/src/Picker.tsx @@ -77,7 +77,7 @@ export interface PickerSharedProps extends React.AriaAttributes { onMouseLeave?: React.MouseEventHandler; onClick?: React.MouseEventHandler; onContextMenu?: React.MouseEventHandler; - onKeyDown?: (e, preventDefaultBehaviors) => void; + onKeyDown?: (event: React.KeyboardEvent, preventDefault: () => void) => void; // Internal /** @private Internal usage, do not use in production mode!!! */ diff --git a/src/RangePicker.tsx b/src/RangePicker.tsx index d38a9232e..5a7ab6571 100644 --- a/src/RangePicker.tsx +++ b/src/RangePicker.tsx @@ -620,8 +620,8 @@ function InnerRangePicker(props: RangePickerProps) { ...getSharedInputHookProps(1, resetEndText), open: endOpen, value: endText, - onKeyDown: (e, preventDefaultBehaviors) => { - if (onKeyDown) onKeyDown(e, preventDefaultBehaviors); + onKeyDown: (e, preventDefault) => { + onKeyDown?.(e, preventDefault); }, }); diff --git a/src/hooks/usePickerInput.ts b/src/hooks/usePickerInput.ts index 8c78674d9..6f2fa8a81 100644 --- a/src/hooks/usePickerInput.ts +++ b/src/hooks/usePickerInput.ts @@ -23,7 +23,7 @@ export default function usePickerInput({ forwardKeyDown: (e: React.KeyboardEvent) => boolean; onKeyDown: ( e: React.KeyboardEvent, - preventDefaultBehaviors: () => void, + preventDefault: () => void, ) => void; blurToCancel?: boolean; onSubmit: () => void | boolean; @@ -50,13 +50,11 @@ export default function usePickerInput({ triggerOpen(true); }, onKeyDown: e => { - if (onKeyDown) { - const preventDefault = (): void => { - preventDefaultRef.current = true; - }; + const preventDefault = (): void => { + preventDefaultRef.current = true; + }; - onKeyDown(e, preventDefault); - } + onKeyDown(e, preventDefault); if (preventDefaultRef.current) return; From 14b1814fd90c319f4d7bc2de9bf5b76d2609f8ce Mon Sep 17 00:00:00 2001 From: Benny Date: Fri, 18 Dec 2020 17:23:47 +0800 Subject: [PATCH 8/9] rename focuseventhandler and mouseeventhandler --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e0af3f08e..d3b2e29ae 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# rc-picker +# rc-picker [![NPM version][npm-image]][npm-url] [![build status][github-actions-image]][github-actions-url] @@ -76,8 +76,8 @@ render(, mountNode); | getPopupContainer | function(trigger) | | to set the container of the floating layer, while the default is to create a div element in body | | onChange | Function(date: moment, dateString: string) | | a callback function, can be executed when the selected time is changing | | onOpenChange | Function(open:boolean) | | called when open/close picker | -| onFocus | (event:React.FocusEventHandler) => void | | called like input's on focus | -| onBlur | (event:React.FocusEventHandler) => void | | called like input's on blur | +| onFocus | (event:React.FocusEvent) => void | | called like input's on focus | +| onBlur | (event:React.FocusEvent) => void | | called like input's on blur | | onKeyDown | (event:React.KeyboardEvent, preventDefault: () => void) => void | | input on keydown event | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | @@ -103,7 +103,7 @@ render(, mountNode); | renderExtraFooter | (mode) => React.Node | | extra footer | | onSelect | Function(date: moment) | | a callback function, can be executed when the selected time | | onPanelChange | Function(value: moment, mode) | | callback when picker panel mode is changed | -| onMouseDown | (event:React.MouseEventHandler) => void | | callback when executed onMouseDown evnent | +| onMouseDown | (event:React.MouseEvent) => void | | callback when executed onMouseDown evnent | | direction | String: ltr or rtl | | Layout direction of picker component, it supports RTL direction too. | ### RangePicker From c490761e6cccd8a38156bf5ec9ea1c1cd0c35118 Mon Sep 17 00:00:00 2001 From: Benny Date: Fri, 18 Dec 2020 19:42:00 +0800 Subject: [PATCH 9/9] update example caption for on keydown --- examples/basic.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/basic.tsx b/examples/basic.tsx index 9e26bc8ff..a68704a96 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -30,7 +30,7 @@ export default () => { }; const keyDown = (e, preventDefault) => { - if(e.keyCode === 13) preventDefault(); + if (e.keyCode === 13) preventDefault(); }; return ( @@ -130,7 +130,7 @@ export default () => { {...sharedProps} locale={enUS} tabIndex={-1} />
-

Keyboard event with disabled key

+

Keyboard event with prevent default behaviors

{...sharedProps} locale={enUS} onKeyDown={keyDown} />