Skip to content

Conversation

@oasis-cloud
Copy link
Collaborator

@oasis-cloud oasis-cloud commented Oct 20, 2025

Summary by CodeRabbit

发布说明

  • 新功能

    • Popup 组件新增 top 属性,支持在标题上方显示自定义内容
    • 新增字体大小和字重设计令牌,增强排版灵活性
  • 样式优化

    • Dialog 组件优化布局间距和按钮边框样式
    • 多个组件完善动态模式下的显示渲染逻辑
    • 调整输入框和弹出框组件的排版
  • 重构

    • NoticeBar 和 SwipeCell 组件内部逻辑优化
    • 多个 Taro 组件生命周期升级,提升性能
    • 事件处理机制改进
  • Bug 修复

    • 修复复选框活动状态样式应用

@github-actions github-actions bot added 3.x Target branch 3.x action:review This PR needs more reviews (less than 2 approvals) labels Oct 20, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Walkthrough

此PR包含事件系统重构(Events转eventCenter)、Popup组件新增top支持、Dialog样式更新、Taro组件生命周期优化(useLayoutEffect→useReady)、50余个组件的样式dynamic条件编译添加,以及主题系统扩展。

Changes

分组 / 文件 变更摘要
Taro事件系统重构
src/hooks/taro/use-custom-event.ts
将customEvents从new Events()改为eventCenter,改变事件注册源
Popup组件top支持
src/packages/popup/popup.tsx, src/packages/popup/popup.scss, src/types/spec/popup/base.ts, src/packages/popup/doc*.md, src/sites/sites-react/doc/docs/*/migrate-from-v2*.md
新增top prop用于在标题上方渲染自定义内容,含类型、样式、文档更新
Dialog样式与主题变量更新
src/packages/dialog/dialog.scss, src/packages/dialog/demos/taro/demo6.tsx, src/packages/configprovider/types.ts
调整dialog header/footer样式,添加字体权重和margin变量
样式主题系统扩展
src/styles/theme-default.scss, src/styles/variables.scss, src/styles/variables-jmapp.scss, src/styles/variables-jrkf.scss
新增font-size-icon、font-weight-medium变量,更新部分尺寸默认值
组件样式dynamic条件编译
src/packages/{animatingnumbers,badge,button,cascader,checkbox,checkboxgroup,divider,drag,elevator,inputnumber,loading,menuitem,noticebar,notify,radio,rate,resultpage,searchbar,segmented,signature,skeleton,steps,switch,tabpane,tabs,tag,timeselect,toast,virtuallist}/\*.scss
为display属性添加#ifndef/#ifdef dynamic条件块,在dynamic模式下从inline-flex切换到flex
Taro组件生命周期优化
src/packages/avatarcropper/avatarcropper.taro.tsx, src/packages/lottiemp/lottiemp.taro.tsx, src/packages/range/range.taro.tsx, src/packages/rate/rate.taro.tsx, src/packages/swipe/swipe.taro.tsx
用useReady替换useLayoutEffect,采用Taro生命周期而非React effect依赖
Checkbox活跃状态样式
src/packages/checkbox/checkbox.tsx, src/packages/checkbox/checkbox.taro.tsx
当innerChecked为true时添加${classPrefix}-active类名
NoticeBar大幅重构
src/packages/noticebar/noticebar.taro.tsx, src/packages/noticebar/demos/taro/demo10.tsx
引入useUuid、nextTick,新增renderLeftIcon/renderRight/renderRightIcon辅助函数,采用ID基础的rect查询,优化竖直滚动初始化
其他组件调整
src/packages/input/input.scss, src/packages/input/input.taro.tsx, src/packages/toast/toast.taro.tsx, src/utils/taro/get-rect-by-id.ts, src/utils/taro/env-type.ts
移除input line-height、调整disabled逻辑、toast平台适配、新增ENV_TYPE工具模块

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

变更涉及50+文件,包括结构化重构(NoticeBar、Swipe)、重复模式化修改(dynamic条件编译)和多类型编辑(样式、类型、Taro生命周期)。大量同构的条件编译块降低单项复杂度,但NoticeBar和Swipe的业务逻辑重构需要深度审查。

Possibly related PRs

Suggested reviewers

  • xiaoyatong
  • Alex-huxiyang

Poem

🐰 样式加编译,dynamic来切换,
事件投eventCenter,Taro生命周期优化长,
Popup顶部现新意,NoticeBar焕然新装,
主题变量齐出阵,NutUI如春风拂岸!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning PR描述完全为空。根据仓库的PR模板要求,应包含变动性质选择、相关Issue链接、需求背景解决方案、以及自查清单等多个必要部分。完全缺失描述信息意味着审阅者无法快速了解该PR的目的、影响范围和作者的自检情况,这对代码评审和合并决策造成了严重的信息缺失。 请根据仓库提供的PR模板补充完整的描述信息。至少应包括:(1) 勾选变动性质(如"功能增强"、"组件样式/交互改进"等);(2) 说明需求背景和解决方案;(3) 完成自查清单中的所有项目。这样可以帮助维护者快速评估PR的质量和影响范围。
Title Check ❓ Inconclusive PR标题"chore: 同步新增功能"过于宽泛和模糊,未能具体说明变动集中的主要改动。虽然这个标题不是完全离题,但从变动涉及多个组件的SCSS条件编译更新、TypeScript类型定义扩展、组件API增强(如Popup新增top属性)、工具函数重构等多个方面来看,"新增功能"这个描述不够具体。扫描PR历史的开发者无法从这个标题快速理解核心变动内容。 建议将标题改为更加具体和清晰的表述,例如区分出主要的变动点。可以考虑如"chore: 新增动态编译条件和主题变量"或"chore: 更新多个组件样式和功能"等,这样能让维护者和代码评审者快速理解PR的主要内容。
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore_v3.x

📜 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 5d77957 and 39f28a1.

⛔ Files ignored due to path filters (1)
  • src/packages/checkbox/__test__/__snapshots__/checkbox.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • src/packages/input/input.taro.tsx (2 hunks)
  • src/packages/popup/popup.tsx (5 hunks)
  • src/utils/taro/env-type.ts (1 hunks)
  • src/utils/taro/get-rect-by-id.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/utils/taro/env-type.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/packages/input/input.taro.tsx
  • src/packages/popup/popup.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/utils/taro/get-rect-by-id.ts (1)
src/utils/taro/env-type.ts (1)
  • ENV_TYPE (1-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: test
🔇 Additional comments (1)
src/utils/taro/get-rect-by-id.ts (1)

2-2: 重构已验证无误,可以合并。

验证结果确认:

  • ENV_TYPE.WEB 的值为 'WEB',与 Taro.ENV_TYPE.WEB 完全等价
  • ✓ 代码库中已无 Taro.ENV_TYPE 的残留引用,重构完整
  • ✓ 其他文件(如 input.taro.tsx)也正确使用了提取的 ENV_TYPE 常量,验证了一致性

此改动成功将环境类型常量提炼到公共位置,解决了之前的审查建议,无任何破坏性变更。


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.

Copy link

@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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/packages/swipe/swipe.taro.tsx (1)

149-160: 修正 toggle 中 opened 的判断

同理,这里应使用 opened.current,否则开启阈值 baseNum 计算错误。

-    const baseNum = opened ? 1 - base : base
+    const baseNum = opened.current ? 1 - base : base
🧹 Nitpick comments (12)
src/packages/noticebar/demos/taro/demo10.tsx (1)

31-37: 文本截断样式实现正确。

使用标准的 CSS 单行文本截断模式(overflow + whiteSpace + textOverflow),与 scrollable={false} 配合实现静态展示效果。

但需要注意:动态添加的项目(第 53 行)使用数字内容,无法演示文本截断效果,建议保持与初始数据相同的长文本格式以保证演示一致性。

可考虑修改动态添加逻辑:

         <Button
           size="small"
           onClick={() => {
-            setList((prev) => [...prev, `${prev.length + 1}`])
+            setList((prev) => [...prev, `新增项目 ${prev.length + 1}-公告栏公告栏公告栏公告栏`])
           }}
         >
src/hooks/taro/use-custom-event.ts (1)

6-7: 建议清理注释代码

虽然将 customEvents 更改为使用 eventCenter 是正确的架构改进(集中化事件管理),但建议删除第 6 行的注释代码。Git 历史已经保留了之前的实现,保留注释会增加代码噪音。

应用此差异来清理注释代码:

 import { eventCenter, getCurrentInstance } from '@tarojs/taro'
 import { useForceUpdate } from '@/hooks/use-force-update'
 
-// export const customEvents = new Events()
 export const customEvents = eventCenter
src/packages/swipe/swipe.taro.tsx (3)

106-109: 在 TouchStart 中等待宽度测量,避免首帧越界/跳变

未等待 getWidth() 即开始计算,会在慢设备/异步测量下出现首次滑动边界不准。

-    nextTick(() => getWidth())
+    nextTick(async () => {
+      await getWidth()
+    })

或直接:

-      getWidth()
+      await getWidth()

233-252: Taro 多端下直接使用 document 需加守卫

小程序端无 DOM,直接读写 document 可能报错。建议仅在 H5 生效或加类型守卫。

-    document.addEventListener('touchstart', handler)
-    return () => {
-      document.removeEventListener('touchstart', handler)
-    }
+    if (typeof document !== 'undefined' && document.addEventListener) {
+      document.addEventListener('touchstart', handler)
+      return () => document.removeEventListener('touchstart', handler)
+    }
+    return () => {}

请在 Taro H5 与微信/支付宝小程序分别验证是否正常关闭。


99-105: 使用 translate3d 提升移动端渲染性能(可选)

translate 改为 translate3d,更利于 GPU 合成。

-      transform: `translate(${state.offset}px, 0)`,
+      transform: `translate3d(${state.offset}px, 0, 0)`,
src/sites/sites-react/doc/docs/react/migrate-from-v2.md (1)

99-103: 微调中文表述与排版

建议在 title 两侧加空格,且用“上方”更自然。

-- 新增属性 top,用于在title上侧展示用户自定义内容
+- 新增属性 top,用于在 title 上方展示用户自定义内容
src/packages/popup/popup.scss (1)

102-104: 为 bottom-top 区域补充定位与尺寸,避免覆盖/错位

仅设置 position: absolute 可能导致与标题/内容重叠;建议补齐定位与宽度。

-    &-top {
-      position: absolute;
-    }
+    &-top {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      z-index: 1;
+    }

请结合组件运行时为主体内容区域腾挪相应的 padding-top(可由 JS 计算 top 区域高度后设置)并在 H5/Taro 小程序端回归。

src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md (1)

99-103: 统一术语与句式(英文文档)

将 attribute 改为 prop,简化句式,顺带避免重复 “Added …”。

-- Added a new attribute top to display user-defined content above the title.
+- Added a top prop to display custom content above the title.
src/utils/taro/get-rect-by-id.ts (1)

3-14: 建议提取共享的 ENV_TYPE 常量

在多个文件中发现了相同的 ENV_TYPE 常量定义(此文件和 src/packages/input/input.taro.tsx)。建议将其提取到共享的工具文件中,避免代码重复。

例如,可以创建 src/utils/taro/constants.ts

export const ENV_TYPE = {
  WEAPP: 'WEAPP',
  SWAN: 'SWAN',
  ALIPAY: 'ALIPAY',
  TT: 'TT',
  QQ: 'QQ',
  JD: 'JD',
  WEB: 'WEB',
  RN: 'RN',
  HARMONY: 'HARMONY',
  QUICKAPP: 'QUICKAPP',
} as const

然后在需要的地方导入使用:

import { ENV_TYPE } from '@/utils/taro/constants'
src/packages/input/input.taro.tsx (1)

18-29: ENV_TYPE 常量重复定义

此文件中的 ENV_TYPE 常量与 src/utils/taro/get-rect-by-id.ts 中的定义完全相同。建议提取到共享工具文件中以避免代码重复。

参考之前的建议,可以创建 src/utils/taro/constants.ts 并在两个文件中导入使用。

src/packages/noticebar/noticebar.taro.tsx (2)

164-171: 命名小误:warpRes → wrapRes

当前变量名与“wrap”语义不一致,易读性下降。建议统一为 wrapRes:

-      const warpRes = await getRectInMultiPlatform(wrapRef.current, wrapRefId)
+      const wrapRes = await getRectInMultiPlatform(wrapRef.current, wrapRefId)
-      if (!warpRes || !contentRes) return
-      const wrapW = warpRes.width
+      if (!wrapRes || !contentRes) return
+      const wrapW = wrapRes.width

145-148: 补充 initScrollWrap 的触发条件(可选)

内容宽度与滚动判定也会受 align、scrollable、speed、RTL 等影响,建议扩展依赖:

-  useEffect(() => {
-    initScrollWrap()
-  }, [content])
+  useEffect(() => {
+    initScrollWrap()
+  }, [content, align, scrollable, speed, rtl])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9a80b8 and 5d77957.

📒 Files selected for processing (62)
  • src/hooks/taro/use-custom-event.ts (1 hunks)
  • src/packages/animatingnumbers/countup.scss (1 hunks)
  • src/packages/avatarcropper/avatarcropper.taro.tsx (3 hunks)
  • src/packages/badge/badge.scss (2 hunks)
  • src/packages/button/button.scss (1 hunks)
  • src/packages/cascader/cascader.scss (1 hunks)
  • src/packages/checkbox/checkbox.scss (1 hunks)
  • src/packages/checkbox/checkbox.taro.tsx (1 hunks)
  • src/packages/checkbox/checkbox.tsx (1 hunks)
  • src/packages/checkboxgroup/checkboxgroup.scss (1 hunks)
  • src/packages/configprovider/types.ts (2 hunks)
  • src/packages/dialog/demos/taro/demo6.tsx (1 hunks)
  • src/packages/dialog/dialog.scss (3 hunks)
  • src/packages/divider/divider.scss (1 hunks)
  • src/packages/drag/drag.scss (1 hunks)
  • src/packages/elevator/elevator.scss (2 hunks)
  • src/packages/input/input.scss (0 hunks)
  • src/packages/input/input.taro.tsx (2 hunks)
  • src/packages/inputnumber/inputnumber.scss (1 hunks)
  • src/packages/loading/loading.scss (1 hunks)
  • src/packages/lottie/lottiemp.taro.tsx (3 hunks)
  • src/packages/menuitem/menuitem.scss (1 hunks)
  • src/packages/noticebar/demos/taro/demo10.tsx (3 hunks)
  • src/packages/noticebar/noticebar.scss (1 hunks)
  • src/packages/noticebar/noticebar.taro.tsx (12 hunks)
  • src/packages/notify/notify.scss (1 hunks)
  • src/packages/popup/doc.en-US.md (1 hunks)
  • src/packages/popup/doc.md (1 hunks)
  • src/packages/popup/doc.taro.md (1 hunks)
  • src/packages/popup/popup.scss (1 hunks)
  • src/packages/popup/popup.tsx (5 hunks)
  • src/packages/radio/radio.scss (1 hunks)
  • src/packages/range/range.taro.tsx (2 hunks)
  • src/packages/rate/rate.scss (1 hunks)
  • src/packages/rate/rate.taro.tsx (3 hunks)
  • src/packages/resultpage/resultpage.scss (1 hunks)
  • src/packages/searchbar/searchbar.scss (1 hunks)
  • src/packages/segmented/segmented.scss (1 hunks)
  • src/packages/sidebaritem/sidebaritem.scss (1 hunks)
  • src/packages/signature/demo.scss (1 hunks)
  • src/packages/skeleton/skeleton.scss (1 hunks)
  • src/packages/steps/steps.scss (2 hunks)
  • src/packages/swipe/swipe.taro.tsx (6 hunks)
  • src/packages/switch/switch.scss (2 hunks)
  • src/packages/tabpane/tabpane.scss (1 hunks)
  • src/packages/tabs/tabs.scss (1 hunks)
  • src/packages/tag/tag.scss (1 hunks)
  • src/packages/textarea/textarea.taro.tsx (0 hunks)
  • src/packages/timeselect/timeselect.scss (1 hunks)
  • src/packages/toast/toast.scss (2 hunks)
  • src/packages/toast/toast.taro.tsx (2 hunks)
  • src/packages/virtuallist/virtuallist.scss (1 hunks)
  • src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md (1 hunks)
  • src/sites/sites-react/doc/docs/react/migrate-from-v2.md (1 hunks)
  • src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md (1 hunks)
  • src/sites/sites-react/doc/docs/taro/migrate-from-v2.md (1 hunks)
  • src/styles/theme-default.scss (2 hunks)
  • src/styles/variables-jmapp.scss (3 hunks)
  • src/styles/variables-jrkf.scss (3 hunks)
  • src/styles/variables.scss (9 hunks)
  • src/types/spec/popup/base.ts (1 hunks)
  • src/utils/taro/get-rect-by-id.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • src/packages/input/input.scss
  • src/packages/textarea/textarea.taro.tsx
🧰 Additional context used
🧬 Code graph analysis (4)
src/packages/range/range.taro.tsx (1)
src/utils/taro/get-rect.ts (1)
  • getRectInMultiPlatform (29-55)
src/packages/toast/toast.taro.tsx (1)
src/utils/taro/platform.ts (1)
  • td (16-18)
src/packages/swipe/swipe.taro.tsx (2)
src/utils/taro/get-rect.ts (1)
  • getRectInMultiPlatform (29-55)
src/types/base/atoms.ts (1)
  • PositionX (42-42)
src/packages/noticebar/noticebar.taro.tsx (2)
src/hooks/use-uuid.ts (1)
  • useUuid (17-20)
src/utils/taro/get-rect.ts (1)
  • getRectInMultiPlatform (29-55)
🪛 LanguageTool
src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md

[style] ~101-~101: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ht, which can be used with resizable. - Added a new attribute top to display user-def...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md

[style] ~101-~101: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ht, which can be used with resizable. - Added a new attribute top to display user-def...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: build
🔇 Additional comments (78)
src/packages/inputnumber/inputnumber.scss (3)

2-7: 验证预处理器指令的用途和构建工具支持。

代码引入了 /* #ifndef dynamic *//* #ifdef dynamic */ 这样的条件编译指令。虽然这种模式在 C/C++ 中很常见,但在 SCSS 中需要明确说明:

  1. 构建工具支持:哪个构建工具或打包工具负责处理这些预处理器指令?是 Taro、Webpack、PostCSS 插件还是自定义工具?
  2. dynamic 标志用途:这个标志何时被定义?在哪些场景或构建配置中使用?
  3. 布局影响:从 inline-flex 切换到 flex 的语义差异是什么?这对组件的布局和渲染会产生什么影响?

