@viraui/react 2026.5.0 → 2026.6.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 (169) hide show
  1. package/dist/catalog.json +5 -5
  2. package/dist/components/avatar/avatar.js +1 -1
  3. package/dist/components/stack/stack.d.ts +4 -1
  4. package/dist/components/tabs/tabs.css +1 -1
  5. package/dist/components/text/text.css +1 -1
  6. package/dist/components/text/text.d.ts +16 -5
  7. package/dist/components/text/text.js +2 -1
  8. package/dist/components/textfield/textfield.d.ts +1 -0
  9. package/dist/components/title/title.css +1 -1
  10. package/dist/components/title/title.d.ts +12 -2
  11. package/dist/components/title/title.js +2 -1
  12. package/dist/preflight.css +4 -1
  13. package/dist/specs/PROTOCOL.md +23 -19
  14. package/dist/specs/activity-hints.xml +18 -3
  15. package/dist/specs/components/accordion/patterns.xml +69 -5
  16. package/dist/specs/components/accordion/props.xml +4 -4
  17. package/dist/specs/components/accordion/usage.xml +8 -4
  18. package/dist/specs/components/annotate/patterns.xml +50 -3
  19. package/dist/specs/components/annotate/props.xml +22 -22
  20. package/dist/specs/components/annotate/usage.xml +7 -6
  21. package/dist/specs/components/autocomplete/patterns.xml +123 -7
  22. package/dist/specs/components/autocomplete/props.xml +14 -14
  23. package/dist/specs/components/autocomplete/usage.xml +11 -6
  24. package/dist/specs/components/avatar/patterns.xml +78 -3
  25. package/dist/specs/components/avatar/props.xml +8 -8
  26. package/dist/specs/components/avatar/usage.xml +9 -3
  27. package/dist/specs/components/avatar-group/patterns.xml +65 -3
  28. package/dist/specs/components/avatar-group/props.xml +8 -8
  29. package/dist/specs/components/avatar-group/usage.xml +10 -7
  30. package/dist/specs/components/badge/patterns.xml +57 -3
  31. package/dist/specs/components/badge/props.xml +8 -8
  32. package/dist/specs/components/badge/usage.xml +5 -3
  33. package/dist/specs/components/beam/meta.xml +1 -1
  34. package/dist/specs/components/beam/patterns.xml +68 -3
  35. package/dist/specs/components/beam/props.xml +22 -22
  36. package/dist/specs/components/beam/usage.xml +7 -7
  37. package/dist/specs/components/bleed/patterns.xml +54 -3
  38. package/dist/specs/components/bleed/props.xml +2 -2
  39. package/dist/specs/components/bleed/usage.xml +6 -3
  40. package/dist/specs/components/breakpoints/meta.xml +1 -1
  41. package/dist/specs/components/breakpoints/patterns.xml +1 -6
  42. package/dist/specs/components/breakpoints/props.xml +4 -2
  43. package/dist/specs/components/breakpoints/usage.xml +10 -2
  44. package/dist/specs/components/button/patterns.xml +124 -6
  45. package/dist/specs/components/button/props.xml +33 -32
  46. package/dist/specs/components/button/usage.xml +13 -13
  47. package/dist/specs/components/checkbox/patterns.xml +83 -3
  48. package/dist/specs/components/checkbox/props.xml +10 -10
  49. package/dist/specs/components/checkbox/usage.xml +11 -6
  50. package/dist/specs/components/chip/patterns.xml +74 -3
  51. package/dist/specs/components/chip/props.xml +14 -14
  52. package/dist/specs/components/chip/usage.xml +10 -6
  53. package/dist/specs/components/clamp-text/patterns.xml +1 -4
  54. package/dist/specs/components/clamp-text/props.xml +2 -2
  55. package/dist/specs/components/clamp-text/usage.xml +8 -5
  56. package/dist/specs/components/dialog/patterns.xml +136 -15
  57. package/dist/specs/components/dialog/props.xml +2 -2
  58. package/dist/specs/components/dialog/usage.xml +9 -7
  59. package/dist/specs/components/elevator/patterns.xml +54 -3
  60. package/dist/specs/components/elevator/usage.xml +8 -5
  61. package/dist/specs/components/fieldset/patterns.xml +97 -3
  62. package/dist/specs/components/fieldset/usage.xml +7 -5
  63. package/dist/specs/components/fit-text/patterns.xml +1 -4
  64. package/dist/specs/components/fit-text/props.xml +2 -2
  65. package/dist/specs/components/fit-text/usage.xml +8 -6
  66. package/dist/specs/components/glow/meta.xml +1 -1
  67. package/dist/specs/components/glow/patterns.xml +74 -3
  68. package/dist/specs/components/glow/props.xml +16 -16
  69. package/dist/specs/components/glow/usage.xml +8 -7
  70. package/dist/specs/components/grid/patterns.xml +88 -5
  71. package/dist/specs/components/grid/props.xml +23 -23
  72. package/dist/specs/components/grid/usage.xml +9 -5
  73. package/dist/specs/components/icon-button/patterns.xml +97 -6
  74. package/dist/specs/components/icon-button/props.xml +32 -32
  75. package/dist/specs/components/icon-button/usage.xml +11 -9
  76. package/dist/specs/components/linear-progress/patterns.xml +58 -3
  77. package/dist/specs/components/linear-progress/props.xml +6 -6
  78. package/dist/specs/components/linear-progress/usage.xml +9 -8
  79. package/dist/specs/components/masonry/patterns.xml +68 -5
  80. package/dist/specs/components/masonry/props.xml +2 -2
  81. package/dist/specs/components/masonry/usage.xml +9 -4
  82. package/dist/specs/components/menu/patterns.xml +179 -15
  83. package/dist/specs/components/menu/usage.xml +8 -7
  84. package/dist/specs/components/meter/patterns.xml +49 -3
  85. package/dist/specs/components/meter/props.xml +6 -6
  86. package/dist/specs/components/meter/usage.xml +10 -7
  87. package/dist/specs/components/popover/patterns.xml +118 -9
  88. package/dist/specs/components/popover/props.xml +2 -2
  89. package/dist/specs/components/popover/usage.xml +9 -8
  90. package/dist/specs/components/progressive-blur/meta.xml +1 -1
  91. package/dist/specs/components/progressive-blur/patterns.xml +1 -4
  92. package/dist/specs/components/progressive-blur/props.xml +2 -2
  93. package/dist/specs/components/progressive-blur/usage.xml +7 -6
  94. package/dist/specs/components/radio/patterns.xml +55 -5
  95. package/dist/specs/components/radio/props.xml +8 -8
  96. package/dist/specs/components/radio/usage.xml +9 -6
  97. package/dist/specs/components/select/patterns.xml +124 -8
  98. package/dist/specs/components/select/props.xml +18 -18
  99. package/dist/specs/components/select/usage.xml +11 -10
  100. package/dist/specs/components/separator/patterns.xml +121 -3
  101. package/dist/specs/components/separator/props.xml +4 -4
  102. package/dist/specs/components/separator/usage.xml +8 -5
  103. package/dist/specs/components/shimmer/patterns.xml +23 -3
  104. package/dist/specs/components/shimmer/props.xml +8 -8
  105. package/dist/specs/components/shimmer/usage.xml +7 -5
  106. package/dist/specs/components/skeleton/patterns.xml +172 -4
  107. package/dist/specs/components/skeleton/props.xml +14 -14
  108. package/dist/specs/components/skeleton/usage.xml +11 -7
  109. package/dist/specs/components/slider/patterns.xml +111 -3
  110. package/dist/specs/components/slider/props.xml +10 -10
  111. package/dist/specs/components/slider/usage.xml +11 -5
  112. package/dist/specs/components/spinner/patterns.xml +35 -3
  113. package/dist/specs/components/spinner/props.xml +2 -2
  114. package/dist/specs/components/spinner/usage.xml +8 -5
  115. package/dist/specs/components/stack/patterns.xml +359 -3
  116. package/dist/specs/components/stack/props.xml +24 -22
  117. package/dist/specs/components/stack/usage.xml +16 -10
  118. package/dist/specs/components/static-noise/meta.xml +1 -1
  119. package/dist/specs/components/static-noise/patterns.xml +20 -3
  120. package/dist/specs/components/static-noise/usage.xml +5 -5
  121. package/dist/specs/components/surface/patterns.xml +188 -3
  122. package/dist/specs/components/surface/props.xml +26 -26
  123. package/dist/specs/components/surface/usage.xml +15 -12
  124. package/dist/specs/components/switch/patterns.xml +73 -3
  125. package/dist/specs/components/switch/props.xml +12 -12
  126. package/dist/specs/components/switch/usage.xml +10 -5
  127. package/dist/specs/components/tabs/patterns.xml +111 -6
  128. package/dist/specs/components/tabs/props.xml +2 -2
  129. package/dist/specs/components/tabs/usage.xml +7 -3
  130. package/dist/specs/components/text/patterns.xml +97 -3
  131. package/dist/specs/components/text/props.xml +48 -43
  132. package/dist/specs/components/text/usage.xml +11 -4
  133. package/dist/specs/components/textarea/patterns.xml +49 -3
  134. package/dist/specs/components/textarea/props.xml +7 -6
  135. package/dist/specs/components/textarea/usage.xml +8 -5
  136. package/dist/specs/components/textfield/patterns.xml +163 -3
  137. package/dist/specs/components/textfield/props.xml +12 -11
  138. package/dist/specs/components/textfield/usage.xml +9 -3
  139. package/dist/specs/components/title/patterns.xml +74 -3
  140. package/dist/specs/components/title/props.xml +48 -43
  141. package/dist/specs/components/title/usage.xml +10 -7
  142. package/dist/specs/components/toast/patterns.xml +85 -8
  143. package/dist/specs/components/toast/usage.xml +8 -5
  144. package/dist/specs/components/toggle-button/patterns.xml +101 -3
  145. package/dist/specs/components/toggle-button/props.xml +16 -16
  146. package/dist/specs/components/toggle-button/usage.xml +9 -5
  147. package/dist/specs/components/toggle-group/patterns.xml +34 -5
  148. package/dist/specs/components/toggle-group/usage.xml +9 -5
  149. package/dist/specs/components/tooltip/patterns.xml +110 -6
  150. package/dist/specs/components/tooltip/props.xml +2 -2
  151. package/dist/specs/components/tooltip/usage.xml +8 -5
  152. package/dist/specs/components/typewriter/patterns.xml +18 -3
  153. package/dist/specs/components/typewriter/props.xml +2 -2
  154. package/dist/specs/components/typewriter/usage.xml +9 -8
  155. package/dist/specs/foundation/attributes.xml +67 -37
  156. package/dist/specs/foundation/bootstrap.xml +6 -6
  157. package/dist/specs/foundation/elevation.xml +51 -3
  158. package/dist/specs/foundation/modules.xml +117 -40
  159. package/dist/specs/foundation/theme-topics.xml +62 -27
  160. package/dist/specs/foundation/toggles.xml +2 -2
  161. package/dist/specs/index.xml +42 -6
  162. package/dist/specs/patterns/card-grid.xml +35 -0
  163. package/dist/specs/patterns/compose-layout-first.xml +32 -0
  164. package/dist/specs/patterns/equal-width-actions.xml +22 -0
  165. package/dist/specs/patterns/page-chrome.xml +34 -0
  166. package/dist/specs/patterns/settings-panel.xml +30 -0
  167. package/dist/specs/patterns/settings-row.xml +9 -7
  168. package/dist/specs/patterns/stack-as-surface.xml +37 -0
  169. package/package.json +2 -2
