Skip to content

refactor(popover): v16适配#3492

Open
irisSong wants to merge 16 commits into
jdf2e:feat_v4.xfrom
irisSong:feat_4.x
Open

refactor(popover): v16适配#3492
irisSong wants to merge 16 commits into
jdf2e:feat_v4.xfrom
irisSong:feat_4.x

Conversation

@irisSong

@irisSong irisSong commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

🤔 这个变动的性质是?

  • 新特性提交
  • 日常 bug 修复
  • 站点、文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • TypeScript 定义更新
  • 包体积优化
  • 性能优化
  • 功能增强
  • 国际化改进
  • 重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他改动(是关于什么的改动?)

🔗 相关 Issue

💡 需求背景和解决方案

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项⚠️

  • 文档已补充或无须补充
  • 代码演示已提供或无须提供
  • TypeScript 定义已补充或无须补充
  • fork仓库代码是否为最新避免文件冲突
  • Files changed 没有 package.json lock 等无关文件

Summary by CodeRabbit

Release Notes

  • New Features

    • 新增 Popover 气泡类型选择(状态型/说明型)
    • 支持自动展示与自动关闭(autoShow、duration)
    • 新增亮色主题选项(theme="light")
  • Bug Fixes & Improvements

    • 默认主题调整为暗色(theme)
    • 更新气泡样式与箭头/定位计算,并细化 CSS 变量以支持更丰富的自定义
    • 更新 Tour/Popover 相关测试断言
  • Documentation

    • 更新 Popover 使用文档与样式变量说明
    • 新增 v3 到 v4 迁移指南

@github-actions github-actions Bot added the action:review This PR needs more reviews (less than 2 approvals) label Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f6aadde7-e122-4ba9-bf76-f977344b5f13

📥 Commits

Reviewing files that changed from the base of the PR and between 9476baf and 8e1951c.

📒 Files selected for processing (6)
  • src/packages/button/button.taro.tsx
  • src/packages/tour/__test__/tour.spec.tsx
  • src/packages/tour/demos/h5/demo3.tsx
  • src/packages/tour/demos/taro/demo3.tsx
  • src/packages/tour/tour.taro.tsx
  • src/packages/tour/tour.tsx
✅ Files skipped from review due to trivial changes (2)
  • src/packages/tour/tour.tsx
  • src/packages/tour/demos/h5/demo3.tsx

代码摘要

对 Popover 组件进行 v4 重构:新增 type(status/description)、autoShowduration Props;重写箭头偏移与气泡定位计算;扩展 CSS 变量体系(含 light 主题、状态/描述宽度、图标热区等);主题类名从 .nut-popover-dark 迁移为 modifier 类;同步更新演示、多语言文档与 v3→v4 迁移说明;并同步调整 Tour 组件箭头偏移与 Button 组件无障碍属性。

变更内容

Popover v4 重构