9-10: 澄清宽度计算的格式调整。

第 9-10 行的宽度计算被重新格式化为两行。虽然这是一个较小的改变,但请确认:

  • 这是否与主要的 display 属性条件编译相关?
  • 或者这只是代码格式的优化?

2-11: 验证测试覆盖和相关配置变更。

这个改动引入了构建时的条件逻辑。请确认:

  1. 是否存在针对 dynamic 和非 dynamic 两种情况的测试覆盖?
  2. 是否在构建配置(如 package.json, tsconfig.json 或 Taro 配置)中添加了对应的标志定义?
  3. 此改动是否相关于 PR 标题中提到的"同步新增功能"?如果是,请在 PR 描述中补充相关背景信息。
src/packages/animatingnumbers/countup.scss (1)

3-8: 动态/非动态构建切换的条件指令使用正确。

预处理器指令格式规范,互斥条件清晰。非动态模式下使用 inline-flex,动态模式下切换为 flex,逻辑合理。该模式与 PR 中其他组件(如 badge、checkboxgroup、divider 等)的模式一致,符合预期的构建变体切换规范。

src/packages/steps/steps.scss (2)

117-122: 确认自定义预处理器配置

此处使用的 #ifndef dynamic#ifdef dynamic 指令为注释形式,依赖自定义构建工具进行条件编译处理。需要确认:

  1. 项目构建系统已正确配置以处理这些预处理指令
  2. 如果指令未被处理,最终 CSS 中将同时出现两个 display 声明,后者会覆盖前者

建议验证完整的构建流程以确保这些条件分支能够正确解析。


240-242: 验证单一守卫的语义

此处仅使用 #ifndef dynamic 保护 overflow: auto; 属性,与前面的双值守卫模式(117-122行)不同。这意味着:

  • 未定义 dynamic 时:应用 overflow: auto;
  • 定义 dynamic 时:该属性被省略

请确认在动态模式下 overflow 行为是否由其他样式规则控制,或确实应该省略此属性。建议补充对应的 #ifdef dynamic 块以明确双路径逻辑(即便该路径为空)。