@@ -1,7 +1,78 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="title">
3
- <example title="Title structure">
4
- <tsx><![CDATA[<Title>…</Title>]]></tsx>
5
- <notes>Public assembly hint from legacy guide; not API authority.</notes>
3
+ <!-- Sources: viraui-app + design-kitchen preview-grid — cleaned (no handlers, no i18n). -->
4
+
5
+ <example title="Auth hero heading">
6
+ <tsx><![CDATA[
7
+ <Title size="1" render={<h1 />} maxWidth="32rem" lineHeight="s">
8
+ Ship real UI at the speed of thought.
9
+ </Title>
10
+ ]]></tsx>
11
+ <notes>From `auth/login-view`. Pair `size` with `render={<h1 />}` — visual preset and heading semantics stay intentional. (Live app nests Typewriter inside; see typewriter patterns.)</notes>
12
+ </example>
13
+
14
+ <example title="Card section heading">
15
+ <tsx><![CDATA[
16
+ <Stack rowGap="xs">
17
+ <Title size="6" render={<h2 />}>
18
+ Preferences
19
+ </Title>
20
+ <Text size="s" maxWidth="18rem" tone="muted">
21
+ Manage your account settings and notifications.
22
+ </Text>
23
+ </Stack>
24
+ ]]></tsx>
25
+ <notes>From preview-grid `preferences` (+ payout-threshold, notifications, …). Dense card titles use `size="6"` + `h2`.</notes>
26
+ </example>
27
+
28
+ <example title="Empty-state heading">
29
+ <tsx><![CDATA[
30
+ <Title align="center" size="5" render={<h3 />}>
31
+ No Team Members
32
+ </Title>
33
+ ]]></tsx>
34
+ <notes>From preview-grid `empty-team`. Centered mid-size heading; pair with muted Text below.</notes>
35
+ </example>
36
+
37
+ <example title="Display metric">
38
+ <tsx><![CDATA[
39
+ <Stack hAlign="center" rowGap="2xs">
40
+ <Title align="center" size="display" lineHeight="s" whiteSpace="nowrap">
41
+ 2400
42
+ </Title>
43
+ <Text align="center" size="xs" tone="muted">
44
+ CALORIES/DAY
45
+ </Text>
46
+ </Stack>
47
+ ]]></tsx>
48
+ <notes>From preview-grid `daily-activity-goal`. `size="display"` for hero numerals; `whiteSpace="nowrap"` keeps metric on one line.</notes>
49
+ </example>
50
+
51
+ <example title="Balance display">
52
+ <tsx><![CDATA[
53
+ <Stack rowGap="s">
54
+ <Text size="s" tone="muted">
55
+ Claimable Balance
56
+ </Text>
57
+ <Title size="1" lineHeight="s">
58
+ $0.00
59
+ </Title>
60
+ </Stack>
61
+ ]]></tsx>
62
+ <notes>From preview-grid `claimable-balance`. Large `size="1"` Title as primary figure — muted label Text above, no heading tag required for non-outline figures.</notes>
63
+ </example>
64
+
65
+ <example title="Theme panel title">
66
+ <tsx><![CDATA[
67
+ <Stack rowGap="s">
68
+ <Title size="4" render={<h3 />}>
69
+ Colors
70
+ </Title>
71
+ <Text size="s" tone="muted">
72
+ Preview of theme voice, contrast, and color rhythm across accents.
73
+ </Text>
74
+ </Stack>
75
+ ]]></tsx>
76
+ <notes>From design-kitchen `theme-preview` (+ `base-theme-selector` label scale). Mid panel titles use `size="4"` + `h3`.</notes>
6
77
  </example>
