@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.
Files changed (128) hide show
  1. package/dist/docs/AGENTS.md +9 -0
  2. package/dist/docs/components/accordion.md +489 -0
  3. package/dist/docs/components/address-card.md +147 -0
  4. package/dist/docs/components/agent-logo.md +194 -0
  5. package/dist/docs/components/alert-dialog.md +631 -0
  6. package/dist/docs/components/alert.md +448 -0
  7. package/dist/docs/components/amount-input.md +305 -0
  8. package/dist/docs/components/amount.md +794 -0
  9. package/dist/docs/components/app-shell.md +559 -0
  10. package/dist/docs/components/asset-chip.md +294 -0
  11. package/dist/docs/components/autocomplete.md +619 -0
  12. package/dist/docs/components/avatar.md +321 -0
  13. package/dist/docs/components/badge.md +339 -0
  14. package/dist/docs/components/badged-logo.md +116 -0
  15. package/dist/docs/components/banner.md +379 -0
  16. package/dist/docs/components/bar-chart.md +208 -0
  17. package/dist/docs/components/breadcrumbs.md +380 -0
  18. package/dist/docs/components/button-group.md +286 -0
  19. package/dist/docs/components/button.md +650 -0
  20. package/dist/docs/components/calendar.md +375 -0
  21. package/dist/docs/components/callout.md +96 -0
  22. package/dist/docs/components/checkbox-group.md +521 -0
  23. package/dist/docs/components/checkbox.md +467 -0
  24. package/dist/docs/components/choice-group.md +516 -0
  25. package/dist/docs/components/choicebox.md +641 -0
  26. package/dist/docs/components/code.md +100 -0
  27. package/dist/docs/components/combobox.md +939 -0
  28. package/dist/docs/components/container.md +257 -0
  29. package/dist/docs/components/copy-button.md +642 -0
  30. package/dist/docs/components/date-picker.md +514 -0
  31. package/dist/docs/components/dialog.md +1332 -0
  32. package/dist/docs/components/drawer.md +966 -0
  33. package/dist/docs/components/empty.md +340 -0
  34. package/dist/docs/components/field.md +570 -0
  35. package/dist/docs/components/fieldset.md +398 -0
  36. package/dist/docs/components/frame.md +434 -0
  37. package/dist/docs/components/gauge.md +299 -0
  38. package/dist/docs/components/get-started-visual.md +117 -0
  39. package/dist/docs/components/grid.md +288 -0
  40. package/dist/docs/components/hero-visual.md +155 -0
  41. package/dist/docs/components/hex.md +487 -0
  42. package/dist/docs/components/icon-tile.md +292 -0
  43. package/dist/docs/components/identicon.md +371 -0
  44. package/dist/docs/components/inline.md +233 -0
  45. package/dist/docs/components/inset.md +225 -0
  46. package/dist/docs/components/kbd.md +423 -0
  47. package/dist/docs/components/list-group.md +981 -0
  48. package/dist/docs/components/loading-dots.md +237 -0
  49. package/dist/docs/components/menu.md +934 -0
  50. package/dist/docs/components/native-select.md +204 -0
  51. package/dist/docs/components/network-logo.md +248 -0
  52. package/dist/docs/components/number-field.md +543 -0
  53. package/dist/docs/components/otp-field.md +616 -0
  54. package/dist/docs/components/pagination.md +516 -0
  55. package/dist/docs/components/popover.md +544 -0
  56. package/dist/docs/components/progress.md +388 -0
  57. package/dist/docs/components/qr.md +314 -0
  58. package/dist/docs/components/radio-group.md +528 -0
  59. package/dist/docs/components/secret-value.md +406 -0
  60. package/dist/docs/components/select.md +751 -0
  61. package/dist/docs/components/separator.md +379 -0
  62. package/dist/docs/components/sidebar-menu.md +922 -0
  63. package/dist/docs/components/skeleton.md +517 -0
  64. package/dist/docs/components/slider.md +539 -0
  65. package/dist/docs/components/snippet.md +424 -0
  66. package/dist/docs/components/spinner.md +216 -0
  67. package/dist/docs/components/split-bar.md +139 -0
  68. package/dist/docs/components/split-button.md +464 -0
  69. package/dist/docs/components/stack.md +299 -0
  70. package/dist/docs/components/status-chip.md +226 -0
  71. package/dist/docs/components/status-indicator.md +119 -0
  72. package/dist/docs/components/status-row.md +174 -0
  73. package/dist/docs/components/stepper.md +451 -0
  74. package/dist/docs/components/success-hero.md +157 -0
  75. package/dist/docs/components/surface.md +639 -0
  76. package/dist/docs/components/switch.md +472 -0
  77. package/dist/docs/components/table.md +967 -0
  78. package/dist/docs/components/tabs.md +627 -0
  79. package/dist/docs/components/tempo-logo.md +185 -0
  80. package/dist/docs/components/text-input.md +624 -0
  81. package/dist/docs/components/textarea.md +352 -0
  82. package/dist/docs/components/toast.md +535 -0
  83. package/dist/docs/components/token-logo.md +371 -0
  84. package/dist/docs/components/token.md +247 -0
  85. package/dist/docs/components/tooltip.md +490 -0
  86. package/dist/docs/components/verification-code.md +116 -0
  87. package/dist/docs/components/visual.md +249 -0
  88. package/dist/docs/components.md +203 -0
  89. package/dist/docs/foundations/accessibility.md +377 -0
  90. package/dist/docs/foundations/agents.md +150 -0
  91. package/dist/docs/foundations/color.md +522 -0
  92. package/dist/docs/foundations/content/tone.md +194 -0
  93. package/dist/docs/foundations/content/voice.md +194 -0
  94. package/dist/docs/foundations/content/writing-style.md +406 -0
  95. package/dist/docs/foundations/iconography.md +282 -0
  96. package/dist/docs/foundations/intent.md +360 -0
  97. package/dist/docs/foundations/layout.md +508 -0
  98. package/dist/docs/foundations/linter.md +296 -0
  99. package/dist/docs/foundations/motion.md +151 -0
  100. package/dist/docs/foundations/radius-and-padding.md +86 -0
  101. package/dist/docs/foundations/typography.md +266 -0
  102. package/dist/docs/index.md +137 -0
  103. package/dist/docs/introduction/faq.md +132 -0
  104. package/dist/docs/introduction/getting-started.md +377 -0
  105. package/dist/docs/patterns/blockchain-values.md +709 -0
  106. package/dist/docs/patterns/dashboards.md +638 -0
  107. package/dist/docs/patterns/destructive-actions.md +626 -0
  108. package/dist/docs/patterns/empty-states.md +612 -0
  109. package/dist/docs/patterns/errors-and-validation.md +808 -0
  110. package/dist/docs/patterns/feedback-and-status.md +518 -0
  111. package/dist/docs/patterns/forms.md +679 -0
  112. package/dist/docs/patterns/loading.md +630 -0
  113. package/dist/docs/patterns/navigation.md +397 -0
  114. package/dist/docs/patterns/payments.md +765 -0
  115. package/dist/docs/patterns/responsive-layout.md +997 -0
  116. package/dist/docs/patterns/tables-and-lists.md +964 -0
  117. package/dist/docs/products/tempo-console.md +671 -0
  118. package/dist/docs/products/tempo-performance.md +437 -0
  119. package/dist/docs/products/tempo-wallet.md +438 -0
  120. package/dist/web/components/OtpField.css +1 -1
  121. package/dist/web/components/OtpField.d.ts +1 -1
  122. package/dist/web/components/OtpField.d.ts.map +1 -1
  123. package/dist/web/components/OtpField.js +3 -4
  124. package/dist/web/components/OtpField.js.map +1 -1
  125. package/dist/web/components/OtpField.js.zyzz.json +1 -1
  126. package/dist/web/index.js.zyzz.json +1 -1
  127. package/package.json +1 -1
  128. package/src/web/components/OtpField.tsx +2 -24
@@ -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.