-
Notifications
You must be signed in to change notification settings - Fork 37
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
base: master
Are you sure you want to change the base?
feat: support keyborad event for Tour steps #86
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Walkthrough为 Tour 组件新增键盘导航能力:新增可选属性 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as 用户
participant KB as 键盘事件
participant Tour as Tour 组件
participant Host as 调用方(回调)
rect rgba(227,242,253,0.5)
Note over Tour: 当 Tour.open === true 且 keyboard 为 true 时注册键盘处理器
end
User->>KB: 按键 (Esc / ArrowLeft / ArrowRight)
KB->>Tour: keyboardHandler(event)
alt Esc
Tour->>Tour: 调用 handleClose()
Tour->>Host: onClose()
else ArrowLeft/ArrowRight
Tour->>Tour: 计算目标步骤索引
Tour->>Host: onInternalChange(nextIndex)
Tour->>Host: onChange(nextIndex) (如有外部绑定)
end
rect rgba(232,245,233,0.5)
Note over Tour: 当 open 为 false 或卸载时注销键盘处理器
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
Summary of ChangesHello @cactuser-Lu, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求通过引入键盘事件支持,显著提升了 Tour 组件的用户体验和可访问性。现在用户可以通过键盘快捷键关闭 Tour 或在不同步骤之间切换,这使得交互更加流畅和便捷。 Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This pull request introduces keyboard navigation to the Tour component, which is a great enhancement for accessibility. The implementation is well done. I have one suggestion to refactor the keyboard event handler to use modern browser APIs and improve its structure, which should also fix a minor bug. Additionally, there's a small typo in the pull request title ('keyborad' should be 'keyboard').
const keyboardHandler = useEvent((e: KeyboardEvent) => { | ||
if (keyboard && e.keyCode === KeyCode.ESC) { | ||
if (mergedClosable !== null) { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
handleClose(); | ||
} | ||
return; | ||
} | ||
|
||
if (keyboard && e.keyCode === KeyCode.LEFT) { | ||
if (mergedCurrent > 0) { | ||
e.preventDefault(); | ||
onInternalChange(mergedCurrent - 1); | ||
} | ||
return; | ||
} | ||
|
||
if (keyboard && e.keyCode === KeyCode.RIGHT) { | ||
e.preventDefault(); | ||
if (mergedCurrent < steps.length - 1) { | ||
onInternalChange(mergedCurrent + 1); | ||
} | ||
return; | ||
} | ||
}); |
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.
The keyboard handler implementation can be improved for better readability, correctness, and to adhere to modern web standards.
- Use
e.key
instead ofe.keyCode
: ThekeyCode
property is deprecated. It's better to usee.key
for future-proofing and consistency with modern web APIs. This change would also allow for the removal of theKeyCode
import. - Conditional
preventDefault
: Thee.preventDefault()
for the right arrow key is called unconditionally. It should only be called when the step actually changes (i.e., inside theif
block), similar to the logic for the left arrow key. This prevents blocking the default browser behavior when at the last step. - Improved Structure: A
switch
statement one.key
would be more readable and maintainable than a series ofif
statements. Theif (keyboard)
check can also be done once at the beginning of the function.
Here is a suggested refactoring that applies these points:
const keyboardHandler = useEvent((e: KeyboardEvent) => {
if (!keyboard) {
return;
}
switch (e.key) {
case 'Escape':
if (mergedClosable !== null) {
e.stopPropagation();
e.preventDefault();
handleClose();
}
break;
case 'ArrowLeft':
if (mergedCurrent > 0) {
e.preventDefault();
onInternalChange(mergedCurrent - 1);
}
break;
case 'ArrowRight':
if (mergedCurrent < steps.length - 1) {
e.preventDefault();
onInternalChange(mergedCurrent + 1);
}
break;
default:
// Do nothing
break;
}
});
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.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/interface.ts (1)
61-61
: 建议添加 JSDoc 注释说明 keyboard 属性的用途。新增的
keyboard
属性缺少文档注释,建议添加说明以提高 API 的可读性和可维护性。例如:open?: boolean; + /** Whether to enable keyboard interaction (Esc to close, Left/Right to navigate). Default: true */ keyboard?: boolean; defaultOpen?: boolean;
src/Tour.tsx (1)
195-201
: 考虑使用useEffect
代替useLayoutEffect
。事件监听器的注册和清理逻辑正确,依赖项数组也准确。但是,对于键盘事件监听器的注册,使用
useEffect
而非useLayoutEffect
更合适,因为这个操作不需要在浏览器绘制之前同步执行,使用useEffect
可以避免阻塞视觉更新。建议修改:
- useLayoutEffect(() => { + useEffect(() => { if (!mergedOpen) return; window.addEventListener('keydown', keyboardHandler); return () => { window.removeEventListener('keydown', keyboardHandler); }; }, [mergedOpen, keyboardHandler]);注意:需要在文件顶部添加
useEffect
的导入:- import { useMemo } from 'react'; + import { useMemo, useEffect } from 'react';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Tour.tsx
(4 hunks)src/interface.ts
(1 hunks)
🔇 Additional comments (3)
src/Tour.tsx (3)
7-8
: 代码更改看起来不错!正确引入了
useEvent
和KeyCode
工具,用于实现键盘事件处理。
39-39
: 代码更改看起来不错!
keyboard
属性默认值为true
是合理的设计,既启用了新功能,又保持了向后兼容性。
161-164
: 代码更改看起来不错!将关闭逻辑提取为
handleClose
函数是良好的代码组织实践,便于在多处复用(键盘处理、按钮点击、完成回调)。
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.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/Tour.tsx (1)
168-204
: 建议采用现代 API 并改进代码结构。当前实现已经解决了之前评审中关于
preventDefault
调用时机和输入元素过滤的问题,这很好!但仍有改进空间:
- 使用
e.key
替代e.keyCode
:keyCode
已被弃用,应使用e.key
以符合现代 Web 标准。- 使用
switch
语句:相比多个if
语句,switch
语句可读性和可维护性更好。应用以下差异来改进实现:
const keyboardHandler = useEvent((e: KeyboardEvent) => { // Ignore keyboard events from input-like elements to avoid interfering when typing const el = e.target as HTMLElement | null; if ( el?.tagName === 'INPUT' || el?.tagName === 'TEXTAREA' || el?.tagName === 'SELECT' || el?.isContentEditable ) { return; } - if (keyboard && e.keyCode === KeyCode.ESC) { - if (mergedClosable !== null) { - e.stopPropagation(); - e.preventDefault(); - handleClose(); - } - return; - } - - if (keyboard && e.keyCode === KeyCode.LEFT) { - if (mergedCurrent > 0) { - e.preventDefault(); - onInternalChange(mergedCurrent - 1); - } - return; - } - - if (keyboard && e.keyCode === KeyCode.RIGHT) { - if (mergedCurrent < steps.length - 1) { - e.preventDefault(); - onInternalChange(mergedCurrent + 1); - } - return; - } + if (!keyboard) { + return; + } + + switch (e.key) { + case 'Escape': + if (mergedClosable !== null) { + e.stopPropagation(); + e.preventDefault(); + handleClose(); + } + break; + case 'ArrowLeft': + if (mergedCurrent > 0) { + e.preventDefault(); + onInternalChange(mergedCurrent - 1); + } + break; + case 'ArrowRight': + if (mergedCurrent < steps.length - 1) { + e.preventDefault(); + onInternalChange(mergedCurrent + 1); + } + break; + default: + break; + } });
🧹 Nitpick comments (1)
src/Tour.tsx (1)
7-8
: 建议使用现代的e.key
API 替代已弃用的KeyCode
。
KeyCode
已被弃用,建议使用e.key
属性来检测按键。这样可以移除对KeyCode
的导入依赖,并使代码更符合现代 Web 标准。应用以下差异以移除
KeyCode
导入:import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect'; 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';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/Tour.tsx
(4 hunks)
🔇 Additional comments (4)
src/Tour.tsx (4)
39-39
: 默认启用键盘支持是合理的设计!将
keyboard
默认设置为true
符合渐进增强原则,为大多数用户提供更好的可访问性体验。
93-93
: 依赖项更新正确!将
setMergedCurrent
添加到依赖数组中符合 React Hooks 的最佳实践,即使该函数引用通常是稳定的。
161-164
: 提取handleClose
函数提高了代码复用性!将关闭逻辑提取为独立函数是良好的重构实践,使得键盘处理和按钮点击可以共享相同的关闭逻辑。
206-212
: 事件监听器的注册和清理实现正确!使用
useLayoutEffect
在 tour 打开时注册全局键盘事件监听器,并在关闭或组件卸载时正确清理,避免了内存泄漏。
🤔 This is a ...
支持键盘 Esc 关闭 \左右切换
Summary by CodeRabbit