@tempoxyz/ds 0.3.10 → 0.3.11

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 (120) hide show
  1. package/dist/docs/AGENTS.md +9 -0
  2. package/dist/docs/components/accordion.md +489 -0
  3. package/dist/docs/components/address-card.md +147 -0
  4. package/dist/docs/components/agent-logo.md +194 -0
  5. package/dist/docs/components/alert-dialog.md +631 -0
  6. package/dist/docs/components/alert.md +448 -0
  7. package/dist/docs/components/amount-input.md +305 -0
  8. package/dist/docs/components/amount.md +794 -0
  9. package/dist/docs/components/app-shell.md +559 -0
  10. package/dist/docs/components/asset-chip.md +294 -0
  11. package/dist/docs/components/autocomplete.md +619 -0
  12. package/dist/docs/components/avatar.md +321 -0
  13. package/dist/docs/components/badge.md +339 -0
  14. package/dist/docs/components/badged-logo.md +116 -0
  15. package/dist/docs/components/banner.md +379 -0
  16. package/dist/docs/components/bar-chart.md +208 -0
  17. package/dist/docs/components/breadcrumbs.md +380 -0
  18. package/dist/docs/components/button-group.md +286 -0
  19. package/dist/docs/components/button.md +650 -0
  20. package/dist/docs/components/calendar.md +375 -0
  21. package/dist/docs/components/callout.md +96 -0
  22. package/dist/docs/components/checkbox-group.md +521 -0
  23. package/dist/docs/components/checkbox.md +467 -0
  24. package/dist/docs/components/choice-group.md +516 -0
  25. package/dist/docs/components/choicebox.md +641 -0
  26. package/dist/docs/components/code.md +100 -0
  27. package/dist/docs/components/combobox.md +939 -0
  28. package/dist/docs/components/container.md +257 -0
  29. package/dist/docs/components/copy-button.md +642 -0
  30. package/dist/docs/components/date-picker.md +514 -0
  31. package/dist/docs/components/dialog.md +1332 -0
  32. package/dist/docs/components/drawer.md +966 -0
  33. package/dist/docs/components/empty.md +340 -0
  34. package/dist/docs/components/field.md +570 -0
  35. package/dist/docs/components/fieldset.md +398 -0
  36. package/dist/docs/components/frame.md +434 -0
  37. package/dist/docs/components/gauge.md +299 -0
  38. package/dist/docs/components/get-started-visual.md +117 -0
  39. package/dist/docs/components/grid.md +288 -0
  40. package/dist/docs/components/hero-visual.md +155 -0
  41. package/dist/docs/components/hex.md +487 -0
  42. package/dist/docs/components/icon-tile.md +292 -0
  43. package/dist/docs/components/identicon.md +371 -0
  44. package/dist/docs/components/inline.md +233 -0
  45. package/dist/docs/components/inset.md +225 -0
  46. package/dist/docs/components/kbd.md +423 -0
  47. package/dist/docs/components/list-group.md +981 -0
  48. package/dist/docs/components/loading-dots.md +237 -0
  49. package/dist/docs/components/menu.md +934 -0
  50. package/dist/docs/components/native-select.md +204 -0
  51. package/dist/docs/components/network-logo.md +248 -0
  52. package/dist/docs/components/number-field.md +543 -0
  53. package/dist/docs/components/otp-field.md +616 -0
  54. package/dist/docs/components/pagination.md +516 -0
  55. package/dist/docs/components/popover.md +544 -0
  56. package/dist/docs/components/progress.md +388 -0
  57. package/dist/docs/components/qr.md +314 -0
  58. package/dist/docs/components/radio-group.md +528 -0
  59. package/dist/docs/components/secret-value.md +406 -0
  60. package/dist/docs/components/select.md +751 -0
  61. package/dist/docs/components/separator.md +379 -0
  62. package/dist/docs/components/sidebar-menu.md +922 -0
  63. package/dist/docs/components/skeleton.md +517 -0
  64. package/dist/docs/components/slider.md +539 -0
  65. package/dist/docs/components/snippet.md +424 -0
  66. package/dist/docs/components/spinner.md +216 -0
  67. package/dist/docs/components/split-bar.md +139 -0
  68. package/dist/docs/components/split-button.md +464 -0
  69. package/dist/docs/components/stack.md +299 -0
  70. package/dist/docs/components/status-chip.md +226 -0
  71. package/dist/docs/components/status-indicator.md +119 -0
  72. package/dist/docs/components/status-row.md +174 -0
  73. package/dist/docs/components/stepper.md +451 -0
  74. package/dist/docs/components/success-hero.md +157 -0
  75. package/dist/docs/components/surface.md +639 -0
  76. package/dist/docs/components/switch.md +472 -0
  77. package/dist/docs/components/table.md +967 -0
  78. package/dist/docs/components/tabs.md +627 -0
  79. package/dist/docs/components/tempo-logo.md +185 -0
  80. package/dist/docs/components/text-input.md +624 -0
  81. package/dist/docs/components/textarea.md +352 -0
  82. package/dist/docs/components/toast.md +535 -0
  83. package/dist/docs/components/token-logo.md +371 -0
  84. package/dist/docs/components/token.md +247 -0
  85. package/dist/docs/components/tooltip.md +490 -0
  86. package/dist/docs/components/verification-code.md +116 -0
  87. package/dist/docs/components/visual.md +249 -0
  88. package/dist/docs/components.md +203 -0
  89. package/dist/docs/foundations/accessibility.md +377 -0
  90. package/dist/docs/foundations/agents.md +150 -0
  91. package/dist/docs/foundations/color.md +522 -0
  92. package/dist/docs/foundations/content/tone.md +194 -0
  93. package/dist/docs/foundations/content/voice.md +194 -0
  94. package/dist/docs/foundations/content/writing-style.md +406 -0
  95. package/dist/docs/foundations/iconography.md +282 -0
  96. package/dist/docs/foundations/intent.md +360 -0
  97. package/dist/docs/foundations/layout.md +508 -0
  98. package/dist/docs/foundations/linter.md +296 -0
  99. package/dist/docs/foundations/motion.md +151 -0
  100. package/dist/docs/foundations/radius-and-padding.md +86 -0
  101. package/dist/docs/foundations/typography.md +266 -0
  102. package/dist/docs/index.md +137 -0
  103. package/dist/docs/introduction/faq.md +132 -0
  104. package/dist/docs/introduction/getting-started.md +377 -0
  105. package/dist/docs/patterns/blockchain-values.md +709 -0
  106. package/dist/docs/patterns/dashboards.md +638 -0
  107. package/dist/docs/patterns/destructive-actions.md +626 -0
  108. package/dist/docs/patterns/empty-states.md +612 -0
  109. package/dist/docs/patterns/errors-and-validation.md +808 -0
  110. package/dist/docs/patterns/feedback-and-status.md +518 -0
  111. package/dist/docs/patterns/forms.md +679 -0
  112. package/dist/docs/patterns/loading.md +630 -0
  113. package/dist/docs/patterns/navigation.md +397 -0
  114. package/dist/docs/patterns/payments.md +765 -0
  115. package/dist/docs/patterns/responsive-layout.md +997 -0
  116. package/dist/docs/patterns/tables-and-lists.md +964 -0
  117. package/dist/docs/products/tempo-console.md +671 -0
  118. package/dist/docs/products/tempo-performance.md +437 -0
  119. package/dist/docs/products/tempo-wallet.md +438 -0
  120. package/package.json +1 -1
