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
2 changes: 2 additions & 0 deletions .changeset/11441-known-types-retired-layout-keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ Migration:
The registered-types ratchet (`REFUSED_AT_TYPE`) falls from 20 to 18, and its namespaced twin from 374 to 372.

**Clause-②: yes**, released as `minor` with this banner.

⚠️ **Dated note, 2026-10-02 — `grid` takes column counts 1 to 12, not any number — objectui#11491.** At this change "the same breakpoint `columns` object" carried any count; now each count in a `grid`'s `columns` is one of 1 to 12, the counts the `grid` renderer maps, and `objectui validate` refuses any other with that set named. Every count `ResponsiveGrid` drew (1, 2, 3, 4, 6 and 12) is one of them, so the migration above holds for every `responsive-grid` that drew its columns. `.changeset/11491-grid-columns-set.md` states what ships. The rest of this entry is kept as the reading of this change.
2 changes: 2 additions & 0 deletions .changeset/11441-retire-nav-responsive-grid-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ Migration, measured against `objectui validate` on both of its faces:
**Clause-②: yes** — two registrations leave the runtime (narrowing), released as `minor` with this banner.

⚠️ **Dated note, 2026-10-02 — `grid` takes one of ten `gap` steps, not any number — objectui#11474.** At this change `grid` accepted any `gap` number; now it accepts one of 0, 1, 2, 3, 4, 5, 6, 8, 10 and 12, the steps the `grid` renderer maps, and `objectui validate` refuses any other `G` at `gap` on both faces with that set named: 7, 9, 11, a number above 12, a negative number or a fraction. For such a number `grid` drew no gap anyway, because the class it built at runtime is in no compiled stylesheet. So in the migration above `G` must be one of those ten steps; each step `ResponsiveGrid`'s own class map drew (0 to 6 and 8) is one of them. `.changeset/11474-layout-spacing-sets.md` states what ships. The rest of this entry is kept as the reading of this change.

⚠️ **Dated note, 2026-10-02 — `grid` takes column counts 1 to 12, not any number — objectui#11491.** At this change `grid` accepted any count in the breakpoint `columns` object; now each count is one of 1 to 12, the counts the `grid` renderer maps, and `objectui validate` refuses any other count in `C` at `columns` on both faces with that set named. For such a count `grid` drew no column class at that breakpoint anyway. So in the migration above every count in `C` must be one of 1 to 12; each count `ResponsiveGrid`'s own class map drew (1, 2, 3, 4, 6 and 12) is one of them. `.changeset/11491-grid-columns-set.md` states what ships. The rest of this entry is kept as the reading of this change.
42 changes: 42 additions & 0 deletions .changeset/11491-grid-columns-set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
'@object-ui/types': minor
'@object-ui/components': minor
'@object-ui/core': minor
---

