@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,939 @@
|
|
|
1
|
+
# Combobox
|
|
2
|
+
|
|
3
|
+
A text input that filters a list of fixed options while people type.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Combobox.tsx)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
A text input with a listbox popup. The value must be one of the options.
|
|
10
|
+
|
|
11
|
+
## Examples
|
|
12
|
+
|
|
13
|
+
### Basic
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Combobox } from '@tempoxyz/ds'
|
|
17
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
18
|
+
import { useState } from 'react'
|
|
19
|
+
import cbBtc from '../../coins/CbBTC.svg'
|
|
20
|
+
import ethereumEth from '../../coins/EthereumETH.svg'
|
|
21
|
+
import pathUsd from '../../coins/PathUSD.svg'
|
|
22
|
+
import usdce from '../../coins/USDCe.svg'
|
|
23
|
+
import usdt0 from '../../coins/USDT0.svg'
|
|
24
|
+
|
|
25
|
+
const coins: Record<string, string> = {
|
|
26
|
+
'Bridged ETH': ethereumEth,
|
|
27
|
+
pathUSD: pathUsd,
|
|
28
|
+
Tether: usdt0,
|
|
29
|
+
'USDC.e': usdce,
|
|
30
|
+
USDT0: usdt0,
|
|
31
|
+
'Wrapped BTC': cbBtc,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const assets = ['pathUSD', 'USDC.e', 'Tether', 'USDT0', 'Bridged ETH', 'Wrapped BTC']
|
|
35
|
+
|
|
36
|
+
function Coin(props: { asset: string }) {
|
|
37
|
+
return <img alt="" height={20} src={coins[props.asset]} width={20} />
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Single(props: Pick<Combobox.InputGroup.Props, 'invalid' | 'variant'>) {
|
|
41
|
+
const [value, setValue] = useState<string | null>('pathUSD')
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Combobox.Root items={assets} onValueChange={setValue} value={value}>
|
|
45
|
+
<Combobox.InputGroup {...props}>
|
|
46
|
+
<Combobox.Prefix>{value ? <Coin asset={value} /> : <Search />}</Combobox.Prefix>
|
|
47
|
+
<Combobox.Input aria-label="Asset" placeholder="Search assets" />
|
|
48
|
+
<Combobox.Clear />
|
|
49
|
+
<Combobox.Trigger />
|
|
50
|
+
</Combobox.InputGroup>
|
|
51
|
+
<Combobox.Popup>
|
|
52
|
+
<Combobox.Empty>No results</Combobox.Empty>
|
|
53
|
+
<Combobox.List>
|
|
54
|
+
{(asset: string) => (
|
|
55
|
+
<Combobox.Item key={asset} value={asset}>
|
|
56
|
+
<Combobox.ItemPrefix>
|
|
57
|
+
<Coin asset={asset} />
|
|
58
|
+
</Combobox.ItemPrefix>
|
|
59
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
60
|
+
</Combobox.Item>
|
|
61
|
+
)}
|
|
62
|
+
</Combobox.List>
|
|
63
|
+
</Combobox.Popup>
|
|
64
|
+
</Combobox.Root>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function Demo() {
|
|
69
|
+
return <Single />
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Combobox/Basic.tsx)
|
|
74
|
+
|
|
75
|
+
### Variant
|
|
76
|
+
|
|
77
|
+
Set `variant` on `Combobox.InputGroup` to `filled` (default) or `outlined`.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { Combobox, style } from '@tempoxyz/ds'
|
|
81
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
82
|
+
import { useState } from 'react'
|
|
83
|
+
import cbBtc from '../../coins/CbBTC.svg'
|
|
84
|
+
import ethereumEth from '../../coins/EthereumETH.svg'
|
|
85
|
+
import pathUsd from '../../coins/PathUSD.svg'
|
|
86
|
+
import usdce from '../../coins/USDCe.svg'
|
|
87
|
+
import usdt0 from '../../coins/USDT0.svg'
|
|
88
|
+
|
|
89
|
+
const coins: Record<string, string> = {
|
|
90
|
+
'Bridged ETH': ethereumEth,
|
|
91
|
+
pathUSD: pathUsd,
|
|
92
|
+
Tether: usdt0,
|
|
93
|
+
'USDC.e': usdce,
|
|
94
|
+
USDT0: usdt0,
|
|
95
|
+
'Wrapped BTC': cbBtc,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const assets = ['pathUSD', 'USDC.e', 'Tether', 'USDT0', 'Bridged ETH', 'Wrapped BTC']
|
|
99
|
+
|
|
100
|
+
function Coin(props: { asset: string }) {
|
|
101
|
+
return <img alt="" height={20} src={coins[props.asset]} width={20} />
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function Single(props: Pick<Combobox.InputGroup.Props, 'invalid' | 'variant'>) {
|
|
105
|
+
const [value, setValue] = useState<string | null>('pathUSD')
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<Combobox.Root items={assets} onValueChange={setValue} value={value}>
|
|
109
|
+
<Combobox.InputGroup {...props}>
|
|
110
|
+
<Combobox.Prefix>{value ? <Coin asset={value} /> : <Search />}</Combobox.Prefix>
|
|
111
|
+
<Combobox.Input aria-label="Asset" placeholder="Search assets" />
|
|
112
|
+
<Combobox.Clear />
|
|
113
|
+
<Combobox.Trigger />
|
|
114
|
+
</Combobox.InputGroup>
|
|
115
|
+
<Combobox.Popup>
|
|
116
|
+
<Combobox.Empty>No results</Combobox.Empty>
|
|
117
|
+
<Combobox.List>
|
|
118
|
+
{(asset: string) => (
|
|
119
|
+
<Combobox.Item key={asset} value={asset}>
|
|
120
|
+
<Combobox.ItemPrefix>
|
|
121
|
+
<Coin asset={asset} />
|
|
122
|
+
</Combobox.ItemPrefix>
|
|
123
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
124
|
+
</Combobox.Item>
|
|
125
|
+
)}
|
|
126
|
+
</Combobox.List>
|
|
127
|
+
</Combobox.Popup>
|
|
128
|
+
</Combobox.Root>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function Demo() {
|
|
133
|
+
return (
|
|
134
|
+
<div {...styles.grid()}>
|
|
135
|
+
<Single />
|
|
136
|
+
<Single variant="outlined" />
|
|
137
|
+
</div>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
namespace styles {
|
|
142
|
+
export const grid = style({
|
|
143
|
+
alignItems: 'start',
|
|
144
|
+
display: 'grid',
|
|
145
|
+
gap: '12',
|
|
146
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr)) !custom',
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Combobox/Variant.tsx)
|
|
152
|
+
|
|
153
|
+
### Invalid
|
|
154
|
+
|
|
155
|
+
Set `invalid` on `Combobox.InputGroup` to style the frame, and `aria-invalid` on the input to expose the state.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import { Combobox } from '@tempoxyz/ds'
|
|
159
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
160
|
+
import { useState } from 'react'
|
|
161
|
+
import cbBtc from '../../coins/CbBTC.svg'
|
|
162
|
+
import ethereumEth from '../../coins/EthereumETH.svg'
|
|
163
|
+
import pathUsd from '../../coins/PathUSD.svg'
|
|
164
|
+
import usdce from '../../coins/USDCe.svg'
|
|
165
|
+
import usdt0 from '../../coins/USDT0.svg'
|
|
166
|
+
|
|
167
|
+
const coins: Record<string, string> = {
|
|
168
|
+
'Bridged ETH': ethereumEth,
|
|
169
|
+
pathUSD: pathUsd,
|
|
170
|
+
Tether: usdt0,
|
|
171
|
+
'USDC.e': usdce,
|
|
172
|
+
USDT0: usdt0,
|
|
173
|
+
'Wrapped BTC': cbBtc,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const assets = ['pathUSD', 'USDC.e', 'Tether', 'USDT0', 'Bridged ETH', 'Wrapped BTC']
|
|
177
|
+
|
|
178
|
+
function Coin(props: { asset: string }) {
|
|
179
|
+
return <img alt="" height={20} src={coins[props.asset]} width={20} />
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function Single(props: Pick<Combobox.InputGroup.Props, 'invalid' | 'variant'>) {
|
|
183
|
+
const [value, setValue] = useState<string | null>('pathUSD')
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<Combobox.Root items={assets} onValueChange={setValue} value={value}>
|
|
187
|
+
<Combobox.InputGroup {...props}>
|
|
188
|
+
<Combobox.Prefix>{value ? <Coin asset={value} /> : <Search />}</Combobox.Prefix>
|
|
189
|
+
<Combobox.Input aria-label="Asset" placeholder="Search assets" />
|
|
190
|
+
<Combobox.Clear />
|
|
191
|
+
<Combobox.Trigger />
|
|
192
|
+
</Combobox.InputGroup>
|
|
193
|
+
<Combobox.Popup>
|
|
194
|
+
<Combobox.Empty>No results</Combobox.Empty>
|
|
195
|
+
<Combobox.List>
|
|
196
|
+
{(asset: string) => (
|
|
197
|
+
<Combobox.Item key={asset} value={asset}>
|
|
198
|
+
<Combobox.ItemPrefix>
|
|
199
|
+
<Coin asset={asset} />
|
|
200
|
+
</Combobox.ItemPrefix>
|
|
201
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
202
|
+
</Combobox.Item>
|
|
203
|
+
)}
|
|
204
|
+
</Combobox.List>
|
|
205
|
+
</Combobox.Popup>
|
|
206
|
+
</Combobox.Root>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function Demo() {
|
|
211
|
+
return <Single invalid />
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Combobox/Invalid.tsx)
|
|
216
|
+
|
|
217
|
+
### Multiple
|
|
218
|
+
|
|
219
|
+
Set `multiple` on `Combobox.Root` to select several values, shown as chips.
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { Combobox } from '@tempoxyz/ds'
|
|
223
|
+
import { useState } from 'react'
|
|
224
|
+
|
|
225
|
+
const assets = ['pathUSD', 'USDC.e', 'Tether', 'USDT0', 'Bridged ETH', 'Wrapped BTC']
|
|
226
|
+
|
|
227
|
+
function Multiple() {
|
|
228
|
+
const [value, setValue] = useState(['pathUSD', 'USDC.e'])
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<Combobox.Root items={assets} multiple onValueChange={setValue} value={value}>
|
|
232
|
+
<Combobox.InputGroup>
|
|
233
|
+
<Combobox.Value>
|
|
234
|
+
{(selected: string[]) => (
|
|
235
|
+
<Combobox.Chips aria-label="Selected assets">
|
|
236
|
+
{selected.map((asset) => (
|
|
237
|
+
<Combobox.Chip key={asset}>
|
|
238
|
+
{asset}
|
|
239
|
+
<Combobox.ChipRemove aria-label={`Remove ${asset}`} />
|
|
240
|
+
</Combobox.Chip>
|
|
241
|
+
))}
|
|
242
|
+
<Combobox.Input
|
|
243
|
+
aria-label="Assets"
|
|
244
|
+
placeholder={selected.length ? '' : 'Add assets'}
|
|
245
|
+
/>
|
|
246
|
+
</Combobox.Chips>
|
|
247
|
+
)}
|
|
248
|
+
</Combobox.Value>
|
|
249
|
+
</Combobox.InputGroup>
|
|
250
|
+
<Combobox.Popup>
|
|
251
|
+
<Combobox.Empty>No results</Combobox.Empty>
|
|
252
|
+
<Combobox.List>
|
|
253
|
+
{(asset: string) => (
|
|
254
|
+
<Combobox.Item key={asset} value={asset}>
|
|
255
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
256
|
+
</Combobox.Item>
|
|
257
|
+
)}
|
|
258
|
+
</Combobox.List>
|
|
259
|
+
</Combobox.Popup>
|
|
260
|
+
</Combobox.Root>
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function Demo() {
|
|
265
|
+
return <Multiple />
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Combobox/Multiple.tsx)
|
|
270
|
+
|
|
271
|
+
## Anatomy
|
|
272
|
+
|
|
273
|
+
Import the component and assemble its parts.
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
import { Combobox } from '@tempoxyz/ds'
|
|
277
|
+
|
|
278
|
+
<Combobox.Root>
|
|
279
|
+
<Combobox.InputGroup>
|
|
280
|
+
<Combobox.Prefix />
|
|
281
|
+
<Combobox.Value>
|
|
282
|
+
<Combobox.Chips>
|
|
283
|
+
<Combobox.Chip>
|
|
284
|
+
<Combobox.ChipRemove />
|
|
285
|
+
</Combobox.Chip>
|
|
286
|
+
<Combobox.Input />
|
|
287
|
+
</Combobox.Chips>
|
|
288
|
+
</Combobox.Value>
|
|
289
|
+
<Combobox.Clear />
|
|
290
|
+
<Combobox.Trigger />
|
|
291
|
+
</Combobox.InputGroup>
|
|
292
|
+
<Combobox.Popup>
|
|
293
|
+
<Combobox.Empty />
|
|
294
|
+
<Combobox.List>
|
|
295
|
+
<Combobox.Group>
|
|
296
|
+
<Combobox.GroupLabel />
|
|
297
|
+
<Combobox.Collection>
|
|
298
|
+
<Combobox.Item>
|
|
299
|
+
<Combobox.ItemPrefix />
|
|
300
|
+
<Combobox.ItemText />
|
|
301
|
+
<Combobox.ItemSuffix />
|
|
302
|
+
</Combobox.Item>
|
|
303
|
+
</Combobox.Collection>
|
|
304
|
+
</Combobox.Group>
|
|
305
|
+
<Combobox.Separator />
|
|
306
|
+
</Combobox.List>
|
|
307
|
+
</Combobox.Popup>
|
|
308
|
+
</Combobox.Root>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Guidelines
|
|
312
|
+
|
|
313
|
+
### When to Use
|
|
314
|
+
|
|
315
|
+
* Choose one item from a long, fixed list filtered by typing, such as the asset to send or the country on an account.
|
|
316
|
+
* Choose several items from that list with `multiple`, such as the assets a report covers.
|
|
317
|
+
|
|
318
|
+
### When Not to Use
|
|
319
|
+
|
|
320
|
+
* If people can scan the whole list without typing, use [Select](select.md).
|
|
321
|
+
* If any typed text is a valid value, such as a recipient address, use [Autocomplete](autocomplete.md).
|
|
322
|
+
* Use [RadioGroup](radio-group.md) or [ChoiceGroup](choice-group.md) for a few options that fit on screen.
|
|
323
|
+
* Use [CheckboxGroup](checkbox-group.md) for several options from a short list.
|
|
324
|
+
|
|
325
|
+
### Keep a Visible Label
|
|
326
|
+
|
|
327
|
+
The placeholder disappears on input, so it can't name the field.
|
|
328
|
+
|
|
329
|
+
**Do:** Label the field and show the selected asset's icon in `Combobox.Prefix`.
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
/**
|
|
333
|
+
* Do example for "Keep a Visible Label" on the Combobox page.
|
|
334
|
+
* Label the field and show the selected asset's icon in `Combobox.Prefix`.
|
|
335
|
+
* @module
|
|
336
|
+
*/
|
|
337
|
+
import { Combobox, Field, style } from '@tempoxyz/ds'
|
|
338
|
+
import usdce from '../../coins/USDCe.svg'
|
|
339
|
+
|
|
340
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
341
|
+
|
|
342
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
343
|
+
export function Demo() {
|
|
344
|
+
return (
|
|
345
|
+
<Field.Root {...styles.field()}>
|
|
346
|
+
<Field.Label>Asset</Field.Label>
|
|
347
|
+
<Combobox.Root defaultValue="USDC.e" items={assets}>
|
|
348
|
+
<Combobox.InputGroup>
|
|
349
|
+
<Combobox.Prefix>
|
|
350
|
+
<img alt="" height={20} src={usdce} width={20} />
|
|
351
|
+
</Combobox.Prefix>
|
|
352
|
+
<Combobox.Input placeholder="Search assets" />
|
|
353
|
+
<Combobox.Trigger />
|
|
354
|
+
</Combobox.InputGroup>
|
|
355
|
+
<Combobox.Popup>
|
|
356
|
+
<Combobox.Empty>No assets found</Combobox.Empty>
|
|
357
|
+
<Combobox.List>
|
|
358
|
+
{(asset: string) => (
|
|
359
|
+
<Combobox.Item key={asset} value={asset}>
|
|
360
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
361
|
+
</Combobox.Item>
|
|
362
|
+
)}
|
|
363
|
+
</Combobox.List>
|
|
364
|
+
</Combobox.Popup>
|
|
365
|
+
</Combobox.Root>
|
|
366
|
+
</Field.Root>
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
namespace styles {
|
|
371
|
+
export const field = style({ width: '100% !custom' })
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Don't:** Rely on the placeholder to say what the field is for.
|
|
376
|
+
|
|
377
|
+
```tsx
|
|
378
|
+
/**
|
|
379
|
+
* Don't example for "Keep a Visible Label" on the Combobox page.
|
|
380
|
+
* Don't rely on the placeholder to say what the field is for.
|
|
381
|
+
* @module
|
|
382
|
+
*/
|
|
383
|
+
import { Combobox, style } from '@tempoxyz/ds'
|
|
384
|
+
import { Search } from '@tempoxyz/ds/icons'
|
|
385
|
+
|
|
386
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
387
|
+
|
|
388
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
389
|
+
export function Demo() {
|
|
390
|
+
return (
|
|
391
|
+
<Combobox.Root items={assets}>
|
|
392
|
+
<Combobox.InputGroup {...styles.group()}>
|
|
393
|
+
<Combobox.Prefix>
|
|
394
|
+
<Search />
|
|
395
|
+
</Combobox.Prefix>
|
|
396
|
+
<Combobox.Input aria-label="Asset" placeholder="Search assets" />
|
|
397
|
+
<Combobox.Trigger />
|
|
398
|
+
</Combobox.InputGroup>
|
|
399
|
+
<Combobox.Popup>
|
|
400
|
+
<Combobox.Empty>No assets found</Combobox.Empty>
|
|
401
|
+
<Combobox.List>
|
|
402
|
+
{(asset: string) => (
|
|
403
|
+
<Combobox.Item key={asset} value={asset}>
|
|
404
|
+
<Combobox.ItemText>{asset}</Combobox.ItemText>
|
|
405
|
+
</Combobox.Item>
|
|
406
|
+
)}
|
|
407
|
+
</Combobox.List>
|
|
408
|
+
</Combobox.Popup>
|
|
409
|
+
</Combobox.Root>
|
|
410
|
+
)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
namespace styles {
|
|
414
|
+
export const group = style({ width: '100% !custom' })
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Always Render Combobox.Empty
|
|
419
|
+
|
|
420
|
+
`Combobox.Empty` shows its children when nothing matches and announces them in a polite status region.
|
|
421
|
+
|
|
422
|
+
**Do:** Render a short, specific message, such as No assets found.
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
/**
|
|
426
|
+
* Do example for "Always Render Combobox.Empty" on the Combobox page.
|
|
427
|
+
* Render a short, specific message, such as No assets found.
|
|
428
|
+
* @module
|
|
429
|
+
*/
|
|
430
|
+
import { Combobox, style } from '@tempoxyz/ds'
|
|
431
|
+
|
|
432
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
433
|
+
|
|
434
|
+
// The popup portals and opens on input, so a static copy shows it open.
|
|
435
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
436
|
+
export function Demo() {
|
|
437
|
+
return (
|
|
438
|
+
<div {...styles.column()}>
|
|
439
|
+
<Combobox.Root defaultInputValue="EURC" items={assets}>
|
|
440
|
+
<Combobox.InputGroup>
|
|
441
|
+
<Combobox.Input aria-label="Asset" />
|
|
442
|
+
<Combobox.Trigger />
|
|
443
|
+
</Combobox.InputGroup>
|
|
444
|
+
</Combobox.Root>
|
|
445
|
+
<div {...styles.popup()}>
|
|
446
|
+
<div {...styles.empty()}>No assets found</div>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
namespace styles {
|
|
453
|
+
export const column = style({
|
|
454
|
+
display: 'flex',
|
|
455
|
+
flexDirection: 'column',
|
|
456
|
+
gap: '8',
|
|
457
|
+
maxWidth: '16rem !custom',
|
|
458
|
+
width: '100% !custom',
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
export const empty = style({
|
|
462
|
+
color: 'content.secondary',
|
|
463
|
+
paddingBlock: '12',
|
|
464
|
+
paddingInline: '16',
|
|
465
|
+
typography: 'body.b2',
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
export const popup = style({
|
|
469
|
+
backgroundColor: 'background.elevated',
|
|
470
|
+
borderRadius: 'sm',
|
|
471
|
+
boxShadow: 'regular',
|
|
472
|
+
padding: '6px !custom',
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Don't:** Leave it out. The popup opens blank and announces nothing.
|
|
478
|
+
|
|
479
|
+
```tsx
|
|
480
|
+
/**
|
|
481
|
+
* Don't example for "Always Render Combobox.Empty" on the Combobox page.
|
|
482
|
+
* Don't leave it out. The popup opens blank and announces nothing.
|
|
483
|
+
* @module
|
|
484
|
+
*/
|
|
485
|
+
import { Combobox, style } from '@tempoxyz/ds'
|
|
486
|
+
|
|
487
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
488
|
+
|
|
489
|
+
// The popup portals and opens on input, so a static copy shows it open.
|
|
490
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
491
|
+
export function Demo() {
|
|
492
|
+
return (
|
|
493
|
+
<div {...styles.column()}>
|
|
494
|
+
<Combobox.Root defaultInputValue="EURC" items={assets}>
|
|
495
|
+
<Combobox.InputGroup>
|
|
496
|
+
<Combobox.Input aria-label="Asset" />
|
|
497
|
+
<Combobox.Trigger />
|
|
498
|
+
</Combobox.InputGroup>
|
|
499
|
+
</Combobox.Root>
|
|
500
|
+
<div {...styles.popup()} />
|
|
501
|
+
</div>
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
namespace styles {
|
|
506
|
+
export const column = style({
|
|
507
|
+
display: 'flex',
|
|
508
|
+
flexDirection: 'column',
|
|
509
|
+
gap: '8',
|
|
510
|
+
maxWidth: '16rem !custom',
|
|
511
|
+
width: '100% !custom',
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
export const popup = style({
|
|
515
|
+
backgroundColor: 'background.elevated',
|
|
516
|
+
borderRadius: 'sm',
|
|
517
|
+
boxShadow: 'regular',
|
|
518
|
+
padding: '6px !custom',
|
|
519
|
+
})
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Show What Identifies Each Item
|
|
524
|
+
|
|
525
|
+
* **`Combobox.ItemText`:** The searchable name, such as the symbol USDC.e.
|
|
526
|
+
* **`Combobox.ItemPrefix`:** A token icon.
|
|
527
|
+
* **`Combobox.ItemSuffix`:** Detail that informs the choice, such as a balance.
|
|
528
|
+
|
|
529
|
+
**Do:** Show the symbol, its icon, and the balance.
|
|
530
|
+
|
|
531
|
+
```tsx
|
|
532
|
+
/**
|
|
533
|
+
* Do example for "Show What Identifies Each Item" on the Combobox page.
|
|
534
|
+
* Show the symbol, its icon, and the balance.
|
|
535
|
+
* @module
|
|
536
|
+
*/
|
|
537
|
+
import pathusd from '../../coins/PathUSD.svg'
|
|
538
|
+
import usdce from '../../coins/USDCe.svg'
|
|
539
|
+
import usdt0 from '../../coins/USDT0.svg'
|
|
540
|
+
import { style } from '@tempoxyz/ds'
|
|
541
|
+
|
|
542
|
+
const assets = [
|
|
543
|
+
{ balance: '1,250.00', icon: usdce, symbol: 'USDC.e' },
|
|
544
|
+
{ balance: '80.50', icon: pathusd, symbol: 'pathUSD' },
|
|
545
|
+
{ balance: '0.00', icon: usdt0, symbol: 'USDT0' },
|
|
546
|
+
]
|
|
547
|
+
|
|
548
|
+
// A static copy of the open popup, since the real one portals and opens on input.
|
|
549
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
550
|
+
export function Demo() {
|
|
551
|
+
return (
|
|
552
|
+
<div {...styles.popup()}>
|
|
553
|
+
{assets.map((asset) => (
|
|
554
|
+
<div key={asset.symbol} {...styles.item()}>
|
|
555
|
+
<img alt="" height={20} src={asset.icon} width={20} />
|
|
556
|
+
{asset.symbol}
|
|
557
|
+
<span {...styles.suffix()}>{asset.balance}</span>
|
|
558
|
+
</div>
|
|
559
|
+
))}
|
|
560
|
+
</div>
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
namespace styles {
|
|
565
|
+
export const item = style({
|
|
566
|
+
alignItems: 'center',
|
|
567
|
+
display: 'flex',
|
|
568
|
+
gap: '8',
|
|
569
|
+
minHeight: '40',
|
|
570
|
+
paddingInline: '16',
|
|
571
|
+
typography: 'body.b2Strong',
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
export const popup = style({
|
|
575
|
+
backgroundColor: 'background.elevated',
|
|
576
|
+
borderRadius: 'sm',
|
|
577
|
+
boxShadow: 'regular',
|
|
578
|
+
padding: '6px !custom',
|
|
579
|
+
width: '16rem !custom',
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
export const suffix = style({
|
|
583
|
+
color: 'content.secondary',
|
|
584
|
+
marginInlineStart: 'auto !custom',
|
|
585
|
+
typography: 'body.b3',
|
|
586
|
+
})
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Don't:** List contract addresses as item text.
|
|
591
|
+
|
|
592
|
+
```tsx
|
|
593
|
+
/**
|
|
594
|
+
* Don't example for "Show What Identifies Each Item" on the Combobox page.
|
|
595
|
+
* Don't list contract addresses as item text.
|
|
596
|
+
* @module
|
|
597
|
+
*/
|
|
598
|
+
import { style } from '@tempoxyz/ds'
|
|
599
|
+
|
|
600
|
+
const assets = ['0x20c0…0001', '0x20c0…0002', '0x20c0…0003']
|
|
601
|
+
|
|
602
|
+
// A static copy of the open popup, since the real one portals and opens on input.
|
|
603
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
604
|
+
export function Demo() {
|
|
605
|
+
return (
|
|
606
|
+
<div {...styles.popup()}>
|
|
607
|
+
{assets.map((address) => (
|
|
608
|
+
<div key={address} {...styles.item()}>
|
|
609
|
+
{address}
|
|
610
|
+
</div>
|
|
611
|
+
))}
|
|
612
|
+
</div>
|
|
613
|
+
)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
namespace styles {
|
|
617
|
+
export const item = style({
|
|
618
|
+
alignItems: 'center',
|
|
619
|
+
display: 'flex',
|
|
620
|
+
gap: '8',
|
|
621
|
+
minHeight: '40',
|
|
622
|
+
paddingInline: '16',
|
|
623
|
+
typography: 'body.b2Strong',
|
|
624
|
+
})
|
|
625
|
+
|
|
626
|
+
export const popup = style({
|
|
627
|
+
backgroundColor: 'background.elevated',
|
|
628
|
+
borderRadius: 'sm',
|
|
629
|
+
boxShadow: 'regular',
|
|
630
|
+
padding: '6px !custom',
|
|
631
|
+
width: '16rem !custom',
|
|
632
|
+
})
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Offer a Way to Browse
|
|
637
|
+
|
|
638
|
+
`Combobox.Clear` mounts only while there is a value.
|
|
639
|
+
|
|
640
|
+
**Do:** Add `Combobox.Trigger` to open the full list, and `Combobox.Clear` if the value can be emptied.
|
|
641
|
+
|
|
642
|
+
```tsx
|
|
643
|
+
/**
|
|
644
|
+
* Do example for "Offer a Way to Browse" on the Combobox page.
|
|
645
|
+
* Add `Combobox.Trigger` to open the full list, and `Combobox.Clear` if the value can be emptied.
|
|
646
|
+
* @module
|
|
647
|
+
*/
|
|
648
|
+
import { Combobox, Field, style } from '@tempoxyz/ds'
|
|
649
|
+
|
|
650
|
+
const countries = ['Germany', 'Singapore', 'United States']
|
|
651
|
+
|
|
652
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
653
|
+
export function Demo() {
|
|
654
|
+
return (
|
|
655
|
+
<Field.Root {...styles.field()}>
|
|
656
|
+
<Field.Label>Country</Field.Label>
|
|
657
|
+
<Combobox.Root defaultValue="Singapore" items={countries}>
|
|
658
|
+
<Combobox.InputGroup>
|
|
659
|
+
<Combobox.Input placeholder="Search countries" />
|
|
660
|
+
<Combobox.Clear />
|
|
661
|
+
<Combobox.Trigger />
|
|
662
|
+
</Combobox.InputGroup>
|
|
663
|
+
</Combobox.Root>
|
|
664
|
+
</Field.Root>
|
|
665
|
+
)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
namespace styles {
|
|
669
|
+
export const field = style({ maxWidth: '16rem !custom', width: '100% !custom' })
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
**Don't:** Make typing the only way to see the options.
|
|
674
|
+
|
|
675
|
+
```tsx
|
|
676
|
+
/**
|
|
677
|
+
* Don't example for "Offer a Way to Browse" on the Combobox page.
|
|
678
|
+
* Don't make typing the only way to see the options.
|
|
679
|
+
* @module
|
|
680
|
+
*/
|
|
681
|
+
import { Combobox, Field, style } from '@tempoxyz/ds'
|
|
682
|
+
|
|
683
|
+
const countries = ['Germany', 'Singapore', 'United States']
|
|
684
|
+
|
|
685
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
686
|
+
export function Demo() {
|
|
687
|
+
return (
|
|
688
|
+
<Field.Root {...styles.field()}>
|
|
689
|
+
<Field.Label>Country</Field.Label>
|
|
690
|
+
<Combobox.Root defaultValue="Singapore" items={countries}>
|
|
691
|
+
<Combobox.InputGroup>
|
|
692
|
+
<Combobox.Input placeholder="Search countries" />
|
|
693
|
+
</Combobox.InputGroup>
|
|
694
|
+
</Combobox.Root>
|
|
695
|
+
</Field.Root>
|
|
696
|
+
)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
namespace styles {
|
|
700
|
+
export const field = style({ maxWidth: '16rem !custom', width: '100% !custom' })
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Group Long Lists
|
|
705
|
+
|
|
706
|
+
Name each `Combobox.Group` with a `Combobox.GroupLabel`, and divide groups with `Combobox.Separator`. Put the most-chosen items first.
|
|
707
|
+
|
|
708
|
+
**Do:** Split a long list into named sections, such as Stablecoins.
|
|
709
|
+
|
|
710
|
+
```tsx
|
|
711
|
+
/**
|
|
712
|
+
* Do example for "Group Long Lists" on the Combobox page.
|
|
713
|
+
* Split a long list into named sections, such as Stablecoins.
|
|
714
|
+
* @module
|
|
715
|
+
*/
|
|
716
|
+
import { style } from '@tempoxyz/ds'
|
|
717
|
+
|
|
718
|
+
// A static copy of the open popup, since the real one portals and opens on input.
|
|
719
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
720
|
+
export function Demo() {
|
|
721
|
+
return (
|
|
722
|
+
<div {...styles.popup()}>
|
|
723
|
+
<div {...styles.label()}>Stablecoins</div>
|
|
724
|
+
<div {...styles.item()}>pathUSD</div>
|
|
725
|
+
<div {...styles.item()}>USDC.e</div>
|
|
726
|
+
<div {...styles.separator()} />
|
|
727
|
+
<div {...styles.label()}>Other assets</div>
|
|
728
|
+
<div {...styles.item()}>cbBTC</div>
|
|
729
|
+
<div {...styles.item()}>ETH</div>
|
|
730
|
+
</div>
|
|
731
|
+
)
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
namespace styles {
|
|
735
|
+
export const item = style({
|
|
736
|
+
alignItems: 'center',
|
|
737
|
+
display: 'flex',
|
|
738
|
+
minHeight: '40',
|
|
739
|
+
paddingInline: '16',
|
|
740
|
+
typography: 'body.b2Strong',
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
export const label = style({
|
|
744
|
+
color: 'content.secondary',
|
|
745
|
+
paddingBlock: '8',
|
|
746
|
+
paddingInline: '16',
|
|
747
|
+
typography: 'body.b3',
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
export const popup = style({
|
|
751
|
+
backgroundColor: 'background.elevated',
|
|
752
|
+
borderRadius: 'sm',
|
|
753
|
+
boxShadow: 'regular',
|
|
754
|
+
padding: '6px !custom',
|
|
755
|
+
width: '16rem !custom',
|
|
756
|
+
})
|
|
757
|
+
|
|
758
|
+
export const separator = style({
|
|
759
|
+
backgroundColor: 'container.strong',
|
|
760
|
+
height: '1',
|
|
761
|
+
marginBlock: '8',
|
|
762
|
+
marginInline: '16',
|
|
763
|
+
})
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Don't:** Mix unrelated kinds of items in one flat list.
|
|
768
|
+
|
|
769
|
+
```tsx
|
|
770
|
+
/**
|
|
771
|
+
* Don't example for "Group Long Lists" on the Combobox page.
|
|
772
|
+
* Don't mix unrelated kinds of items in one flat list.
|
|
773
|
+
* @module
|
|
774
|
+
*/
|
|
775
|
+
import { style } from '@tempoxyz/ds'
|
|
776
|
+
|
|
777
|
+
// A static copy of the open popup, since the real one portals and opens on input.
|
|
778
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
779
|
+
export function Demo() {
|
|
780
|
+
return (
|
|
781
|
+
<div {...styles.popup()}>
|
|
782
|
+
<div {...styles.item()}>cbBTC</div>
|
|
783
|
+
<div {...styles.item()}>pathUSD</div>
|
|
784
|
+
<div {...styles.item()}>ETH</div>
|
|
785
|
+
<div {...styles.item()}>USDC.e</div>
|
|
786
|
+
</div>
|
|
787
|
+
)
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
namespace styles {
|
|
791
|
+
export const item = style({
|
|
792
|
+
alignItems: 'center',
|
|
793
|
+
display: 'flex',
|
|
794
|
+
minHeight: '40',
|
|
795
|
+
paddingInline: '16',
|
|
796
|
+
typography: 'body.b2Strong',
|
|
797
|
+
})
|
|
798
|
+
|
|
799
|
+
export const popup = style({
|
|
800
|
+
backgroundColor: 'background.elevated',
|
|
801
|
+
borderRadius: 'sm',
|
|
802
|
+
boxShadow: 'regular',
|
|
803
|
+
padding: '6px !custom',
|
|
804
|
+
width: '16rem !custom',
|
|
805
|
+
})
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Expose Errors on the Input
|
|
810
|
+
|
|
811
|
+
**Do:** Set `aria-invalid` on `Combobox.Input`, and explain the problem in a `Field.Error`.
|
|
812
|
+
|
|
813
|
+
```tsx
|
|
814
|
+
/**
|
|
815
|
+
* Do example for "Expose Errors on the TextInput" on the Combobox page.
|
|
816
|
+
* Set `aria-invalid` on `Combobox.Input`, and explain the problem in a `Field.Error`.
|
|
817
|
+
* @module
|
|
818
|
+
*/
|
|
819
|
+
import { Combobox, Field, style } from '@tempoxyz/ds'
|
|
820
|
+
|
|
821
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
822
|
+
|
|
823
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
824
|
+
export function Demo() {
|
|
825
|
+
return (
|
|
826
|
+
<Field.Root invalid {...styles.field()}>
|
|
827
|
+
<Field.Label>Asset</Field.Label>
|
|
828
|
+
<Combobox.Root items={assets}>
|
|
829
|
+
<Combobox.InputGroup invalid>
|
|
830
|
+
<Combobox.Input aria-invalid placeholder="Search assets" />
|
|
831
|
+
<Combobox.Trigger />
|
|
832
|
+
</Combobox.InputGroup>
|
|
833
|
+
</Combobox.Root>
|
|
834
|
+
<Field.Error match>Select an asset to send</Field.Error>
|
|
835
|
+
</Field.Root>
|
|
836
|
+
)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
namespace styles {
|
|
840
|
+
export const field = style({ maxWidth: '16rem !custom', width: '100% !custom' })
|
|
841
|
+
}
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
**Don't:** Rely on `invalid` on `Combobox.InputGroup`. It only styles the frame.
|
|
845
|
+
|
|
846
|
+
```tsx
|
|
847
|
+
/**
|
|
848
|
+
* Don't example for "Expose Errors on the TextInput" on the Combobox page.
|
|
849
|
+
* Don't rely on `invalid` on `Combobox.InputGroup`. It only styles the frame.
|
|
850
|
+
* @module
|
|
851
|
+
*/
|
|
852
|
+
import { Combobox, Field, style } from '@tempoxyz/ds'
|
|
853
|
+
|
|
854
|
+
const assets = ['pathUSD', 'USDC.e', 'USDT0']
|
|
855
|
+
|
|
856
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
857
|
+
export function Demo() {
|
|
858
|
+
return (
|
|
859
|
+
<Field.Root {...styles.field()}>
|
|
860
|
+
<Field.Label>Asset</Field.Label>
|
|
861
|
+
<Combobox.Root items={assets}>
|
|
862
|
+
<Combobox.InputGroup invalid>
|
|
863
|
+
<Combobox.Input placeholder="Search assets" />
|
|
864
|
+
<Combobox.Trigger />
|
|
865
|
+
</Combobox.InputGroup>
|
|
866
|
+
</Combobox.Root>
|
|
867
|
+
</Field.Root>
|
|
868
|
+
)
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
namespace styles {
|
|
872
|
+
export const field = style({ maxWidth: '16rem !custom', width: '100% !custom' })
|
|
873
|
+
}
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
## Content
|
|
877
|
+
|
|
878
|
+
* **Label:** The noun the value names, such as Asset, Network, or Country.
|
|
879
|
+
* **Placeholder:** What people can search by, such as Search by name or symbol.
|
|
880
|
+
* **Items:** The names and symbols from the token list, with the same casing everywhere.
|
|
881
|
+
|
|
882
|
+
## Accessibility
|
|
883
|
+
|
|
884
|
+
Follows the [WAI-ARIA combobox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) with list autocomplete.
|
|
885
|
+
|
|
886
|
+
### Semantics
|
|
887
|
+
|
|
888
|
+
* **Combobox.Input (combobox):** A text input that announces an option list and whether it is open.
|
|
889
|
+
* **Highlighted Option (aria-activedescendant):** Points to the highlighted option while focus stays in the input.
|
|
890
|
+
* **Combobox.List and Combobox.Item (listbox):** Each item is an option with a check mark while selected.
|
|
891
|
+
* **Combobox.Trigger and Combobox.Clear (button):** Named "Show options" and "Clear", both out of the tab order. Clear renders only with a value.
|
|
892
|
+
* **Combobox.Chips (toolbar):** With `multiple`, arrow keys move between chips. Each remove button is named "Remove".
|
|
893
|
+
|
|
894
|
+
### Keyboard
|
|
895
|
+
|
|
896
|
+
* **Move Focus to the TextInput (Tab):** Moves focus to the input.
|
|
897
|
+
* **Filter the Options (Typing):** Filters the options and opens the list.
|
|
898
|
+
* **Open or Move Down (Down Arrow):** Opens the list, or highlights the next option.
|
|
899
|
+
* **Move Up (Up Arrow):** Highlights the previous option.
|
|
900
|
+
* **Select an Option (Enter):** Selects the highlighted option and closes the list. With `multiple`, toggles it instead.
|
|
901
|
+
* **Close the List (Escape):** Closes the popup.
|
|
902
|
+
* **Move to the Chips (Left Arrow):** With `multiple`, from the start of the input, focuses the last chip. Arrows move between chips.
|
|
903
|
+
* **Remove a Chip (Backspace):** With `multiple`, removes the focused chip, or the last chip from an empty input.
|
|
904
|
+
|
|
905
|
+
### Focus
|
|
906
|
+
|
|
907
|
+
DOM focus stays on the input while the arrow keys move the highlight. Chips take focus only through the arrow keys, not Tab.
|
|
908
|
+
|
|
909
|
+
### Announcements
|
|
910
|
+
|
|
911
|
+
* **Highlighted Option (aria-activedescendant):** Screen readers announce each option on highlight.
|
|
912
|
+
* **Empty Results (status):** Announces a query without matches.
|
|
913
|
+
|
|
914
|
+
### Your Responsibilities
|
|
915
|
+
|
|
916
|
+
* **Name Chips in Multiple Mode (aria-label):** Name the chips, such as "Selected assets", and each remove button by its value, such as "Remove USDC".
|
|
917
|
+
* **Hide Item Icons (alt):** Leave item icon alt text empty. The item text names the item.
|
|
918
|
+
|
|
919
|
+
## Related
|
|
920
|
+
|
|
921
|
+
[Autocomplete](autocomplete.md)
|
|
922
|
+
|
|
923
|
+
Use for free text with suggestions.
|
|
924
|
+
|
|
925
|
+
[Select](select.md)
|
|
926
|
+
|
|
927
|
+
Use for short lists.
|
|
928
|
+
|
|
929
|
+
[Field](field.md)
|
|
930
|
+
|
|
931
|
+
Use for the label and error.
|
|
932
|
+
|
|
933
|
+
[TokenLogo](token-logo.md)
|
|
934
|
+
|
|
935
|
+
Use for token icons in items.
|
|
936
|
+
|
|
937
|
+
[Blockchain Values](../patterns/blockchain-values.md)
|
|
938
|
+
|
|
939
|
+
Covers showing assets and addresses.
|