7
78
  </patterns>
@@ -4,11 +4,13 @@
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>Fluid clamp sizing across title appearance presets (gated by --effect-fluid-typography; off → fixed at --font-scale-display / h-* for that size)</item>
7
+ <item>Letter-spacing via `tracking` or text-transform via `transform` — prefer props over CSS on the Title root</item>
8
+ <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>
8
9
  </when_to_use>
9
10
  <when_not_to_use>
10
11
  <item>Body copy — use Text</item>
11
12
  <item>Body or mono family typography</item>
13
+ <item>Inventing CSS `letter-spacing` / `text-transform` / `width: 100%` when `tracking` / `transform` / parent Stack `fullWidth` cover the need</item>
12
14
  </when_not_to_use>
13
15
  <prop name="align" kind="react">
14
16
  <description>Aligns text using logical alignment values.</description>
@@ -19,6 +21,9 @@
19
21
  <prop name="color" kind="react">
20
22
  <description>Applies a literal color escape hatch.</description>
21
23
  </prop>
24
+ <prop name="fluid" kind="react">
25
+ <description>Enables viewport fluid clamp sizing for this instance. Pass false to lock at this size’s --font-scale-display / --font-scale-h* token. Theme --effect-fluid-typography: initial still locks all Title globally.</description>
26
+ </prop>
22
27
  <prop name="fontWidth" kind="react">
