@viraui/react 2026.8.0 → 2026.9.1

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.
Files changed (44) hide show
  1. package/dist/catalog.json +3 -3
  2. package/dist/components/prose/prose.css +1 -1
  3. package/dist/components/prose/prose.d.ts +8 -0
  4. package/dist/components/prose/prose.js +2 -1
  5. package/dist/components/select/select.css +1 -1
  6. package/dist/components/stack/stack.css +1 -1
  7. package/dist/components/stack/stack.d.ts +15 -3
  8. package/dist/components/stack/stack.js +2 -1
  9. package/dist/components/surface/surface.css +1 -1
  10. package/dist/components/text/text.css +2 -2
  11. package/dist/components/text/text.d.ts +9 -6
  12. package/dist/components/text/text.js +2 -2
  13. package/dist/components/title/title.css +2 -2
  14. package/dist/components/title/title.d.ts +9 -6
  15. package/dist/components/title/title.js +2 -2
  16. package/dist/preflight.css +1 -1
  17. package/dist/specs/PROTOCOL.md +1 -1
  18. package/dist/specs/activity-hints.xml +4 -4
  19. package/dist/specs/components/progressive-blur/usage.xml +2 -2
  20. package/dist/specs/components/prose/meta.xml +1 -1
  21. package/dist/specs/components/prose/patterns.xml +1 -1
  22. package/dist/specs/components/prose/props.xml +8 -2
  23. package/dist/specs/components/prose/usage.xml +2 -1
  24. package/dist/specs/components/stack/patterns.xml +98 -0
  25. package/dist/specs/components/stack/props.xml +8 -3
  26. package/dist/specs/components/stack/usage.xml +6 -3
  27. package/dist/specs/components/surface/usage.xml +1 -1
  28. package/dist/specs/components/text/meta.xml +1 -1
  29. package/dist/specs/components/text/patterns.xml +11 -11
  30. package/dist/specs/components/text/props.xml +10 -7
  31. package/dist/specs/components/text/usage.xml +2 -2
  32. package/dist/specs/components/title/meta.xml +1 -1
  33. package/dist/specs/components/title/patterns.xml +8 -8
  34. package/dist/specs/components/title/props.xml +10 -7
  35. package/dist/specs/components/title/usage.xml +3 -3
  36. package/dist/specs/foundation/attributes.xml +2 -4
  37. package/dist/specs/foundation/theme-topics.xml +3 -3
  38. package/dist/specs/foundation/toggles.xml +2 -2
  39. package/dist/specs/index.xml +4 -22
  40. package/dist/specs/patterns/compose-layout-first.xml +1 -1
  41. package/package.json +2 -2
  42. package/dist/specs/patterns/equal-width-actions.xml +0 -22
  43. package/dist/specs/patterns/page-chrome.xml +0 -34
  44. package/dist/specs/patterns/stack-as-surface.xml +0 -37
@@ -1,6 +1,71 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="stack">
3
3
  <!-- Sources: viraui-app/components — cleaned (no handlers, no app-only chrome, no CSS that reinvents Stack props). -->
4
+ <!-- Stack-owned recipes live HERE (local patterns unit). Core `specs/patterns/*` = true multi-surface screen recipes only. -->
5
+
6
+ <example title="Stack as Surface (one DOM node)">
7
+ <tsx><![CDATA[
8
+ {/* Preferred: layout + chrome share one root */}
9
+ <Stack
10
+ direction="row"
11
+ columnGap="s"
12
+ vAlign="center"
13
+ fullWidth
14
+ render={<Surface border="all" color={1} radius="m" hPadding="m" vPadding="s" />}
15
+ >
16
+ <Text size="sm" color="muted">
17
+ Status
18
+ </Text>
19
+ <Chip>Active</Chip>
20
+ </Stack>
21
+ ]]></tsx>
22
+ <notes>Gap/align/`fullWidth`/`expandChildren` on Stack; `border`/`color`/`radius`/padding on Surface in `render`. Nest Surface→Stack only when separate roots are required (Elevator, concentric Surfaces). Never invent border/radius CSS on Stack.</notes>
23
+ </example>
24
+
25
+ <example title="Equal-width action row">
26
+ <tsx><![CDATA[
27
+ {/* Full-bleed column CTAs */}
28
+ <Stack fullWidth rowGap="s">
29
+ <Button>Continue</Button>
30
+ <Button variant="secondary">Cancel</Button>
31
+ </Stack>
32
+
33
+ {/* Equal-width row actions — children grow on the main axis. Add fullWidth when this Stack must fill parent width */}
34
+ <Stack expandChildren direction="row" columnGap="s">
35
+ <Button>Continue</Button>
36
+ <Button variant="secondary">Cancel</Button>
37
+ </Stack>
38
+ ]]></tsx>
39
+ <notes>`fullWidth` sizes this Stack; `expandChildren` grows children on the main axis. Never invent `width: 100%` / `flex: 1` CSS on Button. Both-axes fill → examples below (not height CSS).</notes>
40
+ </example>
41
+
42
+ <example title="Page chrome (semantic hosts)">
43
+ <tsx><![CDATA[
44
+ <Stack rowGap="m" expandChildren>
45
+ <Stack
46
+ direction="row"
47
+ hAlign="space-between"
48
+ vAlign="center"
49
+ columnGap="m"
50
+ hPadding="m"
51
+ vPadding="m"
52
+ render={<header />}
53
+ >
54
+ <Title render={<h1 />}>Settings</Title>
55
+ <Button>Save</Button>
56
+ </Stack>
57
+ <Stack direction="row" columnGap="m" expandChildren render={<main />}>
58
+ <Stack rowGap="xs" hPadding="s" vPadding="s" render={<nav aria-label="Settings" />}>
59
+ {/* nav links */}
60
+ </Stack>
61
+ <Stack rowGap="l" expandChildren>
62
+ {/* content */}
63
+ </Stack>
64
+ </Stack>
65
+ </Stack>
66
+ ]]></tsx>
67
+ <notes>Semantic tags via `render` — Stack stays the layout engine. CSS may set `min-block-size` / scroll; never `display:flex`. Omit `render={&lt;div /&gt;}` (default host).</notes>
68
+ </example>
4
69
 
5
70
  <example title="App header (hub)">
6
71
  <tsx><![CDATA[
@@ -360,4 +425,37 @@
360
425
  ]]></tsx>
361
426
  <notes>From `editor/preview-grid/blocks/shipping-address`. `expandChildren` on row Stacks shares width across field pairs — do not invent per-field `flex`/`width` CSS.</notes>
362
427
  </example>
428
+
429
+ <example title="Row panels fill both axes">
430
+ <tsx><![CDATA[
431
+ {/* Parent must be sized (viewport shell, fullHeight ancestor, …). No height CSS on Stack/children. */}
432
+ <Stack direction="row" columnGap="s" expandChildren fullHeight vAlign="stretch">
433
+ <Stack rowGap="s" hPadding="m" vPadding="m">
434
+ {/* sidebar / panel A */}
435
+ </Stack>
436
+ <Stack rowGap="m" hPadding="m" vPadding="m" expandChildren>
437
+ {/* main / panel B */}
438
+ </Stack>
439
+ </Stack>
440
+ ]]></tsx>
441
+ <notes>Canonical horizontal both-axes fill (Stack-owned). Main = `expandChildren`; cross = `vAlign=&quot;stretch&quot;`; root block size = `fullHeight`. Never `style`/`className` height on Stack or children.</notes>
442
+ </example>
443
+
444
+ <example title="Column sections fill both axes">
445
+ <tsx><![CDATA[
446
+ {/* Parent must be sized. Children share height + fill width — props only. */}
447
+ <Stack rowGap="s" expandChildren fullWidth fullHeight hAlign="stretch">
448
+ <Stack direction="row" columnGap="m" vAlign="center" hPadding="m" vPadding="s">
449
+ {/* header strip */}
450
+ </Stack>
451
+ <Stack rowGap="m" hPadding="m" vPadding="m" expandChildren>
452
+ {/* grow body */}
453
+ </Stack>
454
+ <Stack direction="row" columnGap="s" hPadding="m" vPadding="s" data-grow="false">
455
+ {/* footer actions — opt out of main-axis grow */}
456
+ </Stack>
457
+ </Stack>
458
+ ]]></tsx>
459
+ <notes>Canonical vertical both-axes fill (Stack-owned). Main = `expandChildren`; cross = `hAlign=&quot;stretch&quot;`; root = `fullWidth` + `fullHeight`. Footer uses `data-grow=&quot;false&quot;` so only the body expands.</notes>
460
+ </example>
363
461
  </patterns>
@@ -8,12 +8,14 @@
8
8
  <item>Centered max-width shells: parent `hAlign=&quot;center&quot;` + child `fullWidth` + `maxWidth`</item>
9
9
  <item>Readable type columns: `maxWidth` in **`ch`** around Text/Title/Prose for ~10–12 words/line — width **tracks body `size`** (smaller → narrower; prefer `ch` over rem; never one fixed band for every size)</item>
10
10
  <item>Full-bleed or equal-width action clusters (Buttons, etc.): `fullWidth` and/or `expandChildren` instead of per-child width CSS</item>
11
+ <item>Children fill both axes in a sized parent — see this surface `patterns.xml`: row = `direction=&quot;row&quot;` + `expandChildren` + `fullHeight` + `vAlign=&quot;stretch&quot;`; column = `expandChildren` + `fullWidth` + `fullHeight` + `hAlign=&quot;stretch&quot;` — never invent `height`/`width` / `block-size`/`inline-size: 100%` CSS</item>
11
12
  </when_to_use>
12
13
  <when_not_to_use>
13
14
  <item>Cases where a single component already owns required flex chrome</item>
14
15
  <item>Expecting direct children to grow on the main axis without setting `expandChildren`</item>
15
16
  <item>Expecting this stack to fill parent inline size under non-stretch alignment without `fullWidth` (or an explicit `inlineSize`)</item>
16
- <item>Inventing `width: 100%` / `inline-size: 100%` / `w-full` / size-fill className on content-sized children (Button, Chip, …) when this Stack can own fill via `fullWidth` / `expandChildren` — or on fixed-size children (IconButton) where width CSS is useless</item>
17
+ <item>Expecting this stack to fill parent block size without `fullHeight` (or an explicit `blockSize`)</item>
18
+ <item>Inventing `width`/`height` / `inline-size`/`block-size: 100%` / `w-full` / size-fill className on this Stack or content-sized children when `fullWidth` / `fullHeight` / `expandChildren` + stretch align cover it (see `patterns.xml`) — or on fixed-size children (IconButton) where size CSS is useless</item>
17
19
  <item>Using `enableContainer` inside complex masonry-like layouts when you don&apos;t need container queries (inline-size containment can change nested layout)</item>
18
20
  </when_not_to_use>
19
21
  <prop name="columnGap" kind="react">
@@ -26,10 +28,13 @@
26
28
  <description>Renders children across rows or columns using the chosen flex direction.</description>
27
29
  </prop>
28
30
  <prop name="expandChildren" kind="react">
29
- <description>Makes direct children grow along the flex main axis (`flex-grow`). Default `false`. Use for equal-width row actions (Buttons, etc.) instead of inventing `width`/`flex` CSS on each child. Orthogonal to `fullWidth` (children grow vs this root&apos;s inline size). A child opts out with its own `data-grow=&quot;false&quot;`; ancestor `data-grow` does not inherit into nested stacks.</description>
31
+ <description>Makes direct children grow along the flex main axis (`flex-grow`). Default `false`. Use for equal-width row actions (Buttons, etc.) instead of inventing `width`/`flex` CSS on each child. Cross-axis fill stays on `hAlign` / `vAlign=&quot;stretch&quot;` (which prop is cross depends on `direction`). Orthogonal to `fullWidth` / `fullHeight` (children grow vs this root&apos;s size). A child opts out with its own `data-grow=&quot;false&quot;`; ancestor `data-grow` does not inherit into nested stacks.</description>
32
+ </prop>
33
+ <prop name="fullHeight" kind="react">
34
+ <description>Sets `block-size: 100%` on the stack root so it fills the parent&apos;s block size. Default `false`. Prefer this over `style`/`className` `height` / `block-size: 100%` on this Stack. Pair with `expandChildren` and cross-axis `hAlign`/`vAlign=&quot;stretch&quot;` so children fill both axes without per-child size CSS. Orthogonal to `expandChildren` and `fullWidth`.</description>
30
35
  </prop>
31
36
  <prop name="fullWidth" kind="react">
32
- <description>Sets `inline-size: 100%` on the stack root so it fills the parent&apos;s inline size. Default `false`. Prefer this (plus cross-axis stretch) so content-sized children like Button span a panel — do not add `width: 100%` CSS on those children. Use with `maxWidth` under a parent `hAlign=&quot;center&quot;` for a fluid capped centered shell. Does not grow children — use `expandChildren` for that.</description>
37
+ <description>Sets `inline-size: 100%` on the stack root so it fills the parent&apos;s inline size. Default `false`. Prefer this (plus cross-axis stretch) so content-sized children like Button span a panel — do not add `width: 100%` CSS on those children. Use with `maxWidth` under a parent `hAlign=&quot;center&quot;` for a fluid capped centered shell. Pair with `fullHeight` when the root must fill both parent axes. Does not grow children — use `expandChildren` for that.</description>
33
38
  </prop>
