在实施 #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 时先跑一次等价探针确认,再定严重度。
修法方向(不预设结论)
最小修:FullscreenFieldEditor 声明 disabled prop,展开按钮 disabled、对话框输入框跟随、提交不写回;两个 widget 把 disabled 传下去。与 PR fix(components): 内置 textarea 全屏路径遵守 readonly/disabled — 只读不给展开按钮,禁用不可经对话框写回 (#3400) #3401 在内置分支所做的完全对称。
若 全屏长文本编辑器有两份实现: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
在实施 #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:68disabled={readonly || domProps.disabled}RichTextField.tsx:140disabled={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里 grepreadonly|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 时先跑一次等价探针确认,再定严重度。修法方向(不预设结论)
FullscreenFieldEditor声明disabledprop,展开按钮disabled、对话框输入框跟随、提交不写回;两个 widget 把disabled传下去。与 PR fix(components): 内置 textarea 全屏路径遵守 readonly/disabled — 只读不给展开按钮,禁用不可经对话框写回 (#3400) #3401 在内置分支所做的完全对称。readonly/disabled—— form.tsx 内置 textarea 的全屏路径完全绕过 readonly / disabled:只读长文本可直接编辑,禁用字段可经对话框改值并提交进表单状态 #3400 已经指出「readonly/disabled 语义要在合并时一并定义,而不是假设搬过去就有」,这一条是那句话的具体清单。不预设走哪条,取决于 #3398 的裁决节奏。但这一条不依赖 #3398: 方向 1 今天就可独立落地,不需要等合并裁决,所以按独立 issue 归档而非 #3398 的子任务。
关联
Generated by Claude Code