Skip to content

form.tsx 的内置 textarea 分支用 mobile_fullscreen || fullscreen 读全屏开关,而 fullscreen 这个别名全仓无人产出(消费侧宽容兜底) #3303

Description

@xuyushun441-sys

在实施 #3301(给 RichTextField 接上全屏能力,PR #3302)时顺带发现,不在 #3302 —— 那单的范围栅栏明确排除 packages/components

现象

packages/components/src/renderers/form/form.tsx:1945-1947,未注册的裸 textarea 类型走的内置分支:

const { mobile_fullscreen, fullscreen, label } = fieldProps as any;

if (mobile_fullscreen || fullscreen) {
  // renders FullscreenTextarea

fullscreen 是一个没有生产者的别名。全仓 grep fullscreen:(排除 node_modules/dist,排除 mobile_fullscreen / fullscreenLongText)只有 3 类命中,没有一处是表单字段:

命中 是什么
packages/types/src/zod/feedback.zod.ts:30 fullscreen: z.boolean() —— loading/feedback 遮罩的属性,与长文本编辑无关
packages/components/src/renderers/feedback/loading.tsx:75 同上,loading 组件的默认值
form.tsx:226 / form.tsx:283 stripRegisteredFieldProps 里把这个键丢弃的两处(fullscreen: _fullscreen

@objectstack/spec 侧同样为零(objectstackpackages/spec/src grep fullscreen 无命中)。

唯一真实的生产者是 ObjectForm,它产出的键叫 mobile_fullscreen#3245 / #3300 已把它规范到字段元数据这一个载体上)。所以 || fullscreen 这一项从写下起就恒为 undefined

为什么这是缺陷

这正是 AGENTS.md #0.1 明令禁止的形态:消费侧的宽容兜底。一个键有两种拼法、其中一种没有任何生产者,后果不是「多一层保险」,而是:

  1. 它把一个从不成立的契约写进了代码,下一个作者(尤其是 AI 生成的表单元数据)看到 fullscreen 会以为这是受支持的拼法,写下去、静默无效、没有任何一处报错——和 mobile.fullscreenLongText 对 rich-text 字段是空承诺:ObjectForm 给 field:markdown/field:html 盖了 flag,RichTextField 根本不读;string-multiline 分支全仓无人产出 #3301ObjectForm 的 mobile.fullscreenLongText 到不了自动生成字段的 TextAreaField:flag 写在 FormField 上,form.tsx 转发的却是 field.field #3245 完全同一个机制。
  2. 它让「mobile_fullscreen 是唯一载体」这个刚刚在 TextAreaField 读取的 mobileFullscreen prop 全仓无人生产,注释却说"宿主表单传入" #3232 / fieldschema 是同一个意思的两个载体,~25 个 widget 读 field || schema #3233 / ObjectForm 的 mobile.fullscreenLongText 到不了自动生成字段的 TextAreaField:flag 写在 FormField 上,form.tsx 转发的却是 field.field #3245 / fix(plugin-form,types): carry mobile_fullscreen on the field metadata, where widgets actually read (#3245) #3300 一路收敛出来的结论,在这一行上不成立。TextAreaField 与(feat(fields): RichTextField honors mobile_fullscreen with a fullscreen editing dialog (#3301) #3302 之后的)RichTextField 都已经收敛成单读;只有这个内置分支还留着 ||

顺带记录一个更大的重复,供裁决时一并考虑:FullscreenTextareaform.tsx:308-)是全屏编辑对话框的第三份实现——#3302 已把 widget 侧的两份合并成共享的 FullscreenFieldEditorpackages/fields/src/widgets/FullscreenFieldEditor.tsx),但内置分支这一份仍是独立的。两份实现是否要合并,取决于 packages/components 能否依赖 packages/fields(按 AGENTS.md §3 的拓扑,方向是反的,所以这不是一次简单搬运),需要单独裁决,不要顺手做。

修法建议(需裁决)

A. 直接删掉 || fullscreen,只读 mobile_fullscreen。零行为回归(这一项今天本来就恒假),declared = enforced 立刻成立。这是与 #3232 / #3233 同向的收敛,我倾向这条。

B. 若认为 fullscreen 才是想要的拼法,那就该在生产者ObjectForm)改名并一次性收敛,而不是让消费者同时接受两种——但 mobile_fullscreen 已经声明在 @object-ui/typesBaseFieldMetadata 上(#3300),改名成本明显更高且没有收益。

无论走哪条,都值得补一条钉死「拼错的 flag 不生效」的测试——目前这个内置分支的全屏行为没有任何测试覆盖到别名这一半。

证据等级

静态证据(全仓 + objectstack 仓 grep,阅读 form.tsx 三处相关源码),未做浏览器复现。「fullscreen 无生产者」是可机械复核的事实。

关联:#3301(PR #3302)、#3245(PR #3300)、#3232#3233

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions