Skip to content

Commit ce1d8ce

Browse files
committed
docs(spec): regenerate component.mdx on the merged tree
The merge of main brought the object-grid typed members; component.mdx is generated, so it is regenerated from the merged tree rather than text-merged. Against main's copy: 14 rows move, every one adding `?` to a defaulted member, none removing one. Every shared def on the page now renders one face. Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude <noreply@anthropic.com>
1 parent bd4e93b commit ce1d8ce

1 file changed

Lines changed: 69 additions & 9 deletions

File tree

‎content/docs/references/ui/component.mdx‎

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -704,28 +704,28 @@ Sort field and direction pair
704704
| **showPagination** | `boolean` | optional | Show the pager (read only when `pagination` is absent) |
705705
| **searchableFields** | `string[]` | optional | Fields the toolbar search queries; a non-empty list enables search |
706706
| **showSearch** | `boolean` | optional | Show the search box (read only when `searchableFields` is absent) |
707-
| **rowHeight** | `any` | optional | Row density mode (e.g. compact / comfortable) |
707+
| **rowHeight** | `Enum<'compact' \| 'short' \| 'medium' \| 'tall' \| 'extra_tall'>` | optional | Row height — one of `compact`, `short`, `medium`, `tall`, `extra_tall`; the same values a list view's `rowHeight` takes |
708708
| **grouping** | `{ fields: object[] }` | optional | Row grouping config |
709-
| **aggregations** | `any` | optional | Group aggregation config (sum/avg/… per column) |
710-
| **conditionalFormatting** | `any` | optional | Conditional row/cell formatting rules |
711-
| **rowColor** | `any` | optional | Row color rules |
709+
| **aggregations** | `{ field: string; type: Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max' \| 'count_distinct'> }[]` | optional | Per-group aggregations drawn in a grouped grid's group headers — `[{ field, type }]`, `type` one of `count`, `sum`, `avg`, `min`, `max`, `count_distinct` (`count` is the group's row count, whatever `field` names) |
710+
| **conditionalFormatting** | `{ condition: string \| object; style: Record<string, string> }[]` | optional | Conditional formatting rules — `[{ condition, style }]`, the same rules a list view declares: the first rule whose CEL `condition` holds applies its CSS `style` map to the row |
711+
| **rowColor** | `{ field: string; colors?: Record<string, string> }` | optional | Row colour by field value — `{ field, colors }`, the same block a list view's `rowColor` declares |
712712
| **selection** | `any` | optional | Selection config (`{ type: none \| single \| multiple }`) |
713713
| **selectable** | `any` | optional | Legacy selection shorthand, read only when `selection` is absent. Prefer `selection` |
714714
| **rowActions** | `any[]` | optional | Per-row action names |
715715
| **bulkActions** | `any[]` | optional | Bulk action names shown on selection |
716716
| **batchActions** | `any[]` | optional | Alternate spelling the renderer reads FIRST (`batchActions ?? bulkActions`) |
717-
| **bulkActionDefs** | `any[]` | optional | Inline bulk-action definitions (full defs, not names) |
718-
| **navigation** | `any` | optional | Row-click navigation config (`{ mode: page \| drawer \| modal \| split \| popover \| new_window \| none }`) — all seven `NavigationModeSchema` values, since the shared `useNavigationOverlay` hook types its own mode union as that schema |
717+
| **bulkActionDefs** | `{ name: string; label?: string; icon?: string; variant?: Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'outline'>; … }[]` | optional | Inline bulk-action definitions (full defs, not names) — the same `BulkActionDef` entries a list view's `bulkActionDefs` declares |
718+
| **navigation** | `{ mode?: Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>; preventNavigation?: boolean; openNewTab?: boolean; size?: Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>; … }` | optional | Row-click navigation config — the same block `ListViewSchema.navigation` declares (`{ mode, size, openNewTab, preventNavigation }`) |
719719
| **editable** | `boolean` | optional | Enable inline cell editing |
720720
| **singleClickEdit** | `boolean` | optional | Enter cell edit on single click (default true when editable) |
721721
| **keyboardNavigation** | `boolean` | optional | [EXPERIMENTAL — not enforced] Arrow-key cell navigation on the WAI-ARIA grid pattern. Defaults to on when `editable` is set; a read-only grid keeps its Tab behaviour unless this is `true`. No renderer reads it yet: it is declared ahead of the grid's keyboard-navigation build, so authoring it changes nothing today |
722-
| **resizable** | `boolean` | optional | Allow column resize (read before `resizableColumns`) |
723-
| **resizableColumns** | `boolean` | optional | Alternate spelling of `resizable` (the renderer reads `resizable ?? resizableColumns`) |
722+
| **resizable** | `boolean` | optional | Allow column resize (the renderer default is on) |
723+
| **resizableColumns** | `never` | optional | [REMOVED] `object-grid` property `resizableColumns` was removed in @objectstack/spec 17.7.0 (ADR-0049) — it was the legacy second spelling of `resizable`, read only when `resizable` was absent, so one switch had two spellings and a grid authoring both silently ignored this one. Use `resizable`. Rename the key; the value (a boolean) is unchanged. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; apply them by hand. |
724724
| **reorderableColumns** | `boolean` | optional | Allow column drag-reorder |
725725
| **frozenColumns** | `number` | optional | How many leading columns stay frozen (default 1) |
726726
| **showColumnTypeIcons** | `boolean` | optional | Show field-type icons in column headers |
727727
| **exportOptions** | `{ formats?: Enum<'csv' \| 'xlsx' \| 'json'>[]; maxRecords?: integer; includeHeaders?: boolean; fileNamePrefix?: string; … }` | optional | Export config — the object `{ formats?, maxRecords?, includeHeaders?, fileNamePrefix?, streaming? }`, the same block a list view's `exportOptions` declares, with `formats` drawn from `csv`, `xlsx` and `json`. A bare format array is refused: the grid reads `exportOptions.formats`, so write `{ formats: ['csv', 'xlsx'] }` |
728-
| **operations** | `any` | optional | Operation toggles (`{ export: false, … }`) |
728+
| **operations** | `{ create?: boolean; update?: boolean; delete?: boolean; export?: boolean }` | optional | Built-in affordance toggles `{ create?, update?, delete?, export? }` (booleans). A declared block replaces the grid's default: `update` / `delete` not named are withheld from the row menu, `create` enables the add-row affordance, and `export: false` hides the export menu |
729729
| **data** | `{ provider: 'object'; object: string } \| { provider: 'api'; read?: object; write?: object } \| { provider: 'value'; items: any[] } \| { provider: 'schema'; schemaId: string; schema?: Record<string, any> }` | optional | Data source binding (ViewDataSchema — discriminated on `provider`: object \| api \| value \| schema). Static inline rows live at `{ provider: 'value', items: [...] }`; the bare-array shortcut is refused — see migration `object-grid-data-view-data-converged` |
730730
| **staticData** | `any[]` | optional | Deprecated bare-array static-rows shortcut the renderer still reads. Prefer `data: { provider: 'value', items: [...] }` |
731731

