Skip to content
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

fix: The Enter key lock cannot be released correctly when the custom input calls blur(). #1112

Closed
wants to merge 2 commits into from

Conversation

LeeSSHH
Copy link
Contributor

@LeeSSHH LeeSSHH commented Jan 12, 2025

🤔 这个变动的性质是?

  • 🐞 Bug 修复

🔗 相关 Issue

fix: ant-design#52028

💡 需求背景和解决方案

问题:
AutoComplete组件使用自定义Input,在onSelect事件中执行Input的blur(),会导致下次展开备选列表时无法用Enter选中

原因:
按下Enter键 --> 触发onSelect --> 在onSelect里面执行blur() --> 在onKeyDown里面把keyLockRef.current设置为true --> 正常是应该在onKeyUp里面释放锁的,但是因为执行了blur(),导致keyup事件不会触发,所以keyLockRef为true

于是在下次点击enter的时候,由于keyLockRef为true,就不会触发onSelect事件,反而可以正常触发keyup了,在onKeyUp里面释放了keyLockRef,也就是问题描述里的第二次开始需要点击两次Enter键才可以正常用

解决方案:
优化keyLockRef设置为true的时机,在触发onSelect之前设置为true,并给Selector添加一个onBlur的事件处理函数,在onBlur时主动释放keyLockRef

📝 更新日志

语言 更新描述
🇺🇸 英文 fix: The Enter key lock cannot be released correctly when the custom input calls blur().(ant-design#52028)
🇨🇳 中文 fix: 在onSelect中触发自定义Input的blur()时,没有正确释放回车键的keyLockRef。(ant-design#52028)

The Enter key lock cannot be released correctly when the custom input calls blur().

Summary by CodeRabbit

发布说明

  • 新功能

    • 增强了选择器组件的键盘交互逻辑
    • 改进了输入框失焦(blur)事件处理机制
  • 测试

    • 新增了针对选择器组件的测试用例
    • 优化了测试工具函数,提高测试可靠性
  • 改进

    • 优化了Enter键的触发和锁定行为
    • 增加了对自定义输入元素的支持
    • 完善了输入框焦点管理机制

这些更改旨在提升组件的用户交互体验和稳定性。

Copy link

vercel bot commented Jan 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
select ❌ Failed (Inspect) Jan 13, 2025 9:50am

Copy link
Contributor

coderabbitai bot commented Jan 12, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/BaseSelect/index.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: Cannot read config file: /.eslintrc.js
Error: Cannot find module '@umijs/fabric/dist/eslint'
Require stack:

  • /.eslintrc.js
  • /node_modules/.pnpm/@eslint[email protected]/node_modules/@eslint/eslintrc/dist/eslintrc.cjs
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/cli-engine/cli-engine.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/eslint/eslint.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/eslint/index.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/cli.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/bin/eslint.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15)
    at Module._load (node:internal/modules/cjs/loader:1074:27)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
    at Module.require (node:internal/modules/cjs/loader:1339:12)
    at require (node:internal/modules/helpers:135:16)
    at Object. (/.eslintrc.js:1:14)
    at Module._compile (node:internal/modules/cjs/loader:1546:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
    at Module.load (node:internal/modules/cjs/loader:1317:32)

变更概览

演练

这个拉取请求主要修改了 BaseSelectSelector 组件的键盘交互和焦点处理逻辑。核心变更包括为 Enter 键添加锁定机制,引入新的 onSelectorBluronInputBlur 属性,以及在多个选择器组件中增加了对输入框失焦事件的处理。这些修改旨在改进用户交互和组件的事件管理。

变更

文件 变更概要
src/BaseSelect/index.tsx 新增 onSelectorBlur 方法,优化 Enter 键锁定机制
src/Selector/index.tsx 添加 onInputBluronSelectorBlur 属性
src/Selector/Input.tsx 引入 onBlur 事件处理
tests/Select.test.tsx 新增测试用例验证 Enter 键锁定行为
tests/utils/common.ts 添加 waitFakeTimer 异步工具函数
src/Selector/MultipleSelector.tsx 新增 onInputBlur 属性
src/Selector/SingleSelector.tsx 添加 onInputBlur 属性

可能相关的 PR

建议的审阅者

  • zombieJ

诗歌

🐰 键盘舞动,选择轻盈
Enter 键锁,焦点飞扬
组件进化,交互优雅
兔子微笑,代码飞翔
用户体验,如春风般

Finishing Touches

  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@@ -566,6 +566,11 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
});
};