34
39
  <prop name="hAlign" kind="react">
35
40
  <description>Aligns content on the horizontal axis from the consumer point of view.</description>
@@ -2,8 +2,11 @@
2
2
  <usage surface="stack">
3
3
  <do>Default structural box instead of a bare wrapper `div` — Stack owns flex + token gap/padding/align/`fullWidth`/`render`</do>
4
4
  <do>Login/signup (or similar auth swap): host Tabs + Textfield(s) + Button (+ optional Fieldset) inside a Stack or `Stack render={&lt;Surface … /&gt;}` shell — props only, 0 custom CSS</do>
5
- <do>Flex + Surface chrome on one node via `render={&lt;Surface … /&gt;}` — prefer over a CSS border class or an extra wrapper (see package pattern `stack-as-surface`)</do>
6
- <do>Equal-width action or field clusters (Button, Chip, Textfield): `fullWidth` and/or `expandChildren` on this Stack — never per-child width CSS</do>
5
+ <do>Flex + Surface chrome on one node via `render={&lt;Surface … /&gt;}` — prefer over a CSS border class or an extra wrapper (see this surface `patterns.xml` — Stack as Surface)</do>
6
+ <do>Equal-width action or field clusters (Button, Chip, Textfield): `fullWidth` and/or `expandChildren` on this Stack — never per-child width CSS (see `patterns.xml`)</do>
7
+ <do>Children fill **both** axes inside a sized parent — this surface `patterns.xml` (never invent size-fill CSS):
8
+ row → `direction=&quot;row&quot;` + `expandChildren` + `fullHeight` + `vAlign=&quot;stretch&quot;` (share width + fill height);
9
+ column → `expandChildren` + `fullWidth` + `fullHeight` + `hAlign=&quot;stretch&quot;` (share height + fill width)</do>
7
10
  <do>Settings rows: Stack `direction=&quot;row&quot;` + Text (label/description column) + Switch or Checkbox — nest in Surface for panel chrome</do>
8
11
  <do>Centered capped shells: parent `hAlign=&quot;center&quot;` + child Stack `fullWidth` + `maxWidth`</do>
9
12
  <do>Readable type column: Stack `maxWidth` in **`ch`** around Text/Title/Prose sized for the dominant body `size` (~10–12 words/line; smaller → narrower) — prefer `ch` over rem; never one fixed ch for every size</do>
@@ -13,7 +16,7 @@
13
16
  <dont>Passing `render={&lt;div /&gt;}` (or any host that matches Stack&apos;s default root) — omit `render`; use it only for a different host (`header`, `Surface`, …)</dont>
14
17
  <dont>Assuming Stack expands direct children by default — pass `expandChildren` when children should grow on the flex main axis</dont>
15
18
  <dont>Using `expandChildren` to fill parent width under `hAlign=&quot;center&quot;` — that is `fullWidth` on the child Stack (self `inline-size`), not child flex-grow</dont>
16
- <dont>Inventing `width: 100%` / `inline-size: 100%` / `w-full` / `.fullWidth` / size-fill `className` on content-sized children when this Stack can own the fill — or when children are intentionally fixed-size (e.g. IconButton)</dont>
19
+ <dont>Inventing `width`/`height` / `inline-size`/`block-size: 100%` / `w-full` / size-fill `className` on this Stack or content-sized children when `fullWidth` / `fullHeight` / `expandChildren` + stretch align can own the fill — or when children are intentionally fixed-size (e.g. IconButton)</dont>
17
20
  <dont>Inventing CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / side paddings (`style` or className) when public spacing props cover it — one-sided inset uses `hPadding`/`vPadding` `[start, end]` tuples (e.g. `vPadding={[0, &apos;l&apos;]}`), not `paddingBlockEnd: &apos;1rem&apos;`</dont>
18
21
  <dont>Putting `data-grow=&quot;false&quot;` on an ancestor to control nested `expandChildren` — set it on the child that should not grow</dont>
19
22
  <dont>Combining `fullWidth` with `inline` — prefer block flex when the root must fill parent inline size</dont>
@@ -2,7 +2,7 @@
2
2
  <usage surface="surface">
3
3
  <do>Group content with base-level background and contrast border — nest Stack for child gaps (Surface has no gap prop)</do>
4
4
  <do>Login/signup shell: Surface (or `Stack render={&lt;Surface … /&gt;}`) hosts Tabs + Textfield(s) + Button (+ optional Fieldset) — chrome + layout via props, 0 custom CSS</do>
5
- <do>Accept Stack as host via their `render={&lt;Surface … /&gt;}` so border/fill/radius share one DOM node — prefer over inventing chrome CSS (see package pattern `stack-as-surface`)</do>
5
+ <do>Accept Stack as host via their `render={&lt;Surface … /&gt;}` so border/fill/radius share one DOM node — prefer over inventing chrome CSS (see Stack `patterns.xml` — Stack as Surface)</do>
6
6
  <do>Settings / preferences panels: Surface card + Stack body + Switch/Checkbox rows (optionally padded inner Surfaces) + Button footer strip</do>
7
7
  <do>Frosted glass panels with `data-vibrant` — omit `color` for page-level shell or pass `color` for a tinted fill</do>
8
8
  <do>Compose with Elevator for animated elevation — Surface has no `elevation` prop</do>
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <meta id="text" title="Text" category="typography" shared_contract="text">
3
- <summary>Theme-aware body-copy primitive with tone, family, sizing, and readable-measure props (`maxWidth` / `lineHeight` / `balanced`).</summary>
3
+ <summary>Theme-aware body-copy primitive with tone, family, sizing, and readable-measure props (`maxWidth` / `lineHeight` / `wrap`).</summary>
4
4
  <exports>
5
5
  <export name="Text" />
6
6
  </exports>
@@ -6,15 +6,15 @@
6
6
  <example title="Auth muted lead (readable measure)">
7
7
  <tsx><![CDATA[
8
8
  <Stack vPadding={[0, 'l']} rowGap="xl" maxWidth="70ch">
9
- <Title size="1" render={<h1 />} maxWidth="36ch" lineHeight="s" balanced>
9
+ <Title size="1" render={<h1 />} maxWidth="36ch" lineHeight="s" wrap="balance">
10
10
  Design systems that ship
11
11
  </Title>
12
- <Text size="2xl" tone="muted" maxWidth="68ch" balanced>
12
+ <Text size="2xl" tone="muted" maxWidth="68ch" wrap="balance">
13
13
  Login to create custom ViraUI themes, access prompts and more.
14
14
  </Text>
15
15
  </Stack>
16
16
  ]]></tsx>
