@tempoxyz/ds 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/AGENTS.md +9 -0
- package/dist/docs/components/accordion.md +489 -0
- package/dist/docs/components/address-card.md +147 -0
- package/dist/docs/components/agent-logo.md +194 -0
- package/dist/docs/components/alert-dialog.md +631 -0
- package/dist/docs/components/alert.md +448 -0
- package/dist/docs/components/amount-input.md +305 -0
- package/dist/docs/components/amount.md +794 -0
- package/dist/docs/components/app-shell.md +559 -0
- package/dist/docs/components/asset-chip.md +294 -0
- package/dist/docs/components/autocomplete.md +619 -0
- package/dist/docs/components/avatar.md +321 -0
- package/dist/docs/components/badge.md +339 -0
- package/dist/docs/components/badged-logo.md +116 -0
- package/dist/docs/components/banner.md +379 -0
- package/dist/docs/components/bar-chart.md +208 -0
- package/dist/docs/components/breadcrumbs.md +380 -0
- package/dist/docs/components/button-group.md +286 -0
- package/dist/docs/components/button.md +650 -0
- package/dist/docs/components/calendar.md +375 -0
- package/dist/docs/components/callout.md +96 -0
- package/dist/docs/components/checkbox-group.md +521 -0
- package/dist/docs/components/checkbox.md +467 -0
- package/dist/docs/components/choice-group.md +516 -0
- package/dist/docs/components/choicebox.md +641 -0
- package/dist/docs/components/code.md +100 -0
- package/dist/docs/components/combobox.md +939 -0
- package/dist/docs/components/container.md +257 -0
- package/dist/docs/components/copy-button.md +642 -0
- package/dist/docs/components/date-picker.md +514 -0
- package/dist/docs/components/dialog.md +1332 -0
- package/dist/docs/components/drawer.md +966 -0
- package/dist/docs/components/empty.md +340 -0
- package/dist/docs/components/field.md +570 -0
- package/dist/docs/components/fieldset.md +398 -0
- package/dist/docs/components/frame.md +434 -0
- package/dist/docs/components/gauge.md +299 -0
- package/dist/docs/components/get-started-visual.md +117 -0
- package/dist/docs/components/grid.md +288 -0
- package/dist/docs/components/hero-visual.md +155 -0
- package/dist/docs/components/hex.md +487 -0
- package/dist/docs/components/icon-tile.md +292 -0
- package/dist/docs/components/identicon.md +371 -0
- package/dist/docs/components/inline.md +233 -0
- package/dist/docs/components/inset.md +225 -0
- package/dist/docs/components/kbd.md +423 -0
- package/dist/docs/components/list-group.md +981 -0
- package/dist/docs/components/loading-dots.md +237 -0
- package/dist/docs/components/menu.md +934 -0
- package/dist/docs/components/native-select.md +204 -0
- package/dist/docs/components/network-logo.md +248 -0
- package/dist/docs/components/number-field.md +543 -0
- package/dist/docs/components/otp-field.md +616 -0
- package/dist/docs/components/pagination.md +516 -0
- package/dist/docs/components/popover.md +544 -0
- package/dist/docs/components/progress.md +388 -0
- package/dist/docs/components/qr.md +314 -0
- package/dist/docs/components/radio-group.md +528 -0
- package/dist/docs/components/secret-value.md +406 -0
- package/dist/docs/components/select.md +751 -0
- package/dist/docs/components/separator.md +379 -0
- package/dist/docs/components/sidebar-menu.md +922 -0
- package/dist/docs/components/skeleton.md +517 -0
- package/dist/docs/components/slider.md +539 -0
- package/dist/docs/components/snippet.md +424 -0
- package/dist/docs/components/spinner.md +216 -0
- package/dist/docs/components/split-bar.md +139 -0
- package/dist/docs/components/split-button.md +464 -0
- package/dist/docs/components/stack.md +299 -0
- package/dist/docs/components/status-chip.md +226 -0
- package/dist/docs/components/status-indicator.md +119 -0
- package/dist/docs/components/status-row.md +174 -0
- package/dist/docs/components/stepper.md +451 -0
- package/dist/docs/components/success-hero.md +157 -0
- package/dist/docs/components/surface.md +639 -0
- package/dist/docs/components/switch.md +472 -0
- package/dist/docs/components/table.md +967 -0
- package/dist/docs/components/tabs.md +627 -0
- package/dist/docs/components/tempo-logo.md +185 -0
- package/dist/docs/components/text-input.md +624 -0
- package/dist/docs/components/textarea.md +352 -0
- package/dist/docs/components/toast.md +535 -0
- package/dist/docs/components/token-logo.md +371 -0
- package/dist/docs/components/token.md +247 -0
- package/dist/docs/components/tooltip.md +490 -0
- package/dist/docs/components/verification-code.md +116 -0
- package/dist/docs/components/visual.md +249 -0
- package/dist/docs/components.md +203 -0
- package/dist/docs/foundations/accessibility.md +377 -0
- package/dist/docs/foundations/agents.md +150 -0
- package/dist/docs/foundations/color.md +522 -0
- package/dist/docs/foundations/content/tone.md +194 -0
- package/dist/docs/foundations/content/voice.md +194 -0
- package/dist/docs/foundations/content/writing-style.md +406 -0
- package/dist/docs/foundations/iconography.md +282 -0
- package/dist/docs/foundations/intent.md +360 -0
- package/dist/docs/foundations/layout.md +508 -0
- package/dist/docs/foundations/linter.md +296 -0
- package/dist/docs/foundations/motion.md +151 -0
- package/dist/docs/foundations/radius-and-padding.md +86 -0
- package/dist/docs/foundations/typography.md +266 -0
- package/dist/docs/index.md +137 -0
- package/dist/docs/introduction/faq.md +132 -0
- package/dist/docs/introduction/getting-started.md +377 -0
- package/dist/docs/patterns/blockchain-values.md +709 -0
- package/dist/docs/patterns/dashboards.md +638 -0
- package/dist/docs/patterns/destructive-actions.md +626 -0
- package/dist/docs/patterns/empty-states.md +612 -0
- package/dist/docs/patterns/errors-and-validation.md +808 -0
- package/dist/docs/patterns/feedback-and-status.md +518 -0
- package/dist/docs/patterns/forms.md +679 -0
- package/dist/docs/patterns/loading.md +630 -0
- package/dist/docs/patterns/navigation.md +397 -0
- package/dist/docs/patterns/payments.md +765 -0
- package/dist/docs/patterns/responsive-layout.md +997 -0
- package/dist/docs/patterns/tables-and-lists.md +964 -0
- package/dist/docs/products/tempo-console.md +671 -0
- package/dist/docs/products/tempo-performance.md +437 -0
- package/dist/docs/products/tempo-wallet.md +438 -0
- package/dist/web/components/OtpField.css +1 -1
- package/dist/web/components/OtpField.d.ts +1 -1
- package/dist/web/components/OtpField.d.ts.map +1 -1
- package/dist/web/components/OtpField.js +3 -4
- package/dist/web/components/OtpField.js.map +1 -1
- package/dist/web/components/OtpField.js.zyzz.json +1 -1
- package/dist/web/index.js.zyzz.json +1 -1
- package/package.json +1 -1
- package/src/web/components/OtpField.tsx +2 -24
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Linter
|
|
2
|
+
|
|
3
|
+
Oxlint rules that check how your app uses Tempo Design System.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The library ships an Oxlint plugin that reports the mistakes types cannot catch, such as an unnamed icon-only [Button](/docs/components/button), an import from an internal path, or a native control that a component replaces.
|
|
8
|
+
|
|
9
|
+
## Set Up the Linter
|
|
10
|
+
|
|
11
|
+
Spread the configuration for your surface, web or mobile, into the lint options of Vite Plus, then run the linter.
|
|
12
|
+
|
|
13
|
+
```ts title="vite.config.ts"
|
|
14
|
+
import { web } from '@tempoxyz/ds/oxlint'
|
|
15
|
+
import { defineConfig } from 'vite-plus'
|
|
16
|
+
|
|
17
|
+
export default defineConfig({ lint: web })
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
vp lint
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To change a severity, spread the rules and override one.
|
|
25
|
+
|
|
26
|
+
```ts title="vite.config.ts"
|
|
27
|
+
import { web } from '@tempoxyz/ds/oxlint'
|
|
28
|
+
import { defineConfig } from 'vite-plus'
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
lint: { ...web, rules: { ...web.rules, 'tds/no-raw-values': 'error' } },
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Without Vite Plus, register both plugins and enable the rules in an Oxlint configuration file.
|
|
36
|
+
|
|
37
|
+
```json title=".oxlintrc.json"
|
|
38
|
+
{
|
|
39
|
+
"jsPlugins": [
|
|
40
|
+
{ "name": "tds", "specifier": "@tempoxyz/ds/oxlint" },
|
|
41
|
+
{ "name": "zyzz", "specifier": "zyzz/oxlint" }
|
|
42
|
+
],
|
|
43
|
+
"rules": {
|
|
44
|
+
"tds/no-cross-surface": ["error", { "surface": "web" }],
|
|
45
|
+
"tds/no-internal-imports": "error",
|
|
46
|
+
"tds/no-raw-values": "warn",
|
|
47
|
+
"tds/prefer-component": "warn",
|
|
48
|
+
"tds/require-accessible-name": "error"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Rules
|
|
54
|
+
|
|
55
|
+
### Import From Public Entrypoints
|
|
56
|
+
|
|
57
|
+
Reports a library import from a path that the package does not publish. The root, icons, mobile, and oxlint entrypoints pass, and so do icon SVG and font files.
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{ "rules": { "tds/no-internal-imports": "error" } }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Do:** Import components from `@tempoxyz/ds` and icons from `@tempoxyz/ds/icons`.
|
|
64
|
+
|
|
65
|
+
````tsx
|
|
66
|
+
```tsx
|
|
67
|
+
import { Spinner } from '@tempoxyz/ds'
|
|
68
|
+
import { Copy } from '@tempoxyz/ds/icons'
|
|
69
|
+
```
|
|
70
|
+
````
|
|
71
|
+
|
|
72
|
+
**Don't:** Import from `src` or `dist`. Internal paths change without a release note.
|
|
73
|
+
|
|
74
|
+
````tsx
|
|
75
|
+
```tsx
|
|
76
|
+
import { Spinner } from '@tempoxyz/ds/src/web'
|
|
77
|
+
// @lint: tds/no-internal-imports: '@tempoxyz/ds/src/web' is not a published entrypoint. Import from '@tempoxyz/ds', '@tempoxyz/ds/mobile', or their `icons` subpaths.
|
|
78
|
+
import { Copy } from '@tempoxyz/ds/dist/icons'
|
|
79
|
+
// @lint: tds/no-internal-imports: '@tempoxyz/ds/dist/icons' is not a published entrypoint. Import from '@tempoxyz/ds', '@tempoxyz/ds/mobile', or their `icons` subpaths.
|
|
80
|
+
```
|
|
81
|
+
````
|
|
82
|
+
|
|
83
|
+
### Stay on One Surface
|
|
84
|
+
|
|
85
|
+
Reports an import from the surface that your app does not render. Without a surface option, it reports a file that imports from both surfaces.
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{ "rules": { "tds/no-cross-surface": ["error", { "surface": "web" }] } }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Do:** Import every component and icon of a React Native app from the Mobile entrypoints.
|
|
92
|
+
|
|
93
|
+
````tsx
|
|
94
|
+
```tsx
|
|
95
|
+
import { Toggle } from '@tempoxyz/ds/mobile'
|
|
96
|
+
import { Copy } from '@tempoxyz/ds/mobile/icons'
|
|
97
|
+
```
|
|
98
|
+
````
|
|
99
|
+
|
|
100
|
+
**Don't:** Mix surfaces in one app. Each surface owns its variables, and a Web component does not render in React Native.
|
|
101
|
+
|
|
102
|
+
````tsx
|
|
103
|
+
```tsx
|
|
104
|
+
import { Toggle } from '@tempoxyz/ds/mobile'
|
|
105
|
+
import { Switch } from '@tempoxyz/ds'
|
|
106
|
+
// @lint: tds/no-cross-surface: '@tempoxyz/ds' belongs to the web surface, but this app uses the mobile surface.
|
|
107
|
+
```
|
|
108
|
+
````
|
|
109
|
+
|
|
110
|
+
### Name Controls Without Text
|
|
111
|
+
|
|
112
|
+
Reports a library component that renders no text and has no accessible name, such as an icon-only [Button](/docs/components/button) or a [Gauge](/docs/components/gauge).
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{ "rules": { "tds/require-accessible-name": "error" } }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Do:** Name the action in `aria-label`, on the button or on the trigger that renders it.
|
|
119
|
+
|
|
120
|
+
````tsx
|
|
121
|
+
```tsx
|
|
122
|
+
<Button aria-label="Copy address" shape="icon">
|
|
123
|
+
<Copy />
|
|
124
|
+
</Button>
|
|
125
|
+
```
|
|
126
|
+
````
|
|
127
|
+
|
|
128
|
+
**Don't:** Leave an icon-only button or a [Gauge](/docs/components/gauge) unnamed. Screen readers announce only its role.
|
|
129
|
+
|
|
130
|
+
````tsx
|
|
131
|
+
```tsx
|
|
132
|
+
<Button shape="icon">
|
|
133
|
+
<Copy />
|
|
134
|
+
</Button>
|
|
135
|
+
// @lint: tds/require-accessible-name: 'Button' renders no text. Name it with `aria-label` or `aria-labelledby`.
|
|
136
|
+
```
|
|
137
|
+
````
|
|
138
|
+
|
|
139
|
+
### Prefer Library Components
|
|
140
|
+
|
|
141
|
+
Warns on a native element that a library component replaces, such as a button, a checkbox, a dialog, or a table. Elements in a render prop pass, and an allow list skips the elements you name.
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{ "rules": { "tds/prefer-component": ["warn", { "allow": ["table"] }] } }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Do:** Use [Checkbox](/docs/components/checkbox) and [Button](/docs/components/button), which bring Tempo states, focus rings, and motion.
|
|
148
|
+
|
|
149
|
+
````tsx
|
|
150
|
+
```tsx
|
|
151
|
+
<Checkbox defaultChecked />
|
|
152
|
+
<Button variant="secondary">Cancel</Button>
|
|
153
|
+
```
|
|
154
|
+
````
|
|
155
|
+
|
|
156
|
+
**Don't:** Restyle a native control that the library already ships.
|
|
157
|
+
|
|
158
|
+
````tsx
|
|
159
|
+
```tsx
|
|
160
|
+
<input defaultChecked type="checkbox" />
|
|
161
|
+
// @lint: tds/prefer-component: Use 'Checkbox' from '@tempoxyz/ds' instead of <input>.
|
|
162
|
+
<button type="button">Cancel</button>
|
|
163
|
+
// @lint: tds/prefer-component: Use 'Button' from '@tempoxyz/ds' instead of <button>.
|
|
164
|
+
```
|
|
165
|
+
````
|
|
166
|
+
|
|
167
|
+
### Style With Tokens
|
|
168
|
+
|
|
169
|
+
Warns on a raw color, length, or font family in an inline style. A value that reads a custom property passes.
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{ "rules": { "tds/no-raw-values": "warn" } }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Do:** Set colors and spacing with tokens in a `style` definition.
|
|
176
|
+
|
|
177
|
+
````tsx
|
|
178
|
+
```tsx
|
|
179
|
+
namespace styles {
|
|
180
|
+
export const card = style({ padding: '16' })
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
;<div {...styles.card()} />
|
|
184
|
+
```
|
|
185
|
+
````
|
|
186
|
+
|
|
187
|
+
**Don't:** Hardcode colors and lengths in inline styles. They do not follow the scheme or the token scale.
|
|
188
|
+
|
|
189
|
+
````tsx
|
|
190
|
+
```tsx
|
|
191
|
+
<div style={{ color: '#000', padding: 16 }} />
|
|
192
|
+
// @lint: tds/no-raw-values: 'color' sets the raw value '#000'. Use a token through a Zyzz style instead.
|
|
193
|
+
// @lint: tds/no-raw-values: 'padding' sets the raw value 16. Use a token through a Zyzz style instead.
|
|
194
|
+
```
|
|
195
|
+
````
|
|
196
|
+
|
|
197
|
+
## Zyzz Rules
|
|
198
|
+
|
|
199
|
+
Both configurations also turn on the rules of the Zyzz plugin, which check style definitions and their use.
|
|
200
|
+
|
|
201
|
+
### Merge Styling Props Into the Style
|
|
202
|
+
|
|
203
|
+
Reports a className or style prop that would overwrite a style spread.
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{ "rules": { "zyzz/no-conflicting-props": "error" } }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Do:** Pass the caller's class into the style call, which merges it.
|
|
210
|
+
|
|
211
|
+
````tsx
|
|
212
|
+
```tsx
|
|
213
|
+
<div {...styles.card({ className: props.className })} />
|
|
214
|
+
```
|
|
215
|
+
````
|
|
216
|
+
|
|
217
|
+
**Don't:** Set a class beside a style spread. One overwrites the other.
|
|
218
|
+
|
|
219
|
+
````tsx
|
|
220
|
+
```tsx
|
|
221
|
+
<div className="card" {...styles.card()} />
|
|
222
|
+
// @lint: zyzz/no-conflicting-props: Pass 'className' into the Zyzz style call to merge styling props.
|
|
223
|
+
```
|
|
224
|
+
````
|
|
225
|
+
|
|
226
|
+
### Remove Unused Styles
|
|
227
|
+
|
|
228
|
+
Warns on a style in a styles namespace that nothing applies.
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{ "rules": { "zyzz/no-unused": "warn" } }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Do:** Keep only the styles that the module applies.
|
|
235
|
+
|
|
236
|
+
````tsx
|
|
237
|
+
```tsx
|
|
238
|
+
namespace styles {
|
|
239
|
+
export const card = style({ padding: '16' })
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
;<div {...styles.card()} />
|
|
243
|
+
```
|
|
244
|
+
````
|
|
245
|
+
|
|
246
|
+
**Don't:** Leave a style that nothing applies. It still ships in the stylesheet.
|
|
247
|
+
|
|
248
|
+
````tsx
|
|
249
|
+
```tsx
|
|
250
|
+
namespace styles {
|
|
251
|
+
export const card = style({ padding: '16' })
|
|
252
|
+
|
|
253
|
+
export const legacy = style({ padding: '8' })
|
|
254
|
+
// @lint: zyzz/no-unused: Style 'styles.legacy' is never used.
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
````
|
|
258
|
+
|
|
259
|
+
### Write Scalar Declarations
|
|
260
|
+
|
|
261
|
+
Reports a declaration whose value is not a string, a number, or a fallback array.
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{ "rules": { "zyzz/valid-styles": "error" } }
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Do:** Set each side with its own property.
|
|
268
|
+
|
|
269
|
+
````tsx
|
|
270
|
+
```tsx
|
|
271
|
+
style({ paddingTop: '8' })
|
|
272
|
+
```
|
|
273
|
+
````
|
|
274
|
+
|
|
275
|
+
**Don't:** Nest an object inside a declaration.
|
|
276
|
+
|
|
277
|
+
````tsx
|
|
278
|
+
```tsx
|
|
279
|
+
style({ padding: { top: '8' } })
|
|
280
|
+
// @lint: zyzz/valid-styles: CSS declarations require scalar values or fallback arrays.
|
|
281
|
+
```
|
|
282
|
+
````
|
|
283
|
+
|
|
284
|
+
## Related
|
|
285
|
+
|
|
286
|
+
[Agents](/docs/foundations/agents)
|
|
287
|
+
|
|
288
|
+
Covers the rules that coding agents follow and the checks they run.
|
|
289
|
+
|
|
290
|
+
[Accessibility](/docs/foundations/accessibility)
|
|
291
|
+
|
|
292
|
+
Covers the accessible names that the linter checks.
|
|
293
|
+
|
|
294
|
+
[Getting Started](/docs/introduction/getting-started)
|
|
295
|
+
|
|
296
|
+
Covers the install and the Zyzz setup that the linter builds on.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Motion
|
|
2
|
+
|
|
3
|
+
Easing curves, durations, and reduced-motion rules for state changes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Motion in Tempo shows where something came from, confirms a press, and marks what is new. It is short, eases out, and never delays input, both in components and in anything you style yourself.
|
|
8
|
+
|
|
9
|
+
## Easing
|
|
10
|
+
|
|
11
|
+
Three ease-out curves cover interface motion, so each response starts at full speed. Use them by name instead of the browser default or a custom curve.
|
|
12
|
+
|
|
13
|
+
* `ease.snappy`: `cubic-bezier(0.23, 1, 0.32, 1)`
|
|
14
|
+
* `ease.spring`: `cubic-bezier(0.32, 0.72, 0, 1)`
|
|
15
|
+
* `ease.overshoot`: `cubic-bezier(0.34, 1.36, 0.64, 1)`
|
|
16
|
+
|
|
17
|
+
* **Snappy (ease.snappy):** Short changes, such as hover, focus, presses, popovers, and menus.
|
|
18
|
+
* **Overshoot (ease.overshoot):** Only physical feedback, such as switch thumbs and check marks. A dialog or menu would wobble.
|
|
19
|
+
* **Spring (ease.spring):** Larger travel, such as dialogs, drawers, toasts, and tabs.
|
|
20
|
+
* **Constant Rate (linear):** Continuous indicators only, such as [Spinner](/docs/components/spinner), which would pulse with easing.
|
|
21
|
+
|
|
22
|
+
## Durations
|
|
23
|
+
|
|
24
|
+
Small state changes finish fastest, overlays that travel farther run longer, and every overlay leaves faster than it enters.
|
|
25
|
+
|
|
26
|
+
### Micro Interactions
|
|
27
|
+
|
|
28
|
+
* **Press (100ms in, 160ms out):** Buttons scale down slightly and return on release.
|
|
29
|
+
* **Item Highlight (120ms):** Menu, select, and combobox items highlight.
|
|
30
|
+
* **Hover, Focus, and Color (160ms):** Buttons, tabs, and checkboxes change color.
|
|
31
|
+
* **Check Indicators (200ms):** Checkbox and radio indicators overshoot slightly.
|
|
32
|
+
* **Switch Thumb (240ms):** The switch thumb slides with a slight overshoot.
|
|
33
|
+
* **Selection Indicator (240ms):** The tabs indicator slides to the selected tab.
|
|
34
|
+
|
|
35
|
+
### Overlays and Content
|
|
36
|
+
|
|
37
|
+
* **Tooltip (160ms in, 100ms out):** Tooltips fade in, and leave faster than they enter.
|
|
38
|
+
* **Popover and Menu (200ms in, 140ms out):** Popovers and menus grow from their trigger.
|
|
39
|
+
* **Select and Combobox List (240ms in, 150ms out):** Lists open on the spring curve and close on snappy.
|
|
40
|
+
* **Expanding Content (240ms in, 180ms out):** Accordion panels expand and collapse.
|
|
41
|
+
* **Dialog (280ms in, 180ms out):** Dialogs enter over a fading backdrop.
|
|
42
|
+
* **Drawer and Toast (320ms in, 200 to 240ms out):** Drawers and toasts travel farthest and run longest.
|
|
43
|
+
|
|
44
|
+
## Guidelines
|
|
45
|
+
|
|
46
|
+
### Animate Every State Change
|
|
47
|
+
|
|
48
|
+
Give every state change a transition, from hover and focus to checked, disabled, and invalid states. Animate overlays, toasts, expanding content, and changing values in and out.
|
|
49
|
+
|
|
50
|
+
* **Press:** Scale the control to `scale.press` (0.98).
|
|
51
|
+
* **Popover and Menu:** Fade and grow from `scale.enter` (0.96).
|
|
52
|
+
* **Dialog and Drawer:** Fade the backdrop and slide or scale the panel.
|
|
53
|
+
* **Value Change:** Fade or slide the new value in.
|
|
54
|
+
|
|
55
|
+
### Use Transitions for State, Keyframes for Feedback
|
|
56
|
+
|
|
57
|
+
A transition reverses from its current point when the state flips back, so a quick hover in and out never jumps. Keep keyframes for feedback that plays once.
|
|
58
|
+
|
|
59
|
+
* **State Changes (transition):** Hover, press, checked, and open states, such as the switch thumb.
|
|
60
|
+
* **One-Shot Feedback (keyframes):** The 360ms nudge of an invalid [TextInput](/docs/components/text-input) or [OtpField](/docs/components/otp-field), and the 240ms pop of a [CopyButton](/docs/components/copy-button) check.
|
|
61
|
+
|
|
62
|
+
### Animate Transform and Opacity
|
|
63
|
+
|
|
64
|
+
Animate transforms, opacity, colors, shadows, and outlines, which change without a new layout. Animate size only when no transform produces the effect, as the components below do.
|
|
65
|
+
|
|
66
|
+
**Do:** Scale a pressed control to `scale: 'press'` with `ease.snappy`.
|
|
67
|
+
|
|
68
|
+
**Don't:** Animate `width`, `height`, or `margin` when a transform produces the same effect.
|
|
69
|
+
|
|
70
|
+
* **Accordion (height):** Panels grow to a measured height, not a transform.
|
|
71
|
+
* **SidebarMenu (height):** Nested items grow as a group expands.
|
|
72
|
+
* **Progress (width):** The indicator grows and keeps its rounded ends.
|
|
73
|
+
* **Tabs (size):** The indicator stretches to match each tab.
|
|
74
|
+
* **Switch (width):** The pressed thumb stretches to keep its round ends.
|
|
75
|
+
* **Toast (height):** Toasts shrink as their stack collapses.
|
|
76
|
+
|
|
77
|
+
### Never Delay Input
|
|
78
|
+
|
|
79
|
+
Controls respond on the first frame of a press. Don't hold an action until an animation finishes, and don't block the next interaction during an exit animation.
|
|
80
|
+
|
|
81
|
+
**Do:** Use short transitions that respond on the first frame, such as the library's press feedback.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<MotionDemo kind="press" />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Don't:** Make the reader wait for an animation to finish before they can act.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<MotionDemo kind="slow" />
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Authoring Motion
|
|
94
|
+
|
|
95
|
+
Set each curve and duration by its token, and pair each transition with a reduced-motion override that removes movement and keeps color changes.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { style } from '@tempoxyz/ds'
|
|
99
|
+
|
|
100
|
+
namespace styles {
|
|
101
|
+
export const row = style({
|
|
102
|
+
transitionDuration: '160',
|
|
103
|
+
transitionProperty: 'background-color, scale',
|
|
104
|
+
transitionTimingFunction: 'snappy',
|
|
105
|
+
selectors: {
|
|
106
|
+
'&:active': { scale: 'press' },
|
|
107
|
+
'&:hover': { backgroundColor: 'container.regular' },
|
|
108
|
+
},
|
|
109
|
+
'@media (prefers-reduced-motion: reduce)': {
|
|
110
|
+
transitionProperty: 'background-color',
|
|
111
|
+
selectors: { '&:active': { scale: 'none !custom' } },
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
* **Durations (transitionDuration):** Name a duration in ms, such as `'160'`.
|
|
118
|
+
* **Curves (transitionTimingFunction):** Name a curve, such as `'snappy'`.
|
|
119
|
+
* **Keyframes (vars.ease):** A keyframe shorthand reads its curve from `vars`.
|
|
120
|
+
|
|
121
|
+
## Reduced Motion
|
|
122
|
+
|
|
123
|
+
When the system asks for reduced motion, components remove movement and scaling, and keep instant changes or brief opacity fades. Apply the same rule in your own styles, and honor Reduce Motion on iOS and Android.
|
|
124
|
+
|
|
125
|
+
### What Components Change
|
|
126
|
+
|
|
127
|
+
* **Pressable Controls:** Buttons, surfaces, and other pressable controls stop scaling and keep their color transitions.
|
|
128
|
+
* **Overlays:** Popovers, menus, dialogs, and toasts fade in place, including the narrow-screen dialog sheet.
|
|
129
|
+
* **Moving Indicators:** The tabs indicator and the switch thumb jump straight to their final position.
|
|
130
|
+
* **Loading Indicators:** Spinners stop rotating, skeletons stop their sweep, and loading dots stop pulsing.
|
|
131
|
+
* **Feedback:** [CopyButton](/docs/components/copy-button) skips its pop, and invalid fields skip their nudge.
|
|
132
|
+
|
|
133
|
+
## Accessibility
|
|
134
|
+
|
|
135
|
+
[Accessibility](/docs/foundations/accessibility#motion) sets the limits for flashing and for content that moves on its own.
|
|
136
|
+
|
|
137
|
+
* **Never Motion Alone (Field.Error):** Never convey information through motion alone. Pair a nudge on an invalid field with an error message.
|
|
138
|
+
|
|
139
|
+
## Related
|
|
140
|
+
|
|
141
|
+
[Loading](/docs/patterns/loading)
|
|
142
|
+
|
|
143
|
+
Covers spinners, skeletons, and progress.
|
|
144
|
+
|
|
145
|
+
[Feedback and Status](/docs/patterns/feedback-and-status)
|
|
146
|
+
|
|
147
|
+
Covers toasts and confirmations.
|
|
148
|
+
|
|
149
|
+
[Accessibility](/docs/foundations/accessibility)
|
|
150
|
+
|
|
151
|
+
Covers reduced motion and other preferences.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Radius and Padding
|
|
2
|
+
|
|
3
|
+
How corner radius and padding pair, from fields to modals.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Corners in Tempo are squircles that ease into each edge. Each kind of element has its own radius, from fields and buttons up to modals, and the radius stays the same at every size of that element.
|
|
8
|
+
|
|
9
|
+
Padding keeps content clear of the curve. Boxes and modals pad by their own radius, and corners step down the scale as layers nest.
|
|
10
|
+
|
|
11
|
+
## Scale
|
|
12
|
+
|
|
13
|
+
* **Fields, Buttons, and Alerts (xs):** A 12px corner at every size, padded by at least 16px.
|
|
14
|
+
* **Boxes and Tiles (sm):** A 16px corner, padded by 16px, as in a list group.
|
|
15
|
+
* **Small Modals (md):** A 24px corner, padded by 24px, for one decision.
|
|
16
|
+
* **Medium and Large Modals (lg):** A 32px corner, padded by 32px, for longer tasks.
|
|
17
|
+
* **Pills (full):** Icon buttons, avatars, and token chips.
|
|
18
|
+
|
|
19
|
+
**Do:** Pad a corner by at least its radius, so content sits clear of the curve.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<RadiusDemo kind="padded" />
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Don't:** Pad a container by less than its radius.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<RadiusDemo kind="cramped" />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Squircles
|
|
32
|
+
|
|
33
|
+
Every corner is a squircle where the browser supports it, and a round corner of the same radius everywhere else.
|
|
34
|
+
|
|
35
|
+
* **Squircle (corner-shape):** Supporting browsers draw each radius token as a squircle.
|
|
36
|
+
* **Fallback (border-radius):** Other browsers draw the same token as a round corner.
|
|
37
|
+
* **Circles and Pills (full):** Full radius stays round, so circles keep their shape.
|
|
38
|
+
|
|
39
|
+
To keep your own circle or pill round, set the round corner shape beside the full radius.
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { style } from '@tempoxyz/ds'
|
|
43
|
+
|
|
44
|
+
namespace styles {
|
|
45
|
+
export const badge = style({ borderRadius: 'full', cornerShape: 'round' })
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Nested Corners
|
|
50
|
+
|
|
51
|
+
A layer inside another takes a smaller radius: a modal at 32px holds boxes at 16px, which hold fields at 12px.
|
|
52
|
+
|
|
53
|
+
**Do:** Step the radius down at each layer, from modal to box to field.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<RadiusDemo kind="nested" />
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Don't:** Repeat the outer radius on the layers inside it.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<RadiusDemo kind="repeated" />
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Corner Controls
|
|
66
|
+
|
|
67
|
+
* **Close and Back Buttons (First line):** Align with the title beside them, not with the corner.
|
|
68
|
+
|
|
69
|
+
## Bleed
|
|
70
|
+
|
|
71
|
+
* **Edge-Aligned Controls (Up to the padding):** Lines a text button's label up with the content edge.
|
|
72
|
+
* **Full-Bleed Content (Exactly the padding):** Lets rows and tables reach both edges of the box.
|
|
73
|
+
|
|
74
|
+
## Related
|
|
75
|
+
|
|
76
|
+
[Layout](/docs/foundations/layout)
|
|
77
|
+
|
|
78
|
+
Covers the radius, spacing, and shadow scales.
|
|
79
|
+
|
|
80
|
+
[Surface](/docs/components/surface)
|
|
81
|
+
|
|
82
|
+
Use for padded boxes and cards.
|
|
83
|
+
|
|
84
|
+
[Dialog](/docs/components/dialog)
|
|
85
|
+
|
|
86
|
+
Use for modals.
|