fix(plugin-grid): BulkActionDialog 必填 param 宣告 required 状态而非把星号念进名字 (objectui#3967) - #3989
Merged
Merged
Conversation
…t the asterisk (objectui#3967)
`ParamField` renders the required marker inside a `<Label htmlFor>` that points
at the control, so accname folded the bare `*` into the control's accessible
name ("Notify owner asterisk"), while nothing carried the required STATE to the
control at all — `param.required` was live only in the dialog's own pre-submit
gate, and no widget derives `aria-required` from `field.required`.
Aligned with app-shell's `ActionParamDialog` (objectui#3299/#3290), not a second
spelling: `aria-hidden="true"` on the marker span, `aria-required={param.required
|| undefined}` on the widget. Deliberately not the native `required` attribute
(#3290: that arms the browser's constraint bubble alongside this dialog's own
gating — two validators, one field), and `|| undefined` so an optional param
carries no attribute rather than `aria-required="false"`.
`id` ownership at this site was already correct and is untouched, as is
`ActionParamDialog`. The marker stays visible; only its participation in the
accessible name changes.
Pins in `bulkActionDialogParams.test.tsx` cover both halves together — either
one alone is satisfiable the wrong way — plus a non-boolean param, since
`ParamField` has no type branches.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
PM 验收(session_01GTRjn8xBqp75dk7kFupVRt):通过,转 ready 并挂 auto-merge。#3967 落地。 核验记录(head
concern 中 lookup/user picker 触发器的 aria-required 着地未断言 —— 在 issue 验收范围外且 #3306 家族已有先例覆盖路径,同意不另立单,记入分诊轮参考。 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 #3967
前提复核(origin/main @ c4768a7)
正文两条缺陷都成立,并且比正文更具体的一点值得先写清楚:
packages/plugin-grid/src/components/BulkActionDialog.tsx全文只有一处aria-hidden(Suspense 骨架屏),星号 span 上没有;全文aria-required出现 0 次。field.required推出aria-required」这条可能的反驳被证伪:bulkParamToField确实把required写进 field metadata,但packages/fields/src/widgets/BooleanField.tsx与TextField.tsx里required出现 0 次 ——toDomProps按前缀转发aria-*,它不发明属性。所以 host 不传就是没有,通路空着。param.required本身是活的声明:同文件的提交前 gate 读它来禁用 Next。也就是说必填语义在逻辑上生效、在可访问性树里缺席,而唯一在场的是那个装饰字符。改动(仅 2 处,均在
ParamField)aria-hidden="true"。它位于Label htmlFor内部,accname 会把被引用 label 的文本折进控件名字,所以每个必填 bulk param 都被念成「Notify owner 星号」。Widget补aria-required={param.required || undefined}。两条都与 app-shell 的
ActionParamDialog对齐(#3299 / #3290 的裁决),不在这里发明第二套写法:required—— 按aria-required从未到达任何输入控件——必填状态只以「可访问名的一部分」存在 #3290,那会让浏览器的约束校验气泡与本 dialog 自己的 gating 并存,一个字段两个校验器。|| undefined使可选 param 完全不带该属性,而不是aria-required="false"。id下发在本站点原本就正确(bulk-param-${param.name}),未动;ActionParamDialog未动(PR #3971 已定型)。星号仍然可见,变的只是它是否参与可访问名。与派单口径的一处偏差(请复核)
派单写的是「boolean 分支」,并要求「generic 分支不变作阳性对照」。实际代码里
ParamField没有类型分支 —— 它是单一路径,所有类型走同一段 JSX(与 app-shell 的ActionParamDialog不同,后者确实 fork 了一个 boolean 分支)。因此:钉子(两个方向必须一起钉)
任何一条单独成立都能被错误地满足:只隐藏星号而不给
aria-required,则关于必填什么都不宣告;只给aria-required而不隐藏星号,则宣告两次、其中一次是噪音。所以三个用例都同时断言两侧,并额外断言星号仍然可见(否则「直接删掉星号」也能得到干净的名字)。aria-required="true"、无required原生属性、可访问名恰为Notify owner;label 的 textContent 仍含*,且该*在一个aria-hidden="true"元素内。aria-required,名字仍为Notify owner,label 不含*。探针刻意用 host 拥有的 id(
document.getElementById上拼bulk-param-前缀加 param 名)而不是*ByLabelText:后者匹配 label 的原始textContent,会悄悄依赖本 PR 正在断言的那个aria-hidden,自证其成。反向验证(先预判,再跑;变异未提交)
两个变异分别跑,方向都是预判的红:
aria-required={param.required || undefined}:预判「两条必填断言红、两条可选(断言属性缺席)保持绿」。实测2 failed | 5 passed,红的正是:278(boolean)与:311(text)两处toHaveAttribute("aria-required", "true")。aria-hidden="true":预判「可访问名断言红」。实测2 failed | 5 passed,红在:281与:312的toHaveAccessibleName—— 直接证明没有aria-hidden时星号确实折进了名字。复原后全绿。
验证
pnpm exec vitest run packages/plugin-grid --maxWorkers=2→Test Files 57 passed (57)/Tests 523 passed (523)pnpm exec turbo run type-check --concurrency=2→78 successful, 78 totalnode scripts/check-control-bytes.mjs→ OK(3885 个文件);改动文件另做越界自扫,无命中BulkActionDialog的仓内引用只在plugin-grid(ObjectGrid.tsx、demo、3 个测试),bulk-param前缀无其它包的 fixture 依赖,plugin-grid 无快照文件changeset:
@object-ui/plugin-gridpatch。