@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.
- package/dist/docs/AGENTS.md +9 -0
- package/dist/docs/components/accordion.md +489 -0
- package/dist/docs/components/address-card.md +147 -0
- package/dist/docs/components/agent-logo.md +194 -0
- package/dist/docs/components/alert-dialog.md +631 -0
- package/dist/docs/components/alert.md +448 -0
- package/dist/docs/components/amount-input.md +305 -0
- package/dist/docs/components/amount.md +794 -0
- package/dist/docs/components/app-shell.md +559 -0
- package/dist/docs/components/asset-chip.md +294 -0
- package/dist/docs/components/autocomplete.md +619 -0
- package/dist/docs/components/avatar.md +321 -0
- package/dist/docs/components/badge.md +339 -0
- package/dist/docs/components/badged-logo.md +116 -0
- package/dist/docs/components/banner.md +379 -0
- package/dist/docs/components/bar-chart.md +208 -0
- package/dist/docs/components/breadcrumbs.md +380 -0
- package/dist/docs/components/button-group.md +286 -0
- package/dist/docs/components/button.md +650 -0
- package/dist/docs/components/calendar.md +375 -0
- package/dist/docs/components/callout.md +96 -0
- package/dist/docs/components/checkbox-group.md +521 -0
- package/dist/docs/components/checkbox.md +467 -0
- package/dist/docs/components/choice-group.md +516 -0
- package/dist/docs/components/choicebox.md +641 -0
- package/dist/docs/components/code.md +100 -0
- package/dist/docs/components/combobox.md +939 -0
- package/dist/docs/components/container.md +257 -0
- package/dist/docs/components/copy-button.md +642 -0
- package/dist/docs/components/date-picker.md +514 -0
- package/dist/docs/components/dialog.md +1332 -0
- package/dist/docs/components/drawer.md +966 -0
- package/dist/docs/components/empty.md +340 -0
- package/dist/docs/components/field.md +570 -0
- package/dist/docs/components/fieldset.md +398 -0
- package/dist/docs/components/frame.md +434 -0
- package/dist/docs/components/gauge.md +299 -0
- package/dist/docs/components/get-started-visual.md +117 -0
- package/dist/docs/components/grid.md +288 -0
- package/dist/docs/components/hero-visual.md +155 -0
- package/dist/docs/components/hex.md +487 -0
- package/dist/docs/components/icon-tile.md +292 -0
- package/dist/docs/components/identicon.md +371 -0
- package/dist/docs/components/inline.md +233 -0
- package/dist/docs/components/inset.md +225 -0
- package/dist/docs/components/kbd.md +423 -0
- package/dist/docs/components/list-group.md +981 -0
- package/dist/docs/components/loading-dots.md +237 -0
- package/dist/docs/components/menu.md +934 -0
- package/dist/docs/components/native-select.md +204 -0
- package/dist/docs/components/network-logo.md +248 -0
- package/dist/docs/components/number-field.md +543 -0
- package/dist/docs/components/otp-field.md +616 -0
- package/dist/docs/components/pagination.md +516 -0
- package/dist/docs/components/popover.md +544 -0
- package/dist/docs/components/progress.md +388 -0
- package/dist/docs/components/qr.md +314 -0
- package/dist/docs/components/radio-group.md +528 -0
- package/dist/docs/components/secret-value.md +406 -0
- package/dist/docs/components/select.md +751 -0
- package/dist/docs/components/separator.md +379 -0
- package/dist/docs/components/sidebar-menu.md +922 -0
- package/dist/docs/components/skeleton.md +517 -0
- package/dist/docs/components/slider.md +539 -0
- package/dist/docs/components/snippet.md +424 -0
- package/dist/docs/components/spinner.md +216 -0
- package/dist/docs/components/split-bar.md +139 -0
- package/dist/docs/components/split-button.md +464 -0
- package/dist/docs/components/stack.md +299 -0
- package/dist/docs/components/status-chip.md +226 -0
- package/dist/docs/components/status-indicator.md +119 -0
- package/dist/docs/components/status-row.md +174 -0
- package/dist/docs/components/stepper.md +451 -0
- package/dist/docs/components/success-hero.md +157 -0
- package/dist/docs/components/surface.md +639 -0
- package/dist/docs/components/switch.md +472 -0
- package/dist/docs/components/table.md +967 -0
- package/dist/docs/components/tabs.md +627 -0
- package/dist/docs/components/tempo-logo.md +185 -0
- package/dist/docs/components/text-input.md +624 -0
- package/dist/docs/components/textarea.md +352 -0
- package/dist/docs/components/toast.md +535 -0
- package/dist/docs/components/token-logo.md +371 -0
- package/dist/docs/components/token.md +247 -0
- package/dist/docs/components/tooltip.md +490 -0
- package/dist/docs/components/verification-code.md +116 -0
- package/dist/docs/components/visual.md +249 -0
- package/dist/docs/components.md +203 -0
- package/dist/docs/foundations/accessibility.md +377 -0
- package/dist/docs/foundations/agents.md +150 -0
- package/dist/docs/foundations/color.md +522 -0
- package/dist/docs/foundations/content/tone.md +194 -0
- package/dist/docs/foundations/content/voice.md +194 -0
- package/dist/docs/foundations/content/writing-style.md +406 -0
- package/dist/docs/foundations/iconography.md +282 -0
- package/dist/docs/foundations/intent.md +360 -0
- package/dist/docs/foundations/layout.md +508 -0
- package/dist/docs/foundations/linter.md +296 -0
- package/dist/docs/foundations/motion.md +151 -0
- package/dist/docs/foundations/radius-and-padding.md +86 -0
- package/dist/docs/foundations/typography.md +266 -0
- package/dist/docs/index.md +137 -0
- package/dist/docs/introduction/faq.md +132 -0
- package/dist/docs/introduction/getting-started.md +377 -0
- package/dist/docs/patterns/blockchain-values.md +709 -0
- package/dist/docs/patterns/dashboards.md +638 -0
- package/dist/docs/patterns/destructive-actions.md +626 -0
- package/dist/docs/patterns/empty-states.md +612 -0
- package/dist/docs/patterns/errors-and-validation.md +808 -0
- package/dist/docs/patterns/feedback-and-status.md +518 -0
- package/dist/docs/patterns/forms.md +679 -0
- package/dist/docs/patterns/loading.md +630 -0
- package/dist/docs/patterns/navigation.md +397 -0
- package/dist/docs/patterns/payments.md +765 -0
- package/dist/docs/patterns/responsive-layout.md +997 -0
- package/dist/docs/patterns/tables-and-lists.md +964 -0
- package/dist/docs/products/tempo-console.md +671 -0
- package/dist/docs/products/tempo-performance.md +437 -0
- package/dist/docs/products/tempo-wallet.md +438 -0
- 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.
|