@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,934 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
Opens a list of actions from a button.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Menu.tsx)
|
|
6
|
+
|
|
7
|
+
Figma: [Navigation/Account Menu](https://www.figma.com/design/yE96kcymnNR88PJp6G1sPs?node-id=5227-3061) (`Menu.Popup`)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Menu renders a button that opens a list of actions and commands. Arrow keys move through the items, and Escape closes the list.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Button, Menu, style } from '@tempoxyz/ds'
|
|
19
|
+
|
|
20
|
+
export function Demo() {
|
|
21
|
+
// The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
|
|
22
|
+
return (
|
|
23
|
+
<div {...styles.row()}>
|
|
24
|
+
<Menu.Root>
|
|
25
|
+
<Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
|
|
26
|
+
<Menu.Popup align="start">
|
|
27
|
+
<Menu.Item>
|
|
28
|
+
Edit
|
|
29
|
+
<Menu.Shortcut>⌘E</Menu.Shortcut>
|
|
30
|
+
</Menu.Item>
|
|
31
|
+
<Menu.Item>Duplicate</Menu.Item>
|
|
32
|
+
<Menu.Separator />
|
|
33
|
+
<Menu.Item>Archive</Menu.Item>
|
|
34
|
+
</Menu.Popup>
|
|
35
|
+
</Menu.Root>
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
namespace styles {
|
|
41
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Basic.tsx)
|
|
46
|
+
|
|
47
|
+
### Size
|
|
48
|
+
|
|
49
|
+
Set `size` on `Menu.Popup` to `small`, `medium` (default), or `large`.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { Button, Menu, style } from '@tempoxyz/ds'
|
|
53
|
+
import { useState } from 'react'
|
|
54
|
+
|
|
55
|
+
export function Demo() {
|
|
56
|
+
const [density, setDensity] = useState('comfortable')
|
|
57
|
+
|
|
58
|
+
// The gallery canvas stretches its children, so the wrapper keeps each trigger at its own width.
|
|
59
|
+
return (
|
|
60
|
+
<div {...styles.row()}>
|
|
61
|
+
{(['small', 'medium', 'large'] as const).map((size) => (
|
|
62
|
+
<Menu.Root key={size}>
|
|
63
|
+
<Menu.Trigger render={<Button size={size} variant="secondary" />}>
|
|
64
|
+
Options ({size})
|
|
65
|
+
</Menu.Trigger>
|
|
66
|
+
<Menu.Popup align="start" size={size}>
|
|
67
|
+
<Menu.Item>
|
|
68
|
+
Edit
|
|
69
|
+
<Menu.Shortcut>⌘E</Menu.Shortcut>
|
|
70
|
+
</Menu.Item>
|
|
71
|
+
<Menu.Item disabled>Duplicate</Menu.Item>
|
|
72
|
+
<Menu.LinkItem href="https://tempo.xyz">Documentation</Menu.LinkItem>
|
|
73
|
+
<Menu.Separator />
|
|
74
|
+
<Menu.CheckboxItem defaultChecked>Show archived</Menu.CheckboxItem>
|
|
75
|
+
<Menu.Group>
|
|
76
|
+
<Menu.GroupLabel>Density</Menu.GroupLabel>
|
|
77
|
+
<Menu.RadioGroup onValueChange={(value) => setDensity(String(value))} value={density}>
|
|
78
|
+
<Menu.RadioItem value="comfortable">Comfortable</Menu.RadioItem>
|
|
79
|
+
<Menu.RadioItem value="compact">Compact</Menu.RadioItem>
|
|
80
|
+
</Menu.RadioGroup>
|
|
81
|
+
</Menu.Group>
|
|
82
|
+
<Menu.Separator />
|
|
83
|
+
<Menu.SubmenuRoot>
|
|
84
|
+
<Menu.SubmenuTrigger>Share</Menu.SubmenuTrigger>
|
|
85
|
+
<Menu.Popup size={size}>
|
|
86
|
+
<Menu.Item>Copy link</Menu.Item>
|
|
87
|
+
<Menu.Item>Email</Menu.Item>
|
|
88
|
+
</Menu.Popup>
|
|
89
|
+
</Menu.SubmenuRoot>
|
|
90
|
+
<Menu.Item intent="negative">Delete</Menu.Item>
|
|
91
|
+
</Menu.Popup>
|
|
92
|
+
</Menu.Root>
|
|
93
|
+
))}
|
|
94
|
+
</div>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
namespace styles {
|
|
99
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Size.tsx)
|
|
104
|
+
|
|
105
|
+
### Intent
|
|
106
|
+
|
|
107
|
+
Set `intent="negative"` on a `Menu.Item` for destructive actions. The default is `default`.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { Button, Menu, style } from '@tempoxyz/ds'
|
|
111
|
+
|
|
112
|
+
export function Demo() {
|
|
113
|
+
// The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
|
|
114
|
+
return (
|
|
115
|
+
<div {...styles.row()}>
|
|
116
|
+
<Menu.Root>
|
|
117
|
+
<Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
|
|
118
|
+
<Menu.Popup align="start">
|
|
119
|
+
<Menu.Item>Edit</Menu.Item>
|
|
120
|
+
<Menu.Separator />
|
|
121
|
+
<Menu.Item intent="negative">Delete</Menu.Item>
|
|
122
|
+
</Menu.Popup>
|
|
123
|
+
</Menu.Root>
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
namespace styles {
|
|
129
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Intent.tsx)
|
|
134
|
+
|
|
135
|
+
### Disabled
|
|
136
|
+
|
|
137
|
+
Set `disabled` on a `Menu.Item` to make it unavailable.
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
import { Button, Menu, style } from '@tempoxyz/ds'
|
|
141
|
+
|
|
142
|
+
export function Demo() {
|
|
143
|
+
// The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
|
|
144
|
+
return (
|
|
145
|
+
<div {...styles.row()}>
|
|
146
|
+
<Menu.Root>
|
|
147
|
+
<Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
|
|
148
|
+
<Menu.Popup align="start">
|
|
149
|
+
<Menu.Item>Edit</Menu.Item>
|
|
150
|
+
<Menu.Item disabled>Duplicate</Menu.Item>
|
|
151
|
+
</Menu.Popup>
|
|
152
|
+
</Menu.Root>
|
|
153
|
+
</div>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
namespace styles {
|
|
158
|
+
export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '12' })
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Disabled.tsx)
|
|
163
|
+
|
|
164
|
+
## Anatomy
|
|
165
|
+
|
|
166
|
+
Import the component and assemble its parts.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { Menu } from '@tempoxyz/ds'
|
|
170
|
+
|
|
171
|
+
<Menu.Root>
|
|
172
|
+
<Menu.Trigger />
|
|
173
|
+
<Menu.Popup>
|
|
174
|
+
<Menu.Item>
|
|
175
|
+
<Menu.Shortcut />
|
|
176
|
+
</Menu.Item>
|
|
177
|
+
<Menu.LinkItem />
|
|
178
|
+
<Menu.CheckboxItem />
|
|
179
|
+
<Menu.Separator />
|
|
180
|
+
<Menu.Group>
|
|
181
|
+
<Menu.GroupLabel />
|
|
182
|
+
<Menu.RadioGroup>
|
|
183
|
+
<Menu.RadioItem />
|
|
184
|
+
</Menu.RadioGroup>
|
|
185
|
+
</Menu.Group>
|
|
186
|
+
<Menu.SubmenuRoot>
|
|
187
|
+
<Menu.SubmenuTrigger />
|
|
188
|
+
<Menu.Popup />
|
|
189
|
+
</Menu.SubmenuRoot>
|
|
190
|
+
</Menu.Popup>
|
|
191
|
+
</Menu.Root>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Guidelines
|
|
195
|
+
|
|
196
|
+
### When to Use
|
|
197
|
+
|
|
198
|
+
* Offer actions on one object, such as Send to address, Copy address, Rename, and Remove address.
|
|
199
|
+
* If a toolbar, card header, or table row has more than three secondary actions, put them behind an icon button.
|
|
200
|
+
* Change view options in place with `Menu.CheckboxItem` (Show archived) or `Menu.RadioItem` (density). These items keep the menu open on click.
|
|
201
|
+
|
|
202
|
+
### When Not to Use
|
|
203
|
+
|
|
204
|
+
* Use [Select](select.md) or [Combobox](combobox.md) to choose a form value, such as a token or network.
|
|
205
|
+
* Use [Tabs](tabs.md) or [ChoiceGroup](choice-group.md) to switch views with every option visible.
|
|
206
|
+
* Use a [Button](button.md) for one or two actions.
|
|
207
|
+
* Use [SplitButton](split-button.md) when one action is the clear default.
|
|
208
|
+
* Use [SidebarMenu](sidebar-menu.md) or links for navigation. `Menu.LinkItem` suits an occasional link among actions, such as View on explorer.
|
|
209
|
+
* Use [Popover](popover.md) for text or form controls. A menu holds only items.
|
|
210
|
+
|
|
211
|
+
### Order Items by Frequency
|
|
212
|
+
|
|
213
|
+
Put the most frequent action at the top. Keep the same items in the same order wherever the menu appears, such as on every table row.
|
|
214
|
+
|
|
215
|
+
**Do:** Put the most frequent action at the top.
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
/** Do example for "Order Items by Frequency" on the Menu page: put the most frequent action at the top. @module */
|
|
219
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
220
|
+
|
|
221
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
222
|
+
export function Demo() {
|
|
223
|
+
return (
|
|
224
|
+
<div {...styles.popup()}>
|
|
225
|
+
<div {...styles.item()}>Send to address</div>
|
|
226
|
+
<div {...styles.item()}>Copy address</div>
|
|
227
|
+
<div {...styles.item()}>Rename</div>
|
|
228
|
+
</div>
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
namespace styles {
|
|
233
|
+
export const item = variants({
|
|
234
|
+
base: {
|
|
235
|
+
alignItems: 'center',
|
|
236
|
+
borderRadius: 'xs',
|
|
237
|
+
color: 'content.primary',
|
|
238
|
+
columnGap: '8',
|
|
239
|
+
display: 'flex',
|
|
240
|
+
minHeight: '40',
|
|
241
|
+
paddingInline: '12',
|
|
242
|
+
typography: 'body.b2Strong',
|
|
243
|
+
},
|
|
244
|
+
defaultVariants: { state: 'default' },
|
|
245
|
+
variants: {
|
|
246
|
+
state: {
|
|
247
|
+
default: {},
|
|
248
|
+
disabled: { opacity: 'disabled' },
|
|
249
|
+
negative: { color: 'content.negative' },
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
export const popup = style({
|
|
255
|
+
backgroundColor: 'background.elevated',
|
|
256
|
+
borderRadius: 'sm',
|
|
257
|
+
boxShadow: 'regular',
|
|
258
|
+
boxSizing: 'border-box',
|
|
259
|
+
minWidth: '14rem !custom',
|
|
260
|
+
padding: '12',
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Don't:** Lead with a rare action, such as Rename.
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
/**
|
|
269
|
+
* Don't example for "Order Items by Frequency" on the Menu page.
|
|
270
|
+
* Don't lead with a rare action, such as Rename.
|
|
271
|
+
* @module
|
|
272
|
+
*/
|
|
273
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
274
|
+
|
|
275
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
276
|
+
export function Demo() {
|
|
277
|
+
return (
|
|
278
|
+
<div {...styles.popup()}>
|
|
279
|
+
<div {...styles.item()}>Rename</div>
|
|
280
|
+
<div {...styles.item()}>Copy address</div>
|
|
281
|
+
<div {...styles.item()}>Send to address</div>
|
|
282
|
+
</div>
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
namespace styles {
|
|
287
|
+
export const item = variants({
|
|
288
|
+
base: {
|
|
289
|
+
alignItems: 'center',
|
|
290
|
+
borderRadius: 'xs',
|
|
291
|
+
color: 'content.primary',
|
|
292
|
+
columnGap: '8',
|
|
293
|
+
display: 'flex',
|
|
294
|
+
minHeight: '40',
|
|
295
|
+
paddingInline: '12',
|
|
296
|
+
typography: 'body.b2Strong',
|
|
297
|
+
},
|
|
298
|
+
defaultVariants: { state: 'default' },
|
|
299
|
+
variants: {
|
|
300
|
+
state: {
|
|
301
|
+
default: {},
|
|
302
|
+
disabled: { opacity: 'disabled' },
|
|
303
|
+
negative: { color: 'content.negative' },
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
export const popup = style({
|
|
309
|
+
backgroundColor: 'background.elevated',
|
|
310
|
+
borderRadius: 'sm',
|
|
311
|
+
boxShadow: 'regular',
|
|
312
|
+
boxSizing: 'border-box',
|
|
313
|
+
minWidth: '14rem !custom',
|
|
314
|
+
padding: '12',
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Group Related Items
|
|
320
|
+
|
|
321
|
+
Wrap related items in `Menu.Group` and divide groups with `Menu.Separator`. If the items alone do not explain the group, add a `Menu.GroupLabel`, such as Density.
|
|
322
|
+
|
|
323
|
+
Keep a menu to about seven items. A `Menu.SubmenuRoot` hides its items, so keep frequent actions at the top level and nest only one level deep.
|
|
324
|
+
|
|
325
|
+
**Do:** Divide groups with a separator, and label a group whose items need it.
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
/**
|
|
329
|
+
* Do example for "Group Related Items" on the Menu page.
|
|
330
|
+
* Divide groups with a separator, and label a group whose items need it.
|
|
331
|
+
* @module
|
|
332
|
+
*/
|
|
333
|
+
import { Check } from '@tempoxyz/ds/icons'
|
|
334
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
335
|
+
|
|
336
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
337
|
+
export function Demo() {
|
|
338
|
+
return (
|
|
339
|
+
<div {...styles.popup()}>
|
|
340
|
+
<div {...styles.item()}>Send to address</div>
|
|
341
|
+
<div {...styles.item()}>Copy address</div>
|
|
342
|
+
<div {...styles.separator()} />
|
|
343
|
+
<div {...styles.groupLabel()}>Density</div>
|
|
344
|
+
<div {...styles.item()}>
|
|
345
|
+
Comfortable
|
|
346
|
+
<Check {...styles.check()} />
|
|
347
|
+
</div>
|
|
348
|
+
<div {...styles.item()}>Compact</div>
|
|
349
|
+
</div>
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
namespace styles {
|
|
354
|
+
export const check = style({ fontSize: '16', marginInlineStart: 'auto !custom' })
|
|
355
|
+
|
|
356
|
+
export const groupLabel = style({
|
|
357
|
+
color: 'content.secondary',
|
|
358
|
+
paddingBlock: '8',
|
|
359
|
+
paddingInline: '12',
|
|
360
|
+
typography: 'body.b3',
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
export const item = variants({
|
|
364
|
+
base: {
|
|
365
|
+
alignItems: 'center',
|
|
366
|
+
borderRadius: 'xs',
|
|
367
|
+
color: 'content.primary',
|
|
368
|
+
columnGap: '8',
|
|
369
|
+
display: 'flex',
|
|
370
|
+
minHeight: '40',
|
|
371
|
+
paddingInline: '12',
|
|
372
|
+
typography: 'body.b2Strong',
|
|
373
|
+
},
|
|
374
|
+
defaultVariants: { state: 'default' },
|
|
375
|
+
variants: {
|
|
376
|
+
state: {
|
|
377
|
+
default: {},
|
|
378
|
+
disabled: { opacity: 'disabled' },
|
|
379
|
+
negative: { color: 'content.negative' },
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
export const popup = style({
|
|
385
|
+
backgroundColor: 'background.elevated',
|
|
386
|
+
borderRadius: 'sm',
|
|
387
|
+
boxShadow: 'regular',
|
|
388
|
+
boxSizing: 'border-box',
|
|
389
|
+
minWidth: '14rem !custom',
|
|
390
|
+
padding: '12',
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
export const separator = style({
|
|
394
|
+
backgroundColor: 'container.strong',
|
|
395
|
+
height: '1px !custom',
|
|
396
|
+
marginBlock: '8',
|
|
397
|
+
marginInline: '12',
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Don't:** Mix actions and view options in one flat list.
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
/**
|
|
406
|
+
* Don't example for "Group Related Items" on the Menu page.
|
|
407
|
+
* Don't mix actions and view options in one flat list.
|
|
408
|
+
* @module
|
|
409
|
+
*/
|
|
410
|
+
import { Check } from '@tempoxyz/ds/icons'
|
|
411
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
412
|
+
|
|
413
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
414
|
+
export function Demo() {
|
|
415
|
+
return (
|
|
416
|
+
<div {...styles.popup()}>
|
|
417
|
+
<div {...styles.item()}>Send to address</div>
|
|
418
|
+
<div {...styles.item()}>
|
|
419
|
+
Comfortable
|
|
420
|
+
<Check {...styles.check()} />
|
|
421
|
+
</div>
|
|
422
|
+
<div {...styles.item()}>Copy address</div>
|
|
423
|
+
<div {...styles.item()}>Compact</div>
|
|
424
|
+
</div>
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
namespace styles {
|
|
429
|
+
export const check = style({ fontSize: '16', marginInlineStart: 'auto !custom' })
|
|
430
|
+
|
|
431
|
+
export const item = variants({
|
|
432
|
+
base: {
|
|
433
|
+
alignItems: 'center',
|
|
434
|
+
borderRadius: 'xs',
|
|
435
|
+
color: 'content.primary',
|
|
436
|
+
columnGap: '8',
|
|
437
|
+
display: 'flex',
|
|
438
|
+
minHeight: '40',
|
|
439
|
+
paddingInline: '12',
|
|
440
|
+
typography: 'body.b2Strong',
|
|
441
|
+
},
|
|
442
|
+
defaultVariants: { state: 'default' },
|
|
443
|
+
variants: {
|
|
444
|
+
state: {
|
|
445
|
+
default: {},
|
|
446
|
+
disabled: { opacity: 'disabled' },
|
|
447
|
+
negative: { color: 'content.negative' },
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
export const popup = style({
|
|
453
|
+
backgroundColor: 'background.elevated',
|
|
454
|
+
borderRadius: 'sm',
|
|
455
|
+
boxShadow: 'regular',
|
|
456
|
+
boxSizing: 'border-box',
|
|
457
|
+
minWidth: '14rem !custom',
|
|
458
|
+
padding: '12',
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Put Destructive Items Last
|
|
464
|
+
|
|
465
|
+
A keyboard open focuses the first item, so a destructive item at the top is one Enter press away. Place it last, after a `Menu.Separator`, with `intent="negative"`.
|
|
466
|
+
|
|
467
|
+
**Do:** Put destructive items at the end, after a separator.
|
|
468
|
+
|
|
469
|
+
```tsx
|
|
470
|
+
/**
|
|
471
|
+
* Do example for "Put Destructive Items Last" on the Menu page.
|
|
472
|
+
* Put destructive items at the end, after a separator.
|
|
473
|
+
* @module
|
|
474
|
+
*/
|
|
475
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
476
|
+
|
|
477
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
478
|
+
export function Demo() {
|
|
479
|
+
return (
|
|
480
|
+
<div {...styles.popup()}>
|
|
481
|
+
<div {...styles.item()}>Send to address</div>
|
|
482
|
+
<div {...styles.item()}>Copy address</div>
|
|
483
|
+
<div {...styles.item()}>Rename</div>
|
|
484
|
+
<div {...styles.separator()} />
|
|
485
|
+
<div {...styles.item({ intent: 'negative' })}>Remove address</div>
|
|
486
|
+
</div>
|
|
487
|
+
)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
namespace styles {
|
|
491
|
+
export const item = variants({
|
|
492
|
+
base: {
|
|
493
|
+
alignItems: 'center',
|
|
494
|
+
borderRadius: 'xs',
|
|
495
|
+
color: 'content.primary',
|
|
496
|
+
display: 'flex',
|
|
497
|
+
minHeight: '40',
|
|
498
|
+
paddingInline: '12',
|
|
499
|
+
typography: 'body.b2Strong',
|
|
500
|
+
},
|
|
501
|
+
defaultVariants: { intent: 'default' },
|
|
502
|
+
variants: {
|
|
503
|
+
intent: {
|
|
504
|
+
default: {},
|
|
505
|
+
negative: { color: 'content.negative' },
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
export const popup = style({
|
|
511
|
+
backgroundColor: 'background.elevated',
|
|
512
|
+
borderRadius: 'sm',
|
|
513
|
+
boxShadow: 'regular',
|
|
514
|
+
boxSizing: 'border-box',
|
|
515
|
+
minWidth: '14rem !custom',
|
|
516
|
+
padding: '12',
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
export const separator = style({
|
|
520
|
+
backgroundColor: 'container.strong',
|
|
521
|
+
height: '1px !custom',
|
|
522
|
+
marginBlock: '8',
|
|
523
|
+
marginInline: '12',
|
|
524
|
+
})
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Don't:** Lead with a destructive item, or mix it in with routine actions.
|
|
529
|
+
|
|
530
|
+
```tsx
|
|
531
|
+
/**
|
|
532
|
+
* Don't example for "Put Destructive Items Last" on the Menu page.
|
|
533
|
+
* Don't lead with a destructive item, or mix it in with routine actions.
|
|
534
|
+
* @module
|
|
535
|
+
*/
|
|
536
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
537
|
+
|
|
538
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
539
|
+
export function Demo() {
|
|
540
|
+
return (
|
|
541
|
+
<div {...styles.popup()}>
|
|
542
|
+
<div {...styles.item({ intent: 'negative' })}>Remove address</div>
|
|
543
|
+
<div {...styles.item()}>Send to address</div>
|
|
544
|
+
<div {...styles.item()}>Copy address</div>
|
|
545
|
+
<div {...styles.item()}>Rename</div>
|
|
546
|
+
</div>
|
|
547
|
+
)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
namespace styles {
|
|
551
|
+
export const item = variants({
|
|
552
|
+
base: {
|
|
553
|
+
alignItems: 'center',
|
|
554
|
+
borderRadius: 'xs',
|
|
555
|
+
color: 'content.primary',
|
|
556
|
+
display: 'flex',
|
|
557
|
+
minHeight: '40',
|
|
558
|
+
paddingInline: '12',
|
|
559
|
+
typography: 'body.b2Strong',
|
|
560
|
+
},
|
|
561
|
+
defaultVariants: { intent: 'default' },
|
|
562
|
+
variants: {
|
|
563
|
+
intent: {
|
|
564
|
+
default: {},
|
|
565
|
+
negative: { color: 'content.negative' },
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
})
|
|
569
|
+
|
|
570
|
+
export const popup = style({
|
|
571
|
+
backgroundColor: 'background.elevated',
|
|
572
|
+
borderRadius: 'sm',
|
|
573
|
+
boxShadow: 'regular',
|
|
574
|
+
boxSizing: 'border-box',
|
|
575
|
+
minWidth: '14rem !custom',
|
|
576
|
+
padding: '12',
|
|
577
|
+
})
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
If the action cannot be undone, open an [AlertDialog](alert-dialog.md) from the item and repeat the item's verb on its confirm button:
|
|
582
|
+
|
|
583
|
+
* **Placement:** Render the dialog outside `Menu.Popup`, which unmounts when the menu closes.
|
|
584
|
+
* **State:** Open it from the item's `onClick` with `open` and `onOpenChange`.
|
|
585
|
+
|
|
586
|
+
See [Destructive Actions](../patterns/destructive-actions.md).
|
|
587
|
+
|
|
588
|
+
### Disable Unavailable Items
|
|
589
|
+
|
|
590
|
+
Set `disabled` on an item that is unavailable now, such as Send to address with no funds. The menu keeps its shape. Leave out items that are never available, such as admin actions without the permission.
|
|
591
|
+
|
|
592
|
+
**Do:** Disable an item that is unavailable for now.
|
|
593
|
+
|
|
594
|
+
```tsx
|
|
595
|
+
/**
|
|
596
|
+
* Do example for "Disable Unavailable Items" on the Menu page.
|
|
597
|
+
* Disable an item that is unavailable for now.
|
|
598
|
+
* @module
|
|
599
|
+
*/
|
|
600
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
601
|
+
|
|
602
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
603
|
+
export function Demo() {
|
|
604
|
+
return (
|
|
605
|
+
<div {...styles.popup()}>
|
|
606
|
+
<div {...styles.item({ state: 'disabled' })}>Send to address</div>
|
|
607
|
+
<div {...styles.item()}>Copy address</div>
|
|
608
|
+
<div {...styles.item()}>Rename</div>
|
|
609
|
+
<div {...styles.separator()} />
|
|
610
|
+
<div {...styles.item({ state: 'negative' })}>Remove address</div>
|
|
611
|
+
</div>
|
|
612
|
+
)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
namespace styles {
|
|
616
|
+
export const item = variants({
|
|
617
|
+
base: {
|
|
618
|
+
alignItems: 'center',
|
|
619
|
+
borderRadius: 'xs',
|
|
620
|
+
color: 'content.primary',
|
|
621
|
+
columnGap: '8',
|
|
622
|
+
display: 'flex',
|
|
623
|
+
minHeight: '40',
|
|
624
|
+
paddingInline: '12',
|
|
625
|
+
typography: 'body.b2Strong',
|
|
626
|
+
},
|
|
627
|
+
defaultVariants: { state: 'default' },
|
|
628
|
+
variants: {
|
|
629
|
+
state: {
|
|
630
|
+
default: {},
|
|
631
|
+
disabled: { opacity: 'disabled' },
|
|
632
|
+
negative: { color: 'content.negative' },
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
})
|
|
636
|
+
|
|
637
|
+
export const popup = style({
|
|
638
|
+
backgroundColor: 'background.elevated',
|
|
639
|
+
borderRadius: 'sm',
|
|
640
|
+
boxShadow: 'regular',
|
|
641
|
+
boxSizing: 'border-box',
|
|
642
|
+
minWidth: '14rem !custom',
|
|
643
|
+
padding: '12',
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
export const separator = style({
|
|
647
|
+
backgroundColor: 'container.strong',
|
|
648
|
+
height: '1px !custom',
|
|
649
|
+
marginBlock: '8',
|
|
650
|
+
marginInline: '12',
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**Don't:** Remove an item that returns later. The menu changes shape.
|
|
656
|
+
|
|
657
|
+
```tsx
|
|
658
|
+
/**
|
|
659
|
+
* Don't example for "Disable Unavailable Items" on the Menu page.
|
|
660
|
+
* Don't remove an item that returns later. The menu changes shape.
|
|
661
|
+
* @module
|
|
662
|
+
*/
|
|
663
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
664
|
+
|
|
665
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
666
|
+
export function Demo() {
|
|
667
|
+
return (
|
|
668
|
+
<div {...styles.popup()}>
|
|
669
|
+
<div {...styles.item()}>Copy address</div>
|
|
670
|
+
<div {...styles.item()}>Rename</div>
|
|
671
|
+
<div {...styles.separator()} />
|
|
672
|
+
<div {...styles.item({ state: 'negative' })}>Remove address</div>
|
|
673
|
+
</div>
|
|
674
|
+
)
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
namespace styles {
|
|
678
|
+
export const item = variants({
|
|
679
|
+
base: {
|
|
680
|
+
alignItems: 'center',
|
|
681
|
+
borderRadius: 'xs',
|
|
682
|
+
color: 'content.primary',
|
|
683
|
+
columnGap: '8',
|
|
684
|
+
display: 'flex',
|
|
685
|
+
minHeight: '40',
|
|
686
|
+
paddingInline: '12',
|
|
687
|
+
typography: 'body.b2Strong',
|
|
688
|
+
},
|
|
689
|
+
defaultVariants: { state: 'default' },
|
|
690
|
+
variants: {
|
|
691
|
+
state: {
|
|
692
|
+
default: {},
|
|
693
|
+
disabled: { opacity: 'disabled' },
|
|
694
|
+
negative: { color: 'content.negative' },
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
})
|
|
698
|
+
|
|
699
|
+
export const popup = style({
|
|
700
|
+
backgroundColor: 'background.elevated',
|
|
701
|
+
borderRadius: 'sm',
|
|
702
|
+
boxShadow: 'regular',
|
|
703
|
+
boxSizing: 'border-box',
|
|
704
|
+
minWidth: '14rem !custom',
|
|
705
|
+
padding: '12',
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
export const separator = style({
|
|
709
|
+
backgroundColor: 'container.strong',
|
|
710
|
+
height: '1px !custom',
|
|
711
|
+
marginBlock: '8',
|
|
712
|
+
marginInline: '12',
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
### Show Only Shortcuts You Bind
|
|
718
|
+
|
|
719
|
+
`Menu.Shortcut` displays keys and binds nothing. Add one only if the shortcut also works with the menu closed, and register the key handler yourself.
|
|
720
|
+
|
|
721
|
+
**Do:** Show a shortcut only on an item whose key you bind.
|
|
722
|
+
|
|
723
|
+
```tsx
|
|
724
|
+
/**
|
|
725
|
+
* Do example for "Show Only Shortcuts You Bind" on the Menu page.
|
|
726
|
+
* Show a shortcut only on an item whose key you bind.
|
|
727
|
+
* @module
|
|
728
|
+
*/
|
|
729
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
730
|
+
|
|
731
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
732
|
+
export function Demo() {
|
|
733
|
+
return (
|
|
734
|
+
<div {...styles.popup()}>
|
|
735
|
+
<div {...styles.item()}>Send to address</div>
|
|
736
|
+
<div {...styles.item()}>
|
|
737
|
+
Copy address
|
|
738
|
+
<kbd {...styles.shortcut()}>⌘C</kbd>
|
|
739
|
+
</div>
|
|
740
|
+
<div {...styles.item()}>Rename</div>
|
|
741
|
+
</div>
|
|
742
|
+
)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
namespace styles {
|
|
746
|
+
export const item = variants({
|
|
747
|
+
base: {
|
|
748
|
+
alignItems: 'center',
|
|
749
|
+
borderRadius: 'xs',
|
|
750
|
+
color: 'content.primary',
|
|
751
|
+
columnGap: '8',
|
|
752
|
+
display: 'flex',
|
|
753
|
+
minHeight: '40',
|
|
754
|
+
paddingInline: '12',
|
|
755
|
+
typography: 'body.b2Strong',
|
|
756
|
+
},
|
|
757
|
+
defaultVariants: { state: 'default' },
|
|
758
|
+
variants: {
|
|
759
|
+
state: {
|
|
760
|
+
default: {},
|
|
761
|
+
disabled: { opacity: 'disabled' },
|
|
762
|
+
negative: { color: 'content.negative' },
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
export const popup = style({
|
|
768
|
+
backgroundColor: 'background.elevated',
|
|
769
|
+
borderRadius: 'sm',
|
|
770
|
+
boxShadow: 'regular',
|
|
771
|
+
boxSizing: 'border-box',
|
|
772
|
+
minWidth: '14rem !custom',
|
|
773
|
+
padding: '12',
|
|
774
|
+
})
|
|
775
|
+
|
|
776
|
+
export const shortcut = style({
|
|
777
|
+
color: 'content.secondary',
|
|
778
|
+
marginInlineStart: 'auto !custom',
|
|
779
|
+
paddingInlineStart: '16',
|
|
780
|
+
typography: 'body.b3',
|
|
781
|
+
})
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
**Don't:** Decorate every item with a shortcut that does nothing.
|
|
786
|
+
|
|
787
|
+
```tsx
|
|
788
|
+
/**
|
|
789
|
+
* Don't example for "Show Only Shortcuts You Bind" on the Menu page.
|
|
790
|
+
* Don't decorate every item with a shortcut that does nothing.
|
|
791
|
+
* @module
|
|
792
|
+
*/
|
|
793
|
+
import { style, variants } from '@tempoxyz/ds'
|
|
794
|
+
|
|
795
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
796
|
+
export function Demo() {
|
|
797
|
+
return (
|
|
798
|
+
<div {...styles.popup()}>
|
|
799
|
+
<div {...styles.item()}>
|
|
800
|
+
Send to address
|
|
801
|
+
<kbd {...styles.shortcut()}>⌘S</kbd>
|
|
802
|
+
</div>
|
|
803
|
+
<div {...styles.item()}>
|
|
804
|
+
Copy address
|
|
805
|
+
<kbd {...styles.shortcut()}>⌘C</kbd>
|
|
806
|
+
</div>
|
|
807
|
+
<div {...styles.item()}>
|
|
808
|
+
Rename
|
|
809
|
+
<kbd {...styles.shortcut()}>⌘R</kbd>
|
|
810
|
+
</div>
|
|
811
|
+
</div>
|
|
812
|
+
)
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
namespace styles {
|
|
816
|
+
export const item = variants({
|
|
817
|
+
base: {
|
|
818
|
+
alignItems: 'center',
|
|
819
|
+
borderRadius: 'xs',
|
|
820
|
+
color: 'content.primary',
|
|
821
|
+
columnGap: '8',
|
|
822
|
+
display: 'flex',
|
|
823
|
+
minHeight: '40',
|
|
824
|
+
paddingInline: '12',
|
|
825
|
+
typography: 'body.b2Strong',
|
|
826
|
+
},
|
|
827
|
+
defaultVariants: { state: 'default' },
|
|
828
|
+
variants: {
|
|
829
|
+
state: {
|
|
830
|
+
default: {},
|
|
831
|
+
disabled: { opacity: 'disabled' },
|
|
832
|
+
negative: { color: 'content.negative' },
|
|
833
|
+
},
|
|
834
|
+
},
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
export const popup = style({
|
|
838
|
+
backgroundColor: 'background.elevated',
|
|
839
|
+
borderRadius: 'sm',
|
|
840
|
+
boxShadow: 'regular',
|
|
841
|
+
boxSizing: 'border-box',
|
|
842
|
+
minWidth: '14rem !custom',
|
|
843
|
+
padding: '12',
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
export const shortcut = style({
|
|
847
|
+
color: 'content.secondary',
|
|
848
|
+
marginInlineStart: 'auto !custom',
|
|
849
|
+
paddingInlineStart: '16',
|
|
850
|
+
typography: 'body.b3',
|
|
851
|
+
})
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
## Content
|
|
856
|
+
|
|
857
|
+
### Start Items With a Verb
|
|
858
|
+
|
|
859
|
+
Write a verb, plus an object when the verb is ambiguous: Copy address, Rename, Remove address.
|
|
860
|
+
|
|
861
|
+
### Lead With the Distinctive Word
|
|
862
|
+
|
|
863
|
+
Typing jumps to the item whose label starts with the typed characters. Start labels with different words. If an item's text starts with something else, such as a token symbol, pass `label`.
|
|
864
|
+
|
|
865
|
+
### Name Destructive Items Plainly
|
|
866
|
+
|
|
867
|
+
`intent="negative"` only changes the color. Write a verb that states the loss, such as Remove address or Revoke key.
|
|
868
|
+
|
|
869
|
+
## Accessibility
|
|
870
|
+
|
|
871
|
+
Menu follows the [WAI-ARIA Authoring Practices menu button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/).
|
|
872
|
+
|
|
873
|
+
### Semantics
|
|
874
|
+
|
|
875
|
+
* **Menu.Trigger (button):** Announces a menu popup and its expanded state.
|
|
876
|
+
* **Menu.Popup (menu):** Named by its trigger.
|
|
877
|
+
* **Menu.Item and Menu.LinkItem (menuitem):** Menu items, and link items render real links.
|
|
878
|
+
* **Menu.CheckboxItem and Menu.RadioItem (aria-checked):** Checkable items that report their checked state.
|
|
879
|
+
* **Menu.Group (group):** Named by its group label.
|
|
880
|
+
* **Menu.Separator (separator):** Announced as a divider between groups of items.
|
|
881
|
+
* **Disabled Items (aria-disabled):** Reachable with arrow keys, but never activates.
|
|
882
|
+
* **Menu.Shortcut (kbd):** Displays the keys as text.
|
|
883
|
+
|
|
884
|
+
### Keyboard
|
|
885
|
+
|
|
886
|
+
* **Open the Menu (Enter, Space, or Down Arrow):** Opens the menu from the trigger and focuses the first item.
|
|
887
|
+
* **Move to the Next Item (Down Arrow):** Moves focus to the next item, wrapping from the last item to the first.
|
|
888
|
+
* **Move to the Previous Item (Up Arrow):** Moves focus to the previous item, wrapping from the first item to the last.
|
|
889
|
+
* **Move to the First Item (Home):** Moves focus to the first item.
|
|
890
|
+
* **Move to the Last Item (End):** Moves focus to the last item.
|
|
891
|
+
* **Type to Jump (Any character):** Moves focus to the next item whose label starts with the typed characters.
|
|
892
|
+
* **Activate an Item (Enter):** Activates the focused item. Plain items close the menu. Checkbox and radio items keep it open.
|
|
893
|
+
* **Open a Submenu (Right Arrow):** On a submenu trigger, opens the submenu and focuses its first item.
|
|
894
|
+
* **Close a Submenu (Left Arrow):** In a submenu, closes it and returns focus to its trigger.
|
|
895
|
+
* **Close the Menu (Escape):** Closes the menu and returns focus to the trigger.
|
|
896
|
+
* **Leave the Menu (Tab):** Closes the menu and moves focus onward from it.
|
|
897
|
+
|
|
898
|
+
### Focus
|
|
899
|
+
|
|
900
|
+
* **Opening:** A keyboard open focuses the first item. A click focuses the menu, and arrow keys then move to an item.
|
|
901
|
+
* **Highlight:** One item at a time holds focus and renders highlighted.
|
|
902
|
+
* **Modal (modal):** The default. A press outside closes the menu.
|
|
903
|
+
* **Closing (Escape):** Activating an item, pressing Escape, or pressing outside returns focus to the trigger.
|
|
904
|
+
|
|
905
|
+
### Your Responsibilities
|
|
906
|
+
|
|
907
|
+
* **Name Icon-Only Triggers (aria-label):** Name the object, such as "Actions for Main wallet". The menu inherits the trigger's name.
|
|
908
|
+
* **Keep Links as Links (a):** Use `Menu.LinkItem` for navigation. It keeps link semantics.
|
|
909
|
+
|
|
910
|
+
## Related
|
|
911
|
+
|
|
912
|
+
[SplitButton](split-button.md)
|
|
913
|
+
|
|
914
|
+
Use for a main action with alternatives.
|
|
915
|
+
|
|
916
|
+
[Select](select.md)
|
|
917
|
+
|
|
918
|
+
Use for choosing a form value.
|
|
919
|
+
|
|
920
|
+
[AlertDialog](alert-dialog.md)
|
|
921
|
+
|
|
922
|
+
Use for confirming a destructive item.
|
|
923
|
+
|
|
924
|
+
[Popover](popover.md)
|
|
925
|
+
|
|
926
|
+
Use for anchored content other than actions.
|
|
927
|
+
|
|
928
|
+
[Destructive Actions](../patterns/destructive-actions.md)
|
|
929
|
+
|
|
930
|
+
Covers deleting and revoking.
|
|
931
|
+
|
|
932
|
+
[Tables and Lists](../patterns/tables-and-lists.md)
|
|
933
|
+
|
|
934
|
+
Covers row actions.
|