const onSelectorBlur = () => {
// Unlock the Enter key after the selector blur; otherwise, the Enter key needs to be pressed twice to trigger the correct effect.
keyLockRef.current = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有这个了,上面看起来也不用换位置?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要的,因为onSelect事件是在onKeyDown事件里触发的,然后用户在onSelect里面执行blur,就会触发这个新增的onSelectorBlur,然后继续回到onKeyDown的事件里面,如果不调整顺序,最终keyLockRef.current还是会被设置为true

Copy link

codecov bot commented Jan 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.25%. Comparing base (4779fb8) to head (dcf5b99).
Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1112   +/-   ##
=======================================
  Coverage   98.25%   98.25%           
=======================================
  Files          39       39           
  Lines        1486     1488    +2     
  Branches      448      421   -27     
=======================================
+ Hits         1460     1462    +2     
  Misses         26       26           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (2)
docs/examples/combobox.tsx (1)

6-8: 建议添加 null 检查

在调用 blur() 时,建议添加 null 检查以提高代码的健壮性。

  const onSelect = () => {
-   ref.current!.blur();
+   ref.current?.blur();
  };
tests/Select.test.tsx (1)

2393-2394: 建议添加非空断言

由于我们确定 input 元素存在,建议在获取 input 元素后添加非空断言。

-   inputElem = container.querySelector('input');
+   inputElem = container.querySelector('input')!;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcf5b99 and da9bad3.

📒 Files selected for processing (3)
  • docs/examples/combobox.tsx (1 hunks)
  • tests/Select.test.tsx (4 hunks)
  • tests/utils/common.ts (1 hunks)
🔇 Additional comments (3)
docs/examples/combobox.tsx (1)

4-20: 代码实现清晰简洁!

组件实现了一个很好的示例,展示了如何正确处理自定义输入组件的 Enter 键锁定问题。使用 useRef 来管理输入引用是一个很好的做法。

tests/utils/common.ts (1)

121-127: 实用函数实现恰当!

delay 函数的实现很好地封装了异步等待功能,便于测试异步行为。使用 act 确保了 React 状态更新的正确性。

tests/Select.test.tsx (1)

2373-2418: 测试用例设计全面!

测试用例很好地覆盖了 Enter 键锁定问题的各个方面:

  1. 验证了选择后下拉框的关闭
  2. 验证了输入值的更新
  3. 确保可以重新打开下拉框
  4. 验证了多次选择的正确性

@LeeSSHH LeeSSHH marked this pull request as ready for review January 13, 2025 09:50
@LeeSSHH LeeSSHH closed this Jan 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🔭 Outside diff range comments (1)
src/BaseSelect/index.tsx (1)

建议完善 Enter 键锁定机制的单元测试

现有的测试文件中仅包含了自定义输入组件失焦时释放 Enter 键锁定的测试用例。建议在 tests/Select.test.tsx 中补充以下测试场景:

  • Enter 键按下时的锁定机制
  • 防止重复触发的验证
  • 普通失焦时的锁定释放行为

可以参考 tests/shared/keyDownTest.tsx 中的键盘事件测试工具来实现这些测试用例。

🔗 Analysis chain

Line range hint 540-823: 建议添加单元测试

建议为新增的 Enter 键锁定和释放机制添加相应的单元测试,以验证在以下场景下的行为:

  1. Enter 键按下时的锁定
  2. blur 事件触发时的锁定释放
  3. 连续按 Enter 键的情况
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否存在相关的测试用例
rg -l "test.*keyLock|test.*Enter.*key" --type ts

Length of output: 50


Script:

#!/bin/bash
# Search for test files in BaseSelect directory
fd "test.*\.(ts|tsx)$" src/BaseSelect

# Search for keyboard event related tests
rg -l "keyboard|keyDown|keyUp|onKey" --type ts ".*test.*"

# Search for specific test patterns
rg -A 5 "describe.*keyboard|test.*key" --type ts

Length of output: 199


Script:

#!/bin/bash
# Find all test files
fd "\.test\.(ts|tsx)$"

# Search for keyboard event tests with corrected pattern
rg -l "keyboard|keyDown|keyUp|onKey" --type ts

# Look for specific keyboard handling tests
rg -A 5 "describe\(.*keyboard|test\(.*key" --type ts

Length of output: 976


Script:

#!/bin/bash
# Check keyboard event test implementations
rg -A 10 "keyDown|keyUp|onKey" tests/shared/keyDownTest.tsx tests/BaseSelect.test.tsx

# Look for Enter key related tests
rg -A 5 "Enter" tests/shared/keyDownTest.tsx tests/BaseSelect.test.tsx tests/Select.test.tsx

Length of output: 1758

🧹 Nitpick comments (1)
src/Selector/MultipleSelector.tsx (1)

75-75: 代码变更正确,建议小幅优化!

blur 事件处理的实现与 SingleSelector 保持一致,很好地集成到了现有的焦点管理中。

建议考虑将 onBlur 事件与组件内的 focused 状态管理结合:

 <Input
   ...
-  onBlur={onInputBlur}
+  onBlur={(e) => {
+    setFocused(false);
+    onInputBlur?.(e);
+  }}
   ...
 />

这样可以确保组件的内部状态与外部事件处理保持同步。

Also applies to: 235-235

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da9bad3 and 3127740.

📒 Files selected for processing (7)
  • src/BaseSelect/index.tsx (3 hunks)
  • src/Selector/Input.tsx (4 hunks)
  • src/Selector/MultipleSelector.tsx (2 hunks)
  • src/Selector/SingleSelector.tsx (2 hunks)
  • src/Selector/index.tsx (4 hunks)
  • tests/Select.test.tsx (2 hunks)
  • tests/utils/common.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Selector/index.tsx
  • tests/Select.test.tsx
🔇 Additional comments (8)
src/Selector/SingleSelector.tsx (1)

39-39: 代码变更看起来不错!

新增的 onInputBlur 属性和其传递到 Input 组件的实现方式正确。这些更改与修复 Enter 键锁定问题的目标相符。

Also applies to: 104-104

src/Selector/Input.tsx (1)

28-28: 实现完善且符合最佳实践!

blur 事件的处理链完整且符合 React 的事件处理模式:

  1. 正确定义了 onBlur 类型
  2. 保持了原始 input 元素的 blur 处理
  3. 实现了自定义的 blur 处理

这个实现将有效解决 Enter 键锁定的问题。

Also applies to: 56-56, 71-71, 140-145

tests/utils/common.ts (3)

121-126: 代码注释清晰明确!

JSDoc 注释很好地解释了函数的用途和参数。


127-139: 验证该实现是否满足 PR 目标

这个新的 waitFakeTimer 函数很好地支持了 PR 的主要目标:

  1. 通过控制计时器可以准确测试按键锁定和释放的时序
  2. 使用 act 确保状态更新被正确处理
  3. 支持测试 blur() 调用后的异步行为

运行以下脚本验证相关测试用例:

✅ Verification successful

waitFakeTimer 实现完全符合测试需求

该实现完美支持了测试用例中的异步行为验证:

  • 正确处理了 Select 组件的打开/关闭状态
  • 确保了按键事件和 blur 调用的正确时序
  • 通过 act 包装保证了状态更新的可靠性
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 搜索与 Enter 键和 blur 相关的测试
rg "release.*Enter.*key.*lock.*blur" tests/

Length of output: 147


Script:

#!/bin/bash
# Get the test implementation with context
rg -A 20 "release Enter key lock after customize input calls blur" tests/

Length of output: 1207


Script:

#!/bin/bash
# Get more context around the test case
rg -B 5 -A 30 "release Enter key lock after customize input calls blur" tests/

Length of output: 1968


127-139: 建议优化等待时间的默认值

函数实现逻辑正确,但有以下建议:

  1. 默认等待时间(1000ms)和迭代次数(20次)可能过高,这会导致测试运行时间较长。
  2. 考虑根据实际用例调整这些默认值,比如使用较小的初始值。

建议如下修改:

-export async function waitFakeTimer(advanceTime = 1000, times = 20) {
+export async function waitFakeTimer(advanceTime = 100, times = 10) {

另外,建议添加单元测试来验证这个新函数的行为:

  1. 测试正数 advanceTime 的情况
  2. 测试零或负数 advanceTime 的情况
  3. 验证迭代次数是否符合预期

运行以下脚本检查是否已有相关测试:

src/BaseSelect/index.tsx (3)

540-543: 优化了 Enter 键锁定的时机

在下拉菜单打开时,通过在触发 onSelect 事件之前设置 keyLockRef,解决了由于 blur 导致的键盘锁定问题。


571-574: 添加了 blur 时的键盘锁定释放机制

通过在 selector blur 时重置 keyLockRef,确保下次按 Enter 键时能够正确触发事件,避免需要按两次的问题。


823-823: 集成了 blur 事件处理

将 onSelectorBlur 处理函数正确地传递给了 Selector 组件,完成了键盘锁定释放机制的闭环。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AutoComplete onSelect 中 blur 掉 child 组件后无法触发后续 onSelect
2 participants