fix(plugin-detail): record:details edit mode edits a textarea field in a multi-line textarea (objectui#11562) - #11567
Merged
objectstack-fleet[bot] merged 1 commit intoOct 3, 2026
Conversation
…n a multi-line textarea (objectui#11562) `textarea` leaves INLINE_PLAIN_TEXT_FIELD_TYPES (class D) and joins INLINE_ROUTED_FIELD_TYPES; InlineFieldInput routes it to the fields package's multi-line TextAreaField, on markdown's branch (objectui#11541). The terminal input is a one-line INPUT of type text, and the browser strips line breaks from the value it is seeded with, so a stored multi-line note was saved flattened after one keystroke. The hosts' gate is unchanged: textarea is not in the shared INLINE_EXCLUDED_FIELD_TYPES, so DETAIL_ROUTED_INLINE_TYPES does not need it. Drift guard: textarea moves from benign to routed. Class-D pins for text, email, url and phone stay. New pins in InlineFieldInput.textareaEditor-11562.test.tsx. Claude-Session: https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11562-detail-textarea-multiline
branch
October 3, 2026 17:28
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 #11562
Clause-②: no
What changed
record:detailsedit mode now edits atextareafield in the fields package's multi-lineTextAreaField, so a save keeps the line breaks the value was stored with.packages/plugin-detail/src/InlineFieldInput.tsx:textarealeavesINLINE_PLAIN_TEXT_FIELD_TYPES(class D, objectui#4220) and joinsINLINE_ROUTED_FIELD_TYPES. It takes the branchmarkdowngot in objectui#11541, which rendersTextAreaField. The set's docblock drops the warning objectui#11541 wrote abouttextarea. Its "nothing is lost" sentence now covers only the single-line members left:text,email,phone,url.inlineEditTypeCoverage.test.tsx:textareamoves frombenigntorouted. The benign bucket's wording now says single-line.InlineFieldInput.delegation.test.tsx:textarealeaves the class-D loop. The class-D pins fortext,email,urlandphoneare unchanged and green.InlineFieldInput.textareaEditor-11562.test.tsx.@object-ui/plugin-detailpatch changeset.Deviation from the ruling's mechanism words:
DETAIL_ROUTED_INLINE_TYPESis untouchedThe ruling reads "Route
textareathroughDETAIL_ROUTED_INLINE_TYPESto the fields package's multi-lineTextAreaField". The PR does not addtextareato that set. Measured, it is the wrong lever for this type:DETAIL_ROUTED_INLINE_TYPESexists only to exempt members of the fields package's sharedINLINE_EXCLUDED_FIELD_TYPESfrom the detail hosts' gate.markdownneeded it becausemarkdownis in that set.textareais not (EDIT_WIDGETSmaps it toTextAreaField), so both hosts already opened an editor for it. Onorigin/mainthe pin "the details body shows the inline-edit affordance on a textarea row" is green, and the row in edit mode renders exactly one editor: the one-line terminal input.textareainDETAIL_ROUTED_INLINE_TYPES,inlineCredentialGate.test.tsxfails "every exempted type is a member of the shared exclusion (no free-floating entries)" with "textarea must be in the shared set". Nothing else changes.The substance of the ruling lands as written. The row routes
textareatoTextAreaField, and the drift guard moves it from "benign" to "routed". The route lives wheremarkdown's editor lives:INLINE_ROUTED_FIELD_TYPESand the editor branch.The defect, measured
On
origin/main072b7e8,textareaedited in the terminal input, an INPUT element of type text. The browser strips line breaks from the value such an input is given. A stored note"Call back Monday.\n\nBudget approved, needs legal review.\n"showed as"Call back Monday.Budget approved, needs legal review.". One keystroke made that flattened string the value the Save batch wrote.Pins
New file
InlineFieldInput.textareaEditor-11562.test.tsx. The multi-line value has a blank line inside and a trailing newline, and every comparison is byte for byte.InlineFieldInput: a TEXTAREA seeded with the stored value, never the terminal input. One keystroke appended to what the editor shows emits the stored text plus that keystroke.autoFocuslands on it.DetailSection: the pencil shows on a textarea row. Edit mode renders one editor, seeded byte-identical.HeaderHighlight: the same editor inside the edit session.InlineEditProvider+DetailSection+InlineEditSaveBarover a store-backedupdate. The PATCH body is exactly the edited string, the store holds it, and re-entering edit seeds the editor with it."Call back Monday.". Both are green onorigin/mainand after the fix, so a single-line value saves exactly as before.FieldEditWidget, whichObjectGrid's cell editor delegates to, seeds a TEXTAREA with the multi-line value byte for byte. This PR does not touch that path. The pin records that the row and the cell now edit with one widget.Verification
All at
5af2bb9(the only commit), from the worktree.pnpm --workspace-concurrency=2 --filter "@object-ui/plugin-detail^..." build: exit 0. 12 projects in scope, all 11 with a build script printed Done (test-supporthas none).pnpm exec vitest run --maxWorkers=2 packages/plugin-detail/: Test Files 233 passed, 1 skipped (234). Tests 2313 passed, 8 skipped (2321).pnpm --filter @object-ui/plugin-detail run type-check: exit 0.tsc -p tsconfig.test.json --listFileslists all three touched test files.--no-inline-config --format json): 4 files, 0 errors. The three edited files carry the same warning counts as at072b7e8(42, 1 and 0, allno-explicit-anyorreact-refresh), and the new file carries none.eslint.config.jssets noparserOptionsproject, so linting is not type-aware and this diff cannot change the result for an untouched file.check:control-bytes,check:new-line-citations(0 new),check:changeset-claims,check:pending-changeset-literals,check-changeset-presence,check-changeset-overwrite,check-changeset-no-major,check-changeset-fixed,check-test-path-roots, the threecheck-vi-mock-*checks,check-unreferenced-sources,check-type-check-coverage,check-lint-coverage: all exit 0.Ablations, after the commit. Each mutation went through objectstack's
ablation-replace.mjs, or a trap-armed whole-file swap for leg C. Each restore is proven by the blob hash equal to HEAD's and an emptygit diff HEAD. Each leg ran the new pin file, the drift guard and the delegation suite.textareaput back intoINLINE_PLAIN_TEXT_FIELD_TYPES: 2 failed, 113 passed. The drift guard's "no type is claimed twice" and its benign-list pin fail. The new pins stay green because the routed branch runs before the class-D test. A first attempt at this leg did not run: the tool refused an anchor that its own replacement contained, and nothing was measured.textareadisjunct deleted: green, 115 passed. This direction is the expected one. The type is no longer class D, so it falls to the delegation tail, andFieldEditWidgetrenders the sameTextAreaField. See the acceptance notes.InlineFieldInput.tsxswapped whole to072b7e8(byte-identical toorigin/main): 9 failed, 106 passed. 7 are in the new pin file: every multi-line pin and every pin on the editor's kind. The 2 single-line controls stay green. The other 2 are in the drift guard.textareaadded toDETAIL_ROUTED_INLINE_TYPES(withinlineCredentialGate.test.tsxin the run): 1 failed, 151 passed, as described above.CI runs the full farm. Locally only
plugin-detailwas run. The plugin-detail sets this PR edits are not exported from the package index, and outsideplugin-detailno test imports them or queries the terminal input on atextarearow.Acceptance notes
textareathe explicit branch and the delegation tail reach the same widget. So the drift guard cannot tell a routedtextareafrom a delegated one: deleting the branch alone stays green, and the user still getsTextAreaField. The branch follows the ruling's "routed" bucket andmarkdown's precedent. What the pins do guard is the actual regression,textarealanding back on the one-line input (leg C, and leg A at the guard).RecordDetailPanel, whichplugin-gridimports from this package) renders the same detail hosts, so it gets the multi-line editor too. The grid CELL still edits withFieldEditWidget, unchanged.packages/plugin-detail/README.mdis not touched. objectui#11512 edits it, and it does not describe per-type inline editors. Nocontent/docspage lists which editor a detail row uses per type, so no guide page changes.notes: Field.textareaon objectstackexamples/app-crm's lead andexamples/app-showcase's task.Generated by Claude Code