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.

[app-shell] metadata-admin 的 SchemaForm 无条件给每个 widget 发 Label htmlFor={id},但 17 个注册 widget 里只有 5 个消费 id —— 分组类控件面的 for 悬空且组无可访问名 #4871

Closed

Description

@yinlianghui

发现于 #4010 的实施过程(该单主体是 ColorVariantPicker 的三个调用点,PR 只修了 picker 侧,宿主侧刻意未动)。未认领,交 PM triage。

机制

MetadataField(packages/app-shell/src/views/metadata-admin/SchemaForm.tsx)对每个字段渲染

Label htmlFor={id}   // id = `mdf-${name}`,确定性拼接,非 useId

并把同一个 id 传给 FieldControl → 注册 widget。约定与别处一致:被包控件带同一个 id。

但 widgets.tsx 的 WIDGETS 注册表里,17 个 *Widget 函数中只有 5 个在解构里收 id(RefComponentWidget :263、FieldRefWidget :948、ViewRefWidget :1011、FieldRefMultiWidget :1064、ActionMultiWidget :1611)。其余的把 id 丢掉,于是那句 htmlFor 指向一个没有任何元素持有的 id —— 悬空 IDREF,与 #3961 / #3990 / #4788 / #4857 同一失效类,只是宿主换成了 metadata-admin 自己的这套表单。

两档严重度,取决于 widget 渲染的是什么:

  1. 可 label 的控件(Input / Textarea 之类):for 悬空,可见 label 无归属,但控件本身至少还能被点选;
  2. 不可 label 的容器:for 连修都修不了(容器不是 labelable 元素),而且组本身没有 aria-label / aria-labelledby —— 完全匿名。已确认两处:

实测(#4010 实施时,objectui origin/main @ 65e88e6c2,真 SchemaForm 渲染)

colorVariant(type: string,带 enum,title: "Color Variant"):

label[for]:   [{ text: "Color Variant", for: "mdf-colorVariant", resolves: FALSE }]
radiogroup:   aria-labelledby=null  aria-label=null  accName=""

resolves: false 即文档里没有任何元素持有 mdf-colorVariant。#4010 的 PR 之后 accName 变成 "Color Variant"(picker 自带),resolves 仍然是 false —— 那一半正是本单。

为什么宿主侧才修得了(#4010 没有顺手做的原因)

分组面的正确命名通道是 IDREF:label 发布自己的 id、组用 aria-labelledby 应答,并且把 for 去掉(packages/components/src/renderers/form/form.tsx 在 labelling: 'group' 分支正是这么写的,并注明「for 落在 div 上是惰性 HTML,留着就是一个 label 两条通道、其中一条是坏的」)。

宿主要发出这个 IDREF,就必须在渲染 label 之前知道该字段最终渲染的是分组面还是可 label 控件。color-picker 恰好是反例:同一个注册项,有 enum 时渲染 radiogroup、没有时渲染可 label 的 input type="color",而这个分支是 widget 自己按 schema/fieldSpec 决定的 —— 宿主写 label 时还不知道。

所以这需要一个逐 widget 的 labelling 声明(packages/components 的 form renderer 已有的那个形状:ComponentMeta.labelling: 'control' | 'group',#3961),而 widgets.tsx 的 WIDGETS 是一张裸 Record,没有 meta 层。对 color-picker 这种条件分组的,还要决定是拆成两个注册项、还是让宿主把两条通道都递下去由 widget 自选 —— 属于契约层要先定的一步,不该在 #4010 里猜。

边界与去重

建议的验收面

先把 17 个注册 widget 逐个测出「host 的 for 是否解析得到 / 渲染面是否可 label / 组是否有名」三列读数(#4788 与 #4857 都是这么摆的账本),再据此定 labelling 声明的形状 —— 逐个改 widget 而不先定声明,会把同一个决定散到十几处。

Activity

  1. added theissue type on Aug 17, 2026
  2. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    Contributor

    Triage: needs-user-decision, type Bug. The mechanism fix is gated on a contract-layer choice the card names precisely: WIDGETS in metadata-admin is a bare Record with no meta layer, and the host cannot emit the correct IDREF channel without a per-widget labelling declaration — plus a decision for conditional-group widgets (color-picker: split registrations vs pass both channels down). Declaring a new widget-contract key is the manual floor, so this escalates rather than queues.

    ⚠️ Decide together with #4857 — same design axis ("how does a host learn what a widget will render"), different host (SDUI form renderer there, metadata-admin here). One ruling should settle the declaration shape for both; see the facet block on #4857.

    Decision facets:


    Generated by Claude Code

  3. os-zhuang commented on Aug 17, 2026

    @os-zhuang
    Contributor

    Maintainer ruling (2026-08-17, recorded by PM session session_01NYgmGheCzM6NrHZN436Cxf). The maintainer accepted the decision-inbox report's recommendations in full, verbatim: 「同意」. Ruled together with #4857 — one declaration shape settles both hosts (see the sibling ruling there for the shared vocabulary: ComponentMeta.labelling extended to 'control' | 'group' | 'display'; ⛔ no host-local variants; the declaration slice is claude-fable-5).

    This card's landing:

    1. Ledger first (the card's own sequencing, ratified): measure all 17 registered widgets on the three axes — does the host for resolve / is the rendered face labelable / does the group have a name — before declaring; the declarations are then one reviewed table, not seventeen scattered judgements.
    2. metadata-admin's WIDGETS registry gains a meta layer reusing the same declaration type from packages/components — never a local variant (the second-divergent-copy shape this repo keeps paying for).
    3. SchemaForm emits the channel the declaration dictates: for for control; label publishes an id + the face answers aria-labelledby (and for is dropped) for group/display — the form.tsx labelling: 'group' branch is the worked precedent.
    4. Conditional-group widgets (color-picker) split into two registrations (enum ⇒ radiogroup registration, no-enum ⇒ color-input registration) — the host picks by schema, declared beats passing both channels down for the widget to choose at runtime (which would re-introduce the inference this ruling removes).
    5. The same registry-level "registered ⇒ declared" gate ruled on [fields] 七个 widget 在**可编辑态**也丢掉 host 下发的 id —— label 的 for 悬空、description 零消费者(formula / summary / auto_number / vector / grid / slider / signature 实测) #4857 covers this registry too.

    Label flipped needs-user-decision → pm:queue in the same stroke.


    Generated by Claude Code

  4. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    PM 持有(objectui 分片 PM,session session_01GTRjn8xBqp75dk7kFupVRt):挂 pm:blocked。

    Blocked-by: #4857

    依据 05:03Z 合裁:本卡 metadata-admin 的 meta 层必须复用 #4857 落地的 ComponentMeta.labelling 三值词表(⛔ host 本地变体)—— #4857 已派发在飞(声明扩展 + display 四 + 配套门),其 PR 落 main 后本卡回队立即派(账本先行 + 复用声明类型 + color-picker 拆双注册,裁定五点已在楼上)。


    Generated by Claude Code

  5. self-assigned this
    on Aug 17, 2026
  6. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    认领(objectui 分片 PM 座席,批次 21)。Session session_01GTRjn8xBqp75dk7kFupVRt,分支 claude/issue-4871-schemaform-labelling,os-dev 子代理实施。

    解锁依据:Blocked-by #4857 → PR #5036 已落 main(167ec42e7)—— ComponentMeta.labelling 三值词表与穷尽 Record 门形态均已在位可复用。实施依据 = 05:03Z 合裁五点(楼上评论):账本先行(17 widget × 三列读数)→ meta 层复用 core 的声明类型(⛔ host 本地变体)→ SchemaForm 按声明发通道 → color-picker 拆双注册 → registered⇒declared 门覆盖本注册表。文件面:packages/app-shell/src/views/metadata-admin/SchemaForm.tsx + widgets.tsx + 测试,与在飞 #4923(packages/cli)不相交。


    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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions