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.

注册路径的全屏长文本编辑器同样绕过 disabled:TextAreaField / RichTextField 的展开按钮与 FullscreenFieldEditor 不认 disabled,禁用字段可经对话框改值写回 #3402

Closed

Description

@yinlianghui

在实施 #3400(PR #3401,修内置 form.tsx 全屏路径的 readonly/disabled 绕过)时,做「规则消费半径」扫描发现,未在该 PR 内修改 —— #3400 的文件面被裁定为 packages/components/src/renderers/form/form.tsx,且明确 ⛔ 不碰 FullscreenFieldEditor / TextAreaField。这一条在 packages/fields,是另一条独立缺陷。

现象

#3400 修的是内置分支。注册路径的对应实现只守住了 readonly,disabled 一样是漏的:

  • packages/fields/src/widgets/TextAreaField.tsx:40 —— readonly 时提前返回只读展示,showFullscreenButton 根本算不到。readonly 是安全的。
  • packages/fields/src/widgets/RichTextField.tsx:107 —— 同样的提前返回。readonly 也是安全的。
  • 但 disabled 两边都只落到内联控件上:
    • TextAreaField.tsx:68 disabled={readonly || domProps.disabled}
    • RichTextField.tsx:140 disabled={readonly || props.disabled}
  • 而 showFullscreenButton = Boolean(richField?.mobile_fullscreen) 不看 disabled,FullscreenFieldEditor 也没有收到 disabled(TextAreaField.tsx:85-109 / RichTextField.tsx:144-163 的调用点只传 value / onCommit / label / testIdPrefix / footer / children)。
  • packages/fields/src/widgets/FullscreenFieldEditor.tsx 里 grep readonly|readOnly|disabled —— 零命中(form.tsx 内置 textarea 的全屏路径完全绕过 readonly / disabled:只读长文本可直接编辑,禁用字段可经对话框改值并提交进表单状态 #3400 正文已记录这一点,但当时的结论是「它被 TextAreaField 的提前返回挡在前面」;那个结论只对 readonly 成立,对 disabled 不成立)。

于是禁用的长文本 / 富文本字段:内联控件正确地灰着,但展开按钮仍可点,对话框里可以随便改,提交(onCommit={onChange})把值写回。这与 #3400 的 disabled 那一半是同一个缺陷,只是在另一条渲染路径上,而且同样难被发现,因为控件外观是对的。

可达性

与 #3400 相同,而且是平台自己造出来的组合:

  • packages/plugin-form/src/ObjectForm.tsx:1076 在 mobile.fullscreenLongText 打开时,给每一个长文本字段无差别盖 mobile_fullscreen,不看该字段是否 readonly/disabled;
  • 表单渲染器的调用点算的是 disabled: disabled || fieldDisabled || isSubmitting || optionGroupGated,而 stripRegisteredFieldProps 不剥离 disabled(已核实:该函数的剥离清单里没有它),所以这个值确实到达注册 widget;
  • 因此同样包含 isSubmitting —— 表单提交进行中,长文本字段仍可通过全屏对话框改值并写回。

证据等级

静态证据:读 TextAreaField.tsx / RichTextField.tsx 的提前返回与 FullscreenFieldEditor 调用点、FullscreenFieldEditor.tsx 的 grep 零命中、stripRegisteredFieldProps 的剥离清单(确认 disabled 不在其中)。未做动态探针实测(#3400 的探针只覆盖内置分支);建议 triage 时先跑一次等价探针确认,再定严重度。

修法方向(不预设结论)

  1. 最小修:FullscreenFieldEditor 声明 disabled prop,展开按钮 disabled、对话框输入框跟随、提交不写回;两个 widget 把 disabled 传下去。与 PR fix(components): 内置 textarea 全屏路径遵守 readonly/disabled — 只读不给展开按钮,禁用不可经对话框写回 (#3400) #3401 在内置分支所做的完全对称。
  2. 若 全屏长文本编辑器有两份实现:form.tsx 的 FullscreenTextarea 与 fields 的 FullscreenFieldEditor(合并受阻于 components ← fields 的依赖方向) #3398(两份实现的合并)最终裁决为「下沉合并」,则在合并后的实现里一次性定义 readonly/disabled —— form.tsx 内置 textarea 的全屏路径完全绕过 readonly / disabled:只读长文本可直接编辑,禁用字段可经对话框改值并提交进表单状态 #3400 已经指出「readonly/disabled 语义要在合并时一并定义,而不是假设搬过去就有」,这一条是那句话的具体清单。

不预设走哪条,取决于 #3398 的裁决节奏。但这一条不依赖 #3398: 方向 1 今天就可独立落地,不需要等合并裁决,所以按独立 issue 归档而非 #3398 的子任务。

关联


Generated by Claude Code

Activity

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

    @yinlianghui
    ContributorAuthor

    认领:objectui 分片 PM 滚动补位第 15 单(#3400/PR #3401 落地,同族另一半即补)
    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3402-registered-fullscreen-disabled
    Worktree:objectui-issue-3402
    域:objectui 分片(fields)
    文件面:packages/fields/src/widgets/FullscreenFieldEditor.tsx、TextAreaField.tsx、RichTextField.tsx + 相应测试 + .changeset/*.md(patch)。当前在飞 0。

    方向裁定(PM,否决窗口):方向 1 —— FullscreenFieldEditor 声明 disabled prop(展开按钮禁、对话框输入跟随、提交不写回,含「对话框开着时 isSubmitting 翻真」场景 —— 参照 PR #3401 的 locked 闸门形制),两个 widget 传下去;不等 #3398 裁决(readonly 两路径已一致,本单收齐 disabled 的另一半)。issue 证据为 static-only:先跑等价动态探针坐实前提再动手(#3400 的探针形制可复用)。⛔ 不碰 form.tsx(内置分支已修);⛔ readonly 提前返回路径不动。


    Generated by Claude Code

  3. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    ContributorAuthor

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

    落地内容(方向 1):前提按要求先动态坐实(探针在 origin/main 上断言坏行为 3/3 绿,修后 3/3 红,随即删除 —— 两个 widget 都复现了「禁用改值写回」与「对话框开着时翻 disabled」);FullscreenFieldEditor 声明 disabled(按钮禁 + openFullscreen 拒开 + 对话框编辑器经新 children 第三参禁用 + Done 禁用且 onCommit 前置闸门);两 widget 各解析一次传两个编辑面。readonly 提前返回、form.tsx、ObjectForm、strip 均未触碰。

    方法论记账 —— 值得写进纪律:四肢反向验证里 dev 发现「单删 commit 守卫不红」(React 不给带 disabled 属性的按钮派发 onClick),并据此重构测试(写回断言原本挂在属性断言之后,只可能在属性已承重的世界里运行)—— B/C 两肢证明守卫在属性丢失瞬间承重。这是「反向验证发现测试自身结构缺陷」的样本。

    衍生分诊:#3404(注册路径全屏对话框硬编码英文 Cancel/Done 等 —— 十包 key 已存在,同一表单两条路径一边译文一边英文;#3272 的注册路径镜像)已复核入队 bug + pm:queue。

    至此全屏编辑器缺陷链(#3272→#3393→#3400→#3402)四环闭合,readonly/disabled 在两条渲染路径上语义一致。

    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