From d040f04e939c7c935443ec40c43b1b35ff013c1f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 11:05:57 +0000 Subject: [PATCH] docs(objectui): remove phantom tab-level lazy/source and badge/badgeVariant from layout-dsl The Tabs family in content/docs/protocol/objectui/layout-dsl.mdx taught four keys that exist on no schema, plus a wrapper shape the form schema rejects. Measured against packages/spec/authorable-surface/ (7840 authorable keys): - `lazy` returns 0 hits across the ENTIRE authorable surface, not just ui. Positive controls, same command shape: `source` 19, `badge` 8, `badgeVariant` 8, `pagination` 2 - the instrument plainly sees keys. (A bare grep for `lazy` in packages/spec/src/ui/view.zod.ts hits only the `lazySchema` import helper - position, not count.) - All 8 `badge` / `badgeVariant` entries are on NavItem surfaces (ui/ObjectNavItem and siblings) - app navigation, never a form tab. None of the 19 `source` entries is a tab or a section. - ui/ViewTab declares exactly nine keys: filter, icon, isDefault, label, name, order, pinned, view, visible - and it is a LIST view surface (ListViewSchema.tabs / UserFiltersSchema.tabs), not a form surface. - FormViewSchema.layout is a string enum (vertical/horizontal/inline/grid) and FormViewSchema declares no `tabs` key at all, so the `layout: {mode: tabbed, tabs: [...]}` wrapper was wrong independently of the leaf keys. The real shape is `type: tabbed` + `sections`, each section rendering as its own tab (defaultTab / tabPosition), as content/docs/protocol/objectui/index.mdx and examples/app-showcase/src/ui/views/task.view.ts already author it. ViewTabSchema, FormViewSchema and FormSectionSchema are all strictObject, so these were parse REJECTIONS, not silent strips. Fixed by removal/rewrite following PR #8301's shape on this same page, including its "loud absence" style - never by widening a schema. The page's internal inconsistency is gone as a side effect: its ## Performance section stated an absence an earlier passage demonstrated as working syntax. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Jqe56GnYFddggeAyfkZFVz --- content/docs/protocol/objectui/layout-dsl.mdx | 104 +++++++++--------- 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/content/docs/protocol/objectui/layout-dsl.mdx b/content/docs/protocol/objectui/layout-dsl.mdx index 8858ebf1bf..ea26d82b5f 100644 --- a/content/docs/protocol/objectui/layout-dsl.mdx +++ b/content/docs/protocol/objectui/layout-dsl.mdx @@ -429,34 +429,32 @@ Address ## Tabs: Multi-Page Layouts -Organize large forms into tabbed sections. +Organize large forms into tabs. A tabbed form has **no separate tab list** — set +`type: tabbed` and **every section renders as its own tab**, in declaration +order. `defaultTab` names the section that opens first; `tabPosition` places the +strip. ### Basic Tabs ```yaml -layout: - mode: tabbed - tabs: - - name: details - label: Details - icon: file-text - sections: - - label: Basic Info - fields: [name, email, phone] - - - name: address - label: Address - icon: map-pin - sections: - - label: Primary Address - fields: [street, city, state, zip] - - - name: preferences - label: Preferences - icon: settings - sections: - - label: Notifications - fields: [email_notifications, sms_notifications] +type: tabbed +tabPosition: top # top | bottom | left | right +defaultTab: details # a section `name` + +sections: + - name: details + label: Details + columns: 2 + fields: [name, email, phone] + + - name: address + label: Address + columns: 2 + fields: [street, city, state, zip] + + - name: preferences + label: Preferences + fields: [email_notifications, sms_notifications] ``` **Rendered:** @@ -465,7 +463,6 @@ layout: │ [Details] [Address] [Preferences] │ ├──────────────────────────────────────────────────┤ │ │ -│ Basic Info │ │ Name: __________________________________________│ │ Email: __________________________________________│ │ Phone: __________________________________________│ @@ -473,38 +470,37 @@ layout: └──────────────────────────────────────────────────┘ ``` -### Lazy-Loaded Tabs - -Load tab content only when clicked (performance optimization): +### A tab carries no options of its own -```yaml -tabs: - - name: details - label: Details - lazy: false # Load immediately - - - name: history - label: History (1,234 records) - lazy: true # Load when tab clicked - source: /api/customers/123/history -``` +The tab *is* the section, so a section's keys are the whole surface: `name`, +`label`, `description`, `fields`, `columns`, `collapsible`, `collapsed`, +`visibleWhen` — plus `pane`, which split forms alone accept. There is **no** +per-tab `lazy`, `source`, `badge` or `badgeVariant` key, and no +`layout: { mode: tabbed, ... }` wrapper: `FormViewSchema.layout` is a string +enum (`vertical` / `horizontal` / `inline` / `grid`) and the form schema +declares no `tabs` key at all. `FormViewSchema` and `FormSectionSchema` +(`packages/spec/src/ui/view.zod.ts`) are `.strict()`, so authoring any of them +is a **parse failure** — a loud rejection, not a silent no-op. -### Tab Badges and Counters + + Earlier revisions of this page documented tab-level `lazy` / `source` and tab + `badge` / `badgeVariant` (both the scalar `badge: 5` + `badgeVariant: danger` + form and the object `badge: { count, variant }` form), nested under a + `layout: { mode: tabbed, tabs: [...] }` wrapper. None of them existed on any + schema — `lazy` is authorable **nowhere** in the spec — so they are **removed + rather than implemented**; deferred tab loading is an implementation card + first. Counter-badges are real, but on app **navigation** items (`badge` / + `badgeVariant` on `ui/ObjectNavItem` and its siblings), never on a form tab. + For the keys a section really accepts, see the + [View Reference](/docs/references/ui/view). + -```yaml -tabs: - - name: details - label: Details - - - name: tasks - label: Tasks - badge: 5 # Show "5" badge - badgeVariant: danger # Red badge - - - name: notes - label: Notes - badge: { count: 12, variant: info } -``` +Looking for tabs that carry their own `name`, `icon`, `filter`, `order`, +`pinned` and `isDefault`? That surface exists, but it belongs to **list** views, +not forms: `ui/ViewTab` declares exactly nine keys (`filter`, `icon`, +`isDefault`, `label`, `name`, `order`, `pinned`, `view`, `visible`), and each +tab points at a named list view. See +[View Reference → ViewTab](/docs/references/ui/view#viewtab). ## Responsive Layout Modifiers