fix: wrong focus behavior when configuring menu selectability
This PR fixes issue https://github.com/ant-design/ant-design/issues/53495
Determine the focus key based on the selectable configuration:
If the item is not selectable, focus the default item.
If the item is selectable, decide whether to focus based on whether there is already a selected item.
Summary by CodeRabbit
-
Bug Fixes
- 优化菜单组件焦点选择与聚焦行为:当支持可选项时优先聚焦已选项(若存在且有效),否则回退到活跃项或计算的默认焦点;当不支持可选项时始终使用计算的默认焦点,简化并统一聚焦优先级与回退逻辑。
-
Tests
- 新增针对可选/不可选场景的焦点交互测试,覆盖键盘导航与点击、聚焦顺序与 focus 调用验证。
[!NOTE]
Other AI code review bot(s) detected
CodeRabbit 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
修改 Menu 的聚焦与选中状态处理:引入并合并 select 键(internalSelectKeys / mergedSelectKeys),在 focus 流程中当 selectable 为 true 时优先聚焦首个选中键,否则尝试 mergedActiveKey,再回退到计算的默认焦点键;补充/调整相关单元测试覆盖行为。
Changes
| Cohort / File(s) | 变更摘要 |
|---|---|
菜单焦点与选中逻辑 src/Menu.tsx |
引入内部 select 状态(internalSelectKeys)与合并键(mergedSelectKeys);重构 useImperativeHandle 中的 focus 流程:当 selectable === true 时优先使用第一个有效的 select 键,失败则尝试 mergedActiveKey,最终回退到 defaultFocusKey;当 selectable === false 时直接使用 defaultFocusKey。移除重复的 select 状态声明并合并处理位置。 |
焦点行为测试 tests/Focus.spec.tsx |
新增键盘事件辅助 keyDown(含 SubMenu 动画推进)并引入 KeyCode 与本地 isActive,添加两组测试验证在 selectable 为 false/true 时的聚焦与交互(DOWN/ENTER/点击)行为,通过 spy 检查元素 focus() 调用。 |
Sequence Diagram(s)
sequenceDiagram
participant User as 用户
participant Menu as Menu 组件
participant Keys as 键来源器
participant Focus as DOM.focus
User->>Menu: 触发 menuRef.focus()
Menu->>Keys: 计算候选焦点键
alt selectable == true
Keys->>Keys: 读取 mergedSelectKeys
alt mergedSelectKeys 首项 有效
Keys-->>Menu: 返回 mergedSelectKeys[0] (已选项)
else
Keys->>Keys: 检查 mergedActiveKey
alt mergedActiveKey 有效
Keys-->>Menu: 返回 mergedActiveKey
else
Keys-->>Menu: 返回 defaultFocusKey
end
end
else selectable == false
Keys-->>Menu: 返回 defaultFocusKey
end
Menu->>Focus: 对应元素调用 focus()
Focus-->>Menu: 聚焦完成 / 抛出异常
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 分钟
Possibly related PRs
- react-component/menu#759 — 修改 menu 的 imperative handle(menuRef),添加了 findItem,可能与本次 focus/select 暴露的行为相互影响。
- react-component/menu#793 — 直接修改
src/Menu.tsx中 select 状态与 focus 逻辑,与本次合并 select 键的变更高度相关。 - react-component/menu#791 — 也调整了 focus 选择逻辑(mergedActiveKey / fallback),与本次对 focus 决策路径的改动存在代码层面关联。
Suggested reviewers
- zombieJ
- afc163
诗
🐰 我是跳跃的小兔子,
先寻被选的那一只,
无果便望活跃位,
再无回首初始归,
菜单静好我来庆。
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title Check | ✅ Passed | PR标题"fix: wrong focus behavior when configuring menu selectability"准确反映了本PR的主要变更。根据raw_summary,这个PR的核心是修复Menu组件的焦点行为,使其根据菜单的selectability配置进行条件判断:当selectable为false时焦点移到默认项,当selectable为true时焦点取决于是否有已选中的项。标题直接捕捉了这个核心改进,言简意赅且具体,避免了模糊措辞,使团队成员能够快速理解主要变更意图。 |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
Summary of Changes
Hello @codewizardTM, I'm Gemini Code Assist[^1]! 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!
This pull request addresses and resolves an issue where the menu's focus behavior was incorrect, particularly when the selectable configuration was in use. The changes refine the focus determination logic to ensure that the appropriate menu item is focused based on whether the menu allows selection and if any items are already selected, thereby enhancing the user experience and consistency of the component.
Highlights
-
Improved Focus Behavior: The logic for determining which menu item receives focus has been refactored to correctly account for the
selectableproperty of the menu. -
Conditional Focus Application: When a menu is
selectable, the focus will now only be applied if there are no items already selected, preventing unintended focus shifts. -
Default Focus Key: A
defaultFocusKeyvariable has been introduced to consistently determine the fallback focus target, either the first focusable element or the first non-disabled child. -
Helper Function: A new helper function,
getMergedSelectKeys(), was added to provide access to the current selection state within the focus logic.
Using Gemini Code Assist
The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in pull request comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.
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 :thumbsup: and :thumbsdown: 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.
[^1]: Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.
Codecov Report
:x: Patch coverage is 95.00000% with 1 line in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 99.59%. Comparing base (3ba3f98) to head (62360b5).
| Files with missing lines | Patch % | Lines |
|---|---|---|
| src/Menu.tsx | 95.00% | 1 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## master #818 +/- ##
==========================================
- Coverage 99.72% 99.59% -0.14%
==========================================
Files 26 26
Lines 727 733 +6
Branches 199 202 +3
==========================================
+ Hits 725 730 +5
- Misses 2 3 +1
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
@gemini-code-assist 请再次 CR
@gemini-code-assist 请完整的检测 PR 内容,并且对聚焦可能存在的 edge case 进行分析。
@zombieJ 再帮忙 cr 一下