17
- <notes>From `auth/login-view`. Cap ~10–12 words/line with `maxWidth` in `ch` scaled to size (`2xl` wider than `s`); `balanced` on short wrapping hero copy; `lineHeight="s"` on large Title. Prefer `ch` over rem. No CSS width/line-height.</notes>
17
+ <notes>From `auth/login-view`. Cap ~10–12 words/line with `maxWidth` in `ch` scaled to size (`2xl` wider than `s`); `wrap="balance"` on short even-rag hero copy (default `pretty` covers most body); `lineHeight="s"` on large Title. Prefer `ch` over rem. No CSS width/line-height.</notes>
18
18
  </example>
19
19
 
20
20
  <example title="Card section blurb">
@@ -23,12 +23,12 @@
23
23
  <Title size="6" render={<h2 />}>
24
24
  Payout Threshold
25
25
  </Title>
26
- <Text tone="muted" size="s" maxWidth="45ch" balanced>
26
+ <Text tone="muted" size="s" maxWidth="45ch">
27
27
  Set the minimum balance required before a payout is triggered.
28
28
  </Text>
29
29
  </Stack>
30
30
  ]]></tsx>
31
- <notes>From preview-grid `payout-threshold` (+ preferences / workspace-usage). Default pairing: Title + muted `size="s"` Text; short blurb prefers `maxWidth` in `ch` + `balanced`.</notes>
31
+ <notes>From preview-grid `payout-threshold` (+ preferences / workspace-usage). Default pairing: Title + muted `size="s"` Text; short blurb prefers `maxWidth` in `ch` (default `wrap="pretty"`).</notes>
32
32
  </example>
33
33
 
34
34
  <example title="Nested weight + tone">
@@ -52,16 +52,16 @@
52
52
  </Text>
53
53
  </Stack>
54
54
  ]]></tsx>
55
- <notes>From preview-grid `payout-threshold`. `family="mono"` + muted xs for metric chrome — single-line; no `balanced`.</notes>
55
+ <notes>From preview-grid `payout-threshold`. `family="mono"` + muted xs for metric chrome — single-line; prefer `whiteSpace="nowrap"` when overflow risk; do not use `wrap="nowrap"` for metrics.</notes>
56
56
  </example>
57
57
 
58
58
  <example title="Form success paragraph">
59
59
  <tsx><![CDATA[
60
- <Text render={<p />} maxWidth="60ch" balanced>
60
+ <Text render={<p />} maxWidth="60ch">
61
61
  Check your email — we sent a link to your@email.com
62
62
  </Text>
63
63
  ]]></tsx>
64
- <notes>From `auth/login-form` acknowledged state. `render={<p />}` for block semantics; short wrap prefers `balanced` + `ch` measure.</notes>
64
+ <notes>From `auth/login-form` acknowledged state. `render={<p />}` for block semantics; short wrap relies on default `pretty` + `ch` measure.</notes>
65
65
  </example>
66
66
 
67
67
  <example title="Prose link">
@@ -76,15 +76,15 @@
76
76
  <example title="Empty-state centered">
77
77
  <tsx><![CDATA[
78
78
  <Stack hAlign="center" rowGap="m" maxWidth="36ch">
79
- <Title align="center" size="5" render={<h3 />} balanced>
79
+ <Title align="center" size="5" render={<h3 />} wrap="balance">
80
80
  No Team Members
81
81
  </Title>
82
- <Text size="s" align="center" maxWidth="40ch" tone="muted" balanced>
82
+ <Text size="s" align="center" maxWidth="40ch" tone="muted" wrap="balance">
83
83
  Invite your team to collaborate on this project.
84
84
  </Text>
85
85
  </Stack>
86
86
  ]]></tsx>
87
- <notes>From preview-grid `empty-team`. Centered muted copy with `maxWidth` in `ch` + `balanced`; Stack owns column cap / centering.</notes>
87
+ <notes>From preview-grid `empty-team`. Centered muted copy with `maxWidth` in `ch` + `wrap="balance"` for even rag; Stack owns column cap / centering.</notes>
88
88
  </example>
89
89
 
90
90
  <example title="Claimable balance rows">
@@ -2,7 +2,7 @@
2
2
  <props surface="text">
3
3
  <when_to_use>
4
4
  <item>Body copy with semantic tone (including brand `primary`) and token-backed typography</item>
5
- <item>Readable UI measure (~10–12 words/line) via `maxWidth` / parent Stack `maxWidth` **scaled to `size`** (smaller → narrower), `lineHeight` matched to size, and `balanced` on short wrapping paragraphs</item>
5
+ <item>Readable UI measure (~10–12 words/line) via `maxWidth` / parent Stack `maxWidth` **scaled to `size`** (smaller → narrower), `lineHeight` matched to size, and `wrap` (default `pretty`; `balance` on short even-rag blurbs)</item>
6
6
  <item>Letter-spacing via `tracking` or text-transform via `transform` — prefer props over CSS on the Text root</item>
7
7
  <item>Helper, label, or inline copy inside other components</item>
8
8
  <item>Mono or body family text; size locked by default (`fluid` false → --font-scale-body-*); pass `fluid` for viewport clamp (also gated by theme `--effect-fluid-typography`)</item>
@@ -11,14 +11,11 @@
11
11
  <item>Headings or display typography — use Title</item>
12
12
  <item>Heading semantics without an appropriate render root</item>
13
13
  <item>Long-form heading-aware article rhythm — use Prose (keep a reading column)</item>
14
- <item>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap: balance` / `width: 100%` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `balanced` / parent Stack `fullWidth` cover the need</item>
14
+ <item>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap` / `width: 100%` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `wrap` / parent Stack `fullWidth` cover the need</item>
15
15
  </when_not_to_use>
16
16
  <prop name="align" kind="react">
17
17
  <description>Aligns text using logical alignment values. Omit so `text-align` inherits from the parent.</description>
18
18
  </prop>
19
- <prop name="balanced" kind="react">
20
- <description>Enables balanced wrapping for block-like copy. Prefer on short wrapping UI paragraphs (hero lead, empty state, card blurb); omit when single-line or intentional ragged.</description>
21
- </prop>
22
19
  <prop name="color" kind="react">
23
20
  <description>Applies a literal color escape hatch when semantic `tone` is not used.</description>
24
21
  </prop>
@@ -77,7 +74,10 @@
77
74
  <description>Selects a semantic weight keyword or a numeric weight (`font-weight` + `wght` axis).</description>