The `columns` of a `grid` node is one of the counts its renderer maps, 1 to 12, as the bare
number and at every breakpoint of the object form. Any other count is refused at validation,
with the set named (objectui#11491).

**Breaking for a `grid` that carries any other column count.** The key was declared as any
number, at the bare number and at every breakpoint. But the renderer has one column class per
count from 1 to 12 at each breakpoint and nothing for the rest, so such a count drew no column
class where it was authored: `{ "type": "grid", "columns": 13 }` drew one column on a phone and
two from `sm` up, and never its `md` count; `{ "columns": { "md": 13 } }` drew nothing at `md`;
and `{ "columns": { "xs": 13 } }`, `"columns": 0` and `"columns": -1` drew two columns, a count
nobody authored.

- `@object-ui/types`: `GridSchema.columns` is the literal union of 1 to 12, or a partial
breakpoint map of that union, on the TypeScript face, so `tsc` refuses any other count written
as a literal (a computed `Record<string, number>` still assigns, as it did for keys since
objectui#8505; the mirror judges its counts). The zod mirror refuses one at
`columns` as an `invalid_union` whose message lists the set; its arms carry the set as
`values`, at the breakpoint's own path for the object form. `safeValidateSchema` (what
`objectui validate` runs) and the strict authoring face both give that refusal. An unknown
breakpoint key is still reported on its own, as `unrecognized_keys`.
- `@object-ui/components`: the `grid` registration's `columns`, `smColumns`, `mdColumns`,
`lgColumns` and `xlColumns` inputs change from `type: 'number'` to a closed `enum` of the
twelve counts, in the object form the `container` registration's `padding` uses. `columns`
also publishes the breakpoint object the declaration takes, as an `object` arm whose members
(`of`) are the same list. In the SDUI manifest, `validateTree` now answers `smColumns: 13` with
`invalid-enum`, `columns: 13` with an error-level `type-mismatch` that lists the counts, and
`columns: { md: 13 }` with `member-type-mismatch`. A breakpoint object of mapped counts, which
drew a `type-mismatch` warning there, is now accepted, as both declaration faces already
accepted it. The renderer no longer draws `grid-cols-2` for a base count it does not map:
every count a validated document can carry is mapped, and an unmapped one that reaches it
unvalidated draws no base column class, as at every other breakpoint. Nothing rounds or
clamps.
- `@object-ui/core`: `GridBuilder.columns()` takes the declared counts instead of any number.

Migration: replace the count with the one you meant, from 1 to 12. For a grid with no columns
at a breakpoint, leave that breakpoint out; for a single column, write `1`.
2 changes: 2 additions & 0 deletions .changeset/8505-grid-columns-breakpoint-narrowing.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ The command is `objectui validate`, and `check` does not refuse `{ xxl: 6 }`: it
an advisory sweep that never parses against the schema a file whose root carries a structural key
(`children`, `className`, `body`, …), lists a file with none of those keys by name
when the file does not validate, and exits non-zero on unreadable JSON only.

⚠️ **Dated note, 2026-10-02 — the column counts are closed too — objectui#11491.** At this change `GridSchema.columns` was `number | Partial<Record<BreakpointName, number>>`. Now each count, the bare number and every breakpoint's, is one of 1 to 12, the counts the `grid` renderer maps to a column class, on the TypeScript face and in the zod mirror, so a literal `{ md: 13 }` stops compiling as `{ xxl: 6 }` did. The escape described above still holds, for values as well as keys: a computed `Record<string, number>` still assigns, and the zod mirror is what judges its counts. `.changeset/11491-grid-columns-set.md` states what ships. The rest of this entry is kept as the reading of this change.
4 changes: 2 additions & 2 deletions content/docs/api/schema-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ A responsive grid layout. Columns can be a fixed number or responsive breakpoint

| Property | Type | Description |
|----------|------|-------------|
| `columns` | `number \| Partial<Record<BreakpointName, number>>` | Number of columns, or a responsive map keyed by breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `2xl`), e.g. `{ sm: 1, md: 2, lg: 3 }`. |
| `gap` | `number` | Gap between grid items (Tailwind spacing scale). |
| `columns` | `ColumnCount \| Partial<Record<BreakpointName, ColumnCount>>` | A column count from 1 to 12 (`ColumnCount`), or a responsive map of such counts keyed by breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `2xl`), e.g. `{ sm: 1, md: 2, lg: 3 }`. Any other count is refused with the set named (objectui#11491). |
| `gap` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 8 \| 10 \| 12` | Gap step between grid items; `0` is none (default `4`). Any other number is refused with the set named (objectui#11474). |
| `children` | `SchemaNode \| SchemaNode[]` | Grid items. |

**Related:** [DivSchema](#divschema), [CardSchema](#cardschema), [DashboardComponentSchema](#dashboardcomponentschema)
Expand Down
12 changes: 11 additions & 1 deletion content/docs/components/layout/grid.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@ description: "Responsive grid layout container"
```ts
import type { SchemaNode } from '@object-ui/types';

type ColumnCount = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;

interface GridSchema {
type: 'grid';
columns?: number;
columns?: ColumnCount | Partial<Record<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl', ColumnCount>>; // default: 2
gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12; // default: 4
children: SchemaNode[];
className?: string;
}
```

`columns` is a column count from 1 to 12, or an object of such counts keyed by breakpoint
(`{ "xs": 1, "md": 2, "lg": 4 }`). Those twelve counts are the ones the renderer maps to a column
class, at every breakpoint, so they are the only values validation accepts: `"columns": 13`,
`"columns": 0` or `"columns": { "md": 13 }` is refused with the set named (objectui#11491). Such a
count used to draw no column class where it was authored: `13` lost its `md` count, and `0` drew
two columns. A bare count above 1 is one column on a phone and that count from `md` up; an object
keeps full control of every breakpoint.

`gap` is a step on the grid's spacing scale, and `0` means none. The ten steps are the ones
the renderer maps to a gap class, so they are the only values validation accepts: `"gap": 9`
or `"gap": 16` is refused with the set named (objectui#11474). For such a number the renderer
Expand Down
Loading
Loading