Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/25511-hide-empty-describe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@objectstack/spec': minor
---

spec(ui): `record:details` section `hideEmpty: false` — in read-only mode an all-empty section renders its heading plus one fold row, and the `describe()` text says so

Clause-②: no
Metadata-protocol: semantic

The meaning of `hideEmpty: false` on a `record:details` section changes for a section whose fields are ALL empty (for example on a brand-new record):

- **Read-only mode:** the section renders its heading plus one fold row that counts the empty fields and reveals them on request — the same fold a partly-filled section already uses. It no longer renders a column of empty rows.
- **Edit mode:** unchanged. Every field renders as an editable row.

Nothing else changes. No key is added, removed or renamed; the shape and the default are the same. Leaving `hideEmpty` out (or writing `true`) still means an all-empty section renders nothing at all: no heading, no skeleton. A partly-filled section's empty rows are not governed by this key, in either value. Authored metadata needs no change: a section that writes `hideEmpty: false` to keep its heading on an empty record keeps it.

The `describe()` text, which the reference docs and the JSON Schema read, now states this. Its lead changes from "Hide this section's empty fields" to "Whether this section disappears when ALL its fields are empty", because under the new reading both values hide an all-empty section's empty rows in read-only mode and the old lead no longer told them apart. The renderer change is in objectui's record detail section.
2 changes: 1 addition & 1 deletion content/docs/references/ui/component.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,7 @@ View filter rule
| **columns** | `integer` | optional | Field-grid columns for this section (1-4). Omitted → the renderer derives the width. |
| **group** | `string` | optional | Field group key (snake_case) whose members and presentation this section inherits, from the object's `fieldGroups` (ADR-0085 §5 `deriveFieldGroupLayout`). Mutually exclusive with `fields`, and with every key the group itself declares (`name`, `label`, `icon`, `description`, `collapsible`, `defaultCollapsed`). Must name a declared group — checked by reference diagnostics. |
| **fields** | `string[]` | optional | Field names rendered in this section, in order. Omit only when `group` supplies the members instead. |
| **hideEmpty** | `boolean` | optional | Hide this section's empty fields (renderer default: on — and a section whose fields are ALL empty then renders nothing at all: no heading, no skeleton). Set `false` to render empty rows, keeping the section's label skeleton on an all-empty record (e.g. a brand-new one). |
| **hideEmpty** | `boolean` | optional | Whether this section disappears when ALL its fields are empty (renderer default: on — it then renders nothing at all: no heading, no skeleton). Set `false` to keep it on an all-empty record (e.g. a brand-new one): in read-only mode it renders its heading plus one fold row that counts the empty fields and reveals them on request — the same fold a partly-filled section uses; in edit mode it renders every field as an editable row. |
| **collapsible** | `boolean` | optional | Render this section as a collapsible card — the heading becomes a chevron toggle, initially expanded (renderer default: off). |
| **showBorder** | `boolean` | optional | Draw this section's card chrome (renderer default: derived — on for a titled section, off for an untitled one). Set `false` for a borderless titled section, or `true` for a bordered untitled one. |
| **defaultCollapsed** | `boolean` | optional | Start a `collapsible: true` section collapsed (renderer default: expanded). Consulted only when `collapsible` is on — a non-collapsible section never reads its collapse state. |
Expand Down
13 changes: 12 additions & 1 deletion packages/spec/src/ui/component.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1436,8 +1436,19 @@ export const RecordDetailsProps = strictObject({
* asked for the default". Defaults in the describe() texts are MEASURED on
* the renderer (read points recorded in `liveness/page.json`, row
* `regions`), not transcribed from a TS interface.
*
* What `hideEmpty: false` renders was re-ruled (ruling C on
* objectstack-ai/objectui#13386, maintainer 2026-10-23): in read-only mode
* an all-empty section renders its heading plus ONE fold row — the same
* fold a partly-filled section uses — instead of a column of empty rows;
* edit mode is unchanged and renders every row, editable. No key, shape or
* default changed, and the describe() states the ruled rendering, which
* objectui's `DetailSection` follows. The key governs only the ALL-empty
* case: a partly-filled section's empty rows follow the renderer's own
* fold (objectui#7129 Q2-C) in either polarity, so the old lead "hide this
* section's empty fields" no longer told the two values apart.
*/
hideEmpty: z.boolean().optional().describe('Hide this section\'s empty fields (renderer default: on — and a section whose fields are ALL empty then renders nothing at all: no heading, no skeleton). Set `false` to render empty rows, keeping the section\'s label skeleton on an all-empty record (e.g. a brand-new one).'),
hideEmpty: z.boolean().optional().describe('Whether this section disappears when ALL its fields are empty (renderer default: on — it then renders nothing at all: no heading, no skeleton). Set `false` to keep it on an all-empty record (e.g. a brand-new one): in read-only mode it renders its heading plus one fold row that counts the empty fields and reveals them on request — the same fold a partly-filled section uses; in edit mode it renders every field as an editable row.'),
/** Collapsible card. Initial state is expanded; the toggle is the heading. */
collapsible: z.boolean().optional().describe('Render this section as a collapsible card — the heading becomes a chevron toggle, initially expanded (renderer default: off).'),
/** Card chrome; the renderer derives it from the presence of a title. */
Expand Down
Loading