…tForm
`DrawerForm` / `ModalForm` replaced the generated field set with a
non-empty `customFields`, while `ObjectForm`'s default arm merges it
(objectui#9778) and the registered description of the key is one sentence
for every `formType`. The merge rule now lives in one module-private helper,
`customFieldsMerge.ts`, called by ObjectForm and by the shared flat builder
the two overlay containers use. `customFields` no longer switches the
fieldGroups fallback or the modal's auto-layout off, matching ObjectForm,
and a derived group resolves an authored member as its whole definition.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S
Fixes #10073
Clause-②: no
What
object-form.customFieldsis registered with one description for everyformType: "Field definitions merged over the set generated from object metadata." The default arm has merged since objectui#9778. Thedrawerandmodalarms (ObjectFormspreads the whole schema intoDrawerForm/ModalForm) still REPLACED the generated set with the members. They now merge the same way.packages/plugin-form/src/customFieldsMerge.ts(not re-exported from the barrel).mergeCustomFieldsholds the whole rule: override by name in place, keep the rest, append unmatched members in authored order. An emptycustomFieldscounts as unauthored.ObjectForm.tsx: the inline override lookup and the append block moved into that helper. The generator body is byte-identical apart frompushbecomingreturn.flatFields.ts(buildFlatFields, the one flat builderDrawerFormandModalFormshare) takescustomFieldsand routes through the same helper.DrawerForm.tsx/ModalForm.tsx: thesetFormFields(schema.customFields)early return is gone, and the builder getscustomFields.fieldGroups derivation (PM mechanism assumption 4), measured
ObjectFormdoes not switch thefieldGroupsfallback off forcustomFields.fieldGroupSectionsis gated onschema.sectionsonly and is derived fromgroupableFields, which comes from the mergedformFields. Its grouped render then resolves each section's names against that merged pool, so a member renders as its own definition inside the group its owngroupkey names. This behaviour is unambiguous, so no open question was needed. Drawer and modal now do the same:schema.customFields?.lengthshort-circuit is dropped from bothderivedSectionsmemos;withCustomFieldMembers). The drawer and modal build a derived section body throughbuildSectionFields, which regenerates a NAME from the object schema but passes a runtimeFormFieldthrough verbatim. Names no member supplies are unchanged, so forms withoutcustomFieldsresolve as before;customFields.ObjectFormauto-lays-out the merged list, and the modal's flat render already did (it fell back toapplyAutoLayoutat render). Only the inferredmodalSizechanges.The collapse regions,
projectSectionDividerand the divider pushes (objectui#9849 step 2) are untouched.Evidence (HEAD
a54b97d)__tests__/drawerModalCustomFieldsMerge-10073.test.tsx. It runs through the realObjectFormfor each ofsimple/drawer/modal, with rows OVERRIDE, KEEP, APPEND, NO DATA SOURCE and FIELD GROUPS. 15 passed.0aaceccunder a trap, helper and ObjectForm at HEAD): 8 failed, 7 passed. The failures are exactly the drawer and modal OVERRIDE / KEEP / APPEND / FIELD GROUPS rows. The 5simplerows (the lit control) and the 2 no-data-source rows stay green. Restore was proven by the blob hash equalling HEAD and an emptygit diff HEAD.DrawerForm.tsx(scripts/ablation-replace.mjs, anchor 1 to 0): the drawer FIELD GROUPS row goes red withexpected 'Channel' to be 'INLINE CHANNEL'. Restored to blob == HEAD.vitest run packages/plugin-form/: 113 files, 1110 passed, 1 skipped.pnpm --filter @object-ui/plugin-form type-check(after building the^...closure of 10 packages): exit 0.apps/console/src/__tests__/registry-inputs-spec-parity.test.ts: 199 passed.check:new-line-citations,check:control-bytes,check:unreferenced-sources,check:changeset-claims,check:pending-changeset-literalsandcheck:test-path-rootsgates all exit 0.origin/mainwas still0aaceccat PR time, so the merge was a no-op.Acceptance notes
getObjectSchemafails,ObjectFormfalls back to the members only (objectui#9778), while drawer and modal show their error panel, as they did before this PR. The registered description does not cover a failing adapter.fieldkey is read bybuildSectionFieldsas the spec shape. Runtime members carry the metadata object there.sectionspluscustomFields, the drawer and modal build section fields from the object schema and ignore the members. The default arm resolves them from the merged pool. Probe on HEAD, same schema per arm:simple:INLINE NOTE,drawer:Note,modal:Note.Session:
https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3SGenerated by Claude Code