@tempoxyz/ds 0.3.10 → 0.3.13
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/README.md +7 -6
- package/dist/docs/AGENTS.md +12 -0
- package/dist/docs/index.md +145 -0
- package/dist/docs/marketing/introduction/getting-started.md +241 -0
- package/dist/docs/product/components/accordion.md +489 -0
- package/dist/docs/product/components/address-card.md +147 -0
- package/dist/docs/product/components/agent-logo.md +194 -0
- package/dist/docs/product/components/alert-dialog.md +631 -0
- package/dist/docs/product/components/alert.md +448 -0
- package/dist/docs/product/components/amount-input.md +305 -0
- package/dist/docs/product/components/amount.md +794 -0
- package/dist/docs/product/components/app-shell.md +559 -0
- package/dist/docs/product/components/asset-chip.md +294 -0
- package/dist/docs/product/components/autocomplete.md +620 -0
- package/dist/docs/product/components/avatar.md +321 -0
- package/dist/docs/product/components/badge.md +339 -0
- package/dist/docs/product/components/badged-logo.md +116 -0
- package/dist/docs/product/components/banner.md +379 -0
- package/dist/docs/product/components/bar-chart.md +208 -0
- package/dist/docs/product/components/breadcrumbs.md +380 -0
- package/dist/docs/product/components/button-group.md +286 -0
- package/dist/docs/product/components/button.md +650 -0
- package/dist/docs/product/components/calendar.md +375 -0
- package/dist/docs/product/components/callout.md +96 -0
- package/dist/docs/product/components/checkbox-group.md +521 -0
- package/dist/docs/product/components/checkbox.md +467 -0
- package/dist/docs/product/components/choice-group.md +516 -0
- package/dist/docs/product/components/choicebox.md +641 -0
- package/dist/docs/product/components/code.md +100 -0
- package/dist/docs/product/components/combobox.md +939 -0
- package/dist/docs/product/components/container.md +257 -0
- package/dist/docs/product/components/copy-button.md +642 -0
- package/dist/docs/product/components/date-picker.md +514 -0
- package/dist/docs/product/components/dialog.md +1332 -0
- package/dist/docs/product/components/drawer.md +966 -0
- package/dist/docs/product/components/empty.md +340 -0
- package/dist/docs/product/components/field.md +570 -0
- package/dist/docs/product/components/fieldset.md +398 -0
- package/dist/docs/product/components/frame.md +434 -0
- package/dist/docs/product/components/gauge.md +299 -0
- package/dist/docs/product/components/get-started-visual.md +117 -0
- package/dist/docs/product/components/grid.md +288 -0
- package/dist/docs/product/components/hero-visual.md +155 -0
- package/dist/docs/product/components/hex.md +487 -0
- package/dist/docs/product/components/icon-tile.md +292 -0
- package/dist/docs/product/components/identicon.md +371 -0
- package/dist/docs/product/components/inline.md +233 -0
- package/dist/docs/product/components/inset.md +225 -0
- package/dist/docs/product/components/kbd.md +423 -0
- package/dist/docs/product/components/list-group.md +981 -0
- package/dist/docs/product/components/loading-dots.md +237 -0
- package/dist/docs/product/components/menu.md +934 -0
- package/dist/docs/product/components/native-select.md +204 -0
- package/dist/docs/product/components/network-logo.md +248 -0
- package/dist/docs/product/components/number-field.md +543 -0
- package/dist/docs/product/components/otp-field.md +616 -0
- package/dist/docs/product/components/pagination.md +516 -0
- package/dist/docs/product/components/popover.md +544 -0
- package/dist/docs/product/components/progress.md +388 -0
- package/dist/docs/product/components/qr.md +314 -0
- package/dist/docs/product/components/radio-group.md +528 -0
- package/dist/docs/product/components/secret-value.md +406 -0
- package/dist/docs/product/components/select.md +751 -0
- package/dist/docs/product/components/separator.md +379 -0
- package/dist/docs/product/components/sidebar-menu.md +922 -0
- package/dist/docs/product/components/skeleton.md +517 -0
- package/dist/docs/product/components/slider.md +539 -0
- package/dist/docs/product/components/snippet.md +424 -0
- package/dist/docs/product/components/spinner.md +216 -0
- package/dist/docs/product/components/split-bar.md +139 -0
- package/dist/docs/product/components/split-button.md +464 -0
- package/dist/docs/product/components/stack.md +299 -0
- package/dist/docs/product/components/status-chip.md +226 -0
- package/dist/docs/product/components/status-indicator.md +119 -0
- package/dist/docs/product/components/status-row.md +174 -0
- package/dist/docs/product/components/stepper.md +451 -0
- package/dist/docs/product/components/success-hero.md +157 -0
- package/dist/docs/product/components/surface.md +639 -0
- package/dist/docs/product/components/switch.md +472 -0
- package/dist/docs/product/components/table.md +967 -0
- package/dist/docs/product/components/tabs.md +627 -0
- package/dist/docs/product/components/tempo-logo.md +185 -0
- package/dist/docs/product/components/text-input.md +624 -0
- package/dist/docs/product/components/textarea.md +352 -0
- package/dist/docs/product/components/toast.md +535 -0
- package/dist/docs/product/components/token-logo.md +371 -0
- package/dist/docs/product/components/token.md +247 -0
- package/dist/docs/product/components/tooltip.md +490 -0
- package/dist/docs/product/components/verification-code.md +116 -0
- package/dist/docs/product/components/visual.md +249 -0
- package/dist/docs/product/components.md +203 -0
- package/dist/docs/product/foundations/accessibility.md +377 -0
- package/dist/docs/product/foundations/agents.md +150 -0
- package/dist/docs/product/foundations/color.md +522 -0
- package/dist/docs/product/foundations/content/tone.md +194 -0
- package/dist/docs/product/foundations/content/voice.md +194 -0
- package/dist/docs/product/foundations/content/writing-style.md +406 -0
- package/dist/docs/product/foundations/iconography.md +282 -0
- package/dist/docs/product/foundations/intent.md +360 -0
- package/dist/docs/product/foundations/layout.md +508 -0
- package/dist/docs/product/foundations/linter.md +496 -0
- package/dist/docs/product/foundations/motion.md +151 -0
- package/dist/docs/product/foundations/radius-and-padding.md +86 -0
- package/dist/docs/product/foundations/typography.md +266 -0
- package/dist/docs/product/introduction/faq.md +133 -0
- package/dist/docs/product/introduction/getting-started.md +377 -0
- package/dist/docs/product/patterns/blockchain-values.md +709 -0
- package/dist/docs/product/patterns/dashboards.md +638 -0
- package/dist/docs/product/patterns/destructive-actions.md +626 -0
- package/dist/docs/product/patterns/empty-states.md +612 -0
- package/dist/docs/product/patterns/errors-and-validation.md +808 -0
- package/dist/docs/product/patterns/feedback-and-status.md +518 -0
- package/dist/docs/product/patterns/forms.md +679 -0
- package/dist/docs/product/patterns/loading.md +630 -0
- package/dist/docs/product/patterns/navigation.md +397 -0
- package/dist/docs/product/patterns/payments.md +765 -0
- package/dist/docs/product/patterns/responsive-layout.md +997 -0
- package/dist/docs/product/patterns/tables-and-lists.md +964 -0
- package/dist/docs/product/products/tempo-console.md +671 -0
- package/dist/docs/product/products/tempo-performance.md +437 -0
- package/dist/docs/product/products/tempo-wallet.md +438 -0
- package/dist/marketing/index.d.ts +4 -0
- package/dist/marketing/index.d.ts.map +1 -0
- package/dist/marketing/index.js +4 -0
- package/dist/marketing/index.js.map +1 -0
- package/dist/marketing/index.js.zyzz.json +1 -0
- package/dist/marketing/vars.d.ts +907 -0
- package/dist/marketing/vars.d.ts.map +1 -0
- package/dist/marketing/vars.js +15 -0
- package/dist/marketing/vars.js.map +1 -0
- package/dist/marketing/vars.js.zyzz.json +1 -0
- package/dist/marketing/zyzz.config.d.ts +4512 -0
- package/dist/marketing/zyzz.config.d.ts.map +1 -0
- package/dist/marketing/zyzz.config.js +63 -0
- package/dist/marketing/zyzz.config.js.map +1 -0
- package/dist/marketing/zyzz.config.js.zyzz.json +1 -0
- package/dist/oxlint/index.d.ts +12 -1
- package/dist/oxlint/index.d.ts.map +1 -1
- package/dist/oxlint/index.js +39 -1
- package/dist/oxlint/index.js.map +1 -1
- package/dist/oxlint/internal/Docs.d.ts +9 -0
- package/dist/oxlint/internal/Docs.d.ts.map +1 -0
- package/dist/oxlint/internal/Docs.js +15 -0
- package/dist/oxlint/internal/Docs.js.map +1 -0
- package/dist/oxlint/internal/Imports.d.ts +1 -1
- package/dist/oxlint/internal/Imports.d.ts.map +1 -1
- package/dist/oxlint/internal/Imports.js +2 -0
- package/dist/oxlint/internal/Imports.js.map +1 -1
- package/dist/oxlint/internal/Styles.d.ts +40 -0
- package/dist/oxlint/internal/Styles.d.ts.map +1 -0
- package/dist/oxlint/internal/Styles.js +194 -0
- package/dist/oxlint/internal/Styles.js.map +1 -0
- package/dist/oxlint/internal/Tokens.d.ts +16 -0
- package/dist/oxlint/internal/Tokens.d.ts.map +1 -0
- package/dist/oxlint/internal/Tokens.js +39 -0
- package/dist/oxlint/internal/Tokens.js.map +1 -0
- package/dist/oxlint/rules/NoCrossSurface.d.ts +2 -2
- package/dist/oxlint/rules/NoCrossSurface.js +3 -3
- package/dist/oxlint/rules/NoCrossSurface.js.map +1 -1
- package/dist/oxlint/rules/NoCustomValues.d.ts +11 -0
- package/dist/oxlint/rules/NoCustomValues.d.ts.map +1 -0
- package/dist/oxlint/rules/NoCustomValues.js +150 -0
- package/dist/oxlint/rules/NoCustomValues.js.map +1 -0
- package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts +11 -0
- package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts.map +1 -0
- package/dist/oxlint/rules/NoSingleKeyShortcuts.js +158 -0
- package/dist/oxlint/rules/NoSingleKeyShortcuts.js.map +1 -0
- package/dist/oxlint/rules/PreferComponent.d.ts +3 -2
- package/dist/oxlint/rules/PreferComponent.d.ts.map +1 -1
- package/dist/oxlint/rules/PreferComponent.js +11 -4
- package/dist/oxlint/rules/PreferComponent.js.map +1 -1
- package/dist/oxlint/rules/PreferLayout.d.ts +9 -0
- package/dist/oxlint/rules/PreferLayout.d.ts.map +1 -0
- package/dist/oxlint/rules/PreferLayout.js +90 -0
- package/dist/oxlint/rules/PreferLayout.js.map +1 -0
- package/dist/oxlint/rules/PreferProgress.d.ts +9 -0
- package/dist/oxlint/rules/PreferProgress.d.ts.map +1 -0
- package/dist/oxlint/rules/PreferProgress.js +43 -0
- package/dist/oxlint/rules/PreferProgress.js.map +1 -0
- package/dist/oxlint/rules/PreferSurface.d.ts +9 -0
- package/dist/oxlint/rules/PreferSurface.d.ts.map +1 -0
- package/dist/oxlint/rules/PreferSurface.js +55 -0
- package/dist/oxlint/rules/PreferSurface.js.map +1 -0
- package/dist/oxlint/rules/RequireAccessibleName.d.ts.map +1 -1
- package/dist/oxlint/rules/RequireAccessibleName.js +3 -1
- package/dist/oxlint/rules/RequireAccessibleName.js.map +1 -1
- package/dist/oxlint/rules/RequireScrollRegion.d.ts +11 -0
- package/dist/oxlint/rules/RequireScrollRegion.d.ts.map +1 -0
- package/dist/oxlint/rules/RequireScrollRegion.js +71 -0
- package/dist/oxlint/rules/RequireScrollRegion.js.map +1 -0
- package/dist/web/icons/index.js.zyzz.json +1 -0
- package/package.json +6 -1
- package/src/marketing/README.md +21 -0
- package/src/marketing/index.ts +3 -0
- package/src/marketing/vars.ts +751 -0
- package/src/marketing/zyzz.config.ts +376 -0
- package/src/oxlint/index.ts +40 -1
- package/src/oxlint/internal/Docs.ts +18 -0
- package/src/oxlint/internal/Imports.ts +2 -1
- package/src/oxlint/internal/Styles.ts +240 -0
- package/src/oxlint/internal/Tokens.ts +43 -0
- package/src/oxlint/rules/NoCrossSurface.ts +3 -3
- package/src/oxlint/rules/NoCustomValues.ts +170 -0
- package/src/oxlint/rules/NoSingleKeyShortcuts.ts +190 -0
- package/src/oxlint/rules/PreferComponent.ts +11 -4
- package/src/oxlint/rules/PreferLayout.ts +96 -0
- package/src/oxlint/rules/PreferProgress.ts +49 -0
- package/src/oxlint/rules/PreferSurface.ts +70 -0
- package/src/oxlint/rules/RequireAccessibleName.ts +3 -1
- package/src/oxlint/rules/RequireScrollRegion.ts +92 -0
|
@@ -0,0 +1,967 @@
|
|
|
1
|
+
# Table
|
|
2
|
+
|
|
3
|
+
Displays tabular data in rows and columns.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Table.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Data/Table Card](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3500) (`Table.Root`), [Data/Table Cell](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3635) (`Table.Cell`), [Data/Table Empty](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3723) (`Table.Cell`), [Data/Table Footer](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3719) (`Table.Caption`), [Data/Table Header Cell](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3681) (`Table.HeaderCell`), [Data/Table Lead Tile](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3661) (`Table.LeadTile`), [Data/Table Row](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3589) (`Table.Row`), [Dense Table](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=3506-2536) (`Table.Root`), [Simple Table](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=3506-2513) (`Table.Root`)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
A table is a native `<table>` with styled parts. Use it for tabular data only, never for layout.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { style, Surface, Table } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export const fill = true
|
|
21
|
+
function Transactions(props: Table.Root.Props) {
|
|
22
|
+
return (
|
|
23
|
+
<Surface>
|
|
24
|
+
<Table.Root {...props}>
|
|
25
|
+
<Table.Head>
|
|
26
|
+
<Table.Row>
|
|
27
|
+
<Table.HeaderCell>ID</Table.HeaderCell>
|
|
28
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
29
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
30
|
+
</Table.Row>
|
|
31
|
+
</Table.Head>
|
|
32
|
+
<Table.Body>
|
|
33
|
+
{(
|
|
34
|
+
[
|
|
35
|
+
['0x4f2a…91c3', '$1,200.00', 'Confirmed', 'positive'],
|
|
36
|
+
['0x91bd…07e1', '$48.50', 'Confirmed', 'positive'],
|
|
37
|
+
['0xc3e0…5a22', '$310.00', 'Pending', 'warning'],
|
|
38
|
+
['0x77a1…c0d9', '$9.99', 'Failed', 'negative'],
|
|
39
|
+
] as const
|
|
40
|
+
).map(([id, amount, status, tone]) => (
|
|
41
|
+
<Table.Row key={id}>
|
|
42
|
+
<Table.Cell mono>{id}</Table.Cell>
|
|
43
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
44
|
+
<Table.Cell status={tone}>{status}</Table.Cell>
|
|
45
|
+
</Table.Row>
|
|
46
|
+
))}
|
|
47
|
+
</Table.Body>
|
|
48
|
+
</Table.Root>
|
|
49
|
+
</Surface>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function Demo() {
|
|
54
|
+
return (
|
|
55
|
+
<div {...styles.grid()}>
|
|
56
|
+
<Transactions />
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
namespace styles {
|
|
62
|
+
export const grid = style({
|
|
63
|
+
backgroundColor: 'background.primary',
|
|
64
|
+
display: 'grid',
|
|
65
|
+
gap: '24',
|
|
66
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
67
|
+
padding: '16',
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Basic.tsx)
|
|
73
|
+
|
|
74
|
+
### Two Lines
|
|
75
|
+
|
|
76
|
+
Set a second line in `Table.Subtitle`, lead the first cell with a `Table.LeadTile` or a [TokenLogo](token-logo.md), and set `muted` on a value that matters less, such as a zero amount.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { Inline, StatusChip, style, Surface, Table } from '@tempoxyz/ds'
|
|
80
|
+
import { ArrowDownLeft, ArrowUpRight, CreditCard } from '@tempoxyz/ds/icons'
|
|
81
|
+
|
|
82
|
+
export const fill = true
|
|
83
|
+
const activity = [
|
|
84
|
+
{
|
|
85
|
+
amount: '+$48.50',
|
|
86
|
+
detail: '48.50 USDC',
|
|
87
|
+
icon: <ArrowDownLeft />,
|
|
88
|
+
status: ['Settled', 'positive'],
|
|
89
|
+
time: 'Today, 09:41',
|
|
90
|
+
title: 'Received from Bob',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
amount: '$120.00',
|
|
94
|
+
detail: '120.00 USDC',
|
|
95
|
+
icon: <ArrowUpRight />,
|
|
96
|
+
status: ['Pending', 'warning'],
|
|
97
|
+
time: 'Today, 08:12',
|
|
98
|
+
title: 'Sent to Ada',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
amount: '$0.00',
|
|
102
|
+
detail: 'Declined',
|
|
103
|
+
icon: <CreditCard />,
|
|
104
|
+
status: ['Failed', 'negative'],
|
|
105
|
+
time: 'Yesterday, 18:30',
|
|
106
|
+
title: 'Card payment',
|
|
107
|
+
},
|
|
108
|
+
] as const
|
|
109
|
+
|
|
110
|
+
export function Demo() {
|
|
111
|
+
return (
|
|
112
|
+
<div {...styles.grid()}>
|
|
113
|
+
<Surface>
|
|
114
|
+
<Table.Root size="large">
|
|
115
|
+
<Table.Body>
|
|
116
|
+
{activity.map((entry) => (
|
|
117
|
+
<Table.Row key={entry.title}>
|
|
118
|
+
<Table.Cell>
|
|
119
|
+
<Inline gap="12">
|
|
120
|
+
<Table.LeadTile>{entry.icon}</Table.LeadTile>
|
|
121
|
+
<div>
|
|
122
|
+
{entry.title}
|
|
123
|
+
<Table.Subtitle>{entry.time}</Table.Subtitle>
|
|
124
|
+
</div>
|
|
125
|
+
</Inline>
|
|
126
|
+
</Table.Cell>
|
|
127
|
+
<Table.Cell>
|
|
128
|
+
<StatusChip intent={entry.status[1]} size="small">
|
|
129
|
+
{entry.status[0]}
|
|
130
|
+
</StatusChip>
|
|
131
|
+
</Table.Cell>
|
|
132
|
+
<Table.Cell
|
|
133
|
+
muted={entry.amount === '$0.00'}
|
|
134
|
+
status={entry.amount.startsWith('+') ? 'positive' : undefined}
|
|
135
|
+
>
|
|
136
|
+
{entry.amount}
|
|
137
|
+
<Table.Subtitle>{entry.detail}</Table.Subtitle>
|
|
138
|
+
</Table.Cell>
|
|
139
|
+
</Table.Row>
|
|
140
|
+
))}
|
|
141
|
+
</Table.Body>
|
|
142
|
+
</Table.Root>
|
|
143
|
+
</Surface>
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
namespace styles {
|
|
149
|
+
export const grid = style({
|
|
150
|
+
backgroundColor: 'background.primary',
|
|
151
|
+
display: 'grid',
|
|
152
|
+
gap: '24',
|
|
153
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
154
|
+
padding: '16',
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/TwoLines.tsx)
|
|
160
|
+
|
|
161
|
+
### Sortable Columns
|
|
162
|
+
|
|
163
|
+
Put a `Table.SortButton` in a `Table.HeaderCell` and set `aria-sort` on the header cell. The chevron shows on hover and once the column is sorted.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { style, Surface, Table } from '@tempoxyz/ds'
|
|
167
|
+
import { useState } from 'react'
|
|
168
|
+
|
|
169
|
+
export const fill = true
|
|
170
|
+
const assets = [
|
|
171
|
+
['USDC', 3420.18],
|
|
172
|
+
['USDT0', 3150],
|
|
173
|
+
['pathUSD', 2424.24],
|
|
174
|
+
] as const
|
|
175
|
+
|
|
176
|
+
const format = new Intl.NumberFormat('en-US', { currency: 'USD', style: 'currency' })
|
|
177
|
+
|
|
178
|
+
type Sort = { column: 'asset' | 'balance'; order: 'ascending' | 'descending' }
|
|
179
|
+
|
|
180
|
+
export function Demo() {
|
|
181
|
+
const [sort, setSort] = useState<Sort>({ column: 'balance', order: 'descending' })
|
|
182
|
+
|
|
183
|
+
const rows = [...assets].sort((a, b) => {
|
|
184
|
+
const order = sort.order === 'ascending' ? 1 : -1
|
|
185
|
+
if (sort.column === 'asset') return a[0].localeCompare(b[0]) * order
|
|
186
|
+
return (a[1] - b[1]) * order
|
|
187
|
+
})
|
|
188
|
+
const toggle = (column: Sort['column']) =>
|
|
189
|
+
setSort({
|
|
190
|
+
column,
|
|
191
|
+
order: sort.column === column && sort.order === 'descending' ? 'ascending' : 'descending',
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<div {...styles.grid()}>
|
|
196
|
+
<Surface>
|
|
197
|
+
<Table.Root interactive>
|
|
198
|
+
<Table.Head>
|
|
199
|
+
<Table.Row>
|
|
200
|
+
<Table.HeaderCell aria-sort={sort.column === 'asset' ? sort.order : 'none'}>
|
|
201
|
+
<Table.SortButton onClick={() => toggle('asset')}>Asset</Table.SortButton>
|
|
202
|
+
</Table.HeaderCell>
|
|
203
|
+
<Table.HeaderCell aria-sort={sort.column === 'balance' ? sort.order : 'none'}>
|
|
204
|
+
<Table.SortButton onClick={() => toggle('balance')}>Balance</Table.SortButton>
|
|
205
|
+
</Table.HeaderCell>
|
|
206
|
+
</Table.Row>
|
|
207
|
+
</Table.Head>
|
|
208
|
+
<Table.Body>
|
|
209
|
+
{rows.map(([symbol, balance]) => (
|
|
210
|
+
<Table.Row key={symbol}>
|
|
211
|
+
<Table.Cell>{symbol}</Table.Cell>
|
|
212
|
+
<Table.Cell>{format.format(balance)}</Table.Cell>
|
|
213
|
+
</Table.Row>
|
|
214
|
+
))}
|
|
215
|
+
</Table.Body>
|
|
216
|
+
</Table.Root>
|
|
217
|
+
</Surface>
|
|
218
|
+
</div>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
namespace styles {
|
|
223
|
+
export const grid = style({
|
|
224
|
+
backgroundColor: 'background.primary',
|
|
225
|
+
display: 'grid',
|
|
226
|
+
gap: '24',
|
|
227
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
228
|
+
padding: '16',
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Sortable.tsx)
|
|
234
|
+
|
|
235
|
+
### Interactive
|
|
236
|
+
|
|
237
|
+
Set `interactive` to fill a hovered row and outline a focus-visible one.
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import { style, Surface, Table } from '@tempoxyz/ds'
|
|
241
|
+
|
|
242
|
+
export const fill = true
|
|
243
|
+
function Transactions(props: Table.Root.Props) {
|
|
244
|
+
return (
|
|
245
|
+
<Surface>
|
|
246
|
+
<Table.Root {...props}>
|
|
247
|
+
<Table.Head>
|
|
248
|
+
<Table.Row>
|
|
249
|
+
<Table.HeaderCell>ID</Table.HeaderCell>
|
|
250
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
251
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
252
|
+
</Table.Row>
|
|
253
|
+
</Table.Head>
|
|
254
|
+
<Table.Body>
|
|
255
|
+
{(
|
|
256
|
+
[
|
|
257
|
+
['0x4f2a…91c3', '$1,200.00', 'Confirmed', 'positive'],
|
|
258
|
+
['0x91bd…07e1', '$48.50', 'Confirmed', 'positive'],
|
|
259
|
+
['0xc3e0…5a22', '$310.00', 'Pending', 'warning'],
|
|
260
|
+
['0x77a1…c0d9', '$9.99', 'Failed', 'negative'],
|
|
261
|
+
] as const
|
|
262
|
+
).map(([id, amount, status, tone]) => (
|
|
263
|
+
<Table.Row key={id} tabIndex={0}>
|
|
264
|
+
<Table.Cell mono>{id}</Table.Cell>
|
|
265
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
266
|
+
<Table.Cell status={tone}>{status}</Table.Cell>
|
|
267
|
+
</Table.Row>
|
|
268
|
+
))}
|
|
269
|
+
</Table.Body>
|
|
270
|
+
</Table.Root>
|
|
271
|
+
</Surface>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function Demo() {
|
|
276
|
+
return (
|
|
277
|
+
<div {...styles.grid()}>
|
|
278
|
+
<Transactions interactive />
|
|
279
|
+
</div>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
namespace styles {
|
|
284
|
+
export const grid = style({
|
|
285
|
+
backgroundColor: 'background.primary',
|
|
286
|
+
display: 'grid',
|
|
287
|
+
gap: '24',
|
|
288
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
289
|
+
padding: '16',
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Interactive.tsx)
|
|
295
|
+
|
|
296
|
+
### Dividers
|
|
297
|
+
|
|
298
|
+
Rows draw a divider inset by their padding, except the last row. Set `dividers={false}` to remove them.
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { style, Surface, Table } from '@tempoxyz/ds'
|
|
302
|
+
|
|
303
|
+
export const fill = true
|
|
304
|
+
function Transactions(props: Table.Root.Props) {
|
|
305
|
+
return (
|
|
306
|
+
<Surface>
|
|
307
|
+
<Table.Root {...props}>
|
|
308
|
+
<Table.Head>
|
|
309
|
+
<Table.Row>
|
|
310
|
+
<Table.HeaderCell>ID</Table.HeaderCell>
|
|
311
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
312
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
313
|
+
</Table.Row>
|
|
314
|
+
</Table.Head>
|
|
315
|
+
<Table.Body>
|
|
316
|
+
{(
|
|
317
|
+
[
|
|
318
|
+
['0x4f2a…91c3', '$1,200.00', 'Confirmed', 'positive'],
|
|
319
|
+
['0x91bd…07e1', '$48.50', 'Confirmed', 'positive'],
|
|
320
|
+
['0xc3e0…5a22', '$310.00', 'Pending', 'warning'],
|
|
321
|
+
['0x77a1…c0d9', '$9.99', 'Failed', 'negative'],
|
|
322
|
+
] as const
|
|
323
|
+
).map(([id, amount, status, tone]) => (
|
|
324
|
+
<Table.Row key={id}>
|
|
325
|
+
<Table.Cell mono>{id}</Table.Cell>
|
|
326
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
327
|
+
<Table.Cell status={tone}>{status}</Table.Cell>
|
|
328
|
+
</Table.Row>
|
|
329
|
+
))}
|
|
330
|
+
</Table.Body>
|
|
331
|
+
</Table.Root>
|
|
332
|
+
</Surface>
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function Demo() {
|
|
337
|
+
return (
|
|
338
|
+
<div {...styles.grid()}>
|
|
339
|
+
<Transactions dividers={false} />
|
|
340
|
+
</div>
|
|
341
|
+
)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
namespace styles {
|
|
345
|
+
export const grid = style({
|
|
346
|
+
backgroundColor: 'background.primary',
|
|
347
|
+
display: 'grid',
|
|
348
|
+
gap: '24',
|
|
349
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
350
|
+
padding: '16',
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Dividers.tsx)
|
|
356
|
+
|
|
357
|
+
### Size
|
|
358
|
+
|
|
359
|
+
Set `size` to `small`, `medium` (default), or `large`.
|
|
360
|
+
|
|
361
|
+
```tsx
|
|
362
|
+
import { style, Surface, Table } from '@tempoxyz/ds'
|
|
363
|
+
|
|
364
|
+
export const fill = true
|
|
365
|
+
function Transactions(props: Table.Root.Props) {
|
|
366
|
+
return (
|
|
367
|
+
<Surface>
|
|
368
|
+
<Table.Root {...props}>
|
|
369
|
+
<Table.Head>
|
|
370
|
+
<Table.Row>
|
|
371
|
+
<Table.HeaderCell>ID</Table.HeaderCell>
|
|
372
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
373
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
374
|
+
</Table.Row>
|
|
375
|
+
</Table.Head>
|
|
376
|
+
<Table.Body>
|
|
377
|
+
{(
|
|
378
|
+
[
|
|
379
|
+
['0x4f2a…91c3', '$1,200.00', 'Confirmed', 'positive'],
|
|
380
|
+
['0x91bd…07e1', '$48.50', 'Confirmed', 'positive'],
|
|
381
|
+
['0xc3e0…5a22', '$310.00', 'Pending', 'warning'],
|
|
382
|
+
['0x77a1…c0d9', '$9.99', 'Failed', 'negative'],
|
|
383
|
+
] as const
|
|
384
|
+
).map(([id, amount, status, tone]) => (
|
|
385
|
+
<Table.Row key={id}>
|
|
386
|
+
<Table.Cell mono>{id}</Table.Cell>
|
|
387
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
388
|
+
<Table.Cell status={tone}>{status}</Table.Cell>
|
|
389
|
+
</Table.Row>
|
|
390
|
+
))}
|
|
391
|
+
</Table.Body>
|
|
392
|
+
</Table.Root>
|
|
393
|
+
</Surface>
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export function Demo() {
|
|
398
|
+
return (
|
|
399
|
+
<div {...styles.grid()}>
|
|
400
|
+
<Transactions interactive size="small" />
|
|
401
|
+
<Transactions size="large" />
|
|
402
|
+
</div>
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
namespace styles {
|
|
407
|
+
export const grid = style({
|
|
408
|
+
backgroundColor: 'background.primary',
|
|
409
|
+
display: 'grid',
|
|
410
|
+
gap: '24',
|
|
411
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(24rem, 1fr)) !custom',
|
|
412
|
+
padding: '16',
|
|
413
|
+
})
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Size.tsx)
|
|
418
|
+
|
|
419
|
+
### Dense
|
|
420
|
+
|
|
421
|
+
Set `variant="dense"` for a row of labels over rows of details, such as a comparison of plans. Columns share the width equally.
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
import { Table } from '@tempoxyz/ds'
|
|
425
|
+
|
|
426
|
+
export const fill = true
|
|
427
|
+
const plans = [
|
|
428
|
+
['Starter', '0.10%', 'T+1', 'Email', 'USDC'],
|
|
429
|
+
['Growth', '0.08%', 'Same day', 'Chat', 'USDC, USDT0'],
|
|
430
|
+
['Scale', 'Custom', 'Instant', 'Dedicated', 'Any stablecoin'],
|
|
431
|
+
] as const
|
|
432
|
+
|
|
433
|
+
export function Demo() {
|
|
434
|
+
return (
|
|
435
|
+
<Table variant="dense">
|
|
436
|
+
<Table.Head>
|
|
437
|
+
<Table.Row>
|
|
438
|
+
<Table.HeaderCell>Plan</Table.HeaderCell>
|
|
439
|
+
<Table.HeaderCell>Fee</Table.HeaderCell>
|
|
440
|
+
<Table.HeaderCell>Settlement</Table.HeaderCell>
|
|
441
|
+
<Table.HeaderCell>Support</Table.HeaderCell>
|
|
442
|
+
<Table.HeaderCell>Assets</Table.HeaderCell>
|
|
443
|
+
</Table.Row>
|
|
444
|
+
</Table.Head>
|
|
445
|
+
<Table.Body>
|
|
446
|
+
{plans.map((plan) => (
|
|
447
|
+
<Table.Row key={plan[0]}>
|
|
448
|
+
{plan.map((value) => (
|
|
449
|
+
<Table.Cell key={value}>{value}</Table.Cell>
|
|
450
|
+
))}
|
|
451
|
+
</Table.Row>
|
|
452
|
+
))}
|
|
453
|
+
</Table.Body>
|
|
454
|
+
</Table>
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Dense.tsx)
|
|
460
|
+
|
|
461
|
+
### Simple
|
|
462
|
+
|
|
463
|
+
Set `variant="simple"` for rows that each lead with a row header beside a paragraph. Set `scope="row"` on each `Table.HeaderCell`.
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
import { Table } from '@tempoxyz/ds'
|
|
467
|
+
|
|
468
|
+
export const fill = true
|
|
469
|
+
const uses = [
|
|
470
|
+
[
|
|
471
|
+
'Global payouts and payroll',
|
|
472
|
+
'Platforms can pay merchants, contractors, or employees in stablecoins or local currency.',
|
|
473
|
+
],
|
|
474
|
+
[
|
|
475
|
+
'Treasury management',
|
|
476
|
+
'Companies can hold balances in stablecoins and move them between entities in seconds.',
|
|
477
|
+
],
|
|
478
|
+
[
|
|
479
|
+
'Cross-border settlement',
|
|
480
|
+
'Banks can settle with partners abroad without waiting on correspondent accounts.',
|
|
481
|
+
],
|
|
482
|
+
] as const
|
|
483
|
+
|
|
484
|
+
export function Demo() {
|
|
485
|
+
return (
|
|
486
|
+
<Table variant="simple">
|
|
487
|
+
<Table.Caption>Use cases</Table.Caption>
|
|
488
|
+
<Table.Body>
|
|
489
|
+
{uses.map(([title, description]) => (
|
|
490
|
+
<Table.Row key={title}>
|
|
491
|
+
<Table.HeaderCell scope="row">{title}</Table.HeaderCell>
|
|
492
|
+
<Table.Cell>{description}</Table.Cell>
|
|
493
|
+
</Table.Row>
|
|
494
|
+
))}
|
|
495
|
+
</Table.Body>
|
|
496
|
+
</Table>
|
|
497
|
+
)
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Table/Simple.tsx)
|
|
502
|
+
|
|
503
|
+
## Anatomy
|
|
504
|
+
|
|
505
|
+
Import the component and assemble its parts.
|
|
506
|
+
|
|
507
|
+
```tsx
|
|
508
|
+
import { Table } from '@tempoxyz/ds'
|
|
509
|
+
|
|
510
|
+
<Table>
|
|
511
|
+
<Table.Caption />
|
|
512
|
+
<Table.Head>
|
|
513
|
+
<Table.Row>
|
|
514
|
+
<Table.HeaderCell>
|
|
515
|
+
<Table.SortButton />
|
|
516
|
+
</Table.HeaderCell>
|
|
517
|
+
</Table.Row>
|
|
518
|
+
</Table.Head>
|
|
519
|
+
<Table.Body>
|
|
520
|
+
<Table.Row>
|
|
521
|
+
<Table.Cell>
|
|
522
|
+
<Table.LeadTile />
|
|
523
|
+
<Table.Subtitle />
|
|
524
|
+
</Table.Cell>
|
|
525
|
+
</Table.Row>
|
|
526
|
+
</Table.Body>
|
|
527
|
+
</Table>
|
|
528
|
+
<Table.Root />
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Guidelines
|
|
532
|
+
|
|
533
|
+
### When to Use
|
|
534
|
+
|
|
535
|
+
* Compare many records with the same fields, such as wallet activity (date, recipient, amount, status) or benchmark runs (commit, TPS, latency).
|
|
536
|
+
* Let people scan a column or find one row among many.
|
|
537
|
+
* List API keys, webhooks, or team members.
|
|
538
|
+
|
|
539
|
+
### When Not to Use
|
|
540
|
+
|
|
541
|
+
* Use [ListGroup](list-group.md) with `ListGroup.Label` for the fields of one record, such as a transaction's network, fee, and status.
|
|
542
|
+
* Use [ListGroup](list-group.md) with `action="navigation"` for a short list of pages or settings to open.
|
|
543
|
+
* Use [Grid](grid.md) or [Stack](stack.md) to arrange content.
|
|
544
|
+
* Use a [Surface](surface.md) with a large [Amount](amount.md) for one headline number, such as a balance or the current TPS.
|
|
545
|
+
|
|
546
|
+
### Align Numbers to the End
|
|
547
|
+
|
|
548
|
+
* **Figures:** Set `numeric` on number cells for tabular figures.
|
|
549
|
+
* **Alignment:** Set `justify="end"` on those cells and on their `Table.HeaderCell`. The last column already aligns to the end, unless its cells set `justify="start"`.
|
|
550
|
+
* **Decimals:** Keep one decimal count per column, such as `41.2` and `102.5`.
|
|
551
|
+
|
|
552
|
+
**Do:** Set `numeric` and `justify="end"` on number columns and their headers.
|
|
553
|
+
|
|
554
|
+
```tsx
|
|
555
|
+
/**
|
|
556
|
+
* Do example for "Align Numbers to the End" on the Table page.
|
|
557
|
+
* Set `numeric` and `justify="end"` on number columns and their headers.
|
|
558
|
+
* @module
|
|
559
|
+
*/
|
|
560
|
+
import { Table } from '@tempoxyz/ds'
|
|
561
|
+
|
|
562
|
+
const runs = [
|
|
563
|
+
['4f2a91c', '12,480', '41.2'],
|
|
564
|
+
['91bd07e', '9,315', '38.7'],
|
|
565
|
+
['c3e05a2', '10,072', '102.5'],
|
|
566
|
+
] as const
|
|
567
|
+
|
|
568
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
569
|
+
export function Demo() {
|
|
570
|
+
return (
|
|
571
|
+
<Table size="small">
|
|
572
|
+
<Table.Head>
|
|
573
|
+
<Table.Row>
|
|
574
|
+
<Table.HeaderCell>Commit</Table.HeaderCell>
|
|
575
|
+
<Table.HeaderCell justify="end">TPS</Table.HeaderCell>
|
|
576
|
+
<Table.HeaderCell>p99 (ms)</Table.HeaderCell>
|
|
577
|
+
</Table.Row>
|
|
578
|
+
</Table.Head>
|
|
579
|
+
<Table.Body>
|
|
580
|
+
{runs.map(([commit, tps, latency]) => (
|
|
581
|
+
<Table.Row key={commit}>
|
|
582
|
+
<Table.Cell mono>{commit}</Table.Cell>
|
|
583
|
+
<Table.Cell justify="end" numeric>
|
|
584
|
+
{tps}
|
|
585
|
+
</Table.Cell>
|
|
586
|
+
<Table.Cell numeric>{latency}</Table.Cell>
|
|
587
|
+
</Table.Row>
|
|
588
|
+
))}
|
|
589
|
+
</Table.Body>
|
|
590
|
+
</Table>
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
**Don't:** Start-align numbers or leave them in proportional figures.
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
/**
|
|
599
|
+
* Don't example for "Align Numbers to the End" on the Table page.
|
|
600
|
+
* Don't start-align numbers or leave them in proportional figures.
|
|
601
|
+
* @module
|
|
602
|
+
*/
|
|
603
|
+
import { Table } from '@tempoxyz/ds'
|
|
604
|
+
|
|
605
|
+
const runs = [
|
|
606
|
+
['4f2a91c', '12,480', '41.2'],
|
|
607
|
+
['91bd07e', '9,315', '38.7'],
|
|
608
|
+
['c3e05a2', '10,072', '102.5'],
|
|
609
|
+
] as const
|
|
610
|
+
|
|
611
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
612
|
+
export function Demo() {
|
|
613
|
+
return (
|
|
614
|
+
<Table size="small">
|
|
615
|
+
<Table.Head>
|
|
616
|
+
<Table.Row>
|
|
617
|
+
<Table.HeaderCell>Commit</Table.HeaderCell>
|
|
618
|
+
<Table.HeaderCell>TPS</Table.HeaderCell>
|
|
619
|
+
<Table.HeaderCell>p99 (ms)</Table.HeaderCell>
|
|
620
|
+
</Table.Row>
|
|
621
|
+
</Table.Head>
|
|
622
|
+
<Table.Body>
|
|
623
|
+
{runs.map(([commit, tps, latency]) => (
|
|
624
|
+
<Table.Row key={commit}>
|
|
625
|
+
<Table.Cell>{commit}</Table.Cell>
|
|
626
|
+
<Table.Cell>{tps}</Table.Cell>
|
|
627
|
+
<Table.Cell>{latency}</Table.Cell>
|
|
628
|
+
</Table.Row>
|
|
629
|
+
))}
|
|
630
|
+
</Table.Body>
|
|
631
|
+
</Table>
|
|
632
|
+
)
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
An [Amount](amount.md) in a cell renders as a block and sets its own alignment. Give it `align="right"` in an end-aligned column.
|
|
637
|
+
|
|
638
|
+
### Truncate Hashes in the Middle
|
|
639
|
+
|
|
640
|
+
Set `mono` on cells with hashes, addresses, and commit IDs, and shorten them with `formatHex`. Link the row to a details view that shows the full value in a [Hex](hex.md) with `copy`.
|
|
641
|
+
|
|
642
|
+
**Do:** Keep the `0x` prefix and four characters on each side, such as `0x4f2a…91c3`.
|
|
643
|
+
|
|
644
|
+
```tsx
|
|
645
|
+
/**
|
|
646
|
+
* Do example for "Truncate Hashes in the Middle" on the Table page.
|
|
647
|
+
* Keep the `0x` prefix and four characters on each side, such as `0x4f2a…91c3`.
|
|
648
|
+
* @module
|
|
649
|
+
*/
|
|
650
|
+
import { formatHex, Table } from '@tempoxyz/ds'
|
|
651
|
+
|
|
652
|
+
const transfers = [
|
|
653
|
+
['0x4f2a8c1e9b7d3a6f5e2c0b8d7a1f4e6c9b3d2a5f8e7c6b1d0a9f3e2c4b5091c3', '25.00'],
|
|
654
|
+
['0x91bd07e3a5c8f2d6b4e1a9c7f3d5b2e8a6c4f1d9b7e3a5c2f8d6b4e1a9c70e17', '120.00'],
|
|
655
|
+
] as const
|
|
656
|
+
|
|
657
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
658
|
+
export function Demo() {
|
|
659
|
+
return (
|
|
660
|
+
<Table size="small">
|
|
661
|
+
<Table.Head>
|
|
662
|
+
<Table.Row>
|
|
663
|
+
<Table.HeaderCell>Transaction</Table.HeaderCell>
|
|
664
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
665
|
+
</Table.Row>
|
|
666
|
+
</Table.Head>
|
|
667
|
+
<Table.Body>
|
|
668
|
+
{transfers.map(([hash, amount]) => (
|
|
669
|
+
<Table.Row key={hash}>
|
|
670
|
+
<Table.Cell mono>{formatHex(hash)}</Table.Cell>
|
|
671
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
672
|
+
</Table.Row>
|
|
673
|
+
))}
|
|
674
|
+
</Table.Body>
|
|
675
|
+
</Table>
|
|
676
|
+
)
|
|
677
|
+
}
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
**Don't:** Show full hashes, which crowd out the other columns.
|
|
681
|
+
|
|
682
|
+
```tsx
|
|
683
|
+
/**
|
|
684
|
+
* Don't example for "Truncate Hashes in the Middle" on the Table page.
|
|
685
|
+
* Don't show full hashes, which crowd out the other columns.
|
|
686
|
+
* @module
|
|
687
|
+
*/
|
|
688
|
+
import { Table } from '@tempoxyz/ds'
|
|
689
|
+
|
|
690
|
+
const transfers = [
|
|
691
|
+
['0x4f2a8c1e9b7d3a6f5e2c0b8d7a1f4e6c9b3d2a5f8e7c6b1d0a9f3e2c4b5091c3', '25.00'],
|
|
692
|
+
['0x91bd07e3a5c8f2d6b4e1a9c7f3d5b2e8a6c4f1d9b7e3a5c2f8d6b4e1a9c70e17', '120.00'],
|
|
693
|
+
] as const
|
|
694
|
+
|
|
695
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
696
|
+
export function Demo() {
|
|
697
|
+
return (
|
|
698
|
+
<Table size="small">
|
|
699
|
+
<Table.Head>
|
|
700
|
+
<Table.Row>
|
|
701
|
+
<Table.HeaderCell>Transaction</Table.HeaderCell>
|
|
702
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
703
|
+
</Table.Row>
|
|
704
|
+
</Table.Head>
|
|
705
|
+
<Table.Body>
|
|
706
|
+
{transfers.map(([hash, amount]) => (
|
|
707
|
+
<Table.Row key={hash}>
|
|
708
|
+
<Table.Cell mono>{hash}</Table.Cell>
|
|
709
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
710
|
+
</Table.Row>
|
|
711
|
+
))}
|
|
712
|
+
</Table.Body>
|
|
713
|
+
</Table>
|
|
714
|
+
)
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Pair Status Color With Words
|
|
719
|
+
|
|
720
|
+
`status` colors a cell's text `positive`, `negative`, or `warning`. If the status needs more weight, use a [Badge](badge.md) in the cell.
|
|
721
|
+
|
|
722
|
+
**Do:** Keep a word with each color, such as Failed.
|
|
723
|
+
|
|
724
|
+
```tsx
|
|
725
|
+
/**
|
|
726
|
+
* Do example for "Pair Status Color With Words" on the Table page.
|
|
727
|
+
* Keep a word with each color, such as Failed.
|
|
728
|
+
* @module
|
|
729
|
+
*/
|
|
730
|
+
import { Table } from '@tempoxyz/ds'
|
|
731
|
+
|
|
732
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
733
|
+
export function Demo() {
|
|
734
|
+
return (
|
|
735
|
+
<Table size="small">
|
|
736
|
+
<Table.Head>
|
|
737
|
+
<Table.Row>
|
|
738
|
+
<Table.HeaderCell>Recipient</Table.HeaderCell>
|
|
739
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
740
|
+
</Table.Row>
|
|
741
|
+
</Table.Head>
|
|
742
|
+
<Table.Body>
|
|
743
|
+
<Table.Row>
|
|
744
|
+
<Table.Cell>Alice</Table.Cell>
|
|
745
|
+
<Table.Cell status="positive">Confirmed</Table.Cell>
|
|
746
|
+
</Table.Row>
|
|
747
|
+
<Table.Row>
|
|
748
|
+
<Table.Cell>Bob</Table.Cell>
|
|
749
|
+
<Table.Cell status="warning">Pending</Table.Cell>
|
|
750
|
+
</Table.Row>
|
|
751
|
+
<Table.Row>
|
|
752
|
+
<Table.Cell>Carol</Table.Cell>
|
|
753
|
+
<Table.Cell status="negative">Failed</Table.Cell>
|
|
754
|
+
</Table.Row>
|
|
755
|
+
</Table.Body>
|
|
756
|
+
</Table>
|
|
757
|
+
)
|
|
758
|
+
}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**Don't:** Show status by color alone.
|
|
762
|
+
|
|
763
|
+
```tsx
|
|
764
|
+
/** Don't example for "Pair Status Color With Words" on the Table page. Don't show status by color alone. @module */
|
|
765
|
+
import { Table } from '@tempoxyz/ds'
|
|
766
|
+
|
|
767
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
768
|
+
export function Demo() {
|
|
769
|
+
return (
|
|
770
|
+
<Table size="small">
|
|
771
|
+
<Table.Head>
|
|
772
|
+
<Table.Row>
|
|
773
|
+
<Table.HeaderCell>Recipient</Table.HeaderCell>
|
|
774
|
+
<Table.HeaderCell>Status</Table.HeaderCell>
|
|
775
|
+
</Table.Row>
|
|
776
|
+
</Table.Head>
|
|
777
|
+
<Table.Body>
|
|
778
|
+
<Table.Row>
|
|
779
|
+
<Table.Cell>Alice</Table.Cell>
|
|
780
|
+
<Table.Cell status="positive">●</Table.Cell>
|
|
781
|
+
</Table.Row>
|
|
782
|
+
<Table.Row>
|
|
783
|
+
<Table.Cell>Bob</Table.Cell>
|
|
784
|
+
<Table.Cell status="warning">●</Table.Cell>
|
|
785
|
+
</Table.Row>
|
|
786
|
+
<Table.Row>
|
|
787
|
+
<Table.Cell>Carol</Table.Cell>
|
|
788
|
+
<Table.Cell status="negative">●</Table.Cell>
|
|
789
|
+
</Table.Row>
|
|
790
|
+
</Table.Body>
|
|
791
|
+
</Table>
|
|
792
|
+
)
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Make Clickable Rows Reachable by Keyboard
|
|
797
|
+
|
|
798
|
+
`interactive` adds styles only, with no click or key handling. If the whole row also responds to a click, keep other buttons out of it.
|
|
799
|
+
|
|
800
|
+
**Do:** Put a link to the record in the first cell.
|
|
801
|
+
|
|
802
|
+
```tsx
|
|
803
|
+
/**
|
|
804
|
+
* Do example for "Make Clickable Rows Reachable by Keyboard" on the Table page.
|
|
805
|
+
* Put a link to the record in the first cell.
|
|
806
|
+
* @module
|
|
807
|
+
*/
|
|
808
|
+
import { style, Table } from '@tempoxyz/ds'
|
|
809
|
+
|
|
810
|
+
const transfers = [
|
|
811
|
+
['0x4f2a…91c3', '25.00'],
|
|
812
|
+
['0x91bd…07e1', '120.00'],
|
|
813
|
+
['0xc3e0…5a22', '8.50'],
|
|
814
|
+
] as const
|
|
815
|
+
|
|
816
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
817
|
+
export function Demo() {
|
|
818
|
+
return (
|
|
819
|
+
<Table interactive size="small">
|
|
820
|
+
<Table.Head>
|
|
821
|
+
<Table.Row>
|
|
822
|
+
<Table.HeaderCell>Transaction</Table.HeaderCell>
|
|
823
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
824
|
+
</Table.Row>
|
|
825
|
+
</Table.Head>
|
|
826
|
+
<Table.Body>
|
|
827
|
+
{transfers.map(([hash, amount]) => (
|
|
828
|
+
<Table.Row key={hash}>
|
|
829
|
+
<Table.Cell mono>
|
|
830
|
+
<a href="#" {...styles.link()}>
|
|
831
|
+
{hash}
|
|
832
|
+
</a>
|
|
833
|
+
</Table.Cell>
|
|
834
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
835
|
+
</Table.Row>
|
|
836
|
+
))}
|
|
837
|
+
</Table.Body>
|
|
838
|
+
</Table>
|
|
839
|
+
)
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
namespace styles {
|
|
843
|
+
export const link = style({
|
|
844
|
+
color: 'content.primary',
|
|
845
|
+
textDecorationLine: 'underline !custom',
|
|
846
|
+
textUnderlineOffset: '4px !custom',
|
|
847
|
+
})
|
|
848
|
+
}
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
**Don't:** Rely on a row click handler that the keyboard can't reach.
|
|
852
|
+
|
|
853
|
+
```tsx
|
|
854
|
+
/**
|
|
855
|
+
* Don't example for "Make Clickable Rows Reachable by Keyboard" on the Table page.
|
|
856
|
+
* Don't rely on a row click handler that the keyboard can't reach.
|
|
857
|
+
* @module
|
|
858
|
+
*/
|
|
859
|
+
import { Table } from '@tempoxyz/ds'
|
|
860
|
+
|
|
861
|
+
const transfers = [
|
|
862
|
+
['0x4f2a…91c3', '25.00'],
|
|
863
|
+
['0x91bd…07e1', '120.00'],
|
|
864
|
+
['0xc3e0…5a22', '8.50'],
|
|
865
|
+
] as const
|
|
866
|
+
|
|
867
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
868
|
+
export function Demo() {
|
|
869
|
+
return (
|
|
870
|
+
<Table interactive size="small">
|
|
871
|
+
<Table.Head>
|
|
872
|
+
<Table.Row>
|
|
873
|
+
<Table.HeaderCell>Transaction</Table.HeaderCell>
|
|
874
|
+
<Table.HeaderCell>Amount</Table.HeaderCell>
|
|
875
|
+
</Table.Row>
|
|
876
|
+
</Table.Head>
|
|
877
|
+
<Table.Body>
|
|
878
|
+
{transfers.map(([hash, amount]) => (
|
|
879
|
+
<Table.Row key={hash} onClick={() => {}}>
|
|
880
|
+
<Table.Cell mono>{hash}</Table.Cell>
|
|
881
|
+
<Table.Cell numeric>{amount}</Table.Cell>
|
|
882
|
+
</Table.Row>
|
|
883
|
+
))}
|
|
884
|
+
</Table.Body>
|
|
885
|
+
</Table>
|
|
886
|
+
)
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### Keep Long Tables Readable
|
|
891
|
+
|
|
892
|
+
* **Sticky headers:** Set `sticky` on `Table.Head`, and place the table in a scrolling container with a fixed height.
|
|
893
|
+
* **Long histories:** Split them with [Pagination](pagination.md).
|
|
894
|
+
|
|
895
|
+
### Match Density to the Data
|
|
896
|
+
|
|
897
|
+
* **Small (32px):** Dense dashboards, such as benchmark results.
|
|
898
|
+
* **Medium (40px):** The default.
|
|
899
|
+
* **Large (56px):** Avatars or token icons beside two lines of text.
|
|
900
|
+
|
|
901
|
+
## Content
|
|
902
|
+
|
|
903
|
+
* Write column headers as short nouns, such as Recipient, Amount, and Block time.
|
|
904
|
+
* Put the unit of a metric in the header, such as `p99 (ms)`. Keep the currency or token on each amount, since one table can mix assets.
|
|
905
|
+
* Use one date format per column. Use relative times, such as 5 min ago, only for recent activity, and show the full date in the details view.
|
|
906
|
+
* Fill empty cells with one value, such as None or 0, so a blank cell doesn't read as a loading error.
|
|
907
|
+
|
|
908
|
+
## Accessibility
|
|
909
|
+
|
|
910
|
+
A table renders native table elements, so screen readers announce rows, columns, and headers. It follows the [WAI-ARIA table pattern](https://www.w3.org/WAI/ARIA/apg/patterns/table/).
|
|
911
|
+
|
|
912
|
+
### Semantics
|
|
913
|
+
|
|
914
|
+
* **Table.Root (table):** Uses native table elements for every part, from the root to each cell.
|
|
915
|
+
* **Table.HeaderCell (th):** Column headers. If a body row's first cell names the record, such as a commit ID, make it a row header.
|
|
916
|
+
* **Appearance Props (numeric, mono, muted, status):** These and `interactive` change styles only. Status colors aren't announced.
|
|
917
|
+
* **Table.SortButton (button):** A native button in the header cell. The header cell announces its `aria-sort` order.
|
|
918
|
+
|
|
919
|
+
### Keyboard
|
|
920
|
+
|
|
921
|
+
A table has no keys of its own. Screen reader users move through cells with table commands.
|
|
922
|
+
|
|
923
|
+
For a sort button, and for a row you make focusable with `tabIndex={0}` in an `interactive` table:
|
|
924
|
+
|
|
925
|
+
* **Sort the Column (Enter or Space):** Runs the `onClick` of the focused sort button.
|
|
926
|
+
* **Move Focus to the Row (Tab):** Moves focus to the row.
|
|
927
|
+
|
|
928
|
+
### Focus
|
|
929
|
+
|
|
930
|
+
With `interactive`, a focused body row shows an outline inside its edges. A focused sort button shows an outline around the label of its header cell. The table adds no other tab stops.
|
|
931
|
+
|
|
932
|
+
### Your Responsibilities
|
|
933
|
+
|
|
934
|
+
* **Name Every Table (Table.Caption):** Caption it, or use `aria-labelledby` for a visible heading. The caption renders below the rows.
|
|
935
|
+
* **Update the Sort Order (aria-sort):** Sort the rows in `onClick`, and set `aria-sort` on the sorted header cell and `none` on the rest.
|
|
936
|
+
* **Mark Headers (scope):** Mark every column header, and the cell that identifies each row.
|
|
937
|
+
* **Reflow Wide Tables (SC 1.4.10):** Put a wide table in a focusable [scrolling container](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html) with an `aria-label`.
|
|
938
|
+
|
|
939
|
+
## Related
|
|
940
|
+
|
|
941
|
+
[ListGroup](list-group.md)
|
|
942
|
+
|
|
943
|
+
Use for the details of one record.
|
|
944
|
+
|
|
945
|
+
[Amount](amount.md)
|
|
946
|
+
|
|
947
|
+
Use for money and token amounts in cells.
|
|
948
|
+
|
|
949
|
+
[Hex](hex.md)
|
|
950
|
+
|
|
951
|
+
Use for addresses and hashes.
|
|
952
|
+
|
|
953
|
+
[Badge](badge.md)
|
|
954
|
+
|
|
955
|
+
Use for statuses.
|
|
956
|
+
|
|
957
|
+
[Pagination](pagination.md)
|
|
958
|
+
|
|
959
|
+
Use for long histories.
|
|
960
|
+
|
|
961
|
+
[Tables and Lists](../patterns/tables-and-lists.md)
|
|
962
|
+
|
|
963
|
+
Covers choosing a layout.
|
|
964
|
+
|
|
965
|
+
[Dashboards](../patterns/dashboards.md)
|
|
966
|
+
|
|
967
|
+
Covers benchmark and metric views.
|