23
28
  <description>Overrides font width as a percentage (100 = normal); maps to `font-stretch` and `wdth`.</description>
24
29
  </prop>
@@ -44,13 +49,13 @@
44
49
  <description>Enables text selection on the rendered copy.</description>
45
50
  </prop>
46
51
  <prop name="size" kind="react">
47
- <description>Selects a heading or display typography preset from the active theme scale. This controls only the visual preset. Semantic heading choice remains owned by `render`, because `Title` keeps a `span` root unless `render` replaces it. Fluid clamp between prev step and this size’s --font-scale-display / --font-scale-h* token is on when --effect-fluid-typography is empty; set the theme effect to initial to lock at that scale token.</description>
52
+ <description>Selects a heading or display typography preset from the active theme scale. This controls only the visual preset. Semantic heading choice remains owned by `render`, because `Title` keeps a `span` root unless `render` replaces it. Fluid clamp between prev step and this size’s --font-scale-display / --font-scale-h* token is on when --effect-fluid-typography is empty and `fluid` is true; set the theme effect to initial or pass `fluid={false}` to lock at that scale token.</description>
48
53
  </prop>
49
54
  <prop name="tracking" kind="react">
50
- <description>Sets letter spacing on the rendered copy. Overrides size preset letter-spacing when set.</description>
55
+ <description>Sets letter-spacing on the rendered copy (overrides size preset when set). Prefer this prop over CSS `letter-spacing` / Tailwind tracking utilities on the same Title root.</description>
51
56
  </prop>
52
57
  <prop name="transform" kind="react">
53
- <description>Applies a text-transform on the rendered copy.</description>
58
+ <description>Applies CSS `text-transform` on the rendered copy via `--vui-title-text-transform` (`uppercase` \| `lowercase` \| `capitalize` \| …). Prefer this prop over CSS `text-transform` on the same Title root.</description>
54
59
  </prop>
55
60
  <prop name="trim" kind="react">
56
61
  <description>Trims text box whitespace at the chosen edge when the browser supports `text-box`. Pass `false` to disable text-box trim.</description>
@@ -67,58 +72,58 @@
67
72
  <prop name="whiteSpace" kind="react">
68
73
  <description>Controls white-space preservation and wrapping behavior.</description>
69
74
  </prop>
70
- <css_var suffix="align">
75
+ <prop name="align" kind="css">
71
76
  <description>Title alignment on the root.</description>
72
- </css_var>
73
- <css_var suffix="font-family">
77
+ </prop>
78
+ <prop name="font-family" kind="css">
74
79
  <description>Heading font family on the root.</description>
75
- </css_var>
76
- <css_var suffix="font-opsz">
80
+ </prop>
81
+ <prop name="font-opsz" kind="css">
77
82
  <description>Optical size axis on the root (variable fonts).</description>
78
- </css_var>
79
- <css_var suffix="font-size">
80
- <description>Heading font size; size prop presets via data attributes. Defaults to the theme scale token for that size; clamp (prev step→token) applies only when --effect-fluid-typography is on.</description>
81
- </css_var>
82
- <css_var suffix="font-weight">
83
+ </prop>
84
+ <prop name="font-size" kind="css">
85
+ <description>Heading font size; size prop presets via data attributes. Defaults to the theme scale token for that size; clamp (prev step→token) applies only when --effect-fluid-typography is on and `fluid` is true.</description>
86
+ </prop>
87
+ <prop name="font-weight" kind="css">
83
88
  <description>Font weight on the root.</description>
84
- </css_var>
85
- <css_var suffix="font-width">
89
+ </prop>
90
+ <prop name="font-width" kind="css">
86
91
  <description>Font width percentage on the root (font-stretch + wdth).</description>
87
- </css_var>
88
- <css_var suffix="letter-spacing">
89
- <description>Public letter spacing from the `tracking` prop when set.</description>
90
- </css_var>
91
- <css_var suffix="line-height">
92
+ </prop>
93
+ <prop name="letter-spacing" kind="css">
94
+ <description>Public letter spacing from the `tracking` prop when set. Prefer that React prop over inventing CSS `letter-spacing` on the Title root.</description>
95
+ </prop>
96
+ <prop name="line-height" kind="css">
92
97
  <description>Line height; lineHeight prop presets via data attributes.</description>
93
- </css_var>
94
- <css_var suffix="literal-color">
98
+ </prop>
99
+ <prop name="literal-color" kind="css">
95
100
  <description>Literal color override on the root.</description>
96
- </css_var>
97
- <css_var suffix="max-width">
101
+ </prop>
102
+ <prop name="max-width" kind="css">
98
103
  <description>Max inline size of the title root.</description>
99
- </css_var>
100
- <css_var suffix="padding-block-end">
104
+ </prop>
105
+ <prop name="padding-block-end" kind="css">
101
106
  <description>Block-end padding when padding is enabled.</description>