@@ -772,6 +772,57 @@ Sort field and direction pair
772772
| :--- | :--- | :--- | :--- |
773773
| **fields** | `{ field: string; order?: Enum<'asc' \| 'desc'>; collapsed?: boolean }[]` | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field); the same order as the group header query's `groupBy` |
774774

775+
### Nested Shape: `ObjectGridProps.aggregations[number]`
776+
777+
| Property | Type | Required | Description |
778+
| :--- | :--- | :--- | :--- |
779+
| **field** | `string` | ✅ | Field whose values the function aggregates within each group (ignored by `count`) |
780+
| **type** | `Enum<'count' \| 'sum' \| 'avg' \| 'min' \| 'max' \| 'count_distinct'>` | ✅ | Aggregation function — `count` (the group's row count), `sum`, `avg`, `min`, `max` or `count_distinct` |
781+
782+
### Nested Shape: `ObjectGridProps.conditionalFormatting[number]`
783+
784+
| Property | Type | Required | Description |
785+
| :--- | :--- | :--- | :--- |
786+
| **condition** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | ✅ | Predicate (CEL) to evaluate. |
787+
| **style** | `Record<string, string>` | ✅ | CSS styles to apply when condition is true |
788+
789+
### Nested Shape: `ObjectGridProps.rowColor`
790+
791+
| Property | Type | Required | Description |
792+
| :--- | :--- | :--- | :--- |
793+
| **field** | `string` | ✅ | Field whose value is looked up in the `colors` map below to pick a row colour (typically a select/status field). The map is what does the colouring — with no `colors`, no row is ever coloured, whatever this field holds. Author-time diagnostic `view/row-color-without-colors` reports that combination. |
794+
| **colors** | `Record<string, string>` | optional | Map of field value to row colour. The spellings that actually paint a row are not free-form: objectui `plugin-grid`'s `useRowColor` hands a value already written as a complete Tailwind background class (`bg-red-200`) straight through, otherwise lower-cases and trims it and resolves it through its own closed vocabulary of colour NAMES (`red`, `blue`, `slate`, … each mapping to `bg-NAME-100`), and returns undefined for anything else. A hex, an `rgb()` or a CSS variable parses here, publishes, and colours no row — Tailwind v4 has no runtime, so no class can be fabricated from one. Author-time diagnostic `view/row-color-unresolvable-value` reports a value that cannot resolve. |
795+
796+
### Nested Shape: `ObjectGridProps.bulkActionDefs[number]`
797+
798+
| Property | Type | Required | Description |
799+
| :--- | :--- | :--- | :--- |
800+
| **name** | `string` | ✅ | Stable identifier — the audit-log action key, and (for an aggregate def) the name of the object action to dispatch. |
801+
| **label** | `string` | optional | Button + dialog-header text. Plain string: an authored def is not i18n-resolved (declare a real action and name it in `bulkActions` to get localization). |
802+
| **icon** | `string` | optional | Lucide icon name (e.g. "user-check", "trash"). |
803+
| **variant** | `Enum<'primary' \| 'secondary' \| 'danger' \| 'ghost' \| 'outline'>` | optional | Visual treatment of the button. |
804+
| **operation** | `Enum<'update' \| 'delete' \| 'custom'>` | ✅ | What the executor does: 'update'/'delete' are data-plane mass mutations; 'custom' dispatches an object action (see `execution`). |
805+
| **execution** | `Enum<'perRecord' \| 'aggregate'>` | optional | For `operation: 'custom'` — 'aggregate' dispatches the named action ONCE for the whole selection, carrying every id in `params._selectedIds`. Required on a custom def: the per-record form is declared as `bulkActions: ['<name>']` instead. |
806+
| **patch** | `Record<string, any>` | optional | For `operation: 'update'` — static field values applied to every selected record, merged UNDER the user-supplied params so a fixed value can be declared without exposing it in the dialog. |
807+
| **params** | `{ name: string; label?: string; help?: string; type: Enum<'text' \| 'textarea' \| 'email' \| 'url' \| 'phone' \| 'password' \| 'secret' \| …>; … }[]` | optional | Inputs collected once before the run. Omit to skip the params step and go straight to confirm. |
808+
| **confirmText** | `string` | optional | Confirmation text shown above the affected-record summary. |
809+
| **confirmLabel** | `string` | optional | Custom Confirm button label (default: "Run"). |
810+
| **visible** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Eligibility predicate (CEL) — a string or a `{dialect, source}` envelope, i.e. `action.visible` without its boolean-literal arm: a per-record predicate has nothing to say as a constant. Evaluated once PER SELECTED RECORD with that record bound: the button is offered when at least one passes, the run covers only those, and the rest are reported as skipped. A record-free predicate (`features.x`, `current_user.y`) therefore behaves as a plain button-level gate. Fail-closed — a predicate that faults excludes the record. |
811+
| **requiredPermissions** | `string[]` | optional | [ADR-0066 D4] Capability gate on the button, `action.requiredPermissions` semantics verbatim: absent or empty always passes, several are AND-ed, and a client that cannot resolve the caller's capabilities fails OPEN (the server stays the authority). This key exists for INLINE defs — notably the `update`/`delete` data-plane forms, which dispatch no action and so have nothing to inherit a gate from; a def promoted from `bulkActions: ['<name>']` (or an aggregate def naming a declared action) inherits the action's own declaration instead. On a data-plane def the gate governs visibility only — the write itself is still authorized by the data API's object permissions and server hooks. |
812+
| **maxRecords** | `integer` | optional | Selection size above which the run is blocked. Set it on defs whose server work is expensive — an aggregate def carries every selected id in one request. |
813+
| **batchSize** | `integer` | optional | Records per executor batch (default 200). Data-plane operations only — an aggregate run is a single call by definition. |
814+
815+
### Nested Shape: `ObjectGridProps.navigation`
816+
817+
| Property | Type | Required | Description |
818+
| :--- | :--- | :--- | :--- |
819+
| **mode** | `Enum<'page' \| 'drawer' \| 'modal' \| 'split' \| 'popover' \| 'new_window' \| 'none'>` | optional (default: `"page"`) | |
820+
| **view** | `never` | optional | [REMOVED] `view.list.navigation.view` was removed in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — it named the form view to open for a record detail, and no layer resolved a view by that name: the value was passed straight into the navigation-MODE argument of the console's `onNavigate`, where anything other than `edit` or `view` matched no branch, so the key selected nothing and could silently deaden the row click. Delete the key; to choose what opens for a record, assign a `record` page to the object and let `isDefault` pick the one that opens — page assignment is the machinery that resolves a detail layout, and a list view's navigation block only decides HOW the detail is surfaced (`mode`, `size`). |
821+
| **preventNavigation** | `boolean` | optional (default: `false`) | Disable standard navigation entirely |
822+
| **openNewTab** | `boolean` | optional (default: `false`) | Force open in new tab (applies to page mode) |
823+
| **size** | `Enum<'auto' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'>` | optional (default: `"auto"`) | Overlay size bucket for drawer/modal detail: 'auto' (default — renderer derives from field count + viewport; AI writes nothing) or a coarse override sm/md/lg/xl/full. Prefer this over the pixel `width`; page mode ignores it. |
824+
| **width** | `string \| number` | optional | [DEPRECATED → size] Pixel/percent width of the drawer/modal (e.g. "600px"). A pixel width cannot be chosen at authoring time without knowing the client viewport — use the `size` bucket. |
825+
775826
### Nested Shape: `ObjectGridProps.exportOptions`
776827

777828
| Property | Type | Required | Description |
@@ -782,6 +833,15 @@ Sort field and direction pair
782833
| **fileNamePrefix** | `string` | optional | Download file name prefix — replaces the object label and suppresses the view label in the generated file name |
783834
| **streaming** | `boolean` | optional | Set false to force the client-side export path (csv/json only) instead of the server stream |
784835

836+
### Nested Shape: `ObjectGridProps.operations`
837+
838+
| Property | Type | Required | Description |
839+
| :--- | :--- | :--- | :--- |
840+
| **create** | `boolean` | optional | Show the add-row affordance (also gated by the user's create permission) |
841+
| **update** | `boolean` | optional | Offer the row menu's generic Edit entry |
842+
| **delete** | `boolean` | optional | Offer the row menu's generic Delete entry |
843+
| **export** | `boolean` | optional | `false` hides the export menu that `exportOptions` enables |
844+
785845
### Nested Shape: `ObjectGridProps.data[provider='object']`
786846

787847
| Property | Type | Required | Description |

0 commit comments

Comments
 (0)