src/packages/tabs/tabs.scss (2)

113-115: 验证自定义预处理器指令的处理

代码使用 CSS 注释形式的预处理器指令 /* #ifndef dynamic*/ 来条件性地包含 overflow: unset;。这种模式非标准,通常需要自定义构建工具处理。

请确认以下事项:

  1. 构建系统(webpack/rollup/其他)是否配置了处理这些注释指令的预处理器或插件?
  2. 这些指令在最终编译后的 CSS 中是否会被正确移除(在 dynamic 定义时)或保留(在 dynamic 未定义时)?
  3. 这种模式是否已在项目中的其他文件中验证过有效性?

如果您想,我可以生成一个脚本来搜索其他使用此模式的文件,确认一致性。


123-125: 模式一致性良好

与第 113-115 行一致,此段代码使用相同的预处理器指令模式。两处修改都在活跃状态选择器中,统一地应用了条件性 overflow: unset;。SCSS 语法本身没有问题。

src/packages/noticebar/demos/taro/demo10.tsx (2)

6-9: 数据更新合理。

扩展文本长度用于演示文本截断效果,与新增的样式功能配合良好。


20-20: 验证 scrollable={false} 的行为变更。

scrollable 设置为 false 会改变垂直公告栏的滚动行为,请确认这是演示预期的功能效果(静态展示 + 文本截断)。

src/packages/lottie/lottiemp.taro.tsx (3)

1-2: 引入 useReady 生命周期钩子符合 Taro 最佳实践。

将初始化逻辑从 useLayoutEffect 迁移到 useReady 是正确的做法,这是 Taro 为小程序环境提供的专用生命周期钩子,确保在页面准备就绪后再执行 canvas 初始化操作。


23-28: 验证 speed 属性的响应式行为。

setSpeed 函数的逻辑正确,使用 Math.abs(speed) 设置速度值,并根据正负号设置播放方向。但是,该函数仅在动画初始化时调用一次(第 67 行),如果 speed 属性在组件挂载后发生变化,动画速度不会更新。

请确认 speed 属性是否需要支持动态更新。如果需要,应添加一个 effect 来监听 speed 的变化并调用 setSpeed()

如需支持动态 speed,可参考以下实现:

// 在 useReady 之后添加
useEffect(() => {
  setSpeed()
}, [speed])

Also applies to: 67-67


31-75: useReady 钩子使用正确。

初始化逻辑正确地封装在 useReady 钩子中,包括 canvas 查询、Lottie 动画加载、事件监听器绑定以及速度设置。错误处理也已到位。这符合 Taro 小程序的开发规范。

src/packages/rate/rate.taro.tsx (3)

10-10: LGTM!正确引入 Taro 生命周期钩子。

使用 useReady 替代 React 的 useLayoutEffect 是 Taro 小程序环境的最佳实践,能确保在页面完全准备好后执行初始化逻辑。


134-143: 移除 useCallback 是可接受的简化。

updateRectsuseCallback 包裹的函数改为普通函数在功能上是正确的,因为该函数只在 useReadyhandleTouchStart 中直接调用,未作为依赖项传递。虽然每次渲染都会重新创建函数实例,但性能影响微乎其微,代码反而更简洁。


145-147: 优秀的 Taro 生命周期适配!

使用 useReady 替代 useLayoutEffect 是针对 Taro 小程序环境的正确做法:

  • useLayoutEffect 在小程序环境中可能无法按预期工作
  • useReady 确保在 Taro 页面完全就绪后执行,此时 refs 已正确填充
  • 配合 handleTouchStart 中的 updateRects() 调用(第 157 行),在用户交互时也能更新尺寸信息

这一改动与 Taro 4.0.12 的最佳实践保持一致。

src/packages/virtuallist/virtuallist.scss (1)

38-40: 这些预处理指令不被构建系统处理,是无效的 CSS 注释。

虽然 /* #ifndef dynamic*//* #ifdef */ 指令确实在项目中广泛使用(button、badge、animatingnumbers、address、virtuallist 等多个组件都有此模式),但构建系统并未处理它们。package.json 中仅配置了标准 Sass 和 PostCSS 工具,没有任何自定义预处理器插件来解析这些指令。

因此,这些指令仅作为普通 CSS 注释被忽略,不产生任何条件编译效果。这可能表示:

  • 该模式是遗留代码或来自前一个构建系统
  • 项目计划支持但尚未实现的功能
  • 对 SCSS 条件语法(应使用 @if/@else)的误解

建议: 如这些指令无实际用途,应从 virtuallist.scss 及整个项目中移除;或澄清它们是否为未来功能的占位符。

src/packages/timeselect/timeselect.scss (1)

19-21: 澄清非标准 CSS 预处理器指令的用途——该模式缺乏构建工具支持证据。

验证确认了这些 /* #ifndef dynamic*//* #endif */ 注释在代码库中被广泛使用(badge、elevator、noticebar、input 以及 20+ 个其他组件),但以下问题仍未解决:

  1. 无可见的构建工具支持:检查的 vite.config.site.mts 采用标准 SCSS 编译(modern-compiler API、postcss-import),但不包含处理这些 CSS 注释指令的自定义插件。

  2. 注释将被按字面意思编译:SCSS 编译器不处理这些指令;它们最终会作为字面 CSS 注释出现在编译后的 CSS 文件中,不影响样式。

  3. 用途不明确:代码库中未找到关于"dynamic"标志用途的文档;这些指令似乎要么是遗留代码,要么由未在 vite 配置中显示的后处理工具处理。

建议开发者验证并补充说明:

  • 这些指令是否由某个专用的后处理工具处理(如自定义 webpack 插件、构建脚本)?
  • "dynamic"标志的确切用途是什么?
  • 这个模式是否仍在维护,还是遗留代码?
src/packages/toast/toast.taro.tsx (1)

16-16: 引入平台检测工具函数

正确引入了 td 函数用于后续的动态平台渲染判断,与现有的 harmony 引入保持一致。

src/packages/toast/toast.scss (2)

99-102: 动态平台样式适配

为 harmony dynamic 平台添加了 line-height: normalheight: auto 覆盖,与 TypeScript 文件中使用 Text 组件的条件渲染逻辑配合良好,有助于文本在不同平台下的正确显示。


111-113: 确认样式差异是否有意为之

注意到 .nut-toast-title 的 harmony dynamic 块中仅添加了 line-height: normal,而未像 .nut-toast-text(第 99-102 行)那样同时添加 height: auto。请确认这种差异是有意设计还是遗漏。如果 title 也应该自适应高度,建议补充 height: auto

src/packages/cascader/cascader.scss (1)

14-16: 验证动态编译指令的构建系统支持。

此文件使用注释风格的预处理指令(/* #ifndef dynamic*/ 等)来条件编译CSS属性。需要确认构建系统是否正确支持并处理这些指令。建议补充构建配置文档说明如何启用/禁用"dynamic"模式。

src/packages/rate/rate.scss (1)

100-105: 确认 display 属性切换对布局的影响。

在动态模式下,display: inline-flex 改为 display: flex,这会改变评分组件相对于其他内联元素的布局行为。需要确保此改动在预期的使用场景中不会导致意外的页面布局变化,特别是在包含评分组件的行内上下文中。

src/packages/sidebaritem/sidebaritem.scss (1)

10-12: 验证 overflow 属性移除对滚动行为的影响。

在动态模式下,overflow: auto 会被完全移除。需要确保侧边栏项目内容超出容器时,动态模式下有适当的滚动处理机制或无此需求。建议在具体的使用场景中测试此改动。

src/packages/skeleton/skeleton.scss (1)

7-12: 确认动态模式下骨架屏布局的一致性。

骨架屏内容在动态模式下从 inline-flex 变为 flex。需要确保此改动不会导致骨架屏加载状态与实际加载后内容的布局差异,特别是在内联上下文中。

src/packages/segmented/segmented.scss (1)

2-7: 验证分段控制器在动态模式下的呈现行为。

分段控制组件在动态模式下从 display: inline-flex 改为 display: flex。请确认此改动在各种容器上下文(例如表单、工具栏、内联布局)中的表现符合预期,避免出现意外的换行或布局破损。

src/packages/drag/drag.scss (1)

10-15: 验证动态模式下拖拽元素的尺寸计算。

拖拽内部元素在动态模式下从 display: inline-flex 变为 display: flex。需要确保此改动不会影响被拖拽元素的 fit-content 尺寸计算和拖拽操作的流畅性。建议在实际拖拽场景中验证。

src/packages/signature/demo.scss (1)

16-21: 验证 demo 文件中的样式改动。

这是演示页面的样式改动,与实际组件功能无关。确保此改动仅影响演示UI,不会对签名组件本身的功能或布局造成影响。

src/packages/divider/divider.scss (1)

48-53: 确认垂直分隔线在动态模式下的对齐行为。

垂直分隔线在动态模式下从 display: inline-flex 改为 display: flex。需要确保此改动不会导致垂直分隔线与水平布局中其他元素的对齐问题,尤其是在涉及 vertical-align: middle 的场景中。

src/packages/tabpane/tabpane.scss (1)

9-11: 自定义预处理器指令需要构建系统支持

这些注释形式的条件编译块(/* #ifndef dynamic*/ 等)需要在构建过程中被正确处理,否则将以注释形式保留在最终的 CSS 中。请确认你的构建工具链支持这类指令的解析。

src/packages/tag/tag.scss (1)

65-70: 动态构建标志使用一致,需构建系统验证

这个文件遵循了 PR 中的一致模式,使用条件编译块切换 display 属性。请确认你的构建流程能够正确识别并处理这些 #ifndef#ifdef 指令。

src/packages/switch/switch.scss (1)

4-9: 多个条件块的处理需验证

此文件中两个独立的条件编译块(根元素和标签元素)都使用了动态标志。请确保你的构建系统能够正确处理同一文件中的多个 #ifndef dynamic 块。

Also applies to: 66-71

src/packages/noticebar/noticebar.scss (1)

39-47: 使用 initial 关键字存在潜在布局风险

与其他组件不同,这个文件使用 display: initialflex: initial,这会将这些属性重置为浏览器默认值(inline0 1 auto)。这可能会在非动态构建中破坏 flex 容器布局。请验证在两种构建模式下布局行为是否符合预期,并确保 initial 关键字的浏览器兼容性满足要求。

src/packages/notify/notify.scss (1)

76-84: 条件编译模式一致,需构建系统验证

