@viraui/react 2026.10.0 → 2026.11.0-next.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.
Files changed (127) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +8 -0
  2. package/dist/catalog.json +12 -0
  3. package/dist/components/avatar/avatar.d.ts +6 -0
  4. package/dist/components/avatar/avatar.js +2 -2
  5. package/dist/components/badge/badge.css +1 -1
  6. package/dist/components/button/button.css +1 -1
  7. package/dist/components/dialog/dialog-sheet.d.ts +1 -1
  8. package/dist/components/gauge/arcs.d.ts +134 -0
  9. package/dist/components/gauge/arcs.js +145 -0
  10. package/dist/components/gauge/context.d.ts +134 -0
  11. package/dist/components/gauge/context.js +83 -0
  12. package/dist/components/gauge/control.d.ts +107 -0
  13. package/dist/components/gauge/control.js +223 -0
  14. package/dist/components/gauge/demos/_shared.d.ts +28 -0
  15. package/dist/components/gauge/demos/activity-ring.d.ts +9 -0
  16. package/dist/components/gauge/demos/air-quality.d.ts +9 -0
  17. package/dist/components/gauge/demos/analog-dial.d.ts +9 -0
  18. package/dist/components/gauge/demos/battery.d.ts +9 -0
  19. package/dist/components/gauge/demos/chronograph.d.ts +9 -0
  20. package/dist/components/gauge/demos/clock.d.ts +9 -0
  21. package/dist/components/gauge/demos/compass.d.ts +9 -0
  22. package/dist/components/gauge/demos/data-usage.d.ts +9 -0
  23. package/dist/components/gauge/demos/dimmer.d.ts +9 -0
  24. package/dist/components/gauge/demos/fuel.d.ts +9 -0
  25. package/dist/components/gauge/demos/heart-rate.d.ts +9 -0
  26. package/dist/components/gauge/demos/internet-speed.d.ts +9 -0
  27. package/dist/components/gauge/demos/nested-rings.d.ts +11 -0
  28. package/dist/components/gauge/demos/orrery.d.ts +12 -0
  29. package/dist/components/gauge/demos/power-meter.d.ts +9 -0
  30. package/dist/components/gauge/demos/progress-ring.d.ts +9 -0
  31. package/dist/components/gauge/demos/range.d.ts +10 -0
  32. package/dist/components/gauge/demos/saas-metric.d.ts +9 -0
  33. package/dist/components/gauge/demos/segments.d.ts +9 -0
  34. package/dist/components/gauge/demos/simple.d.ts +9 -0
  35. package/dist/components/gauge/demos/speed-fuel.d.ts +10 -0
  36. package/dist/components/gauge/demos/speedometer.d.ts +9 -0
  37. package/dist/components/gauge/demos/sprint.d.ts +9 -0
  38. package/dist/components/gauge/demos/sun-path.d.ts +9 -0
  39. package/dist/components/gauge/demos/system.d.ts +11 -0
  40. package/dist/components/gauge/demos/tachometer.d.ts +9 -0
  41. package/dist/components/gauge/demos/temperature.d.ts +9 -0
  42. package/dist/components/gauge/demos/thermostat.d.ts +9 -0
  43. package/dist/components/gauge/demos/timer.d.ts +9 -0
  44. package/dist/components/gauge/demos/volume.d.ts +10 -0
  45. package/dist/components/gauge/demos/wind.d.ts +9 -0
  46. package/dist/components/gauge/dot.d.ts +55 -0
  47. package/dist/components/gauge/dot.js +34 -0
  48. package/dist/components/gauge/gauge.css +1 -0
  49. package/dist/components/gauge/gauge.d.ts +84 -0
  50. package/dist/components/gauge/gauge.js +62 -0
  51. package/dist/components/gauge/gauge.module.js +24 -0
  52. package/dist/components/gauge/index.d.ts +15 -0
  53. package/dist/components/gauge/inset.d.ts +30 -0
  54. package/dist/components/gauge/inset.js +39 -0
  55. package/dist/components/gauge/math.d.ts +69 -0
  56. package/dist/components/gauge/math.js +135 -0
  57. package/dist/components/gauge/needle.d.ts +81 -0
  58. package/dist/components/gauge/needle.js +162 -0
  59. package/dist/components/gauge/scale.d.ts +44 -0
  60. package/dist/components/gauge/scale.js +21 -0
  61. package/dist/components/gauge/text.d.ts +79 -0
  62. package/dist/components/gauge/text.js +42 -0
  63. package/dist/components/gauge/ticks.d.ts +169 -0
  64. package/dist/components/gauge/ticks.js +124 -0
  65. package/dist/components/gauge/tooltip.d.ts +117 -0
  66. package/dist/components/gauge/tooltip.js +337 -0
  67. package/dist/components/gauge/transition.d.ts +60 -0
  68. package/dist/components/gauge/transition.js +129 -0
  69. package/dist/components/gauge/use-animated-value.d.ts +14 -0
  70. package/dist/components/gauge/use-animated-value.js +111 -0
  71. package/dist/components/gauge/utils.d.ts +51 -0
  72. package/dist/components/gauge/utils.js +80 -0
  73. package/dist/components/icon-meter/icon-meter.css +1 -0
  74. package/dist/components/icon-meter/icon-meter.d.ts +62 -0
  75. package/dist/components/icon-meter/icon-meter.js +105 -0
  76. package/dist/components/icon-meter/icon-meter.module.js +11 -0
  77. package/dist/components/icon-meter/index.d.ts +2 -0
  78. package/dist/components/icon-meter/utils.d.ts +22 -0
  79. package/dist/components/icon-meter/utils.js +40 -0
  80. package/dist/components/index.d.ts +2 -0
  81. package/dist/components/popover/popover-sheet.d.ts +1 -2
  82. package/dist/components/stack/stack.d.ts +9 -2
  83. package/dist/components/tabs/tabs.d.ts +1 -2
  84. package/dist/index.js +17 -1
  85. package/dist/internal/chrome-icons/chrome-icons.d.ts +4 -0
  86. package/dist/internal/chrome-icons/chrome-icons.js +12 -4
  87. package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/cjs/react-dom.development.js +192 -0
  88. package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/cjs/react-dom.production.js +156 -0
  89. package/dist/node_modules/.pnpm/react-dom@19.3.0_react@19.3.0/node_modules/react-dom/index.js +22 -0
  90. package/dist/preflight.css +1 -1
  91. package/dist/specs/components/avatar/props.xml +3 -0
  92. package/dist/specs/components/avatar/usage.xml +1 -0
  93. package/dist/specs/components/badge/a11y.xml +1 -1
  94. package/dist/specs/components/button/props.xml +2 -2
  95. package/dist/specs/components/button/usage.xml +1 -1
  96. package/dist/specs/components/gauge/a11y.xml +8 -0
  97. package/dist/specs/components/gauge/meta.xml +38 -0
  98. package/dist/specs/components/gauge/patterns.xml +1158 -0
  99. package/dist/specs/components/gauge/props.xml +452 -0
  100. package/dist/specs/components/gauge/usage.xml +21 -0
  101. package/dist/specs/components/icon-button/props.xml +2 -2
  102. package/dist/specs/components/icon-button/usage.xml +1 -1
  103. package/dist/specs/components/icon-meter/a11y.xml +9 -0
  104. package/dist/specs/components/icon-meter/meta.xml +21 -0
  105. package/dist/specs/components/icon-meter/patterns.xml +23 -0
  106. package/dist/specs/components/icon-meter/props.xml +44 -0
  107. package/dist/specs/components/icon-meter/usage.xml +13 -0
  108. package/dist/specs/components/linear-progress/usage.xml +1 -0
  109. package/dist/specs/components/meter/meta.xml +1 -0
  110. package/dist/specs/components/meter/props.xml +1 -0
  111. package/dist/specs/components/meter/usage.xml +1 -0
  112. package/dist/specs/components/stack/patterns.xml +21 -21
  113. package/dist/specs/components/stack/props.xml +6 -6
  114. package/dist/specs/components/stack/usage.xml +4 -2
  115. package/dist/specs/components/text/patterns.xml +1 -1
  116. package/dist/specs/components/text/usage.xml +1 -1
  117. package/dist/specs/components/toggle-button/props.xml +1 -1
  118. package/dist/specs/components/toggle-button/usage.xml +1 -1
  119. package/dist/specs/components/toggle-text-button/props.xml +1 -1
  120. package/dist/specs/foundation/attributes.xml +3 -3
  121. package/dist/specs/foundation/modules.xml +1 -1
  122. package/dist/specs/foundation/theme-topics.xml +7 -2
  123. package/dist/specs/index.xml +21 -1
  124. package/dist/specs/patterns/compose-layout-first.xml +1 -1
  125. package/dist/specs/patterns/settings-panel.xml +1 -1
  126. package/dist/specs/patterns/settings-row.xml +1 -1
  127. package/package.json +2 -2
