@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,709 @@
|
|
|
1
|
+
# Blockchain Values
|
|
2
|
+
|
|
3
|
+
Formats addresses, hashes, amounts, and timestamps so people can verify them.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
An address has 42 characters, a transaction hash has 66, and a token amount can carry 6 decimal places. Nothing reverses a misread decimal or a mistyped address.
|
|
8
|
+
|
|
9
|
+
Format each value the same way in every view. Four principles apply to every value:
|
|
10
|
+
|
|
11
|
+
* **Exact:** Round only for display. Never round an amount the reader is about to send.
|
|
12
|
+
* **Labelled:** Pair every number with its unit, and every known address with a name.
|
|
13
|
+
* **Comparable:** Keep both ends of a long value visible for comparison with another source.
|
|
14
|
+
* **Copyable:** Let the reader copy the full value, not only the visible part.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { Amount, Badge, Button, Hex, Identicon, ListGroup, style, Surface, TokenLogo, Tooltip } from '@tempoxyz/ds'
|
|
18
|
+
import { ExternalLink } from '@tempoxyz/ds/icons'
|
|
19
|
+
|
|
20
|
+
export const fill = true
|
|
21
|
+
const hash = '0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060'
|
|
22
|
+
const from = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
|
|
23
|
+
const to = '0x71C7656EC7ab88b098defB751B7401B5f6d8976F'
|
|
24
|
+
|
|
25
|
+
function Explorer(props: { label: string }) {
|
|
26
|
+
return (
|
|
27
|
+
<Tooltip.Root>
|
|
28
|
+
<Tooltip.Trigger
|
|
29
|
+
render={
|
|
30
|
+
<Button.Link
|
|
31
|
+
aria-label={props.label}
|
|
32
|
+
href="https://explore.tempo.xyz"
|
|
33
|
+
rel="noreferrer"
|
|
34
|
+
shape="icon"
|
|
35
|
+
size="small"
|
|
36
|
+
target="_blank"
|
|
37
|
+
variant="tertiary"
|
|
38
|
+
/>
|
|
39
|
+
}
|
|
40
|
+
>
|
|
41
|
+
<ExternalLink />
|
|
42
|
+
</Tooltip.Trigger>
|
|
43
|
+
<Tooltip.Popup>{props.label}</Tooltip.Popup>
|
|
44
|
+
</Tooltip.Root>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function Demo() {
|
|
49
|
+
return (
|
|
50
|
+
<Tooltip.Provider>
|
|
51
|
+
<Surface render={<section aria-labelledby="transaction-title" />} {...styles.card()}>
|
|
52
|
+
<Surface.Header>
|
|
53
|
+
<Surface.Title id="transaction-title">Transaction</Surface.Title>
|
|
54
|
+
<Badge>Confirmed</Badge>
|
|
55
|
+
</Surface.Header>
|
|
56
|
+
<ListGroup.Root>
|
|
57
|
+
<ListGroup.Row>
|
|
58
|
+
<ListGroup.Label>Hash</ListGroup.Label>
|
|
59
|
+
<span {...styles.value()}>
|
|
60
|
+
<Hex copy value={hash} />
|
|
61
|
+
<Explorer label="View transaction on explorer" />
|
|
62
|
+
</span>
|
|
63
|
+
</ListGroup.Row>
|
|
64
|
+
<ListGroup.Row>
|
|
65
|
+
<ListGroup.Label>Block</ListGroup.Label>
|
|
66
|
+
<span {...styles.value()}>
|
|
67
|
+
<span {...styles.number()}>18,204,551</span>
|
|
68
|
+
<Explorer label="View block 18204551 on explorer" />
|
|
69
|
+
</span>
|
|
70
|
+
</ListGroup.Row>
|
|
71
|
+
<ListGroup.Row>
|
|
72
|
+
<ListGroup.Label>Time</ListGroup.Label>
|
|
73
|
+
<span {...styles.value()}>
|
|
74
|
+
<time dateTime="2026-10-20T09:41:07Z">Oct 20, 2026, 09:41:07 UTC</time>
|
|
75
|
+
</span>
|
|
76
|
+
</ListGroup.Row>
|
|
77
|
+
<ListGroup.Row>
|
|
78
|
+
<ListGroup.Label>From</ListGroup.Label>
|
|
79
|
+
<span {...styles.value()}>
|
|
80
|
+
<Identicon aria-hidden address={from} size="16" />
|
|
81
|
+
<Hex copy value={from} />
|
|
82
|
+
</span>
|
|
83
|
+
</ListGroup.Row>
|
|
84
|
+
<ListGroup.Row>
|
|
85
|
+
<ListGroup.Label>To</ListGroup.Label>
|
|
86
|
+
<span {...styles.value()}>
|
|
87
|
+
<Identicon aria-hidden address={to} size="16" />
|
|
88
|
+
<span {...styles.name()}>Tempo Labs</span>
|
|
89
|
+
<Hex copy value={to} />
|
|
90
|
+
</span>
|
|
91
|
+
</ListGroup.Row>
|
|
92
|
+
<ListGroup.Row>
|
|
93
|
+
<ListGroup.Label>Amount</ListGroup.Label>
|
|
94
|
+
<span {...styles.value()}>
|
|
95
|
+
<TokenLogo address="0x20c0000000000000000000000000000000000000" size="small" />
|
|
96
|
+
<Amount symbol="PathUSD" value="1250.504211" />
|
|
97
|
+
</span>
|
|
98
|
+
</ListGroup.Row>
|
|
99
|
+
<ListGroup.Row>
|
|
100
|
+
<ListGroup.Label>Network fee</ListGroup.Label>
|
|
101
|
+
<Amount currency="USD" precise value="0.00003" />
|
|
102
|
+
</ListGroup.Row>
|
|
103
|
+
</ListGroup.Root>
|
|
104
|
+
</Surface>
|
|
105
|
+
</Tooltip.Provider>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
namespace styles {
|
|
110
|
+
export const card = style({
|
|
111
|
+
boxSizing: 'border-box',
|
|
112
|
+
marginInline: 'auto !custom',
|
|
113
|
+
maxWidth: '576',
|
|
114
|
+
width: '100% !custom',
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
export const name = style({ flexShrink: '0 !custom', typography: 'body.b2Strong' })
|
|
118
|
+
|
|
119
|
+
export const number = style({ fontVariantNumeric: 'tabular-nums !custom' })
|
|
120
|
+
|
|
121
|
+
export const value = style({
|
|
122
|
+
alignItems: 'center',
|
|
123
|
+
columnGap: '8',
|
|
124
|
+
display: 'flex',
|
|
125
|
+
justifyContent: 'flex-end',
|
|
126
|
+
minWidth: '0',
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Patterns/BlockchainTransaction.tsx)
|
|
132
|
+
|
|
133
|
+
## Addresses and Hashes
|
|
134
|
+
|
|
135
|
+
Use [Hex](/docs/components/hex) for addresses and transaction hashes. Add `copy` wherever the reader may need the full value.
|
|
136
|
+
|
|
137
|
+
### Truncate in the Middle
|
|
138
|
+
|
|
139
|
+
[Hex](/docs/components/hex) keeps the prefix and the checksum ending, and fits the value to its container. For plain strings, such as a [Toast](/docs/components/toast) title, `formatHex` keeps four characters on each side of an ellipsis: 0xd8dA…6045.
|
|
140
|
+
|
|
141
|
+
**Do:** Truncate addresses in the middle with [Hex](/docs/components/hex).
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
/**
|
|
145
|
+
* Do example for "Truncate in the Middle" on the Blockchain Values page.
|
|
146
|
+
* Truncate addresses in the middle with Hex.
|
|
147
|
+
* @module
|
|
148
|
+
*/
|
|
149
|
+
import { Hex, style } from '@tempoxyz/ds'
|
|
150
|
+
|
|
151
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
152
|
+
export function Demo() {
|
|
153
|
+
return (
|
|
154
|
+
<div {...styles.frame()}>
|
|
155
|
+
<Hex copy value="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" />
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
namespace styles {
|
|
161
|
+
export const frame = style({ display: 'flex', width: '12rem !custom' })
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Don't:** Cut off the end of an address with a CSS ellipsis.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
/**
|
|
169
|
+
* Don't example for "Truncate in the Middle" on the Blockchain Values page.
|
|
170
|
+
* Don't cut off the end of an address with a CSS ellipsis.
|
|
171
|
+
* @module
|
|
172
|
+
*/
|
|
173
|
+
import { style } from '@tempoxyz/ds'
|
|
174
|
+
|
|
175
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
176
|
+
export function Demo() {
|
|
177
|
+
return <span {...styles.value()}>0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045</span>
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
namespace styles {
|
|
181
|
+
export const value = style({
|
|
182
|
+
display: 'block',
|
|
183
|
+
overflow: 'hidden',
|
|
184
|
+
textOverflow: 'ellipsis',
|
|
185
|
+
typography: 'mono.m1',
|
|
186
|
+
whiteSpace: 'nowrap',
|
|
187
|
+
width: '12rem !custom',
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Show the Full Value Where You Verify
|
|
193
|
+
|
|
194
|
+
Attackers create addresses that match the first and last characters of a known one. Where the reader chooses or confirms a recipient, show the full address, as the [review and receive steps](/docs/patterns/payments#review-before-confirming) of a payment do.
|
|
195
|
+
|
|
196
|
+
* **Short forms:** If only a short form fits but people compare it, keep more characters with the `min` option of `formatHex`, such as 0xd8dA6B…A96045.
|
|
197
|
+
* **Activity lists:** A short value with a contact name is enough. The reader opens the record to verify it.
|
|
198
|
+
|
|
199
|
+
### Pair Addresses With Names
|
|
200
|
+
|
|
201
|
+
Show the known contact or account name beside the address, with an [Identicon](/docs/components/identicon) before both. The [Identicon](/docs/components/identicon) is a cue, never the identifier.
|
|
202
|
+
|
|
203
|
+
**Do:** Pair the name, identicon, and truncated address with a copy button.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<Inline gap="12">
|
|
207
|
+
<Identicon aria-hidden address="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" size="32" />
|
|
208
|
+
<Stack gap="0">
|
|
209
|
+
<span>Alice</span>
|
|
210
|
+
<Hex copy value="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" />
|
|
211
|
+
</Stack>
|
|
212
|
+
</Inline>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Don't:** Let an identicon stand in for the address or the name.
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
<Identicon aria-hidden address="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" size="32" />
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Keep the letter case of an address as received, since mixed case carries its checksum. Compare addresses without regard to case. [Identicon](/docs/components/identicon) renders the same colors for any letter case.
|
|
222
|
+
|
|
223
|
+
## Copy Values
|
|
224
|
+
|
|
225
|
+
* **Name the Button (aria-label):** The default name is Copy and the value. If that reads poorly, compose `Hex.Copy` with a label such as Copy address.
|
|
226
|
+
* **Confirm Once (2 seconds):** The button shows Copied and announces it politely. Do not add a [Toast](/docs/components/toast).
|
|
227
|
+
* **Your Own Layouts (CopyButton):** Use [CopyButton](/docs/components/copy-button) beside values you lay out yourself, named by what it copies.
|
|
228
|
+
|
|
229
|
+
## Link to the Explorer
|
|
230
|
+
|
|
231
|
+
Link transaction hashes, block numbers, and addresses to their page on [explore.tempo.xyz](https://explore.tempo.xyz). In a receipt, use a text link labelled View on explorer.
|
|
232
|
+
|
|
233
|
+
* **Icon Links (shape=icon):** Name an icon link by destination, and repeat the name in a [Tooltip](/docs/components/tooltip).
|
|
234
|
+
* **Separate Controls:** Keep copy and link as separate controls. One text never copies on one click and navigates on another.
|
|
235
|
+
|
|
236
|
+
## Amounts and Precision
|
|
237
|
+
|
|
238
|
+
Always pass a unit: `currency` with an ISO 4217 code for money, or `symbol` for a token.
|
|
239
|
+
|
|
240
|
+
Pass amounts as decimal strings, such as `"1250.50"`, so floating-point math never changes the value. TIP-20 tokens use 6 decimal places, so convert base units first (12500000 to 12.5).
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
import { Amount, style } from '@tempoxyz/ds'
|
|
244
|
+
|
|
245
|
+
export const fill = true
|
|
246
|
+
export function Demo() {
|
|
247
|
+
return (
|
|
248
|
+
<div {...styles.stack()}>
|
|
249
|
+
<Amount currency="USD" size="lg" value={1234.5} />
|
|
250
|
+
<Amount currency="EUR" value={1234.5} />
|
|
251
|
+
<Amount size="lg" symbol="PathUSD" value={1234.5} />
|
|
252
|
+
</div>
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
namespace styles {
|
|
257
|
+
export const stack = style({ display: 'grid', gap: '12', maxWidth: '24rem !custom' })
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Amount/Currency.tsx)
|
|
262
|
+
|
|
263
|
+
### Decimals
|
|
264
|
+
|
|
265
|
+
Pick the precision by context. Show as many decimals as the value needs to stay exact.
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { Amount, Surface, Table } from '@tempoxyz/ds'
|
|
269
|
+
|
|
270
|
+
export const fill = true
|
|
271
|
+
export function Demo() {
|
|
272
|
+
return (
|
|
273
|
+
<Surface size="medium">
|
|
274
|
+
<Table.Root>
|
|
275
|
+
<Table.Caption>
|
|
276
|
+
One balance of 1250.504211 PathUSD and a 0.00003 fee, by context
|
|
277
|
+
</Table.Caption>
|
|
278
|
+
<Table.Head>
|
|
279
|
+
<Table.Row>
|
|
280
|
+
<Table.HeaderCell>Context</Table.HeaderCell>
|
|
281
|
+
<Table.HeaderCell>Props</Table.HeaderCell>
|
|
282
|
+
<Table.HeaderCell justify="end">Shows</Table.HeaderCell>
|
|
283
|
+
</Table.Row>
|
|
284
|
+
</Table.Head>
|
|
285
|
+
<Table.Body>
|
|
286
|
+
<Table.Row>
|
|
287
|
+
<Table.Cell>Balance in a list</Table.Cell>
|
|
288
|
+
<Table.Cell mono>currency="USD"</Table.Cell>
|
|
289
|
+
<Table.Cell numeric>
|
|
290
|
+
<Amount align="right" currency="USD" value="1250.504211" />
|
|
291
|
+
</Table.Cell>
|
|
292
|
+
</Table.Row>
|
|
293
|
+
<Table.Row>
|
|
294
|
+
<Table.Cell>Receipt or detail</Table.Cell>
|
|
295
|
+
<Table.Cell mono>symbol="PathUSD"</Table.Cell>
|
|
296
|
+
<Table.Cell numeric>
|
|
297
|
+
<Amount align="right" symbol="PathUSD" value="1250.504211" />
|
|
298
|
+
</Table.Cell>
|
|
299
|
+
</Table.Row>
|
|
300
|
+
<Table.Row>
|
|
301
|
+
<Table.Cell>Compact token amount</Table.Cell>
|
|
302
|
+
<Table.Cell mono>maxDecimals={'{2}'}</Table.Cell>
|
|
303
|
+
<Table.Cell numeric>
|
|
304
|
+
<Amount align="right" maxDecimals={2} symbol="PathUSD" value="1250.504211" />
|
|
305
|
+
</Table.Cell>
|
|
306
|
+
</Table.Row>
|
|
307
|
+
<Table.Row>
|
|
308
|
+
<Table.Cell>Fee in dollars</Table.Cell>
|
|
309
|
+
<Table.Cell mono>currency="USD"</Table.Cell>
|
|
310
|
+
<Table.Cell numeric>
|
|
311
|
+
<Amount align="right" currency="USD" value="0.00003" />
|
|
312
|
+
</Table.Cell>
|
|
313
|
+
</Table.Row>
|
|
314
|
+
<Table.Row>
|
|
315
|
+
<Table.Cell>Fee on a review step</Table.Cell>
|
|
316
|
+
<Table.Cell mono>currency="USD" precise</Table.Cell>
|
|
317
|
+
<Table.Cell numeric>
|
|
318
|
+
<Amount align="right" currency="USD" precise value="0.00003" />
|
|
319
|
+
</Table.Cell>
|
|
320
|
+
</Table.Row>
|
|
321
|
+
</Table.Body>
|
|
322
|
+
</Table.Root>
|
|
323
|
+
</Surface>
|
|
324
|
+
)
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Patterns/BlockchainPrecision.tsx)
|
|
329
|
+
|
|
330
|
+
* **Lists and Balances (maxDecimals):** Round fiat and stablecoin amounts to two decimals. Cap other token amounts.
|
|
331
|
+
* **Review and Receipts (Full):** Show the full value where the reader confirms it. A string keeps every digit, even trailing zeros.
|
|
332
|
+
* **Spendable Balances:** Never round a spendable balance up. Amounts round to the nearest digit, so truncate the string first.
|
|
333
|
+
|
|
334
|
+
**Do:** Keep a sub-cent amount, such as a fee, exact with `precise`.
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
<Amount currency="USD" precise size="md" value="0.00003" />
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Don't:** Hide a sub-cent amount behind a `<$0.01` bound.
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
<Amount currency="USD" size="md" value="0.00003" />
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Signs
|
|
347
|
+
|
|
348
|
+
In lists of moving amounts, such as activity, mark direction with `sign`: "+" for money in, the minus sign "−" for money out. Pair the sign with text, such as "Received" or "Sent".
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { Amount, style } from '@tempoxyz/ds'
|
|
352
|
+
|
|
353
|
+
export const fill = true
|
|
354
|
+
export function Demo() {
|
|
355
|
+
return (
|
|
356
|
+
<div {...styles.stack()}>
|
|
357
|
+
<Amount align="center" sign="+" size="md" symbol="PathUSD" value="1250.50" />
|
|
358
|
+
<Amount align="right" currency="USD" sign="−" size="md" value={1234.5} />
|
|
359
|
+
</div>
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
namespace styles {
|
|
364
|
+
export const stack = style({ display: 'grid', gap: '12', maxWidth: '24rem !custom' })
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Amount/Sign.tsx)
|
|
369
|
+
|
|
370
|
+
[Payments](/docs/patterns/payments#enter-the-amount) covers entering amounts with [AmountInput](/docs/components/amount-input).
|
|
371
|
+
|
|
372
|
+
## Tokens
|
|
373
|
+
|
|
374
|
+
* **Icon Beside Symbol (alt):** Beside the symbol, the empty default fits. If the icon stands alone, pass the token name.
|
|
375
|
+
* **Prefer Address (address):** Prefer it over a symbol. A symbol lookup adds a request, and symbols are not unique.
|
|
376
|
+
* **Contract in Details:** Show the contract address in token details to separate tokens with similar names.
|
|
377
|
+
* **Shared Lookups (TokenLogo.Provider):** Wrap lists in it, so tokens with the same symbol share one lookup.
|
|
378
|
+
|
|
379
|
+
**Do:** Show the token's symbol as text beside its icon and amount.
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
/**
|
|
383
|
+
* Do example for "Signs" on the Blockchain Values page.
|
|
384
|
+
* Show the token's symbol as text beside its icon and amount.
|
|
385
|
+
* @module
|
|
386
|
+
*/
|
|
387
|
+
import { Amount, style, TokenLogo } 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
|
+
<TokenLogo address="0x20c0000000000000000000000000000000000000" />
|
|
394
|
+
<span {...styles.name()}>PathUSD</span>
|
|
395
|
+
<Amount symbol="PathUSD" value="1240.50" />
|
|
396
|
+
</div>
|
|
397
|
+
)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
namespace styles {
|
|
401
|
+
export const name = style({ flex: '1 !custom', typography: 'body.b2Strong' })
|
|
402
|
+
|
|
403
|
+
export const row = style({
|
|
404
|
+
alignItems: 'center',
|
|
405
|
+
columnGap: '12',
|
|
406
|
+
display: 'flex',
|
|
407
|
+
width: '16rem !custom',
|
|
408
|
+
})
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Don't:** Rely on the icon alone to identify the token.
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
/**
|
|
416
|
+
* Don't example for "Signs" on the Blockchain Values page.
|
|
417
|
+
* Don't rely on the icon alone to identify the token.
|
|
418
|
+
* @module
|
|
419
|
+
*/
|
|
420
|
+
import { style, TokenLogo } from '@tempoxyz/ds'
|
|
421
|
+
|
|
422
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
423
|
+
export function Demo() {
|
|
424
|
+
return (
|
|
425
|
+
<div {...styles.row()}>
|
|
426
|
+
<TokenLogo address="0x20c0000000000000000000000000000000000000" />
|
|
427
|
+
<span {...styles.value()}>1,240.50</span>
|
|
428
|
+
</div>
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
namespace styles {
|
|
433
|
+
export const row = style({
|
|
434
|
+
alignItems: 'center',
|
|
435
|
+
columnGap: '12',
|
|
436
|
+
display: 'flex',
|
|
437
|
+
justifyContent: 'space-between',
|
|
438
|
+
width: '16rem !custom',
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
export const value = style({ typography: 'body.b2Strong' })
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Block Numbers
|
|
446
|
+
|
|
447
|
+
* **On screen:** Group digits with the locale separator, such as 18,204,551, in tabular figures.
|
|
448
|
+
* **In copies:** Use the raw digits, such as 18204551, in copied values, URLs, and API calls.
|
|
449
|
+
* **Label:** Label the value Block in details, not with a `#` prefix.
|
|
450
|
+
|
|
451
|
+
## Timestamps
|
|
452
|
+
|
|
453
|
+
* **Markup:** Render a `time` element with a machine-readable `dateTime`, such as 2026-10-20T09:41:07Z, so assistive technology and translation tools read the exact time.
|
|
454
|
+
* **Lists:** Show relative times for the last day, such as 5 min ago, then dates. Refresh them on a timer without announcing each change.
|
|
455
|
+
* **Details:** In receipts and details, show the absolute time with seconds and a time zone, such as Oct 20, 2026, 09:41:07 UTC.
|
|
456
|
+
* **Durations:** Switch units at one second, such as 633 ms and then 1.2 s.
|
|
457
|
+
|
|
458
|
+
## Hidden Amounts
|
|
459
|
+
|
|
460
|
+
A privacy toggle hides balances from people nearby.
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
import { Amount, Button, style, Surface, TokenLogo } from '@tempoxyz/ds'
|
|
464
|
+
import { Eye, EyeOff } from '@tempoxyz/ds/icons'
|
|
465
|
+
import { useState } from 'react'
|
|
466
|
+
|
|
467
|
+
export const fill = true
|
|
468
|
+
const balances = [
|
|
469
|
+
['PathUSD', '0x20c0000000000000000000000000000000000000', '1240.50'],
|
|
470
|
+
['USDC.e', '0x20c000000000000000000000b9537d11c60e8b50', '845.00'],
|
|
471
|
+
['USDT0', '0x20c00000000000000000000014f22ca97301eb73', '12.25'],
|
|
472
|
+
] as const
|
|
473
|
+
|
|
474
|
+
// One fixed mask for every amount, so hidden values reveal neither their size nor their digits.
|
|
475
|
+
function Hidden() {
|
|
476
|
+
return (
|
|
477
|
+
<span>
|
|
478
|
+
<span aria-hidden="true">••••••</span>
|
|
479
|
+
<span {...styles.hidden()}>Hidden</span>
|
|
480
|
+
</span>
|
|
481
|
+
)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export function Demo() {
|
|
485
|
+
const [hidden, setHidden] = useState(false)
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<Surface render={<section aria-labelledby="balance-title" />} {...styles.card()}>
|
|
489
|
+
<Surface.Header>
|
|
490
|
+
<Surface.Title id="balance-title">Balance</Surface.Title>
|
|
491
|
+
<Button
|
|
492
|
+
aria-label="Hide amounts"
|
|
493
|
+
aria-pressed={hidden}
|
|
494
|
+
onClick={() => setHidden(!hidden)}
|
|
495
|
+
shape="icon"
|
|
496
|
+
size="small"
|
|
497
|
+
variant="tertiary"
|
|
498
|
+
>
|
|
499
|
+
{hidden ? <Eye /> : <EyeOff />}
|
|
500
|
+
</Button>
|
|
501
|
+
</Surface.Header>
|
|
502
|
+
<div {...styles.total()}>
|
|
503
|
+
{hidden ? <Hidden /> : <Amount currency="USD" size="xl" value="2097.75" />}
|
|
504
|
+
</div>
|
|
505
|
+
<ul {...styles.list()}>
|
|
506
|
+
{balances.map(([symbol, address, value]) => (
|
|
507
|
+
<li key={symbol} {...styles.item()}>
|
|
508
|
+
<TokenLogo address={address} />
|
|
509
|
+
<span {...styles.symbol()}>{symbol}</span>
|
|
510
|
+
{hidden ? <Hidden /> : <Amount symbol={symbol} value={value} />}
|
|
511
|
+
</li>
|
|
512
|
+
))}
|
|
513
|
+
</ul>
|
|
514
|
+
</Surface>
|
|
515
|
+
)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
namespace styles {
|
|
519
|
+
export const card = style({
|
|
520
|
+
boxSizing: 'border-box',
|
|
521
|
+
marginInline: 'auto !custom',
|
|
522
|
+
maxWidth: '360',
|
|
523
|
+
width: '100% !custom',
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
export const hidden = style({
|
|
527
|
+
clipPath: 'inset(50%) !custom',
|
|
528
|
+
height: '1px !custom',
|
|
529
|
+
overflow: 'hidden',
|
|
530
|
+
position: 'absolute',
|
|
531
|
+
whiteSpace: 'nowrap',
|
|
532
|
+
width: '1px !custom',
|
|
533
|
+
})
|
|
534
|
+
|
|
535
|
+
export const item = style({
|
|
536
|
+
alignItems: 'center',
|
|
537
|
+
columnGap: '12',
|
|
538
|
+
display: 'flex',
|
|
539
|
+
minHeight: '40',
|
|
540
|
+
typography: 'body.b2Strong',
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
export const list = style({ listStyle: 'none !custom', margin: '0', padding: '0' })
|
|
544
|
+
|
|
545
|
+
export const symbol = style({ flex: '1 !custom' })
|
|
546
|
+
|
|
547
|
+
export const total = style({
|
|
548
|
+
fontVariantNumeric: 'tabular-nums !custom',
|
|
549
|
+
marginBlockEnd: '16',
|
|
550
|
+
minHeight: '48',
|
|
551
|
+
typography: 'display.d2',
|
|
552
|
+
})
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Patterns/BlockchainHiddenAmounts.tsx)
|
|
557
|
+
|
|
558
|
+
* **Toggle:** Use an icon [Button](/docs/components/button) with the eye icons, named Hide amounts, that reports its pressed state.
|
|
559
|
+
* **Everywhere:** Hide every amount, including totals, activity, and charts.
|
|
560
|
+
* **Out of the page:** Render the mask in place of the value, not a blur, so the value is absent from the page. Expose the word Hidden to screen readers instead of the dots.
|
|
561
|
+
* **Remembered:** Keep the choice on the device, so amounts stay hidden on the next launch.
|
|
562
|
+
|
|
563
|
+
**Do:** Use the same fixed mask for every hidden amount.
|
|
564
|
+
|
|
565
|
+
```tsx
|
|
566
|
+
/** Do example for "Signs" on the Blockchain Values page: use the same fixed mask for every hidden amount. @module */
|
|
567
|
+
import { style } from '@tempoxyz/ds'
|
|
568
|
+
|
|
569
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
570
|
+
export function Demo() {
|
|
571
|
+
return (
|
|
572
|
+
<div {...styles.list()}>
|
|
573
|
+
{['PathUSD', 'USDC.e', 'USDT0'].map((symbol) => (
|
|
574
|
+
<div key={symbol} {...styles.row()}>
|
|
575
|
+
<span>{symbol}</span>
|
|
576
|
+
<span>••••••</span>
|
|
577
|
+
</div>
|
|
578
|
+
))}
|
|
579
|
+
</div>
|
|
580
|
+
)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
namespace styles {
|
|
584
|
+
export const list = style({
|
|
585
|
+
display: 'flex',
|
|
586
|
+
flexDirection: 'column',
|
|
587
|
+
rowGap: '8',
|
|
588
|
+
width: '14rem !custom',
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
export const row = style({
|
|
592
|
+
display: 'flex',
|
|
593
|
+
justifyContent: 'space-between',
|
|
594
|
+
typography: 'body.b2Strong',
|
|
595
|
+
})
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Don't:** Shape the mask like the number, which reveals its size.
|
|
600
|
+
|
|
601
|
+
```tsx
|
|
602
|
+
/**
|
|
603
|
+
* Don't example for "Signs" on the Blockchain Values page.
|
|
604
|
+
* Don't shape the mask like the number, which reveals its size.
|
|
605
|
+
* @module
|
|
606
|
+
*/
|
|
607
|
+
import { style } from '@tempoxyz/ds'
|
|
608
|
+
|
|
609
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
610
|
+
export function Demo() {
|
|
611
|
+
return (
|
|
612
|
+
<div {...styles.list()}>
|
|
613
|
+
{[
|
|
614
|
+
['PathUSD', '•,•••.••'],
|
|
615
|
+
['USDC.e', '•••.••'],
|
|
616
|
+
['USDT0', '••.••'],
|
|
617
|
+
].map(([symbol, mask]) => (
|
|
618
|
+
<div key={symbol} {...styles.row()}>
|
|
619
|
+
<span>{symbol}</span>
|
|
620
|
+
<span>{mask}</span>
|
|
621
|
+
</div>
|
|
622
|
+
))}
|
|
623
|
+
</div>
|
|
624
|
+
)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
namespace styles {
|
|
628
|
+
export const list = style({
|
|
629
|
+
display: 'flex',
|
|
630
|
+
flexDirection: 'column',
|
|
631
|
+
rowGap: '8',
|
|
632
|
+
width: '14rem !custom',
|
|
633
|
+
})
|
|
634
|
+
|
|
635
|
+
export const row = style({
|
|
636
|
+
display: 'flex',
|
|
637
|
+
justifyContent: 'space-between',
|
|
638
|
+
typography: 'body.b2Strong',
|
|
639
|
+
})
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
## Secrets
|
|
644
|
+
|
|
645
|
+
Recovery phrases, private keys, API keys, and access keys grant control of funds. Show them with [SecretValue](/docs/components/secret-value), which starts masked and copies without revealing. Never show a secret with [Hex](/docs/components/hex).
|
|
646
|
+
|
|
647
|
+
**Do:** Start masked, and copy without revealing.
|
|
648
|
+
|
|
649
|
+
```tsx
|
|
650
|
+
<SecretValue label="Access key" value="tempo-access-key-example-0000" />
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Don't:** Reveal a secret by default.
|
|
654
|
+
|
|
655
|
+
```tsx
|
|
656
|
+
<SecretValue defaultRevealed label="Access key" value="tempo-access-key-example-0000" />
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
## States
|
|
660
|
+
|
|
661
|
+
* **Loading (Skeleton):** Keeps the row height while a value loads. A token shows a gray circle until its icon arrives.
|
|
662
|
+
* **Unknown TokenLogo:** An unknown token keeps the gray circle. Show its symbol and contract address as text.
|
|
663
|
+
* **Pending Transaction (Badge):** Show the hash at once, tagged Pending. Add the block and time when it confirms.
|
|
664
|
+
* **Copy Failed:** The copy button falls back to an older browser method. If that fails, keep the value selectable.
|
|
665
|
+
|
|
666
|
+
## Content
|
|
667
|
+
|
|
668
|
+
* **Plain words:** Write "address", not "public key", and "network fee", not "gas".
|
|
669
|
+
* **Exact symbols:** Keep the casing of token symbols, such as "pathUSD" and "USDC".
|
|
670
|
+
|
|
671
|
+
## Accessibility
|
|
672
|
+
|
|
673
|
+
* **Hex (Full value):** Screen readers read the full value, even when it is truncated. Pair it with a name.
|
|
674
|
+
* **Identicon (role=img):** Named by its address. If the address or name is beside it, set `aria-hidden` to avoid a double read.
|
|
675
|
+
* **Amount (strikethrough):** Screen readers do not announce it. State in text when an amount is superseded.
|
|
676
|
+
|
|
677
|
+
## Related
|
|
678
|
+
|
|
679
|
+
[Hex](/docs/components/hex)
|
|
680
|
+
|
|
681
|
+
Use for addresses and hashes.
|
|
682
|
+
|
|
683
|
+
[CopyButton](/docs/components/copy-button)
|
|
684
|
+
|
|
685
|
+
Use for copying values.
|
|
686
|
+
|
|
687
|
+
[Amount](/docs/components/amount)
|
|
688
|
+
|
|
689
|
+
Use for formatting amounts.
|
|
690
|
+
|
|
691
|
+
[TokenLogo](/docs/components/token-logo)
|
|
692
|
+
|
|
693
|
+
Use for token icons.
|
|
694
|
+
|
|
695
|
+
[Identicon](/docs/components/identicon)
|
|
696
|
+
|
|
697
|
+
Use for address avatars.
|
|
698
|
+
|
|
699
|
+
[SecretValue](/docs/components/secret-value)
|
|
700
|
+
|
|
701
|
+
Use for secrets.
|
|
702
|
+
|
|
703
|
+
[Payments](/docs/patterns/payments)
|
|
704
|
+
|
|
705
|
+
Covers send, receive, and deposit flows.
|
|
706
|
+
|
|
707
|
+
[Tables and Lists](/docs/patterns/tables-and-lists)
|
|
708
|
+
|
|
709
|
+
Covers columns of values.
|