78
75
  </prop>
79
76
  <prop name="whiteSpace" kind="react">
80
- <description>Controls white-space preservation and wrapping behavior.</description>
77
+ <description>Controls white-space collapse/preserve (`white-space`). Prefer `whiteSpace=&quot;nowrap&quot;` for single-line metrics/chrome (also collapses spaces). For wrapping algorithm / even line lengths use `wrap` (`text-wrap`) — not this prop.</description>
78
+ </prop>
79
+ <prop name="wrap" kind="react">
80
+ <description>Controls CSS `text-wrap` (wrapping algorithm / wrap on-off). Default `pretty` for orphan-aware UI copy. Prefer `balance` on short multi-line heads/blurbs that need even line lengths. Use `wrap=&quot;nowrap&quot;` only when you need no wrap without changing white-space collapse; prefer `whiteSpace=&quot;nowrap&quot;` for metrics.</description>
81
81
  </prop>
82
82
  <prop name="align" kind="css">
83
83
  <description>Text alignment on the root when the `align` prop is set; omitted inherits parent `text-align`.</description>
@@ -131,6 +131,9 @@
131
131
  <description>Text transform on the root. Prefer the `transform` React prop; set this hook only when theming beyond the prop.</description>
132
132
  </prop>
133
133
  <prop name="white-space" kind="css">
134
- <description>White-space behavior on the root.</description>
134
+ <description>White-space behavior on the root (`--vui-text-white-space`). Prefer the `whiteSpace` React prop.</description>
135
+ </prop>
136
+ <prop name="wrap" kind="css">
137
+ <description>Text-wrap on the root (`--vui-text-wrap`). Prefer the `wrap` React prop; default `pretty`.</description>
135
138
  </prop>
136
139
  </props>
@@ -3,7 +3,7 @@
3
3
  <do>Body copy, helpers, and labels — semantic `tone` before literal `color` or raw theme vars</do>
4
4
  <do>Readable UI measure: aim ~10–12 words per line — `maxWidth` / Stack `maxWidth` **scales with `size`** (smaller type → narrower column; larger → wider); prefer **`ch`** in patterns/examples (not `rem`); never one fixed ch for every size; no full-bleed wrapping blurbs</do>
5
5
  <do>Match `lineHeight` to size/context (`m` default on root; `l` when open; `s` for dense chrome); omit `lineHeight`/`size` on nested Text so the outer Text owns type</do>
6
- <do>Prefer `balanced` on short wrapping paragraphs (hero lead, empty state, card blurb); omit when single-line or intentional ragged</do>
6
+ <do>Default `wrap` is `pretty` (orphan-aware). Prefer `wrap=&quot;balance&quot;` on short multi-line blurbs that need even line lengths; use `whiteSpace=&quot;nowrap&quot;` for single-line metrics (not `wrap=&quot;nowrap&quot;` unless you must keep space collapse unchanged)</do>
7
7
  <do>Omit `align` so copy inherits parent `text-align`; pass `align` only to override</do>
8
8
  <do>Card / settings section blurb: Stack `rowGap` + Title heading + muted `size=&quot;s&quot;` Text — no invent CSS gap</do>
9
9
  <do>Settings row: Stack `direction=&quot;row&quot;` + Text label + Switch/Checkbox (or nest Text inside Switch `label`) — Surface for chrome</do>
@@ -16,7 +16,7 @@
16
16
  <do>Long articles / docs / privacy walls → Prose (not Text alone for heading-aware rhythm); still keep a reading column</do>
17
17
  <dont>Using Text for headings — use Title (`render` for h1–h6)</dont>
18
18
  <dont>Putting `data-no-link-style` on Text-as-a when the default underline hover is wanted</dont>
19
- <dont>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap: balance` / `width: 100%` / `paddingBlock*` / `paddingInline*` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `balanced` / Stack `fullWidth` / `hPadding`/`vPadding` tuples cover it</dont>
19
+ <dont>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap` / `width: 100%` / `paddingBlock*` / `paddingInline*` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `wrap` / Stack `fullWidth` / `hPadding`/`vPadding` tuples cover it</dont>
20
20
  <dont>Setting body color with raw `--global-*` when `tone` covers the role</dont>
21
21
  <dont>Full-bleed marketing/UI paragraphs across a wide shell when a ~10–12-word measure fits</dont>
22
22
  <dont>Reusing a large-body shell (`~65ch`–`75ch` / wide rem) for small `size` copy — column width must track `size`</dont>
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <meta id="title" title="Title" category="typography" shared_contract="title">
3
- <summary>Theme-aware heading and display typography with readable-measure props (`maxWidth` / `lineHeight` / `balanced`).</summary>
3
+ <summary>Theme-aware heading and display typography with readable-measure props (`maxWidth` / `lineHeight` / `wrap`).</summary>
4
4
  <exports>
5
5
  <export name="Title" />
6
6
  </exports>
@@ -5,11 +5,11 @@
5
5
 
6
6
  <example title="Auth hero heading (readable measure)">
7
7
  <tsx><![CDATA[
8
- <Title size="1" render={<h1 />} maxWidth="36ch" lineHeight="s" balanced>
8
+ <Title size="1" render={<h1 />} maxWidth="36ch" lineHeight="s" wrap="balance">
9
9
  Ship real UI at the speed of thought.
10
10
  </Title>
11
11
  ]]></tsx>
12
- <notes>From `auth/login-view`. Pair `size` with `render={<h1 />}`; cap measure in `ch`; `lineHeight="s"` + `balanced` on wrapping display. Prefer `ch` over rem. (Live app nests Typewriter inside; see typewriter patterns.)</notes>
12
+ <notes>From `auth/login-view`. Pair `size` with `render={<h1 />}`; cap measure in `ch`; `lineHeight="s"` + `wrap="balance"` on short even-rag display (default `pretty` covers most titles). Prefer `ch` over rem. (Live app nests Typewriter inside; see typewriter patterns.)</notes>
13
13
  </example>
14
14
 
15
15
  <example title="Card section heading">
@@ -18,21 +18,21 @@
18
18
  <Title size="6" render={<h2 />}>
19
19
  Preferences
20
20
  </Title>
21
- <Text size="s" maxWidth="45ch" tone="muted" balanced>
21
+ <Text size="s" maxWidth="45ch" tone="muted">
22
22
  Manage your account settings and notifications.
23
23
  </Text>
24
24
  </Stack>
25
25
  ]]></tsx>
26
- <notes>From preview-grid `preferences` (+ payout-threshold, notifications, …). Dense card titles use `size="6"` + `h2`; blurb keeps `ch` measure + `balanced`.</notes>
26
+ <notes>From preview-grid `preferences` (+ payout-threshold, notifications, …). Dense card titles use `size="6"` + `h2`; blurb keeps `ch` measure (default `wrap="pretty"`).</notes>
27
27
  </example>
28
28
 
29
29
  <example title="Empty-state heading">
30
30
  <tsx><![CDATA[
31
- <Title align="center" size="5" render={<h3 />} balanced>
31
+ <Title align="center" size="5" render={<h3 />} wrap="balance">
32
32
  No Team Members
33
33
  </Title>
34
34
  ]]></tsx>
35
- <notes>From preview-grid `empty-team`. Centered mid-size heading; prefer `balanced` when the title wraps; pair with muted Text below.</notes>
35
+ <notes>From preview-grid `empty-team`. Centered mid-size heading; prefer `wrap="balance"` when the title wraps and needs even rag; pair with muted Text below.</notes>
36
36
  </example>
37
37
 
38
38
  <example title="Display metric">
@@ -46,7 +46,7 @@
46
46
  </Text>
47
47
  </Stack>
48
48
  ]]></tsx>
49
- <notes>From preview-grid `daily-activity-goal`. `size="display"` for hero numerals; `whiteSpace="nowrap"` keeps metric on one line — skip `balanced`.</notes>
49
+ <notes>From preview-grid `daily-activity-goal`. `size="display"` for hero numerals; `whiteSpace="nowrap"` keeps metric on one line — prefer that over `wrap="nowrap"`.</notes>
50
50
  </example>
51
51
 
52
52
  <example title="Balance display">
@@ -69,7 +69,7 @@
69
69
  <Title size="4" render={<h3 />}>
70
70
  Colors
71
71
  </Title>
72
- <Text size="s" tone="muted" maxWidth="48ch" balanced>
72
+ <Text size="s" tone="muted" maxWidth="48ch">
73
73
  Preview of theme voice, contrast, and color rhythm across accents.
74
74
  </Text>
75
75
  </Stack>
@@ -4,21 +4,18 @@
4
4
  <item>Headings and display text with title presets</item>
5
5
  <item>Semantic heading tags chosen explicitly through render</item>
6
6
  <item>Size and render paired together for most heading use cases</item>
7
- <item>Readable wrapping titles: `maxWidth` (~10–12 words/line, **scaled to `size`** — smaller → narrower), `lineHeight` (`s` on large wrapping / inside Prose), and `balanced` on short multi-line heads</item>
7
+ <item>Readable wrapping titles: `maxWidth` (~10–12 words/line, **scaled to `size`** — smaller → narrower), `lineHeight` (`s` on large wrapping / inside Prose), and `wrap` (default `pretty`; `balance` on short even-rag heads)</item>
8
8
  <item>Letter-spacing via `tracking` or text-transform via `transform` — prefer props over CSS on the Title root</item>
9
9
  <item>Fluid clamp sizing across title appearance presets (theme `--effect-fluid-typography` or per-instance `fluid`; off → fixed at --font-scale-display / h-* for that size)</item>
10
10
  </when_to_use>
11
11
  <when_not_to_use>
12
12
  <item>Body copy — use Text</item>
13
13
  <item>Body or mono family typography</item>
14
- <item>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap: balance` / `width: 100%` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `balanced` / parent Stack `fullWidth` cover the need</item>
14
+ <item>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap` / `width: 100%` when `tracking` / `transform` / `lineHeight` / `maxWidth` / `wrap` / parent Stack `fullWidth` cover the need</item>
15
15
  </when_not_to_use>
16
16
  <prop name="align" kind="react">
17
17
  <description>Aligns text using logical alignment values. Omit so `text-align` inherits from the parent.</description>
18
18
  </prop>
19
- <prop name="balanced" kind="react">
20
- <description>Enables balanced wrapping for block-like titles. Prefer on short wrapping heads (hero, empty state, section); omit for single-line / `whiteSpace=&quot;nowrap&quot;` metrics.</description>
21
- </prop>
22
19
  <prop name="color" kind="react">
23
20
  <description>Applies a literal color escape hatch.</description>
24
21
  </prop>
@@ -71,7 +68,10 @@
71
68
  <description>Overrides the size preset weight (`font-weight` + `wght` axis).</description>
72
69
  </prop>
73
70
  <prop name="whiteSpace" kind="react">
74
- <description>Controls white-space preservation and wrapping behavior.</description>
71
+ <description>Controls white-space collapse/preserve (`white-space`). Prefer `whiteSpace=&quot;nowrap&quot;` for single-line metrics/chrome (also collapses spaces). For wrapping algorithm / even line lengths use `wrap` (`text-wrap`) — not this prop.</description>
72
+ </prop>
73
+ <prop name="wrap" kind="react">
74
+ <description>Controls CSS `text-wrap` (wrapping algorithm / wrap on-off). Default `pretty` for orphan-aware titles. Prefer `balance` on short multi-line heads that need even line lengths. Use `wrap=&quot;nowrap&quot;` only when you need no wrap without changing white-space collapse; prefer `whiteSpace=&quot;nowrap&quot;` for metrics.</description>
75
75
  </prop>
76
76
  <prop name="align" kind="css">
77
77
  <description>Title alignment on the root when the `align` prop is set; omitted inherits parent `text-align`.</description>
@@ -125,6 +125,9 @@
125
125
  <description>Text transform on the root. Prefer the `transform` React prop; set this hook only when theming beyond the prop.</description>
126
126
  </prop>
127
127
  <prop name="white-space" kind="css">
128
- <description>White-space behavior on the root.</description>
128
+ <description>White-space behavior on the root (`--vui-title-white-space`). Prefer the `whiteSpace` React prop.</description>
129
+ </prop>
130
+ <prop name="wrap" kind="css">
131
+ <description>Text-wrap on the root (`--vui-title-wrap`). Prefer the `wrap` React prop; default `pretty`.</description>
129
132
  </prop>
130
133
  </props>
@@ -2,7 +2,7 @@
2
2
  <usage surface="title">
3
3
  <do>Headings and display type — pair `size` (visual preset) with `render={&lt;h1 /&gt;}`…`h6` for outline semantics (default root is `span`)</do>
4
4
  <do>Readable measure on wrapping titles: aim ~10–12 words per line — `maxWidth` / Stack `maxWidth` **scales with `size`** (smaller → narrower; larger → wider); prefer **`ch`** (not `rem`) in patterns/examples; large wrapping presets often `lineHeight=&quot;s&quot;`</do>
