Skip to content

feat: improve a11y #888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 25, 2024
Merged

Conversation

aojunhao123
Copy link
Contributor

@aojunhao123 aojunhao123 commented Nov 17, 2024

image
image

  • input只是单纯用于键盘导航的,screen reader不用读取它的信息
  • aria-grabbed在最新的ARIA 规范中也已经被废弃了
  • 对于上面那个issue,我理解当treeCheckable={true}时,只需要让screen reader能够读取到CheckBox即可
  • 为树节点添加了对应的role="treeitem"

Summary by CodeRabbit

  • 新功能
    • 改进了 NodeListTreeNode 组件的可访问性,增强了对辅助技术的支持。
    • 更新了 NodeList 组件的运动效果处理逻辑,确保状态更新正确。
    • Tree 组件中添加了 role="tree" 属性,进一步提升了可访问性。
  • 文档
    • 更新了 .gitignore 文件,添加了对 .vscode 目录的忽略。

Copy link

vercel bot commented Nov 17, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
tree ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 25, 2024 3:19am

Copy link

coderabbitai bot commented Nov 17, 2024

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • tests/__snapshots__/Tree.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeProps.spec.tsx.snap is excluded by !**/*.snap

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

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

Walkthrough

此次更改包括对.gitignore文件的更新,新增了对.vscode目录的忽略条目。此外,src/NodeList.tsxsrc/TreeNode.tsxsrc/Tree.tsx文件中的组件进行了多项修改,主要集中在增强可访问性和改进事件处理上。NodeList组件的VirtualList添加了role="tree"属性,更新了状态管理逻辑。TreeNode组件则更新了复选框的角色和ARIA属性,以改善对辅助技术的支持,Tree组件也添加了role="tree"以增强可访问性。

Changes

文件路径 更改摘要
.gitignore 新增对.vscode目录的忽略条目。
src/NodeList.tsx 更新VirtualList添加role="tree",调整状态管理逻辑以改善运动效果处理。
src/TreeNode.tsx 更新renderCheckboxrender方法,添加ARIA属性以增强可访问性,移除aria-grabbed属性。
src/Tree.tsx 添加role="tree"到主容器div,增强可访问性。

Assessment against linked issues

Objective Addressed Explanation
提升TreeSelect组件在使用treeCheckable={true}属性时的可访问性 (#51517)

兔子欢快跳跃,代码更清晰,
.vscode被忽略,环境更整齐。
节点可访问性提升,屏幕读者乐,
复选框角色明确,助力无障碍。
代码如春风,轻松又愉快,
兔子欢呼声中,变化真精彩! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@aojunhao123
Copy link
Contributor Author

@afc163 大佬有空的时候帮忙看一下

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

🧹 Outside diff range and nitpick comments (2)
src/NodeList.tsx (1)

Line range hint 1-385: 建议进一步增强组件的无障碍性能

为了更好地支持辅助技术,建议考虑以下改进:

  1. 动画过渡的无障碍性:

    • 考虑添加 aria-busy 属性在动画过程中
    • 确保动画不会影响屏幕阅读器的导航
  2. 树形结构的语义化:

    • 为整个树添加 role="tree" 属性
    • 确保每个节点都有正确的 aria-levelaria-setsize 属性
  3. 文档完善:

    • 添加无障碍性相关的使用说明
    • 说明键盘导航的方式

建议添加以下属性到 VirtualList 组件:

 <VirtualList<FlattenNode>
   {...domProps}
   data={mergedData}
   itemKey={itemKey}
   height={height}
   fullHeight={false}
   virtual={virtual}
   itemHeight={itemHeight}
   prefixCls={`${prefixCls}-list`}
+  role="tree"
+  aria-label="树形选择器"
   ref={listRef}
src/TreeNode.tsx (1)

377-379: 复选框无障碍功能改进符合规范

复选框的ARIA属性实现符合标准,但建议考虑以下增强:

  • 添加aria-labelaria-labelledby以提供更明确的标签
  • 考虑添加键盘事件处理(Space键)以增强可访问性
 <span
   className={classNames(
     `${prefixCls}-checkbox`,
     checked && `${prefixCls}-checkbox-checked`,
     !checked && halfChecked && `${prefixCls}-checkbox-indeterminate`,
     (disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`,
   )}
   onClick={this.onCheck}
   role="checkbox"
   aria-checked={halfChecked ? 'mixed' : checked}
   aria-disabled={disabled || disableCheckbox}
+  aria-label={`${title || ''} 复选框`}
+  onKeyDown={this.onCheckboxKeyDown}
+  tabIndex={disabled ? -1 : 0}
 >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5da03 and 1abb752.

⛔ Files ignored due to path filters (3)
  • tests/__snapshots__/Tree.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeNodeProps.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeProps.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • .gitignore (1 hunks)
  • src/NodeList.tsx (2 hunks)
  • src/TreeNode.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🔇 Additional comments (2)
src/NodeList.tsx (1)

Line range hint 287-296: 无障碍性改进符合预期!

对输入框的改动很好地提升了无障碍性:

  • 添加 aria-hidden 到包装 div 可以防止屏幕阅读器读取这个区域
  • 添加 role="presentation" 明确表示这个输入框仅用于键盘导航
  • 移除了 aria-label 避免了冗余的朗读

这些改动与 PR 的目标完全一致,可以改善使用屏幕阅读器时的体验。

src/TreeNode.tsx (1)

377-379: 验证无障碍改进的实际效果

为确保这些改动能够解决 #51517 中提到的问题,建议进行以下验证:

  1. 使用 VoiceOver 和 NVDA 测试树节点的可访问性
  2. 验证复选框状态是否正确朗读
  3. 确认键盘导航是否正常工作

Also applies to: 551-551

✅ Verification successful

无障碍改进已正确实现且经过充分测试

代码分析显示:

  • 树组件已正确实现 ARIA 角色(role="tree"、role="treeitem")
  • 复选框状态通过 aria-checked 属性正确传递给屏幕阅读器
  • 测试用例覆盖了无障碍相关功能,包括:
    • 复选框状态的切换
    • 键盘导航
    • 禁用状态的处理
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否有其他需要类似无障碍改进的组件

# 搜索其他可能需要添加 role="treeitem" 的组件
rg -l "className.*treenode" --type tsx

# 搜索其他可能需要添加 ARIA 属性的复选框实现
ast-grep --pattern 'className={classNames($$$, "checkbox"$$$)}'

Length of output: 134


Script:

#!/bin/bash
# 搜索包含 treenode 相关类名的文件
rg -l "treenode" --type ts --type tsx --type jsx

# 搜索包含 checkbox 相关实现的文件
rg -l "checkbox" --type ts --type tsx --type jsx

# 查找其他使用 aria-checked 属性的组件
rg "aria-checked" --type ts --type tsx --type jsx -A 2 -B 2

# 检查相关的无障碍测试文件
fd -e test.tsx -e test.ts -e spec.tsx -e spec.ts | xargs rg "accessibility|aria|screen reader"

Length of output: 1356


Script:

#!/bin/bash
# 使用通用文件搜索,不指定文件类型
rg -l "treenode"

# 搜索树组件中的无障碍相关实现
rg "role=\"(treeitem|tree|group)\"" -A 2 -B 2

# 查找复选框状态相关的测试用例
rg "checkbox.*checked|checked.*checkbox" tests/

# 检查键盘导航相关的测试
rg "keyboard|keydown|keyup" tests/

Length of output: 54452

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

🧹 Outside diff range and nitpick comments (1)
src/TreeNode.tsx (1)

539-541: 建议优化节点位置计算的性能

当前使用 findIndex 计算位置可能在大型树结构中造成性能问题。建议考虑以下优化方案:

-const posInSet = siblings.findIndex(node => node.key === eventKey);
+const posInSet = siblings.findIndex(node => node.key === eventKey) + 1;

考虑在父节点中缓存子节点的位置信息,避免重复计算。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1abb752 and edcc573.

⛔ Files ignored due to path filters (3)
  • tests/__snapshots__/Tree.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeNodeProps.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeProps.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • src/TreeNode.tsx (3 hunks)
🔇 Additional comments (2)
src/TreeNode.tsx (2)

377-379: 复选框无障碍属性设置正确!

复选框的ARIA属性设置完整且准确:

  • role="checkbox" 明确了元素的语义
  • aria-checked 正确处理了半选状态
  • aria-disabled 适当反映了禁用状态

553-557: 树节点无障碍属性设置完善!

树节点的ARIA属性设置符合WAI-ARIA规范,建议验证在以下场景下的行为:

  • 使用VoiceOver和NVDA测试节点层级朗读
  • 验证展开/折叠状态的朗读
  • 检查节点位置信息的准确性
✅ Verification successful

Let me run one more verification to check the implementation of aria-posinset and aria-setsize:


树节点的ARIA属性实现正确且完整!

代码分析显示:

  • 所有树节点都包含必要的ARIA属性(role、aria-level、aria-expanded、aria-setsize、aria-posinset)
  • 层级(aria-level)计算正确,测试快照显示从0到2级的正确嵌套
  • 位置信息计算逻辑合理:
    • aria-setsize使用siblings.length计算同级节点数
    • aria-posinset通过findIndex正确计算当前节点位置

无障碍实现符合WAI-ARIA规范要求,无需进一步修改。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否所有树节点都正确设置了必要的ARIA属性

# 搜索所有可能缺少必要ARIA属性的树节点
rg -l 'role="treeitem"' | xargs rg -L 'aria-level' || echo "所有树节点都包含必要的ARIA属性"

# 检查是否存在可能的ARIA属性值计算错误
ast-grep --pattern 'aria-posinset={$_}'

Length of output: 7339


Script:

#!/bin/bash
# 检查树节点的位置信息计算
rg -A 5 'aria-posinset' src/
rg -A 5 'aria-setsize' src/

# 检查相关的计算逻辑
ast-grep --pattern 'const posInSet = $_'
ast-grep --pattern 'const siblings = $_'

Length of output: 1229

Copy link

codecov bot commented Nov 17, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.84%. Comparing base (9b5da03) to head (ab06684).
Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #888   +/-   ##
=======================================
  Coverage   99.84%   99.84%           
=======================================
  Files          14       14           
  Lines        1317     1321    +4     
  Branches      380      384    +4     
=======================================
+ Hits         1315     1319    +4     
  Misses          2        2           

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


🚨 Try these New Features:

@aojunhao123
Copy link
Contributor Author

@afc163 @zombieJ

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

🧹 Outside diff range and nitpick comments (2)
src/TreeNode.tsx (2)

377-379: 复选框无障碍属性实现正确!

复选框的ARIA属性实现符合规范,正确处理了混合状态(mixed)和禁用状态。

建议添加aria-label属性来提供更好的语义描述:

 <span
   className={classNames(
     `${prefixCls}-checkbox`,
     checked && `${prefixCls}-checkbox-checked`,
     !checked && halfChecked && `${prefixCls}-checkbox-indeterminate`,
     (disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`,
   )}
   onClick={this.onCheck}
   role="checkbox"
   aria-checked={halfChecked ? 'mixed' : checked}
   aria-disabled={disabled || disableCheckbox}
+  aria-label={`选择${title || ''}`}
 >

551-552: 树节点基础无障碍属性已添加,建议补充更多ARIA属性!

已添加的role="treeitem"aria-expanded是个好的开始,但建议继续完善以下ARIA属性以提供更完整的无障碍体验:

建议添加以下属性:

 <div
   ref={domRef}
   role="treeitem"
   aria-expanded={isLeaf ? undefined : expanded}
+  aria-level={level}
+  aria-setsize={isEnd.length}
+  aria-posinset={isEnd.length - (isEndNode ? 0 : 1)}
+  aria-selected={selected}
   className={classNames(className, `${prefixCls}-treenode`, {

属性说明:

  • aria-level: 表示节点的层级深度
  • aria-setsize: 表示同级节点的总数
  • aria-posinset: 表示在同级节点中的位置
  • aria-selected: 表示节点的选中状态
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ccaf035 and 91df852.

⛔ Files ignored due to path filters (3)
  • tests/__snapshots__/Tree.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeNodeProps.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeProps.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • src/TreeNode.tsx (2 hunks)

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 91df852 and 86404b0.

⛔ Files ignored due to path filters (3)
  • tests/__snapshots__/Tree.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeNodeProps.spec.tsx.snap is excluded by !**/*.snap
  • tests/__snapshots__/TreeProps.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • src/NodeList.tsx (1 hunks)
  • src/Tree.tsx (0 hunks)
  • src/TreeNode.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • src/Tree.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/NodeList.tsx
🔇 Additional comments (1)
src/TreeNode.tsx (1)

377-379: 复选框无障碍属性设置正确!

复选框的无障碍属性设置完整且准确:

  • 使用role="checkbox"明确表示这是一个复选框
  • 使用aria-checked正确处理了半选状态
  • 使用aria-disabled正确传达了禁用状态

@zombieJ zombieJ merged commit 37cb671 into react-component:master Nov 25, 2024
9 checks passed
@aojunhao123 aojunhao123 deleted the a11y-checkbox branch November 28, 2024 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TreeSelect with treeCheckable={true} prop is not recognizable by screen readers.
2 participants