Skip to content

CommentThread 的 "+" 表情选择器:title 永远不会成为它的可访问名(内容 "+" 优先),#3424 只命名了 tooltip #3478

Description

@yinlianghui

发现于 #3441 的实现过程,不在该 issue 的范围内(#3441 的正文把这颗按钮明确当作"已有名字"的参照物,用来证明另外三颗是遗漏),因此单独提。

现象

packages/collaboration/src/CommentThread.tsx 里每条评论回应条右侧的表情选择器按钮:

onReaction && React.createElement('button', {
  style: styles.reactionPicker,
  onClick: () => onReaction(comment.id, '👍'),
  title: t('collaboration.addThumbsUp'),
}, '+'),

#3424 / #3438(objectstack#5506)给它接上了 collaboration.addThumbsUp,走的是 title。但对 button 来说,accname 算法先看内容(§2F "name from content"),title 是最后一档兜底(§2I)。这颗按钮有内容 '+',所以计算出来的可访问名就是 "+",title 从头到尾只是鼠标 tooltip,从来没有成为过它的名字。

屏幕阅读器读到的是"加号 按钮"/"plus button" —— 用户无从知道它做什么。title 被翻译了,可访问名没有。

证据(实测,非推演)

#3441 的 PR 里有一条现在就是绿的断言,直接钉住了这一点:

expect(screen.getByTitle('Add thumbs up')).toBeTruthy();
expect(screen.queryAllByRole('button', { name: 'Add thumbs up' })).toHaveLength(0);

getByRole(… { name }) 走的是 dom-accessibility-api 的 accname 实现。title 属性在(第一行绿),但没有任何按钮的可访问名Add thumbs up(第二行绿)。这两行同时成立,就是本 issue 的全部内容。

那条断言在 #3441 里的用途是区分 addThumbsUp(选择器)与新增的 reactThumbsUp(快捷 👍),顺手暴露了这个副作用;#3441 修的三颗按钮用的是 aria-label,正因为 aria-label 是唯一能盖过内容的那一档。

建议修法

title 换成(或补上)aria-label,复用同一个 key,不新增翻译:

title: t('collaboration.addThumbsUp'),
'aria-label': t('collaboration.addThumbsUp'),

两个都留着最稳:aria-label 给辅助技术,title 保留鼠标悬停提示(视觉用户目前唯一的线索),且仓内已有若干用例按 getByTitle('Add thumbs up') 定位它,不会被打断。

顺带需要判断的一个语义问题(留给处理人,不预设):这颗按钮的样式名叫 reactionPicker,但当前实现写死 onReaction(id, '👍') —— 它是个"选择器"的桩。名字到底该是 "Add thumbs up"(描述当前行为)还是 "Add reaction"(描述控件意图),取决于这个桩是否要继续做成真的选择器。当前的 addThumbsUp 描述行为是准确的,不改也自洽。

不属于本条的相邻情况

同一行的回应 chip 按钮(内容 👍 2,title 是 "2 reactions")同样是内容优先,但它的可访问名 "👍 2" 本身就是描述性的,读作"thumbs up 2 按钮",可用。不建议一并改动。

影响面

CommentThread 是 published exported component,仓内无消费方 —— 只有外部宿主会碰到,和 #3441 同一族。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions