Skip to content

Conversation

@yangyanAurora
Copy link

@yangyanAurora yangyanAurora commented Nov 10, 2025

  • button
  • Checkbox
  • Countdown
  • Empty
  • Image
  • InputNumber
  • Price
  • Progress
  • NavBar
  • NoticeBar
  • Radio
  • Switch
  • Tabbar
  • Tabs
  • Toast

🤔 这个变动的性质是?

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

🔗 相关 Issue

💡 需求背景和解决方案

为让更多人(包括残障人士)能够平等、便捷地使用和访问应用,对组件提升对无障碍的支持。

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

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

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

Summary by CodeRabbit

新功能

  • 多个组件新增无障碍支持:添加ARIA标签、角色和属性,增强屏幕阅读器兼容性
  • 倒计时组件:新增结束时的通知提醒功能
  • 交互组件改进:为按钮、复选框、单选、开关、标签栏等添加ARIA角色和状态属性
  • 图片、导航栏、价格等组件:添加文字标签用于屏幕阅读

- button
- Checkbox
- Countdown
- Empty
- Image
- InputNumber
- Price
- Progress
- NavBar
- NoticeBar
- Radio
- Switch
- Tabbar
- Tabs
- Toast
@github-actions github-actions bot added action:review This PR needs more reviews (less than 2 approvals) 3.x Target branch 3.x labels Nov 10, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

此PR为NutUI React组件库的多个组件系统添加ARIA可访问性属性支持,包括角色、标签、选中状态等属性,同时新增相关演示和类型定义,以改进屏幕阅读器兼容性。

Changes

Cohort / File(s) 变更摘要
按钮组件可访问性
src/packages/button/button.taro.tsx
添加 ariaLabel="button" 属性到TaroButton元素以增强可访问性。
复选框组件可访问性
src/packages/checkbox/checkbox.taro.tsx, src/packages/checkbox/checkbox.tsx
添加 ariaRole="checkbox"ariaChecked 属性,反映复选框的选中和非不定状态。
倒计时组件ARIA增强
src/packages/countdown/countdown.taro.tsx, src/packages/countdown/countdown.tsx
添加 ariaRoledescription 属性,实现倒计时结束时的ARIA alert提示("时间到")。
倒计时演示和翻译
src/packages/countdown/demo.taro.tsx, src/packages/countdown/demo.tsx, src/packages/countdown/demos/h5/demo10.tsx, src/packages/countdown/demos/taro/demo10.tsx
添加新演示组件Demo10和国际化翻译支持。
对话框ARIA支持
src/packages/dialog/content.taro.tsx, src/packages/dialog/content.tsx, src/packages/dialog/dialog.taro.tsx, src/packages/dialog/dialog.tsx
添加 role="dialog"aria-modal 和内容特定的ARIA属性。
图片组件可访问性
src/packages/image/image.taro.tsx, src/packages/image/image.tsx, src/packages/image/demo.taro.tsx, src/packages/image/demo.tsx, src/packages/image/demos/h5/demo9.tsx, src/packages/image/demos/taro/demo9.tsx
添加 ariaLabel 属性及演示。
数字输入组件按钮角色
src/packages/inputnumber/inputnumber.taro.tsx, src/packages/inputnumber/inputnumber.tsx
为加减按钮添加 role="button"tabIndex 属性。
导航栏ARIA增强
src/packages/navbar/navbar.taro.tsx, src/packages/navbar/navbar.tsx, src/packages/navbar/demo.taro.tsx, src/packages/navbar/demo.tsx, src/packages/navbar/demos/h5/demo4.tsx, src/packages/navbar/demos/taro/demo4.tsx
添加 role="navigation"、返回按钮和标题的ARIA标签。
通知条ARIA增强
src/packages/noticebar/noticebar.taro.tsx, src/packages/noticebar/noticebar.tsx, src/packages/noticebar/demo.taro.tsx, src/packages/noticebar/demo.tsx, src/packages/noticebar/demos/h5/demo12.tsx, src/packages/noticebar/demos/taro/demo12.tsx
添加 rightIconAriaLabel 属性和隐藏图标的ARIA支持。
弹窗ARIA角色
src/packages/popup/popup.taro.tsx, src/packages/popup/popup.tsx
添加 role="dialog" 属性到弹窗容器。
价格组件ARIA标签
src/packages/price/price.taro.tsx, src/packages/price/price.tsx
添加基于符号和格式的动态 ariaLabel
进度条ARIA支持
src/packages/progress/progress.taro.tsx, src/packages/progress/progress.tsx
添加 role="progressbar"ariaLabel 属性。
单选框ARIA属性
src/packages/radio/radio.taro.tsx, src/packages/radio/radio.tsx
添加 role="radio"tabIndexaria-checked 属性。
开关组件ARIA增强
src/packages/switch/switch.taro.tsx, src/packages/switch/switch.tsx
添加 role="switch"tabIndexaria-checked 属性。
轮播图ARIA支持
src/packages/swiper/swiper.taro.tsx, src/packages/swiper/swiper.tsx, src/packages/swiper/effects/default.tsx, src/packages/swiper/effects/focus.tsx, src/packages/swiper/demo.taro.tsx, src/packages/swiper/demos/taro/demo10.tsx
添加 ariaLabelaria-hiddentabIndex 属性及演示组件。
标签栏ARIA增强
src/packages/tabbar/tabbar.taro.tsx, src/packages/tabbar/tabbaritem/tabbaritem.taro.tsx, src/packages/tabbar/tabbaritem/tabbaritem.tsx, src/packages/tabbar/demo.taro.tsx, src/packages/tabbar/demo.tsx, src/packages/tabbar/demos/h5/demo10.tsx, src/packages/tabbar/demos/taro/demo10.tsx
添加 role="tab"aria-selectedariaLabelariaRoledescription 属性。
标签页ARIA支持
src/packages/tabs/tabs.taro.tsx, src/packages/tabs/tabs.tsx
添加 role="tablist"role="tab"aria-selected 属性。
提示框ARIA角色
src/packages/toast/Notification.tsx, src/packages/toast/toast.taro.tsx
添加 role="alert" 属性。
头部按钮ARIA
src/sites/components/header.tsx
添加返回按钮的 role="button"aria-label 属性。
类型定义ARIA扩展
src/types/spec/countdown/base.ts, src/types/spec/dialog/base.ts, src/types/spec/dialog/taro.ts, src/types/spec/image/base.ts, src/types/spec/noticebar/base.ts, src/types/spec/popup/base.ts, src/types/spec/progress/base.ts, src/types/spec/radio/base.ts, src/types/spec/swiper/taro.ts, src/types/spec/tabbar/base.ts
添加ARIA相关属性类型定义到各组件的基础接口。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