5
- <do>Prefer `balanced` on short wrapping titles (hero, empty state, section head); omit when single-line / `whiteSpace=&quot;nowrap&quot;` metrics</do>
5
+ <do>Default `wrap` is `pretty`. Prefer `wrap=&quot;balance&quot;` on short multi-line heads that need even line lengths; use `whiteSpace=&quot;nowrap&quot;` for single-line metrics (not `wrap=&quot;nowrap&quot;` unless space collapse must stay unchanged)</do>
6
6
  <do>Omit `align` so the heading inherits parent `text-align`; pass `align` only to override</do>
7
7
  <do>Title inside Prose → `lineHeight=&quot;s&quot;`; long-form rhythm stays on Prose — not Stack `rowGap`</do>
8
8
  <do>Card / panel header: Stack `rowGap=&quot;xs&quot;` + Title + muted Text blurb — Surface for card chrome</do>
@@ -14,7 +14,7 @@
14
14
  <do>Title-as-prose-link (`render={&lt;a /&gt;}`) keeps preflight link chrome — omit `data-no-link-style`</do>
15
15
  <dont>Assuming `size` changes the HTML tag — choose `render` explicitly</dont>
16
16
  <dont>Using Title for long body paragraphs — use Text</dont>
17
- <dont>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap: balance` / `width: 100%` / `paddingBlock*` / `paddingInline*` when props / Stack / `hPadding`/`vPadding` tuples cover it</dont>
18
- <dont>Full-bleed wrapping headlines across a wide shell when a capped measure + `balanced` fits</dont>
17
+ <dont>Inventing CSS `letter-spacing` / `text-transform` / `line-height` / `max-width` / `text-wrap` / `width: 100%` / `paddingBlock*` / `paddingInline*` when props / Stack / `hPadding`/`vPadding` tuples cover it</dont>
18
+ <dont>Full-bleed wrapping headlines across a wide shell when a capped measure + `wrap` fits</dont>
19
19
  <dont>One fixed wide measure for every Title `size` — smaller presets need a narrower column for ~10–12 words/line</dont>
20
20
  </usage>
@@ -138,9 +138,8 @@
138
138
  <attr name="data-vibrant">
139
139
  <presence>boolean attribute; value ignored</presence>
140
140
  <effect>
141
- When the active theme sets --effect-vibrancy, applies vibrancy backdrop-filter (brightness/blur/saturate). Surface with data-vibrant translucifies its fill via component CSS: it doesn't apply a background color to the element, that still need to be set by the consumer.
142
- Only the urface component applies the correct `color` prop based on the presence of the attribute. For custom styles you need to set the background color explicitly if you need one.
143
- In built-in themes, the applied backdrop-filter is different based on the active theme mode: light or dark.
141
+ When the active theme sets --effect-vibrancy, applies vibrancy backdrop-filter (blur/saturate). Surface with data-vibrant translucifies its fill via component CSS: it doesn't apply a background color to the element, that still need to be set by the consumer.
142
+ Only the Surface component applies the correct `color` prop based on the presence of the attribute. For custom styles you need to set the background color explicitly if you need one.
144
143
  </effect>
145
144
  <values>
146
145
  <value>(boolean presence)</value>
@@ -152,7 +151,6 @@
152
151
  <gotcha>Surface</gotcha>
153
152
  <gotcha>--effect-vibrancy</gotcha>
154
153
  <gotcha>--vibrancy-blur</gotcha>
155
- <gotcha>--vibrancy-brightness</gotcha>
156
154
  </attr>
157
155
  <attr name="data-layout-fixed">
158
156
  <presence>boolean attribute on table elements</presence>
@@ -45,9 +45,9 @@
45
45
  <agent>Theme-level gates. Runtime polarity/details: toggles.xml. Do not invent alternate effect hooks.</agent>
46
46
  </topic>
47
47
  <topic id="vibrancy" surface="theme">
48
- <pattern>--vibrancy-blur | --vibrancy-brightness</pattern>
49
- <summary>Vibrancy glass params; blur is a numeric amount consumed as pixels, brightness is a percent string.</summary>
50
- <agent>Theme params for data-vibrant hosts when --effect-vibrancy is on. Do not hand-roll backdrop-filter.</agent>
48
+ <pattern>--vibrancy-blur</pattern>
49
+ <summary>Vibrancy glass blur amount; numeric value consumed as pixels in data-vibrant backdrop-filter (with fixed saturate).</summary>
50
+ <agent>Theme param for data-vibrant hosts when --effect-vibrancy is on. Do not hand-roll backdrop-filter.</agent>
51
51
  </topic>
52
52
  <topic id="radius" surface="theme">
53
53
  <pattern>--radius-* | --corner-shape</pattern>
@@ -5,13 +5,13 @@
5
5
  <when>html registers polarity via contrast-color(var(--global-background)) so light backgrounds resolve to black and dark backgrounds to white; container name is root (see core.css).</when>
6
6
  <when>data-mode=&quot;light&quot; forces --is-light-mode: black and color-scheme: light; data-mode=&quot;dark&quot; forces white and color-scheme: dark.</when>
7
7
  <when>data-mode=&quot;inverted&quot; flips color-scheme against the root value: @container root style(--is-light-mode: black) → dark; style(--is-light-mode: white) → light.</when>
8
- <when>Component/preflight CSS branches on polarity with @container root style(--is-light-mode: black) or white — e.g. vibrancy brightness, holofoil mix-blend, Button/Chip secondary fills. Do not invent alternate light/dark hooks.</when>
8
+ <when>Component/preflight CSS branches on polarity with @container root style(--is-light-mode: black) or white — e.g. holofoil mix-blend, Button/Chip secondary fills. Do not invent alternate light/dark hooks.</when>
9
9
  </toggle>
10
10
  <toggle name="--effect-shadows">
11
11
  <when>Empty/unset enables data-elevation box-shadow stacks; set to initial to disable. Preflight gates with @container root not style(--effect-shadows: initial). Do not hand-roll box-shadow.</when>
12
12
  </toggle>
13
13
  <toggle name="--effect-vibrancy">
14
- <when>Empty/unset enables data-vibrant backdrop filters; set to initial to disable. Preflight gates with @container root not style(--effect-vibrancy: initial); vibrancy may further branch on --is-light-mode. Do not hand-roll backdrop-filter.</when>
14
+ <when>Empty/unset enables data-vibrant backdrop filters; set to initial to disable. Preflight gates with @container root not style(--effect-vibrancy: initial). Do not hand-roll backdrop-filter.</when>
15
15
  </toggle>
16
16
  <toggle name="--effect-corner-shape">
17
17
  <when>Empty/unset enables theme corner-shape on *; set to initial to disable. Preflight gates with @container root not style(--effect-corner-shape: initial) and applies var(--__corner-shape, var(--corner-shape)). Pair with --corner-shape token.</when>
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <index package="@viraui/react" version="2026.8.0" generated="2026-10-14T16:23:26.846Z">
2
+ <index package="@viraui/react" version="2026.9.1" generated="2026-10-15T08:18:55.911Z">
3
3
  <categories>
4
4
  <category id="layout" />
5
5
  <category id="action" />
@@ -312,7 +312,7 @@
312
312
  </units>
313
313
  </entry>
314
314
  <entry id="prose" category="typography" title="Prose">
315
- <summary>Text-wall grouping region (articles, docs, privacy) with heading-aware em rhythm; reading column via parent Stack `maxWidth` sized for body Text `size`.</summary>
315
+ <summary>Text-wall grouping region (articles, docs, privacy) with heading-aware em rhythm, region `wrap` (default `pretty`), and reading column via parent Stack `maxWidth` sized for body Text `size`.</summary>
316
316
  <units>
317
317
  <unit kind="meta" href="components/prose/meta.xml" />
318
318
  <unit kind="a11y" href="components/prose/a11y.xml" />
@@ -442,7 +442,7 @@
442
442
  </units>
443
443
  </entry>
444
444
  <entry id="text" category="typography" title="Text">
445
- <summary>Theme-aware body-copy primitive with tone, family, sizing, and readable-measure props (`maxWidth` / `lineHeight` / `balanced`).</summary>
445
+ <summary>Theme-aware body-copy primitive with tone, family, sizing, and readable-measure props (`maxWidth` / `lineHeight` / `wrap`).</summary>
446
446
  <units>
447
447
  <unit kind="meta" href="components/text/meta.xml" />
448
448
  <unit kind="a11y" href="components/text/a11y.xml" />
@@ -472,7 +472,7 @@
472
472
  </units>
473
473
  </entry>
474
474
  <entry id="title" category="typography" title="Title">
475
- <summary>Theme-aware heading and display typography with readable-measure props (`maxWidth` / `lineHeight` / `balanced`).</summary>
475
+ <summary>Theme-aware heading and display typography with readable-measure props (`maxWidth` / `lineHeight` / `wrap`).</summary>
476
476
  <units>
477
477
  <unit kind="meta" href="components/title/meta.xml" />
478
478
  <unit kind="a11y" href="components/title/a11y.xml" />
@@ -598,18 +598,6 @@
598
598
  <unit kind="pattern" href="patterns/compose-layout-first.xml" />
599
599
  </units>
600
600
  </entry>
601
- <entry id="equal-width-actions" category="pattern" title="Equal-width action row">
602
- <summary>Span or share space with Stack `fullWidth` and/or `expandChildren` (and control `fullWidth` when the surface owns it). Orthogonal: `fullWidth` sizes the Stack; `expandChildren` grows direct children …</summary>
603
- <units>
604
- <unit kind="pattern" href="patterns/equal-width-actions.xml" />
605
- </units>
606
- </entry>
607
- <entry id="page-chrome" category="pattern" title="Page chrome with Stack render">
608
- <summary>Own page/section flex with Stack. Pick semantic tags (`header`, `main`, `nav`, `section`, …) via `render={&amp;lt;tag /&amp;gt;}` — keep Stack as the layout engine. CSS modules may set min-block-size / scrol…</summary>
609
- <units>
610
- <unit kind="pattern" href="patterns/page-chrome.xml" />
611
- </units>
612
- </entry>
613
601
  <entry id="settings-panel" category="pattern" title="Settings panel (Surface + Stack)">
614
602
  <summary>Wrap a settings block in Surface for fill/border/radius/padding; nest Stack for child gaps and rows. Compose the settings-row pattern inside for label+control rows. Prefer props over CSS for spacing …</summary>
615
603
  <units>
@@ -622,10 +610,4 @@
622
610
  <unit kind="pattern" href="patterns/settings-row.xml" />
623
611
  </units>
624
612
  </entry>
625
- <entry id="stack-as-surface" category="pattern" title="Stack as Surface (avoid extra DOM)">
626
- <summary>When a flex cluster also needs Surface chrome (border, color, radius, padding), prefer `Stack render={&amp;lt;Surface … /&amp;gt;}` so layout + chrome share one root. Put gap/align/`fullWidth`/`expandChildre…</summary>
627
- <units>
628
- <unit kind="pattern" href="patterns/stack-as-surface.xml" />
629
- </units>
630
- </entry>
631
613
  </index>
@@ -10,7 +10,7 @@
10
10
  <ref id="bleed" units="meta,usage" />
11
11
  </uses>
12
12
  <do>Prefer Vira layout roots (`Stack`, `Grid`, `Masonry`, `Bleed`, `Surface`) and their public props for every consumer layout. Treat `Stack` as the default box: an enriched `div` (flex + gap/padding/align/`fullWidth`/`render`/…) — prefer it over bare wrapper `div`s even for simple nesting. Compose **with** these parts; default custom CSS = **app chrome** the system does not own. Prefer another Vira component (e.g. `Surface` for border/fill/radius) or `render` merge over a CSS class for chrome the library already owns. Do not open a CSS module to reshape a Vira control unless the consumer **expressly asked** for that override (still read `props`/`usage` first; a future override layer will formalize hooks).</do>
13
- <dont>Do not invent bare wrapper `div`s (or `display:flex` / `display:grid` / CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / `width` / `inline-size` / border/radius chrome on raw tags or Vira control roots) when `Stack` or another layout primitive / `Surface` / a public `fullWidth` or `hPadding`/`vPadding` tuple covers it. Do not skip composition to reach for a one-off stylesheet — including size-fill classNames that would do nothing on fixed-size controls. Do not pass `render` that restates a component&apos;s default root (e.g. Stack `render={&lt;div /&gt;}`) — omit `render` unless the host changes.</dont>
13
+ <dont>Do not invent bare wrapper `div`s (or `display:flex` / `display:grid` / CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / `width` / `height` / `inline-size` / `block-size: 100%` / border/radius chrome on raw tags or Vira control roots) when `Stack` or another layout primitive / `Surface` / a public `fullWidth`/`fullHeight`/`expandChildren` + stretch align (Stack `patterns.xml`) or `hPadding`/`vPadding` tuple covers it. Do not skip composition to reach for a one-off stylesheet — including size-fill classNames that would do nothing on fixed-size controls. Do not pass `render` that restates a component&apos;s default root (e.g. Stack `render={&lt;div /&gt;}`) — omit `render` unless the host changes.</dont>
14
14
  <tsx><![CDATA[
15
15
  {/* Flex row + panel chrome: one DOM node via Stack render={<Surface />} */}
16
16
  <Stack