feat: 合并近期跨原生改动点,增加了无障碍,部分组件增加了新功能。#3420
Conversation
Walkthrough替换 Taro 事件源与若干 Taro 工具调用;为 Popup 添加 top 槽与 closeAriaLabel(含测量定位与 ARIA);为 Input 增加 inputStyle;为 Radio/Switch/Checkbox 等加入 aria 属性;新增 locales 键;大量 SCSS 添加基于 Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Popup as Popup Component
participant DOM as DOM / 测量
participant TopNode as Top Slot Node
Note over User,Popup: 用户打开弹窗并提供 top 插槽
User->>Popup: open() / innerVisible = true
Popup->>DOM: nextTick -> 请求测量 popup 高度
DOM-->>Popup: popupHeight
Popup->>Popup: 计算 topBottom = popupHeight - 偏移
Popup->>TopNode: 设置 top 区域 style bottom = topBottom
Popup->>User: 渲染 popup 与 top(包含 ARIA close 标签)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/hooks/taro/use-custom-event.ts (1)
16-21:⚠️ Potential issue | 🟠 Major
off(path)未传入回调函数可能导致误删其他监听器当前 cleanup 函数调用
customEvents.off(path)时没有传入对应的回调函数cb。在 Taro 的eventCenter中,off(eventName)会移除该事件名下的所有监听器,而非仅移除当前组件注册的那个。如果多个组件使用相同的
selector(生成相同的path),当其中一个组件卸载时,会把其他组件的监听器也一并移除,导致功能异常。🐛 建议修复:传入具体回调以仅移除当前监听器
export function useCustomEvent(selector: string, cb: any) { const path = useCustomEventsPath(selector) useEffect(() => { customEvents.on(path, cb) return () => { - customEvents.off(path) + customEvents.off(path, cb) } }, [])src/locales/zh-TW.ts (1)
3-3:⚠️ Potential issue | 🟡 Minor变量名错误:
zhCN应为zhTW。此文件是繁体中文 (zh-TW) 的本地化文件,但变量名使用了
zhCN(简体中文的命名)。这可能是从 zh-CN.ts 复制时遗留的问题,会导致代码混淆。🐛 建议修复
-const zhCN: BaseLang = { +const zhTW: BaseLang = {同时需要修改导出语句(Line 146):
-export default zhCN +export default zhTWsrc/packages/steps/steps.taro.tsx (1)
53-65:⚠️ Potential issue | 🟠 Major建议继续透传
restProps,避免破坏自定义属性。
当前 Line 53 的根节点未展开restProps,可能导致用户传入的style/id/data-*等属性失效。若非刻意收紧,请恢复透传。🛠️ 建议修改
- <View className={classes}> + <View className={classes} {...restProps}>
🤖 Fix all issues with AI agents
In `@src/locales/zh-UG.ts`:
- Line 142: The locale entry mask: 'mask' is still in English; update the 'mask'
key in src/locales/zh-UG.ts to use the correct Uyghur translation (similar
script style to existing close: 'تاقاش'), replacing the English literal so the
'mask' string is properly localized.
In `@src/packages/checkbox/checkbox.taro.tsx`:
- Around line 207-215: The component is using a non-standard prop ariaChecked
which Taro doesn't recognize; update the custom checkbox rendering (where class
names, innerChecked, innerIndeterminate and handleClick are used) to provide the
standard ARIA attribute aria-checked instead of ariaChecked, or switch to Taro's
native Checkbox component; if keeping the custom View, pass aria-checked (e.g.,
via nativeProps or the component's props mapping) with value innerIndeterminate
? 'mixed' : innerChecked and ensure role="checkbox" and tabIndex logic remain
unchanged.
In `@src/packages/menuitem/menuitem.scss`:
- Line 64: 在 .nut-menu-placeholder-element 的定位中发现同时使用了 SCSS 变量
$menu-bar-line-height 和 CSS 自定义属性 --menu-bar-line-height,且在第64/71行改为
var(--menu-bar-line-height) 会在鸿蒙系统产生兼容问题;请统一为兼容方案:保留 SCSS 变量作为回退并优先使用 CSS
变量(或反之,按项目规范),例如将 top 的计算改为使用 CSS 变量并在其后提供 SCSS 变量回退(应用到第64行和第71行),并在样式顶部确认
$menu-bar-line-height 定义存在以避免断裂。
In `@src/packages/table/table.scss`:
- Around line 131-139: The .nut-table-body (aka .nut-table-main-body) selector
currently sets display: table-header-group; which is incorrect for tbody
semantics—update the &-body rule in src/packages/table/table.scss to use
display: table-row-group; (respecting the existing /* `#ifndef` dynamic*/
conditional blocks) so the table body renders as a row group rather than a
header group.
In `@src/packages/toast/toast.scss`:
- Around line 110-114: 条件编译中的 "line-height: normal" 被后面的非条件 "line-height: 22px"
覆盖:在包含标记 /* `#ifdef` harmony dynamic*/ 和 /* `#endif` */ 的块内保留 line-height:
normal,并将非条件的 line-height: 22px 移入一个对应的非动态分支(例如使用 /* `#else` */ ... /* `#endif`
*/)或删除重复,使得当标志启用时只应用 line-height: normal,未启用时才应用 line-height:
22px(参考代码片段中的标记和两个属性名)。
- Around line 98-103: The conditional compilation is wrong because both
"line-height: normal" and "line-height: 20px" are emitted, so the latter always
wins; inside the CSS block that contains the two line-height declarations
replace the current structure by keeping "/* `#ifdef` harmony dynamic*/
line-height: normal; /* `#endif` */" for the harmony case and move the fallback
"line-height: 20px;" into a matching "/* `#ifndef` harmony dynamic*/ ... /* `#endif`
*/" block (the same block that contains height: auto) so only one line-height is
output; locate the pair of "line-height" declarations in this toast.scss block
to apply the change.
🧹 Nitpick comments (6)
src/packages/cascader/cascader.scss (1)
14-17: 条件编译指令格式不一致
/*#ifndefdynamic*/在dynamic后缺少空格,而/*#endif*/在#endif后有空格。建议保持一致的格式以提高可读性并避免潜在的预处理器解析问题。♻️ 建议修复
- /* `#ifndef` dynamic*/ + /* `#ifndef` dynamic */ flex: initial; min-width: auto; /* `#endif` */src/packages/cellgroup/cellgroup.scss (1)
4-7: 确认 dynamic 构建下标题/描述的 display 行为在 dynamic 条件下移除了
display: inherit,如果渲染节点默认不是 block(或父级 display 变化),可能导致标题/描述回退为 inline,影响布局。建议在 dynamic 端显式设置display: block,或在目标平台上验证默认 display 是否满足需求。💡 可选修正(在 dynamic 构建显式设置为 block)
&-title { /* `#ifndef` dynamic*/ display: inherit; /* `#endif` */ + /* `#ifdef` dynamic */ + display: block; + /* `#endif` */ padding: $cell-group-title-padding; color: $cell-group-title-color; font-size: $cell-group-title-font-size; line-height: $cell-group-title-line-height; margin-top: 30px; margin-bottom: 10px; } &-description { /* `#ifndef` dynamic*/ display: inherit; /* `#endif` */ + /* `#ifdef` dynamic */ + display: block; + /* `#endif` */ padding: $cell-group-description-padding; color: $cell-group-description-color; font-size: $cell-group-description-font-size; line-height: $cell-group-description-line-height; margin-top: 10px; margin-bottom: 10px; }Also applies to: 16-19
src/utils/taro/get-system-info.ts (1)
12-36: 为三处 get*Info 增加 try/catch 兜底仅用
typeof判断无法覆盖"API 存在但运行时不支持/抛错"的场景。Taro 官方文档对getDeviceInfo、getWindowInfo、getAppBaseInfo这三个同步 API 均建议使用 try/catch 捕获运行时异常并回落getSystemInfoSync(),这是官方推荐的兼容写法。示例(同样应用到另外两个函数)
export const getDeviceInfo = (): IDeviceInfo => { - return typeof Taro.getDeviceInfo === 'function' - ? Taro.getDeviceInfo() - : Taro.getSystemInfoSync() + try { + return typeof Taro.getDeviceInfo === 'function' + ? Taro.getDeviceInfo() + : Taro.getSystemInfoSync() + } catch { + return Taro.getSystemInfoSync() + } }src/utils/taro/px-transform.ts (1)
1-8: 为 Harmony/dynamic 平台的 Taro.pxTransform 增加安全检查
Taro.pxTransform在 Harmony/Harmony Hybrid 平台官方支持,但对于 dynamic 平台,其可用性取决于自定义运行时的实现。若该平台未注入pxTransform,调用时会抛出运行时错误。建议添加存在性检查以确保兼容性,并在函数不可用时回退到字符串像素。建议修改
- if (harmony() || td()) return Taro.pxTransform(value, radix || 375) + if (harmony() || td()) { + if (typeof Taro.pxTransform === 'function') { + return Taro.pxTransform(value, radix || 375) + } + return `${value}px` + }src/utils/taro/get-rect-by-id.ts (1)
3-18: 根据 Taro 官方文档,Taro.getEnv()返回Taro.ENV_TYPE枚举常量(如 'WEAPP'、'WEB' 等),各平台的返回值大小写是一致的,无需额外的大小写处理。问题分析:
- 官方推荐方式是使用
Taro.ENV_TYPE.WEB而非本地定义的 ENV_TYPE 常量- 当前代码
Taro.getEnv() === ENV_TYPE.WEB实际上工作正常platform.ts中的.toLowerCase()是不必要的且与官方 API 行为不符建议改进:使用官方提供的
Taro.ENV_TYPE常量,而非本地定义的字符串常量。建议修改
import Taro, { createSelectorQuery } from '@tarojs/taro' -const ENV_TYPE = { - WEAPP: 'WEAPP', - SWAN: 'SWAN', - ALIPAY: 'ALIPAY', - TT: 'TT', - QQ: 'QQ', - JD: 'JD', - WEB: 'WEB', - RN: 'RN', - HARMONY: 'HARMONY', - QUICKAPP: 'QUICKAPP', -} export const getRectById = (id: string) => { return new Promise((resolve, reject) => { - if (Taro.getEnv() === ENV_TYPE.WEB) { + if (Taro.getEnv() === Taro.ENV_TYPE.WEB) {src/packages/badge/badge.scss (1)
3-10:box-sizing: content-box仅在非动态模式下应用当前实现将
box-sizing: content-box放在#ifndef dynamic块内,这意味着在动态模式下该属性不会被显式设置。虽然浏览器默认值通常是content-box,但原生平台的行为可能不同。如果这是有意为之(原生侧不支持或有不同的盒模型需求),请忽略此建议。否则建议将
box-sizing移到条件块外部以确保一致性。♻️ 可选:将 box-sizing 移到条件块外部
.nut-badge { position: relative; /* `#ifdef` dynamic*/ display: flex; /* `#endif` */ /* `#ifndef` dynamic*/ display: inline-flex; - box-sizing: content-box; /* `#endif` */ + box-sizing: content-box; vertical-align: middle; width: auto;
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/packages/inputnumber/inputnumber.scss`:
- Around line 2-7: The SCSS conditional comments using /* `#ifdef` */ and /*
`#ifndef` */ are not supported by the current sass.compileString() pipeline and
both display rules are compiled, so update the build to remove or replace these
pseudo-preprocessor blocks: either add a pre-processing step that strips the
irrelevant /* `#ifdef` dynamic */.../* `#endif` */ or /* `#ifndef` dynamic */.../*
`#endif` */ blocks from src/packages/inputnumber/inputnumber.scss (and the other
~50 affected component .scss files) based on the build target, or stop using
those comments and implement platform-specific styles via a Taro/platform switch
(e.g., use process.env.TARO_ENV to choose different .scss files at build time)
or switch to CSS variables/CSS-in-JS so only the intended display rule (display:
flex vs display: inline-flex) is included in the final CSS.
| /* #ifdef dynamic*/ | ||
| display: flex; | ||
| /* #endif */ | ||
| /* #ifndef dynamic*/ | ||
| display: inline-flex; | ||
| /* #endif */ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find Taro configuration files and conditional compilation setup
fd -e 'config\.(ts|js|json)' | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Search for build and taro configuration files
rg -l 'taro|ifdef|ifndef' --type ts --type js -g '!node_modules' | grep -E '(config|build)' | head -20Repository: jdf2e/nutui-react
Length of output: 719
🏁 Script executed:
# Check for SCSS conditional compilation patterns in the codebase
rg '#ifdef|#ifndef' --type scss -n | head -30Repository: jdf2e/nutui-react
Length of output: 89
🏁 Script executed:
# Look for how the project is structured and what preprocessors are configured
cat taro.config.ts 2>/dev/null || cat taro.config.js 2>/dev/null || find . -maxdepth 3 -name 'taro.config.*' | head -5Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check package.json for build scripts and dependencies
cat package.json | grep -A 20 -E '"(scripts|devDependencies)"'Repository: jdf2e/nutui-react
Length of output: 2349
🏁 Script executed:
# Search for SCSS files with conditional compilation directives
fd -e scss -x grep -l '#ifdef\|#ifndef' {}Repository: jdf2e/nutui-react
Length of output: 1883
🏁 Script executed:
# Check the actual inputnumber.scss file and surrounding context
cat -n src/packages/inputnumber/inputnumber.scss | head -20Repository: jdf2e/nutui-react
Length of output: 688
🏁 Script executed:
# Find and read taro configuration
find . -maxdepth 3 -name 'taro.config.*' -type f -exec cat {} \;Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Search for how SCSS preprocessing is configured in the build pipeline
rg -A 5 -B 5 'scss|sass|style' vite.config.ts vite.config.js 2>/dev/null | head -40Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for Taro's platform/target configuration handling
rg 'platform|target|dynamic|ifdef' packages/nutui-taro-demo/config/ -A 3 -B 3 | head -50Repository: jdf2e/nutui-react
Length of output: 2557
🏁 Script executed:
# Look for preprocessor scripts that handle `#ifdef/`#ifndef
fd -e js -e mjs -x grep -l 'ifdef\|ifndef\|preprocess' {} \; | grep -E '(script|build)' | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check the build scripts for preprocessing logic
cat scripts/build.mjs | head -50Repository: jdf2e/nutui-react
Length of output: 1716
🏁 Script executed:
# Search for how "dynamic" target is defined or used
rg -i 'dynamic' scripts/ -A 3 -B 3 | head -60Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for preprocessor configuration in rollup or build configs
rg -i 'preprocess|ifdef|ifndef' build/ rollup.config.js vite.config.ts 2>/dev/null | head -40Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check if there's a replace-css-var script that might handle preprocessing
cat scripts/replace-css-var.js | head -80Repository: jdf2e/nutui-react
Length of output: 2377
🏁 Script executed:
# Check if there's any preprocessing of SCSS files before compilation
rg -B 5 -A 5 'readFile.*\.scss\|compileString' scripts/replace-css-var.js | head -60Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for any dynamic target or ifdef handling in the entire build pipeline
rg -r 'dynamic|ifdef|ifndef' build/ packages/ --include='*.js' --include='*.ts' 2>/dev/null | grep -v node_modules | head -40Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check if there's a Taro-specific preprocessor for these directives
rg -i 'preprocessor|transform.*scss|ifdef' . -g '!node_modules' --type ts --type js | head -40Repository: jdf2e/nutui-react
Length of output: 190
🏁 Script executed:
# Verify: read the full replace-css-var script to see the complete flow
cat scripts/replace-css-var.jsRepository: jdf2e/nutui-react
Length of output: 2396
🏁 Script executed:
# Check if Taro itself has preprocessing for these directives
rg -r 'ifdef\|ifndef' node_modules/@tarojs --type js 2>/dev/null | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Search for how Taro handles dynamic target builds
rg -r 'dynamic' packages/nutui-taro-demo -A 3 -B 3 | head -60Repository: jdf2e/nutui-react
Length of output: 3869
🏁 Script executed:
# Look for any Taro plugin or loader that might preprocess SCSS
rg -r 'loader|plugin.*scss|transform.*style' packages/nutui-taro-demo/config -A 2 -B 2Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check Taro documentation or comments about these directives in the repo
rg -r '#ifdef|#ifndef' src/packages --context 10 | grep -E '(taro|dynamic|harmony|platform)' -i | head -40Repository: jdf2e/nutui-react
Length of output: 2865
🏁 Script executed:
# Verify: Check if this pattern exists in Taro framework's own components or docs
fd -e md -e txt | xargs grep -l 'ifdef\|ifndef' 2>/dev/null | head -10Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check if the "dynamic" directory exists and what it contains
ls -la dynamic/ 2>/dev/null || echo "dynamic directory check"Repository: jdf2e/nutui-react
Length of output: 84
🏁 Script executed:
# Check the dynamic package structure
fd -d 2 -t d . dynamic/ 2>/dev/null | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for SCSS or style handling in the dynamic workspace
fd -e 'scss\|sass\|css' dynamic/ --type f 2>/dev/null | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check dynamic package.json for build configuration
cat dynamic/package.json 2>/dev/null | grep -A 10 -B 2 -E 'script|build|scss'Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Search for any Taro preprocessor plugin or SCSS loader in config
cat dynamic/config/index.js 2>/dev/null || find dynamic -name '*config*' -type f 2>/dev/null | head -10Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check if Taro has built-in support for these directives in its loaders
rg -r 'scss.*loader\|loader.*scss' . -g '!node_modules' -g '!dist' --type ts --type js | head -20Repository: jdf2e/nutui-react
Length of output: 16056
🏁 Script executed:
# Search for any actual Taro configuration that might process these directives
find . -path '*/node_modules' -prune -o -name 'taro.config.*' -type f -print 2>/dev/null | xargs cat 2>/dev/nullRepository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Check if there are any compiled CSS files to verify what's actually output
fd -e '.harmony.css' -e '.taro.css' | head -10Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for test files or examples that might show the expected behavior
fd -e '.test.ts' -e '.spec.ts' -e '.test.js' inputnumber | xargs cat 2>/dev/null | grep -A 5 -B 5 'display\|flex' | head -40Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Final verification: check what the actual build output shows for inputnumber
fd 'inputnumber.*\.css' dist/ release/ 2>/dev/null | head -5 | xargs cat 2>/dev/null | head -20Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Look for documentation or comments in code about how these directives should work
rg -B 3 -A 3 '#ifdef dynamic' src/packages/ | head -50Repository: jdf2e/nutui-react
Length of output: 2378
🏁 Script executed:
# Check if there's any information in Taro's documentation or source about these directives
find . -name 'README*' -o -name '*.md' | xargs grep -l 'ifdef\|ifndef\|dynamic.*compile' 2>/dev/null | head -10Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Try to understand the actual purpose by checking git history or comments
git log --oneline -S '#ifdef dynamic' -- src/packages/inputnumber/ 2>/dev/null | head -10Repository: jdf2e/nutui-react
Length of output: 82
🏁 Script executed:
# Check the actual compiled output from a built component to verify behavior
find . -path '*/dist/*' -o -path '*/release/*' -name '*.css' -o -name '*.harmony.css' 2>/dev/null | xargs grep -l 'display.*flex' 2>/dev/null | head -5Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Final check: look for any actual Taro preprocessor or loader that handles these
rg 'ifdef|ifndef' . -g '!node_modules' --type ts --type js -B 5 -A 5 -i 'preprocess\|loader\|transform' | head -80Repository: jdf2e/nutui-react
Length of output: 130
🏁 Script executed:
# Get full commit information for the style compatibility fix
git show b1b0b2c7 --stat 2>/dev/null | head -100Repository: jdf2e/nutui-react
Length of output: 6040
🏁 Script executed:
# Check if Taro has any built-in preprocessor for these specific directives
rg '@tarojs' package.json -A 2 -B 2 | grep -i 'plugin\|loader\|transform' | head -20Repository: jdf2e/nutui-react
Length of output: 199
🏁 Script executed:
# Look at how Taro actually processes SCSS in its plugins
find node_modules/@tarojs -name '*scss*' -o -name '*loader*' 2>/dev/null | head -10Repository: jdf2e/nutui-react
Length of output: 43
🏁 Script executed:
# Search for any actual preprocessing before SCSS compilation in Taro build
rg -r 'preprocess' . -g '!node_modules' --type ts --type js -B 3 -A 3 | head -60Repository: jdf2e/nutui-react
Length of output: 12480
🏁 Script executed:
# Check the actual commit that introduced these conditionals
git show b1b0b2c7 -- src/packages/inputnumber/inputnumber.scss 2>/dev/null | head -80Repository: jdf2e/nutui-react
Length of output: 2085
SCSS 条件编译指令在当前构建链路中不生效,导致样式逻辑失效。
#ifdef/#ifndef 不是标准 Sass/SCSS 预处理器指令。当前构建通过 sass.compileString() 直接编译 SCSS,这些指令会被作为 CSS 注释处理,最终两条 display 规则都会编译进 CSS,后者 inline-flex 会覆盖 flex,使得 dynamic 构建与预期的条件逻辑完全失效。此问题影响 50+ 个组件。
建议:
- 在 SCSS 编译前添加预处理步骤,根据构建目标删除对应的条件注释块,或
- 使用 Taro 提供的平台预处理机制(如
process.env.TARO_ENV)通过 JavaScript/TypeScript 注入不同的样式文件,或 - 采用 CSS 变量或 CSS-in-JS 方案处理动态样式差异
🤖 Prompt for AI Agents
In `@src/packages/inputnumber/inputnumber.scss` around lines 2 - 7, The SCSS
conditional comments using /* `#ifdef` */ and /* `#ifndef` */ are not supported by
the current sass.compileString() pipeline and both display rules are compiled,
so update the build to remove or replace these pseudo-preprocessor blocks:
either add a pre-processing step that strips the irrelevant /* `#ifdef` dynamic
*/.../* `#endif` */ or /* `#ifndef` dynamic */.../* `#endif` */ blocks from
src/packages/inputnumber/inputnumber.scss (and the other ~50 affected component
.scss files) based on the build target, or stop using those comments and
implement platform-specific styles via a Taro/platform switch (e.g., use
process.env.TARO_ENV to choose different .scss files at build time) or switch to
CSS variables/CSS-in-JS so only the intended display rule (display: flex vs
display: inline-flex) is included in the final CSS.
There was a problem hiding this comment.
@xiaoyatong 明白了,感谢您的说明!已记录下这些条件编译指令是用于原生平台兼容性处理的设计决策。
✏️ Learnings added
Learnt from: xiaoyatong
Repo: jdf2e/nutui-react PR: 3420
File: src/packages/inputnumber/inputnumber.scss:2-7
Timestamp: 2026-02-03T03:22:51.350Z
Learning: 在 `nutui-react` 项目中,SCSS 文件中的 `/* `#ifdef` dynamic */` 和 `/* `#ifndef` dynamic */` 条件编译指令是有意使用的,用于原生平台的兼容性处理。这些指令不应被标记为需要修复的问题。
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2540
File: src/packages/trendarrow/trendarrow.taro.tsx:29-30
Timestamp: 2024-11-06T02:16:07.069Z
Learning: 在`TrendArrow`组件(`src/packages/trendarrow/trendarrow.taro.tsx`)中,CSS变量在鸿蒙系统(Harmony OS)中可能未被完全支持,导致兼容性问题。因此,使用硬编码的十六进制颜色值可以确保在鸿蒙系统上的正确显示。
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/packages/input/input.taro.tsx`:
- Around line 18-29: Remove the local ENV_TYPE constant and replace all usages
with the canonical Taro.ENV_TYPE export: update comparisons that use the literal
'WEB' and any ENV_TYPE.WEB references to use Taro.ENV_TYPE.WEB, and remove the
local ENV_TYPE declaration; ensure Taro is imported (use the existing Taro
import or add one) so all checks (e.g., where string 'WEB' or ENV_TYPE.WEB is
used) reference Taro.ENV_TYPE consistently across the file (functions/components
referencing ENV_TYPE or comparing to 'WEB' should be changed to
Taro.ENV_TYPE.WEB).
In `@src/styles/theme-default.scss`:
- Around line 262-263: font-size-l is inconsistent between themes
(theme-default.scss defines --nutui-font-size-l as var(--nutui-font-size-15)
while theme-dark.scss uses 16px); update the theme files so both define
--nutui-font-size-l to the same token/value (e.g., change --nutui-font-size-l in
theme-default.scss to var(--nutui-font-size-16) or set both to
var(--nutui-font-size-15) depending on design decision) and ensure the new
--nutui-font-size-icon variable remains separate; verify the change covers
usages of --nutui-font-size-l in components like shortpassword, toast, price,
empty, dialog, input, tabs, steps to preserve consistent rendering.
| const ENV_TYPE = { | ||
| WEAPP: 'WEAPP', | ||
| SWAN: 'SWAN', | ||
| ALIPAY: 'ALIPAY', | ||
| TT: 'TT', | ||
| QQ: 'QQ', | ||
| JD: 'JD', | ||
| WEB: 'WEB', | ||
| RN: 'RN', | ||
| HARMONY: 'HARMONY', | ||
| QUICKAPP: 'QUICKAPP', | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/packages/input/input.taro.tsx | head -250Repository: jdf2e/nutui-react
Length of output: 7642
🏁 Script executed:
rg "ENV_TYPE|getEnv|@tarojs/taro" src/packages/input/input.taro.tsx -A 2 -B 2Repository: jdf2e/nutui-react
Length of output: 1194
🏁 Script executed:
rg "export.*ENV_TYPE|Taro\.ENV_TYPE" --type ts --type tsxRepository: jdf2e/nutui-react
Length of output: 88
🏁 Script executed:
fd "taro" --type d | head -20Repository: jdf2e/nutui-react
Length of output: 684
🏁 Script executed:
rg "ENV_TYPE|Taro\.getEnv|getEnv\(\)" src/packages --type ts --type tsx -lRepository: jdf2e/nutui-react
Length of output: 88
🏁 Script executed:
rg "getEnv.*WEB|getEnv.*WEAPP|Taro\.getEnv" src/packages -B 2 -A 2 | head -100Repository: jdf2e/nutui-react
Length of output: 6025
🏁 Script executed:
# Search for type definitions related to Taro environment
rg "type.*ENV|interface.*ENV" src/types --type ts --type tsxRepository: jdf2e/nutui-react
Length of output: 88
🌐 Web query:
@tarojs/taro ENV_TYPE constant export documentation
💡 Result:
In @tarojs/taro, the environment “constant” is exposed as Taro.ENV_TYPE (a static enum-like object on the default Taro export), and you typically use it together with Taro.getEnv(). [1]
import Taro from '@tarojs/taro'
const env = Taro.getEnv()
if (env === Taro.ENV_TYPE.WEAPP) {
// WeChat Mini Program
}
if (env === Taro.ENV_TYPE.WEB) {
// H5
}Taro.ENV_TYPE includes: WEAPP, SWAN, ALIPAY, TT, WEB, RN, QUICKAPP, QQ, JD. [1]
If you want compile-time platform branching (dead-code elimination), use process.env.TARO_ENV instead (values like weapp / alipay / h5 / rn / etc.). [2]
Docs: “Operating environment / 环境判断” (Taro.ENV_TYPE, Taro.getEnv) [1] and “Cross-platform development / 跨平台开发” (process.env.TARO_ENV) [2].
Sources:
[1] (docs.taro.zone)
[2] (docs.taro.zone)
Citations:
- 1: https://docs.taro.zone/docs/apis/about/env/?utm_source=openai
- 2: https://docs.taro.zone/docs/envs/?utm_source=openai
移除冗余的本地 ENV_TYPE 常量,直接使用 Taro 导出的 Taro.ENV_TYPE。
@tarojs/taro 已导出 Taro.ENV_TYPE 常量,无需本地重复定义。当前代码在第 176 行使用本地的 ENV_TYPE.WEB,但在第 96、155、171 行使用字符串 'WEB' 直接比较。建议统一改为 Taro.ENV_TYPE.WEB 以保持与 Taro 官方 API 的一致性,避免维护时潜在的同步问题。
🤖 Prompt for AI Agents
In `@src/packages/input/input.taro.tsx` around lines 18 - 29, Remove the local
ENV_TYPE constant and replace all usages with the canonical Taro.ENV_TYPE
export: update comparisons that use the literal 'WEB' and any ENV_TYPE.WEB
references to use Taro.ENV_TYPE.WEB, and remove the local ENV_TYPE declaration;
ensure Taro is imported (use the existing Taro import or add one) so all checks
(e.g., where string 'WEB' or ENV_TYPE.WEB is used) reference Taro.ENV_TYPE
consistently across the file (functions/components referencing ENV_TYPE or
comparing to 'WEB' should be changed to Taro.ENV_TYPE.WEB).
There was a problem hiding this comment.
@xiaoyatong 感谢您的说明!我已了解本地定义 ENV_TYPE 常量是为了原生平台的兼容性处理。
✏️ Learnings added
Learnt from: xiaoyatong
Repo: jdf2e/nutui-react PR: 3420
File: src/packages/input/input.taro.tsx:18-29
Timestamp: 2026-02-03T03:29:22.962Z
Learning: 在 `nutui-react` 项目的 Taro 组件中(如 `src/packages/input/input.taro.tsx`),本地定义的 `ENV_TYPE` 常量(而非直接使用 `Taro.ENV_TYPE`)是有意为之,用于原生平台的兼容性处理。这种模式不应被标记为需要重构的问题。
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: xiaoyatong
Repo: jdf2e/nutui-react PR: 3420
File: src/packages/inputnumber/inputnumber.scss:2-7
Timestamp: 2026-02-03T03:22:51.350Z
Learning: 在 `nutui-react` 项目中,SCSS 文件中的 `/* `#ifdef` dynamic */` 和 `/* `#ifndef` dynamic */` 条件编译指令是有意使用的,用于原生平台的兼容性处理。这些指令不应被标记为需要修复的问题。
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2540
File: src/packages/trendarrow/trendarrow.taro.tsx:29-30
Timestamp: 2024-11-06T02:16:07.069Z
Learning: 在`TrendArrow`组件(`src/packages/trendarrow/trendarrow.taro.tsx`)中,CSS变量在鸿蒙系统(Harmony OS)中可能未被完全支持,导致兼容性问题。因此,使用硬编码的十六进制颜色值可以确保在鸿蒙系统上的正确显示。
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/packages/radio/radio.taro.tsx`:
- Line 40: Update ARIA attribute names in src/packages/radio/radio.taro.tsx:
replace any uses of ariaHidden on the Icon component(s) with the standard
kebab-case attribute aria-hidden, change ariaRole on the View rendering the
radio to use role="radio" instead of ariaRole, and replace undocumented
ariaChecked/ariaDisabled with standard aria-checked and aria-disabled (or remove
them if the target Taro/miniprogram platform doesn’t support them); also remove
the related `@ts-ignore` comments. Look for the Icon usages around the ariaHidden
occurrences and the View that renders the radio (references: Icon, View, and the
radio render function/component) and apply these renames consistently.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/packages/popup/doc.taro.md`:
- Around line 110-114: In the docs table for the popup props, replace the
Traditional Chinese text "頂部佔位" with Simplified Chinese "顶部占位" for the `top`
prop description so the file `src/packages/popup/doc.taro.md` uses consistent
Simplified Chinese; update the table cell where `top` is documented (the row
with the `top` column) to the corrected phrase.
In `@src/packages/popup/doc.zh-TW.md`:
- Around line 71-76: The demo source reference under the "### 頂部佔位" section
currently points to CodeBlock src='h5/demo8.tsx' but the new top placeholder
demo file is named h5/demo9.tsx; update the CodeBlock src to the correct file
name (replace 'h5/demo8.tsx' with 'h5/demo9.tsx') so the displayed example
matches the added demo component and avoid misaligned examples.
In `@src/packages/tabs/tabs.taro.tsx`:
- Around line 196-206: The td() check is invalid because Taro.getEnv() never
returns 'dynamic', so replace the td() conditional around the
transform/transition block with a proper Android detection: in Taro builds use
Taro.getSystemInfoSync().platform (compare lowercased to 'android'), and in RN
builds check Platform.OS === 'android'; update the conditional that surrounds
the transform/transition return (the block using direction, index, duration,
rtl) to use this new Android check so the 50% translation hack runs on actual
Android devices.
🧹 Nitpick comments (8)
src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md (1)
99-102: 建议避免连续三条同词开头的句式可读性上略显重复,建议改写其中一到两条。
📝 参考改写
- - Added the resizable property for scrolling up and down when the bottom popup is active. - - Added the minHeight property for setting the minimum height, which can be used with resizable. - - Added a new attribute top to display user-defined content above the title. + - Added the resizable property for scrolling up and down when the bottom popup is active. + - The minHeight property sets the minimum height and can be used with resizable. + - A new attribute top displays user-defined content above the title.src/packages/switch/demos/h5/demo9.tsx (1)
1-8: ARIA 文案建议随语言切换
当前 ariaLabel 固定为中文,英文站点的读屏体验可能不一致。可考虑用翻译钩子按语言输出。🌍 可选改法示例
-import React from 'react' +import React from 'react' +import { useTranslate } from '@/sites/assets/locale' import { Cell, Switch } from '@nutui/nutui-react' const Demo9 = () => { + const [translated] = useTranslate({ + 'zh-CN': { ariaLabel: '开关按钮' }, + 'zh-TW': { ariaLabel: '開關按鈕' }, + 'en-US': { ariaLabel: 'Switch button' }, + }) return ( <Cell> - <Switch defaultChecked ariaLabel="开关按钮" /> + <Switch defaultChecked ariaLabel={translated.ariaLabel} /> </Cell> ) }src/packages/popup/demos/h5/demo9.tsx (1)
4-52: 建议统一为 Demo9 命名以避免混淆
文件名为 demo9.tsx,但组件名/默认导出为 Demo8,后续检索和维护容易误解,建议改为 Demo9。建议修改
-const Demo8 = () => { +const Demo9 = () => { const [showTop, setShowTop] = useState(false) @@ -export default Demo8 +export default Demo9src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md (1)
99-102: 可微调措辞以避免重复 “Added” 开头
建议改写其中一条以提升可读性。示例改写
-- Added a new attribute top to display user-defined content above the title. +- Introduced a new attribute top to display user-defined content above the title.src/packages/switch/switch.tsx (1)
86-96: 缺少键盘事件处理支持添加了
role="switch"和tabIndex属性使元素可聚焦,但缺少onKeyDown事件处理。键盘用户期望使用 Enter 或 Space 键来切换开关状态。♿ 建议添加键盘事件支持
+ const onKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + onClick() + } + } + return ( <div className={classes()} onClick={onClick} + onKeyDown={onKeyDown} style={style} {...rest} role="switch" tabIndex={disabled ? -1 : 0} aria-checked={value} aria-disabled={disabled} aria-label={ariaLabel} >src/packages/switch/switch.taro.tsx (1)
89-91:ariaChecked应传递字符串类型根据 ARIA 规范,
aria-checked属性值应为"true"或"false"字符串。当前传递的是布尔值value,这可能导致部分平台兼容性问题,也是需要@ts-ignore的原因之一。♻️ 建议修复
ariaRole="switch" - // `@ts-ignore` - ariaChecked={value} + ariaChecked={value ? 'true' : 'false'} ariaDisabled={disabled}src/packages/popup/popup.taro.tsx (1)
165-173: 双重nextTick嵌套值得关注嵌套两层
nextTick的写法不太常见,可能是为了确保 DOM 完全渲染后再获取高度。建议添加注释说明原因,或考虑是否有更可靠的方式(如使用ResizeObserver或监听渲染完成事件)。此外,
getPopupHeight是异步函数,但在nextTick回调中调用时未处理其返回的 Promise。💡 建议添加注释或简化
useEffect(() => { if (innerVisible && topNodeRef.current && nodeRef.current) { + // 双重 nextTick 确保 Taro 渲染完成后再计算高度 nextTick(() => { nextTick(() => { - getPopupHeight() + void getPopupHeight() }) }) } }, [innerVisible])src/packages/popup/popup.tsx (1)
150-154:useEffect缺少top属性的检查当
top属性未提供时,topNodeRef.current应该为null,但为了代码健壮性,建议在条件中显式检查top属性。♻️ 建议优化
useEffect(() => { - if (topNodeRef.current && nodeRef.current) { + if (top && topNodeRef.current && nodeRef.current) { topNodeRef.current.style.bottom = `${nodeRef.current?.clientHeight}px` } }, [innerVisible])
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/packages/dialog/__test__/dialog.spec.tsx (1)
142-144:⚠️ Potential issue | 🟡 Minor缺少
await关键字导致断言可能不执行
waitFor返回 Promise,需要await才能确保断言被执行并等待条件满足。🐛 建议修复
- waitFor(() => { + await waitFor(() => { expect(footerOkEle).not.toHaveClass('nut-button-loading') })
🤖 Fix all issues with AI agents
In `@src/packages/dialog/dialog.taro.tsx`:
- Around line 251-261: The close button View (using closeClasses,
closeIcon/systomIcon and handleClose) is focusable via tabIndex={0} but lacks
keyboard handling; add an onKeyDown handler on that View which listens for Enter
and Space keys and calls handleClose (prevent default for Space), ensuring the
handler mirrors the onClick behavior and preserves ariaRole/ariaLabel semantics
so keyboard users can activate the button.
In `@src/packages/dialog/dialog.tsx`:
- Around line 240-249: The close button div (using closeClasses,
closeIcon/systomIcon and handleClose) has role="button" and tabIndex but lacks
keyboard handling; add an onKeyDown handler on this element that listens for
Enter (Enter/Return) and Space keys and invokes handleClose (optionally calling
event.preventDefault() for Space) so keyboard users can activate the close
action; implement the handler as a small function near the component (e.g.,
onCloseKeyDown or inline) and attach it to the div alongside the existing
onClick.
In `@src/styles/theme-daojia.scss`:
- Around line 39-40: 当前样式文件里保留了两处“danger color 发现不一致TODO”注释(当前 diff
的注释以及文件中另一处相同 TODO),请在合并前落地解决:要么在相应的变量或主题声明处(将涉及的 danger 变量/配置统一,如 $danger /
--color-danger / 对应暗/亮主题变量名)直接填入最终一致的色值并移除 TODO,要么创建一个跟踪 issue 并在两个 TODO 注释中添加该
issue 编号和责任人以避免遗忘;更新后确保注释被移除或替换为带有 issue 链接的说明。
In `@src/styles/theme-dark-daojia.scss`:
- Around line 38-40: 在 src/styles/theme-dark-daojia.scss 中存在两处 TODO 注释(例如 "//
danger color 发现不一致 TODO" 及另一处指向 danger 的注释),请不要保留模糊的 TODO:要么直接在该 SCSS 中将 danger
颜色替换为确定的、语义化的变量值(例如统一成 $color-danger 或 $danger-xxx),确保两个注释处使用同一变量/色值;要么在合并前创建一个
issue 描述当前不一致并在这两个注释中加入该 issue 链接/编号并写明需要决策的候选值,确保注释里包含 issue
编号以便追踪(同时更新注释文本以反映已创建的 issue)。
- Around line 221-222: The CSS custom property name is misspelled: replace every
occurrence of --nutui-color-mask-fault-toleran with the correct
--nutui-color-mask-fault-tolerant across all theme and variables SCSS files and
update any references/usages (variables.scss, variables-daojia.scss,
theme-*.scss) so definitions and lookups use the corrected symbol consistently.
In `@src/types/spec/dialog/base.ts`:
- Around line 37-38: BaseDialog 的 confirmBadge 和 cancelBadge
当前为必填字段,会破坏向后兼容性;将这两个字段调整为可选(将 confirmBadge 和 cancelBadge
改为可选属性)以避免编译失败并与文档默认值保持一致,定位符为 BaseDialog、confirmBadge、cancelBadge(在
src/types/spec/dialog/base.ts 中修改相应属性签名即可)。
🧹 Nitpick comments (5)
src/packages/dialog/dialog.taro.tsx (2)
142-169: 冗余的条件检查在外层已经检查了
cancelBadge为 truthy 的情况下,内层再次检查cancelBadge ? ... : null是冗余的,因为此时cancelBadge必定为真。♻️ 建议简化
{cancelBadge ? ( <View className={`${classPrefix}-footer-cancel-container`}> <Button type="default" size="large" className={`${classPrefix}-footer-cancel ${btnClass}`} onClick={(e) => handleCancel(e)} > {cancelText || locale.cancel} </Button> - {cancelBadge ? ( - <View className={`${classPrefix}-footer-cancel-badge`}> - {cancelBadge} - </View> - ) : null} + <View className={`${classPrefix}-footer-cancel-badge`}> + {cancelBadge} + </View> </View> ) : (
177-215: 同样存在冗余的条件检查
confirmBadge的渲染逻辑与cancelBadge有相同的问题,外层已检查confirmBadge为真,内层的三元判断是多余的。♻️ 建议简化
{confirmBadge ? ( <View className={`${classPrefix}-footer-ok-container`}> <Button type="primary" size="large" className={classNames( `${classPrefix}-footer-ok ${btnClass}`, { disabled: disableConfirmButton, } )} disabled={disableConfirmButton} onClick={(e) => handleOk(e)} loading={loading} > {confirmText || locale.confirm} </Button> - {confirmBadge ? ( - <View className={`${classPrefix}-footer-ok-badge`}> - {confirmBadge} - </View> - ) : null} + <View className={`${classPrefix}-footer-ok-badge`}> + {confirmBadge} + </View> </View> ) : (src/packages/dialog/dialog.tsx (2)
131-158: 冗余的条件检查与 Taro 版本相同,在外层已经检查了
cancelBadge的情况下,内层第 142-146 行的cancelBadge ? ... : null是冗余的。♻️ 建议简化
{cancelBadge ? ( <div className={`${classPrefix}-footer-cancel-container`}> <Button type="default" size="large" className={`${classPrefix}-footer-cancel ${btnClass}`} onClick={(e) => handleCancel(e)} > {cancelText || locale.cancel} </Button> - {cancelBadge ? ( - <div className={`${classPrefix}-footer-cancel-badge`}> - {cancelBadge} - </div> - ) : null} + <div className={`${classPrefix}-footer-cancel-badge`}> + {cancelBadge} + </div> </div> ) : (
166-204: 同样存在冗余的条件检查第 184-188 行的
confirmBadge ?检查在外层条件已满足时是多余的。♻️ 建议简化
{confirmBadge ? ( <div className={`${classPrefix}-footer-ok-container`}> <Button type="primary" size="large" className={classNames( `${classPrefix}-footer-ok ${btnClass}`, { disabled: disableConfirmButton, } )} disabled={disableConfirmButton} onClick={(e) => handleOk(e)} loading={loading} > {confirmText || locale.confirm} </Button> - {confirmBadge ? ( - <div className={`${classPrefix}-footer-ok-badge`}> - {confirmBadge} - </div> - ) : null} + <div className={`${classPrefix}-footer-ok-badge`}> + {confirmBadge} + </div> </div> ) : (src/styles/theme-dark-daojia.scss (1)
251-277: 补齐font-size-icon与font-weight-medium以保持主题 token 对齐暗色主题(
theme-dark-daojia.scss和theme-dark.scss)缺失--nutui-font-size-icon与--nutui-font-weight-medium,而明亮主题中已存在。虽然variables.scss提供了默认回退值(16px 和 500),但为确保主题 token 完整性和一致性,建议补齐。✅ 建议补齐的最小改动
--nutui-font-size-l: var(--nutui-font-size-16); + --nutui-font-size-icon: var(--nutui-font-size-16); // 汉字:页面标题、页面级最重要内容 数字:模块级主价格,如购物车、结算、底导 --nutui-font-size-xl: var(--nutui-font-size-18); @@ // 常规内容 --nutui-font-weight: 400; + // 500 + --nutui-font-weight-medium: 500; // 强化内容 --nutui-font-weight-bold: 600;
| <View | ||
| className={closeClasses} | ||
| onClick={handleClose} | ||
| ariaRole="button" | ||
| ariaLabel={locale.close} | ||
| // @ts-ignore | ||
| tabIndex={0} | ||
| > | ||
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | ||
| </View> | ||
| ) |
There was a problem hiding this comment.
关闭按钮缺少键盘事件处理
添加了 tabIndex={0} 使元素可聚焦,但没有添加 onKeyDown 或 onKeyPress 处理器来响应 Enter/Space 键,这会影响键盘用户的可访问性体验。
♿ 建议添加键盘事件支持
+ const handleKeyDown = (e: any) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault()
+ handleClose()
+ }
+ }
+
return (
<View
className={closeClasses}
onClick={handleClose}
ariaRole="button"
ariaLabel={locale.close}
// `@ts-ignore`
tabIndex={0}
+ onKeyDown={handleKeyDown}
>📝 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.
| <View | |
| className={closeClasses} | |
| onClick={handleClose} | |
| ariaRole="button" | |
| ariaLabel={locale.close} | |
| // @ts-ignore | |
| tabIndex={0} | |
| > | |
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | |
| </View> | |
| ) | |
| const handleKeyDown = (e: any) => { | |
| if (e.key === 'Enter' || e.key === ' ') { | |
| e.preventDefault() | |
| handleClose() | |
| } | |
| } | |
| return ( | |
| <View | |
| className={closeClasses} | |
| onClick={handleClose} | |
| ariaRole="button" | |
| ariaLabel={locale.close} | |
| // `@ts-ignore` | |
| tabIndex={0} | |
| onKeyDown={handleKeyDown} | |
| > | |
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | |
| </View> | |
| ) |
🤖 Prompt for AI Agents
In `@src/packages/dialog/dialog.taro.tsx` around lines 251 - 261, The close button
View (using closeClasses, closeIcon/systomIcon and handleClose) is focusable via
tabIndex={0} but lacks keyboard handling; add an onKeyDown handler on that View
which listens for Enter and Space keys and calls handleClose (prevent default
for Space), ensuring the handler mirrors the onClick behavior and preserves
ariaRole/ariaLabel semantics so keyboard users can activate the button.
| <div | ||
| className={closeClasses} | ||
| onClick={handleClose} | ||
| role="button" | ||
| aria-label={locale.close} | ||
| tabIndex={0} | ||
| > | ||
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | ||
| </div> | ||
| ) |
There was a problem hiding this comment.
关闭按钮缺少键盘事件处理
添加了 role="button" 和 tabIndex={0} 使元素可聚焦,但缺少 onKeyDown 处理器来响应 Enter/Space 键,影响键盘可访问性。
♿ 建议添加键盘事件支持
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault()
+ handleClose()
+ }
+ }
+
return (
<div
className={closeClasses}
onClick={handleClose}
role="button"
aria-label={locale.close}
tabIndex={0}
+ onKeyDown={handleKeyDown}
>📝 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.
| <div | |
| className={closeClasses} | |
| onClick={handleClose} | |
| role="button" | |
| aria-label={locale.close} | |
| tabIndex={0} | |
| > | |
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | |
| </div> | |
| ) | |
| const handleKeyDown = (e: React.KeyboardEvent) => { | |
| if (e.key === 'Enter' || e.key === ' ') { | |
| e.preventDefault() | |
| handleClose() | |
| } | |
| } | |
| return ( | |
| <div | |
| className={closeClasses} | |
| onClick={handleClose} | |
| role="button" | |
| aria-label={locale.close} | |
| tabIndex={0} | |
| onKeyDown={handleKeyDown} | |
| > | |
| {React.isValidElement(closeIcon) ? closeIcon : systomIcon} | |
| </div> | |
| ) |
🤖 Prompt for AI Agents
In `@src/packages/dialog/dialog.tsx` around lines 240 - 249, The close button div
(using closeClasses, closeIcon/systomIcon and handleClose) has role="button" and
tabIndex but lacks keyboard handling; add an onKeyDown handler on this element
that listens for Enter (Enter/Return) and Space keys and invokes handleClose
(optionally calling event.preventDefault() for Space) so keyboard users can
activate the close action; implement the handler as a small function near the
component (e.g., onCloseKeyDown or inline) and attach it to the div alongside
the existing onClick.
| // danger color 发现不一致TODO | ||
|
|
There was a problem hiding this comment.
危险色 TODO 建议落地或建立跟踪
与暗色主题一样,这里也保留了 danger 颜色的不一致/待办 TODO。建议在合并前确定最终值或创建 issue 并加引用,避免遗忘与跨主题不一致。
需要的话我可以帮忙整理两套主题的 danger 色对齐清单。
Also applies to: 171-172
🤖 Prompt for AI Agents
In `@src/styles/theme-daojia.scss` around lines 39 - 40, 当前样式文件里保留了两处“danger color
发现不一致TODO”注释(当前 diff 的注释以及文件中另一处相同 TODO),请在合并前落地解决:要么在相应的变量或主题声明处(将涉及的 danger
变量/配置统一,如 $danger / --color-danger / 对应暗/亮主题变量名)直接填入最终一致的色值并移除 TODO,要么创建一个跟踪
issue 并在两个 TODO 注释中添加该 issue 编号和责任人以避免遗忘;更新后确保注释被移除或替换为带有 issue 链接的说明。
| // danger color 发现不一致 TODO | ||
|
|
||
| // red color |
There was a problem hiding this comment.
危险色 TODO 建议落地或建立跟踪
这里有两处 TODO 指向 danger 颜色体系不一致/语义化未完成,长期保留会让主题规范难以落地。建议在合并前明确最终取值,或至少创建 issue 并在注释里引用。
如需我整理一份 danger 颜色对齐方案或创建 issue 模板,请告知。
Also applies to: 170-171
🤖 Prompt for AI Agents
In `@src/styles/theme-dark-daojia.scss` around lines 38 - 40, 在
src/styles/theme-dark-daojia.scss 中存在两处 TODO 注释(例如 "// danger color 发现不一致 TODO"
及另一处指向 danger 的注释),请不要保留模糊的 TODO:要么直接在该 SCSS 中将 danger 颜色替换为确定的、语义化的变量值(例如统一成
$color-danger 或 $danger-xxx),确保两个注释处使用同一变量/色值;要么在合并前创建一个 issue
描述当前不一致并在这两个注释中加入该 issue 链接/编号并写明需要决策的候选值,确保注释里包含 issue 编号以便追踪(同时更新注释文本以反映已创建的
issue)。
| --nutui-color-mask-fault-toleran: var(--nutui-color-mask-gray-1); | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for both spelling variations in the repository
echo "=== Searching for 'fault-toleran' (without final 't') ==="
rg -n "nutui-color-mask-fault-toleran"
echo ""
echo "=== Searching for 'fault-tolerant' (with final 't') ==="
rg -n "nutui-color-mask-fault-tolerant"Repository: jdf2e/nutui-react
Length of output: 722
修复 --nutui-color-mask-fault-toleran 的拼写错误
变量名 --nutui-color-mask-fault-toleran 在整个主题系统中使用一致,但少了一个 "t",应为 --nutui-color-mask-fault-tolerant。该错误出现在 6 个文件中(variables.scss、variables-daojia.scss、theme-default.scss、theme-dark-daojia.scss、theme-daojia.scss、theme-dark.scss),建议统一修正拼写。
🤖 Prompt for AI Agents
In `@src/styles/theme-dark-daojia.scss` around lines 221 - 222, The CSS custom
property name is misspelled: replace every occurrence of
--nutui-color-mask-fault-toleran with the correct
--nutui-color-mask-fault-tolerant across all theme and variables SCSS files and
update any references/usages (variables.scss, variables-daojia.scss,
theme-*.scss) so definitions and lookups use the corrected symbol consistently.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/packages/toast/Notification.tsx`:
- Around line 137-138: The aria-label concatenation in Notification.tsx
currently does (title ?? '') + (content ?? '') creating no separator and an
empty string when both are missing; update the aria-label expression to produce
a readable label by joining non-empty values with a space (e.g., combine title
and content only if present, inserting a single space between them) and ensure
the fallback is undefined or omitted when both are empty so screen readers don't
receive an empty label; locate the aria-label attribute on the Notification
component and change how title and content are combined accordingly.
In `@src/packages/toast/toast.taro.tsx`:
- Around line 182-183: The ariaLabel currently concatenates (title ?? '') +
(content ?? '') which can produce unseparated text or "[object Object]" for
non-string content; update the ariaLabel logic in the Toast component
(toast.taro.tsx) to (1) build a sanitized string by including a clear separator
(e.g. ": " or " - ") between title and content, and (2) only append content when
it is a string or number (or extract plaintext safely from a ReactNode via a
helper like getTextFromNode) otherwise skip or use a provided contentLabel prop;
reference the ariaLabel prop and the title and content values to implement this
filtering and separator behavior.
🧹 Nitpick comments (1)
src/packages/toast/toast.taro.tsx (1)
150-153: 可缓存平台判断,减少重复调用并提升可读性。Line 150 与 Line 187 都在做平台判断,建议提取一次复用。
♻️ 建议改法
- const styles = - harmony() || td() + const isDynamic = harmony() || td() + const styles = + isDynamic ? { left: '50%', transform: 'translate(-50%, -50%)' } : null @@ - {content && - (td() ? ( + {content && + (isDynamic ? ( <Text className={`${classPrefix}-text`}>{content}</Text> ) : ( <View className={`${classPrefix}-text`}>{content}</View> ))}
| role="alert" | ||
| aria-label={(title ?? '') + (content ?? '')} |
There was a problem hiding this comment.
aria-label 拼接缺少分隔符,可能影响无障碍体验
当 title 和 content 同时存在时,当前拼接方式会生成无空格的字符串(如 "标题内容" 而非 "标题 内容"),对屏幕阅读器用户不够友好。另外,若两者都为空,aria-label 会是空字符串。
🛠️ 建议修复:添加分隔符并处理空值
role="alert"
- aria-label={(title ?? '') + (content ?? '')}
+ aria-label={[title, content].filter(Boolean).join(' ')}📝 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.
| role="alert" | |
| aria-label={(title ?? '') + (content ?? '')} | |
| role="alert" | |
| aria-label={[title, content].filter(Boolean).join(' ')} |
🤖 Prompt for AI Agents
In `@src/packages/toast/Notification.tsx` around lines 137 - 138, The aria-label
concatenation in Notification.tsx currently does (title ?? '') + (content ?? '')
creating no separator and an empty string when both are missing; update the
aria-label expression to produce a readable label by joining non-empty values
with a space (e.g., combine title and content only if present, inserting a
single space between them) and ensure the fallback is undefined or omitted when
both are empty so screen readers don't receive an empty label; locate the
aria-label attribute on the Notification component and change how title and
content are combined accordingly.
| ariaRole="alert" | ||
| ariaLabel={(title ?? '') + (content ?? '')} |
There was a problem hiding this comment.
ariaLabel 建议做分隔与类型过滤,避免读屏拼接或 [object Object]。
当前直接拼接 (title ?? '') + (content ?? '') 无分隔,且 content 若为 ReactNode 可能被 toString,影响可访问性。
🛠️ 建议改法
+ const ariaText =
+ [title, content]
+ .filter((v) => typeof v === 'string' && v.trim() !== '')
+ .join(' ') || undefined
@@
- ariaLabel={(title ?? '') + (content ?? '')}
+ ariaLabel={ariaText}🤖 Prompt for AI Agents
In `@src/packages/toast/toast.taro.tsx` around lines 182 - 183, The ariaLabel
currently concatenates (title ?? '') + (content ?? '') which can produce
unseparated text or "[object Object]" for non-string content; update the
ariaLabel logic in the Toast component (toast.taro.tsx) to (1) build a sanitized
string by including a clear separator (e.g. ": " or " - ") between title and
content, and (2) only append content when it is a string or number (or extract
plaintext safely from a ReactNode via a helper like getTextFromNode) otherwise
skip or use a provided contentLabel prop; reference the ariaLabel prop and the
title and content values to implement this filtering and separator behavior.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/types/spec/textarea/base.ts`:
- Around line 3-5: The BaseTextArea interface currently makes viewId required
which is a breaking change; update the type to make viewId optional (change
viewId: string to viewId?: string in BaseTextArea) and then audit usages of
BaseTextArea (components that implement or consume BaseTextArea) to handle
missing viewId safely or enforce passing a value at construction; alternatively,
if you opt to keep it required, revert the type and instead add runtime
checks/defaults in the TextArea component to ensure a viewId is always provided
and update docs—reference the BaseTextArea interface and the TextArea component
implementations when applying the change.
🧹 Nitpick comments (2)
src/packages/noticebar/demos/taro/demo10.tsx (1)
38-38: 可选优化:动态列表中使用index作为key可能导致渲染异常。当前列表支持动态添加/删除操作,使用
index作为key在删除中间项时可能导致 React 的 diff 算法产生非预期的 DOM 复用。建议使用稳定唯一标识符,例如item本身(若唯一)或生成的 ID。由于这是 demo 文件且影响较小,可视情况决定是否调整。
♻️ 可选修改
<div className="custom-item" style={{ height: '50px', lineHeight: '50px', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', }} - key={index} + key={item} onClick={() => { console.log('custom-inner', item) }} >src/packages/noticebar/noticebar.taro.tsx (1)
9-9: 在异步测量后添加 ref 校验,防止组件卸载后的状态更新。Taro 的
nextTick在组件卸载后仍会继续执行回调,await getRectInMultiPlatform完成后仍可能发生组件已卸载或关闭的情况。建议在所有await操作之后再次验证 ref 有效性,防止无效的状态更新。♻️ 建议修改
nextTick(async () => { if (!wrapRef.current || !contentRef.current) { return } const warpRes = await getRectInMultiPlatform(wrapRef.current, wrapRefId) const contentRes = await getRectInMultiPlatform( contentRef.current, contentRefId ) + if (!wrapRef.current || !contentRef.current) { + return + } if (!warpRes || !contentRes) return同样适用于其他使用
nextTick + await的位置(如 popover 组件)。
| export interface BaseTextArea<EVENT = any> extends BaseProps { | ||
| viewId: string | ||
| value: string |
There was a problem hiding this comment.
将 viewId 设为必填会造成破坏性变更。
公共类型要求必传,但组件内部仍允许缺省,会导致既有调用方编译失败。建议改为可选,或在默认值/文档中明确要求并确保组件强制传入。
🔧 建议改为可选
export interface BaseTextArea<EVENT = any> extends BaseProps {
- viewId: string
+ viewId?: string
value: string📝 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.
| export interface BaseTextArea<EVENT = any> extends BaseProps { | |
| viewId: string | |
| value: string | |
| export interface BaseTextArea<EVENT = any> extends BaseProps { | |
| viewId?: string | |
| value: string |
🤖 Prompt for AI Agents
In `@src/types/spec/textarea/base.ts` around lines 3 - 5, The BaseTextArea
interface currently makes viewId required which is a breaking change; update the
type to make viewId optional (change viewId: string to viewId?: string in
BaseTextArea) and then audit usages of BaseTextArea (components that implement
or consume BaseTextArea) to handle missing viewId safely or enforce passing a
value at construction; alternatively, if you opt to keep it required, revert the
type and instead add runtime checks/defaults in the TextArea component to ensure
a viewId is always provided and update docs—reference the BaseTextArea interface
and the TextArea component implementations when applying the change.
🤔 这个变动的性质是?
🔗 相关 Issue
💡 需求背景和解决方案
☑️ 请求合并前的自查清单
Summary by CodeRabbit
新功能
改进
样式
测试