此文件对图标元素使用了条件编译块。请确认构建工具能正确处理这些动态标志。

src/packages/checkboxgroup/checkboxgroup.scss (1)

32-39: 水平布局的条件编译应用正确,需构建系统验证

针对水平排列模式的复选框元素应用了条件编译块。请确保构建系统能正确处理此指令。

src/packages/resultpage/resultpage.scss (1)

8-20: 图标显示属性的条件编译应用标准,需构建系统验证

此文件对结果页面的图标元素使用了条件编译块切换显示属性。请确认构建工具支持该指令。

src/packages/loading/loading.scss (1)

2-7: 根级别条件编译应用标准,需构建系统验证

此文件在根组件级别应用了条件编译块。请确保构建系统能正确处理该指令,且不影响加载动画等其他功能。

src/packages/avatarcropper/avatarcropper.taro.tsx (2)

696-696: 与 AI 摘要不一致

AI 摘要中提到移除了 AvatarCropper.displayName 的赋值,但在提供的代码中第 696 行仍然保留了该赋值。请确认是否需要移除此行以保持与其他更改的一致性。


140-152: 原始审查评论基于对 Taro 生命周期的错误理解,代码实现实际上是正确的

Taro 的 useReady 仅在页面的 onReady 生命周期触发时执行一次,不会在返回页面时重新执行。返回页面会触发 onShow/useDidShow,而非 onReady/useReady。

审查评论声称"useReady 在每次页面显示时都会执行(包括从后台切换回来)",但这是错误的。代码中的 useReady 模式:

  • 在页面首次加载时执行一次
  • 自动获取 Alipay Canvas2D 节点引用
  • 与同一代码库的其他组件(swipe、rate、range、lottie)保持一致

不需要添加标志位来防止重复执行,因为 Taro 本身已确保 useReady 的单次执行。

Likely an incorrect or invalid review comment.

src/packages/menuitem/menuitem.scss (1)

31-41: LGTM!

条件编译块的使用正确,与 PR 中其他组件(badge.scss、elevator.scss 等)的模式保持一致。这允许在动态构建模式下使用 flex 而在常规模式下使用 inline-flex

src/packages/range/range.taro.tsx (1)

289-299: useReady + nextTick 的组合使用合理

使用 nextTick 延迟 rect 测量是正确的做法,确保 DOM 已经渲染完成。这比之前的 useLayoutEffect 更符合 Taro 的生命周期模型。

不过同样需要注意 useReady 在页面每次显示时都会执行,请确认是否需要添加逻辑来避免重复测量。

根据学习内容,建议在升级后针对各平台(微信、支付宝、京东、H5)进行全面测试。

src/packages/elevator/elevator.scss (2)

19-21: 验证移除 overflow 的影响

dynamic 模式下移除了 overflow: auto,这可能会影响滚动行为。请确保在动态构建环境中测试了电梯组件的滚动功能,特别是在内容超出容器高度时的表现。


100-106: LGTM!

条件编译模式与其他组件保持一致,在 dynamic 模式下使用 flex,在常规模式下使用 inline-flex

src/packages/badge/badge.scss (1)

1-51: LGTM!

Badge 组件的条件编译实现正确,与 PR 中其他组件保持一致。在基础类和 &-sup 变体中都正确应用了 dynamic 标志的判断。

src/styles/variables-jrkf.scss (2)

129-129: LGTM!

新增的 $font-weight-medium 变量定义合理,默认值 500 符合中等字重的标准。这扩展了主题定制能力。


1617-1640: LGTM!

新增的 Dialog 相关变量($dialog-title-margin-bottom$dialog-footer-button-border)提供了更细粒度的样式控制。默认值(8px 和 6px)符合设计系统规范。

这些变量已在 src/packages/configprovider/types.ts 中添加了对应的类型定义,保持了一致性。

根据相关上下文,这些变量也在 theme-default.scss 和 variables.scss 中有相应定义。

src/packages/configprovider/types.ts (2)

59-66: LGTM!

新增的 CSS 变量类型定义(nutuiFontSizeIconnutuiFontWeightMedium)与主题变量文件中的定义保持一致,扩展了类型安全的主题定制能力。


464-469: LGTM!

Dialog 相关的 CSS 变量类型(nutuiDialogTitleMarginBottomnutuiDialogFooterButtonBorder)与 variables-jrkf.scss 中新增的变量相对应,保持了类型定义的完整性。

根据相关上下文,这些变量也在 theme-default.scss 和 variables.scss 中有定义。

src/hooks/taro/use-custom-event.ts (1)

7-7: 评论已验证并确认无需改动

迁移到 eventCenter 是安全的。验证结果:

  1. 事件隔离性:✓ 通过 ${routerPath}__${selector} 命名规则确保唯一性,已在 toast/dialog/notify 中验证
  2. API 兼容性:✓ eventCenter 是 Taro 官方全局事件中心,完全支持代码中使用的 on/off/trigger 方法
  3. 内存泄漏防护:✓ 在 useCustomEvent 的 useEffect 中正确实现了清理函数调用 off()

该迁移符合 Taro 官方设计,代码实现完整无误。

src/types/spec/popup/base.ts (1)

18-22: 接口扩展合理,保持向后兼容

新增 top?: ReactNode 与文档、样式变更一致,无破坏性修改。

src/packages/checkbox/checkbox.tsx (1)

206-206: 代码变更符合预期。

新增的 ${classPrefix}-active 类在 checkbox 被选中时应用,为选中状态提供样式钩子。实现简洁且与 Taro 版本保持一致。

src/packages/radio/radio.scss (1)

52-57: 条件编译指令实现正确。

新增的动态构建守卫为 radio 按钮提供了构建时的布局切换能力(非动态构建使用 inline-flex,动态构建使用 flex),与项目中其他组件的模式保持一致。

src/packages/checkbox/checkbox.taro.tsx (1)

201-201: LGTM!

Taro 版本的实现与 Web 版本保持一致,正确添加了选中状态的样式类。

src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md (1)

101-101: 文档更新准确。

清晰地记录了 Popup 组件新增的 top 属性,说明其用途是在标题上方显示用户自定义内容。

src/packages/popup/doc.md (1)

94-94: 属性文档完整且格式正确。

新增的 top 属性文档清晰记录了类型和用途,格式与其他属性保持一致。

src/packages/popup/doc.en-US.md (1)

94-94: 英文文档正确且清晰。

top 属性的英文文档与中文版本保持一致,描述清晰。

src/sites/sites-react/doc/docs/taro/migrate-from-v2.md (1)

101-101: 迁移文档准确完整。

清晰记录了 Popup 组件新增的 top 属性及其用途,有助于用户从 v2 升级到 v3。

src/packages/checkbox/checkbox.scss (1)

68-73: 条件编译样式看起来正确

使用预处理器注释实现的条件编译语法正确,根据 dynamic 标志切换 display 属性(inline-flex vs flex)的逻辑清晰。

src/packages/button/button.scss (1)

58-60: 条件编译的 pointer-events 设置合理

在 dynamic 构建模式下为 ::before 伪元素添加 pointer-events: none 是合理的,可以防止遮罩层捕获指针事件,确保按钮交互正常工作。

src/packages/dialog/dialog.scss (4)

22-26: 条件编译注释已添加

在 transition 属性周围添加了 /* #ifndef dynamic *//* #endif */ 条件编译注释,与 PR 中其他组件的模式保持一致。


88-88: 标题下边距已更新为使用新变量

使用 $dialog-title-margin-bottom 变量替代硬编码值,提高了可维护性和主题定制能力。


131-132: 对话框底部按钮样式已增强

添加了 border-radiuspadding 属性,使用 CSS 变量提供了更好的主题定制支持。


147-149: 确认按钮字体粗细已调整

将 OK 按钮的 font-weight 从 $font-weight-bold (600) 改为 $font-weight-medium (500),这是一个视觉设计调整。请确认此更改符合设计规范要求。

src/styles/theme-default.scss (2)

276-277: 新增中等字重令牌

添加了 --nutui-font-weight-medium: 500,为字体粗细提供了更细粒度的控制选项。这与其他文件中的相关更新保持一致。


262-263: 字体大小令牌更新存在主题不一致问题,需要修正

验证发现 --nutui-font-size-l 的更改在主题间不一致:

  • theme-default.scss (第262行):已更新为 var(--nutui-font-size-15) (15px)
  • theme-dark.scss (第263行):仍为 var(--nutui-font-size-16) (16px)

受影响的组件(使用 $font-size-l):

  • src/packages/toast/toast.scss
  • src/packages/shortpassword/shortpassword.scss
  • src/packages/price/price.scss
  • src/packages/empty/empty.scss

新增的 --nutui-font-size-icon 令牌在 variables.scss 中已正确定义。

建议:同步更新 theme-dark.scss 第263行,保持两个主题的一致性。

src/styles/variables-jmapp.scss (3)

106-106: 新增中等字重变量

添加了 $font-weight-medium 变量,默认值为 500,与主题令牌保持一致,为字体粗细提供了更多选择。


1504-1507: 新增对话框标题下边距变量

添加了 $dialog-title-margin-bottom 变量(默认 8px),提供了对话框标题间距的主题定制能力。


1524-1527: 新增对话框底部按钮圆角变量

添加了 $dialog-footer-button-border 变量(默认 6px),使对话框按钮的圆角可以通过主题进行定制。

src/styles/variables.scss (9)

155-156: 字体大小令牌已更新

$font-size-l 从 16px 调整为 15px,同时新增了 $font-size-icon: 16px。这与 theme-default.scss 中的更改保持一致。

请参考 theme-default.scss 的评审意见,验证此更改对使用这些令牌的组件的影响。


165-165: 新增中等字重变量

添加了 $font-weight-medium: 500,为字体粗细提供了更细粒度的控制。


598-598: 输入框行高已更新

$input-lineheight 现在使用 $font-size-xl 而不是之前的值,这可能会影响输入框的垂直对齐。请确认此更改符合设计规范。


1084-1084: 弹出层标题字体大小已更新

$popup-title-font-size$font-size-l 更改为 $font-size-xl,由于 font-size-l 本身也减小了 1px,这个更改会使标题更大。请验证视觉效果是否符合预期。


1397-1401: 对话框标题和内容间距变量已添加

新增了 $dialog-title-margin-bottom (8px) 并更新了 $dialog-content-margin (0 0 20px 0),提供了更好的间距控制。这些变量与 dialog.scss 和 variables-jmapp.scss 中的更改保持一致。