@@ -8,6 +8,7 @@
8
8
  </when_to_use>
9
9
  <when_not_to_use>
10
10
  <item>Use LinearProgress for in-progress tasks or indeterminate work.</item>
11
+ <item>Use IconMeter for discrete icon-row scores (stars / hearts / custom glyphs).</item>
11
12
  <item>Use Slider when the user needs to choose or adjust a value.</item>
12
13
  <item>Use Spinner for a small standalone loading affordance without metric context.</item>
13
14
  </when_not_to_use>
@@ -7,6 +7,7 @@
7
7
  <do>Color-coded metrics via highlight `variant` (`green`, `red`, `yellow`, …) or default `primary` — tints track wash + indicator like Chip</do>
8
8
  <do>Prefer LinearProgress for in-progress or indeterminate tasks (`value={null}`) — Meter has no indeterminate mode</do>
9
9
  <dont>Using Meter as an interactive value control — use Slider</dont>
10
+ <dont>Using Meter for discrete icon-row scores (stars / hearts) — use IconMeter</dont>
10
11
  <dont>Using Meter for indeterminate or in-progress work — use LinearProgress</dont>
11
12
  <dont>Modeling invalid or disabled meter state — Base UI Meter exposes neither</dont>
12
13
  <dont>Hiding the metric name when multiple meters share a view</dont>
@@ -9,7 +9,7 @@
9
9
  <Stack
10
10
  direction="row"
11
11
  columnGap="s"
12
- vAlign="center"
12
+ vAlign="safe center"
13
13
  fullWidth
14
14
  render={<Surface border="all" color={1} radius="m" hPadding="m" vPadding="s" />}
15
15
  >
@@ -45,7 +45,7 @@
45
45
  <Stack
46
46
  direction="row"
47
47
  hAlign="space-between"
48
- vAlign="center"
48
+ vAlign="safe center"
49
49
  columnGap="m"
50
50
  hPadding="m"
51
51
  vPadding="m"
@@ -72,19 +72,19 @@
72
72
  <Stack
73
73
  render={<header />}
74
74
  direction="row"
75
- vAlign="center"
75
+ vAlign="safe center"
76
76
  hAlign="space-between"
77
77
  hPadding="m"
78
78
  vPadding="m"
79
79
  columnGap="s"
80
80
  >
81
- <Stack direction="row" vAlign="center" columnGap="s">
81
+ <Stack direction="row" vAlign="safe center" columnGap="s">
82
82
  {/* brand / logo */}
83
83
  </Stack>
84
84
 
85
85
  <Surface hPadding="xs" vPadding="xs" radius="m" border="all" data-vibrant>
86
86
  <Surface radius="auto" color={1} hPadding="xs" vPadding="xs">
87
- <Stack render={<nav />} direction="row" vAlign="center" columnGap="xs">
87
+ <Stack render={<nav />} direction="row" vAlign="safe center" columnGap="xs">
88
88
  <ButtonLink size="s" variant="secondary" href="/hub">
89
89
  Hub
90
90
  </ButtonLink>
@@ -98,7 +98,7 @@
98
98
  </Surface>
99
99
  </Surface>
100
100
 
101
- <Stack direction="row" vAlign="center" columnGap="s">
101
+ <Stack direction="row" vAlign="safe center" columnGap="s">
102
102
  <Button size="s" variant="secondary">
103
103
  Sign out
104
104
  </Button>
@@ -113,7 +113,7 @@
113
113
  <form>
114
114
  <Stack direction="row" columnGap="m" rowGap="m" hAlign="start" vAlign="start" wrap>
115
115
  <Textfield type="email" placeholder="your@email.com" size={30} aria-label="Email" />
116
- <Stack direction="row" vAlign="center" columnGap="m">
116
+ <Stack direction="row" vAlign="safe center" columnGap="m">
117
117
  <Button type="submit">Send magic link</Button>
118
118
  or
119
119
  <ButtonLink variant="secondary" href="#">
@@ -136,7 +136,7 @@
136
136
  expandChildren
137
137
  >
138
138
  {/* brand */}
139
- <Stack rowGap="xl" vAlign="center">
139
+ <Stack rowGap="xl" vAlign="safe center">
140
140
  <Stack vPadding={[0, 'l']} rowGap="xl">
141
141
  <Title size="1" render={<h1 />} maxWidth="36ch" lineHeight="s">
142
142
  Design systems that ship
@@ -173,8 +173,8 @@
173
173
  <Stack hPadding="m">
174
174
  <Surface color={2} hoverColor={3} radius="m" vPadding="s">
175
175
  <Stack rowGap="s" hPadding="m" vPadding={[0, 's']}>
176
- <Stack direction="row" vAlign="center" hAlign="space-between" columnGap="s">
177
- <Stack direction="row" vAlign="center" columnGap="s">
176
+ <Stack direction="row" vAlign="safe center" hAlign="space-between" columnGap="s">
177
+ <Stack direction="row" vAlign="safe center" columnGap="s">
178
178
  {/* section icon */}
179
179
  <Text size="xs" weight="semibold">
180
180
  Colors
@@ -198,7 +198,7 @@
198
198
  <example title="Dialog form (import)">
199
199
  <tsx><![CDATA[
200
200
  <Dialog.Sheet title="Import preset" description="Paste preset code." showCloseButton headerAlign="center">
201
- <Stack rowGap="m" hAlign="center" hPadding="m" vPadding={['s', 0]}>
201
+ <Stack rowGap="m" hAlign="safe center" hPadding="m" vPadding={['s', 0]}>
202
202
  <Textfield size={40} placeholder="Paste preset…" aria-label="Preset code" />
203
203
  <Stack direction="row" hAlign="end" columnGap="s">
204
204
  <Button>Apply</Button>
@@ -213,7 +213,7 @@
213
213
  <example title="Dialog action strip (export)">
214
214
  <tsx><![CDATA[
215
215
  <Stack rowGap="m" hPadding="m" vPadding={['s', 0]}>
216
- <Stack direction="row" hAlign="center" columnGap="m">
216
+ <Stack direction="row" hAlign="safe center" columnGap="m">
217
217
  <Button size="l">Download</Button>
218
218
  <ButtonLink size="l" variant="secondary" href="#">
219
219
  Share
@@ -231,7 +231,7 @@
231
231
  <example title="Toolbar chip (canvas zoom)">
232
232
  <tsx><![CDATA[
233
233
  <Surface color={1} border="all" radius="m" vPadding="2xs" hPadding="2xs">
234
- <Stack direction="row" vAlign="center">
234
+ <Stack direction="row" vAlign="safe center">
235
235
  <IconButton aria-label="Zoom out" icon={<Minus />} variant="flat" />
236
236
  <IconButton aria-label="Reset zoom" icon={<FocusCenter />} variant="flat" />
237
237
  <IconButton aria-label="Zoom in" icon={<Plus />} variant="flat" />
@@ -243,11 +243,11 @@
243
243
 
244
244
  <example title="Empty / info state">
245
245
  <tsx><![CDATA[
246
- <Stack hAlign="center" vAlign="center" rowGap="l" render={<div role="status" />}>
246
+ <Stack hAlign="safe center" vAlign="safe center" rowGap="l" render={<div role="status" />}>
247
247
  <Surface color={1} border="all" hPadding="m" vPadding="m" radius="full">
248
248
  {/* icon */}
249
249
  </Surface>
250
- <Stack hAlign="center" maxWidth="36ch" rowGap="s">
250
+ <Stack hAlign="safe center" maxWidth="36ch" rowGap="s">
251
251
  <Title align="center" render={<h2 />} size="3">
252
252
  No prompts yet
253
253
  </Title>
@@ -267,7 +267,7 @@
267
267
  rowGap="m"
268
268
  hPadding="l"
269
269
  vPadding="2xl"
270
- hAlign="center"
270
+ hAlign="safe center"
271
271
  render={<Surface border="all" borderStyle="dashed" radius="l" />}
272
272
  >
273
273
  <AvatarGroup
@@ -322,7 +322,7 @@
322
322
  </Stack>
323
323
 
324
324
  <Surface color={2} hPadding="l" vPadding="m">
325
- <Stack columnGap="m" direction="row" hAlign="space-between" vAlign="center">
325
+ <Stack columnGap="m" direction="row" hAlign="space-between" vAlign="safe center">
326
326
  <Button variant="secondary">Reset</Button>
327
327
  <Button>Save Preferences</Button>
328
328
  </Stack>
@@ -353,7 +353,7 @@
353
353
 
354
354
  <Stack rowGap="m">
355
355
  <Slider label="Minimum Payout Amount" min={50} max={10000} step={50} value={2500} />
356
- <Stack columnGap="s" direction="row" hAlign="space-between" vAlign="center">
356
+ <Stack columnGap="s" direction="row" hAlign="space-between" vAlign="safe center">
357
357
  <Text family="mono" size="xs" tone="muted">
358
358
  $50 (MIN)
359
359
  </Text>
@@ -374,8 +374,8 @@
374
374
  <example title="Directory list row">
375
375
  <tsx><![CDATA[
376
376
  <Surface color={2} radius="m" hPadding="m" vPadding="m">
377
- <Stack columnGap="m" direction="row" hAlign="space-between" vAlign="center">
378
- <Stack columnGap="m" direction="row" vAlign="center">
377
+ <Stack columnGap="m" direction="row" hAlign="space-between" vAlign="safe center">
378
+ <Stack columnGap="m" direction="row" vAlign="safe center">
379
379
  <Avatar alt="Sarah Chen" fallback="SC" size="s" />
380
380
  <Stack rowGap="xs">
381
381
  <Text weight="semibold">Sarah Chen</Text>
@@ -445,7 +445,7 @@
445
445
  <tsx><![CDATA[
446
446
  {/* Parent must be sized. Children share height + fill width — props only. */}
447
447
  <Stack rowGap="s" expandChildren fullWidth fullHeight hAlign="stretch">
448
- <Stack direction="row" columnGap="m" vAlign="center" hPadding="m" vPadding="s">
448
+ <Stack direction="row" columnGap="m" vAlign="safe center" hPadding="m" vPadding="s">
449
449
  {/* header strip */}
450
450
  </Stack>
451
451
  <Stack rowGap="m" hPadding="m" vPadding="m" expandChildren>
@@ -5,7 +5,7 @@
5
5
  <item>Composing screens and component internals without custom flex CSS</item>
6
6
  <item>Custom native root through render while keeping data-stack hooks</item>
7
7
  <item>Style descendants with `@container stack` queries when layout, gap, or typography should respond to the Stack&apos;s own inline-size instead of the viewport (set `enableContainer` on the Stack you&apos;re querying)</item>
8
- <item>Centered max-width shells: parent `hAlign=&quot;center&quot;` + child `fullWidth` + `maxWidth`</item>
8
+ <item>Centered max-width shells: parent `hAlign=&quot;safe center&quot;` + child `fullWidth` + `maxWidth` (prefer `safe` on content-position)</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
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>
@@ -34,10 +34,10 @@
34
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>
35
35
  </prop>
36
36
  <prop name="fullWidth" kind="react">
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>
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;safe 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>
38
38
  </prop>
39
39
  <prop name="hAlign" kind="react">
40
- <description>Aligns content on the horizontal axis from the consumer point of view.</description>
40
+ <description>Aligns content on the horizontal axis from the consumer point of view. Accepts CSS `justify-content` / `align-items` values (which property is used depends on `direction`), including overflow keywords such as `safe center`.</description>
41
41
  </prop>
42
42
  <prop name="hPadding" kind="react">
43
43
  <description>Sets inline padding using one token for both sides or a `[start, end]` tuple (`0` allowed). Prefer the tuple for one-sided inset — never `style`/`paddingInline*` CSS when this prop covers it.</description>
@@ -61,7 +61,7 @@
61
61
  <description>Sets the gap between flex rows using the Vira space token scale.</description>
62
62
  </prop>
63
63
  <prop name="vAlign" kind="react">
64
- <description>Aligns content on the vertical axis from the consumer point of view.</description>
64
+ <description>Aligns content on the vertical axis from the consumer point of view. Accepts CSS `justify-content` / `align-items` values (which property is used depends on `direction`), including overflow keywords such as `safe center`.</description>
65
65
  </prop>
66
66
  <prop name="vPadding" kind="react">
67
67
  <description>Sets block padding using one token for both sides or a `[start, end]` tuple (`0` allowed). Prefer the tuple for one-sided inset (e.g. bottom only `vPadding={[0, &apos;l&apos;]}`) — never `style`/`paddingBlock*` CSS when this prop covers it.</description>
@@ -73,7 +73,7 @@
73
73
  <description>Flex column gap on the root.</description>
74
74
  </prop>
75
75
  <prop name="h-align" kind="css">
76
- <description>Logical horizontal flex alignment hook.</description>
76
+ <description>Horizontal flex alignment custom property (`justify-content` or `align-items` by `direction`). Accepts full CSS values including overflow keywords such as `safe center`.</description>
77
77
  </prop>
78
78
  <prop name="max-width" kind="css">
79
79
  <description>Max inline size of the stack root.</description>
@@ -97,6 +97,6 @@
97
97
  <description>Flex row gap on the root.</description>
98
98
  </prop>
99
99
  <prop name="v-align" kind="css">
100
- <description>Logical vertical flex alignment hook.</description>
100
+ <description>Vertical flex alignment custom property (`justify-content` or `align-items` by `direction`). Accepts full CSS values including overflow keywords such as `safe center`.</description>
101
101
  </prop>
102
102
  </props>
@@ -8,14 +8,16 @@
8
8
  row → `direction=&quot;row&quot;` + `expandChildren` + `fullHeight` + `vAlign=&quot;stretch&quot;` (share width + fill height);
9
9
  column → `expandChildren` + `fullWidth` + `fullHeight` + `hAlign=&quot;stretch&quot;` (share height + fill width)</do>
10
10
  <do>Settings rows: Stack `direction=&quot;row&quot;` + Text (label/description column) + Switch or Checkbox — nest in Surface for panel chrome</do>
11
- <do>Centered capped shells: parent `hAlign=&quot;center&quot;` + child Stack `fullWidth` + `maxWidth`</do>
11
+ <do>Centered capped shells: parent `hAlign=&quot;safe center&quot;` + child Stack `fullWidth` + `maxWidth` — prefer `safe` on content-position (`center`/`end`); keep `stretch` / `space-*` bare</do>
12
+ <do>Overflow-safe flex alignment via `hAlign`/`vAlign` props (`safe center`, `safe end`, …) — never `style`/`justifyContent`/`alignItems` solely for `safe …`</do>
12
13
  <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
14
  <do>Semantic/native roots via `render` (`header`, `main`, `nav`, `section`, …) while keeping Stack as the layout engine</do>
14
15
  <do>Opt into `@container stack` with `enableContainer` when layout should follow this Stack&apos;s inline-size, not the viewport</do>
15
16
  <dont>Reaching for a plain wrapper `div` when Stack (optionally with `render` for a semantic tag) can own the box</dont>
16
17
  <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>
17
18
  <dont>Assuming Stack expands direct children by default — pass `expandChildren` when children should grow on the flex main axis</dont>
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>
19
+ <dont>Using `expandChildren` to fill parent width under `hAlign=&quot;safe center&quot;` / `center` — that is `fullWidth` on the child Stack (self `inline-size`), not child flex-grow</dont>
20
+ <dont>Inventing `style` / CSS `justify-content` / `align-items` (including solely for `safe center`) when `hAlign`/`vAlign` cover it — prefer `safe` on content-position values</dont>
19
21
  <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>
20
22
  <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>
21
23
  <dont>Putting `data-grow=&quot;false&quot;` on an ancestor to control nested `expandChildren` — set it on the child that should not grow</dont>
@@ -70,7 +70,7 @@
70
70
  Forgot password?
71
71
  </Text>
72
72
  ]]></tsx>
73
- <notes>Text-as-a keeps preflight link chrome (animated underline). Do not set `data-no-link-style` — that attr is for painted chrome links only.</notes>
73
+ <notes>Text-as-a keeps preflight link chrome (always-visible decoration; hover/focus offset only). Do not set `data-no-link-style` — that attr is for painted chrome links only.</notes>
74
74
  </example>
75
75
 
76
76
  <example title="Empty-state centered">
@@ -15,7 +15,7 @@
15
15
  <do>Inline prose link: `Text render={&lt;a href=… /&gt;}` — keeps preflight link chrome (no `data-no-link-style`)</do>
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
- <dont>Putting `data-no-link-style` on Text-as-a when the default underline hover is wanted</dont>
18
+ <dont>Putting `data-no-link-style` on Text-as-a when the default always-visible underline is wanted</dont>
19
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>
@@ -46,7 +46,7 @@
46
46
  <description>Button block size; size prop presets via data attributes.</description>
47
47
  </prop>
48
48
  <prop name="icon-size" kind="css">
49
- <description>Addon icon size inside the button (`--vui-button-icon-size`). Prefer this over setting `size` on the glyph ReactNode.</description>
49
+ <description>Addon icon size inside the button (`--vui-button-icon-size`). Defaults to a fixed fraction of `--vui-button-height` so glyphs stay proportional across space scales; prefer this over setting `size` on the glyph ReactNode.</description>
50
50
  </prop>
51
51
  <prop name="padding-block" kind="css">
52
52
  <description>Vertical padding inside the button.</description>
@@ -3,7 +3,7 @@
3
3
  <do>Toolbar pin, favorite, mute, or lock toggles identified only by icon</do>
4
4
  <do>Compact on/off controls that share IconButton size, variant, and loading model</do>
5
5
  <do>Two-state actions where pressed state should swap the visible glyph via `restingIcon` / `pressedIcon`</do>
6
- <do>Omit `size` / width / height on `restingIcon` / `pressedIcon` glyphs — host CSS sizes SVG via `--vui-button-icon-size`; set glyph size only to expressly override</do>
6
+ <do>Omit `size` / width / height on `restingIcon` / `pressedIcon` glyphs — host CSS sizes SVG via `--vui-button-icon-size` (fraction of `--vui-button-height`); set glyph size only to expressly override</do>
7
7
  <do>Temporal pressed feedback (e.g. copy) with optional `interpolateIcons` crossfade</do>
8
8
  <do>Segmented toolbars: nest ToggleButtons with `value` inside ToggleGroup; label each control and the group</do>
9
9
  <do>Optional chrome: wrap with Tooltip.Trigger / Badge — keep the accessible name on the ToggleButton</do>
@@ -41,7 +41,7 @@
41
41
  <description>Button block size; size prop presets via data attributes.</description>
42
42
  </prop>
43
43
  <prop name="icon-size" kind="css">
44
- <description>Addon icon size inside the button (`--vui-button-icon-size`). Prefer this over setting `size` on the glyph ReactNode.</description>
44
+ <description>Addon icon size inside the button (`--vui-button-icon-size`). Defaults to a fixed fraction of `--vui-button-height` so glyphs stay proportional across space scales; prefer this over setting `size` on the glyph ReactNode.</description>
45
45
  </prop>
46
46
  <prop name="padding-block" kind="css">
47
47
  <description>Vertical padding inside the button.</description>
@@ -19,14 +19,14 @@
19
19
  </attr>
20
20
  <attr name="data-no-link-style">
21
21
  <presence>boolean attribute on anchor elements</presence>
22
- <effect>Excludes the anchor from all preflight default link styling (interactive color, text-decoration reset, animated underline on hover/focus). Every a:any-link without this attribute gets that chrome — class presence alone does not opt out.</effect>
22
+ <effect>Excludes the anchor from all preflight default link styling (interactive color + always-visible native text-decoration from --global-link-decoration / --global-contrast; hover/focus only increases text-underline-offset). Every a:any-link without this attribute gets that chrome — class presence alone does not opt out. Theme --global-link-decoration: none clears the line globally; this attr remains the only per-anchor opt-out.</effect>
23
23
  <values>
24
24
  <value>(boolean presence)</value>
25
25
  </values>
26
26
  <when>Component-owned or custom link chrome (ButtonLink, Chip-as-link, Menu.LinkItem, Surface-as-link, app anchors with their own paint)</when>
27
- <when>Any anchor whose background must not receive the preflight underline gradient</when>
27
+ <when>Any painted chrome anchor that must not receive preflight link decoration</when>
28
28
  <when_not>Standard inline prose links (bare a, Text/Title render as a) that should keep preflight link styling</when_not>
29
- <gotcha>A class on the anchor no longer suppresses link styles — only data-no-link-style does. Chrome components set it; prose Text/Title-as-a keep the underline with no extra markup.</gotcha>
29
+ <gotcha>A class on the anchor never suppresses link styles — only data-no-link-style does. Chrome components set it; prose Text/Title-as-a keep the always-visible underline with no extra markup.</gotcha>
30
30
  </attr>
31
31
  <attr name="data-elevation">
32
32
  <presence>value required</presence>
@@ -56,7 +56,7 @@
56
56
  <purpose>Semantic HTML element typography defaults and link chrome opt-out. Preflight already styles bare prose, lists, and inline chrome — agents must not reinvent these as app CSS by default.</purpose>
57
57
  <provides>element type defaults for p, small, strong/b, s, address, label/legend, a:any-link, code, kbd, abbr, mark, del, ins, ul, ol, dt, dd; data-no-link-style</provides>
58
58
  <use>Prose: p uses body-m size + 1.5 line-height; small scales down; strong/b use wght 700; s is strikethrough + disabled foreground; address is normal style; label/legend inherit font-size.</use>
59
- <use>Inline chrome: every a:any-link gets interactive color + animated underline unless data-no-link-style is set (attributes.xml). Prose links — including Text/Title render as a — keep it. Chrome components set the attr. Inline code (not inside pre) and kbd get contrast pill chrome; pre code drops the box-shadow. abbr uses dashed primary underline. mark / del / ins get highlight-tinted chips (yellow / red / green).</use>
59
+ <use>Inline chrome: every a:any-link without data-no-link-style gets interactive color + always-visible native text-decoration (style from --global-link-decoration, brand default wavy; color var(--global-contrast)). Hover/focus only increases text-underline-offset. Theme may set --global-link-decoration: none to clear the line. Opt out per anchor with data-no-link-style only — class never opts out (attributes.xml). Prose links — including Text/Title render as a — keep it. Chrome components set the attr. Inline code (not inside pre) and kbd get contrast pill chrome; pre code drops the box-shadow. abbr uses dashed primary underline. mark / del / ins get highlight-tinted chips (yellow / red / green).</use>
60
60
  <use>Lists: ul gets inline padding + muted ::marker; ol gets muted tabular-nums ::marker. Prefer bare ul/ol/li (or Stack render as list) — do not invent list-style / marker / list padding CSS. Nested-list font-size reset is baseline module.</use>
61
61
  <use>Definitions: dt is semibold; dd has zero margin/padding.</use>
62
62
  <do_not>Rely on class presence to suppress link styles — use data-no-link-style only.</do_not>
@@ -9,7 +9,7 @@
9
9
  </audience>
10
10
 
11
11
  <agent_rules>
12
- <use>Override --global-*, --base-*, --highlight-*, --space-*, --radius-*, --corner-shape, --effect-*, --vibrancy-*, --font-root-size, --font-*-typescale, --font-leading-*, --font-family-*, --duration-*, --easing-* after a complete compatible theme sheet.</use>
12
+ <use>Override --global-*, --global-link-decoration, --base-*, --highlight-*, --space-*, --radius-*, --corner-shape, --effect-*, --vibrancy-*, --font-root-size, --font-*-typescale, --font-leading-*, --font-family-*, --duration-*, --easing-* after a complete compatible theme sheet.</use>
13
13
  <use>Change live typography scale via --font-heading-typescale / --font-body-typescale; preflight re-derives --font-scale-*.</use>
14
14
  <use>Read surface=&quot;derived&quot; tokens (var(--font-scale-*)) in component/app CSS — consume, do not redefine in theme.</use>
15
15
  <do_not>Author --font-scale-* in theme CSS or brand typography.json. Theme ships typescale ratios only.</do_not>
@@ -32,7 +32,12 @@
32
32
  <topic id="global" surface="theme">
33
33
  <pattern>--global-*</pattern>
34
34
  <summary>App-facing foreground, background, primary, muted, interactive, disabled, and contrast colors.</summary>
35
- <agent>Primary brand/accent override surface.</agent>
35
+ <agent>Primary brand/accent override surface. Link decoration style is the sibling topic --global-link-decoration (not a color).</agent>
36
+ </topic>
37
+ <topic id="global-link-decoration" surface="theme">
38
+ <pattern>--global-link-decoration</pattern>
39
+ <summary>Free string mapped to text-decoration-style on every preflight a:any-link (brand default wavy). Color is var(--global-contrast). none clears the underline. Hover/focus only increases text-underline-offset — no gradient or grow-from-zero animation.</summary>
40
+ <agent>Theme lever for prose link decoration. Per-anchor opt-out remains data-no-link-style only (class never opts out). modules.xml typography + attributes.xml.</agent>
36
41
  </topic>
37
42
  <topic id="highlight" surface="theme">
38
43
  <pattern>--highlight-*</pattern>
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <index package="@viraui/react" version="2026.10.0" generated="2026-10-16T10:31:41.253Z">
2
+ <index package="@viraui/react" version="2026.11.0-next.0" generated="2026-10-28T09:41:51.880Z">
3
3
  <categories>
4
4
  <category id="layout" />
5
5
  <category id="action" />
@@ -211,6 +211,16 @@
211
211
  <unit kind="patterns" href="components/glow/patterns.xml" />
212
212
  </units>
213
213
  </entry>
214
+ <entry id="gauge" category="feedback" title="Gauge">
215
+ <summary>Composable round dial for determinate readings and optional polar slider control, built from SVG parts sharing one domain context. Linear bars stay on Slider.</summary>
216
+ <units>
217
+ <unit kind="meta" href="components/gauge/meta.xml" />
218
+ <unit kind="a11y" href="components/gauge/a11y.xml" />
219
+ <unit kind="props" href="components/gauge/props.xml" />
220
+ <unit kind="usage" href="components/gauge/usage.xml" />
221
+ <unit kind="patterns" href="components/gauge/patterns.xml" />
222
+ </units>
223
+ </entry>
214
224
  <entry id="grid" category="layout" title="Grid">
215
225
  <summary>CSS Grid layout primitive for auto-fill/fit or fixed track layouts with token gaps, Stack-aligned padding, and item placement (`fullWidth` / `fullHeight` / column / row).</summary>
216
226
  <units>
@@ -231,6 +241,16 @@
231
241
  <unit kind="patterns" href="components/icon-button/patterns.xml" />
232
242
  </units>
233
243
  </entry>
244
+ <entry id="icon-meter" category="feedback" title="IconMeter">
245
+ <summary>Display-only discrete icon row for scores and levels (empty / half / full), with APG Meter semantics. Distinct from track Meter, arc Gauge, and LinearProgress.</summary>
246
+ <units>
247
+ <unit kind="meta" href="components/icon-meter/meta.xml" />
248
+ <unit kind="a11y" href="components/icon-meter/a11y.xml" />
249
+ <unit kind="props" href="components/icon-meter/props.xml" />
250
+ <unit kind="usage" href="components/icon-meter/usage.xml" />
251
+ <unit kind="patterns" href="components/icon-meter/patterns.xml" />
252
+ </units>
253
+ </entry>
234
254
  <entry id="linear-progress" category="feedback" title="LinearProgress">
235
255
  <summary>Shows determinate or indeterminate progress for a task in a compact horizontal track.</summary>
236
256
  <units>
@@ -16,7 +16,7 @@
16
16
  <Stack
17
17
  direction="row"
18
18
  columnGap="m"
19
- vAlign="center"
19
+ vAlign="safe center"
20
20
  fullWidth
21
21
  expandChildren
22
22
  render={
@@ -14,7 +14,7 @@
14
14
  <Surface color={1} border="all" radius="m" hPadding="m" vPadding="m">
15
15
  <Stack rowGap="m">
16
16
  <Textfield label="Display name" fullWidth />
17
- <Stack direction="row" vAlign="center" columnGap="m" fullWidth>
17
+ <Stack direction="row" vAlign="safe center" columnGap="m" fullWidth>
18
18
  <Stack rowGap="2xs" expandChildren>
19
19
  <Text weight="m">Notifications</Text>
20
20
  <Text size="sm" color="muted">
@@ -8,7 +8,7 @@
8
8
  <do>Use Stack for the row flex layout and token `columnGap`; put label copy in a nested column Stack with `expandChildren`; put the control at the trailing edge.</do>
9
9
  <dont>Do not reimplement row flex, gap, or stretch in app CSS when Stack covers alignment and spacing.</dont>
10
10
  <tsx><![CDATA[
11
- <Stack direction="row" vAlign="center" columnGap="m" fullWidth>
11
+ <Stack direction="row" vAlign="safe center" columnGap="m" fullWidth>
12
12
  <Stack rowGap="2xs" expandChildren>
13
13
  <Text weight="m">Notifications</Text>
14
14
  <Text size="sm" color="muted">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viraui/react",
3
- "version": "2026.10.0",
3
+ "version": "2026.11.0-next.0",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist"
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@base-ui/react": ">=1.8.0",
31
- "@viraui/foundation": "2026.10.0",
31
+ "@viraui/foundation": "2026.11.0-next.0",
32
32
  "@viraui/icons": "2026.1.0",
33
33
  "@viraui/postcss-config": "2026.0.0",
34
34
  "@viraui/tsconfig": "2026.0.0",