Commit ab18797
fix(plugin-detail): record:details edit mode edits a textarea field in a multi-line textarea (objectui#11562) (#11567)
Fixes #11562
Clause-②: no
## What changed
`record:details` edit mode now edits a `textarea` field in the fields
package's multi-line `TextAreaField`, so a save keeps the line breaks
the value was stored with.
- `packages/plugin-detail/src/InlineFieldInput.tsx`: `textarea` leaves
`INLINE_PLAIN_TEXT_FIELD_TYPES` (class D, objectui#4220) and joins
`INLINE_ROUTED_FIELD_TYPES`. It takes the branch `markdown` got in
objectui#11541, which renders `TextAreaField`. The set's docblock drops
the warning objectui#11541 wrote about `textarea`. Its "nothing is lost"
sentence now covers only the single-line members left: `text`, `email`,
`phone`, `url`.
- Drift guard `inlineEditTypeCoverage.test.tsx`: `textarea` moves from
`benign` to `routed`. The benign bucket's wording now says single-line.
- `InlineFieldInput.delegation.test.tsx`: `textarea` leaves the class-D
loop. The class-D pins for `text`, `email`, `url` and `phone` are
unchanged and green.
- New pin file `InlineFieldInput.textareaEditor-11562.test.tsx`.
- One `@object-ui/plugin-detail` patch changeset.
## Deviation from the ruling's mechanism words:
`DETAIL_ROUTED_INLINE_TYPES` is untouched
The ruling reads "Route `textarea` through `DETAIL_ROUTED_INLINE_TYPES`
to the fields package's multi-line `TextAreaField`". The PR does not add
`textarea` to that set. Measured, it is the wrong lever for this type:
- `DETAIL_ROUTED_INLINE_TYPES` exists only to exempt members of the
fields package's shared `INLINE_EXCLUDED_FIELD_TYPES` from the detail
hosts' gate. `markdown` needed it because `markdown` is in that set.
`textarea` is not (`EDIT_WIDGETS` maps it to `TextAreaField`), so both
hosts already opened an editor for it. On `origin/main` the 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.
- Adding it anyway is refused by an existing pin. Probe leg D below:
with `textarea` in `DETAIL_ROUTED_INLINE_TYPES`,
`inlineCredentialGate.test.tsx` fails "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 `textarea`
to `TextAreaField`, and the drift guard moves it from "benign" to
"routed". The route lives where `markdown`'s editor lives:
`INLINE_ROUTED_FIELD_TYPES` and the editor branch.
## The defect, measured
On `origin/main` `072b7e8`, `textarea` edited 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. `autoFocus` lands 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.
- Save round trip: `InlineEditProvider` + `DetailSection` +
`InlineEditSaveBar` over a store-backed `update`. The PATCH body is
exactly the edited string, the store holds it, and re-entering edit
seeds the editor with it.
- Single-line control: the keystroke pin and the round trip also run
with `"Call back Monday."`. Both are green on `origin/main` and after
the fix, so a single-line value saves exactly as before.
- Grid cell: `FieldEditWidget`, which `ObjectGrid`'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-support` has 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 --listFiles` lists all three touched test files.
- eslint over the 4 touched source and test files (`--no-inline-config
--format json`): 4 files, 0 errors. The three edited files carry the
same warning counts as at `072b7e8` (42, 1 and 0, all `no-explicit-any`
or `react-refresh`), and the new file carries none. `eslint.config.js`
sets no `parserOptions` project, 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 three `check-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 empty `git
diff HEAD`. Each leg ran the new pin file, the drift guard and the
delegation suite.
- Leg A, `textarea` put back into `INLINE_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.
- Leg B, only the branch's `textarea` disjunct deleted: green, 115
passed. This direction is the expected one. The type is no longer class
D, so it falls to the delegation tail, and `FieldEditWidget` renders the
same `TextAreaField`. See the acceptance notes.
- Leg C, `InlineFieldInput.tsx` swapped whole to `072b7e8`
(byte-identical to `origin/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.
- Leg D, the ruling's mechanism words: `textarea` added to
`DETAIL_ROUTED_INLINE_TYPES` (with `inlineCredentialGate.test.tsx` in
the run): 1 failed, 151 passed, as described above.
CI runs the full farm. Locally only `plugin-detail` was run. The
plugin-detail sets this PR edits are not exported from the package
index, and outside `plugin-detail` no test imports them or queries the
terminal input on a `textarea` row.
## Acceptance notes
- Leg B shows that for `textarea` the explicit branch and the delegation
tail reach the same widget. So the drift guard cannot tell a routed
`textarea` from a delegated one: deleting the branch alone stays green,
and the user still gets `TextAreaField`. The branch follows the ruling's
"routed" bucket and `markdown`'s precedent. What the pins do guard is
the actual regression, `textarea` landing back on the one-line input
(leg C, and leg A at the guard).
- The grid's record overlay (`RecordDetailPanel`, which `plugin-grid`
imports from this package) renders the same detail hosts, so it gets the
multi-line editor too. The grid CELL still edits with `FieldEditWidget`,
unchanged.
- `packages/plugin-detail/README.md` is not touched. objectui#11512
edits it, and it does not describe per-type inline editors. No
`content/docs` page lists which editor a detail row uses per type, so no
guide page changes.
- Reach, from the card: `notes: Field.textarea` on objectstack
`examples/app-crm`'s lead and `examples/app-showcase`'s task.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FjqrwXPfSMkSfkKYDSRkN2)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent dbd1081 commit ab18797
5 files changed
Lines changed: 295 additions & 28 deletions
File tree
- .changeset
- packages/plugin-detail/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
89 | 87 | | |
90 | 88 | | |
91 | 89 | | |
92 | | - | |
93 | 90 | | |
94 | 91 | | |
95 | 92 | | |
| |||
145 | 142 | | |
146 | 143 | | |
147 | 144 | | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
148 | 149 | | |
149 | 150 | | |
150 | 151 | | |
| |||
412 | 413 | | |
413 | 414 | | |
414 | 415 | | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
425 | 428 | | |
426 | 429 | | |
427 | 430 | | |
| |||
Lines changed: 4 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
361 | 361 | | |
362 | 362 | | |
363 | 363 | | |
364 | | - | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
365 | 368 | | |
366 | 369 | | |
367 | 370 | | |
| |||
Lines changed: 235 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
0 commit comments