@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,543 @@
|
|
|
1
|
+
# NumberField
|
|
2
|
+
|
|
3
|
+
A numeric input with increment and decrement buttons.
|
|
4
|
+
|
|
5
|
+
[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/NumberField.tsx)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
NumberField renders a numeric text input with decrement and increment buttons, for quantities adjusted in small steps.
|
|
10
|
+
|
|
11
|
+
## Examples
|
|
12
|
+
|
|
13
|
+
### Basic
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { NumberField } from '@tempoxyz/ds'
|
|
17
|
+
|
|
18
|
+
export function Demo() {
|
|
19
|
+
return (
|
|
20
|
+
<NumberField.Root defaultValue={3}>
|
|
21
|
+
<NumberField.Group>
|
|
22
|
+
<NumberField.Decrement />
|
|
23
|
+
<NumberField.Input aria-label="Quantity" />
|
|
24
|
+
<NumberField.Increment />
|
|
25
|
+
</NumberField.Group>
|
|
26
|
+
</NumberField.Root>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/NumberField/Basic.tsx)
|
|
32
|
+
|
|
33
|
+
### Min
|
|
34
|
+
|
|
35
|
+
Set `min` and `max` on `NumberField.Root` to bound the value.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { NumberField, style } from '@tempoxyz/ds'
|
|
39
|
+
|
|
40
|
+
export const fill = true
|
|
41
|
+
function Example(
|
|
42
|
+
props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
|
|
43
|
+
Pick<NumberField.Group.Props, 'invalid'>,
|
|
44
|
+
) {
|
|
45
|
+
const { invalid, ...root } = props
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<NumberField.Root {...root}>
|
|
49
|
+
<NumberField.Group invalid={invalid}>
|
|
50
|
+
<NumberField.Decrement />
|
|
51
|
+
<NumberField.Input aria-label="Quantity" />
|
|
52
|
+
<NumberField.Increment />
|
|
53
|
+
</NumberField.Group>
|
|
54
|
+
</NumberField.Root>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function Demo() {
|
|
59
|
+
return (
|
|
60
|
+
<div {...styles.grid()}>
|
|
61
|
+
<Example defaultValue={0} min={0} />
|
|
62
|
+
<Example defaultValue={10} max={10} />
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
namespace styles {
|
|
68
|
+
export const grid = style({
|
|
69
|
+
alignItems: 'start',
|
|
70
|
+
display: 'grid',
|
|
71
|
+
gap: '12',
|
|
72
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
|
|
73
|
+
maxWidth: '520px !custom',
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/NumberField/Min.tsx)
|
|
79
|
+
|
|
80
|
+
### Invalid
|
|
81
|
+
|
|
82
|
+
Set `invalid` on `NumberField.Group` to mark the value as rejected.
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { NumberField, style } from '@tempoxyz/ds'
|
|
86
|
+
|
|
87
|
+
export const fill = true
|
|
88
|
+
function Example(
|
|
89
|
+
props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
|
|
90
|
+
Pick<NumberField.Group.Props, 'invalid'>,
|
|
91
|
+
) {
|
|
92
|
+
const { invalid, ...root } = props
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<NumberField.Root {...root}>
|
|
96
|
+
<NumberField.Group invalid={invalid}>
|
|
97
|
+
<NumberField.Decrement />
|
|
98
|
+
<NumberField.Input aria-label="Quantity" />
|
|
99
|
+
<NumberField.Increment />
|
|
100
|
+
</NumberField.Group>
|
|
101
|
+
</NumberField.Root>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function Demo() {
|
|
106
|
+
return (
|
|
107
|
+
<div {...styles.grid()}>
|
|
108
|
+
<Example defaultValue={5} invalid />
|
|
109
|
+
</div>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
namespace styles {
|
|
114
|
+
export const grid = style({
|
|
115
|
+
alignItems: 'start',
|
|
116
|
+
display: 'grid',
|
|
117
|
+
gap: '12',
|
|
118
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
|
|
119
|
+
maxWidth: '520px !custom',
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/NumberField/Invalid.tsx)
|
|
125
|
+
|
|
126
|
+
### Disabled
|
|
127
|
+
|
|
128
|
+
Set `disabled` on `NumberField.Root` to make the field unavailable.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { NumberField, style } from '@tempoxyz/ds'
|
|
132
|
+
|
|
133
|
+
export const fill = true
|
|
134
|
+
function Example(
|
|
135
|
+
props: Pick<NumberField.Root.Props, 'defaultValue' | 'disabled' | 'max' | 'min' | 'step'> &
|
|
136
|
+
Pick<NumberField.Group.Props, 'invalid'>,
|
|
137
|
+
) {
|
|
138
|
+
const { invalid, ...root } = props
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<NumberField.Root {...root}>
|
|
142
|
+
<NumberField.Group invalid={invalid}>
|
|
143
|
+
<NumberField.Decrement />
|
|
144
|
+
<NumberField.Input aria-label="Quantity" />
|
|
145
|
+
<NumberField.Increment />
|
|
146
|
+
</NumberField.Group>
|
|
147
|
+
</NumberField.Root>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function Demo() {
|
|
152
|
+
return (
|
|
153
|
+
<div {...styles.grid()}>
|
|
154
|
+
<Example defaultValue={5} disabled />
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
namespace styles {
|
|
160
|
+
export const grid = style({
|
|
161
|
+
alignItems: 'start',
|
|
162
|
+
display: 'grid',
|
|
163
|
+
gap: '12',
|
|
164
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr)) !custom',
|
|
165
|
+
maxWidth: '520px !custom',
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/NumberField/Disabled.tsx)
|
|
171
|
+
|
|
172
|
+
## Anatomy
|
|
173
|
+
|
|
174
|
+
Import the component and assemble its parts.
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { NumberField } from '@tempoxyz/ds'
|
|
178
|
+
|
|
179
|
+
<NumberField.Root>
|
|
180
|
+
<NumberField.Group>
|
|
181
|
+
<NumberField.Decrement />
|
|
182
|
+
<NumberField.Input />
|
|
183
|
+
<NumberField.Increment />
|
|
184
|
+
</NumberField.Group>
|
|
185
|
+
</NumberField.Root>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Guidelines
|
|
189
|
+
|
|
190
|
+
### When to Use
|
|
191
|
+
|
|
192
|
+
* Enter a whole number that people nudge up or down, such as webhook retry attempts or block confirmations.
|
|
193
|
+
* Set a bounded count, such as seats on a team plan or API keys per project.
|
|
194
|
+
|
|
195
|
+
### When Not to Use
|
|
196
|
+
|
|
197
|
+
* Use [AmountInput](/docs/components/amount-input) for token and fiat amounts.
|
|
198
|
+
* Use [TextInput](/docs/components/text-input) for codes and identifiers that look numeric, such as a chain ID or a postal code.
|
|
199
|
+
* Use [Slider](/docs/components/slider) when an approximate position matters more than the exact number.
|
|
200
|
+
* Use [ChoiceGroup](/docs/components/choice-group) or [Select](/docs/components/select) when only a few values are valid, such as 1, 5, or 10 minutes.
|
|
201
|
+
|
|
202
|
+
### State the Bounds and the Unit
|
|
203
|
+
|
|
204
|
+
Set `min` and `max`, and state them in `Field.Description`, such as Between 0 and 10. Typed input does not show the range.
|
|
205
|
+
|
|
206
|
+
Name the unit in the label, such as Timeout (seconds), or add it to the value with `format`. Format large numbers with `format` and `locale`, not hand-written separators.
|
|
207
|
+
|
|
208
|
+
**Do:** Name the unit in the label and the range in the description.
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
/**
|
|
212
|
+
* Do example for "State the Bounds and the Unit" on the NumberField page.
|
|
213
|
+
* Name the unit in the label and the range in the description.
|
|
214
|
+
* @module
|
|
215
|
+
*/
|
|
216
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
217
|
+
|
|
218
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
219
|
+
export function Demo() {
|
|
220
|
+
return (
|
|
221
|
+
<Field.Root {...styles.field()}>
|
|
222
|
+
<Field.Label>Block confirmations</Field.Label>
|
|
223
|
+
<NumberField.Root defaultValue={2} max={12} min={1} {...styles.number()}>
|
|
224
|
+
<NumberField.Group>
|
|
225
|
+
<NumberField.Decrement />
|
|
226
|
+
<NumberField.Input />
|
|
227
|
+
<NumberField.Increment />
|
|
228
|
+
</NumberField.Group>
|
|
229
|
+
</NumberField.Root>
|
|
230
|
+
<Field.Description>Between 1 and 12.</Field.Description>
|
|
231
|
+
</Field.Root>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
namespace styles {
|
|
236
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
237
|
+
|
|
238
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
239
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Don't:** Leave people to find the bounds by stepping.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
/**
|
|
247
|
+
* Don't example for "State the Bounds and the Unit" on the NumberField page.
|
|
248
|
+
* Don't leave people to find the bounds by stepping.
|
|
249
|
+
* @module
|
|
250
|
+
*/
|
|
251
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
252
|
+
|
|
253
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
254
|
+
export function Demo() {
|
|
255
|
+
return (
|
|
256
|
+
<Field.Root {...styles.field()}>
|
|
257
|
+
<Field.Label>Block confirmations</Field.Label>
|
|
258
|
+
<NumberField.Root defaultValue={2} max={12} min={1} {...styles.number()}>
|
|
259
|
+
<NumberField.Group>
|
|
260
|
+
<NumberField.Decrement />
|
|
261
|
+
<NumberField.Input />
|
|
262
|
+
<NumberField.Increment />
|
|
263
|
+
</NumberField.Group>
|
|
264
|
+
</NumberField.Root>
|
|
265
|
+
</Field.Root>
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
namespace styles {
|
|
270
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
271
|
+
|
|
272
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
273
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Size the Field to the Number
|
|
278
|
+
|
|
279
|
+
`NumberField.Root` fills its container. Set a `maxWidth` that fits the longest value, so the steppers stay close to the digits.
|
|
280
|
+
|
|
281
|
+
**Do:** Size the field for a few digits and state the range below it.
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
/**
|
|
285
|
+
* Do example for "Size the Field to the Number" on the NumberField page.
|
|
286
|
+
* Size the field for a few digits and state the range below it.
|
|
287
|
+
* @module
|
|
288
|
+
*/
|
|
289
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
290
|
+
|
|
291
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
292
|
+
export function Demo() {
|
|
293
|
+
return (
|
|
294
|
+
<Field.Root {...styles.field()}>
|
|
295
|
+
<Field.Label>Retry attempts</Field.Label>
|
|
296
|
+
<NumberField.Root defaultValue={3} max={10} min={0} {...styles.number()}>
|
|
297
|
+
<NumberField.Group>
|
|
298
|
+
<NumberField.Decrement />
|
|
299
|
+
<NumberField.Input />
|
|
300
|
+
<NumberField.Increment />
|
|
301
|
+
</NumberField.Group>
|
|
302
|
+
</NumberField.Root>
|
|
303
|
+
<Field.Description>Between 0 and 10.</Field.Description>
|
|
304
|
+
</Field.Root>
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
namespace styles {
|
|
309
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
310
|
+
|
|
311
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
312
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Don't:** Stretch a one-digit count across the form.
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
/**
|
|
320
|
+
* Don't example for "Size the Field to the Number" on the NumberField page.
|
|
321
|
+
* Don't stretch a one-digit count across the form.
|
|
322
|
+
* @module
|
|
323
|
+
*/
|
|
324
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
325
|
+
|
|
326
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
327
|
+
export function Demo() {
|
|
328
|
+
return (
|
|
329
|
+
<Field.Root {...styles.field()}>
|
|
330
|
+
<Field.Label>Retry attempts</Field.Label>
|
|
331
|
+
<NumberField.Root defaultValue={3} max={10} min={0}>
|
|
332
|
+
<NumberField.Group>
|
|
333
|
+
<NumberField.Decrement />
|
|
334
|
+
<NumberField.Input />
|
|
335
|
+
<NumberField.Increment />
|
|
336
|
+
</NumberField.Group>
|
|
337
|
+
</NumberField.Root>
|
|
338
|
+
</Field.Root>
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
namespace styles {
|
|
343
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Pick Steps People Expect
|
|
348
|
+
|
|
349
|
+
Set `step` to the increment the value moves in, such as 5 seconds for a timeout. Add `snapOnStep` to snap typed values to a multiple of the step. If a value has no natural step and spans a wide range, typing is faster than stepping.
|
|
350
|
+
|
|
351
|
+
**Do:** Step a timeout in fives and say so in the description.
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
/**
|
|
355
|
+
* Do example for "Pick Steps People Expect" on the NumberField page.
|
|
356
|
+
* Step a timeout in fives and say so in the description.
|
|
357
|
+
* @module
|
|
358
|
+
*/
|
|
359
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
360
|
+
|
|
361
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
362
|
+
export function Demo() {
|
|
363
|
+
return (
|
|
364
|
+
<Field.Root {...styles.field()}>
|
|
365
|
+
<Field.Label>Timeout (seconds)</Field.Label>
|
|
366
|
+
<NumberField.Root defaultValue={30} max={60} min={5} step={5} {...styles.number()}>
|
|
367
|
+
<NumberField.Group>
|
|
368
|
+
<NumberField.Decrement />
|
|
369
|
+
<NumberField.Input />
|
|
370
|
+
<NumberField.Increment />
|
|
371
|
+
</NumberField.Group>
|
|
372
|
+
</NumberField.Root>
|
|
373
|
+
<Field.Description>Between 5 and 60, in steps of 5.</Field.Description>
|
|
374
|
+
</Field.Root>
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
namespace styles {
|
|
379
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
380
|
+
|
|
381
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
382
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Don't:** Step by 1 through a range that people set in fives.
|
|
387
|
+
|
|
388
|
+
```tsx
|
|
389
|
+
/**
|
|
390
|
+
* Don't example for "Pick Steps People Expect" on the NumberField page.
|
|
391
|
+
* Don't step by 1 through a range that people set in fives.
|
|
392
|
+
* @module
|
|
393
|
+
*/
|
|
394
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
395
|
+
|
|
396
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
397
|
+
export function Demo() {
|
|
398
|
+
return (
|
|
399
|
+
<Field.Root {...styles.field()}>
|
|
400
|
+
<Field.Label>Timeout (seconds)</Field.Label>
|
|
401
|
+
<NumberField.Root defaultValue={31} max={60} min={5} {...styles.number()}>
|
|
402
|
+
<NumberField.Group>
|
|
403
|
+
<NumberField.Decrement />
|
|
404
|
+
<NumberField.Input />
|
|
405
|
+
<NumberField.Increment />
|
|
406
|
+
</NumberField.Group>
|
|
407
|
+
</NumberField.Root>
|
|
408
|
+
<Field.Description>Between 5 and 60.</Field.Description>
|
|
409
|
+
</Field.Root>
|
|
410
|
+
)
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
namespace styles {
|
|
414
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
415
|
+
|
|
416
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
417
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Avoid Silent Clamping
|
|
422
|
+
|
|
423
|
+
A typed value outside `min` and `max` is clamped by default, so a typo such as 100 becomes 10.
|
|
424
|
+
|
|
425
|
+
If a silent change would surprise people, set `allowOutOfRange` and explain the limit in `Field.Error`. Arrow keys and the steppers still clamp.
|
|
426
|
+
|
|
427
|
+
**Do:** Keep the typed value and explain the limit.
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
/**
|
|
431
|
+
* Do example for "Avoid Silent Clamping" on the NumberField page.
|
|
432
|
+
* Keep the typed value and explain the limit.
|
|
433
|
+
* @module
|
|
434
|
+
*/
|
|
435
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
436
|
+
|
|
437
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
438
|
+
export function Demo() {
|
|
439
|
+
return (
|
|
440
|
+
<Field.Root invalid {...styles.field()}>
|
|
441
|
+
<Field.Label>Seats</Field.Label>
|
|
442
|
+
<NumberField.Root allowOutOfRange defaultValue={100} max={10} min={1} {...styles.number()}>
|
|
443
|
+
<NumberField.Group invalid>
|
|
444
|
+
<NumberField.Decrement />
|
|
445
|
+
<NumberField.Input />
|
|
446
|
+
<NumberField.Increment />
|
|
447
|
+
</NumberField.Group>
|
|
448
|
+
</NumberField.Root>
|
|
449
|
+
<Field.Error match>Choose up to 10 seats.</Field.Error>
|
|
450
|
+
</Field.Root>
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
namespace styles {
|
|
455
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
456
|
+
|
|
457
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
458
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Don't:** Silently replace a typed 100 with the maximum of 10.
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
/**
|
|
466
|
+
* Don't example for "Avoid Silent Clamping" on the NumberField page.
|
|
467
|
+
* Don't silently replace a typed 100 with the maximum of 10.
|
|
468
|
+
* @module
|
|
469
|
+
*/
|
|
470
|
+
import { Field, NumberField, style } from '@tempoxyz/ds'
|
|
471
|
+
|
|
472
|
+
/** Renders the static preview, which the guideline card shows inert. */
|
|
473
|
+
export function Demo() {
|
|
474
|
+
return (
|
|
475
|
+
<Field.Root {...styles.field()}>
|
|
476
|
+
<Field.Label>Seats</Field.Label>
|
|
477
|
+
<NumberField.Root defaultValue={10} max={10} min={1} {...styles.number()}>
|
|
478
|
+
<NumberField.Group>
|
|
479
|
+
<NumberField.Decrement />
|
|
480
|
+
<NumberField.Input />
|
|
481
|
+
<NumberField.Increment />
|
|
482
|
+
</NumberField.Group>
|
|
483
|
+
</NumberField.Root>
|
|
484
|
+
</Field.Root>
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
namespace styles {
|
|
489
|
+
export const field = style({ maxWidth: '18rem !custom', width: '100% !custom' })
|
|
490
|
+
|
|
491
|
+
// The root keeps its full width, so a maximum narrows it.
|
|
492
|
+
export const number = style({ maxWidth: '8rem !custom' })
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
## Accessibility
|
|
497
|
+
|
|
498
|
+
The keyboard follows the [WAI-ARIA Authoring Practices spinbutton pattern](https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/).
|
|
499
|
+
|
|
500
|
+
### Semantics
|
|
501
|
+
|
|
502
|
+
* **NumberField.Group (group):** Groups the input and its steppers.
|
|
503
|
+
* **NumberField.Input (textbox):** A text input with a numeric keyboard, announced as a number field.
|
|
504
|
+
* **Animated Digits (aria-hidden):** Screen readers skip them and read only the input's value.
|
|
505
|
+
* **NumberField.Decrement and NumberField.Increment (button):** Labelled "Decrease" and "Increase". They stay out of the tab order, since arrow keys do the same.
|
|
506
|
+
* **Limits (min and max):** A stepper is disabled once the value reaches its limit.
|
|
507
|
+
* **Invalid (data-invalid):** `invalid` on the group only fills it red. It sets no ARIA state.
|
|
508
|
+
|
|
509
|
+
### Keyboard
|
|
510
|
+
|
|
511
|
+
* **Move Focus to the TextInput (Tab):** Focuses the input but skips the stepper buttons.
|
|
512
|
+
* **Step the Value (Up or Down Arrow):** Increases or decreases the value by `step`.
|
|
513
|
+
* **Take a Large Step (Shift+Arrow):** Steps by `largeStep`, which defaults to 10.
|
|
514
|
+
* **Take a Small Step (Alt+Arrow):** Steps by `smallStep`, which defaults to 0.1.
|
|
515
|
+
* **Jump to a Limit (Home or End):** Sets the value to `min` or `max`, when defined.
|
|
516
|
+
|
|
517
|
+
### Size and Motion
|
|
518
|
+
|
|
519
|
+
* **Stepper Size (40px):** Steppers sit 4px inside the 48px field, above the 24px WCAG minimum.
|
|
520
|
+
* **Reduced Motion (reduce):** If the reader prefers reduced motion, the value morph turns off.
|
|
521
|
+
|
|
522
|
+
### Your Responsibilities
|
|
523
|
+
|
|
524
|
+
* **Name the TextInput (aria-label):** Use a field label. Without a visible label, set an `aria-label` such as "Quantity".
|
|
525
|
+
* **Mark Invalid Values (aria-invalid):** Set `invalid` on the field, not the group, and explain the problem in an error message.
|
|
526
|
+
|
|
527
|
+
## Related
|
|
528
|
+
|
|
529
|
+
[AmountInput](/docs/components/amount-input)
|
|
530
|
+
|
|
531
|
+
Use for token and fiat amounts.
|
|
532
|
+
|
|
533
|
+
[TextInput](/docs/components/text-input)
|
|
534
|
+
|
|
535
|
+
Use for codes and identifiers.
|
|
536
|
+
|
|
537
|
+
[Slider](/docs/components/slider)
|
|
538
|
+
|
|
539
|
+
Use for approximate values in a range.
|
|
540
|
+
|
|
541
|
+
[Field](/docs/components/field)
|
|
542
|
+
|
|
543
|
+
Use for labels, descriptions, and errors.
|