fix(plugin-detail): quick_actions 读 aria 契约拼写,并撤下不存在的 actionNames 回退承诺 (#4663) - #5133
Merged
Merged
Conversation
#4663) 同一组件的两处生产侧缺陷,objectstack#8744 测量该 renderer 读点时发现。 一、aria 读点双向落空。工具条只读 `schema.aria?.label` —— 恰是 `@objectstack/spec` 的 `AriaPropsSchema` 唯一拒绝的拼写:在那个封闭形上 `label` 是 alias 条目(指向 `ariaLabel` 的改名指示),存在意义是给出更好的 拒绝消息,从不被接受(实测:`safeParse({ label })` 返回 unrecognized_keys 并点名 `label`,`safeParse({ ariaLabel })` 通过)。于是 spec-valid 的 `aria: { ariaLabel: … }` 到达 renderer 后无人读取,内建 "Quick actions" 每次都赢;而 renderer 认的拼写,作者一写文档就被契约拒收。 `SchemaRenderer` 的通用 ARIA 通道也不是出口:它读扁平 `schema.ariaLabel` 并以组件 prop 注入 `aria-label`,而本 renderer 的 `splitDesigner` 连同其他 非 designer prop 一并丢弃。 读点改为 `(aria.ariaLabel ?? aria.label) || 'Quick actions'`:legacy 一腿 仅为契约封闭前的存量文档保留,两者同现时 canonical 赢。两半都照本仓既有的 同键惯例 —— `normalizeListViewSchema` 的 aria fold 仅在 canonical 为 `undefined` 时才搬运 legacy 键(故 `ariaLabel: ''` 遮蔽陈旧的 `label`), 而 `ListView` 自身读点把空串视为「没有可访问名」;因 `role="toolbar"` 必须 有名字,此处「没有名字」落到内建兜底,而非 ListView 的省略属性。 二、`actionNames` 注册描述承诺了不存在的回退(「else every action declared for the object at this location」)。实测:无 `actionNames` 且宿主不传 `actions` 时 `namesToResolve` 为空、`needsLookup` 为 false、对象元数据从不 被查询、渲染虚线占位符。注册 `inputs` 是发布面(序列化进 `sdui.manifest.json` 与 JSX 授权类型,Studio 据此教作者),该承诺已流入工具 链 —— objectstack#8744 的派发提示逐字引用了它。按分诊口径改句子:实现该回退 属能力扩张,另立卡。回归测试驱动一个「有货」的元数据 provider,证明对象上已 声明的 action 确实不会被拉进来(并附控制用例证明同一套接线在有名字时照常 交付)。 Fixes #4663 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
PM 验收:ACCEPT(session_01GTRjn8xBqp75dk7kFupVRt,objectui 分片,批次 23) 实物核验:merge-base 验收要点:
三件套照常:本评论 → undraft → auto-merge(SQUASH)。 Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4663
同一组件的两处生产侧缺陷,按 PM 两点代裁执行。基线
958d7573ac2ae610f9f9db9c7f52cf13f28b9ac3。前提验证(实测,非复述)
卡面三条判断逐条复测,全部成立:
record-quick-actions.tsx工具条读schema.aria?.label || 'Quick actions';AriaPropsSchema是strictObject,label是其 alias 条目。实测safeParse({ ariaLabel })通过,safeParse({ label })返回unrecognized_keys并点名label(消息为 “Did you meanlabel→ariaLabel?”)—— alias 是拒绝消息设施,不是接受面。渲染侧双向实测:spec-valid 拼写到达 renderer 后零读取(落到内建兜底),renderer 认的拼写恰是 spec 拒的。SchemaRenderer的resolveAriaProps读扁平schema.ariaLabel并以组件 prop 注入aria-label;本 renderer 的splitDesigner只保留data-obj-id/data-obj-type/style,rest从不使用。且normalizeListViewSchema的 aria fold 只在 list-view 路径上运行,不经过本组件 —— 嵌套袋读点是唯一活路径。actionNames且宿主不传actions时,namesToResolve空 ⇒needsLookupfalse ⇒ 元数据从不被查询 ⇒actions=[]⇒ 虚线占位符。新增回归测试用一个有货的元数据 provider 驱动(对象上声明了record_header位置的 action),断言getItem从未被调用、该 action 不出现;控制用例证明同一套接线在给出名字时照常交付。代裁一:aria 读点
canonical 优先,legacy 仅为契约封闭前的存量文档保留,两者同现时 canonical 赢。
空串语义按同键既有惯例选,并偏离了代裁的字面写法(
?? ??),理由如下:??—— 对齐normalizeListViewSchema的 aria fold(ARIA_KEY_ALIASES),它仅在 canonical 为undefined时才搬运 legacy 键,故一个已声明的ariaLabel: ''会遮蔽陈旧的label;||—— 对齐ListView自身读点(schema.aria?.ariaLabel ? { 'aria-label': … } : {}),它把空串视为「没有可访问名」。因role="toolbar"必须有名字,此处「没有名字」落到内建兜底,而非 ListView 的省略属性。若照字面写成纯
??链,aria: { ariaLabel: '' }会渲染出aria-label=""—— 一个有 toolbar 角色却没有可访问名的元素,比兜底更差。该差异已被变异实测量化(见下 M3)。⛔ 未动 spec,⛔ 未在本单声明
aria: AriaPropsSchema。代裁二:注册描述
actionNames描述改为实测行为,不预告回退:注册
inputs是发布面(序列化进sdui.manifest.json与 JSX 授权类型),原句已流入工具链 —— objectstack#8744 的派发提示逐字引用它作为待验证声明,正是那条未通过验证。实现该回退属能力扩张,按分诊口径不做、另立卡。objectstack#8744 follow-up 解锁状态
卡面写明「declares aria the day the renderer reads the contract spelling」。该条件现已满足:renderer 读
aria.ariaLabel,RecordQuickActionsProps可以声明aria: AriaPropsSchema而不再是 declared-but-unenforced(#8691 那一类)。跨仓卡由 PM 转办。一个随之而来的事实已另立卡(见 findings):spec 的
AriaPropsSchema.ariaLabel是I18nLabelSchema,即也接受 inline locale map;本仓唯一的嵌套袋读点ListView.tsx:2380以as string原样送进 DOM,map 值会念成[object Object]。#8744 声明aria之后,本读点会继承同一空缺。反向验证(先书面预判,commit 后变异还原)
aria?.labelariaLabel:'' + label:'Legacy'),前半仍绿。符合ariaLabelZ??链(代裁字面写法)ariaLabel: ''单独出现 ⇒aria-label="")。量化了本 PR 对字面写法的偏离变异后已还原,
git diff对 commit 为空,9/9 复绿。验证
pnpm --filter '@object-ui/plugin-detail^...' build通过pnpm type-check:81/81 successfulno-explicit-any)check:control-bytesOK(4562 tracked files);另对改动文件自扫[\x00-\x08\x0b\x0c\x0e-\x1f]无命中.changeset/quick-actions-aria-label-and-actionnames-description-4663.md(patch)半径严格限于
renderers/record-quick-actions.tsx+src/index.tsx注册描述 + 两个测试 + changeset。未触及 #4646/#4647 席在飞的 RecordDetailView / RelatedList / list-toolbar 任何文件。Generated by Claude Code