-
Notifications
You must be signed in to change notification settings - Fork 36
feat: support keyborad event for Tour steps #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,8 @@ import type { TriggerRef } from '@rc-component/trigger'; | |
| import Trigger from '@rc-component/trigger'; | ||
| import { clsx } from 'clsx'; | ||
| import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; | ||
| import useMergedState from '@rc-component/util/lib/hooks/useMergedState'; | ||
| import useEvent from '@rc-component/util/lib/hooks/useEvent'; | ||
| import KeyCode from '@rc-component/util/lib/KeyCode'; | ||
| import useControlledState from '@rc-component/util/lib/hooks/useControlledState'; | ||
| import { useMemo } from 'react'; | ||
| import { useClosable } from './hooks/useClosable'; | ||
|
|
@@ -35,6 +36,7 @@ const Tour: React.FC<TourProps> = props => { | |
| steps = [], | ||
| defaultCurrent, | ||
| current, | ||
| keyboard = true, | ||
| onChange, | ||
| onClose, | ||
| onFinish, | ||
|
|
@@ -88,7 +90,7 @@ const Tour: React.FC<TourProps> = props => { | |
| setHasOpened(true); | ||
| } | ||
| openRef.current = mergedOpen; | ||
| }, [mergedOpen]); | ||
| }, [mergedOpen, setMergedCurrent]); | ||
|
|
||
| const { | ||
| target, | ||
|
|
@@ -156,18 +158,59 @@ const Tour: React.FC<TourProps> = props => { | |
| } | ||
| return getPlacements(arrowPointAtCenter); | ||
| }, [builtinPlacements, arrowPointAtCenter]); | ||
| const handleClose = () => { | ||
| setMergedOpen(false); | ||
| onClose?.(mergedCurrent); | ||
| }; | ||
|
|
||
| // ========================= Esc Close ========================= | ||
| // Use Portal's onEsc to handle Escape key with proper stacking logic | ||
| const handleEscClose = useEvent(({ event }: { top: boolean; event: KeyboardEvent }) => { | ||
| if (keyboard && mergedClosable !== null) { | ||
| event.preventDefault(); | ||
| handleClose(); | ||
| } | ||
| }); | ||
|
|
||
| // ========================= Keyboard ========================= | ||
| // Support ArrowLeft/ArrowRight to navigate steps. | ||
| const keyboardHandler = useEvent((e: KeyboardEvent) => { | ||
| // Ignore keyboard events from input-like elements to avoid interfering when typing | ||
| if (KeyCode.isEditableTarget(e)) { | ||
| return; | ||
| } | ||
|
Comment on lines
+179
to
+181
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里我有个疑问,如果tour里有一些表单,比如input,此时我点击input聚焦后,再按下esc,是不是就直接return了?感觉这个是有点问题的,豆酱老师觉得呢 @zombieJ
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这不是预期的么……输入框里键盘操作都不应该控制 Tour 的切换
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
经讨论,在与表单交互时(非IME),esc依旧能够关闭tour,这个case会在Portal中通过加锁处理 |
||
|
|
||
| if (keyboard && e.key === 'ArrowLeft') { | ||
| if (mergedCurrent > 0) { | ||
| e.preventDefault(); | ||
| onInternalChange(mergedCurrent - 1); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| if (keyboard && e.key === 'ArrowRight') { | ||
| if (mergedCurrent < steps.length - 1) { | ||
| e.preventDefault(); | ||
| onInternalChange(mergedCurrent + 1); | ||
| } | ||
| return; | ||
| } | ||
| }); | ||
|
|
||
| useLayoutEffect(() => { | ||
| if (!mergedOpen) return; | ||
| window.addEventListener('keydown', keyboardHandler); | ||
| return () => { | ||
| window.removeEventListener('keydown', keyboardHandler); | ||
| }; | ||
| }, [mergedOpen, keyboardHandler]); | ||
|
|
||
| // ========================= Render ========================= | ||
| // Skip if not init yet | ||
| if (targetElement === undefined || !hasOpened) { | ||
| return null; | ||
| } | ||
|
|
||
| const handleClose = () => { | ||
| setMergedOpen(false); | ||
| onClose?.(mergedCurrent); | ||
| }; | ||
|
|
||
| const getPopupElement = () => ( | ||
| <TourStep | ||
| styles={styles} | ||
|
|
@@ -220,6 +263,7 @@ const Tour: React.FC<TourProps> = props => { | |
| animated={animated} | ||
| rootClassName={rootClassName} | ||
| disabledInteraction={disabledInteraction} | ||
| onEsc={handleEscClose} | ||
| /> | ||
| <Trigger | ||
| {...restProps} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK