Skip to content

fix: release unique popup ownership on trigger unmount - #649

Open
yulman2207 wants to merge 1 commit into
react-component:masterfrom
yulman2207:fix/unique-owner-unmount
Open

yulman2207 wants to merge 1 commit into
react-component:masterfrom
yulman2207:fix/unique-owner-unmount

Conversation

@yulman2207

@yulman2207 yulman2207 commented Oct 19, 2026 •

Copy link
Copy Markdown

What changed

  • Release a trigger's displayed, delayed, and motion-pending unique popup ownership when it unmounts, while preserving another mounted owner's popup and scheduled work.
  • Ignore stale hide requests from previous owners and retain the surviving owner's controlled visibility callback.
  • Track current ownership synchronously so multiple owners unmounting in the same React commit cannot leave an orphaned popup.
  • Add 16 regression cases covering controlled and uncontrolled visibility, inactive and previous owners, delayed callbacks, repeated remounts, provider isolation, StrictMode, and individual/simultaneous unmounts during enter motion.

Why

With Ant Design's ConfigProvider tooltip={{ unique: true }}, clicking a button that removes its Tooltip leaves the shared popup visible. The same failure reproduces directly in Trigger: the provider outlives the trigger and previously received no ownership-release notification.

Fixes ant-design/ant-design#59603. The fix belongs here rather than in an Ant Design DOM or event workaround. Existing leave animations and cached popup content are preserved.

Validation

  • Before the fix, 10 of the first 15 regression cases failed. The additional simultaneous-unmount case also failed before the synchronous ownership refinement.
  • Full Trigger suite using the rc-test Jest configuration: 18 suites passed, 149 tests passed, 1 skipped.
  • Ant Design 6.6.7 with the local Trigger source and its existing portal test mock: original reproduction plus focused Tooltip/ConfigProvider suites 73 tests and 8 snapshots passed.
  • npm run tsc: passed.
  • npm run lint: passed with 0 errors and 10 hook-dependency warnings.
  • Prettier check of all changed files and git diff --check: passed.
  • Browser verification was not performed.

AI assistance disclosure: this implementation, regression coverage, and PR description were prepared with OpenAI Codex, including a separate code-review pass. Please review the change normally.

Summary by CodeRabbit

  • Bug 修复
    • 唯一弹层的触发器卸载后,会正确释放其占用状态,避免弹层状态残留。
    • 延迟隐藏仅作用于仍拥有该弹层的触发器,避免误关闭已切换到其他触发器的弹层。
    • 弹层切换或动画期间触发器卸载时,会正确处理待显示弹层及关闭状态。
    • 修复受控、非受控及 StrictMode 等场景下,弹层卸载、重挂载和切换时的状态异常。

@vercel

vercel Bot commented Oct 19, 2026

Copy link
Copy Markdown

@yulman2207 is attempting to deploy a commit to the afc163's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cb6be8e2-234d-4fd0-87fb-5fd23bb34114
📥 Commits

Reviewing files that changed from the base of the PR and between 3ff7d68 and 04e498b.

📒 Files selected for processing: 5
  • src/UniqueProvider/index.tsx
  • src/UniqueProvider/useTargetState.ts
  • src/context.ts
  • src/index.tsx
  • tests/unique-unmount.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Walkthrough

唯一弹层现在按触发器 ID 管理所有者和延迟操作。触发器卸载时会释放对应 ID。目标状态 hook 支持释放当前或待处理选项。新增测试覆盖卸载、延迟操作和 Provider 隔离。

Changes

唯一弹层生命周期

Layer / File(s) Summary
目标状态跟踪
src/UniqueProvider/useTargetState.ts
Hook 同步追踪当前选项。释放 ID 时会清除匹配的待处理选项;若 ID 匹配当前选项,则切换到其他有效选项或关闭弹层。
Provider 所有权与释放
src/context.ts, src/UniqueProvider/index.tsx
上下文新增 release(id),且 hide 接收 ID 和延迟。Provider 按 ID 管理 owner、隐藏请求和释放操作。
卸载清理与行为验证
src/index.tsx, tests/unique-unmount.test.tsx
唯一触发器卸载时释放自身 ID;受控和非受控隐藏路径传入 ID。测试覆盖所有者卸载、延迟操作、重挂载和 Provider 隔离。

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant Trigger
  participant UniqueContext
  participant UniqueProvider
  participant useTargetState
  Trigger->>UniqueContext: 卸载时调用 release(id)
  UniqueContext->>UniqueProvider: 转发 release(id)
  UniqueProvider->>useTargetState: 调用 releaseTarget(id)
  useTargetState-->>UniqueProvider: 返回仍有效的选项 ID
Loading
Merge Risk: ⚪ Minimal · up to 04e49

This change releases unique popup ownership when a trigger unmounts, and it adds regression tests. No concrete merge-blocking risk was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed 标题准确概括了主要变更:在触发器卸载时释放唯一弹层所有权。标题简洁、明确,并与代码修改和 PR 目标一致。
Linked Issues check Passed PR 实现了 Issue #59603 的编码要求。generateTrigger 在唯一弹窗触发器卸载时调用 uniqueContext.release(id)。UniqueProvider 按 owner ID 取消待处理操作并释放当前目标。当前 owner 卸载时会关闭弹窗;存在其他 owner 时会保留其弹窗。hide(id, delay) 会忽略非当前 owner 的过期…
Out of Scope Changes check Passed 变更范围与 Issue #59603 一致。源码变更集中在唯一弹窗的 owner 释放、过期隐藏请求处理和同步 owner 状态。新增回归测试直接验证触发器卸载后的关闭行为及相关 owner 保留行为。未发现与该问题无关的功能变更。
Full details: Linked Issues check

Explanation

PR 实现了 Issue #59603 的编码要求。generateTrigger 在唯一弹窗触发器卸载时调用 uniqueContext.release(id)。UniqueProvider 按 owner ID 取消待处理操作并释放当前目标。当前 owner 卸载时会关闭弹窗;存在其他 owner 时会保留其弹窗。hide(id, delay) 会忽略非当前 owner 的过期隐藏请求。新增测试覆盖唯一和非唯一模式、受控模式、延迟操作、重复挂载、StrictMode、Provider 隔离,以及进入动画期间的卸载。

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

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

ESLint install timed out. The project may have too many dependencies for the sandbox.

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

我是小兔,蹦到弹层旁,
触发器离开,状态也退场。
当前选项清理好,
待处理项接上跑。
延迟请求不再乱,
Provider 各自守一方。

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

This branch has not been deployed

No deployments
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.

Tooltip stays open after its trigger is unmounted when ConfigProvider tooltip.unique is enabled

1 participant