1414-1417: 对话框底部按钮圆角变量已添加

新增了 $dialog-footer-button-border: 6px,为对话框底部按钮提供了圆角定制能力。


1436-1436: 对话框标题字体大小已更新

$dialog-header-font-size$font-size-l 更改为 $font-size-xl。考虑到 font-size-l 减小了,这个更改会使对话框标题更大。请验证是否符合设计意图。


1477-1477: 复选框图标字体大小使用新令牌

$checkbox-icon-font-size 现在使用 $font-size-icon (16px) 而不是 $font-size-l (15px),图标会稍微大一些。


1516-1519: 单选框图标字体大小使用新令牌

$radio-icon-font-size 现在使用 $font-size-icon (16px),与复选框的更改保持一致。

src/packages/input/input.taro.tsx (1)

211-211: 验证 disabled 属性变更与其他 Taro 组件的一致性

input.taro.tsx 中,disabled 属性仅传递 disabled,但 readOnly 未被传入原生 TaroInput 组件,这意味着 readonly 输入框不再完全禁用交互。

需要注意的是,同一库中的其他 Taro 组件(如 searchbar.taro.tsx 第 184、203 行,textarea.taro.tsx 第 131 行)仍然使用 disabled={disabled || readOnly} 的模式。此变更创建了库内的不一致性。

建议验证:

  1. readonly 输入框行为变更是否为有意为之
  2. 是否有现存代码依赖于 readonly 使输入框完全禁用
  3. 是否应与其他 Taro 组件保持一致

Comment on lines +43 to +46
onClose={() => {
setVisible2(false)
console.log('关闭底部icon 3')
}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

请移除调试日志,并考虑与第一个对话框保持一致性

添加 onClose 处理器来响应关闭图标的点击是合理的,但存在以下问题:

  1. 调试代码残留:第 45 行的 console.log('关闭底部icon 3') 看起来像是调试代码,不应该保留在演示代码中
  2. 不一致性:第一个对话框(第 15-28 行)同样设置了 closeIcon,但没有 onClose 处理器。请确认这种差异是否是有意为之,用于演示不同的用法

应用此修改以移除调试日志:

 onClose={() => {
   setVisible2(false)
-  console.log('关闭底部icon 3')
 }}

如果希望保持两个对话框的一致性,可以考虑为第一个对话框也添加 onClose 处理器:

<Dialog
  className="test-dialog"
  title="顶部带关闭按钮"
  visible={visible1}
  closeIcon
  closeIconPosition="top-right"
  style={{
    '--nutui-dialog-close-color': '#888B94',
  }}
  onConfirm={() => setVisible1(false)}
  onCancel={() => setVisible1(false)}
+ onClose={() => setVisible1(false)}
>
  支持函数调用和组件调用两种方式。
</Dialog>

🏁 Script executed:

#!/bin/bash
# 查看完整的演示文件内容,特别是两个 Dialog 组件的定义
cat src/packages/dialog/demos/taro/demo6.tsx

Length of output: 1263


🏁 Script executed:

#!/bin/bash
# 检查项目中是否有类似的 console.log 用法模式
rg "console\.log\(" src/packages/dialog/demos/ -n -B2 -A2 | head -50

Length of output: 1998


🏁 Script executed:

#!/bin/bash
# 检查文件中是否有其他中文日志,用于判断是否是有意的演示代码
rg "console\.(log|warn|error)" src/packages/dialog/demos/taro/ -n

Length of output: 159


移除调试日志,并建议与第一个对话框保持一致

通过验证完整文件内容确认:

  1. 调试代码需要删除:第45行的 console.log('关闭底部icon 3') 是中文调试信息,不应保留在演示代码中。相比之下,项目中其他demo文件使用的console.log(如'stop close'或'onClose')都是英文功能描述,而此处的中文信息明显是内部调试遗留。

  2. 两个Dialog的不一致性

    • 第一个Dialog(第15-28行):有 closeIcon 但无 onClose 处理器
    • 第二个Dialog(第35-50行):既有 closeIcon 又有 onClose 处理器

    建议保持一致,为两个Dialog都添加 onClose 处理器,使演示代码更清晰完整。

建议修改

移除第45行的调试日志:

 onClose={() => {
   setVisible2(false)
-  console.log('关闭底部icon 3')
 }}

同时为第一个Dialog添加 onClose 处理器以保持一致:

 <Dialog
   className="test-dialog"
   title="顶部带关闭按钮"
   visible={visible1}
   closeIcon
   closeIconPosition="top-right"
   style={{
     '--nutui-dialog-close-color': '#888B94',
   }}
   onConfirm={() => setVisible1(false)}
   onCancel={() => setVisible1(false)}
+  onClose={() => setVisible1(false)}
 >
📝 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
onClose={() => {
setVisible2(false)
console.log('关闭底部icon 3')
}}
onClose={() => {
setVisible2(false)
}}
🤖 Prompt for AI Agents
In src/packages/dialog/demos/taro/demo6.tsx around lines 43-46 (and also note
the first Dialog at lines 15-28), remove the debugging statement
console.log('关闭底部icon 3') and add an onClose handler to the first Dialog so both
Dialogs are consistent; the onClose handlers should mirror each other (set the
corresponding visible state to false) and avoid any debug-only console output.

useState,
useCallback,
} from 'react'
import { nextTick } from '@tarojs/taro'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

用 nextTick + 基于 id 的多端测量重构很赞

  • 使用 useUuid 生成 wrap/content 唯一 id 并配合 getRectInMultiPlatform,解决了小程序端无法直接用 ref 测量的问题;
  • nextTick 保证节点挂载后再测量,减少空 rect 的概率;
  • 横向场景只在可滚动时启动画动,逻辑清晰。

建议:

  • 在 H5 与各小程序端各跑一次 smoke(测量为空、重复初始化等);
  • 对于 RTL/align/scrollable/speed 等会影响宽度或滚动判定的 props,适当扩展触发 initScrollWrap 的依赖,避免遗漏重算。

我可提供简单用例矩阵以在 CI 执行。基于 Learnings(Taro 4.0.12 建议用统一 API 并保持多包对齐)。

Also applies to: 13-13, 73-76, 155-183, 505-510


🏁 Script executed:

#!/bin/bash
# 粗验初始化触发点,关注依赖项是否包含关键 props
rg -nP 'useEffect\(\s*\(\)\s*=>\s*{\s*initScrollWrap' src/packages/noticebar/noticebar.taro.tsx -C3

Length of output: 0


搜索结果中未找到 getRectInMultiPlatform 的具体文档。我需要先审视原始文件内容,理解代码结构和依赖问题。


🏁 Script executed:

#!/bin/bash
# 查看文件前 100 行,定位关键函数和 import
head -100 src/packages/noticebar/noticebar.taro.tsx

Length of output: 2622


🏁 Script executed:

#!/bin/bash
# 搜索 initScrollWrap 的定义
rg -n 'initScrollWrap' src/packages/noticebar/noticebar.taro.tsx -B2 -A5

Length of output: 551


🏁 Script executed:

#!/bin/bash
# 搜索所有 useEffect 及其依赖
rg -n 'useEffect' src/packages/noticebar/noticebar.taro.tsx -B1 -A6

Length of output: 1147


🏁 Script executed:

#!/bin/bash
# 搜索 handleClickIcon 的定义和实现
rg -n 'handleClickIcon' src/packages/noticebar/noticebar.taro.tsx -B2 -A10

Length of output: 1021


修复 handleClickIcon 的关闭逻辑和补充 initScrollWrap 依赖

发现两处需要修复的问题:

  1. 行 219-227 handleClickIcon 语义错误
    当前 setShowNoticeBar(!closeable) 导致逻辑反向。当 closeable=false 时,!closeable=true 会显示通知栏(无法真正关闭),违反预期。应改为 setShowNoticeBar(false) 或添加条件判断 if (closeable) 后才调用 onClose,避免 closeable=false 时仍然触发关闭回调。

  2. 行 128-142 首个 useEffect 依赖不完整
    当前依赖仅包含 [isVertical, children, list],缺少 directionalignscrollablespeedwrap 等会影响滚动判定的 props。当这些 props 变化时无法触发 initScrollWrap 重算,可能导致测量结果过期。建议补充完整依赖。

🤖 Prompt for AI Agents
In src/packages/noticebar/noticebar.taro.tsx around lines 219-227, fix the close
logic by changing the toggle to explicitly hide the bar and only invoke the
onClose callback when the component is actually closeable (call
setShowNoticeBar(false) and if (closeable) onClose?.()). In
src/packages/noticebar/noticebar.taro.tsx around lines 128-142, update the first
useEffect dependency array to include all props that affect scroll computation —
add direction, align, scrollable, speed, wrap (and any other props used in
initScrollWrap) so initScrollWrap reruns when those change.

Comment on lines +219 to +227
const handleClickIcon = useCallback(
(event: ITouchEvent) => {
event.stopPropagation()
setShowNoticeBar(!closeable)
close && close(event)
onClose && onClose(event)
},
[close, onClose, closeable]
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

右侧图标点击语义不当:在不可关闭时也触发 onClose,且会把条目“强制显示”

现实现为:

  • setShowNoticeBar(!closeable):closeable=false 时点击会将其设为 true;
  • 无论 closeable 与否,都会调用 close/onClose。

期望:

  • 仅在 closeable=true 时关闭并触发 onClose;
  • closeable=false 且存在自定义 rightIcon 时,点击应透传为普通点击(或触发 click/onClick),不改变显隐。

修复建议:

-  const handleClickIcon = useCallback(
-    (event: ITouchEvent) => {
-      event.stopPropagation()
-      setShowNoticeBar(!closeable)
-      close && close(event)
-      onClose && onClose(event)
-    },
-    [close, onClose, closeable]
-  )
+  const handleClickIcon = useCallback(
+    (event: ITouchEvent) => {
+      event.stopPropagation()
+      if (closeable) {
+        setShowNoticeBar(false)
+        close?.(event)
+        onClose?.(event)
+      } else {
+        // 不可关闭时,将点击行为上抛,保持语义一致
+        click?.(event)
+        onClick?.(event)
+      }
+    },
+    [closeable, close, onClose, click, onClick]
+  )

Also applies to: 485-499

🤖 Prompt for AI Agents
In src/packages/noticebar/noticebar.taro.tsx around lines 219-227 (also applies
to 485-499), the right-icon click handler unconditionally toggles visibility and
calls close/onClose even when closeable is false, causing non-closeable bars to
be forced visible and firing onClose incorrectly; update the handler so that if
closeable is true it sets show state to false and calls close/onClose, otherwise
if a custom rightIcon exists it should stop propagation only and invoke the
generic click/onClick handler (or let the event bubble) without changing
visibility or calling close/onClose; ensure dependency array remains correct and
mirror the same fix at the other occurrence (lines 485-499).

| minHeight | 设置最小高度 | `string` | `26%` |
| left | 标题左侧部分 | `ReactNode` | `-` |
| title | 标题中间部分 | `ReactNode` | `-` |
| top | 頂部佔位 | `ReactNode` | `-` |
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

文字使用不一致。

此处使用了繁体中文"頂部佔位",而同一属性在 src/packages/popup/doc.md 第 94 行使用的是简体中文"顶部占位"。为保持项目文档的一致性,建议统一使用简体中文。

应用以下修改以保持一致:

-| top | 頂部佔位 | `ReactNode` | `-` |
+| top | 顶部占位 | `ReactNode` | `-` |
📝 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
| top | 頂部佔位 | `ReactNode` | `-` |
| top | 顶部占位 | `ReactNode` | `-` |
🤖 Prompt for AI Agents
In src/packages/popup/doc.taro.md around line 104, the property description uses
Traditional Chinese "頂部佔位" which is inconsistent with the Simplified Chinese
"顶部占位" used in src/packages/popup/doc.md line 94; update the string at line 104
to the Simplified Chinese "顶部占位" so both documents use the same wording.

Comment on lines +69 to 70
top,
description,
Copy link

@coderabbitai coderabbitai bot Oct 20, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

新增 top API 与结构注入整体看起来合理

  • API 扩展与渲染入口清晰;引入独立 ref 便于定位样式。
  • 建议仅在 position==='bottom' 时渲染/定位 ${classPrefix}-bottom-top,避免其它位置出现意外定位逻辑。
  • 命名“top”与 CSS 属性同名,易产生理解歧义;若后续还有 header/extra 等区域,考虑顶层 API 命名一致性(可选)。

是否已同步更新类型定义与文档示例(多端)?若需要,我可批量检查类型与文档引用处。

Also applies to: 92-92, 192-200, 310-310


🏁 Script executed:

#!/bin/bash
# 检查类型与文档是否一致暴露了 top
rg -nP --type=ts,tsx '\btop\?\s*:\s*ReactNode' src/types -C2
rg -nP 'Popup.*top' src/packages/popup -C2
rg -nP 'top.*Popup' src/packages/popup/doc.* -C2

Length of output: 458


Now let me run scripts to directly inspect the codebase:


🏁 Script executed:

#!/bin/bash
# Directly inspect popup.tsx file at mentioned line numbers and surrounding code
# Also search for type definitions

# 1. Check lines 69-70 in popup.tsx
echo "=== Lines 69-70 in popup.tsx ==="
sed -n '65,75p' src/packages/popup/popup.tsx

# 2. Check line 92 in popup.tsx
echo -e "\n=== Line 92 in popup.tsx ==="
sed -n '88,96p' src/packages/popup/popup.tsx

# 3. Check lines 192-200 in popup.tsx  
echo -e "\n=== Lines 192-200 in popup.tsx ==="
sed -n '188,204p' src/packages/popup/popup.tsx

# 4. Check line 310 in popup.tsx
echo -e "\n=== Line 310 in popup.tsx ==="
sed -n '306,314p' src/packages/popup/popup.tsx

# 5. Find type definition files
echo -e "\n=== Type definition files for Popup ==="
find src -name "*.d.ts" -o -name "*type*" | grep -i popup | head -10

# 6. Search for interface or type definitions with 'top'
echo -e "\n=== Type definitions with 'top' property ==="
rg -n "^\s*top\?" src/packages/popup --type ts --type tsx -C 2 2>/dev/null || echo "No matches found"

# 7. Find documentation files
echo -e "\n=== Documentation files ==="
find src/packages/popup -name "*.md" -o -name "*doc*" | head -10

Length of output: 1513


🏁 Script executed:

#!/bin/bash
# Find type definitions and understand the structure

# 1. Search for PopupProps interface/type definition
echo "=== PopupProps type definition ==="
rg -n "interface PopupProps|type PopupProps|export.*Props" src/packages/popup/popup.tsx -A 50 | head -80

# 2. Check the index.ts file for exports
echo -e "\n=== Index.ts exports ==="
cat src/packages/popup/index.ts 2>/dev/null || echo "File not found"

# 3. Search for 'top' property in type definitions
echo -e "\n=== Search for 'top' in all tsx/ts files ==="
rg -n '\btop\b' src/packages/popup/popup.tsx -B 2 -A 2 | grep -E "(interface|type|:\s|top)" | head -20

# 4. Check CSS files for bottom-top class
echo -e "\n=== Search for CSS class 'bottom-top' ==="
find src/packages/popup -name "*.css" -o -name "*.scss" -o -name "*.less" | xargs rg -n "bottom-top" 2>/dev/null || echo "No CSS files found"

# 5. Check documentation for 'top' prop examples
echo -e "\n=== Check documentation for top prop ==="
rg -n "top" src/packages/popup/doc.md -B 2 -A 2 | head -40

# 6. Look at full popup.tsx top-level interface
echo -e "\n=== Full props destructuring area ==="
sed -n '1,100p' src/packages/popup/popup.tsx | tail -50

Length of output: 2550


🏁 Script executed:

#!/bin/bash
# Find type definitions and verify consistency

# 1. Find the types file
echo "=== Find @/types location ==="
find src -name "types.ts" -o -path "*/types/index.ts" | head -5

# 2. Search for TaroPopupProps definition
echo -e "\n=== Search for TaroPopupProps definition ==="
rg -n "TaroPopupProps|interface.*PopupProps" src -A 30 | head -100

# 3. Check if 'top' property exists in type
echo -e "\n=== Check for 'top' property in Popup types ==="
rg -n "top.*ReactNode|top\?" src -C 3 | grep -A 5 -B 5 "Popup\|Props" | head -40

# 4. Search for where "bottom-top" class is used/styled
echo -e "\n=== Search for bottom-top class usage ==="
rg -n "bottom-top" src -C 2

# 5. Search for position check in renderTop or similar
echo -e "\n=== Check position logic in popup ==="
sed -n '190,210p' src/packages/popup/popup.tsx

# 6. Check test file for top prop usage
echo -e "\n=== Check test file for top prop ==="
rg -n "top" src/packages/popup/__tests__/popup.spec.tsx -B 2 -A 2

Length of output: 7005


🏁 Script executed:

#!/bin/bash
# Find BasePopup and verify type definitions

# 1. Search for BasePopup definition
echo "=== Search for BasePopup definition ==="
rg -n "interface BasePopup|type BasePopup|export.*BasePopup" src -A 40 | head -120

# 2. Directly search for 'top' in popup type files
echo -e "\n=== Search for 'top' in popup type files ==="
rg -n "top" src/types/spec/popup/ -B 3 -A 3

# 3. Check if class naming "bottom-top" appears elsewhere
echo -e "\n=== Check class naming patterns ==="
rg -n "popup-.*-top|bottom-top" src --type ts --type tsx | head -20

# 4. Verify test expectation
echo -e "\n=== Full test context ==="
sed -n '35,40p' src/packages/popup/__tests__/popup.spec.tsx

Length of output: 3158


修复类名与条件渲染逻辑,确保与测试和设计一致

src/packages/popup/popup.tsx 中发现以下问题:

  1. 第 195 行类名错误:当前生成 ${classPrefix}-bottom-top,但测试期望 ${classPrefix}-top.nut-popup-top)。类名不匹配导致测试失败。

  2. 第 192-200 行缺少位置条件renderTop() 无条件渲染,而 renderTitle() 函数(第 203 行)采用 position === 'bottom' 检查。建议 renderTop() 也遵循相同的位置逻辑模式,避免不一致行为。

验证结果

  • ✓ 类型定义已正确包含 top?: ReactNodesrc/types/spec/popup/base.ts:20
  • ✓ 文档已更新(doc.md 第 94 行)
  • ✗ 实现存在类名与条件逻辑缺陷
🤖 Prompt for AI Agents
In src/packages/popup/popup.tsx around lines 192-203 (and specifically line
~195), fix the rendering and class name logic: change the generated class from
`${classPrefix}-bottom-top` to `${classPrefix}-top` and make renderTop() follow
the same positional guard as renderTitle() by only rendering when position ===
'top'; ensure renderTop uses the correct classPrefix (`${classPrefix}-top`) and
conditional check to match tests and design.

Copy link
Collaborator

Choose a reason for hiding this comment

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

这里可以看下ai提示~

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the test file to see what class name is expected
echo "=== Test file content for top prop ==="
cat src/packages/popup/__tests__/popup.spec.tsx | grep -A 10 -B 10 "nut-popup-top" || echo "No match found in test file"

# Check SCSS to see the class structure
echo -e "\n=== SCSS class structure ==="
cat src/packages/popup/popup.scss | grep -A 5 -B 2 "bottom-top\|&-top"

# Check demo6 to see how top prop is used
echo -e "\n=== Demo6 usage ==="
cat src/packages/popup/demos/taro/demo6.tsx | grep -A 20 "visible2"

# Check if there are other position checks in renderTitle
echo -e "\n=== renderTitle position logic ==="
sed -n '202,230p' src/packages/popup/popup.tsx

Length of output: 2842


@xiaoyatong 我检查了一下,AI 提示中关于类名的问题是误判,但位置条件判断的建议是合理的:

1. 类名问题 - AI 误判 ❌

AI 把两个不同的功能混淆了:

  • 现有功能: position="top" → 生成 .nut-popup-top 类(用于从顶部弹出)
  • 新增功能: top prop → 生成 .nut-popup-bottom-top 类(在 bottom 弹窗标题上方显示内容)

当前实现 ${classPrefix}-bottom-top 与 SCSS 定义 &-top (嵌套在 &-bottom 下) 是完全匹配的,无需修改。

2. 位置条件判断 - 建议合理 ✅

不过 AI 关于位置判断的建议是对的。建议在 renderTop() 中添加位置检查:

const renderTop = () => {
  if (!top || position !== 'bottom') return null
  return (
    <div className={`${classPrefix}-bottom-top`} ref={topNodeRef}>
      {top}
    </div>
  )
}

