Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

form.tsx 全屏文本编辑对话框拿不到字段 label:标题恒为通用「编辑文本」,展开按钮的无障碍名在同一表单上完全一样 #3393

Closed

Description

@yinlianghui

在实现 #3272(PR #3392)时发现,未在该 PR 内修改 —— 那一单的范围是「把硬编码英文接进 i18n」,而这一条是数据没送到,属于行为缺陷,修法要动 props 传递。

现象

packages/components/src/renderers/form/form.tsx 内置 textarea 分支:

case 'textarea': {
  const { mobile_fullscreen, fullscreen, label } = fieldProps as any;

这里的 label 恒为 undefined。原因在上游 renderFormField 的字段解构 —— label 在 ...fieldProps 之前就被单独取走了:

const {
  name,
  label,
  description,
  type = 'input',
  ...
  ...fieldProps
} = field;

而 renderFieldComponent 的唯一调用点展开的是 ...fieldProps,并没有把 label 再补回去。那个 props 对象里显式补了 field / inputType / options / placeholder / disabled / readonly / emptyHint / dataSource / dependentValues / dependsOnLabels / validation 等等,唯独没有 label。全文件 grep,props 对象里没有任何一处 label:。

后果(用户可见)

FullscreenTextarea 里两处依赖 label 的分支从来没有被走到:

  1. 对话框标题 {label ?? t('form.fullscreen.title')} —— 一个叫「备注」的长文本字段,点开全屏编辑,标题恒为通用的「编辑文本」,而不是字段名。作者写 label ?? … 显然是想要字段名兜个通用词,结果通用词成了唯一结果。
  2. 展开按钮的无障碍名 t('form.fullscreen.toggle', { label: label ?? t('form.fullscreen.textFallback') })(form.tsx 仍有一批用户可见的硬编码英文(全屏文本编辑对话框、Submit/Cancel 默认值、required aria-label) #3272 之前是模板串 Edit ${label ?? 'text'} fullscreen)—— 屏幕阅读器恒读「全屏编辑文本」。一张有三个长文本字段的表单上,三个展开按钮的无障碍名完全一样,读屏用户无法区分自己要展开的是哪个字段。这是 ADR-0054 之外的一条独立可达性问题,不是纯视觉问题。

旁证:ESLint 早就在同一分支的下一行报着 '_label' is assigned a value but never used

const { label: _label, ...rest } = stripRendererOnlyProps(fieldProps);

那一行的意图是「别让 label 落到 DOM 属性上」,而它要防的东西根本就没来。

修法建议

把 label 补进调用点的 props 对象即可(和 placeholder / emptyHint 一样显式传递),然后确认 stripRendererOnlyProps / stripRegisteredFieldProps 仍把它挡在 DOM 之外 —— _label 那一行届时就真的开始起作用了。

建议只给内置分支补,不要顺手改注册路径:注册型 field widget 走的是 FieldWidgetProps 契约,widget 已经能从 field 元数据里读到 label,再多送一路 label prop 是否合适需要对着那份契约单独确认(#3233 刚把「哪条 registry 入口决定哪份契约」收敛过一次,别在这里又开一个口)。

证据等级

静态证据(读 form.tsx 的三处相关源码 + 全文件 grep + 现成的 ESLint 告警),未做浏览器复现。「label 恒为 undefined」是可机械复核的事实:在 renderFieldComponent 入口打印 props 即可确认。

关联

Activity

  1. self-assigned this
    on Aug 5, 2026
  2. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    ContributorAuthor

    认领:objectui 分片 PM 滚动补位第 13 单(form.tsx 串行链末单:#3303/PR #3397 已落地解锁)
    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3393-fullscreen-label-prop
    Worktree:objectui-issue-3393
    域:objectui 分片(components form)
    文件面:packages/components/src/renderers/form/form.tsx + 相应测试 + .changeset/*.md(patch,用户可见行为修复)。当前在飞 0。

    口径照正文:label 显式补进 renderFieldComponent 调用点的 props 对象(与 placeholder/emptyHint 同法);确认 strip 两函数仍把它挡在 DOM 外(_label 行从此真正起作用,ESLint 告警随之消失);只补内置分支,⛔ 不动注册路径(FieldWidgetProps 契约的口子不在本单开,#3233 刚收敛过)。测试:对话框标题 = 字段 label(非通用词)、多长文本字段的展开按钮无障碍名互不相同、label 不落 DOM 属性。#3272 已把 form.fullscreen.toggle 做成插值句,label 补通后句子直接正确,十包零改动。


    Generated by Claude Code

  3. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    ContributorAuthor

    PM 验收:ACCEPT → PR #3399 已转 ready + auto-merge(CI 16/16 全绿),跟到 MERGED。

    落地内容:label 显式转发进调用点 props;issue 半句证伪并据此调整修法 —— strip 两函数原本都无 label 条目(真正拦着的只有 textarea 分支的局部解构,只护一个分支),故两侧各补丢弃项:DOM 侧防杂属性、注册侧保证 widget 载荷逐字节不变(FieldWidgetProps 契约未动,与 fields 包既有做法一致)。三肢反向验证各自预判命中(调用点/DOM strip/注册 strip 各红各的),i18n 组在第一肢下保持绿是 fixture 改判正确的独立证据。十包零改动(#3272 预埋的插值句直接生效)。

    衍生分诊:#3400(全屏路径完全绕过 readonly/disabled —— 只读长文本可编辑、禁用字段展开可改、isSubmitting 期间仍可写回,vitest 探针实证;ObjectForm 无差别盖 mobile_fullscreen 使可达性高)已复核入队 bug + pm:queue,下批优先;#3398 已被追加交叉引用(其「两实现行为一致」判断被 #3400 证伪,选项成本需重估);第三条观察明确标注未验证、未立单,记录在 #3400 末尾,纪律正确。

    objectui 分片 PM session_01GTRjn8xBqp75dk7kFupVRt


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions