picker icon indicating copy to clipboard operation
picker copied to clipboard

fix: trigger onChange when manually clearing input via select all + delete

Open alii13 opened this issue 2 months ago • 11 comments

Title

fix: trigger onChange when manually clearing input via select all + delete

Description

This PR fixes the issue where manually clearing a date input by selecting all text (Ctrl+A/Cmd+A) and pressing Delete/Backspace does not trigger the onChange callback.

Problem

When users manually select and delete date text in the input field:

  • onChange was NOT triggered
  • ❌ After blur, the previous date value reappeared
  • ❌ Inconsistent with the clear button (×) behavior

This was a UX and accessibility issue that prevented keyboard-only users from clearing dates effectively.

Solution

Changes Made:

  1. useInputProps.ts - Added logic to detect empty input and trigger onChange(null)
  2. Input.tsx - Added handlers for both formatted and non-formatted inputs
  3. SingleSelector/index.tsx - Updated to properly handle null values
  4. manual-clear.spec.tsx - Added 11 comprehensive tests

Behavior After Fix:

  • ✅ Select all text (Ctrl+A/Cmd+A) and press Delete → input clears immediately
  • onChange is called with (null, null)
  • ✅ Matches clear button behavior exactly
  • ✅ Works for both Picker and RangePicker
  • ✅ Works for all picker modes (date, week, month, year, quarter, time)

Testing

All Tests Pass

  • 453 existing tests pass ✅ (no breaking changes)
  • 11 new tests added ✅ (comprehensive coverage)
  • Total: 16 test suites, 455 tests

Manual Testing

  1. Click in the input
  2. Select all text: Ctrl+A (Windows/Linux) or Cmd+A (Mac)
  3. Press Delete or Backspace
  4. Verify input clears and onChange is triggered

Backward Compatibility

Fully backward compatible - all existing tests pass

  • Invalid partial inputs still reset on blur (existing behavior preserved)
  • Clear button behavior unchanged
  • No API changes

Fixes

Fixes ant-design/ant-design#52473

Summary by CodeRabbit

  • Bug Fixes

    • 改进了日期/区间选择器的手动清除与空输入处理:在输入清空或通过清除控件时会显式走清除路径、重置输入并同步外部状态;单选场景在为空且允许清除时会触发清除回调;公共 API 保持不变。
  • Tests

    • 新增全面手动清除测试,覆盖通过输入/失焦与清除控件、allowClear 不同配置、无效部分输入、不同行为模式与掩码、范围起止清空等场景,提升一致性验证。

alii13 avatar Oct 27 '25 10:10 alii13

@alii13 is attempting to deploy a commit to the React Component Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Oct 27 '25 10:10 vercel[bot]

Summary of Changes

Hello @alii13, 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 resolves a significant user experience and accessibility flaw in date input components. Previously, manually clearing a date field by selecting all text and pressing delete or backspace would not correctly trigger the onChange event, leading to inconsistent state and the reappearance of old values. The implemented solution ensures that such manual clearing actions are properly recognized, triggering onChange(null) and providing a consistent, accessible experience across all picker types and modes, mirroring the behavior of the dedicated clear button.

Highlights

  • Manual Clear Fix: Implemented a fix to ensure the onChange callback is triggered when a date input is manually cleared using "select all + delete/backspace".
  • Consistent Behavior: The manual clearing behavior now aligns with the dedicated clear button, preventing previous date values from reappearing on blur.
  • Enhanced Accessibility: This change improves keyboard accessibility for users who clear date inputs without relying on a mouse.
  • Broad Coverage: The fix applies consistently to both single and range pickers, and across all picker modes (date, week, month, year, quarter, time).
  • Comprehensive Testing: 11 new, comprehensive tests have been added to validate the new functionality across various scenarios, ensuring robustness.
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.

gemini-code-assist[bot] avatar Oct 27 '25 10:10 gemini-code-assist[bot]

[!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

在输入与选择处理路径中加入对手动清空的显式处理:当输入变为空或通过键盘(全选 + Backspace/Delete)清除时,触发相应的清空回调(onChange(null)/onClear),更新输入状态并提前返回以阻止后续处理。

Changes

Cohort / File(s) 变更摘要
输入组件改动
src/PickerInput/Selector/Input.tsx
提取顶部输入文本变量并在通用/无格式化路径中检测并处理手动清空:当输入变为空且当前值非空且存在清空图标时,调用 onChange('') 并重置输入值,阻止默认事件并提前返回;同时统一使用顶部提取的 text 变量以避免重复声明。
单选选择器
src/PickerInput/Selector/SingleSelector/index.tsx
将单选变更处理改为接受 `DateType
输入属性钩子
src/PickerInput/Selector/hooks/useInputProps.ts
增加空字符串分支:当 text === '' 时先调用 onInvalid(false, index)onChange(null, index) 并提前返回,确保外部状态与无效标记同步并阻止后续验证流程。
测试
tests/manual-clear.spec.tsx
新增手动清空相关测试,覆盖键盘/输入/blur 清空、allowClear 开关、range picker 两端清空、不同模式与掩码下行为,使用 dayjs generateConfig、en_US locale 与假定定时器模拟异步验证。

Sequence Diagram(s)

sequenceDiagram
    participant 用户
    participant Input as Input 组件
    participant Hook as useInputProps
    participant Selector as SingleSelector
    participant Parent as 上层 onChange/onClear

    Note over 用户,Input: 用户全选并按 Delete/Backspace 或 将输入清空
    用户->>Input: 输入事件 / keydown
    alt 检测到手动清空 (text === '' 且 当前值非空)
        Input->>Input: 阻止默认、重置输入值
        Input->>Parent: onChange(null) / onClear()
        Note right of Parent: 上层接收空值清空事件
    else 常规格式化/校验流程
        Input->>Hook: 继续格式化与校验(可能触发 onModify/onChange)
    end

    Note over Input,Hook: 若 text === '' 导致钩子提前返回
    Input->>Hook: text === ''
    Hook->>Hook: onInvalid(false), onChange(null) 并提前返回
    Hook-->>Parent: onChange(null)

    Note over Selector: 通过选择器接口触发选择/清空
    用户->>Selector: 选择器产生 date (可能为 null)
    alt date === null
        Selector->>Parent: onClear()
    else
        Selector->>Parent: onChange([date])
    end

Estimated code review effort

🎯 3 (中等) | ⏱️ ~20-25 minutes

需要额外关注:

  • src/PickerInput/Selector/Input.tsx 中对选区/光标状态与 preventDefault 的判断是否覆盖所有输入场景(含掩码/格式化路径)。
  • src/PickerInput/Selector/hooks/useInputProps.ts 的空字符串早退对去抖、异步验证和现有校验流程的影响。
  • src/PickerInput/Selector/SingleSelector/index.tsx 中 onClear/onChange 的调用时机与副作用顺序。
  • 新增测试中使用的假定定时器与 locale 设置对 CI 稳定性的影响。

Possibly related issues

  • #52473: DatePicker does not allow manual clear — 本 PR 在输入为空时显式调用 onChange/onClear,直接对应“手动清空未触发 onChange”的描述。
  • react-component/picker#946 — 与本次改动相似,均在输入清空路径增加显式 onChange(null) 处理,目标一致。

Possibly related PRs

  • react-component/picker#942 — 对清空行为的 onChange/onClear 传递进行类似修改,与本 PR 在实现上高度相关。

Suggested reviewers

  • afc163
  • zombieJ

诗语

🐰 退格轻敲风声短,字符随手散云端,
空白化作 null 一环,onChange 回声暖心间,
测试护航夜半看,清空今朝终可安。

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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 拉取请求标题"fix: trigger onChange when manually clearing input via select all + delete"清晰准确地描述了主要变更。标题具体说明了修复内容(通过选中所有文本后删除来手动清空输入时触发onChange回调),与提供的代码摘要中所有四个修改文件的核心目标保持一致。标题简洁明了,没有冗余信息,能够帮助开发人员快速理解此变更的主要作用。
Linked Issues Check ✅ Passed 本次拉取请求的代码变更完全符合关联问题#52473的所有核心要求。问题要求允许通过选中所有文本并按Delete/Backspace键手动清空日期选择器输入,并确保此行为与清除按钮(×)相同、触发onChange回调、防止模糊焦点后日期重新出现、以及支持所有选择器模式。代码修改(useInputProps.ts中添加空输入检测、Input.tsx中处理已格式化和未格式化输入、SingleSelector/index.tsx中处理null值)和新增的11个全面测试套件直接解决了这些要求。测试覆盖了不同的选择器模式、allowClear配置选项以及手动清除与清除按钮的一致性验证。
Out of Scope Changes Check ✅ Passed 所有代码变更均直接与问题#52473的修复目标相关,不存在超出范围的改动。四个修改文件(Input.tsx、SingleSelector/index.tsx、useInputProps.ts和manual-clear.spec.tsx)的变更都专注于实现手动清空输入功能。新增的测试仅验证手动清除行为及其与清除按钮的一致性,不涉及其他功能或特性的改动。代码摘要明确指出未对导出或公共实体签名进行任何改动,确保了后向兼容性。
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 669467f4a215b4bde10fefd98b565291ec7d4220 and 81b32b68fc02f75b40bcb625a0aa950e189d2f02.

📒 Files selected for processing (1)
  • tests/manual-clear.spec.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/manual-clear.spec.tsx (1)
tests/util/commonUtil.tsx (3)
  • getDay (186-195)
  • openPicker (78-87)
  • waitFakeTimer (71-76)
🔇 Additional comments (3)
tests/manual-clear.spec.tsx (3)

8-16: 测试设置正确。

使用假计时器固定时间点,并在测试后正确清理,这是测试日期选择器的标准做法。


67-86: 已修复:测试现在正确输入了部分值。

此测试已根据之前的反馈进行了修正。第 80 行现在正确地输入了部分日期值 '2023-08',然后验证在 blur 时该值被重置为完整日期 '2023-08-01' 且不触发 onChange。测试描述与实际行为现在一致。


265-302: 优秀的对比测试!

此测试很好地验证了手动清空和清除按钮行为的一致性。两个 onChange 回调都被正确断言,确保两种清空方式产生相同的结果。这种对比测试对于保证功能等价性非常有价值。


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Oct 27 '25 10:10 coderabbitai[bot]

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 98.81%. Comparing base (0dadb0a) to head (81b32b6). :warning: Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #947   +/-   ##
=======================================
  Coverage   98.80%   98.81%           
=======================================
  Files          65       65           
  Lines        2680     2691   +11     
  Branches      744      748    +4     
=======================================
+ Hits         2648     2659   +11     
  Misses         29       29           
  Partials        3        3           

: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.

codecov[bot] avatar Oct 27 '25 12:10 codecov[bot]

@li-jia-nan / @afc163 / @zombieJ Can someone please take a look at this PR whenever you have time. Thank you!

alii13 avatar Oct 28 '25 05:10 alii13

@zombieJ Please review this

li-jia-nan avatar Oct 28 '25 05:10 li-jia-nan

Bumping this up, incase missed it.

alii13 avatar Oct 30 '25 03:10 alii13

@gemini-code-assist Pls help to CR agaign.

zombieJ avatar Oct 30 '25 08:10 zombieJ

@gemini-code-assist can you re-review the PR?

alii13 avatar Oct 31 '25 06:10 alii13

@zombieJ thanks for your suggestions. I have resolved those changes, can you please do a re-review whenever you get time? Thanks!

alii13 avatar Oct 31 '25 07:10 alii13

^ Bumping this up again, thanks for reviewing the PR

alii13 avatar Nov 03 '25 05:11 alii13