理由:

  1. 文档说明该功能是"在 title 上侧展示用户自定义内容",主要针对 bottom 弹窗场景
  2. SCSS 类明确定义在 .nut-popup-bottom
  3. renderTitle()left/title/description 的条件渲染逻辑保持一致(第 206 行)
  4. 在 center/top/left/right 位置渲染该元素没有实际意义

是否需要添加这个位置判断?

Comment on lines +147 to +152
useEffect(() => {
if (topNodeRef.current && nodeRef.current) {
topNodeRef.current.style.bottom = `${nodeRef.current?.clientHeight}px`
}
}, [innerVisible])

Copy link

@coderabbitai coderabbitai bot Oct 20, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

resizable 场景下“顶部区块”不会跟随高度变化,易出现错位

仅在 innerVisible 变化时设置一次 bottom,会在拖拽调整高度或内容高度变化后与弹层脱节。建议:

  • 仅在 position==='bottom' 时更新;
  • 在拖拽过程中同步 topNodeRef 的 bottom;
  • 可选:用 ResizeObserver 监听高度变化,避免手动同步多处。

修复示例(必要最少变更):

-  useEffect(() => {
-    if (topNodeRef.current && nodeRef.current) {
-      topNodeRef.current.style.bottom = `${nodeRef.current?.clientHeight}px`
-    }
-  }, [innerVisible])
+  useEffect(() => {
+    if (position === 'bottom' && topNodeRef.current && nodeRef.current) {
+      topNodeRef.current.style.bottom = `${nodeRef.current.clientHeight}px`
+    }
+  }, [innerVisible, position])

并在拖拽时同步:

     nodeRef.current.style.height = `${currentHeight}px`
+    // 同步顶部区块位置(仅 bottom 模式)
+    if (position === 'bottom' && topNodeRef.current) {
+      topNodeRef.current.style.bottom = `${currentHeight}px`
+    }

Also applies to: 264-272

🤖 Prompt for AI Agents
In src/packages/popup/popup.tsx around lines 147-152, the current useEffect only
updates topNodeRef.style.bottom once when innerVisible changes, causing the top
block to desync during resizes or dragging; change the logic to only run when
position === 'bottom', and add a ResizeObserver on nodeRef (or listen to its
size changes) to update topNodeRef.style.bottom to
`${nodeRef.current.clientHeight}px` whenever height changes; additionally,
invoke the same update function from the drag handlers so the bottom is synced
during dragging; apply the identical fix to the similar section at lines
264-272.

Copy link
Collaborator

Choose a reason for hiding this comment

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

这个看上去很有用~~

Copy link

Choose a reason for hiding this comment

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

@xiaoyatong 很高兴这个建议对您有帮助!😊

如果您在实现修复时需要任何帮助,或者想讨论其他实现方案(比如使用 ResizeObserver),随时告诉我。

Comment on lines +124 to +129
/* #ifndef dynamic*/
display: inline-flex;
/* #endif */
/* #ifdef dynamic*/
display: flex;
/* #endif */
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CSS 级联会覆盖条件注释 — 无法按预期工作。

在第 124-129 行添加的预处理器风格的注释(/* #ifndef dynamic*//* #ifdef dynamic*/)不会被 SCSS 编译器解析。SCSS 会编译两个 display 规则,CSS 级联机制会始终应用最后定义的值(display: flex;),使条件逻辑无效。

条件注释只有在存在专门的自定义预处理器来处理这些指令时才能生效。当前的实现方式:

  • 不符合 SCSS/CSS 标准
  • 会导致 display: inline-flex; 被忽略
  • 行为无法根据 dynamic 状态改变

请验证以下几点:

  1. 构建管道中是否存在处理 /* #ifndef *//* #ifdef */ 指令的自定义预处理器?
  2. 预期的行为是什么?是否应该根据 dynamic 条件动态改变 display 属性?

如果确实需要条件分支,建议改用以下标准方案之一:

方案 1:使用 SCSS @if 和变量

&-left,
&-right {
  @if variable-exists(dynamic) and $dynamic {
    display: flex;
  } @else {
    display: inline-flex;
  }
  align-items: center;
  // ...
}

方案 2:使用 CSS 自定义属性(CSS Variables)

&-left,
&-right {
  display: var(--searchbar-display, inline-flex);
  align-items: center;
  // ...
}

然后在 JavaScript 或根样式中动态设置 --searchbar-display 的值。


🏁 Script executed:

#!/bin/bash
# Search for similar preprocessor-style directives in the codebase
echo "=== Searching for preprocessor directives ===" 
rg -n '#ifndef|#ifdef|#endif' --type scss --type css --type ts --type js

echo ""
echo "=== Searching for 'dynamic' in searchbar files ===" 
rg -n 'dynamic' src/packages/searchbar/ -C2

echo ""
echo "=== Checking for build config files ===" 
fd -e 'webpack.config.*|vite.config.*|taro.config.*|rollup.config.*' .

echo ""
echo "=== Checking package.json for build tools ===" 
cat package.json | grep -A 20 '"devDependencies"' | head -30

echo ""
echo "=== Looking at surrounding code context ===" 
sed -n '110,135p' src/packages/searchbar/searchbar.scss

Length of output: 1971


🏁 Script executed:

#!/bin/bash
# Search for taro config files at any depth
echo "=== Searching for taro.config files ===" 
find . -name 'taro.config.*' -o -name '.tarorc*' 2>/dev/null

echo ""
echo "=== Checking searchbar component entry ===" 
cat src/packages/searchbar/index.ts 2>/dev/null || cat src/packages/searchbar/index.tsx 2>/dev/null || cat src/packages/searchbar/index.js 2>/dev/null || echo "Not found"

echo ""
echo "=== Searching for preprocessor/dynamic references in ts/tsx files ===" 
rg -n 'dynamic|preprocessor|#ifdef|#ifndef' --type ts --type tsx -i | head -20

echo ""
echo "=== Checking project root for config/docs ===" 
ls -la | grep -i 'taro\|config\|readme'

echo ""
echo "=== Checking package.json main/type fields ===" 
cat package.json | grep -E '"main"|"type"|"scripts"' | head -20

Length of output: 1521


🏁 Script executed:

#!/bin/bash
# Check if "dynamic" mode is used anywhere in the codebase
echo "=== Searching for 'dynamic' across entire codebase ===" 
rg -n -i 'dynamic.*display|display.*dynamic' --type-list | head -10
find . -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' \) -exec grep -l 'dynamic' {} \; 2>/dev/null | head -10

echo ""
echo "=== Check searchbar component context - is there a dynamic mode parameter? ===" 
cat src/packages/searchbar/searchbar.tsx 2>/dev/null | grep -A 5 -B 5 'interface\|type.*Props\|export.*SearchBar' | head -40

echo ""
echo "=== Check if NutUI docs mention dynamic or display modes ===" 
cat README.md | grep -i 'dynamic\|display\|searchbar' | head -10

echo ""
echo "=== Verify: what does SCSS compilation produce with cascade rule? ===" 
echo "Two consecutive display properties will result in the LAST one being used in final CSS"
</parameter>

Length of output: 1561


CSS 级联覆盖条件注释——预处理器未激活,条件逻辑无效。

在第 124-129 行的预处理器风格注释(/* #ifndef dynamic*//* #ifdef dynamic*/)无法生效,原因如下:

  1. 预处理器未启用:项目中不存在 taro.config.js,Taro 条件编译未激活
  2. SCSS 编译级联:SCSS 编译器将这些注释视为普通注释,编译两个 display 规则,CSS 级联机制最终只应用最后定义的值(display: flex;
  3. 无效的条件分支:第 125 行的 display: inline-flex; 被彻底忽略,dynamic 变量在组件中不存在

验证结果表明:SearchBar 组件不存在 dynamic 模式或相关属性,这些指令是完全无效的代码。

需要修复

  • 移除这些无效的预处理器注释,保留单一的 display 值;或
  • 如果确实需要条件分支,使用 SCSS 变量、CSS 自定义属性或组件 props 实现
🤖 Prompt for AI Agents
In src/packages/searchbar/searchbar.scss lines 124-129, the preprocessor-style
comments (/* #ifndef dynamic*/ / /* #ifdef dynamic*/ ) are inert here and cause
both display rules to be emitted, so remove those conditional comments and keep
a single display declaration (e.g., keep display: flex; and delete display:
inline-flex; and the surrounding comment markers). If conditional behavior is
actually required, replace this with a real mechanism: use an SCSS variable or
CSS custom property toggled by a class or the component prop (set the class from
the component and switch display via that class) rather than preprocessor
comments.

Comment on lines +84 to +98
const setActionWidth = (fn: any) => {
const res = fn()
if (res.left !== undefined) {
updateState({
...actionWidth.current,
left: res.left,
})
}

getWidth()
}, [leftId, rightId, setActionWidth])

const wrapperStyle = {
transform: `translate(${state.offset}${!harmony() ? 'px' : ''}, 0)`,
transitionDuration: state.dragging ? '0s' : '.6s',
}
const onTouchStart = async (event: BaseEventOrig<HTMLDivElement>) => {
if (leftWrapper.current) {
const leftRect = await getRectInMultiPlatform(leftWrapper.current, leftId)
leftRect && setActionWidth((v: any) => ({ ...v, left: leftRect.width }))
if (res.right !== undefined) {
updateState({
...actionWidth.current,
right: res.right,
})
}
if (rightWrapper.current) {
const rightRect = await getRectInMultiPlatform(
rightWrapper.current,
rightId
)
rightRect &&
setActionWidth((v: any) => ({ ...v, right: rightRect.width }))
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

修复 setActionWidth 回调参数导致的运行时错误

当前对 fn() 不传参,getWidth 里回调使用了 { ...v },会对 undefined 执行对象展开,产生 TypeError。应将当前宽度作为参数传入回调,或直接合并更新。

建议最小修复:

-  const setActionWidth = (fn: any) => {
-    const res = fn()
+  const setActionWidth = (fn: any) => {
+    const res = fn(actionWidth.current)
     if (res.left !== undefined) {
       updateState({
         ...actionWidth.current,
         left: res.left,
       })
     }
     if (res.right !== undefined) {
       updateState({
         ...actionWidth.current,
         right: res.right,
       })
     }
   }
📝 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
const setActionWidth = (fn: any) => {
const res = fn()
if (res.left !== undefined) {
updateState({
...actionWidth.current,
left: res.left,
})
}
getWidth()
}, [leftId, rightId, setActionWidth])
const wrapperStyle = {
transform: `translate(${state.offset}${!harmony() ? 'px' : ''}, 0)`,
transitionDuration: state.dragging ? '0s' : '.6s',
}
const onTouchStart = async (event: BaseEventOrig<HTMLDivElement>) => {
if (leftWrapper.current) {
const leftRect = await getRectInMultiPlatform(leftWrapper.current, leftId)
leftRect && setActionWidth((v: any) => ({ ...v, left: leftRect.width }))
if (res.right !== undefined) {
updateState({
...actionWidth.current,
right: res.right,
})
}
if (rightWrapper.current) {
const rightRect = await getRectInMultiPlatform(
rightWrapper.current,
rightId
)
rightRect &&
setActionWidth((v: any) => ({ ...v, right: rightRect.width }))
}
const setActionWidth = (fn: any) => {
const res = fn(actionWidth.current)
if (res.left !== undefined) {
updateState({
...actionWidth.current,
left: res.left,
})
}
if (res.right !== undefined) {
updateState({
...actionWidth.current,
right: res.right,
})
}
}
🤖 Prompt for AI Agents
In src/packages/swipe/swipe.taro.tsx around lines 84 to 98, setActionWidth calls
fn() with no args and then spreads returned values causing a TypeError when the
callback does something like `{ ...v }` with undefined; change setActionWidth to
pass the current width into the callback (e.g., call fn(actionWidth.current))
and update state by merging with existing values so undefined fields do not
overwrite current widths (use conditional/nullable merging so only provided
left/right replace existing ones).

Comment on lines +116 to +134
if (props.disabled) return
touch.move(event)
props.onTouchMove?.(event)
if (touch.isHorizontal()) {
lockClick.current = true
const newState = { ...state, dragging: true }
const isEdge = !opened || touch.deltaX.current * startOffset.current < 0
if (isEdge) {
preventDefault(event, true)
}

newState.offset = rangeCalculation(
const offset = rangeCalculation(
touch.deltaX.current + startOffset.current,
-actionWidth.current.right || 0,
actionWidth.current.left || 0
)
setState(newState)
setState((prevState) => ({
...prevState,
dragging: true,
offset: Number(offset) || 0,
}))
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

修正 opened 引用的误用,避免阈值判断失效

opened 是 ref,应使用 opened.current。否则 !opened 恒为 false,边缘判定与滚动阻止逻辑异常。

应用以下修复:

-      const isEdge = !opened || touch.deltaX.current * startOffset.current < 0
+      const isEdge = !opened.current || touch.deltaX.current * startOffset.current < 0
📝 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
if (props.disabled) return
touch.move(event)
props.onTouchMove?.(event)
if (touch.isHorizontal()) {
lockClick.current = true
const newState = { ...state, dragging: true }
const isEdge = !opened || touch.deltaX.current * startOffset.current < 0
if (isEdge) {
preventDefault(event, true)
}
newState.offset = rangeCalculation(
const offset = rangeCalculation(
touch.deltaX.current + startOffset.current,
-actionWidth.current.right || 0,
actionWidth.current.left || 0
)
setState(newState)
setState((prevState) => ({
...prevState,
dragging: true,
offset: Number(offset) || 0,
}))
if (props.disabled) return
touch.move(event)
props.onTouchMove?.(event)
if (touch.isHorizontal()) {
lockClick.current = true
const isEdge = !opened.current || touch.deltaX.current * startOffset.current < 0
if (isEdge) {
preventDefault(event, true)
}
const offset = rangeCalculation(
touch.deltaX.current + startOffset.current,
-actionWidth.current.right || 0,
actionWidth.current.left || 0
)
setState((prevState) => ({
...prevState,
dragging: true,
offset: Number(offset) || 0,
}))
🤖 Prompt for AI Agents
In src/packages/swipe/swipe.taro.tsx around lines 116 to 134, the code uses the
ref variable opened directly (e.g. !opened) which is incorrect; replace usages
with opened.current so the edge detection reads something like !opened.current
|| touch.deltaX.current * startOffset.current < 0. Ensure you reference
opened.current (and handle it if possibly undefined) when computing isEdge and
any other places in this block where opened is used.

Comment on lines +184 to +189
{content &&
(td() ? (
<Text className={`${classPrefix}-text`}>{content}</Text>
) : (
<View className={`${classPrefix}-text`}>{content}</View>
))}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

验证 content 属性的类型安全性

条件渲染逻辑在动态平台下使用 Text 组件包裹 content。请确认 content 属性的类型定义仅允许字符串或原始类型,而不包含复杂的 React 元素。如果 content 可以是 ReactNode,在 td() 返回 true 时使用 Text 组件可能导致运行时错误。

运行以下脚本验证 content 的类型定义:


🏁 Script executed:

#!/bin/bash
# 描述: 检查 TaroToastProps 中 content 属性的类型定义

# 查找 TaroToastProps 类型定义
ast-grep --pattern $'interface TaroToastProps {
  $$$
  content: $_
  $$$
}'

# 如果是类型别名形式
ast-grep --pattern $'type TaroToastProps = {
  $$$
  content: $_
  $$$
}'

Length of output: 0



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for TaroToastProps definition using ripgrep
rg -n "TaroToastProps" --type=ts --type=tsx -A 10

# Also search directly for content property definition in toast file
rg -n "content\s*:" src/packages/toast/toast.taro.tsx -A 2 -B 2

Length of output: 167



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for TaroToastProps interface or type declaration
rg -n "interface TaroToastProps|type TaroToastProps" --type=ts -A 15

# Also search the file for content property with type annotation
rg -n "content\s*:\s*" src/packages/toast/toast.taro.tsx -B 5

# Check if there's a separate types file
fd -e ts -e js src/packages/toast | head -20

Length of output: 650



---

🏁 Script executed:

```shell
#!/bin/bash
# Find BaseToast type definition
rg -n "interface BaseToast|type BaseToast" --type=ts -A 30

# Also check what's exported from base toast types
rg -n "content" src/types/spec/toast -B 2 -A 2 --type=ts

Length of output: 1040


修复 content 在 Text 组件中的类型安全问题

已确认 content 属性的类型为 ReactNode(见 src/types/spec/toast/base.ts 第14行),但代码在 td() 返回 true 时将其包裹在 Taro Text 组件中。Text 组件仅支持文本/字符串内容,不能渲染复杂的 React 元素。当 content 为非字符串的 ReactNode 时,将导致运行时错误。

建议修复方案:

  • td() 为 true 时,也使用 View 组件(与 else 分支一致),以支持任意 ReactNode 内容
  • 或添加类型约束和运行时检查,确保 td() 为 true 时 content 仅为字符串类型
🤖 Prompt for AI Agents
In src/packages/toast/toast.taro.tsx around lines 184 to 189, the code wraps the
ReactNode content in a Taro Text component when td() is true, but Text only
supports plain string/text and will throw at runtime for non-string ReactNodes;
change the branch so that when td() returns true you render a View (same as the
else branch) to support arbitrary ReactNode content, or alternatively add a
runtime/type guard to only use Text when typeof content === 'string' and fall
back to View otherwise.

useLayoutEffect(() => {
if (root.current) {
getRectInMultiPlatform(root.current).then((rect) => {
useReady(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

大佬,这里撤回到useReady的原因是什么?
useReady只会在页面第一次挂载的时候触发,如果当前组件是懒加载渲染的就不会重复触发了
比如页面渲染2秒后再渲染当前组件,就不会触发useReady,理论上就算使用了nextTick也不行。
最好还是使用react的hooks,跟组件绑定,不跟页面绑定

https://docs.taro.zone/docs/ref#%E5%9C%A8%E6%87%92%E5%8A%A0%E8%BD%BD%E7%BB%84%E4%BB%B6%E4%B8%AD%E8%8E%B7%E5%8F%96

https://docs.taro.zone/docs/hooks#uselayouteffect

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

这里可以集中测试一下多端的反应~~ h5、小程序 还有鸿蒙端,我记得当时小程序就不好使了~ 可以看下

@codecov
Copy link

codecov bot commented Oct 20, 2025

Codecov Report

❌ Patch coverage is 62.50000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.13%. Comparing base (e9a80b8) to head (374b7ae).

Files with missing lines Patch % Lines
src/packages/popup/popup.tsx 60.00% 6 Missing ⚠️

❌ Your patch check has failed because the patch coverage (62.50%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@              Coverage Diff              @@
##           feat_v3.x    #3374      +/-   ##
=============================================
- Coverage      88.15%   88.13%   -0.03%     
=============================================
  Files            291      291              
  Lines          19212    19228      +16     
  Branches        2988     2992       +4     
=============================================
+ Hits           16937    16947      +10     
- Misses          2269     2275       +6     
  Partials           6        6              

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Collaborator

@xiaoyatong xiaoyatong left a comment

Choose a reason for hiding this comment

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

相关的组件,需要在 h5 和小程序端验证一下可用性~~~

Comment on lines +69 to 70
top,
description,
Copy link
Collaborator

Choose a reason for hiding this comment

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

这里可以看下ai提示~

Comment on lines +147 to +152
useEffect(() => {
if (topNodeRef.current && nodeRef.current) {
topNodeRef.current.style.bottom = `${nodeRef.current?.clientHeight}px`
}
}, [innerVisible])

Copy link
Collaborator

Choose a reason for hiding this comment

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

这个看上去很有用~~

useLayoutEffect(() => {
if (root.current) {
getRectInMultiPlatform(root.current).then((rect) => {
useReady(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

这里可以集中测试一下多端的反应~~ h5、小程序 还有鸿蒙端,我记得当时小程序就不好使了~ 可以看下

maxlength={maxLength}
placeholder={
placeholder !== undefined ? placeholder : locale.placeholder
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

这个是新增的~~

Copy link
Collaborator

Choose a reason for hiding this comment

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

不要删掉~~

@@ -1,8 +1,21 @@
import Taro, { createSelectorQuery } from '@tarojs/taro'

const ENV_TYPE = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

可以把这个提炼到一个 公共的 constant 中

import { useEffect, useRef } from 'react'
import isEqual from 'react-fast-compare'
import { Events, getCurrentInstance } from '@tarojs/taro'
import { eventCenter, getCurrentInstance } from '@tarojs/taro'
Copy link
Collaborator

Choose a reason for hiding this comment

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

需要在 h5 和小程序端验证一下

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

Labels

3.x Target branch 3.x action:review This PR needs more reviews (less than 2 approvals) size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants