@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.
Files changed (210) hide show
  1. package/README.md +7 -6
  2. package/dist/docs/AGENTS.md +12 -0
  3. package/dist/docs/index.md +145 -0
  4. package/dist/docs/marketing/introduction/getting-started.md +241 -0
  5. package/dist/docs/product/components/accordion.md +489 -0
  6. package/dist/docs/product/components/address-card.md +147 -0
  7. package/dist/docs/product/components/agent-logo.md +194 -0
  8. package/dist/docs/product/components/alert-dialog.md +631 -0
  9. package/dist/docs/product/components/alert.md +448 -0
  10. package/dist/docs/product/components/amount-input.md +305 -0
  11. package/dist/docs/product/components/amount.md +794 -0
  12. package/dist/docs/product/components/app-shell.md +559 -0
  13. package/dist/docs/product/components/asset-chip.md +294 -0
  14. package/dist/docs/product/components/autocomplete.md +620 -0
  15. package/dist/docs/product/components/avatar.md +321 -0
  16. package/dist/docs/product/components/badge.md +339 -0
  17. package/dist/docs/product/components/badged-logo.md +116 -0
  18. package/dist/docs/product/components/banner.md +379 -0
  19. package/dist/docs/product/components/bar-chart.md +208 -0
  20. package/dist/docs/product/components/breadcrumbs.md +380 -0
  21. package/dist/docs/product/components/button-group.md +286 -0
  22. package/dist/docs/product/components/button.md +650 -0
  23. package/dist/docs/product/components/calendar.md +375 -0
  24. package/dist/docs/product/components/callout.md +96 -0
  25. package/dist/docs/product/components/checkbox-group.md +521 -0
  26. package/dist/docs/product/components/checkbox.md +467 -0
  27. package/dist/docs/product/components/choice-group.md +516 -0
  28. package/dist/docs/product/components/choicebox.md +641 -0
  29. package/dist/docs/product/components/code.md +100 -0
  30. package/dist/docs/product/components/combobox.md +939 -0
  31. package/dist/docs/product/components/container.md +257 -0
  32. package/dist/docs/product/components/copy-button.md +642 -0
  33. package/dist/docs/product/components/date-picker.md +514 -0
  34. package/dist/docs/product/components/dialog.md +1332 -0
  35. package/dist/docs/product/components/drawer.md +966 -0
  36. package/dist/docs/product/components/empty.md +340 -0
  37. package/dist/docs/product/components/field.md +570 -0
  38. package/dist/docs/product/components/fieldset.md +398 -0
  39. package/dist/docs/product/components/frame.md +434 -0
  40. package/dist/docs/product/components/gauge.md +299 -0
  41. package/dist/docs/product/components/get-started-visual.md +117 -0
  42. package/dist/docs/product/components/grid.md +288 -0
  43. package/dist/docs/product/components/hero-visual.md +155 -0
  44. package/dist/docs/product/components/hex.md +487 -0
  45. package/dist/docs/product/components/icon-tile.md +292 -0
  46. package/dist/docs/product/components/identicon.md +371 -0
  47. package/dist/docs/product/components/inline.md +233 -0
  48. package/dist/docs/product/components/inset.md +225 -0
  49. package/dist/docs/product/components/kbd.md +423 -0
  50. package/dist/docs/product/components/list-group.md +981 -0
  51. package/dist/docs/product/components/loading-dots.md +237 -0
  52. package/dist/docs/product/components/menu.md +934 -0
  53. package/dist/docs/product/components/native-select.md +204 -0
  54. package/dist/docs/product/components/network-logo.md +248 -0
  55. package/dist/docs/product/components/number-field.md +543 -0
  56. package/dist/docs/product/components/otp-field.md +616 -0
  57. package/dist/docs/product/components/pagination.md +516 -0
  58. package/dist/docs/product/components/popover.md +544 -0
  59. package/dist/docs/product/components/progress.md +388 -0
  60. package/dist/docs/product/components/qr.md +314 -0
  61. package/dist/docs/product/components/radio-group.md +528 -0
  62. package/dist/docs/product/components/secret-value.md +406 -0
  63. package/dist/docs/product/components/select.md +751 -0
  64. package/dist/docs/product/components/separator.md +379 -0
  65. package/dist/docs/product/components/sidebar-menu.md +922 -0
  66. package/dist/docs/product/components/skeleton.md +517 -0
  67. package/dist/docs/product/components/slider.md +539 -0
  68. package/dist/docs/product/components/snippet.md +424 -0
  69. package/dist/docs/product/components/spinner.md +216 -0
  70. package/dist/docs/product/components/split-bar.md +139 -0
  71. package/dist/docs/product/components/split-button.md +464 -0
  72. package/dist/docs/product/components/stack.md +299 -0
  73. package/dist/docs/product/components/status-chip.md +226 -0
  74. package/dist/docs/product/components/status-indicator.md +119 -0
  75. package/dist/docs/product/components/status-row.md +174 -0
  76. package/dist/docs/product/components/stepper.md +451 -0
  77. package/dist/docs/product/components/success-hero.md +157 -0
  78. package/dist/docs/product/components/surface.md +639 -0
  79. package/dist/docs/product/components/switch.md +472 -0
  80. package/dist/docs/product/components/table.md +967 -0
  81. package/dist/docs/product/components/tabs.md +627 -0
  82. package/dist/docs/product/components/tempo-logo.md +185 -0
  83. package/dist/docs/product/components/text-input.md +624 -0
  84. package/dist/docs/product/components/textarea.md +352 -0
  85. package/dist/docs/product/components/toast.md +535 -0
  86. package/dist/docs/product/components/token-logo.md +371 -0
  87. package/dist/docs/product/components/token.md +247 -0
  88. package/dist/docs/product/components/tooltip.md +490 -0
  89. package/dist/docs/product/components/verification-code.md +116 -0
  90. package/dist/docs/product/components/visual.md +249 -0
  91. package/dist/docs/product/components.md +203 -0
  92. package/dist/docs/product/foundations/accessibility.md +377 -0
  93. package/dist/docs/product/foundations/agents.md +150 -0
  94. package/dist/docs/product/foundations/color.md +522 -0
  95. package/dist/docs/product/foundations/content/tone.md +194 -0
  96. package/dist/docs/product/foundations/content/voice.md +194 -0
  97. package/dist/docs/product/foundations/content/writing-style.md +406 -0
  98. package/dist/docs/product/foundations/iconography.md +282 -0
  99. package/dist/docs/product/foundations/intent.md +360 -0
  100. package/dist/docs/product/foundations/layout.md +508 -0
  101. package/dist/docs/product/foundations/linter.md +496 -0
  102. package/dist/docs/product/foundations/motion.md +151 -0
  103. package/dist/docs/product/foundations/radius-and-padding.md +86 -0
  104. package/dist/docs/product/foundations/typography.md +266 -0
  105. package/dist/docs/product/introduction/faq.md +133 -0
  106. package/dist/docs/product/introduction/getting-started.md +377 -0
  107. package/dist/docs/product/patterns/blockchain-values.md +709 -0
  108. package/dist/docs/product/patterns/dashboards.md +638 -0
  109. package/dist/docs/product/patterns/destructive-actions.md +626 -0
  110. package/dist/docs/product/patterns/empty-states.md +612 -0
  111. package/dist/docs/product/patterns/errors-and-validation.md +808 -0
  112. package/dist/docs/product/patterns/feedback-and-status.md +518 -0
  113. package/dist/docs/product/patterns/forms.md +679 -0
  114. package/dist/docs/product/patterns/loading.md +630 -0
  115. package/dist/docs/product/patterns/navigation.md +397 -0
  116. package/dist/docs/product/patterns/payments.md +765 -0
  117. package/dist/docs/product/patterns/responsive-layout.md +997 -0
  118. package/dist/docs/product/patterns/tables-and-lists.md +964 -0
  119. package/dist/docs/product/products/tempo-console.md +671 -0
  120. package/dist/docs/product/products/tempo-performance.md +437 -0
  121. package/dist/docs/product/products/tempo-wallet.md +438 -0
  122. package/dist/marketing/index.d.ts +4 -0
  123. package/dist/marketing/index.d.ts.map +1 -0
  124. package/dist/marketing/index.js +4 -0
  125. package/dist/marketing/index.js.map +1 -0
  126. package/dist/marketing/index.js.zyzz.json +1 -0
  127. package/dist/marketing/vars.d.ts +907 -0
  128. package/dist/marketing/vars.d.ts.map +1 -0
  129. package/dist/marketing/vars.js +15 -0
  130. package/dist/marketing/vars.js.map +1 -0
  131. package/dist/marketing/vars.js.zyzz.json +1 -0
  132. package/dist/marketing/zyzz.config.d.ts +4512 -0
  133. package/dist/marketing/zyzz.config.d.ts.map +1 -0
  134. package/dist/marketing/zyzz.config.js +63 -0
  135. package/dist/marketing/zyzz.config.js.map +1 -0
  136. package/dist/marketing/zyzz.config.js.zyzz.json +1 -0
  137. package/dist/oxlint/index.d.ts +12 -1
  138. package/dist/oxlint/index.d.ts.map +1 -1
  139. package/dist/oxlint/index.js +39 -1
  140. package/dist/oxlint/index.js.map +1 -1
  141. package/dist/oxlint/internal/Docs.d.ts +9 -0
  142. package/dist/oxlint/internal/Docs.d.ts.map +1 -0
  143. package/dist/oxlint/internal/Docs.js +15 -0
  144. package/dist/oxlint/internal/Docs.js.map +1 -0
  145. package/dist/oxlint/internal/Imports.d.ts +1 -1
  146. package/dist/oxlint/internal/Imports.d.ts.map +1 -1
  147. package/dist/oxlint/internal/Imports.js +2 -0
  148. package/dist/oxlint/internal/Imports.js.map +1 -1
  149. package/dist/oxlint/internal/Styles.d.ts +40 -0
  150. package/dist/oxlint/internal/Styles.d.ts.map +1 -0
  151. package/dist/oxlint/internal/Styles.js +194 -0
  152. package/dist/oxlint/internal/Styles.js.map +1 -0
  153. package/dist/oxlint/internal/Tokens.d.ts +16 -0
  154. package/dist/oxlint/internal/Tokens.d.ts.map +1 -0
  155. package/dist/oxlint/internal/Tokens.js +39 -0
  156. package/dist/oxlint/internal/Tokens.js.map +1 -0
  157. package/dist/oxlint/rules/NoCrossSurface.d.ts +2 -2
  158. package/dist/oxlint/rules/NoCrossSurface.js +3 -3
  159. package/dist/oxlint/rules/NoCrossSurface.js.map +1 -1
  160. package/dist/oxlint/rules/NoCustomValues.d.ts +11 -0
  161. package/dist/oxlint/rules/NoCustomValues.d.ts.map +1 -0
  162. package/dist/oxlint/rules/NoCustomValues.js +150 -0
  163. package/dist/oxlint/rules/NoCustomValues.js.map +1 -0
  164. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts +11 -0
  165. package/dist/oxlint/rules/NoSingleKeyShortcuts.d.ts.map +1 -0
  166. package/dist/oxlint/rules/NoSingleKeyShortcuts.js +158 -0
  167. package/dist/oxlint/rules/NoSingleKeyShortcuts.js.map +1 -0
  168. package/dist/oxlint/rules/PreferComponent.d.ts +3 -2
  169. package/dist/oxlint/rules/PreferComponent.d.ts.map +1 -1
  170. package/dist/oxlint/rules/PreferComponent.js +11 -4
  171. package/dist/oxlint/rules/PreferComponent.js.map +1 -1
  172. package/dist/oxlint/rules/PreferLayout.d.ts +9 -0
  173. package/dist/oxlint/rules/PreferLayout.d.ts.map +1 -0
  174. package/dist/oxlint/rules/PreferLayout.js +90 -0
  175. package/dist/oxlint/rules/PreferLayout.js.map +1 -0
  176. package/dist/oxlint/rules/PreferProgress.d.ts +9 -0
  177. package/dist/oxlint/rules/PreferProgress.d.ts.map +1 -0
  178. package/dist/oxlint/rules/PreferProgress.js +43 -0
  179. package/dist/oxlint/rules/PreferProgress.js.map +1 -0
  180. package/dist/oxlint/rules/PreferSurface.d.ts +9 -0
  181. package/dist/oxlint/rules/PreferSurface.d.ts.map +1 -0
  182. package/dist/oxlint/rules/PreferSurface.js +55 -0
  183. package/dist/oxlint/rules/PreferSurface.js.map +1 -0
  184. package/dist/oxlint/rules/RequireAccessibleName.d.ts.map +1 -1
  185. package/dist/oxlint/rules/RequireAccessibleName.js +3 -1
  186. package/dist/oxlint/rules/RequireAccessibleName.js.map +1 -1
  187. package/dist/oxlint/rules/RequireScrollRegion.d.ts +11 -0
  188. package/dist/oxlint/rules/RequireScrollRegion.d.ts.map +1 -0
  189. package/dist/oxlint/rules/RequireScrollRegion.js +71 -0
  190. package/dist/oxlint/rules/RequireScrollRegion.js.map +1 -0
  191. package/dist/web/icons/index.js.zyzz.json +1 -0
  192. package/package.json +6 -1
  193. package/src/marketing/README.md +21 -0
  194. package/src/marketing/index.ts +3 -0
  195. package/src/marketing/vars.ts +751 -0
  196. package/src/marketing/zyzz.config.ts +376 -0
  197. package/src/oxlint/index.ts +40 -1
  198. package/src/oxlint/internal/Docs.ts +18 -0
  199. package/src/oxlint/internal/Imports.ts +2 -1
  200. package/src/oxlint/internal/Styles.ts +240 -0
  201. package/src/oxlint/internal/Tokens.ts +43 -0
  202. package/src/oxlint/rules/NoCrossSurface.ts +3 -3
  203. package/src/oxlint/rules/NoCustomValues.ts +170 -0
  204. package/src/oxlint/rules/NoSingleKeyShortcuts.ts +190 -0
  205. package/src/oxlint/rules/PreferComponent.ts +11 -4
  206. package/src/oxlint/rules/PreferLayout.ts +96 -0
  207. package/src/oxlint/rules/PreferProgress.ts +49 -0
  208. package/src/oxlint/rules/PreferSurface.ts +70 -0
  209. package/src/oxlint/rules/RequireAccessibleName.ts +3 -1
  210. package/src/oxlint/rules/RequireScrollRegion.ts +92 -0
@@ -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](amount-input.md) for token and fiat amounts.
198
+ * Use [TextInput](text-input.md) for codes and identifiers that look numeric, such as a chain ID or a postal code.
199
+ * Use [Slider](slider.md) when an approximate position matters more than the exact number.
200
+ * Use [ChoiceGroup](choice-group.md) or [Select](select.md) 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](amount-input.md)
530
+
531
+ Use for token and fiat amounts.
532
+
533
+ [TextInput](text-input.md)
534
+
535
+ Use for codes and identifiers.
536
+
537
+ [Slider](slider.md)
538
+
539
+ Use for approximate values in a range.
540
+
541
+ [Field](field.md)
542
+
543
+ Use for labels, descriptions, and errors.