@@ -0,0 +1,139 @@
1
+ # SplitBar
2
+
3
+ Splits one total between two parts, with a legend under the bar.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/SplitBar.tsx)
6
+
7
+ Figma: [Data/Split Bar](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-4474)
8
+
9
+ ## Overview
10
+
11
+ A split bar renders a thin bar that two parts share in proportion to their values, and a legend that names each part with its value. A part of zero draws no segment, so the other part fills the bar.
12
+
13
+ ## Examples
14
+
15
+ ### Basic
16
+
17
+ ```tsx
18
+ import { SplitBar } from '@tempoxyz/ds'
19
+
20
+ export function Demo() {
21
+ return (
22
+ <SplitBar
23
+ items={[
24
+ { label: 'Available', text: '$75.62', value: 75.62 },
25
+ { label: 'Agents', text: '$8.58', value: 8.58 },
26
+ ]}
27
+ />
28
+ )
29
+ }
30
+ ```
31
+
32
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/SplitBar/Basic.tsx)
33
+
34
+ ### One Part
35
+
36
+ A part of 0 keeps its legend entry and draws no segment.
37
+
38
+ ```tsx
39
+ import { SplitBar } from '@tempoxyz/ds'
40
+
41
+ export function Demo() {
42
+ return (
43
+ <SplitBar
44
+ items={[
45
+ { label: 'Available', text: '$75.62', value: 75.62 },
46
+ { label: 'Agents', text: '$0.00', value: 0 },
47
+ ]}
48
+ />
49
+ )
50
+ }
51
+ ```
52
+
53
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/SplitBar/Empty.tsx)
54
+
55
+ ## Anatomy
56
+
57
+ Import the component and assemble its parts.
58
+
59
+ ```tsx
60
+ import { SplitBar } from '@tempoxyz/ds'
61
+
62
+ <SplitBar />
63
+ ```
64
+
65
+ ## Guidelines
66
+
67
+ ### When to Use
68
+
69
+ * Show how a balance splits between two uses, such as the available funds and the funds set aside for agents.
70
+
71
+ ### When Not to Use
72
+
73
+ * Use [BarChart](/docs/components/bar-chart) for values over time.
74
+ * Use [Progress](/docs/components/progress) for the progress of one task.
75
+ * Use [Gauge](/docs/components/gauge) for one value against a limit.
76
+
77
+ ### Show the Values
78
+
79
+ **Do:** Give each part its amount, in the unit people act on.
80
+
81
+ ```tsx
82
+ import { SplitBar } from '@tempoxyz/ds'
83
+
84
+ export function Demo() {
85
+ return (
86
+ <SplitBar
87
+ items={[
88
+ { label: 'Available', text: '$75.62', value: 75.62 },
89
+ { label: 'Agents', text: '$8.58', value: 8.58 },
90
+ ]}
91
+ />
92
+ )
93
+ }
94
+ ```
95
+
96
+ **Don't:** Show percentages alone when people act on amounts.
97
+
98
+ ```tsx
99
+ import { SplitBar } from '@tempoxyz/ds'
100
+
101
+ export function Demo() {
102
+ return (
103
+ <SplitBar
104
+ items={[
105
+ { label: 'Available', text: '90%', value: 90 },
106
+ { label: 'Agents', text: '10%', value: 10 },
107
+ ]}
108
+ />
109
+ )
110
+ }
111
+ ```
112
+
113
+ ## Content
114
+
115
+ ### Name the Parts
116
+
117
+ Name each part with one or two words, such as Available and Agents. Format each value as the rest of the page does, such as $75.62.
118
+
119
+ ## Accessibility
120
+
121
+ A split bar renders a `<div>` whose bar is hidden from screen readers. The legend carries each label and value as text, in reading order.
122
+
123
+ ### Semantics
124
+
125
+ * **Bar (aria-hidden):** Screen readers skip the bar and read the legend.
126
+
127
+ ### Your Responsibilities
128
+
129
+ * **Name the Total (SC 1.3.1):** Place a heading or a label before the bar that names what it splits.
130
+
131
+ ## Related
132
+
133
+ [BarChart](/docs/components/bar-chart)
134
+
135
+ Use for values over time.
136
+
137
+ [Progress](/docs/components/progress)
138
+
139
+ Use for the progress of one task.
@@ -0,0 +1,464 @@
1
+ # SplitButton
2
+
3
+ Pairs a primary action with a menu of alternatives.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/SplitButton.tsx)
6
+
7
+ ## Overview
8
+
9
+ A split button places the most common action beside a trigger that opens a menu of alternatives.
10
+
11
+ ## Examples
12
+
13
+ ### Basic
14
+
15
+ ```tsx
16
+ import { Menu, SplitButton } from '@tempoxyz/ds'
17
+
18
+ export function Demo() {
19
+ return (
20
+ <SplitButton.Root aria-label="Save">
21
+ <SplitButton.Action>Save</SplitButton.Action>
22
+ <Menu.Root>
23
+ <SplitButton.Trigger aria-label="More save options" />
24
+ <Menu.Popup align="end">
25
+ <Menu.Item>Save as draft</Menu.Item>
26
+ <Menu.Item>Save and close</Menu.Item>
27
+ </Menu.Popup>
28
+ </Menu.Root>
29
+ </SplitButton.Root>
30
+ )
31
+ }
32
+ ```
33
+
34
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/SplitButton/Basic.tsx)
35
+
36
+ ### Variant
37
+
38
+ Set `variant` on `SplitButton.Root` to `primary` (default), `secondary`, or `tertiary`.
39
+
40
+ ```tsx
41
+ import { Menu, SplitButton, style } from '@tempoxyz/ds'
42
+
43
+ export function Demo() {
44
+ return (
45
+ <div {...styles.row()}>
46
+ {(['primary', 'secondary', 'tertiary'] as const).map((variant) => (
47
+ <SplitButton.Root key={variant} variant={variant}>
48
+ <SplitButton.Action>Save</SplitButton.Action>
49
+ <Menu.Root>
50
+ <SplitButton.Trigger aria-label="More save options" />
51
+ <Menu.Popup align="end">
52
+ <Menu.Item>Save as draft</Menu.Item>
53
+ <Menu.Item>Save and close</Menu.Item>
54
+ </Menu.Popup>
55
+ </Menu.Root>
56
+ </SplitButton.Root>
57
+ ))}
58
+ </div>
59
+ )
60
+ }
61
+
62
+ namespace styles {
63
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
64
+ }
65
+ ```
66
+
67
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/SplitButton/Variant.tsx)
68
+
69
+ ## Anatomy
70
+
71
+ Import the component and assemble its parts.
72
+
73
+ ```tsx
74
+ import { Menu, SplitButton } from '@tempoxyz/ds'
75
+
76
+ <SplitButton.Root>
77
+ <SplitButton.Action />
78
+ <Menu.Root>
79
+ <SplitButton.Trigger />
80
+ <Menu.Popup />
81
+ </Menu.Root>
82
+ </SplitButton.Root>
83
+ ```
84
+
85
+ ## Guidelines
86
+
87
+ ### When to Use
88
+
89
+ * Offer a main action with a few variations, such as Export CSV with Export JSON and Schedule export.
90
+ * Keep the common choice one press away, such as Create key with Create test key.
91
+
92
+ ### When Not to Use
93
+
94
+ * Use a [Button](/docs/components/button) with a [Menu](/docs/components/menu) when no option is the clear default.
95
+ * Use two [Buttons](/docs/components/button) when both actions matter equally.
96
+ * Use [Select](/docs/components/select) or [ChoiceGroup](/docs/components/choice-group) to choose a value or mode, not to run an action.
97
+ * Use a separate [Button](/docs/components/button) for destructive actions, confirmed with an [AlertDialog](/docs/components/alert-dialog).
98
+
99
+ ### Make the Action the Common Choice
100
+
101
+ `SplitButton.Action` runs without opening the menu, so give it the option most people pick. If people often open the menu first, move the popular option into the action, or use a [Menu](/docs/components/menu) button.
102
+
103
+ **Do:** Put the option most people pick on the action.
104
+
105
+ ```tsx
106
+ /**
107
+ * Do example for "Make the Action the Common Choice" on the SplitButton page.
108
+ * Put the option most people pick on the action.
109
+ * @module
110
+ */
111
+ import { Menu, SplitButton, style } from '@tempoxyz/ds'
112
+
113
+ /** Renders the static preview, which the guideline card shows inert. */
114
+ export function Demo() {
115
+ return (
116
+ <div {...styles.stack()}>
117
+ <SplitButton.Root aria-label="Keys">
118
+ <SplitButton.Action>Create key</SplitButton.Action>
119
+ <Menu.Root>
120
+ <SplitButton.Trigger aria-label="More key options" />
121
+ </Menu.Root>
122
+ </SplitButton.Root>
123
+ <div {...styles.popup()}>
124
+ <div {...styles.item()}>Create test key</div>
125
+ <div {...styles.item()}>Import key</div>
126
+ </div>
127
+ </div>
128
+ )
129
+ }
130
+
131
+ namespace styles {
132
+ export const item = style({
133
+ alignItems: 'center',
134
+ borderRadius: 'xs',
135
+ color: 'content.primary',
136
+ display: 'flex',
137
+ minHeight: '40',
138
+ paddingInline: '12',
139
+ typography: 'body.b2Strong',
140
+ })
141
+
142
+ export const popup = style({
143
+ backgroundColor: 'background.elevated',
144
+ borderRadius: 'sm',
145
+ boxShadow: 'regular',
146
+ boxSizing: 'border-box',
147
+ minWidth: '14rem !custom',
148
+ padding: '12',
149
+ })
150
+
151
+ export const stack = style({
152
+ alignItems: 'flex-end',
153
+ display: 'flex',
154
+ flexDirection: 'column',
155
+ rowGap: '4',
156
+ })
157
+ }
158
+ ```
159
+
160
+ **Don't:** Put a rare option on the action and the common one in the menu.
161
+
162
+ ```tsx
163
+ /**
164
+ * Don't example for "Make the Action the Common Choice" on the SplitButton page.
165
+ * Don't put a rare option on the action and the common one in the menu.
166
+ * @module
167
+ */
168
+ import { Menu, SplitButton, style } from '@tempoxyz/ds'
169
+
170
+ /** Renders the static preview, which the guideline card shows inert. */
171
+ export function Demo() {
172
+ return (
173
+ <div {...styles.stack()}>
174
+ <SplitButton.Root aria-label="Keys">
175
+ <SplitButton.Action>Import key</SplitButton.Action>
176
+ <Menu.Root>
177
+ <SplitButton.Trigger aria-label="More key options" />
178
+ </Menu.Root>
179
+ </SplitButton.Root>
180
+ <div {...styles.popup()}>
181
+ <div {...styles.item()}>Create key</div>
182
+ <div {...styles.item()}>Create test key</div>
183
+ </div>
184
+ </div>
185
+ )
186
+ }
187
+
188
+ namespace styles {
189
+ export const item = style({
190
+ alignItems: 'center',
191
+ borderRadius: 'xs',
192
+ color: 'content.primary',
193
+ display: 'flex',
194
+ minHeight: '40',
195
+ paddingInline: '12',
196
+ typography: 'body.b2Strong',
197
+ })
198
+
199
+ export const popup = style({
200
+ backgroundColor: 'background.elevated',
201
+ borderRadius: 'sm',
202
+ boxShadow: 'regular',
203
+ boxSizing: 'border-box',
204
+ minWidth: '14rem !custom',
205
+ padding: '12',
206
+ })
207
+
208
+ export const stack = style({
209
+ alignItems: 'flex-end',
210
+ display: 'flex',
211
+ flexDirection: 'column',
212
+ rowGap: '4',
213
+ })
214
+ }
215
+ ```
216
+
217
+ ### Keep Alternatives Related
218
+
219
+ Make every menu item a variation of the action, such as a different format or timing, and use two to five of them. Put unrelated commands, or a longer list, in a [Menu](/docs/components/menu).
220
+
221
+ **Do:** Fill the menu with variations of the main action.
222
+
223
+ ```tsx
224
+ /**
225
+ * Do example for "Keep Alternatives Related" on the SplitButton page.
226
+ * Fill the menu with variations of the main action.
227
+ * @module
228
+ */
229
+ import { Menu, SplitButton, style } from '@tempoxyz/ds'
230
+
231
+ /** Renders the static preview, which the guideline card shows inert. */
232
+ export function Demo() {
233
+ return (
234
+ <div {...styles.stack()}>
235
+ <SplitButton.Root aria-label="Export" variant="secondary">
236
+ <SplitButton.Action>Export CSV</SplitButton.Action>
237
+ <Menu.Root>
238
+ <SplitButton.Trigger aria-label="More export options" />
239
+ </Menu.Root>
240
+ </SplitButton.Root>
241
+ <div {...styles.popup()}>
242
+ <div {...styles.item()}>Export JSON</div>
243
+ <div {...styles.item()}>Schedule export</div>
244
+ </div>
245
+ </div>
246
+ )
247
+ }
248
+
249
+ namespace styles {
250
+ export const item = style({
251
+ alignItems: 'center',
252
+ borderRadius: 'xs',
253
+ color: 'content.primary',
254
+ display: 'flex',
255
+ minHeight: '40',
256
+ paddingInline: '12',
257
+ typography: 'body.b2Strong',
258
+ })
259
+
260
+ export const popup = style({
261
+ backgroundColor: 'background.elevated',
262
+ borderRadius: 'sm',
263
+ boxShadow: 'regular',
264
+ boxSizing: 'border-box',
265
+ minWidth: '14rem !custom',
266
+ padding: '12',
267
+ })
268
+
269
+ export const stack = style({
270
+ alignItems: 'flex-end',
271
+ display: 'flex',
272
+ flexDirection: 'column',
273
+ rowGap: '4',
274
+ })
275
+ }
276
+ ```
277
+
278
+ **Don't:** Collect unrelated or destructive commands behind the trigger.
279
+
280
+ ```tsx
281
+ /**
282
+ * Don't example for "Keep Alternatives Related" on the SplitButton page.
283
+ * Don't collect unrelated or destructive commands behind the trigger.
284
+ * @module
285
+ */
286
+ import { Menu, SplitButton, style, variants } from '@tempoxyz/ds'
287
+
288
+ /** Renders the static preview, which the guideline card shows inert. */
289
+ export function Demo() {
290
+ return (
291
+ <div {...styles.stack()}>
292
+ <SplitButton.Root aria-label="Export" variant="secondary">
293
+ <SplitButton.Action>Export CSV</SplitButton.Action>
294
+ <Menu.Root>
295
+ <SplitButton.Trigger aria-label="More options" />
296
+ </Menu.Root>
297
+ </SplitButton.Root>
298
+ <div {...styles.popup()}>
299
+ <div {...styles.item()}>Rename dashboard</div>
300
+ <div {...styles.item()}>Share</div>
301
+ <div {...styles.item({ intent: 'negative' })}>Delete dashboard</div>
302
+ </div>
303
+ </div>
304
+ )
305
+ }
306
+
307
+ namespace styles {
308
+ export const item = variants({
309
+ base: {
310
+ alignItems: 'center',
311
+ borderRadius: 'xs',
312
+ color: 'content.primary',
313
+ display: 'flex',
314
+ minHeight: '40',
315
+ paddingInline: '12',
316
+ typography: 'body.b2Strong',
317
+ },
318
+ defaultVariants: { intent: 'default' },
319
+ variants: {
320
+ intent: {
321
+ default: {},
322
+ negative: { color: 'content.negative' },
323
+ },
324
+ },
325
+ })
326
+
327
+ export const popup = style({
328
+ backgroundColor: 'background.elevated',
329
+ borderRadius: 'sm',
330
+ boxShadow: 'regular',
331
+ boxSizing: 'border-box',
332
+ minWidth: '14rem !custom',
333
+ padding: '12',
334
+ })
335
+
336
+ export const stack = style({
337
+ alignItems: 'flex-end',
338
+ display: 'flex',
339
+ flexDirection: 'column',
340
+ rowGap: '4',
341
+ })
342
+ }
343
+ ```
344
+
345
+ ### Match the Buttons Around It
346
+
347
+ Set `variant` and `size` on `SplitButton.Root`, and both buttons follow. A split button counts toward the one `primary` action per section, so use `secondary` when the view already has one. Use `small` in toolbars and table headers.
348
+
349
+ **Do:** Match the size of nearby buttons, and leave `primary` to the main action.
350
+
351
+ ```tsx
352
+ /**
353
+ * Do example for "Match the Buttons Around It" on the SplitButton page.
354
+ * Match the size of nearby buttons, and leave `primary` to the main action.
355
+ * @module
356
+ */
357
+ import { Button, Menu, SplitButton, style } from '@tempoxyz/ds'
358
+
359
+ /** Renders the static preview, which the guideline card shows inert. */
360
+ export function Demo() {
361
+ return (
362
+ <div {...styles.row()}>
363
+ <SplitButton.Root aria-label="Export" size="small" variant="secondary">
364
+ <SplitButton.Action>Export CSV</SplitButton.Action>
365
+ <Menu.Root>
366
+ <SplitButton.Trigger aria-label="More export options" />
367
+ </Menu.Root>
368
+ </SplitButton.Root>
369
+ <Button size="small">Send payment</Button>
370
+ </div>
371
+ )
372
+ }
373
+
374
+ namespace styles {
375
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
376
+ }
377
+ ```
378
+
379
+ **Don't:** Add a second `primary` action, or a size that differs from its neighbors.
380
+
381
+ ```tsx
382
+ /**
383
+ * Don't example for "Match the Buttons Around It" on the SplitButton page.
384
+ * Don't add a second `primary` action, or a size that differs from its neighbors.
385
+ * @module
386
+ */
387
+ import { Button, Menu, SplitButton, style } from '@tempoxyz/ds'
388
+
389
+ /** Renders the static preview, which the guideline card shows inert. */
390
+ export function Demo() {
391
+ return (
392
+ <div {...styles.row()}>
393
+ <SplitButton.Root aria-label="Export">
394
+ <SplitButton.Action>Export CSV</SplitButton.Action>
395
+ <Menu.Root>
396
+ <SplitButton.Trigger aria-label="More export options" />
397
+ </Menu.Root>
398
+ </SplitButton.Root>
399
+ <Button size="small">Send payment</Button>
400
+ </div>
401
+ )
402
+ }
403
+
404
+ namespace styles {
405
+ export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
406
+ }
407
+ ```
408
+
409
+ ## Content
410
+
411
+ ### Name the Action and Its Object
412
+
413
+ Label `SplitButton.Action` with a verb and an object, such as Export CSV. A bare Export hides which variation runs.
414
+
415
+ ### Make Each Item Stand Alone
416
+
417
+ Repeat the verb in each menu item, such as Export JSON, not JSON, so each item reads as a complete action.
418
+
419
+ ## Accessibility
420
+
421
+ `SplitButton` renders a group with a primary [Button](/docs/components/button) and a menu trigger. The trigger follows the [WAI-ARIA menu button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/).
422
+
423
+ ### Semantics
424
+
425
+ * **SplitButton.Root (group):** Holds both buttons, named by its `aria-label`.
426
+ * **SplitButton.Action (button):** The primary action, as a native button.
427
+ * **SplitButton.Trigger (aria-haspopup):** A native button that announces its menu and open state.
428
+ * **Menu (menu):** Named by the trigger. Items are announced as menu items.
429
+ * **Chevron (reduced motion):** Rotates while the menu is open. Flips without animation under reduced motion.
430
+
431
+ ### Keyboard
432
+
433
+ * **Move Between Buttons (Tab):** Moves focus to the action, then to the trigger.
434
+ * **Run the Action (Enter or Space):** On the action, runs the primary action.
435
+ * **Open to the First Item (Enter, Space, or Down Arrow):** Opens the menu and focuses the first item.
436
+ * **Open to the Last Item (Up Arrow):** Opens the menu and focuses the last item.
437
+ * **Move Between Items (Down Arrow and Up Arrow):** Move between items, and wrap at the ends.
438
+ * **Jump to the Ends (Home and End):** Move to the first and last item.
439
+ * **Activate an Item (Enter):** Activates the focused item and closes the menu.
440
+ * **Close the Menu (Escape):** Closes the menu.
441
+
442
+ ### Your Responsibilities
443
+
444
+ * **Name the Group (aria-label):** Name the root, such as "Save", so the pair reads as one group.
445
+ * **Name the Trigger (aria-label):** Name the alternatives, such as "More save options". The chevron is the trigger's only content.
446
+ * **Keep Actions Reachable:** If the primary action fails or is disabled, keep every menu action reachable another way.
447
+
448
+ ## Related
449
+
450
+ [Button](/docs/components/button)
451
+
452
+ Use for single actions.
453
+
454
+ [Menu](/docs/components/menu)
455
+
456
+ Use for lists of actions without a default.
457
+
458
+ [AlertDialog](/docs/components/alert-dialog)
459
+
460
+ Use for confirming destructive actions.
461
+
462
+ [Forms](/docs/patterns/forms)
463
+
464
+ Covers placing actions.