102
- </css_var>
103
- <css_var suffix="padding-block-start">
107
+ </prop>
108
+ <prop name="padding-block-start" kind="css">
104
109
  <description>Block-start padding when padding is enabled.</description>
105
- </css_var>
106
- <css_var suffix="padding-inline-end">
110
+ </prop>
111
+ <prop name="padding-inline-end" kind="css">
107
112
  <description>Inline-end padding when padding is enabled.</description>
108
- </css_var>
109
- <css_var suffix="padding-inline-start">
113
+ </prop>
114
+ <prop name="padding-inline-start" kind="css">
110
115
  <description>Inline-start padding when padding is enabled.</description>
111
- </css_var>
112
- <css_var suffix="trim">
116
+ </prop>
117
+ <prop name="trim" kind="css">
113
118
  <description>Text-box trim mode on the root.</description>
114
- </css_var>
115
- <css_var suffix="trim-type">
119
+ </prop>
120
+ <prop name="trim-type" kind="css">
116
121
  <description>Text-box trim basis on the root.</description>
117
- </css_var>
118
- <css_var suffix="text-transform">
119
- <description>Text transform on the root.</description>
120
- </css_var>
121
- <css_var suffix="white-space">
122
+ </prop>
123
+ <prop name="text-transform" kind="css">
124
+ <description>Text transform on the root. Prefer the `transform` React prop; set this hook only when theming beyond the prop.</description>
125
+ </prop>
126
+ <prop name="white-space" kind="css">
122
127
  <description>White-space behavior on the root.</description>
123
- </css_var>
128
+ </prop>
124
129
  </props>
@@ -1,10 +1,13 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <usage surface="title">
3
- <do>Headings and display text with title presets</do>
4
- <do>Semantic heading tags chosen explicitly through render</do>
5
- <do>Size and render paired together for most heading use cases</do>
6
- <do>Fluid clamp sizing across title appearance presets (gated by --effect-fluid-typography; off → fixed at --font-scale-display / h-* for that size)</do>
7
- <dont>Assuming size changes the HTML tag automatically</dont>
8
- <dont>Letting size force the HTML tag instead of choosing render explicitly</dont>
9
- <dont>Using Title for long body paragraphs</dont>
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
+ <do>Card / panel header: Stack `rowGap=&quot;xs&quot;` + Title + muted Text blurb — Surface for card chrome</do>
5
+ <do>Auth / hero cycle: nest Typewriter inside Title (`preserveSpace`, caret props) so display preset + heading tag stay on the parent</do>
6
+ <do>Loading title copy: nest Shimmer inside Title — parent region owns busy semantics</do>
7
+ <do>Truncation: ClampText `render={&lt;Title size=… render={&lt;h* /&gt;} /&gt;}` — FitText wraps Title when short headlines must fill a constrained width</do>
8
+ <do>Fluid clamp across presets (`fluid` / theme `--effect-fluid-typography`); pass `fluid={false}` inside chrome or dense UI</do>
9
+ <do>Letter-spacing via `tracking`; text-transform via `transform`; width via `maxWidth` or parent Stack `fullWidth`</do>
10
+ <dont>Assuming `size` changes the HTML tag — choose `render` explicitly</dont>
11
+ <dont>Using Title for long body paragraphs — use Text</dont>
12
+ <dont>Inventing CSS `letter-spacing` / `text-transform` / `width: 100%` when props / Stack cover it</dont>
10
13
  </usage>
@@ -1,15 +1,92 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="toast">
3
- <example title="Toast structure">
4
- <tsx><![CDATA[<Toast.Provider>
3
+ <!-- Sources: viraui-app/components + design-kitchen preview-support — cleaned (no handlers, no portal/preview chrome). -->
4
+
5
+ <example title="App toast region">
6
+ <tsx><![CDATA[
7
+ const toastManager = Toast.createToastManager();
8
+
9
+ <Toast.Provider toastManager={toastManager}>
10
+ {/* app tree */}
5
11
  <Toast.Portal>
6
- <Toast.Viewport>
7
- <Toast.Banner toast={…}>
8
- <Toast.Action>…</Toast.Action>
9
- </Toast.Banner>
12
+ <Toast.Viewport position="bottom-left">
13
+ {toasts.map((toast) => (
14
+ <Toast.Banner key={toast.id} description={toast.description} toast={toast} />
15
+ ))}
10
16
  </Toast.Viewport>
11
17
  </Toast.Portal>
12
- </Toast.Provider>]]></tsx>
13
- <notes>Public assembly hint from legacy guide; not API authority.</notes>
18
+ </Toast.Provider>
19
+ ]]></tsx>
20
+ <notes>From `providers/providers`. Non-callable `Toast` namespace: Provider + Portal + Viewport + Banner list. `toasts` from `Toast.useToastManager()` inside the Provider.</notes>
21
+ </example>
22
+
23
+ <example title="Stacked alerts">
24
+ <tsx><![CDATA[
25
+ const stackedManager = Toast.createToastManager();
26
+
27
+ {/* somewhere under Toast.Provider toastManager={stackedManager} */}
28
+ <button type="button" onClick={() => stackedManager.add({ title: 'Order submitted', description: '1.95 shares at market price.' })}>
29
+ Simulate alert
30
+ </button>
31
+
32
+ <Toast.Portal>
33
+ <Toast.Viewport>
34
+ {toasts.map((toast) => (
35
+ <Toast.Banner key={toast.id} description={toast.description} toast={toast} />
36
+ ))}
37
+ </Toast.Viewport>
38
+ </Toast.Portal>
39
+ ]]></tsx>
40
+ <notes>From preview-grid `activity-feedback` + `preview-toast`. Manager `.add({ title, description })` feeds Banner. Drop portal-container props.</notes>
41
+ </example>
42
+
43
+ <example title="Anchored confirmation">
44
+ <tsx><![CDATA[
45
+ const anchoredManager = Toast.createToastManager();
46
+ const copyLinkRef = React.useRef<HTMLButtonElement>(null);
47
+
48
+ <button
49
+ ref={copyLinkRef}
50
+ type="button"
51
+ onClick={() =>
52
+ anchoredManager.add({
53
+ description: 'Link copied to clipboard.',
54
+ timeout: 1500,
55
+ positionerProps: { anchor: copyLinkRef.current, sideOffset: 8 },
56
+ })
57
+ }
58
+ >
59
+ Copy
60
+ </button>
61
+
62
+ <Toast.Portal>
63
+ <Toast.Viewport position="anchored">
64
+ {toasts.map((toast) => {
65
+ if (!toast.positionerProps?.anchor) return null;
66
+ return (
67
+ <Toast.Positioner key={toast.id} toast={toast}>
68
+ <Toast.Banner description={toast.description} dismissable={false} toast={toast} />
69
+ </Toast.Positioner>
70
+ );
71
+ })}
72
+ </Toast.Viewport>
73
+ </Toast.Portal>
74
+ ]]></tsx>
75
+ <notes>From preview `preview-providers` anchored list + `activity-feedback` Copy. Viewport `position="anchored"` + `Toast.Positioner` wraps Banner.</notes>
76
+ </example>
77
+
78
+ <example title="Banner with undo action">
79
+ <tsx><![CDATA[
80
+ <Toast.Portal>
81
+ <Toast.Viewport>
82
+ {toasts.map((toast) => (
83
+ <Toast.Banner key={toast.id} description={toast.description} toast={toast}>
84
+ <Toast.Action render={<Button variant="destructive" />}>Undo</Toast.Action>
85
+ </Toast.Banner>
86
+ ))}
87
+ </Toast.Viewport>
88
+ </Toast.Portal>
89
+ ]]></tsx>
90
+ <notes>From Toast stories undo list. Banner children are `Toast.Action` only. Close via manager inside a real handler — omitted here.</notes>
14
91
  </example>
15
92
  </patterns>
@@ -1,10 +1,13 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <usage surface="toast">
3
- <do>Confirming a completed action such as save or delete</do>
4
- <do>Offering a short undo window after a reversible change</do>
5
- <do>Showing contextual feedback anchored to the control that triggered it</do>
6
- <do>Custom portal host (iframe preview, shadow root, or app overlay root) via `container` on the portal-owning public part</do>
3
+ <do>Mount once: `Toast.createToastManager()` → `Toast.Provider toastManager={…}` around the app tree</do>
4
+ <do>Render region: `Toast.Portal` → `Toast.Viewport` → map `Toast.useToastManager().toasts` to `Toast.Banner`</do>
5
+ <do>Confirm save/delete or short undo: manager `.add({ title, description })` feeds Banner</do>
6
+ <do>Undo / secondary actions: Banner children are `Toast.Action` only — default Button chrome, or `render={&lt;Button …/&gt;}`</do>
7
+ <do>Anchored feedback: Viewport `position=&quot;anchored&quot;` + `Toast.Positioner` wrapping Banner; pass `positionerProps.anchor` from `.add`</do>
8
+ <do>Custom portal host (iframe preview, shadow root, or app overlay root) via `container` on `Toast.Portal`</do>
7
9
  <dont>Nesting arbitrary components inside Toast.Banner — children must be Toast.Action only</dont>
10
+ <dont>Calling Toast as a component — it is a non-callable namespace (Provider / Portal / Viewport / Banner / Action)</dont>
11
+ <dont>Using toasts for critical validation that blocks the task — use field errors or Dialog</dont>
8
12
  <dont>Stacking many simultaneous toasts without a clear limit</dont>
9
- <dont>Using toasts for critical validation errors that block task completion</dont>
10
13
  </usage>
@@ -1,7 +1,105 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="toggle-button">
3
- <example title="ToggleButton structure">
4
- <tsx><![CDATA[<ToggleButton restingIcon={<Plus />} aria-label="Pin" />]]></tsx>
5
- <notes>Public assembly hint from legacy guide; not API authority.</notes>
3
+ <!-- Sources: viraui-app — cleaned (no handlers, no i18n, no studio store). Icon-only; never children. -->
4
+
5
+ <example title="Copy feedback (interpolate)">
6
+ <tsx><![CDATA[
7
+ <ToggleButton
8
+ aria-label="Copy to clipboard"
9
+ restingIcon={<Duplicate aria-hidden />}
10
+ pressedIcon={<CircleCheck aria-hidden color="var(--highlight-green)" />}
11
+ interpolateIcons
12
+ variant="secondary"
13
+ />
14
+ ]]></tsx>
15
+ <notes>From `common/code-block` (+ `editor/export-dialog` preset copy). Temporal pressed state swaps glyph; `interpolateIcons` crossfades. App resets pressed after a timer — omit that from the hint.</notes>
16
+ </example>
17
+
18
+ <example title="Shuffle lock">
19
+ <tsx><![CDATA[
20
+ <Tooltip>
21
+ <Tooltip.Trigger
22
+ render={
23
+ <ToggleButton
24
+ aria-label="Lock in shuffle"
25
+ restingIcon={<LockOpen2 aria-hidden size="1rem" />}
26
+ pressedIcon={<Lock aria-hidden size="1rem" color="var(--global-primary)" />}
27
+ variant="flat"
28
+ pressedVariant="secondary"
29
+ />
30
+ }
31
+ />
32
+ <Tooltip.Content>Unlocked in shuffle</Tooltip.Content>
33
+ </Tooltip>
34
+ ]]></tsx>
35
+ <notes>From `editor/controls/shuffle-lock-toggle`. Flat resting + `pressedVariant` for locked chrome. Name via `aria-label`; tooltip is optional extra copy.</notes>
36
+ </example>
37
+
38
+ <example title="Mode sync (pressedVariant)">
39
+ <tsx><![CDATA[
40
+ <Tooltip>
41
+ <Tooltip.Trigger
42
+ render={
43
+ <ToggleButton
44
+ aria-label="Sync light and dark"
45
+ size="s"
46
+ restingIcon={<DarkLight aria-hidden size="1rem" />}
47
+ variant="flat"
48
+ pressedVariant="primary"
49
+ />
50
+ }
51
+ />
52
+ <Tooltip.Content>Keep light and dark in sync</Tooltip.Content>
53
+ </Tooltip>
54
+ ]]></tsx>
55
+ <notes>From `editor/controls/primary-color-select` / `foreground-color` custom fields. Single ToggleButton (not a group) with `pressedVariant="primary"` for sync-on.</notes>
56
+ </example>
57
+
58
+ <example title="Notify mute with Badge">
59
+ <tsx><![CDATA[
60
+ <Badge show color="yellow">
61
+ <ToggleButton
62
+ aria-label="Mute notifications"
63
+ restingIcon={<BellSlash aria-hidden size={16} />}
64
+ pressedIcon={<BellOn aria-hidden size={16} />}
65
+ size="s"
66
+ interpolateIcons
67
+ variant="secondary"
68
+ />
69
+ </Badge>
70
+ ]]></tsx>
71
+ <notes>From `editor/preview-grid/blocks/team-directory`. Badge attention dot wraps ToggleButton; icon pair + `interpolateIcons`. Accessible name on the control (app may use `aria-labelledby` + Tooltip text).</notes>
72
+ </example>
73
+
74
+ <example title="Segmented group child">
75
+ <tsx><![CDATA[
76
+ <ToggleGroup aria-label="Color mode" value={['system']}>
77
+ <ToggleButton
78
+ value="light"
79
+ aria-label="Light"
80
+ restingIcon={<Sun aria-hidden size="1rem" />}
81
+ variant="flat"
82
+ size="s"
83
+ pressedVariant="secondary"
84
+ />
85
+ <ToggleButton
86
+ value="dark"
87
+ aria-label="Dark"
88
+ restingIcon={<MoonStars aria-hidden size="1rem" />}
89
+ variant="flat"
90
+ size="s"
91
+ pressedVariant="secondary"
92
+ />
93
+ <ToggleButton
94
+ value="system"
95
+ aria-label="System"
96
+ restingIcon={<DarkLight aria-hidden size="1rem" />}
97
+ variant="flat"
98
+ size="s"
99
+ pressedVariant="secondary"
100
+ />
101
+ </ToggleGroup>
102
+ ]]></tsx>
103
+ <notes>From `common/mode-switcher`. Inside ToggleGroup each child needs `value` + accessible name. Prefer ToggleGroup patterns for full chrome; this shows the per-button shape.</notes>
6
104
  </example>
7
105
  </patterns>
@@ -34,28 +34,28 @@
34
34
  <prop name="variant" kind="react">
35
35
  <description>Visual variant while the toggle is not pressed.</description>
36
36
  </prop>
37
- <css_var suffix="background">
37
+ <prop name="background" kind="css">
38
38
  <description>Button fill; variant and state selectors preset this.</description>
39
- </css_var>
40
- <css_var suffix="color">
39
+ </prop>
40
+ <prop name="color" kind="css">
41
41
  <description>Button label and icon color.</description>
42
- </css_var>
43
- <css_var suffix="height">
42
+ </prop>
43
+ <prop name="height" kind="css">
44
44
  <description>Button block size; size prop presets via data attributes.</description>
45
- </css_var>
46
- <css_var suffix="icon-size">
45
+ </prop>
46
+ <prop name="icon-size" kind="css">
47
47
  <description>Addon icon size inside the button.</description>
48
- </css_var>
49
- <css_var suffix="padding-block">
48
+ </prop>
49
+ <prop name="padding-block" kind="css">
50
50
  <description>Vertical padding inside the button.</description>
51
- </css_var>
52
- <css_var suffix="padding-inline">
51
+ </prop>
52
+ <prop name="padding-inline" kind="css">
53
53
  <description>Horizontal padding inside the button.</description>
54
- </css_var>
55
- <css_var suffix="radius">
54
+ </prop>
55
+ <prop name="radius" kind="css">
56
56
  <description>Corner radius; pill sets full radius via data-pill.</description>
57
- </css_var>
58
- <css_var suffix="spinner-color">
57
+ </prop>
58
+ <prop name="spinner-color" kind="css">
59
59
  <description>Loading spinner color on the root.</description>
60
- </css_var>
60
+ </prop>
61
61
  </props>
@@ -1,10 +1,14 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <usage surface="toggle-button">
3
- <do>Toolbar pin, favorite, or mute toggles identified only by icon</do>
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
- <do>Two-state actions where pressed state should swap the visible glyph</do>
6
- <do>Temporally swap icons after user interactions with temporal pressed state, like copy feedback.</do>
7
- <dont>Using IconButton for persistent pressed toolbar state</dont>
5
+ <do>Two-state actions where pressed state should swap the visible glyph via `restingIcon` / `pressedIcon`</do>
6
+ <do>Temporal pressed feedback (e.g. copy) with optional `interpolateIcons` crossfade</do>
7
+ <do>Segmented toolbars: nest ToggleButtons with `value` inside ToggleGroup; label each control and the group</do>
8
+ <do>Optional chrome: wrap with Tooltip.Trigger / Badge — keep the accessible name on the ToggleButton</do>
9
+ <dont>Using IconButton for persistent or temporal pressed toolbar state</dont>
8
10
  <dont>Using Switch for compact icon-only toolbar toggles</dont>
9
- <dont>Passing icon or render — ToggleButton owns icon swap and Toggle render wiring</dont>
11
+ <dont>Passing `icon` or `render` — ToggleButton owns icon swap and Toggle render wiring; use `restingIcon` / `pressedIcon`</dont>
12
+ <dont>Omitting `value` on ToggleButton children inside a ToggleGroup</dont>
13
+ <dont>Omitting both `aria-label` and `aria-labelledby`</dont>
10
14
  </usage>
@@ -1,9 +1,38 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="toggle-group">
3
- <example title="ToggleGroup structure">
4
- <tsx><![CDATA[<ToggleGroup>
5
- <ToggleButton restingIcon={<Plus />} aria-label="List" value="list" />
6
- </ToggleGroup>]]></tsx>
7
- <notes>Public assembly hint from legacy guide; not API authority.</notes>
3
+ <!-- Sources: viraui-app — cleaned (no handlers, no i18n, no theme store). Compound: ToggleGroup + ToggleButton children with value. -->
4
+
5
+ <example title="Mode switcher chrome">
6
+ <tsx><![CDATA[
7
+ <Surface border="all" radius="m" vPadding="2xs" hPadding="2xs">
8
+ <ToggleGroup aria-label="Color mode" value={['system']}>
9
+ <ToggleButton
10
+ value="light"
11
+ aria-label="Light"
12
+ restingIcon={<Sun aria-hidden size="1rem" />}
13
+ variant="flat"
14
+ size="s"
15
+ pressedVariant="secondary"
16
+ />
17
+ <ToggleButton
18
+ value="dark"
19
+ aria-label="Dark"
20
+ restingIcon={<MoonStars aria-hidden size="1rem" />}
21
+ variant="flat"
22
+ size="s"
23
+ pressedVariant="secondary"
24
+ />
25
+ <ToggleButton
26
+ value="system"
27
+ aria-label="System"
28
+ restingIcon={<DarkLight aria-hidden size="1rem" />}
29
+ variant="flat"
30
+ size="s"
31
+ pressedVariant="secondary"
32
+ />
33
+ </ToggleGroup>
34
+ </Surface>
35
+ ]]></tsx>
36
+ <notes>From `common/mode-switcher`. ToggleGroup selection is `string[]` (`value` / `defaultValue` / `onValueChange`). Label the group with `aria-label`. Surface tight padding is chrome — group Stack owns item gap (`2xs`). Exclusive mode: one selected value in the array.</notes>
8
37
  </example>
9
38
  </patterns>
@@ -1,9 +1,13 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <usage surface="toggle-group">
3
- <do>Segmented icon toolbars such as text alignment or formatting controls</do>
4
- <do>Single- or multi-select pressed states across related ToggleButton items</do>
5
- <do>Compact action clusters that need coordinated value and disabled state</do>
6
- <dont>Omitting value on ToggleButton children inside a group</dont>
3
+ <do>Segmented icon toolbars such as text alignment, formatting, or mode switchers</do>
4
+ <do>Single- or multi-select pressed states across related ToggleButton items (`value` / `defaultValue` as `string[]`)</do>
5
+ <do>Compose only ToggleButton children — each child needs a `value` plus `aria-label` / `aria-labelledby`</do>
6
+ <do>Label the group root with `aria-label` or `aria-labelledby`</do>
7
+ <do>Optional Surface chrome around the group for bordered toolbar shells — Stack gap is owned by ToggleGroup</do>
8
+ <dont>Omitting `value` on ToggleButton children inside a group</dont>
7
9
  <dont>Using Switch for icon-only toolbar toggle sets</dont>
8
- <dont>Embedding Surface chrome in the component — wrap demos or app chrome at the consumer</dont>
10
+ <dont>Using ToggleGroup for tabbed panel navigation — use Tabs</dont>
11
+ <dont>Using ToggleGroup for a lone one-off toggle — use ToggleButton alone</dont>
12
+ <dont>Embedding Surface chrome inside the component — wrap demos or app chrome at the consumer</dont>
9
13
  </usage>