From 956f30d48f6ed9ba58297794b2542578c92aefd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=91=A8=E6=B6=9B?= Date: Mon, 29 Jun 2026 12:21:42 -0700 Subject: [PATCH] feat(spec): add typed detail.stageField key for record:path stepper The detail-page synth (@object-ui/plugin-detail) already reads def.detail?.stageField to drive or disable the auto status-path stepper (record:path), but it only survived via the detail block's .passthrough(), so authors got no type/autocomplete and no way to discover the switch. Declare it explicitly alongside renderViaSchema/hideReferenceRail/ hideRelatedTab: string forces a status field, false/null disables the stepper (for non-linear status picklists). .passthrough() kept for back-compat. Type matches the synth's string | false | null. Closes #2452 --- .changeset/detail-stagefield-typed.md | 13 +++++++++++++ packages/spec/src/data/object.zod.ts | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 .changeset/detail-stagefield-typed.md diff --git a/.changeset/detail-stagefield-typed.md b/.changeset/detail-stagefield-typed.md new file mode 100644 index 0000000000..1aa791688f --- /dev/null +++ b/.changeset/detail-stagefield-typed.md @@ -0,0 +1,13 @@ +--- +'@objectstack/spec': patch +--- + +feat(spec): add a typed `stageField` key to the object `detail` block + +The detail-page synth (`@object-ui/plugin-detail`) already reads +`def.detail?.stageField` to drive — or disable — the auto status-path stepper +(`record:path`). It only survived via the `detail` block's `.passthrough()`, so +authors got no type or autocomplete and no way to discover the switch. Declare +it explicitly: `string` forces a status field, `false`/`null` disables the +stepper (use it when `status` is a non-linear picklist). `.passthrough()` is +kept for back-compat. diff --git a/packages/spec/src/data/object.zod.ts b/packages/spec/src/data/object.zod.ts index 5d3f5c9351..f8e7006fcc 100644 --- a/packages/spec/src/data/object.zod.ts +++ b/packages/spec/src/data/object.zod.ts @@ -707,11 +707,18 @@ const ObjectSchemaBase = z.object({ * - `hideRelatedTab=true` suppresses the "Related" tab. By default the * synth removes the Related tab automatically when the rail is shown to * avoid duplication; set this flag to force hide/show regardless. + * - `stageField` controls the auto status-path stepper (`record:path`). + * A field name forces that field; `false`/`null` disables the stepper — + * use it when `status` is a non-linear picklist (active/paused/voided) + * that shouldn't render as an ordered Path. Omit it to let the synth + * auto-detect (status/stage/state/phase, or a status/stage-typed field). */ detail: z.object({ renderViaSchema: z.boolean().optional().describe('Opt this object out of the schema-driven detail renderer'), hideReferenceRail: z.boolean().optional().describe('Suppress the right-hand reference-rail on the detail page'), hideRelatedTab: z.boolean().optional().describe('Suppress the Related tab on the detail page'), + stageField: z.union([z.string(), z.literal(false), z.null()]).optional() + .describe('record:path status field name; false/null disables the auto status-path stepper'), }).passthrough().optional().describe('Detail-page UI hints consumed by @object-ui/plugin-detail synth'), /**