@aiaiai-pt/design-system 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Grid layout helpers (#176 Tier 1 / ADR 0003).
3
+ *
4
+ * A page is still a flat `Block[]`; a block may carry an optional `layout`
5
+ * placing it on a 12-column grid. These pure helpers turn that descriptor field
6
+ * into CSS, shared by BOTH host apps (admin dashboard + portal page) so the
7
+ * arrangement is identical and DRY. Presentation-only: no editing concern lives
8
+ * here — the editor merely writes the same `layout` coords the renderer reads.
9
+ *
10
+ * Back-compatible: a block without `layout` falls back to source order, and a
11
+ * page with NO laid-out blocks renders as the shipped stacked list.
12
+ */
13
+ import type { Block, BlockLayout } from "./types";
14
+ export declare const GRID_COLUMNS = 12;
15
+ /** Clamp a layout to valid 12-col track bounds (defensive against operator /
16
+ * drag input). `w` is 1..12; `x` keeps the span on-track; `y`/`h` are >=0/>=1. */
17
+ export declare function normalizeLayout(layout: BlockLayout): BlockLayout;
18
+ /**
19
+ * CSS `grid-column` / `grid-row` placement for a block's layout, or `null` when
20
+ * the block has none (the caller renders it in source order). Grid lines are
21
+ * 1-based, so a 0-based `x`/`y` maps to line `x+1`/`y+1`.
22
+ */
23
+ export declare function gridStyleFor(block: Pick<Block, "layout">): string | null;
24
+ /** True when ANY block carries a `layout` — the page should render as a grid
25
+ * (12-col track) rather than the stacked list. */
26
+ export declare function hasGridLayout(blocks: ReadonlyArray<Pick<Block, "layout">>): boolean;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Grid layout helpers (#176 Tier 1 / ADR 0003).
3
+ *
4
+ * A page is still a flat `Block[]`; a block may carry an optional `layout`
5
+ * placing it on a 12-column grid. These pure helpers turn that descriptor field
6
+ * into CSS, shared by BOTH host apps (admin dashboard + portal page) so the
7
+ * arrangement is identical and DRY. Presentation-only: no editing concern lives
8
+ * here — the editor merely writes the same `layout` coords the renderer reads.
9
+ *
10
+ * Back-compatible: a block without `layout` falls back to source order, and a
11
+ * page with NO laid-out blocks renders as the shipped stacked list.
12
+ */
13
+ import type { Block, BlockLayout } from "./types";
14
+
15
+ export const GRID_COLUMNS = 12;
16
+
17
+ /** Clamp a layout to valid 12-col track bounds (defensive against operator /
18
+ * drag input). `w` is 1..12; `x` keeps the span on-track; `y`/`h` are >=0/>=1. */
19
+ export function normalizeLayout(layout: BlockLayout): BlockLayout {
20
+ const w = clampInt(layout.w, 1, GRID_COLUMNS, 1);
21
+ const x = clampInt(layout.x, 0, GRID_COLUMNS - w, 0);
22
+ const h = clampInt(layout.h, 1, Number.MAX_SAFE_INTEGER, 1);
23
+ const y = clampInt(layout.y, 0, Number.MAX_SAFE_INTEGER, 0);
24
+ return { x, y, w, h };
25
+ }
26
+
27
+ /**
28
+ * CSS `grid-column` / `grid-row` placement for a block's layout, or `null` when
29
+ * the block has none (the caller renders it in source order). Grid lines are
30
+ * 1-based, so a 0-based `x`/`y` maps to line `x+1`/`y+1`.
31
+ */
32
+ export function gridStyleFor(block: Pick<Block, "layout">): string | null {
33
+ if (!block.layout) return null;
34
+ const { x, y, w, h } = normalizeLayout(block.layout);
35
+ return `grid-column:${x + 1} / span ${w};grid-row:${y + 1} / span ${h};`;
36
+ }
37
+
38
+ /** True when ANY block carries a `layout` — the page should render as a grid
39
+ * (12-col track) rather than the stacked list. */
40
+ export function hasGridLayout(
41
+ blocks: ReadonlyArray<Pick<Block, "layout">>,
42
+ ): boolean {
43
+ return blocks.some((b) => b.layout != null);
44
+ }
45
+
46
+ function clampInt(
47
+ value: unknown,
48
+ min: number,
49
+ max: number,
50
+ fallback: number,
51
+ ): number {
52
+ const n =
53
+ typeof value === "number" && Number.isFinite(value)
54
+ ? Math.round(value)
55
+ : fallback;
56
+ return Math.max(min, Math.min(max, n));
57
+ }
@@ -183,6 +183,34 @@ export interface Block {
183
183
  * (set on the default block), not tenant content.
184
184
  */
185
185
  bleed?: boolean;
186
+ /**
187
+ * #176 Tier 1 (ADR 0003) — 2D grid placement on a 12-column track. A block
188
+ * WITH `layout` is positioned by the renderer's grid (col `x`, span `w`; row
189
+ * `y`, span `h`); a block WITHOUT it falls back to source order (the shipped
190
+ * ordered-list behaviour — fully back-compatible). This is a DESCRIPTOR field
191
+ * consumed by BOTH render (places the block) and authoring (drag/resize writes
192
+ * the coords); the DS never learns it is being edited. `x`/`y` are 0-based;
193
+ * `w`/`h` are 1-based spans (w clamped to 1..12).
194
+ */
195
+ layout?: BlockLayout;
196
+ /**
197
+ * #176 Tier 1 — child blocks for a future grid-IN-grid container. Reserved
198
+ * (single-level page grids use `layout` on flat blocks); nesting is deferred
199
+ * until a concrete need (ADR 0003 build-order note).
200
+ */
201
+ children?: Block[];
202
+ }
203
+
204
+ /** 12-column grid placement (#176 Tier 1). All fields in grid track units. */
205
+ export interface BlockLayout {
206
+ /** 0-based start column (0..11). */
207
+ x: number;
208
+ /** 0-based start row. */
209
+ y: number;
210
+ /** Column span (1..12). */
211
+ w: number;
212
+ /** Row span (>=1). */
213
+ h: number;
186
214
  }
187
215
 
188
216
  export interface PageDescriptor {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/design-system",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Design system tokens and Svelte components for aiaiai products",
5
5
  "license": "MIT",
6
6
  "type": "module",