@tempoxyz/ds 0.3.9 → 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/dist/web/components/OtpField.css +1 -1
- package/dist/web/components/OtpField.d.ts +1 -1
- package/dist/web/components/OtpField.d.ts.map +1 -1
- package/dist/web/components/OtpField.js +3 -4
- package/dist/web/components/OtpField.js.map +1 -1
- package/dist/web/components/OtpField.js.zyzz.json +1 -1
- package/dist/web/index.js.zyzz.json +1 -1
- package/package.json +1 -1
- package/src/web/components/OtpField.tsx +2 -24
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Avatar
|
|
2
|
+
|
|
3
|
+
Represents a person, contact, or wallet with an image, initials, or an icon.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Avatar.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Avatar](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1418-13100)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
An avatar is a circle that holds an image, or initials or an icon in secondary text on a neutral fill. It leads a list row or a modal header.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Avatar } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export function Demo() {
|
|
21
|
+
return (
|
|
22
|
+
<Avatar.Root>
|
|
23
|
+
<Avatar.Fallback>J</Avatar.Fallback>
|
|
24
|
+
</Avatar.Root>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Basic.tsx)
|
|
30
|
+
|
|
31
|
+
### Size
|
|
32
|
+
|
|
33
|
+
Set `size` to `16`, `24`, `32`, `40` (default), `48`, or `64`.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Avatar, style } from '@tempoxyz/ds'
|
|
37
|
+
|
|
38
|
+
export function Demo() {
|
|
39
|
+
return (
|
|
40
|
+
<div {...styles.row()}>
|
|
41
|
+
{(['16', '24', '32', '40', '48', '64'] as const).map((size) => (
|
|
42
|
+
<Avatar.Root key={size} size={size}>
|
|
43
|
+
<Avatar.Fallback>J</Avatar.Fallback>
|
|
44
|
+
</Avatar.Root>
|
|
45
|
+
))}
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
namespace styles {
|
|
51
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Size.tsx)
|
|
56
|
+
|
|
57
|
+
### Icon
|
|
58
|
+
|
|
59
|
+
Put an icon in `Avatar.Fallback` for a wallet or app. It renders at 16px in a `24` or `32` avatar, and at 20px in a `40` avatar.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { Avatar, style } from '@tempoxyz/ds'
|
|
63
|
+
import { Wallet } from '@tempoxyz/ds/icons'
|
|
64
|
+
|
|
65
|
+
export function Demo() {
|
|
66
|
+
return (
|
|
67
|
+
<div {...styles.row()}>
|
|
68
|
+
{(['24', '32', '40'] as const).map((size) => (
|
|
69
|
+
<Avatar.Root key={size} size={size}>
|
|
70
|
+
<Avatar.Fallback>
|
|
71
|
+
<Wallet />
|
|
72
|
+
</Avatar.Fallback>
|
|
73
|
+
</Avatar.Root>
|
|
74
|
+
))}
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
namespace styles {
|
|
80
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Avatar/Icon.tsx)
|
|
85
|
+
|
|
86
|
+
## Anatomy
|
|
87
|
+
|
|
88
|
+
Import the component and assemble its parts.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { Avatar } from '@tempoxyz/ds'
|
|
92
|
+
|
|
93
|
+
<Avatar />
|
|
94
|
+
|
|
95
|
+
<Avatar.Root>
|
|
96
|
+
<Avatar.Image />
|
|
97
|
+
<Avatar.Fallback />
|
|
98
|
+
</Avatar.Root>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Guidelines
|
|
102
|
+
|
|
103
|
+
### When to Use
|
|
104
|
+
|
|
105
|
+
* Represent a person or organization beside their name, such as a contact in Send or a merchant in activity.
|
|
106
|
+
* Represent a wallet or app with an icon, such as a connected wallet in a list row.
|
|
107
|
+
|
|
108
|
+
### When Not to Use
|
|
109
|
+
|
|
110
|
+
* Use [Identicon](/docs/components/identicon) for an account known only by its address.
|
|
111
|
+
* Use [TokenLogo](/docs/components/token-logo) for the icon of a token or asset.
|
|
112
|
+
* Use [IconTile](/docs/components/icon-tile) for the icon above a centered modal title.
|
|
113
|
+
|
|
114
|
+
### Choose Avatar or Identicon
|
|
115
|
+
|
|
116
|
+
* **Person or Organization (Avatar):** A name, shown as initials.
|
|
117
|
+
* **Address Only (Identicon):** An account known only by its address.
|
|
118
|
+
* **Mixed List (Avatar.Fallback):** A mix of both, with an identicon in the fallback.
|
|
119
|
+
|
|
120
|
+
### Always Include a Fallback
|
|
121
|
+
|
|
122
|
+
* **People and organizations:** Use initials.
|
|
123
|
+
* **Wallets and apps:** Use an icon.
|
|
124
|
+
* **Accounts known by address:** Use an [Identicon](/docs/components/identicon) with `size="fill"`.
|
|
125
|
+
|
|
126
|
+
**Do:** Give every avatar a fallback, such as initials, an icon, or an `Identicon`.
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
/**
|
|
130
|
+
* Do example for "Always Include a Fallback" on the Avatar page.
|
|
131
|
+
* Give every avatar a fallback, such as initials, an icon, or an `Identicon`.
|
|
132
|
+
* @module
|
|
133
|
+
*/
|
|
134
|
+
import { Avatar, Identicon, style } from '@tempoxyz/ds'
|
|
135
|
+
import { Wallet } from '@tempoxyz/ds/icons'
|
|
136
|
+
|
|
137
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
138
|
+
export function Demo() {
|
|
139
|
+
return (
|
|
140
|
+
<div {...styles.row()}>
|
|
141
|
+
<Avatar size="40">
|
|
142
|
+
<Avatar.Fallback>AL</Avatar.Fallback>
|
|
143
|
+
</Avatar>
|
|
144
|
+
<Avatar size="40">
|
|
145
|
+
<Avatar.Fallback>
|
|
146
|
+
<Wallet />
|
|
147
|
+
</Avatar.Fallback>
|
|
148
|
+
</Avatar>
|
|
149
|
+
<Avatar size="40">
|
|
150
|
+
<Avatar.Fallback>
|
|
151
|
+
<Identicon address="0x71C7656EC7ab88b098defB751B7401B5f6d8976F" aria-hidden size="fill" />
|
|
152
|
+
</Avatar.Fallback>
|
|
153
|
+
</Avatar>
|
|
154
|
+
</div>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
namespace styles {
|
|
159
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Don't:** Leave an empty circle.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
/**
|
|
167
|
+
* Don't example for "Always Include a Fallback" on the Avatar page.
|
|
168
|
+
* Don't leave an empty circle.
|
|
169
|
+
* @module
|
|
170
|
+
*/
|
|
171
|
+
import { Avatar, style } from '@tempoxyz/ds'
|
|
172
|
+
|
|
173
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
174
|
+
export function Demo() {
|
|
175
|
+
return (
|
|
176
|
+
<div {...styles.row()}>
|
|
177
|
+
<Avatar size="40" />
|
|
178
|
+
<Avatar size="40" />
|
|
179
|
+
<Avatar size="40" />
|
|
180
|
+
</div>
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
namespace styles {
|
|
185
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Pair the Avatar With a Name
|
|
190
|
+
|
|
191
|
+
Hide the avatar with `aria-hidden` beside a visible name, so screen readers don't read the initials and the name.
|
|
192
|
+
|
|
193
|
+
**Do:** Show the name, and a detail such as an email, beside each avatar.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
/**
|
|
197
|
+
* Do example for "Pair the Avatar With a Name" on the Avatar page.
|
|
198
|
+
* Show the name, and a detail such as an email, beside each avatar.
|
|
199
|
+
* @module
|
|
200
|
+
*/
|
|
201
|
+
import { Avatar, style } from '@tempoxyz/ds'
|
|
202
|
+
|
|
203
|
+
const contacts = [
|
|
204
|
+
['JC', 'Jane Cooper', 'jane@example.com'],
|
|
205
|
+
['AL', 'Ada Lovelace', 'ada@example.com'],
|
|
206
|
+
] as const
|
|
207
|
+
|
|
208
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
209
|
+
export function Demo() {
|
|
210
|
+
return (
|
|
211
|
+
<div {...styles.list()}>
|
|
212
|
+
{contacts.map(([initials, name, email]) => (
|
|
213
|
+
<div key={name} {...styles.row()}>
|
|
214
|
+
<Avatar aria-hidden size="40">
|
|
215
|
+
<Avatar.Fallback>{initials}</Avatar.Fallback>
|
|
216
|
+
</Avatar>
|
|
217
|
+
<div {...styles.text()}>
|
|
218
|
+
<span {...styles.name()}>{name}</span>
|
|
219
|
+
<span {...styles.detail()}>{email}</span>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
))}
|
|
223
|
+
</div>
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
namespace styles {
|
|
228
|
+
export const detail = style({ color: 'content.secondary', typography: 'body.b3' })
|
|
229
|
+
|
|
230
|
+
export const list = style({ display: 'grid', gap: '12', width: '100% !custom' })
|
|
231
|
+
|
|
232
|
+
export const name = style({ color: 'content.primary', typography: 'body.b2Strong' })
|
|
233
|
+
|
|
234
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
235
|
+
|
|
236
|
+
export const text = style({ display: 'flex', flexDirection: 'column', gap: '4' })
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Don't:** Ask people to pick a recipient from initials alone.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
/**
|
|
244
|
+
* Don't example for "Pair the Avatar With a Name" on the Avatar page.
|
|
245
|
+
* Don't ask people to pick a recipient from pictures or initials alone.
|
|
246
|
+
* @module
|
|
247
|
+
*/
|
|
248
|
+
import { Avatar, style } from '@tempoxyz/ds'
|
|
249
|
+
|
|
250
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
251
|
+
export function Demo() {
|
|
252
|
+
return (
|
|
253
|
+
<div {...styles.row()}>
|
|
254
|
+
{['JC', 'AL', 'MR', 'JD'].map((initials) => (
|
|
255
|
+
<Avatar key={initials} size="40">
|
|
256
|
+
<Avatar.Fallback>{initials}</Avatar.Fallback>
|
|
257
|
+
</Avatar>
|
|
258
|
+
))}
|
|
259
|
+
</div>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
namespace styles {
|
|
264
|
+
export const row = style({ alignItems: 'center', display: 'flex', gap: '12' })
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Match Size to the Layout
|
|
269
|
+
|
|
270
|
+
* **Inline and Dense Rows (24):** Inline with text and in dense table rows.
|
|
271
|
+
* **List Rows (32):** List rows, such as recipients in a modal.
|
|
272
|
+
* **Header Lead (40):** The default. The lead of a header.
|
|
273
|
+
|
|
274
|
+
### Use Initials for People and Icons for Wallets
|
|
275
|
+
|
|
276
|
+
* **Person or Contact (Initials):** One or two initials from the name.
|
|
277
|
+
* **Wallet or App (Icon):** One icon from the library, in the text color.
|
|
278
|
+
|
|
279
|
+
In a modal, leave out brand colors, so every avatar keeps the neutral fill.
|
|
280
|
+
|
|
281
|
+
## Content
|
|
282
|
+
|
|
283
|
+
* **Initials:** Use one or two, such as AL for Ada Lovelace. The fallback uppercases them.
|
|
284
|
+
* **Organizations:** Use the first letter of the name, not an unfamiliar abbreviation.
|
|
285
|
+
* **Wallets and apps:** Use an icon instead of letters.
|
|
286
|
+
|
|
287
|
+
## Accessibility
|
|
288
|
+
|
|
289
|
+
Renders a `<span>` that holds the fallback.
|
|
290
|
+
|
|
291
|
+
### Semantics
|
|
292
|
+
|
|
293
|
+
* **Avatar.Fallback (span):** Plain text. Screen readers read the initials as written.
|
|
294
|
+
* **Icon Fallback (aria-hidden):** Icons without an `aria-label` are hidden, so the avatar is silent.
|
|
295
|
+
|
|
296
|
+
### Keyboard
|
|
297
|
+
|
|
298
|
+
An avatar takes no focus. To open a profile, wrap the avatar and name in one link, and let the name label it.
|
|
299
|
+
|
|
300
|
+
### Your Responsibilities
|
|
301
|
+
|
|
302
|
+
* **Hide a Duplicate Avatar (aria-hidden):** If the name is visible beside the avatar, hide the root so screen readers skip the initials.
|
|
303
|
+
* **Name a Standalone Avatar (aria-label):** If no name is visible, set `role="img"` and an `aria-label` with the full name on the root.
|
|
304
|
+
|
|
305
|
+
## Related
|
|
306
|
+
|
|
307
|
+
[Identicon](/docs/components/identicon)
|
|
308
|
+
|
|
309
|
+
Use for accounts known by address.
|
|
310
|
+
|
|
311
|
+
[TokenLogo](/docs/components/token-logo)
|
|
312
|
+
|
|
313
|
+
Use for token icons.
|
|
314
|
+
|
|
315
|
+
[IconTile](/docs/components/icon-tile)
|
|
316
|
+
|
|
317
|
+
Use for the icon above a centered modal title.
|
|
318
|
+
|
|
319
|
+
[ListGroup](/docs/components/list-group)
|
|
320
|
+
|
|
321
|
+
Use for lists of people and accounts.
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Badge
|
|
2
|
+
|
|
3
|
+
Labels a status or category in a compact chip.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Badge.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Badge](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1186-3286), [Icon Badge](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=1191-4539)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A compact chip at least 80px wide, in one of five `variant` fills and two sizes, or a square or round chip that holds one icon. It renders a `<span>` unless you pass `render`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Badge } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export function Demo() {
|
|
21
|
+
return <Badge>Routes</Badge>
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Basic.tsx)
|
|
26
|
+
|
|
27
|
+
### Variant
|
|
28
|
+
|
|
29
|
+
Set `variant` to `soft` (default), `outlined`, `elevated`, `inverse`, or `accent`.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
33
|
+
|
|
34
|
+
export function Demo() {
|
|
35
|
+
return (
|
|
36
|
+
<div {...styles.row()}>
|
|
37
|
+
<Badge>Routes</Badge>
|
|
38
|
+
<Badge variant="outlined">Testnet</Badge>
|
|
39
|
+
<Badge variant="elevated">New</Badge>
|
|
40
|
+
<Badge variant="inverse">Recommended</Badge>
|
|
41
|
+
<Badge variant="accent">Beta</Badge>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
namespace styles {
|
|
47
|
+
export const row = style({
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
backgroundColor: 'container.regular',
|
|
50
|
+
borderRadius: 'xs',
|
|
51
|
+
display: 'flex',
|
|
52
|
+
flexWrap: 'wrap',
|
|
53
|
+
gap: '8',
|
|
54
|
+
padding: '16',
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Variant.tsx)
|
|
60
|
+
|
|
61
|
+
### Size
|
|
62
|
+
|
|
63
|
+
Set `size` to `small` (28px) or `medium` (32px, the default).
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
67
|
+
|
|
68
|
+
export function Demo() {
|
|
69
|
+
return (
|
|
70
|
+
<div {...styles.row()}>
|
|
71
|
+
{(['small', 'medium'] as const).map((size) => (
|
|
72
|
+
<Badge key={size} size={size}>
|
|
73
|
+
{size}
|
|
74
|
+
</Badge>
|
|
75
|
+
))}
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
namespace styles {
|
|
81
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Size.tsx)
|
|
86
|
+
|
|
87
|
+
### Shape
|
|
88
|
+
|
|
89
|
+
Set `shape="icon"` for a badge that holds one icon. A `medium` icon badge is a 32px square, and a `small` one is a 24px circle.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
93
|
+
import { ArrowRight } from '@tempoxyz/ds/icons'
|
|
94
|
+
|
|
95
|
+
export function Demo() {
|
|
96
|
+
return (
|
|
97
|
+
<div {...styles.rows()}>
|
|
98
|
+
{(['medium', 'small'] as const).map((size) => (
|
|
99
|
+
<div key={size} {...styles.row()}>
|
|
100
|
+
{(['soft', 'outlined', 'elevated', 'inverse', 'accent'] as const).map((variant) => (
|
|
101
|
+
<Badge key={variant} shape="icon" size={size} variant={variant}>
|
|
102
|
+
<ArrowRight />
|
|
103
|
+
</Badge>
|
|
104
|
+
))}
|
|
105
|
+
</div>
|
|
106
|
+
))}
|
|
107
|
+
</div>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
namespace styles {
|
|
112
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
|
|
113
|
+
|
|
114
|
+
export const rows = style({ display: 'grid', gap: '12' })
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Shape.tsx)
|
|
119
|
+
|
|
120
|
+
### Render
|
|
121
|
+
|
|
122
|
+
Pass a `button` or link to `render` for an interactive badge with pointer, focus, and press feedback.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
126
|
+
|
|
127
|
+
export function Demo() {
|
|
128
|
+
return (
|
|
129
|
+
<div {...styles.row()}>
|
|
130
|
+
{(['small', 'medium'] as const).map((size) => (
|
|
131
|
+
<Badge key={size} render={<button type="button" />} size={size}>
|
|
132
|
+
Stablecoins
|
|
133
|
+
</Badge>
|
|
134
|
+
))}
|
|
135
|
+
<Badge render={<button type="button" />} variant="accent">
|
|
136
|
+
Accent chip
|
|
137
|
+
</Badge>
|
|
138
|
+
</div>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
namespace styles {
|
|
143
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '8' })
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Badge/Render.tsx)
|
|
148
|
+
|
|
149
|
+
## Anatomy
|
|
150
|
+
|
|
151
|
+
Import the component and assemble its parts.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { Badge } from '@tempoxyz/ds'
|
|
155
|
+
|
|
156
|
+
<Badge />
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Guidelines
|
|
160
|
+
|
|
161
|
+
### When to Use
|
|
162
|
+
|
|
163
|
+
* Label an attribute next to a title or row value, such as Routes, New address, or Testnet.
|
|
164
|
+
* Label the status of a record in words, such as Confirmed, Pending, or Failed.
|
|
165
|
+
* Build compact filters, such as Stablecoins, with `render={<button type="button" />}`.
|
|
166
|
+
|
|
167
|
+
### When Not to Use
|
|
168
|
+
|
|
169
|
+
* Use an [Alert](/docs/components/alert) or [Banner](/docs/components/banner) for a message that needs a sentence.
|
|
170
|
+
* Use a [Button](/docs/components/button) for an action, such as Retry.
|
|
171
|
+
* Use the `status` of a [Table](/docs/components/table) cell to color a status in a table.
|
|
172
|
+
* Use a [ChoiceGroup](/docs/components/choice-group) to switch between two to four views.
|
|
173
|
+
* Use [Kbd](/docs/components/kbd) for keyboard keys.
|
|
174
|
+
|
|
175
|
+
### Choose a Variant by Emphasis
|
|
176
|
+
|
|
177
|
+
* **Soft (soft):** The default. Attributes and categories on any surface.
|
|
178
|
+
* **Outlined (outlined):** Lower emphasis, such as a network beside its name.
|
|
179
|
+
* **Elevated (elevated):** A white fill that stands out on a tinted surface.
|
|
180
|
+
* **Inverse (inverse):** The strongest fill, for one recommended option.
|
|
181
|
+
* **Accent (accent):** Something new or highlighted, such as Beta.
|
|
182
|
+
|
|
183
|
+
### Keep One Variant per Context
|
|
184
|
+
|
|
185
|
+
Use one variant for every badge in a list or column, so only the label differs.
|
|
186
|
+
|
|
187
|
+
**Do:** Keep one variant per list or column, so only the status differs.
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
/**
|
|
191
|
+
* Do example for "Keep One Variant per Context" on the Badge page.
|
|
192
|
+
* Keep one variant per list or column, so only the status differs.
|
|
193
|
+
* @module
|
|
194
|
+
*/
|
|
195
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
196
|
+
|
|
197
|
+
const payments = [
|
|
198
|
+
{ address: '0x8f3c…a21b', status: 'Confirmed', variant: 'outlined' },
|
|
199
|
+
{ address: '0x41d0…9c7e', status: 'Pending', variant: 'outlined' },
|
|
200
|
+
{ address: '0xb27a…04f5', status: 'Failed', variant: 'outlined' },
|
|
201
|
+
] as const
|
|
202
|
+
|
|
203
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
204
|
+
export function Demo() {
|
|
205
|
+
return (
|
|
206
|
+
<div {...styles.list()}>
|
|
207
|
+
{payments.map((payment) => (
|
|
208
|
+
<div {...styles.row()} key={payment.address}>
|
|
209
|
+
<span>{payment.address}</span>
|
|
210
|
+
<Badge size="small" variant={payment.variant}>
|
|
211
|
+
{payment.status}
|
|
212
|
+
</Badge>
|
|
213
|
+
</div>
|
|
214
|
+
))}
|
|
215
|
+
</div>
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
namespace styles {
|
|
220
|
+
export const list = style({
|
|
221
|
+
display: 'flex',
|
|
222
|
+
flexDirection: 'column',
|
|
223
|
+
gap: '12',
|
|
224
|
+
width: '100% !custom',
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
export const row = style({
|
|
228
|
+
alignItems: 'center',
|
|
229
|
+
display: 'flex',
|
|
230
|
+
justifyContent: 'space-between',
|
|
231
|
+
typography: 'mono.m1',
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Don't:** Mix `soft`, `outlined`, and `inverse` badges in one list.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
/**
|
|
240
|
+
* Don't example for "Keep One Variant per Context" on the Badge page.
|
|
241
|
+
* Don't mix `soft`, `outlined`, and `inverse` tags in one list.
|
|
242
|
+
* @module
|
|
243
|
+
*/
|
|
244
|
+
import { Badge, style } from '@tempoxyz/ds'
|
|
245
|
+
|
|
246
|
+
const payments = [
|
|
247
|
+
{ address: '0x8f3c…a21b', status: 'Confirmed', variant: 'soft' },
|
|
248
|
+
{ address: '0x41d0…9c7e', status: 'Pending', variant: 'outlined' },
|
|
249
|
+
{ address: '0xb27a…04f5', status: 'Failed', variant: 'inverse' },
|
|
250
|
+
] as const
|
|
251
|
+
|
|
252
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
253
|
+
export function Demo() {
|
|
254
|
+
return (
|
|
255
|
+
<div {...styles.list()}>
|
|
256
|
+
{payments.map((payment) => (
|
|
257
|
+
<div {...styles.row()} key={payment.address}>
|
|
258
|
+
<span>{payment.address}</span>
|
|
259
|
+
<Badge size="small" variant={payment.variant}>
|
|
260
|
+
{payment.status}
|
|
261
|
+
</Badge>
|
|
262
|
+
</div>
|
|
263
|
+
))}
|
|
264
|
+
</div>
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
namespace styles {
|
|
269
|
+
export const list = style({
|
|
270
|
+
display: 'flex',
|
|
271
|
+
flexDirection: 'column',
|
|
272
|
+
gap: '12',
|
|
273
|
+
width: '100% !custom',
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
export const row = style({
|
|
277
|
+
alignItems: 'center',
|
|
278
|
+
display: 'flex',
|
|
279
|
+
justifyContent: 'space-between',
|
|
280
|
+
typography: 'mono.m1',
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Make a Badge Interactive Only for an Action
|
|
286
|
+
|
|
287
|
+
* **Display (span):** A status or attribute. Keep the default `span`.
|
|
288
|
+
* **Action (render):** Pass a button or link only if the badge does something.
|
|
289
|
+
|
|
290
|
+
## Content
|
|
291
|
+
|
|
292
|
+
* Keep the text to one or two words in sentence case, such as Expiring soon.
|
|
293
|
+
* Describe a state, not an action. Write Failed, not Retry.
|
|
294
|
+
* Use one word for one state across a product, such as Confirmed everywhere, not Confirmed in one place and Complete in another.
|
|
295
|
+
* Tags don't wrap, so a long label overflows its cell.
|
|
296
|
+
|
|
297
|
+
## Accessibility
|
|
298
|
+
|
|
299
|
+
A badge renders a `<span>` with no role, so screen readers read its text inline.
|
|
300
|
+
|
|
301
|
+
### Semantics
|
|
302
|
+
|
|
303
|
+
* **Root (span):** Screen readers read its text in place, as part of the surrounding content.
|
|
304
|
+
* **Render (render):** Takes the semantics of the button or link you pass, with a focus outline and press scale.
|
|
305
|
+
* **Variant (variant):** Changes only the fill, sets no state or role, and isn't announced. The text must name it.
|
|
306
|
+
|
|
307
|
+
### Keyboard
|
|
308
|
+
|
|
309
|
+
A static badge takes no focus. A badge rendered as a button or link is a native control:
|
|
310
|
+
|
|
311
|
+
* **Move Focus to the Badge (Tab):** Moves focus to the badge.
|
|
312
|
+
* **Activate or Follow (Enter):** Activates a button badge or follows a link badge.
|
|
313
|
+
* **Activate a Button Badge (Space):** Activates a button badge.
|
|
314
|
+
|
|
315
|
+
### Your Responsibilities
|
|
316
|
+
|
|
317
|
+
* **Name Meaningful Icons (aria-label):** If an icon badge carries meaning, set `role="img"` and an `aria-label` that names it.
|
|
318
|
+
* **Use Native Controls (button or a):** Pass a native button or link to `render`, so keyboards reach it. Don't add `onClick` to a static span.
|
|
319
|
+
* **Add Context (aria-describedby):** If a badge sits apart from its subject, add context, so "Pending" isn't read alone.
|
|
320
|
+
* **Report Toggle State (aria-pressed):** A filter badge must report whether it is pressed, so its state is announced.
|
|
321
|
+
* **Size Interactive Badges (24px):** Both sizes clear the 24px minimum target. Use medium where people tap.
|
|
322
|
+
|
|
323
|
+
## Related
|
|
324
|
+
|
|
325
|
+
[Table](/docs/components/table)
|
|
326
|
+
|
|
327
|
+
Use for status columns.
|
|
328
|
+
|
|
329
|
+
[Alert](/docs/components/alert)
|
|
330
|
+
|
|
331
|
+
Use for messages about a section.
|
|
332
|
+
|
|
333
|
+
[ChoiceGroup](/docs/components/choice-group)
|
|
334
|
+
|
|
335
|
+
Use for switching views.
|
|
336
|
+
|
|
337
|
+
[Feedback and Status](/docs/patterns/feedback-and-status)
|
|
338
|
+
|
|
339
|
+
Covers status conventions.
|