Skip to content

fix(components): 表单内置 textarea 分支只读 mobile_fullscreen,删掉无生产者的 fullscreen 别名 (#3303) - #3397

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3303-fullscreen-alias-removal
Aug 5, 2026
Merged

fix(components): 表单内置 textarea 分支只读 mobile_fullscreen,删掉无生产者的 fullscreen 别名 (#3303)#3397
yinlianghui merged 2 commits into
mainfrom
claude/issue-3303-fullscreen-alias-removal

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3303

做了什么

按 PM 裁定的 A 方案收敛:表单渲染器内置 textarea 分支只读 mobile_fullscreen 一种拼法。

  1. packages/components/src/renderers/form/form.tsx 内置 textarea 分支:
    mobile_fullscreen || fullscreenmobile_fullscreen
  2. 同文件 stripRendererOnlyPropsstripRegisteredFieldProps 各自丢弃
    fullscreen 键的那一条(别名的最后残留)一并删除。
  3. 新增钉子测试
    packages/components/src/renderers/form/__tests__/form-fullscreen-flag-single-spelling.test.tsx
  4. changeset 一份(见下面「为什么补了 changeset」)。

前提复核(issue 行号基于 08-03 快照)

issue 写的是 form.tsx:1945-1947,而今天 #3392 刚改过同一文件。已对当前
origin/main(4eeb932aa)复核,别名读取仍在
,只是行号漂到 2016-2018;两处 strip
条目漂到 259 / 321。前提成立。

fullscreen 零生产者」也机械复核过:全仓 + 全扩展名 grep 一个裸 fullscreen
键,只剩两类无关命中 —— feedback/loading 遮罩的同名属性
packages/types/src/zod/feedback.zod.tsrenderers/feedback/loading.tsx
按裁定不碰),以及各 locale 文件里的 fullscreen: 词条命名空间。没有任何一处是表单字段。

为什么这不是「多一层保险」

ObjectForm 是唯一生产者,产出的键叫 mobile_fullscreen#3245/#3300),也是
TextAreaField / RichTextField 单读的那一个。所以 || fullscreen 从写下起恒为
undefined —— 它的代价不是取错值,而是多了一种拼法:下一个作者(尤其是写表单元数据的
AI)从渲染器里读到 fullscreen,照着写,静默无效、没有任何一处报错。这正是 AGENTS.md
0.1 禁止的消费侧宽容兜底,与 #3245#3301 同一机制。

两处 strip 条目同理:一个没人产出的键不该享有专门的丢弃条目,它应该落回普通的
「不认识的键」那一类,这样拼错才和其它拼错一样可见,而不是被悄悄吞掉。

顺带说明,#3232 那份 changeset 当初明确把这个内置分支记为「另一条仍接受两种拼法的活路径」,
本 PR 就是把那条 forward reference 关掉,#3232/#3233/#3245/#3301 这一串收敛到此收口。

反向验证(方向是先定后跑的)

跑之前先记下预期:钉子里「金丝雀」用例(元数据只写 fullscreen: true)应当
改前红、改后绿;因为 fixture 故意不写规范键,|| 的第二项才是决定项 —— 这不是
canonical-key-first 那种「改前后都红」的反转家族。

改前(未动源码,只加测试)实测:

 Test Files  1 failed (1)
      Tests  2 failed | 3 passed (5)

两条红的正是要钉的两条:别名用例渲染出了展开按钮(dump 里能看到
lucide-maximize2 的 button),strip 用例里 props.fullscreenundefined
(说明当时确实有专门的丢弃条目)。两条限肢都是活的,不是空绿。

改后:

 Test Files  1 passed (1)
      Tests  5 passed (5)

钉子怎么写的

  • 正例与反例成对:只断言「别名不渲染展开按钮」是会因为空的理由变绿的 —— 全屏能力整个
    失效时它同样通过。所以同一 describe 里先钉住 mobile_fullscreen 确实渲染展开按钮、
    且开-改-Done 的 draft/commit 语义仍然完好。
  • strip 语义单独钉:只钉内置分支的话,删掉两处 strip 条目是零测试覆盖的,后人原样加
    回去不会有任何东西变红。所以用一个探针 field widget 断言:mobile_fullscreen 仍被 strip
    掉(它只走 field 这一个载体),而 fullscreen 现在与一个随手编的 not_a_real_flag
    行为完全一致。断言写成两者相等,意思不是「widget 应该收到 fullscreen」,而是
    「渲染器不再为它保留专门条目」。

消费半径已扫

两个 strip 只在 form.tsx 的 renderFieldComponent 里被调用,但它们的下游是所有注册
字段 widget。按消费半径(不是按改动包)扫了 fixture:全仓没有任何 fixture 拼过表单字段级的
fullscreen,所以没有需要改拼写 / 补声明 / 整条替换的 fixture。

明确没做(按裁定)

为什么补了 changeset

PM 说纯收敛可免、由 dev 判。判下来是:这一族(#3232/#3245/#3301)每一单都发了
changeset,且 #3232 那份正文里对本分支留了 forward reference,不补会让发布说明里这串收敛
断在半路。定为 patch / @object-ui/componentscheck-changeset-no-major 已过。

验证

  • 新钉子 5/5 绿,并用 --reporter=verbose文件名确认确实跑到了(objectui#3288/pnpm --filter @object-ui/app-shell test 跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378
    的路径过滤被吞陷阱)。
  • 表单渲染器全目录 + 三个跨包 fullscreen 消费者(fields 的 TextAreaField / RichTextField、
    plugin-form 的 ObjectForm、types 的字段元数据)一起从仓根跑:
    Test Files 31 passed (31) / Tests 153 passed (153)
  • turbo run type-check --filter=@object-ui/components:8/8 successful。
  • turbo run lint --filter=@object-ui/components:0 errors(770 条既有 warning 全在
    src/ui/** 免动区等无关文件;新测试文件只有 3 条 no-explicit-any,与同目录既有探针测试
    form-field-carrier.test.tsx 同款)。
  • pnpm check:control-bytes:OK。

Generated by Claude Code

claude added 2 commits August 5, 2026 16:12
…3303)

The built-in `textarea` branch resolved the flag as
`mobile_fullscreen || fullscreen`, and both prop strips carried a matching
entry discarding a `fullscreen` key. That alias had zero producers: neither
this repo nor `@objectstack/spec` publishes a form-field `fullscreen`
property (the only `fullscreen` keys that exist belong to the unrelated
feedback/loading overlay), so the second term was undefined from the day it
was written.

Its cost was not a wrong value, it was a second spelling: the renderer
advertised a flag that quietly does nothing, which is the lenient consumer
fallback AGENTS.md #0.1 forbids and the same mechanism as #3245 / #3301.
`ObjectForm` is the sole producer and stamps `mobile_fullscreen`
(#3245/#3300) — also the single spelling `TextAreaField` and `RichTextField`
read, so the built-in branch was the last place where a producer-less
spelling still "worked".

Removing the strip entries puts `fullscreen` in the ordinary unknown-key
class rather than giving a key nobody produces a dedicated discard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 5, 2026 4:20pm

Request Review

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-yak3Wxh8.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.47KB 3.09KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 18.38KB 4.49KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 3.65KB 1.42KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.25KB 0.53KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 477.84KB 104.86KB
core (index.js) 2.25KB 0.80KB
create-plugin (index.js) 9.28KB 2.98KB
data-objectstack (index.js) 136.23KB 34.75KB
fields (index.js) 227.18KB 55.72KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 3.26KB 1.44KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.05KB 1.53KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 112.01KB 28.86KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 231.54KB 57.09KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 111.54KB 26.97KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 185.08KB 49.04KB
plugin-kanban (index.js) 47.89KB 13.18KB
plugin-list (index.js) 105.02KB 25.36KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.55KB 10.59KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.34KB 2.82KB
plugin-view (index.js) 83.67KB 20.43KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.46KB 1.21KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 0.20KB 0.18KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

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

Projects

None yet

2 participants