需要特别关注的区域:

  • 倒计时alert实现 — 验证"时间到"alert的3秒定时清除机制是否正确工作
  • 对话框role和aria-modal配置 — 确保role="dialog"与aria-modal的可视性绑定逻辑一致
  • 轮播图tab导航 — 检查tabIndex、aria-hidden和aria-label在多张幻灯片间的正确传播
  • 类型定义一致性 — 验证所有新增的ARIA属性类型定义与组件实现保持同步
  • 跨平台差异 — 确保Taro和Web版本的ARIA属性保持语义一致性

Possibly related PRs

Suggested reviewers

  • irisSong
  • oasis-cloud
  • Alex-huxiyang

Poem

🐰 兔子漫步在代码小径,
添加标签让视障者欢喜,
对话、标签、图片与开关,
无障碍之光闪闪发亮,
ARIA魔法让交互更有意义~✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed PR描述包含了必需的自查清单,标记了变动性质为新特性,说明了背景和解决方案,但缺少具体的相关Issue链接。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed PR标题清晰准确地反映了主要变更:为多个组件添加无障碍功能支持,这是一个新功能特性。

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

Caution

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

⚠️ Outside diff range comments (4)
src/packages/tabs/tabs.tsx (1)

161-213: 建议完善 ARIA Tabs 模式的实现

当前实现添加了基本的 ARIA 属性(role="tablist"role="tab"aria-selected),这是一个良好的开端。但完整的 ARIA Tabs 模式还需要以下增强:

  1. 键盘导航支持:应实现方向键(左/右或上/下)、Home、End 键的导航
  2. tabIndex 管理:活动标签应设置 tabIndex={0},非活动标签设置 tabIndex={-1}
  3. aria-controls:每个标签应通过 aria-controls 属性关联到对应的面板 ID

这些是 ARIA 规范中 Tabs 模式的必需特性,能显著提升键盘用户和屏幕阅读器用户的体验。

参考 ARIA Tabs 模式获取完整实现指南。

src/packages/inputnumber/inputnumber.tsx (2)

183-198: 建议完善按钮的无障碍实现

当前添加了 role="button"tabIndex={0},使元素可聚焦,但还需要以下改进才能成为完整的可访问按钮:

  1. aria-label:添加描述性标签(如 aria-label="减少数值"
  2. aria-disabled:反映禁用状态 aria-disabled={Number(shadowValue) <= Number(min) || disabled}
  3. 键盘激活:添加 onKeyDown 处理程序以支持 Enter 和 Space 键激活

建议修改:

       <div
         className={`${classPrefix}-minus`}
         onClick={handleReduce}
         role="button"
         tabIndex={0}
+        aria-label="减少数值"
+        aria-disabled={Number(shadowValue) <= Number(min) || disabled}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault()
+            handleReduce(e as any)
+          }
+        }}
       >

212-227: 增加按钮也需要完善的无障碍实现

与减少按钮类似,增加按钮也需要添加 aria-labelaria-disabled 和键盘激活支持。

建议修改:

       <div
         className={`${classPrefix}-add`}
         role="button"
         tabIndex={0}
         onClick={handlePlus}
+        aria-label="增加数值"
+        aria-disabled={Number(shadowValue) >= Number(max) || disabled}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault()
+            handlePlus(e as any)
+          }
+        }}
       >
src/packages/image/demo.tsx (1)

25-36: 修正拼写错误

翻译键名称中存在拼写错误。应该是 "ARIA"(Accessible Rich Internet Applications),而不是 "ATRIA"。

应用此修复:

-      ATRIAUsage: 'ATRIA用法',
+      ARIAUsage: 'ARIA用法',
     },
     'en-US': {
       basic: 'Basic Usage',
@@ -32,7 +32,7 @@
       error: 'Error',
       lazyload: 'Lazyload',
       imageText: 'image + text ',
-      ATRIAUsage: 'ATRIA Usage',
+      ARIAUsage: 'ARIA Usage',
     },
🧹 Nitpick comments (18)
src/packages/toast/Notification.tsx (1)

137-137: 考虑为不同类型的 Toast 使用不同的 ARIA 角色

当前为所有 Toast 类型统一使用 role="alert"。虽然这对于 success、fail、warn 等提示类消息是合适的,但对于 loading 类型的 Toast,role="status" 可能更为恰当,因为:

  • role="alert" 隐式设置了 aria-live="assertive",会立即打断屏幕阅读器
  • loading 状态更适合使用 role="status"(隐式 aria-live="polite"),以非打断方式通知用户

建议根据 Toast 类型动态设置 role:

          <div
            className={classNames(
              `${classPrefix}-inner`,
              `${classPrefix}-${position}`,
              contentClassName,
              `${classPrefix}-inner-${size}`,
              `${classPrefix}-inner-${wordBreak}`,
              {
                [`${classPrefix}-inner-descrption`]: content,
              }
            )}
            style={{
              ...contentStyle,
            }}
-           role="alert"
+           role={icon === 'loading' ? 'status' : 'alert'}
          >
src/packages/toast/toast.taro.tsx (1)

181-181: 建议为不同类型的 Toast 使用不同的 ARIA 角色

Notification.tsx 中的建议一致,Taro 版本也应该根据 Toast 类型动态设置 ariaRole

  • 对于 loading 类型,使用 ariaRole="status" 更为合适(非打断式通知)
  • 对于 successfailwarn 等类型,使用 ariaRole="alert" 是恰当的(立即通知)

建议应用以下修改:

            <View
              className={classNames(
                `${classPrefix}-inner`,
                `${classPrefix}-${position}`,
                contentClassName,
                `${classPrefix}-inner-${size}`,
                `${classPrefix}-inner-${wordBreak}`,
                {
                  [`${classPrefix}-inner-descrption`]: content,
                }
              )}
              style={{ ...styles, ...contentStyle }}
-             ariaRole="alert"
+             ariaRole={icon === 'loading' ? 'status' : 'alert'}
            >
src/packages/switch/switch.tsx (1)

85-93: 应根据禁用状态条件性地设置 tabIndex。

无障碍属性的添加总体良好,但 tabIndex={0} 应仅在组件未禁用时应用。当前实现即使在禁用状态下也会使元素可聚焦,这不符合无障碍最佳实践。

应用以下修改:

 <div
   className={classes()}
   onClick={onClick}
   style={style}
   {...rest}
   role="switch"
-  tabIndex={0}
+  tabIndex={disabled ? -1 : 0}
   aria-checked={value}
 >

另外,建议添加键盘事件处理器以支持空格键和回车键切换开关状态:

+const handleKeyDown = (e: React.KeyboardEvent) => {
+  if (e.key === ' ' || e.key === 'Enter') {
+    e.preventDefault()
+    onClick()
+  }
+}
+
 <div
   className={classes()}
   onClick={onClick}
+  onKeyDown={handleKeyDown}
   style={style}
   {...rest}
   role="switch"
   tabIndex={disabled ? -1 : 0}
   aria-checked={value}
 >
src/packages/checkbox/checkbox.taro.tsx (1)

206-207: 考虑为不确定状态添加 aria-checked="mixed" 支持

当前实现中,ariaChecked 在不确定状态(indeterminate)时值为 false,但根据 ARIA 规范,复选框的不确定状态应该使用 aria-checked="mixed" 来正确传达给辅助技术。

建议修改为:

       ariaRole="checkbox"
-      ariaChecked={innerChecked && !innerIndeterminate}
+      ariaChecked={
+        innerIndeterminate ? 'mixed' : innerChecked
+      }
src/packages/navbar/navbar.taro.tsx (2)

70-70: 建议支持 ARIA 标签的国际化

ariaLabel="back" 使用了硬编码的英文文本,这会影响非英语用户的无障碍体验。建议通过组件 props 或国际化系统来支持多语言的 ARIA 标签。


87-87: 标题的 ARIA 标签也需要国际化支持

与返回按钮类似,ariaLabel="nav title" 的硬编码英文文本应该支持国际化,以便为不同语言的用户提供适当的无障碍标签。

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

185-200: 建议为按钮添加更完善的无障碍属性

当前只添加了 ariaRole="button",但缺少其他重要的无障碍属性:

  1. ariaLabel: 应该添加描述性标签(如 "减少数值"),让屏幕阅读器用户了解按钮用途
  2. ariaDisabled: 当按钮禁用时(值达到最小值或 disabled 为 true),应该设置 ariaDisabled={true} 来明确传达状态

建议修改:

       <View
         className={`${classPrefix}-minus`}
         onClick={handleReduce}
         ariaRole="button"
+        ariaLabel="减少数值"
+        ariaDisabled={Number(shadowValue) <= Number(min) || disabled}
       >

216-231: 增加按钮也需要完善的无障碍属性

与减少按钮类似,增加按钮也应该添加 ariaLabelariaDisabled 属性以提供完整的无障碍支持。

建议修改:

       <View
         className={`${classPrefix}-add`}
         onClick={handlePlus}
         ariaRole="button"
+        ariaLabel="增加数值"
+        ariaDisabled={Number(shadowValue) >= Number(max) || disabled}
       >
src/types/spec/countdown/base.ts (1)

30-30: 建议将 ariaRoledescription 设为可选属性

ariaRoledescription 通常不是所有倒计时场景都需要的属性。建议在类型定义中将其标记为可选:

-  ariaRoledescription: string
+  ariaRoledescription?: string

或者确保在组件的 defaultProps 中提供合理的默认值(如空字符串)。

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

69-69: 建议支持 ARIA 标签的国际化

与 Taro 版本类似,这里的 aria-label="back"aria-label="nav title" 使用了硬编码的英文文本。建议通过组件 props 或国际化系统来支持多语言的无障碍标签,以便为全球用户提供适当的无障碍体验。

Also applies to: 86-86

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

236-236: 检查冗余的角色属性

在同一个元素上同时使用了 role="tablist"ariaRole="tablist"。在 Taro 中,通常只需要使用 ariaRole 属性,role 属性可能是冗余的。

建议验证 Taro 文档以确认正确的用法。如果只需要 ariaRole,可以移除 role 属性:

-        <View className="nut-tabs-list" role="tablist" ariaRole="tablist">
+        <View className="nut-tabs-list" ariaRole="tablist">

262-263: 验证 ariaHidden 属性语法

ariaHidden 属性没有显式设置值。在 Taro 中,建议明确设置布尔值。

建议明确设置为 true

-                        ariaHidden
+                        ariaHidden={true}
src/packages/navbar/demos/taro/demo4.tsx (1)

1-113: ARIA 演示实现良好

此演示文件很好地展示了如何在 NavBar 组件中使用 ARIA 属性。各个交互元素都添加了适当的 ariaLabel,有助于屏幕阅读器用户理解界面。

可选建议:第 59 和 63 行的 ariaLabel 是添加在文本容器上的,这些元素不是交互元素,可以考虑是否需要这些标签。通常 aria-label 用于交互元素或需要替代文本的元素。

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

296-300: 避免在 dangerouslySetInnerHTML 中使用字符串插值

虽然当前代码中 rolealertContent 是组件内部控制的,没有直接的 XSS 风险,但使用 dangerouslySetInnerHTML 配合字符串插值不是最佳实践。建议使用 React 的 ARIA live region 方法来实现提醒功能。

建议重构为使用单独的元素和 React 状态:

-          aria-label="倒计时"
-          aria-roledescription={ariaRoledescription}
-          {...rest}
-          dangerouslySetInnerHTML={{
-            __html: `${renderTime}<span style="display:none" role=${role}>${alertContent}</span>`,
-          }}
+          aria-label="倒计时"
+          aria-roledescription={ariaRoledescription}
+          {...rest}
+        >
+          <div dangerouslySetInnerHTML={{ __html: renderTime }} />
+          {role && (
+            <span style={{ display: 'none' }} role={role}>
+              {alertContent}
+            </span>
+          )}
+        </div>
-        />

这样可以避免在 HTML 字符串中插值,更安全且更符合 React 最佳实践。

src/sites/components/header.tsx (1)

32-32: 返回按钮无障碍属性正确

为返回按钮添加 role='button'aria-label='back' 提高了可访问性,有助于屏幕阅读器用户理解此元素的功能。

可选建议:为保持代码风格一致性,可以考虑使用双引号:

-          <div className="back" onClick={navigateTo} role='button' aria-label='back'>
+          <div className="back" onClick={navigateTo} role="button" aria-label="back">
src/packages/popup/popup.taro.tsx (1)

316-316: 建议添加 aria-modal 属性

当 Popup 作为对话框(dialog)呈现并且具有遮罩层时,应该添加 ariaModal 属性以向辅助技术指示这是一个模态对话框。这是 ARIA 对话框模式的最佳实践。

应用以下修改:

         onTouchEnd={handleTouchEnd}
         ariaRole="dialog"
+        ariaModal={overlay && innerVisible}
       >
src/packages/image/demos/taro/demo9.tsx (1)

9-9: 建议澄清 altariaLabel 的使用场景

Image 组件同时使用了 alt="图片内容"ariaLabel="图片"。对于图片元素,aria-label 会覆盖 alt 文本。通常情况下:

  • 仅使用 alt 即可满足大多数无障碍需求
  • aria-label 适用于需要为屏幕阅读器提供与 alt 不同的额外上下文时

建议在演示中明确两者的使用场景,或根据实际需求选择其一,避免混淆。

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

460-462: 建议显式设置 aria-hidden 值

虽然在 HTML/React 中,aria-hidden 不带值会被浏览器解析为字符串 "true",但显式设置布尔值 aria-hidden={true} 会更清晰且与 TypeScript 的类型检查更一致。

可选改进:

           {leftIcon ? (
-            <div className="nut-noticebar-box-left-icon" aria-hidden>
+            <div className="nut-noticebar-box-left-icon" aria-hidden="true">
               {leftIcon}
             </div>
📜 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 2e7cbd2.

📒 Files selected for processing (70)
  • src/packages/button/button.taro.tsx (1 hunks)
  • src/packages/checkbox/checkbox.taro.tsx (1 hunks)
  • src/packages/checkbox/checkbox.tsx (1 hunks)
  • src/packages/countdown/countdown.taro.tsx (4 hunks)
  • src/packages/countdown/countdown.tsx (4 hunks)
  • src/packages/countdown/demo.taro.tsx (5 hunks)
  • src/packages/countdown/demo.tsx (5 hunks)
  • src/packages/countdown/demos/h5/demo10.tsx (1 hunks)
  • src/packages/countdown/demos/taro/demo10.tsx (1 hunks)
  • src/packages/dialog/content.taro.tsx (2 hunks)
  • src/packages/dialog/content.tsx (2 hunks)
  • src/packages/dialog/dialog.taro.tsx (5 hunks)
  • src/packages/dialog/dialog.tsx (2 hunks)
  • src/packages/image/demo.taro.tsx (4 hunks)
  • src/packages/image/demo.tsx (4 hunks)
  • src/packages/image/demos/h5/demo9.tsx (1 hunks)
  • src/packages/image/demos/taro/demo9.tsx (1 hunks)
  • src/packages/image/image.taro.tsx (2 hunks)
  • src/packages/image/image.tsx (2 hunks)
  • src/packages/inputnumber/inputnumber.taro.tsx (2 hunks)
  • src/packages/inputnumber/inputnumber.tsx (2 hunks)
  • src/packages/navbar/demo.taro.tsx (2 hunks)
  • src/packages/navbar/demo.tsx (2 hunks)
  • src/packages/navbar/demos/h5/demo4.tsx (1 hunks)
  • src/packages/navbar/demos/taro/demo4.tsx (1 hunks)
  • src/packages/navbar/navbar.taro.tsx (3 hunks)
  • src/packages/navbar/navbar.tsx (3 hunks)
  • src/packages/noticebar/demo.taro.tsx (4 hunks)
  • src/packages/noticebar/demo.tsx (4 hunks)
  • src/packages/noticebar/demos/h5/demo12.tsx (1 hunks)
  • src/packages/noticebar/demos/taro/demo12.tsx (1 hunks)
  • src/packages/noticebar/noticebar.taro.tsx (4 hunks)
  • src/packages/noticebar/noticebar.tsx (4 hunks)
  • src/packages/popup/popup.taro.tsx (1 hunks)
  • src/packages/popup/popup.tsx (1 hunks)
  • src/packages/price/price.taro.tsx (1 hunks)
  • src/packages/price/price.tsx (1 hunks)
  • src/packages/progress/progress.taro.tsx (1 hunks)
  • src/packages/progress/progress.tsx (1 hunks)
  • src/packages/radio/radio.taro.tsx (1 hunks)
  • src/packages/radio/radio.tsx (1 hunks)
  • src/packages/swiper/demo.taro.tsx (4 hunks)
  • src/packages/swiper/demos/taro/demo10.tsx (1 hunks)
  • src/packages/swiper/effects/default.tsx (3 hunks)
  • src/packages/swiper/effects/focus.tsx (1 hunks)
  • src/packages/swiper/swiper.taro.tsx (2 hunks)
  • src/packages/swiper/swiper.tsx (2 hunks)
  • src/packages/switch/switch.taro.tsx (1 hunks)
  • src/packages/switch/switch.tsx (1 hunks)
  • src/packages/tabbar/demo.taro.tsx (5 hunks)
  • src/packages/tabbar/demo.tsx (5 hunks)
  • src/packages/tabbar/demos/h5/demo10.tsx (1 hunks)
  • src/packages/tabbar/demos/taro/demo10.tsx (1 hunks)
  • src/packages/tabbaritem/tabbaritem.taro.tsx (1 hunks)
  • src/packages/tabbaritem/tabbaritem.tsx (2 hunks)
  • src/packages/tabs/tabs.taro.tsx (3 hunks)
  • src/packages/tabs/tabs.tsx (3 hunks)
  • src/packages/toast/Notification.tsx (1 hunks)
  • src/packages/toast/toast.taro.tsx (1 hunks)
  • src/sites/components/header.tsx (1 hunks)
  • src/types/spec/countdown/base.ts (1 hunks)
  • src/types/spec/dialog/base.ts (1 hunks)
  • src/types/spec/dialog/taro.ts (1 hunks)
  • src/types/spec/image/base.ts (1 hunks)
  • src/types/spec/noticebar/base.ts (1 hunks)
  • src/types/spec/popup/base.ts (1 hunks)
  • src/types/spec/progress/base.ts (1 hunks)
  • src/types/spec/radio/base.ts (2 hunks)
  • src/types/spec/swiper/taro.ts (1 hunks)
  • src/types/spec/tabbar/base.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2700
File: src/packages/animatingnumbers/animatingnumbers.harmony.css:25-32
Timestamp: 2024-11-06T05:56:06.800Z
Learning: 在优化 NutUI React 动画性能时,添加 `will-change` 属性可能会对布局产生影响,需要谨慎使用。
📚 Learning: 2024-11-06T05:56:06.800Z
Learnt from: oasis-cloud
Repo: jdf2e/nutui-react PR: 2700
File: src/packages/animatingnumbers/animatingnumbers.harmony.css:25-32
Timestamp: 2024-11-06T05:56:06.800Z
Learning: 在优化 NutUI React 动画性能时,添加 `will-change` 属性可能会对布局产生影响,需要谨慎使用。

Applied to files:

  • src/packages/noticebar/demos/h5/demo12.tsx
  • src/packages/noticebar/demos/taro/demo12.tsx
📚 Learning: 2024-07-05T02:58:57.992Z
Learnt from: Alex-huxiyang
Repo: jdf2e/nutui-react PR: 2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-07-05T02:58:57.992Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.

Applied to files:

  • src/packages/checkbox/checkbox.taro.tsx
📚 Learning: 2025-05-02T01:45:09.576Z
Learnt from: irisSong
Repo: jdf2e/nutui-react PR: 3209
File: src/packages/searchbar/searchbar.taro.tsx:111-124
Timestamp: 2025-05-02T01:45:09.576Z
Learning: 在 React/Taro 组件中使用 setTimeout 或 setInterval 时,应当在组件卸载时通过 useEffect 的清理函数清除定时器,以防止内存泄漏。可以使用 useState 存储定时器 ID,并在 useEffect 的返回函数中清除。

Applied to files:

  • src/packages/countdown/demos/h5/demo10.tsx
  • src/packages/countdown/demos/taro/demo10.tsx
  • src/packages/navbar/demos/taro/demo4.tsx
  • src/packages/countdown/countdown.taro.tsx
🧬 Code graph analysis (14)
src/packages/swiper/effects/focus.tsx (1)
src/hooks/use-ref-state.ts (1)
  • getRefValue (3-5)
src/packages/noticebar/demos/h5/demo12.tsx (3)
src/packages/noticebar/noticebar.taro.tsx (1)
  • NoticeBar (35-556)
src/packages/noticebar/noticebar.tsx (1)
  • NoticeBar (35-551)
src/packages/button/button.taro.tsx (1)
  • Button (63-182)
src/packages/radio/radio.taro.tsx (1)
src/packages/sidebar/utils.ts (1)
  • handleClick (22-22)
src/packages/tabbar/demos/taro/demo10.tsx (2)
src/packages/tabbar/demos/h5/demo9.tsx (1)
  • Tabbar (5-13)
src/packages/tabbar/demos/h5/demo5.tsx (1)
  • Tabbar (5-13)
src/packages/countdown/demo.tsx (1)
scripts/create-properties.js (1)
  • h2 (58-58)
src/packages/countdown/demos/h5/demo10.tsx (2)
src/packages/countdown/countdown.taro.tsx (1)
  • CountDown (355-357)
src/packages/countdown/countdown.tsx (1)
  • CountDown (308-310)
src/packages/countdown/demos/taro/demo10.tsx (2)
src/packages/countdown/countdown.taro.tsx (1)
  • CountDown (355-357)
src/packages/countdown/countdown.tsx (1)
  • CountDown (308-310)
src/types/spec/swiper/taro.ts (1)
src/types/spec/swiper/base.ts (1)
  • BaseSwiperItem (33-35)
src/packages/navbar/demos/h5/demo4.tsx (3)
src/packages/navbar/navbar.taro.tsx (1)
  • NavBar (19-138)
src/packages/navbar/navbar.tsx (1)
  • NavBar (18-137)
src/packages/toast/toast.taro.tsx (1)
  • Toast (39-194)
src/packages/navbar/demos/taro/demo4.tsx (3)
src/utils/taro/px-transform.ts (1)
  • pxTransform (5-9)
src/packages/navbar/navbar.taro.tsx (1)
  • NavBar (19-138)
src/utils/taro/platform.ts (1)
  • harmony (3-7)
src/packages/noticebar/demos/taro/demo12.tsx (2)
src/packages/noticebar/noticebar.taro.tsx (1)
  • NoticeBar (35-556)
src/packages/button/button.taro.tsx (1)
  • Button (63-182)
src/packages/image/demos/h5/demo9.tsx (2)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
src/packages/image/image.tsx (1)
  • Image (27-204)
src/packages/image/demos/taro/demo9.tsx (1)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
src/packages/swiper/demos/taro/demo10.tsx (3)
packages/nutui-inject-ui-styles/dist/index.js (1)
  • list (26-129)
src/packages/swiper/swiper.taro.tsx (1)
  • Swiper (31-179)
src/packages/image/image.taro.tsx (1)
  • Image (25-141)
🪛 ast-grep (0.39.7)
src/packages/countdown/countdown.tsx

[warning] 298-298: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🔇 Additional comments (43)
src/types/spec/popup/base.ts (1)

20-20: 此更改似乎与 PR 目标不符。

此 PR 的目标是添加无障碍功能支持,但 top?: ReactNode 属性似乎是一个 UI 布局属性,而非无障碍相关的属性。请确认:

  1. 此更改是否应该包含在本 PR 中
  2. 或者应该在单独的 PR 中处理布局功能增强
src/packages/navbar/navbar.taro.tsx (1)

110-110: LGTM - 导航角色设置正确

ariaRole="navigation" 正确使用了 ARIA 地标角色,有助于屏幕阅读器用户快速导航到页面的导航区域。

src/types/spec/dialog/taro.ts (1)

6-7: LGTM - 类型定义正确

TaroContentProps 添加 ariaModalariaRole 属性的类型定义是正确的,这些属性将帮助对话框组件正确实现 ARIA 规范中的模态对话框语义。

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

185-186: LGTM - 正确隐藏装饰性元素

在视觉装饰元素(活动线指示器和笑脸图标)上使用 aria-hidden 是正确的做法,这可以防止屏幕阅读器读取这些仅用于视觉呈现的元素。

Also applies to: 189-192

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

109-109: LGTM - 导航角色设置正确

role="navigation" 正确使用了 ARIA 地标角色,有助于屏幕阅读器用户识别和导航到导航区域。

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

266-269: 验证 ariaHidden 属性语法

与上面的问题相同,建议为 ariaHidden 明确设置布尔值。
[request_optional_refactor]

-                      <View
-                        className={`${classPrefix}-titles-item-smile`}
-                        ariaHidden
-                      >
+                      <View
+                        className={`${classPrefix}-titles-item-smile`}
+                        ariaHidden={true}
+                      >

281-284: ARIA 标签页属性实现正确

ariaRole="tab"ariaSelected 的实现符合 WAI-ARIA 规范,正确反映了标签页的选中状态。

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

225-226: 进度条无障碍属性实现正确

正确添加了 ariaLabelariaRole="progressbar" 属性,为屏幕阅读器提供了清晰的进度信息。默认的中文标签 "进度${percent}%" 对于中文用户友好。

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

138-139: Web 版本无障碍属性实现正确

使用标准的 React ARIA 属性 aria-labelrole="progressbar",与 Taro 版本保持一致。

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

292-292: 弹窗角色属性正确

为弹窗容器添加 role="dialog" 符合 WAI-ARIA 规范,有助于屏幕阅读器正确识别弹窗的语义。

src/packages/countdown/countdown.tsx (2)

65-67: ARIA 提醒状态管理

添加状态来管理 ARIA 提醒的角色和内容是合理的。


105-110: 倒计时结束提醒逻辑

在倒计时结束时设置 ARIA 提醒,3秒后清除,这个交互逻辑合理。

src/packages/countdown/demo.tsx (1)

12-12: 代码更改看起来不错

Demo10 的导入和 ARIA 基础用法示例集成正确,多语言翻译键(zh-CN、zh-TW、en-US)都已正确添加。

Also applies to: 26-26, 38-38, 50-50, 75-76

src/packages/swiper/demo.taro.tsx (1)

17-17: 代码更改看起来不错

Demo10 的导入和 ARIA 示例集成正确,多语言翻译已正确添加。

Also applies to: 31-31, 43-43, 84-85

src/packages/navbar/demo.taro.tsx (1)

10-10: 代码更改看起来不错

Demo4 的导入和 ARIA 基础用法示例集成正确,多语言翻译键已完整添加。

Also applies to: 18-18, 24-24, 30-30, 45-46

src/packages/navbar/demo.tsx (1)

7-7: 代码更改看起来不错

Demo4 的导入和 ARIA 基础用法示例集成正确,多语言翻译已完整添加。

Also applies to: 15-15, 21-21, 27-27, 39-40

src/packages/noticebar/demo.tsx (1)

15-15: LGTM! ARIA 演示添加正确

Demo12 的导入、翻译键和渲染逻辑都符合现有的演示模式,实现正确。

Also applies to: 31-31, 45-45, 78-79

src/packages/noticebar/demo.taro.tsx (1)

19-19: LGTM! Taro 版本的 ARIA 演示添加正确

与 H5 版本保持一致,Demo12 的集成符合现有模式。

Also applies to: 35-35, 49-49, 88-89

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

38-38: LGTM! ariaLabel 属性传递正确

正确地从 props 中解构 ariaLabel 并传递给底层的 TImage 组件,实现了无障碍标签支持。

Also applies to: 133-133

src/packages/tabbar/demo.tsx (1)

12-12: LGTM! Demo10 集成正确

ARIA 演示的导入、翻译(除 zh-TW 的小问题外)和渲染逻辑都实现正确。

Also applies to: 26-26, 50-50, 73-74

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

26-26: rightIconAriaLabel 属性定义不会造成破坏性变更

虽然 rightIconAriaLabel: string 在接口中被定义为必需属性,但实际并不会导致现有代码失败。组件的类型签名使用了 Partial<WebNoticeBarProps>,这使得所有属性在组件层面都是可选的。此外,组件提供了默认值 rightIconAriaLabel: ''。现有演示代码(如 demo1.tsx)已经在不提供此属性的情况下成功运行。

将其改为可选属性仍是更好的做法,以保持接口定义与实现的一致性,但这不是必要的修复。

Likely an incorrect or invalid review comment.

src/packages/countdown/demo.taro.tsx (1)

15-15: LGTM!

Demo10 组件导入和 ARIA 国际化配置实现正确,遵循了项目的标准 demo 集成模式。

Also applies to: 29-29, 41-41, 53-53, 83-84

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

41-41: LGTM!

alt 属性的提取和转发实现正确,当未指定 effect 时,该属性会正确传递给 defaultEffect 用于设置 ARIA 标签。

Also applies to: 256-263

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

45-45: LGTM!

ariaLabel 属性的实现符合无障碍规范,正确应用于 img 元素的 aria-label 属性。

Also applies to: 198-198

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

45-45: LGTM!

BaseDialog 接口添加 role 属性的类型定义,与无障碍功能增强保持一致。

src/packages/tabbar/demos/taro/demo10.tsx (1)

5-38: LGTM!

Demo 正确演示了 ARIA 属性的使用方式,为每个 Tabbar.Item 提供了 ariaLabelariaRoledescription 属性,有助于改善屏幕阅读器的用户体验。

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

221-221: LGTM!

为 Dialog 组件添加的 ARIA 属性实现正确:

  • role="dialog" 正确标识了对话框角色
  • aria-modal={visible} 在对话框可见时正确设置模态状态

这些改动提升了对话框组件的无障碍性。

Also applies to: 230-230

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

1-10: LGTM!

导入和组件初始化代码正确,使用 useRef 存储 endTime 是合适的做法。


11-38: 演示代码清晰有效

三个 CountDown 实例展示了不同的 type 属性,同时统一使用了 ariaRoledescription 属性,有效演示了无障碍功能的使用。

src/packages/image/demos/h5/demo9.tsx (2)

16-23: LGTM!

正确使用了 alt 和 ariaLabel 属性,alt 描述图片内容,ariaLabel 提供可访问的名称,这是符合无障碍最佳实践的。


24-40: 错误处理演示清晰

使用无效 URL 触发错误状态是演示错误处理功能的常见做法,同时展示了默认和自定义错误内容两种场景。

src/packages/tabbar/demo.taro.tsx (1)

15-15: Demo10 集成正确

Demo10 的导入和渲染遵循了现有的演示模式,集成方式正确。

Also applies to: 78-79

src/packages/dialog/content.taro.tsx (1)

31-32: ARIA 属性集成正确

ariaRole 和 ariaModal 属性的添加和使用符合 Taro 的无障碍实现模式,将 ariaModal 绑定到 visible 状态也是合理的。

Also applies to: 64-65

src/packages/countdown/demos/h5/demo10.tsx (1)

11-38: 演示结构实现正确

三个 CountDown 实例正确展示了不同 type 属性下的 ariaRoledescription 使用,演示结构清晰。

src/packages/tabbar/demos/h5/demo10.tsx (1)

7-37: ARIA 属性使用规范

每个 Tabbar.Item 都正确配置了 ariaLabel 和 ariaRoledescription 属性,ariaLabel 与 title 保持一致,ariaRoledescription 统一描述了操作类型,符合无障碍最佳实践。动态图标的使用也展示了更丰富的交互场景。

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

20-26: rightIconAriaLabel 使用正确

为右侧图标添加 rightIconAriaLabel="more" 提供了可访问的标签,这对于屏幕阅读器用户理解图标功能很重要。


28-39: 自定义右侧内容演示清晰

使用 right 插槽放置自定义 Button 组件展示了 NoticeBar 的灵活性,虽然这个示例不直接涉及无障碍功能,但与其他演示一起提供了完整的使用场景。

src/packages/dialog/content.tsx (1)

57-64: ARIA 属性实现正确

role 和 aria-modal 属性的实现符合无障碍规范。role 属性被正确传递,aria-modal 接收布尔值以反映对话框的模态状态。

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

543-551: 验证 rightIconAriaLabel 为空的情况

closeable 为 false 且用户未提供 rightIconAriaLabel 时,aria-label 将是空字符串,这对屏幕阅读器用户没有帮助。虽然通常在有 rightIcon 时应该提供有意义的 rightIconAriaLabel,但建议在文档中明确说明这一要求,或者在代码中添加条件判断,仅在有有效内容时才设置 aria-label。

建议验证以下场景:

  1. 当使用 rightIcon 但未提供 rightIconAriaLabel 时的行为
  2. 文档是否明确要求提供 rightIconAriaLabel

可以考虑改进实现:

ariaLabel={closeable ? 'close' : (rightIconAriaLabel || undefined)}

这样当 rightIconAriaLabel 为空时,不会设置 aria-label 属性。

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

481-487: 验证 rightIconAriaLabel 为空的情况

与 Taro 版本类似,当 closeable 为 false 且 rightIconAriaLabel 为空时,aria-label 将是空字符串。建议确保文档中明确要求在使用自定义 rightIcon 时必须提供有意义的 rightIconAriaLabel

可选改进(与 Taro 版本保持一致):

           <div
             className="nut-noticebar-box-right-icon"
             onClick={onClickIcon}
-            aria-label={`${closeable ? 'close' : rightIconAriaLabel}`}
+            aria-label={closeable ? 'close' : (rightIconAriaLabel || undefined)}
           >
src/packages/dialog/dialog.taro.tsx (1)

234-259: ARIA 实现正确且完善

Dialog 组件的无障碍实现非常完善:

  • 正确传递 role 属性到 Content 组件
  • ariaModal 属性正确反映对话框的模态状态
  • 为 Overlay 添加了有意义的 ariaRoledescription="背景蒙层",帮助屏幕阅读器用户理解背景遮罩的用途
src/packages/navbar/demos/h5/demo4.tsx (1)

1-95: 优秀的无障碍示例

这个 Demo 很好地展示了 NavBar 的无障碍用法:

  • 所有交互元素都添加了有意义的 aria-label
  • 标签描述清晰准确
  • 为开发者提供了良好的参考示例
src/packages/countdown/countdown.taro.tsx (1)

341-348: ARIA alert 实现正确

倒计时结束时的 ARIA alert 实现遵循了无障碍最佳实践:

  • 使用 role="alert" 动态通知屏幕阅读器
  • 提供有意义的提示内容 "时间到"
  • 通过隐藏的元素实现,不影响视觉布局

注意:已在上方评论中指出定时器清理的问题。

className={buttonClassNames}
style={{ ...getStyle, ...style }}
onClick={(e) => handleClick(e as any)}
ariaLabel="button"
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

硬编码的 ariaLabel 值缺乏实用性。

ariaLabel 硬编码为 "button" 不会为屏幕阅读器用户提供有意义的信息。应该:

  1. 通过 props 使其可配置
  2. 描述按钮的具体用途而非仅说明它是按钮
  3. 设为可选属性,因为按钮内容通常已提供足够的上下文

建议应用以下修改:

ButtonProps 接口中添加可选的 ariaLabel 属性:

 export interface ButtonProps
   extends BasicComponent,
     OmitMiniProgramButtonProps {
   color: string
   shape: ButtonShape
   type: ButtonType
   size: ButtonSize
   fill: ButtonFill
   block: boolean
   loading: boolean
   disabled: boolean
   icon: React.ReactNode
   rightIcon: React.ReactNode
   nativeType: 'submit' | 'reset' // | 'button'
   onClick: (e: MouseEvent<HTMLButtonElement>) => void
+  ariaLabel?: string
 }

然后在组件中使用:

 const {
   color,
   shape,
   fill,
   loading,
   disabled,
   type,
   size,
   block,
   icon,
   rightIcon,
   children,
   className,
   style,
   formType,
   nativeType,
   onClick,
+  ariaLabel,
   ...rest
 } = { ...defaultProps, ...props }

在渲染时有条件地应用:

 <TaroButton
   {...rest}
   ref={ref}
   formType={formType || nativeType}
   className={buttonClassNames}
   style={{ ...getStyle, ...style }}
   onClick={(e) => handleClick(e as any)}
-  ariaLabel="button"
+  {...(ariaLabel && { ariaLabel })}
 >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/button/button.taro.tsx around line 162, the ariaLabel is
hardcoded to "button"; update ButtonProps to include an optional ariaLabel?:
string, accept it in the component props, and replace the hardcoded ariaLabel
with the passed-in prop so the rendered element conditionally sets the
aria-label attribute only when ariaLabel is provided (or uses a meaningful
fallback like the button text if you choose), ensuring the value describes the
button's purpose rather than the generic word "button".

Comment on lines 211 to 213
role="checkbox"
tabIndex={0}
aria-checked={innerChecked && !innerIndeterminate}
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

aria-checked 对不确定状态的处理不正确。

当前的 aria-checked={innerChecked && !innerIndeterminate} 实现存在严重问题:

  1. 不确定状态处理错误:当复选框处于不确定状态(indeterminate=true)时,aria-checked 应该是 "mixed",而不是 false
  2. 类型不正确aria-checked 应该接受 "true" | "false" | "mixed",而非布尔运算结果
  3. tabIndex 未考虑禁用状态:禁用的复选框不应该可聚焦

应用以下修改:

 <div
   className={classNames(
     classPrefix,
     {
       [`${classPrefix}-reverse`]: labelPosition === 'left',
       'nut-checkbox-list-item': ctx?.list,
     },
     className
   )}
   {...rest}
   onClick={handleClick}
   role="checkbox"
-  tabIndex={0}
-  aria-checked={innerChecked && !innerIndeterminate}
+  tabIndex={innerDisabled ? -1 : 0}
+  aria-checked={innerIndeterminate ? 'mixed' : innerChecked}
 >
   {renderCheckboxItem()}
 </div>

此外,建议添加键盘事件处理器以支持空格键切换复选框:

+const handleKeyDown = (e: React.KeyboardEvent) => {
+  if (e.key === ' ' || e.key === 'Enter') {
+    e.preventDefault()
+    handleClick()
+  }
+}
+
 <div
   className={classNames(
     classPrefix,
     {
       [`${classPrefix}-reverse`]: labelPosition === 'left',
       'nut-checkbox-list-item': ctx?.list,
     },
     className
   )}
   {...rest}
   onClick={handleClick}
+  onKeyDown={handleKeyDown}
   role="checkbox"
   tabIndex={innerDisabled ? -1 : 0}
   aria-checked={innerIndeterminate ? 'mixed' : innerChecked}
 >

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/checkbox/checkbox.tsx around lines 211-213, aria-checked and
tabIndex are incorrect: change aria-checked to return the string union "true" |
"false" | "mixed" (e.g. innerIndeterminate ? "mixed" : innerChecked ? "true" :
"false") instead of a boolean expression, make tabIndex non-focusable when
disabled (e.g. tabIndex={disabled ? -1 : 0}), and add a onKeyDown handler that
listens for the Space key, prevents default, and toggles the checkbox
(respecting disabled state) so keyboard users can toggle via space.

Comment on lines 110 to 115
setRole('alert')
setAlertContent('时间到')
setTimeout(() => {
setRole('')
setAlertContent('')
}, 3000)
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

修复潜在的内存泄漏

setTimeout 设置的定时器在组件卸载时未被清除,可能导致内存泄漏。当倒计时结束后,如果组件在 3 秒内被卸载,定时器仍会尝试调用 setRolesetAlertContent,可能导致 React 警告或内存泄漏。

基于学习经验(Based on learnings)

建议将定时器 ID 存储在 ref 中并在组件卸载时清除:

+  const alertTimerRef = useRef<number>()
+
   // ... 在 tick 函数中
         if (!remainTime) {
           stateRef.current.counting = false
           pause()
           onEnd && onEnd()
           setRole('alert')
           setAlertContent('时间到')
-          setTimeout(() => {
+          alertTimerRef.current = window.setTimeout(() => {
             setRole('')
             setAlertContent('')
           }, 3000)
         }

并在 componentWillUnmount 中清除:

   const componentWillUnmount = () => {
     destroy && cancelAnimationFrame(stateRef.current.timer)
+    if (alertTimerRef.current) {
+      clearTimeout(alertTimerRef.current)
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/packages/countdown/countdown.taro.tsx around lines 110 to 115, the
setTimeout used to clear role/alertContent is not tracked or cleared on unmount
which can cause state updates after unmount; store the timeout ID in a ref (e.g.
timeoutRef), assign the ID when calling setTimeout, clear any existing timeout
before creating a new one, and clear the timeout in useEffect
cleanup/componentWillUnmount to prevent the callback running after the component
is unmounted.

error: '加载失败',
lazyload: '图片懒加载',
imageText: 'Image + text 模式',
ATRIAUsage: '无障碍使用示例',
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

修正拼写错误:ATRIA → ARIA

翻译键名和英文翻译值中的 "ATRIA" 是拼写错误,应该是 "ARIA"(Accessible Rich Internet Applications,无障碍富互联网应用)。

应用此差异修复拼写错误:

-      ATRIAUsage: '无障碍使用示例',
+      ARIAUsage: '无障碍使用示例',
-      ATRIAUsage: 'ATRIA Usage',
+      ARIAUsage: 'ARIA Usage',

同时需要更新 Line 70 的引用:

-        <View className="h2">{translated.ATRIAUsage}</View>
+        <View className="h2">{translated.ARIAUsage}</View>

Also applies to: 39-39

🤖 Prompt for AI Agents
In src/packages/image/demo.taro.tsx around lines 28 and 39 (and update the usage
at line 70), fix the misspelling "ATRIA" to "ARIA": rename the translation
key(s) (e.g., ATRIAUsage → ARIAUsage), update any English/Chinese translation
values that contain "ATRIA" to "ARIA", and change the reference at line 70 to
use the new ARIAUsage key; ensure consistency across the file so all occurrences
of "ATRIA" are replaced with "ARIA".

activeIcon: ReactNode
value: SimpleValue
onChange: (checked: boolean) => void
type: string
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

属性名称 "type" 过于泛化且可能引起混淆。

在 BaseRadio 接口中添加 type: string 存在以下问题:

  1. 属性名称过于通用,不清楚其用途
  2. 可能与 HTML 原生的 type 属性产生命名冲突
  3. 如果用于无障碍功能,应使用更具描述性的名称(如 ariaTyperole
  4. 应设为可选属性而非必需

请说明此属性的具体用途,并考虑使用更具描述性的名称。

🤖 Prompt for AI Agents
In src/types/spec/radio/base.ts around line 24, the BaseRadio interface defines
a generic required property "type: string" which is ambiguous and could clash
with HTML attributes; clarify its purpose and either rename it to a descriptive
name (e.g., "variant", "role", or "ariaType") or make it optional if it conveys
non-essential metadata. Update the interface to use the new name or optional
modifier, adjust all imports/usages and tests to the new property, and add a
short JSDoc comment explaining the property's semantics and expected values to
avoid future confusion.

disabled?: boolean
options: RadioGroupOption[]
onChange: (value: SimpleValue) => void
type: string
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

属性名称 "type" 过于泛化且可能引起混淆。

在 BaseRadioGroup 接口中添加 type: string 存在与 BaseRadio 相同的问题。建议:

  1. 使用更具描述性的属性名称
  2. 将其设为可选属性
  3. 在文档中明确说明其用途
🤖 Prompt for AI Agents
In src/types/spec/radio/base.ts around line 36, the property named "type:
string" is too generic and may conflict with BaseRadio; rename it to a more
descriptive identifier (for example radioType or variant), make the property
optional (radioType?: string) and update any usages/imports accordingly, and add
a short JSDoc comment above the property explaining its purpose and expected
values; ensure type references, interfaces and any serializers/deserializers are
updated to use the new optional name to avoid breaking changes.

autoplay: boolean
loop: boolean
defaultValue: number
ariaLabel: string
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

ariaLabel 应设为可选属性。

ariaLabel 定义为必需属性会强制所有 Swiper 实例都必须提供 aria 标签。建议设为可选,因为:

  1. 组件可以提供合理的默认标签
  2. 并非所有使用场景都需要自定义标签
  3. 减少开发者的使用负担

应用以下修改:

 export type TaroSwiperProps = Omit<BaseSwiper, OmittedKeys> &
   OmittedSwiperProps &
   BaseProps & {
     width?: SimpleValue
     height?: SimpleValue
     direction: Direction
     indicator: ReactNode
     /**
      * @deprecated Please use `autoplay` prop instead.
      */
     autoPlay: boolean
     autoplay: boolean
     loop: boolean
     defaultValue: number
-    ariaLabel: string
+    ariaLabel?: 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.

Suggested change
ariaLabel: string
export type TaroSwiperProps = Omit<BaseSwiper, OmittedKeys> &
OmittedSwiperProps &
BaseProps & {
width?: SimpleValue
height?: SimpleValue
direction: Direction
indicator: ReactNode
/**
* @deprecated Please use `autoplay` prop instead.
*/
autoPlay: boolean
autoplay: boolean
loop: boolean
defaultValue: number
ariaLabel?: string
}
🤖 Prompt for AI Agents
In src/types/spec/swiper/taro.ts around line 22, the ariaLabel property is
currently defined as a required string which forces all Swiper instances to
supply an ARIA label; change the type to make ariaLabel optional (e.g., use
optional property syntax) so the component can rely on a default or omit it when
not needed, and update any related type usages or overrides that assume it is
always present to handle undefined.

export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
itemId?: string
skipHiddenItemLayout?: boolean
ariaLabel: string
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

ariaLabel 应设为可选属性。

与 TaroSwiperProps 相同,TaroSwiperItemProps 的 ariaLabel 也应设为可选属性。

应用以下修改:

 export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
   itemId?: string
   skipHiddenItemLayout?: boolean
-  ariaLabel: string
+  ariaLabel?: 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.

Suggested change
ariaLabel: string
export interface TaroSwiperItemProps extends Omit<BaseSwiperItem, 'onClick'> {
itemId?: string
skipHiddenItemLayout?: boolean
ariaLabel?: string
}
🤖 Prompt for AI Agents
In src/types/spec/swiper/taro.ts around line 28, the property ariaLabel is
currently required; make it optional to match TaroSwiperProps by changing its
declaration to an optional property (ariaLabel?: string) so TaroSwiperItemProps
aligns with the other prop definitions.

Comment on lines 25 to 27
ariaLabel: string
ariaSelected: boolean
ariaRoledescription: string
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

建议将 ARIA 属性设为可选

这些 ARIA 属性被定义为必需属性,这会导致所有现有的 TabbarItem 使用处都需要提供这些值,可能造成破坏性变更。建议将它们设为可选属性以保持向后兼容。

应用此差异将属性改为可选:

-  ariaLabel: string
-  ariaSelected: boolean
-  ariaRoledescription: string
+  ariaLabel?: string
+  ariaSelected?: boolean
+  ariaRoledescription?: 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.

Suggested change
ariaLabel: string
ariaSelected: boolean
ariaRoledescription: string
ariaLabel?: string
ariaSelected?: boolean
ariaRoledescription?: string
🤖 Prompt for AI Agents
In src/types/spec/tabbar/base.ts around lines 25 to 27, the ARIA properties
ariaLabel, ariaSelected and ariaRoledescription are currently required; change
their type declarations to optional (e.g., add ? after each property name) so
existing TabbarItem usages aren’t broken, update any related exported
interfaces/types if necessary, and run type checks to ensure no downstream type
errors remain.

@yangyanAurora yangyanAurora marked this pull request as draft November 10, 2025 07:38
yangyanAurora and others added 4 commits November 10, 2025 18:35
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@yangyanAurora yangyanAurora changed the title feat: 添加部分组件无障碍功能支持 feat: 添加组件无障碍功能支持 Nov 10, 2025
yangyanAurora and others added 8 commits November 10, 2025 20:56
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant