fix(components): 内置 textarea 全屏路径遵守 readonly/disabled — 只读不给展开按钮,禁用不可经对话框写回 (#3400) - #3401
Merged
Merged
Conversation
…llscreen path (#3400) `renderFieldComponent` destructures `readonly` off its props, so it is not in the `...rest` each branch spreads. The built-in `textarea` branch has two exits and only the plain one put it back (`readOnly={readonly}` + the read-only tint); the `mobile_fullscreen` exit forwarded neither. `FullscreenTextarea` renders three controls — the inline textarea, the expand button, and the dialog's own textarea — and only the first ever saw a spread prop. So a read-only long-text field was editable in place without opening the dialog, and a disabled one looked correctly greyed out while its expand button stayed live, its dialog accepted any edit, and "Done" wrote that edit back into form state. `readonly` now suppresses the expand button entirely, matching the registered path (`fields/src/widgets/TextAreaField.tsx` early-returns a read-only display before `showFullscreenButton` is computed), so both renderers give the same metadata the same user-visible behaviour. `disabled` keeps the button but disables it. Both states also lock the dialog's textarea and its "Done" button independently of the button, because `disabled` is additionally `isSubmitting`, which can flip to true while the dialog is already open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This was referenced Aug 5, 2026
akarma-synetal
pushed a commit
to akarma-synetal/objectui
that referenced
this pull request
Aug 6, 2026
…k-ai#3403) * fix(fields): honour disabled on the registered fullscreen long-text path (objectstack-ai#3402) `disabled` reached the inline control of `TextAreaField` / `RichTextField` and nothing else. `showFullscreenButton` did not consult it, neither call site forwarded it, and `FullscreenFieldEditor` did not declare the prop at all — so a disabled long-text or rich-text field was greyed out inline while its expand button stayed live, its dialog accepted any edit, and "Done" wrote that edit back through `onCommit`. The issue carried static evidence only, so the premise was reproduced with a dynamic probe first: toggle `disabled=false`, dialog opened, dialog input `disabled=false`, `onChange` called with "EDITED WHILE DISABLED" — on both widgets, and again with `disabled` flipped true under an already-open dialog. `FullscreenFieldEditor` now declares `disabled`, shaped like the built-in path's `locked` gate (objectstack-ai#3400 / PR objectstack-ai#3401): the toggle stays but is disabled and refuses to open, the dialog's editor is disabled via a new third `children` argument, and "Done" is disabled and gated before `onCommit`. The dialog holds on its own rather than trusting the button, because `disabled` also carries the form's `isSubmitting` and can flip true while the dialog is open. Cancel and Esc stay live so a submit in flight cannot trap the user in a modal. `readonly` is untouched: both widgets early-return a read-only display before the affordance is computed, which is why readonly was never part of this defect, and no `readonly` prop is added here that no host would produce. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt * test(fields): merge the stacked doc comments on the fullscreen-disabled helper Comment-only. Two JSDoc blocks had accreted on `openThenDisable`; they say one thing, so they are one block. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3400
问题
renderFieldComponent在入口就把readonly从 props 里解构走了,因此它不在各分支 spread 的...rest里。内置textarea分支有两条出口,只有非全屏那条把它放了回去(readOnly={readonly}+readonlyInputClass);mobile_fullscreen那条两样都没转发。FullscreenTextarea内部有三个控件 —— 内联 textarea、展开按钮、对话框里那个独立的 textarea —— 而只有第一个见过 spread 进来的 prop。于是:这不是刁钻写法:
ObjectForm在mobile.fullscreenLongText打开时给每一个长文本字段无差别盖mobile_fullscreen,不看 readonly/disabled;readonly还可由readonlyWhen的 CEL 在运行时解析;disabled又会因isSubmitting为真 —— 也就是提交进行中仍可通过全屏对话框改值。改法(PM 裁定的方案 2+1 组合)
readonly⇒ 完全不渲染展开按钮。这与注册路径一致(fields/src/widgets/TextAreaField.tsx在 readonly 时提前返回只读展示,showFullscreenButton根本算不到),两条渲染路径对同一份元数据给出同一种用户可见行为。给个禁用的按钮反而更糟:它宣告了一个只读路径压根没有的可供性。disabled⇒ 按钮保留但disabled(disabled 是「不可交互、变灰」,不是「平铺展示」,与调用点一贯的区分一致)。readOnly/disabled,「完成」按钮禁用,且commit走同一个locked闸门。这不是叠甲 ——disabled同时也是isSubmitting,它可以在对话框已经打开时翻成 true,那一刻按钮已经不是关口了。readOnly={readonly}与只读底色;readonly 时去掉pr-10(那段右内边距是给按钮预留的,没有按钮就是死空间)。FullscreenTextarea的readOnly/disabled现在是声明的 props,不再是搭rest便车的乘客。测试
新增
form-fullscreen-textarea-readonly-disabled.test.tsx,14 例,覆盖 issue 实测的全部状态:readonly(无展开按钮、内联不可改、只读底色、readonlyWhen运行时解析同样成立)、disabled(按钮禁、点击也不开对话框)、isSubmitting期间(对话框内防线 + 写回被拒)、以及正常字段全屏编辑/取消/内联编辑不回归。反向验证(方向先声明后执行):预测「加固类改动 ⇒ 还原后守卫用例转红、对照与回归用例保持绿」。stash 掉
form.tsx后实测 9 红 / 5 绿,且这 5 个绿正是预测点名的那 5 个 ——leaves an editable long-text field alone、keeps the inline control disabled(该出口本来就守住了,issue 自己也测到「内联 disabled = true」)、以及三条全屏往返回归用例。没有任何一例是因为「什么都没产出」而空绿。消费半径已扫:
form-textarea-fullscreen-*testid 与mobile_fullscreen的全仓 fixture(components 三个姊妹测试 +types+plugin-form+fields两个注册路径测试)7 文件 43 例全绿;packages/components全量 84 文件 614 例全绿;type-check通过;改动文件 eslint 0 error;check:control-bytesOK。⛔ 未触碰
FullscreenFieldEditor/TextAreaField/ObjectForm。issue 正文末那条未验证的.field载体镜像不在本单范围,未修也未验证。🤖 Generated with Claude Code
https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Generated by Claude Code