层 / 文件 摘要
类型契约与配置开关
src/types/spec/popover/base.ts, src/packages/configprovider/types.ts, src/config.json, package.json
新增导出类型 PopoverType ('status' | 'description'),BasePopover 增加 type/autoShow/duration 字段;NutCSSVariables 补充 nutuiPopover 相关 CSS 变量字面量(12 项新增);config.json 将 v16 开关置为 true;升级 @nutui/icons-react^3.0.2-beta.6@nutui/icons-react-taro3.0.2-beta.6
CSS 变量体系扩展
src/styles/variables.scss, src/styles/variables-daojia.scss, src/styles/variables-jmapp.scss, src/styles/variables-jrkf.scss
扩展 popover token 集合:新增 padding-horizontal/padding-verticalheighticon-size/icon-colorstatus-max-width/description-max-widthaction-hotspot-size、light 主题色彩变量;调整既有变量默认值(圆角 $radius-xs$radius-s、背景 #ffffff$color-mask、文字颜色默认值、分割线颜色等);四个主题变量文件统一对齐新结构。
SCSS 布局与箭头样式重构
src/packages/popover/popover.scss, src/sites/theme/components/header/header.scss
箭头改为 8px 高度,各方向定位更新为 ±12px 偏移;重构 nut-popover-item flex 布局(最小高度、垂直 padding、分割线处理);新增图标与热点层 (::before) 相对定位与 flex 约束;新增 &--status/&--description max-width 修饰符;更新 light 主题全量覆盖(背景/文字/图标/分割线颜色);清理 RTL 中旧有 16px 箭头偏移逻辑;header.scss 选择器改为 .nut-popover(移除 --dark 限定)。
组件核心逻辑重写
src/packages/popover/popover.tsx, src/packages/popover/popover.taro.tsx
defaultProps 新增 type: 'status'/theme: 'dark'/autoShow: false/duration: 0;新增两个 useEffectautoShow 挂载触发 onOpenvisible && duration > 0 时启动定时器,在超时点触发 onClickonClose);classes 拼接新增 nut-popover--${type};调整 light 主题类逻辑(仅 theme === 'light' 时加 nut-popover-light);getPopoverPosition 引入 edgeOffset = arrowOffset,重写 skewleft/right 时的水平偏移公式;popoverArrowStyle 移除 basecalc(50% ± ...) 分支,改用直接像素值。
测试用例更新
src/packages/popover/__tests__/popover.spec.tsx
暗色内容用例移除 theme="dark",改为断言 nut-popover--status 类;箭头样式断言重构为支持 null 期望(期望为 null 时断言 style 属性为 null),重新定义各 FullPosition 预期值(从 calc(...) 调整为显式 left/right: 20pxnull);新增两条用例验证 autoShow 触发 onOpenduration 定时触发 onClose/onClick
演示组件重构(H5 & Taro)
src/packages/popover/demos/h5/demo*.tsx, src/packages/popover/demos/taro/demo*.tsx, src/packages/popover/demo.tsx, src/packages/popover/demo.taro.tsx
demo1(两端):将 basic/dark 双主题改为 statusVisible/descriptionVisible/lightVisible/autoVisible 四个独立可见性状态,对应四类 Popover(status/description/light theme/autoShow);demo2~8(两端):全量移除 theme="dark" 属性;demo3(两端):margin 改为 '10px 0'(上下同时生效);demo4(两端):新增 type="description" 并扩充 positionList 至 2 项;多语言:主标题改为"气泡类型"、"Bubble Types"、"氣泡類型"。
文档与迁移说明
src/packages/popover/doc*.md, src/sites/sites-react/doc/docs/*/migrate-from-v3*.md
文档章节标题改为"气泡类型";Props 表新增 type/autoShow/duration 行,调整 offset/arrowOffset 默认值;CSS 变量清单整体重构(新增 14+ 变量,调整默认值);四个 migrate-from-v3 文档新增 Popover v3→v4 迁移小节,覆盖 type 引入与默认值、theme 默认改为 dark、CSS 类名断裂点(移除 .nut-popover-dark、新增 modifier 类)、主题变量映射变更。

Tour 与 Button 联动更新

层 / 文件 摘要
Tour 组件 arrowOffset 同步
src/packages/tour/tour.tsx, src/packages/tour/tour.taro.tsx, src/packages/tour/__test__/tour.spec.tsx, src/packages/tour/demos/h5/demo3.tsx, src/packages/tour/demos/taro/demo3.tsx
Tour 渲染的 Popover arrowOffset 默认值由 0 改为 20;测试断言 arrow right 样式由 52px 改为 -36px;演示配置 popoverOffset[40, 12] 改为 [0, 12],并移除显式 arrowOffset: -36
Button 无障碍属性调整
src/packages/button/button.taro.tsx
组件 loading 图标渲染改用显式 aria-hidden="true" 属性,移除 ariaHidden 简写,提升代码可读性与语义一致性。

估算代码审查工作量

🎯 4 (Complex) | ⏱️ ~60 minutes

可能相关的 PR

  • jdf2e/nutui-react#2850:同样修改了 src/packages/popover/popover.scss 中的箭头样式与暗色模式行为,与本次箭头定位重构直接相关。
  • jdf2e/nutui-react#2884:同样修改了 popover.tsx/popover.taro.tsx 的箭头渲染与 offset 默认值调整,与本次定位计算重写存在代码级关联。
  • jdf2e/nutui-react#3330:同样在 package.json 中将 @nutui/icons-react/@nutui/icons-react-taro 升级到 3.0.2-beta.* 版本,属于同类依赖变更。

建议审查者

  • xiaoyatong
  • oasis-cloud

小诗

🐰 兔子跳跳迎新版,
气泡换装真好看~
statusdescription
autoShow 自动弹出来,
箭头对齐不再偏,
light/dark 随心换!✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR 描述完全未填充,仅包含空的模板和未勾选的复选框,没有实质内容。 请填充 PR 描述,包括变动性质、相关 issue、需求背景与解决方案,以及完成自查清单的勾选。
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确反映了主要变化,即对 popover 组件的 v16 适配重构。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

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

@irisSong

irisSong commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author
image 升级后 image

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 110-111: The version specification strategy for `@nutui/icons-react`
and `@nutui/icons-react-taro` is inconsistent: `@nutui/icons-react` uses a caret
range (^3.0.2-beta.6) allowing minor version updates, while
`@nutui/icons-react-taro` uses an exact version (3.0.2-beta.6) with the caret
removed. Align these two icon package dependencies by applying the same
versioning strategy to both, either by adding the caret prefix to
`@nutui/icons-react-taro` to match `@nutui/icons-react`, or removing the caret from
`@nutui/icons-react` to match `@nutui/icons-react-taro`, ensuring consistency across
H5 and Taro icon dependencies.

In `@src/packages/popover/__tests__/popover.spec.tsx`:
- Around line 207-226: The test "should auto close after duration" has two
timer-related issues that need fixing. First, add a try-finally block to ensure
timers are properly cleaned up even if assertions fail early; in the finally
block, call both vi.clearAllTimers() and vi.useRealTimers() to completely reset
the timer state. Second, wrap the vi.advanceTimersByTime() call with the act()
function from React testing library to properly handle React state updates
triggered by timer advancement, which prevents "not wrapped in act" warnings and
potential race conditions.

In `@src/packages/popover/popover.taro.tsx`:
- Around line 188-192: The skew positioning logic in lines 188-192 consistently
uses styles.left for both left and right skew cases, but the arrow positioning
logic in lines 218-228 has already been updated to handle RTL by switching
between left and right sides. Apply the same RTL-aware strategy used in the
arrow positioning section to the content positioning in the skew branch. Instead
of always assigning to styles.left, conditionally assign to either styles.left
or styles.right based on the RTL direction check, ensuring the content anchor
positioning aligns correctly with the arrow positioning in RTL mode.

In `@src/packages/popover/popover.tsx`:
- Around line 210-215: The content positioning logic in the skew === 'left' and
skew === 'right' blocks always assigns to styles.left, but the arrow positioning
code (referenced around lines 240-250) already implements proper RTL handling by
switching between left and right. This inconsistency causes the content
container and arrow anchor to be positioned on different sides in RTL mode.
Apply the same RTL-aware logic to the content positioning by checking the RTL
status and conditionally assigning to either styles.left or styles.right
(similar to how the arrow positioning handles this), ensuring the content
container and arrow anchor remain aligned in both LTR and RTL modes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5578985a-6c74-4463-860f-5b9f624b4d81

📥 Commits

Reviewing files that changed from the base of the PR and between 79f7ea1 and 9476baf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • package.json
  • src/config.json
  • src/packages/configprovider/types.ts
  • src/packages/popover/__tests__/popover.spec.tsx
  • src/packages/popover/demo.taro.tsx
  • src/packages/popover/demo.tsx
  • src/packages/popover/demos/h5/demo1.tsx
  • src/packages/popover/demos/h5/demo2.tsx
  • src/packages/popover/demos/h5/demo3.tsx
  • src/packages/popover/demos/h5/demo4-1.tsx
  • src/packages/popover/demos/h5/demo4.tsx
  • src/packages/popover/demos/h5/demo5.tsx
  • src/packages/popover/demos/h5/demo7.tsx
  • src/packages/popover/demos/h5/demo8.tsx
  • src/packages/popover/demos/taro/demo1.tsx
  • src/packages/popover/demos/taro/demo2.tsx
  • src/packages/popover/demos/taro/demo3.tsx
  • src/packages/popover/demos/taro/demo4-1.tsx
  • src/packages/popover/demos/taro/demo4.tsx
  • src/packages/popover/demos/taro/demo5.tsx
  • src/packages/popover/doc.en-US.md
  • src/packages/popover/doc.md
  • src/packages/popover/doc.taro.md
  • src/packages/popover/doc.zh-TW.md
  • src/packages/popover/popover.scss
  • src/packages/popover/popover.taro.tsx
  • src/packages/popover/popover.tsx
  • src/sites/sites-react/doc/docs/react/migrate-from-v3.en-US.md
  • src/sites/sites-react/doc/docs/react/migrate-from-v3.md
  • src/sites/sites-react/doc/docs/taro/migrate-from-v3.en-US.md
  • src/sites/sites-react/doc/docs/taro/migrate-from-v3.md
  • src/sites/theme/components/header/header.scss
  • src/styles/variables-daojia.scss
  • src/styles/variables-jmapp.scss
  • src/styles/variables-jrkf.scss
  • src/styles/variables.scss
  • src/types/spec/popover/base.ts
💤 Files with no reviewable changes (8)
  • src/packages/popover/demos/h5/demo5.tsx
  • src/packages/popover/demos/taro/demo5.tsx
  • src/packages/popover/demos/h5/demo4-1.tsx
  • src/packages/popover/demos/taro/demo2.tsx
  • src/packages/popover/demos/h5/demo8.tsx
  • src/packages/popover/demos/taro/demo4-1.tsx
  • src/packages/popover/demos/h5/demo7.tsx
  • src/packages/popover/demos/h5/demo2.tsx

Comment thread package.json
Comment on lines +110 to +111
"@nutui/icons-react": "^3.0.2-beta.6",
"@nutui/icons-react-taro": "3.0.2-beta.6",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

版本锁定策略不一致

@nutui/icons-react 保持范围符 ^3.0.2-beta.6(允许小版本更新),而 @nutui/icons-react-taro 改为精确版本 3.0.2-beta.6(移除了 ^)。

这样的不一致可能导致 H5 和 Taro 版本的图标依赖在不同环境中出现版本分歧。请说明为什么需要这样的差异,或统一为相同的版本策略。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 110 - 111, The version specification strategy for
`@nutui/icons-react` and `@nutui/icons-react-taro` is inconsistent:
`@nutui/icons-react` uses a caret range (^3.0.2-beta.6) allowing minor version
updates, while `@nutui/icons-react-taro` uses an exact version (3.0.2-beta.6) with
the caret removed. Align these two icon package dependencies by applying the
same versioning strategy to both, either by adding the caret prefix to
`@nutui/icons-react-taro` to match `@nutui/icons-react`, or removing the caret from
`@nutui/icons-react` to match `@nutui/icons-react-taro`, ensuring consistency across
H5 and Taro icon dependencies.

Comment on lines +207 to +226
test('should auto close after duration', () => {
vi.useFakeTimers()
const close = vi.fn()
const click = vi.fn()
render(
<Popover
visible
duration={5000}
list={itemList}
onClose={close}
onClick={click}
>
<Button type="primary">自动关闭</Button>
</Popover>
)
vi.advanceTimersByTime(5000)
expect(close).toBeCalled()
expect(click).toBeCalled()
vi.useRealTimers()
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the test file structure
cat -n src/packages/popover/__tests__/popover.spec.tsx | sed -n '207,226p'

Repository: jdf2e/nutui-react

Length of output: 1917


🏁 Script executed:

# Also check the Popover component implementation to understand how duration works
fd -t f "popover" --type f -e ts -e tsx src/packages/popover/ | grep -v "spec\|test" | head -5

Repository: jdf2e/nutui-react

Length of output: 1917


🏁 Script executed:

# Let's look at the broader test file context
wc -l src/packages/popover/__tests__/popover.spec.tsx

Repository: jdf2e/nutui-react

Length of output: 1917


🌐 Web query:

Vitest vi.useFakeTimers try-finally cleanup pattern best practices

💡 Result:

Best-practice cleanup pattern for Vitest fake timers (vi.useFakeTimers) is: always restore real timers in a finally/afterEach, and clear any scheduled timers before switching back. Recommended pattern (per test) try { vi.useFakeTimers //...test code that schedules timers // optionally: vi.advanceTimersByTime(...), vi.runAllTimers, etc. } finally { vi.clearAllTimers vi.useRealTimers } Why this pattern 1) vi.useFakeTimers keeps faking timers until you call vi.useRealTimers. [1] 2) vi.clearAllTimers “removes all timers that are scheduled to run” so they will never run later (prevents leakage into subsequent tests). [1] 3) vi.useRealTimers restores mocked timers back to their original implementations; timers scheduled before switching back are discarded. [2] Notes / variations - If you only need a subset of timer APIs, pass options like vi.useFakeTimers({ toFake: [...] }) or vi.useFakeTimers({ toNotFake: [...] }). [1] - Dates: with fake timers, Date.now is mocked, and to control Date you can use vi.setSystemTime; when done you should restore with vi.useRealTimers in afterEach/cleanup. [3] Example using beforeEach/afterEach instead of per-test try/finally beforeEach( => { vi.useFakeTimers }) afterEach( => { vi.clearAllTimers vi.useRealTimers }) This is consistent with Vitest’s timer APIs: useFakeTimers wraps timer calls until useRealTimers, and clearAllTimers drops queued timers so they don’t affect later tests. [1][2]

Citations:


🌐 Web query:

React Testing Library act() wrapping vi.advanceTimersByTime Vitest integration

💡 Result:

When using Vitest fake timers with React Testing Library (RTL), you should generally wrap calls to vi.advanceTimersByTime in act [1][2][3]. This ensures that any React state updates triggered by the timer advancement are processed and flushed, preventing "not wrapped in act" warnings and ensuring your assertions reflect the updated component state [2][3]. Why act is required React processes state updates in batches [4]. When you manually advance timers using vi.advanceTimersByTime, the callbacks associated with those timers (such as setTimeout or setInterval) execute outside of React's standard update cycle [3]. Without act, React may not be aware of the state updates triggered by these callbacks, leading to warnings or race conditions where your assertions run before the component has finished re-rendering [2][3]. Recommended Usage Pattern To correctly advance timers and update the component, wrap the call in act: import { act, render, screen } from '@testing-library/react'; import { vi } from 'vitest'; test('advances timer correctly', => { vi.useFakeTimers; render(); act( => { vi.advanceTimersByTime(1000); }); expect(screen.getByText('Updated')).toBeInTheDocument; }); Handling user-event with Fake Timers If you use user-event in combination with fake timers, it is important to configure it to use your test runner's timer functions [5][6]. This prevents compatibility issues and test timeouts [6]: const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime.bind(vi), }); Best Practices Always restore timers: Use afterEach to clear timers and restore real timers to prevent side effects in other tests [6]. import { vi } from 'vitest'; afterEach( => { vi.runOnlyPendingTimers; vi.useRealTimers; }); Warning about "not wrapped in act": If you continue to see act warnings despite wrapping, ensure that your environment is properly configured for React 18+ and that you are not running into issues with asynchronous timer flushing (where you might need vi.runAllTimersAsync instead) [7][8]. Additionally, some newer versions of testing libraries are working toward better integration to minimize the need for manual act wrapping [9].

Citations:


在 Line 207-226 增强定时器用例隔离,避免测试串扰

当前测试缺少两个关键的最佳实践:

  1. 定时器清理不可靠vi.useRealTimers() 仅在成功路径执行;若断言提前失败,伪计时器会污染后续测试。
  2. 状态更新未包裹 act()vi.advanceTimersByTime() 触发的 React 状态更新需要在 act() 中执行,否则可能出现"not wrapped in act"警告或竞态条件。

建议使用 try-finally 结构并在 finally 块中同时调用 vi.clearAllTimers()vi.useRealTimers() 来完全清理定时器。

建议修改
 test('should auto close after duration', () => {
   vi.useFakeTimers()
   const close = vi.fn()
   const click = vi.fn()
-  render(
-    <Popover
-      visible
-      duration={5000}
-      list={itemList}
-      onClose={close}
-      onClick={click}
-    >
-      <Button type="primary">自动关闭</Button>
-    </Popover>
-  )
-  vi.advanceTimersByTime(5000)
-  expect(close).toBeCalled()
-  expect(click).toBeCalled()
-  vi.useRealTimers()
+  try {
+    render(
+      <Popover
+        visible
+        duration={5000}
+        list={itemList}
+        onClose={close}
+        onClick={click}
+      >
+        <Button type="primary">自动关闭</Button>
+      </Popover>
+    )
+    act(() => {
+      vi.advanceTimersByTime(5000)
+    })
+    expect(close).toBeCalled()
+    expect(click).toBeCalled()
+  } finally {
+    vi.clearAllTimers()
+    vi.useRealTimers()
+  }
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('should auto close after duration', () => {
vi.useFakeTimers()
const close = vi.fn()
const click = vi.fn()
render(
<Popover
visible
duration={5000}
list={itemList}
onClose={close}
onClick={click}
>
<Button type="primary">自动关闭</Button>
</Popover>
)
vi.advanceTimersByTime(5000)
expect(close).toBeCalled()
expect(click).toBeCalled()
vi.useRealTimers()
})
test('should auto close after duration', () => {
vi.useFakeTimers()
const close = vi.fn()
const click = vi.fn()
try {
render(
<Popover
visible
duration={5000}
list={itemList}
onClose={close}
onClick={click}
>
<Button type="primary">自动关闭</Button>
</Popover>
)
act(() => {
vi.advanceTimersByTime(5000)
})
expect(close).toBeCalled()
expect(click).toBeCalled()
} finally {
vi.clearAllTimers()
vi.useRealTimers()
}
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/packages/popover/__tests__/popover.spec.tsx` around lines 207 - 226, The
test "should auto close after duration" has two timer-related issues that need
fixing. First, add a try-finally block to ensure timers are properly cleaned up
even if assertions fail early; in the finally block, call both
vi.clearAllTimers() and vi.useRealTimers() to completely reset the timer state.
Second, wrap the vi.advanceTimersByTime() call with the act() function from
React testing library to properly handle React state updates triggered by timer
advancement, which prevents "not wrapped in act" warnings and potential race
conditions.

Comment on lines +188 to 192
styles.left = pxTransform(left + width / 2 - edgeOffset + parallel)
}
if (skew === 'right') {
styles.left = pxTransform(right + parallel)
styles.left = pxTransform(left + width / 2 + edgeOffset + parallel)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

同步修复 Taro 端 RTL skew 锚点错位。

Line 188-192 的内容定位在 skew 分支固定走 styles.left,而 Line 218-228 的箭头已按 RTL 在左右侧切换。该不一致会在 RTL 下造成箭头与内容对齐偏差,需与 H5 端同策略修复。

Also applies to: 218-228

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/packages/popover/popover.taro.tsx` around lines 188 - 192, The skew
positioning logic in lines 188-192 consistently uses styles.left for both left
and right skew cases, but the arrow positioning logic in lines 218-228 has
already been updated to handle RTL by switching between left and right sides.
Apply the same RTL-aware strategy used in the arrow positioning section to the
content positioning in the skew branch. Instead of always assigning to
styles.left, conditionally assign to either styles.left or styles.right based on
the RTL direction check, ensuring the content anchor positioning aligns
correctly with the arrow positioning in RTL mode.

Comment on lines 210 to 215
if (skew === 'left') {
styles.left = `${left + parallel}px`
styles.left = `${left + width / 2 - edgeOffset + parallel}px`
}
if (skew === 'right') {
styles.left = `${right + parallel}px`
styles.left = `${left + width / 2 + edgeOffset + parallel}px`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

修复 RTL 下内容定位与箭头锚点不一致问题。

Line 211-214 在 skew === left/right 时始终写入 styles.left,但 Line 240-250 的箭头定位已经按 RTL 在 left/right 间切换。这样会导致 RTL 场景下内容容器与箭头锚点不在同一侧,出现偏移错位。

建议修复(示意)
- if (skew === 'left') {
-   styles.left = `${left + width / 2 - edgeOffset + parallel}px`
- }
- if (skew === 'right') {
-   styles.left = `${left + width / 2 + edgeOffset + parallel}px`
- }
+ if (skew === 'left') {
+   styles[dir] = `${wrapperPosition[dir] + width / 2 - edgeOffset + parallel}px`
+ }
+ if (skew === 'right') {
+   styles[dir2] = `${wrapperPosition[dir2] + width / 2 + edgeOffset + parallel}px`
+ }

Also applies to: 240-250

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/packages/popover/popover.tsx` around lines 210 - 215, The content
positioning logic in the skew === 'left' and skew === 'right' blocks always
assigns to styles.left, but the arrow positioning code (referenced around lines
240-250) already implements proper RTL handling by switching between left and
right. This inconsistency causes the content container and arrow anchor to be
positioned on different sides in RTL mode. Apply the same RTL-aware logic to the
content positioning by checking the RTL status and conditionally assigning to
either styles.left or styles.right (similar to how the arrow positioning handles
this), ensuring the content container and arrow anchor remain aligned in both
LTR and RTL modes.

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.18919% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.43%. Comparing base (a938cf8) to head (8e1951c).
⚠️ Report is 13 commits behind head on feat_v4.x.

Files with missing lines Patch % Lines
src/packages/popover/popover.tsx 88.88% 4 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           feat_v4.x    #3492      +/-   ##
=============================================
+ Coverage      88.33%   88.43%   +0.10%     
=============================================
  Files            295      296       +1     
  Lines          19747    19818      +71     
  Branches        3117     3136      +19     
=============================================
+ Hits           17443    17527      +84     
+ Misses          2298     2285      -13     
  Partials           6        6              

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action:review This PR needs more reviews (less than 2 approvals) size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant