@antadesign/anta 0.3.25 → 0.3.27

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 (104) hide show
  1. package/README.md +26 -28
  2. package/dist/anta_helpers.d.ts +4 -0
  3. package/dist/anta_helpers.js +17 -3
  4. package/dist/box-types.d.ts +161 -0
  5. package/dist/box-types.js +0 -0
  6. package/dist/bundle.css +1 -1
  7. package/dist/bundle.js +25 -25
  8. package/dist/capture-types.d.ts +156 -0
  9. package/dist/capture-types.js +0 -0
  10. package/dist/components/Box.d.ts +52 -0
  11. package/dist/components/Box.js +55 -0
  12. package/dist/components/Capture.d.ts +39 -0
  13. package/dist/components/Capture.js +36 -0
  14. package/dist/components/capture-props.d.ts +30 -0
  15. package/dist/components/capture-props.js +44 -0
  16. package/dist/elements/a-avatar.css +1 -1
  17. package/dist/elements/a-banner.css +1 -1
  18. package/dist/elements/a-banner.js +4 -4
  19. package/dist/elements/a-box.css +1 -0
  20. package/dist/elements/a-box.d.ts +41 -0
  21. package/dist/elements/a-box.js +584 -0
  22. package/dist/elements/a-button.css +1 -1
  23. package/dist/elements/a-calendar.js +2 -2
  24. package/dist/elements/a-capture.css +1 -0
  25. package/dist/elements/a-capture.d.ts +10 -0
  26. package/dist/elements/a-capture.js +24 -0
  27. package/dist/elements/a-card.css +1 -1
  28. package/dist/elements/a-checkbox.css +1 -1
  29. package/dist/elements/a-checkbox.js +4 -4
  30. package/dist/elements/a-dialog.css +1 -1
  31. package/dist/elements/a-expander.css +1 -1
  32. package/dist/elements/a-expander.js +2 -2
  33. package/dist/elements/a-input-time.css +1 -1
  34. package/dist/elements/a-input-time.js +3 -3
  35. package/dist/elements/a-input.css +1 -1
  36. package/dist/elements/a-input.js +6 -6
  37. package/dist/elements/a-menu-item.css +1 -1
  38. package/dist/elements/a-menu-item.js +3 -3
  39. package/dist/elements/a-menu.css +1 -1
  40. package/dist/elements/a-menu.js +2 -2
  41. package/dist/elements/a-radio-group.js +3 -3
  42. package/dist/elements/a-radio.css +1 -1
  43. package/dist/elements/a-slider.css +1 -1
  44. package/dist/elements/a-slider.js +6 -6
  45. package/dist/elements/a-switch.css +1 -1
  46. package/dist/elements/a-switch.js +2 -2
  47. package/dist/elements/a-tabpanel.js +2 -2
  48. package/dist/elements/a-tabs.css +1 -1
  49. package/dist/elements/a-tabs.js +6 -6
  50. package/dist/elements/a-tag.css +1 -1
  51. package/dist/elements/a-text.css +1 -1
  52. package/dist/elements/a-title.css +1 -1
  53. package/dist/elements/a-toast.js +2 -2
  54. package/dist/elements/a-tooltip.css +1 -1
  55. package/dist/elements/a-tooltip.d.ts +4 -3
  56. package/dist/elements/a-tooltip.js +9 -5
  57. package/dist/elements/capture-input.d.ts +5 -0
  58. package/dist/elements/capture-input.js +609 -0
  59. package/dist/elements/index.d.ts +2 -0
  60. package/dist/elements/index.js +6 -0
  61. package/dist/general_types.d.ts +70 -0
  62. package/dist/index.d.ts +6 -0
  63. package/dist/index.js +4 -0
  64. package/dist/jsx-runtime.d.ts +3 -1
  65. package/docs/accessibility.md +24 -0
  66. package/docs/changelog.md +45 -3
  67. package/docs/colors.md +141 -0
  68. package/docs/comparison.md +463 -28
  69. package/docs/components/avatar.md +364 -0
  70. package/docs/components/banner.md +13 -27
  71. package/docs/components/box.md +354 -0
  72. package/docs/components/breadcrumbs.md +7 -6
  73. package/docs/components/button.md +48 -37
  74. package/docs/components/capture.md +345 -0
  75. package/docs/components/card.md +17 -38
  76. package/docs/components/checkbox.md +16 -39
  77. package/docs/components/dialog.md +14 -36
  78. package/docs/components/expander.md +15 -40
  79. package/docs/components/icon.md +111 -9
  80. package/docs/components/input-autocomplete.md +9 -11
  81. package/docs/components/input-date.md +33 -23
  82. package/docs/components/input-time.md +15 -23
  83. package/docs/components/input.md +27 -76
  84. package/docs/components/loader.md +7 -5
  85. package/docs/components/menu.md +73 -77
  86. package/docs/components/progress.md +10 -14
  87. package/docs/components/radio.md +17 -36
  88. package/docs/components/select-faceted.md +7 -25
  89. package/docs/components/select.md +24 -97
  90. package/docs/components/slider.md +16 -21
  91. package/docs/components/steps.md +38 -8
  92. package/docs/components/switch.md +11 -14
  93. package/docs/components/tabs.md +52 -40
  94. package/docs/components/tag.md +11 -22
  95. package/docs/components/text.md +10 -23
  96. package/docs/components/title.md +7 -8
  97. package/docs/components/toaster.md +6 -3
  98. package/docs/components/tooltip.md +13 -23
  99. package/docs/index.md +6 -3
  100. package/docs/install-config.md +24 -0
  101. package/docs/normalization.md +45 -0
  102. package/docs/packages/stickers.md +56 -0
  103. package/docs/theming.md +270 -0
  104. package/package.json +3 -1
@@ -0,0 +1,354 @@
1
+ # Box
2
+
3
+ `Box` is a DOM container with layout props, overflow states, and browser context
4
+ events. For custom wheel, pointer, and touch handling, use [Capture](./capture.md).
5
+
6
+ ## Display
7
+
8
+ Use `display`, `gap`, and `round` for layout and corners. Numeric lengths use
9
+ pixels; strings accept CSS lengths. A bare `round` fully rounds the corners.
10
+
11
+ ```tsx
12
+ <Box round={8}><span /></Box>
13
+ <Box display="flex" round={8} gap={6}><span /></Box>
14
+ <Box display="grid" round={8} gap="0.5rem" style={{ gridTemplateColumns: '1fr 1fr' }}><span /></Box>
15
+ ```
16
+
17
+ ## Overflow
18
+
19
+ Box reports overflow, clipping, and scrollability as measurements and CSS
20
+ states. Use `observe="size"` to keep CSS states current. `fade` and
21
+ `onMeasureChange` also enable measurement; without these, Box adds no size
22
+ observers.
23
+
24
+ `.edge` is a demo class name. Use your own selector.
25
+
26
+ ```tsx
27
+ <Box observe="size" round={8} className="edge" style={{ width: 150 }}>Content that fits.</Box>
28
+
29
+ <Box observe="size" round={8} className="edge" style={{ width: 150, overflow: 'hidden', whiteSpace: 'nowrap' }}>
30
+ A label too long for this box.
31
+ </Box>
32
+
33
+ <Box observe="size" round={8} className="edge" style={{ width: 150, height: 56, overflowY: 'auto' }}>
34
+ One. Two. Three. Four. Five. Six. Seven. Eight. Nine. Ten.
35
+ </Box>
36
+ ```
37
+
38
+ ```css
39
+ .edge:state(clipped-x) { border-color: var(--border-3-warning); }
40
+ .edge:state(scrollable-y) { border-color: var(--border-3-info); }
41
+ ```
42
+
43
+ ### Fading a clipped edge
44
+
45
+ `fade` masks edges with hidden content and removes the mask as scrolling reveals
46
+ them. `fadeSize` sets its depth. It measures on connection, even off screen.
47
+
48
+ ```tsx
49
+ const TAGS = ['frontend', 'design-system', 'a11y', 'performance']
50
+
51
+ <Box fade fadeSize={32} round display="flex" gap={6} className="fade-demo" style={{ width: 190, overflowX: 'auto' }}>
52
+ {TAGS.map((t) => <Tag key={t} size="small" label={t} />)}
53
+ </Box>
54
+
55
+ <Box fade fadeSize={32} round={8} className="fade-demo" style={{ width: 190, height: 56, overflowY: 'auto' }}>
56
+ One. Two. Three. Four. Five. Six. Seven. Eight. Nine. Ten. Eleven. Twelve.
57
+ </Box>
58
+ ```
59
+
60
+ ```css
61
+ .fade-demo { flex-wrap: nowrap; padding: 10px; border: 1px solid var(--border-4); }
62
+ .fade-demo a-tag { flex: 0 0 auto; }
63
+ ```
64
+
65
+ The mask clips to the padding box. It preserves the Box border, shadows, and
66
+ focus ring when no edge is hidden.
67
+
68
+ To style hidden edges without `fade`, use `observe="size"` and the
69
+ `hidden-start-x`, `hidden-end-x`, `hidden-start-y`, or `hidden-end-y` CSS states.
70
+
71
+ ### Tooltip on clipped content
72
+
73
+ `Tooltip truncatedOnly` shows when Box clips content on either axis, including
74
+ wrapped children.
75
+
76
+ ```tsx
77
+ const TAGS = ['frontend', 'design-system', 'a11y', 'performance']
78
+
79
+ <Box display="flex" round={8} gap={6} className="tag-box" style={{ height: 34 }}>
80
+ {TAGS.map((t) => <Tag key={t} size="small" label={t} />)}
81
+ <Tooltip truncatedOnly>{TAGS.join(' · ')}</Tooltip>
82
+ </Box>
83
+ ```
84
+
85
+ ```css
86
+ .tag-box { flex-wrap: wrap; padding: 6px; overflow: hidden; }
87
+ ```
88
+
89
+ ## Measurements
90
+
91
+ `onMeasureChange` reports one frame after observation starts and when the Box or
92
+ its content changes. `changed` contains changed fields; `current` is the full
93
+ snapshot. Reporting pauses off screen and resumes when Box returns.
94
+
95
+ Resize or scroll the Box to update its measurements.
96
+
97
+ ```tsx title="measurechange"
98
+ const [measurement, setMeasurement] = useState<BoxMeasurement | null>(null)
99
+
100
+ <Box
101
+ round={8}
102
+ className="measure-probe-box"
103
+ onMeasureChange={(_, { current }) => setMeasurement(current)}
104
+ >
105
+ <Text size="small" priority="tertiary">Resize or scroll this Box.</Text>
106
+ <div className="measure-probe-wide">wide content, so both axes overflow</div>
107
+ <div className="measure-probe-wide">and a second line, so the vertical axis does too</div>
108
+ <div className="measure-probe-wide">and a third</div>
109
+ </Box>
110
+
111
+ <div className="measure-probe-readout">
112
+ {Object.entries(measurement ?? {}).map(([field, value]) => (
113
+ <Tag key={field} size="small" label={field} value={String(value)} />
114
+ ))}
115
+ </div>
116
+ ```
117
+
118
+ ```css
119
+ .measure-probe-box {
120
+ resize: both;
121
+ overflow: auto;
122
+ inline-size: 320px;
123
+ block-size: 132px;
124
+ min-inline-size: 120px;
125
+ min-block-size: 64px;
126
+ padding: 10px;
127
+ border: 1px solid var(--border-4);
128
+ }
129
+ .measure-probe-wide { inline-size: 520px; padding-block: 6px; }
130
+ .measure-probe-readout { display: flex; flex-wrap: wrap; gap: 6px; }
131
+ ```
132
+
133
+ See the [measurement fields](#boxmeasurement). Overflow fields map to kebab-case
134
+ CSS states, such as `clippedX` → `:state(clipped-x)`.
135
+
136
+ ## Context
137
+
138
+ `onContextChange` reports theme, focus, and browser context as
139
+ `{ changed, current }`. See the [context fields](#boxcontext). For CSS, use
140
+ `:focus-within`, mode classes, and media queries instead.
141
+
142
+ Switch themes, resize, or zoom to update the preview. The `.light` Box keeps its
143
+ local `mode`; `globalMode` follows the document. Browser and OS versions may be
144
+ frozen, so use `pointer`, `hover`, or feature tests to choose behavior.
145
+
146
+ ```tsx title="contextchange"
147
+ import { useState } from 'react'
148
+ import { Box, Tag, Text, type BoxContext } from '@antadesign/anta'
149
+
150
+ function ScopedContext() {
151
+ const [context, setContext] = useState<BoxContext | null>(null)
152
+
153
+ return (
154
+ <div className="light">
155
+ <Box display="flex" round={8} gap={6} className="context-probe-box"
156
+ onContextChange={(_, { current }) => setContext(current)}>
157
+ <Text size="small" priority="tertiary">inside a .light scope</Text>
158
+ <Tag size="small" tone="brand" label="mode" value={context?.mode ?? '…'} />
159
+ <Tag size="small" label="globalMode" value={context?.globalMode ?? '…'} />
160
+ </Box>
161
+ </div>
162
+ )
163
+ }
164
+ ```
165
+
166
+ ```css
167
+ .context-probe-box {
168
+ flex-wrap: wrap;
169
+ align-items: center;
170
+ padding: 10px;
171
+ border: 1px solid var(--border-4);
172
+ background: var(--bg-1);
173
+ color: var(--text-1);
174
+ }
175
+ ```
176
+
177
+ <a id="canvas"></a>
178
+
179
+ ### Canvas-related styles
180
+
181
+ Use `context.font` and `devicePixelRatio` to match canvas text to the DOM.
182
+ The first line is DOM text; the second is drawn on canvas. Switch themes or
183
+ zoom to update both. `context.inset` also reports border and padding when you
184
+ need to align drawing coordinates with the Box's content edge.
185
+
186
+ Set `ctx.font` before spacing and direction. Box assembles `font.shorthand`
187
+ because `getComputedStyle(element).font` can be empty. Stretch and variant caps
188
+ remain separate fields; percentage stretch is invalid in the shorthand.
189
+
190
+ ```tsx title="canvas"
191
+ const canvasRef = useRef<HTMLCanvasElement>(null)
192
+
193
+ <Box className="canvas-probe"
194
+ onContextChange={(_, { current }) => {
195
+ const canvas = canvasRef.current
196
+ const ctx = canvas?.getContext('2d')
197
+ if (!canvas || !ctx) return
198
+
199
+ const { font, devicePixelRatio: dpr } = current
200
+ canvas.width = canvas.clientWidth * dpr
201
+ canvas.height = canvas.clientHeight * dpr
202
+ ctx.scale(dpr, dpr)
203
+
204
+ ctx.font = font.shorthand
205
+ ctx.letterSpacing = font.letterSpacing
206
+ ctx.wordSpacing = font.wordSpacing
207
+ ctx.direction = font.direction === 'rtl' ? 'rtl' : 'ltr'
208
+ ctx.fillStyle = font.color
209
+
210
+ ctx.fillText('Matches the DOM', 0, font.lineHeight ?? font.size)
211
+ }}
212
+ >
213
+ <span>Matches the DOM</span>
214
+ <canvas ref={canvasRef} aria-label="Canvas text using the Box font and color" />
215
+ </Box>
216
+ ```
217
+
218
+ ```css
219
+ .canvas-probe { width: 100%; font-size: 20px; line-height: 32px; color: var(--text-1); }
220
+ .canvas-probe canvas { display: block; width: 100%; height: 48px; }
221
+ ```
222
+
223
+ ## Component props
224
+
225
+ | Prop | Type | Default | Description |
226
+ |------|------|---------|-------------|
227
+ | `display?` | BoxDisplay | block | Layout model for the host. All other layout, sizing, mask, and shadow properties stay ordinary `className` / `style` CSS on the Box itself. |
228
+ | `fade?` | boolean | — | Fades out every edge that currently hides clipped content, and drops the fade from an edge once the reader scrolls to it. |
229
+ | `fadeSize?` | number \| string | 24 | Depth of the `fade` gradient. A `number` is pixels; a string is any CSS length. |
230
+ | `gap?` | number \| string | — | Gap between children, matching the CSS `gap` property. A `number` is pixels; a string is any CSS length or two-value gap (`'1rem'`, `'8px 16px'`). Applies while the Box is a flex or grid container. |
231
+ | `observe?` | 'size' \| 'context' \| 'all' | — | What the Box watches, when a handler is not what turns it on. `'size'` keeps the overflow CSS states (`:state(clipped-x)`, `:state(scrollable-y)`, …) current — reach for it when your own CSS is the only reader. `'context'` and `'all'` are there for symmetry; passing `onMeasureChange` or `onContextChange` already turns the matching half on. |
232
+ | `onContextChange?` | (event, detail) => void | — | Fired after Box's browser and local rendering context changes. `detail` contains the changed fields and a full current snapshot. |
233
+ | `onMeasureChange?` | (event, detail) => void | — | Fired after Box geometry or its content-overflow state changes. `detail` contains the changed fields and a full current snapshot. |
234
+ | `round?` | boolean \| number \| string | — | Fully-round corners (`border-radius: 999px`, clamped to the box). Pass a `number` (px) or a CSS length string (`'1rem'`) for a custom radius. Omit for square corners. |
235
+
236
+ ### BoxMeasurement
237
+
238
+ | Field | Type | Default | Description |
239
+ |------|------|---------|-------------|
240
+ | `clientHeight` | number | — | |
241
+ | `clientWidth` | number | — | Padding-box dimensions, matching the browser's `clientWidth` / `clientHeight`. |
242
+ | `clippedX` | boolean | — | The exceeded content is visually clipped on this axis. |
243
+ | `clippedY` | boolean | — | |
244
+ | `height` | number | — | |
245
+ | `hiddenEndX` | boolean | — | |
246
+ | `hiddenEndY` | boolean | — | |
247
+ | `hiddenStartX` | boolean | — | Clipped content sits past this specific edge, in logical writing-mode terms. A clipped box that has not been scrolled hides content past its end edge only; scroll it to the end and the hidden content moves to the start. These drive the `fade` mask. |
248
+ | `hiddenStartY` | boolean | — | |
249
+ | `overflowX` | boolean | — | Content exceeds the padding box on this axis, regardless of CSS overflow. |
250
+ | `overflowY` | boolean | — | |
251
+ | `scrollableX` | boolean | — | The exceeded content can be scrolled by the reader on this axis. |
252
+ | `scrollableY` | boolean | — | |
253
+ | `scrollHeight` | number | — | |
254
+ | `scrollLeft` | number | — | Current scroll offset, matching `scrollLeft` / `scrollTop`. |
255
+ | `scrollTop` | number | — | |
256
+ | `scrollWidth` | number | — | Full scrollable-content dimensions, matching `scrollWidth` / `scrollHeight`. |
257
+ | `width` | number | — | Border-box width and height in CSS pixels. |
258
+
259
+ ### BoxContext
260
+
261
+ | Field | Type | Default | Description |
262
+ |------|------|---------|-------------|
263
+ | `backgroundColor` | string | — | Resolved `background-color`. Needed when the box's content is drawn somewhere else — an offscreen canvas, a worker, an export — where the box's own background is not behind it. |
264
+ | `browser` | BoxBrowser | — | Browser family. |
265
+ | `browserVersion` | number | — | Browser major version, or `0` when unknown. Minor and patch digits are frozen by every engine, so only the major number is reported. |
266
+ | `devicePixelRatio` | number | — | `window.devicePixelRatio`: CSS pixels per device pixel. `1` on a standard display, `2` on most Retina screens, and a fraction under OS or browser zoom. Live — it re-reports on zoom and when the window moves to a monitor with a different density. |
267
+ | `focusWithin` | boolean | — | Whether focus is on the box or any of its descendants, read from the native `:focus-within`. For CSS, use that pseudo-class directly; this field is for logic that cannot query the DOM. |
268
+ | `font` | BoxFont | — | Resolved text style, ready to hand to a canvas 2D context. |
269
+ | `globalMode` | BoxMode | — | Mode on `<html>`, independent of an enclosing local scope. |
270
+ | `hover` | boolean | — | Whether ordinary hover interaction is available. |
271
+ | `inset` | BoxInset | — | Padding and border widths, for placing content inside the border box. |
272
+ | `mobile` | boolean | — | Whether the browser reports a mobile device. |
273
+ | `mode` | BoxMode | — | Closest scoped Anta mode. A local `.light` can override a dark document. |
274
+ | `os` | BoxOS | — | Operating-system family. |
275
+ | `osVersion` | number | — | Operating-system major version, or `0` when the browser withholds it. Browsers freeze this: every engine reports macOS as `10.15.7` and Windows 11 as `10.0`, so only Android and iOS carry a real number. Treat it as a hint, never as a gate. |
276
+ | `pointer` | BoxPointer | — | Most precise available primary pointer. |
277
+ | `reducedMotion` | boolean | — | Whether the reader asks for reduced motion. |
278
+ | `systemAppearance` | BoxMode | — | Browser / operating-system color preference, independent of Anta classes. |
279
+
280
+ ### BoxFont
281
+
282
+ `context.font`, the resolved text style.
283
+
284
+ | Field | Type | Default | Description |
285
+ |------|------|---------|-------------|
286
+ | `color` | string | — | Resolved text color. Canvas: `ctx.fillStyle`. |
287
+ | `direction` | string | — | Canvas: `ctx.direction`. |
288
+ | `family` | string | — | Resolved family list, quoted as the engine reports it. |
289
+ | `featureSettings` | string | — | Canvas 2D consumes neither of these. They are here for text you measure or draw some other way. |
290
+ | `kerning` | string | — | Canvas: `ctx.fontKerning`. |
291
+ | `letterSpacing` | string | — | A length, never `normal` - `normal` is reported as `0px`, which is what `ctx.letterSpacing` accepts. |
292
+ | `lineHeight` | number \| null | — | Line height in CSS pixels, or `null` when it computes to `normal`. Canvas ignores line height in `ctx.font`; this is for laying text out yourself. |
293
+ | `shorthand` | string | — | CSS `font` shorthand, assembled here because every engine returns an empty string for the computed shorthand. `stretch` and `variantCaps` are left out of it deliberately: a percentage `font-stretch` makes every engine reject the whole string and fall back to `10px sans-serif`. Apply those through `ctx.fontStretch` / `ctx.fontVariantCaps` after setting `ctx.font`. |
294
+ | `size` | number | — | Font size in CSS pixels. |
295
+ | `stretch` | string | — | Computed `font-stretch`, a percentage such as `88%`. Canvas: `ctx.fontStretch`. |
296
+ | `style` | string | — | `normal`, `italic`, or an `oblique <angle>`. |
297
+ | `textRendering` | string | — | Canvas: `ctx.textRendering`, which WebKit does not implement. |
298
+ | `variantCaps` | string | — | Canvas: `ctx.fontVariantCaps`. |
299
+ | `variationSettings` | string | — | |
300
+ | `weight` | number | — | Numeric weight, 1-1000. |
301
+ | `wordSpacing` | string | — | Same normalization as `letterSpacing`. Canvas: `ctx.wordSpacing`. |
302
+
303
+ ### BoxInset
304
+
305
+ `context.inset`, the distance from the border edge to the content edge.
306
+
307
+ | Field | Type | Default | Description |
308
+ |------|------|---------|-------------|
309
+ | `borderBottom` | number | — | |
310
+ | `borderLeft` | number | — | |
311
+ | `borderRight` | number | — | |
312
+ | `borderTop` | number | — | |
313
+ | `paddingBottom` | number | — | |
314
+ | `paddingLeft` | number | — | |
315
+ | `paddingRight` | number | — | |
316
+ | `paddingTop` | number | — | |
317
+
318
+ ## Web component
319
+
320
+ Use `<a-box>` without JSX. Events are non-bubbling `CustomEvent`s with the same
321
+ `detail`. Set `observe="size"`, `"context"`, or `"all"` explicitly; adding a
322
+ listener does not enable observation. A bare `observe` means `"all"`.
323
+
324
+ ```html title="a-box"
325
+ <a-box display="grid" gap="8px" round="12px" observe="all"
326
+ style="--box-gap: 8px; --box-round: 12px; padding: 12px; border: 1px solid var(--border-4)">
327
+ <span>Summary content</span>
328
+ <span>Observation enabled</span>
329
+ </a-box>
330
+ ```
331
+
332
+ Import `@antadesign/anta/elements/a-box` to register the element. Listen for
333
+ `measurechange` and `contextchange` with `addEventListener`.
334
+ `box.measurement`, `box.context`, and `box.isTruncated` read values synchronously.
335
+
336
+ ## Styling
337
+
338
+ Your `className` and `style` override `display`, `gap`, and `round` through the
339
+ `anta.components` CSS layer.
340
+
341
+ Without typed CSS `attr()` support, raw `gap`, `round`, and `fade-size` length
342
+ attributes need matching custom properties. The JSX wrapper sets these for you:
343
+
344
+ ```html
345
+ <a-box display="flex" gap round fade class="raw-box"
346
+ style="--box-gap: 8px; --box-round: 12px; --box-fade-size: 32px">
347
+ <span>Layout</span><span>Context</span><span>Measurements</span>
348
+ </a-box>
349
+ ```
350
+
351
+ ```css
352
+ .raw-box { width: 190px; overflow: auto; padding: 12px; border: 1px solid var(--border-4); }
353
+ .raw-box span { flex: 0 0 auto; }
354
+ ```
@@ -111,16 +111,13 @@ Use `copyUrl` to copy `location.href`, `copyNode` to copy a marked rendered
111
111
  region, or `copy` for a known string. For dynamic text, pass a controlled `copy`
112
112
  string and set it from `onCopyRequest`. `onCopied` receives the result.
113
113
 
114
- ### Props
114
+ ## Component props
115
115
 
116
116
  | Prop | Type | Default | Description |
117
117
  |------|------|---------|-------------|
118
118
  | `items` | BreadcrumbItem[] | — | Ordered breadcrumb entries. |
119
- | `itemsBeforeCollapse?` | number | 0 | Number of original items kept before the More control when `maxItems`
120
- collapses the trail. The rest of the visible-item budget is kept from the
121
- end, so `0` puts More first. |
122
- | `maxItems?` | number | — | Maximum number of original breadcrumb items left visible. The More
123
- control does not count. Omit to keep every item visible. |
119
+ | `itemsBeforeCollapse?` | number | 0 | Number of original items kept before the More control when `maxItems` collapses the trail. The rest of the visible-item budget is kept from the end, so `0` puts More first. |
120
+ | `maxItems?` | number | — | Maximum number of original breadcrumb items left visible. The More control does not count. Omit to keep every item visible. |
124
121
  | `moreLabel?` | string | 'Show more breadcrumbs' | Accessible name for the More control. |
125
122
  | `paddingless?` | boolean | — | Remove horizontal padding from every visible breadcrumb control. |
126
123
  | `priority?` | 'quaternary' \| 'tertiary' | quaternary | Button priority applied to every visible item and the More control. |
@@ -129,6 +126,8 @@ string and set it from `onCopyRequest`. `onCopied` receives the result.
129
126
  | `underline?` | 'solid' \| 'dashed' \| 'dotted' | — | Underline style applied to every visible breadcrumb control. |
130
127
  | `underlineOnHover?` | boolean | — | Hide the underline at rest and reveal it on hover. |
131
128
 
129
+ ## Web Component
130
+
132
131
  `Breadcrumbs` deliberately adds no custom-element behavior: it assembles Anta
133
132
  Buttons, an optional Menu, and two light-DOM layout tags. When you are not using
134
133
  JSX, import the Breadcrumbs stylesheet and the primitives, then compose the same
@@ -161,6 +160,8 @@ import '@antadesign/anta/elements'
161
160
  </a-breadcrumbs>
162
161
  ```
163
162
 
163
+ ## Styling
164
+
164
165
  Use `priority`, `size`, and `separator` before adding CSS. A `className` on
165
166
  `Breadcrumbs` lands on the navigation wrapper; item `className` values land on
166
167
  their individual Buttons. The composed structure uses light-DOM tags, so plain
@@ -217,6 +217,8 @@ underline stylistically, it supports three styles — `solid`, `dashed`,
217
217
  - **`selected`** — toggled-on / pressed visual; shares the active
218
218
  state's look. Useful for filter chips and icon toggles.
219
219
 
220
+ ## ButtonCopy
221
+
220
222
  `ButtonCopy` is a copy button — a `Button` preset for copy-to-clipboard. It
221
223
  composes a plain `<Button>` with a slotted `<a-copy>` element that writes to the
222
224
  clipboard when the button is activated. A button with a copy glyph changes the
@@ -329,57 +331,32 @@ current URL (`copyUrl`).
329
331
  |------|------|---------|-------------|
330
332
  | `copiedLabel?` | string | Copied | Text in the successful no-icon confirmation. |
331
333
  | `copy?` | string | — | Text copied to the clipboard on activation. |
332
- | `copyNode?` | boolean \| string | — | Copy a DOM node as rich text (`text/html`) + plain text. `true` copies
333
- the nearest ancestor marked `data-copy-source`; a string is a CSS
334
- selector for an ancestor region (`closest`). The copy control is stripped
335
- from the copied output. |
334
+ | `copyNode?` | boolean \| string | — | Copy a DOM node as rich text (`text/html`) + plain text. `true` copies the nearest ancestor marked `data-copy-source`; a string is a CSS selector for an ancestor region (`closest`). The copy control is stripped from the copied output. |
336
335
  | `copyUrl?` | true | — | Copy the current page URL (`location.href`). |
337
336
  | `copyWithUrl?` | boolean | — | Prefix the copied text with `// URL: <current page URL>`. |
338
337
  | `disabled?` | boolean | — | Disable the button. |
339
338
  | `download?` | string \| boolean | — | Anchor download attribute. Empty string / `true` triggers a download with the resource's default name; a string overrides the filename. |
340
339
  | `form?` | string | — | Form id when the button isn't a descendant of its form. |
341
- | `href?` | string | — | URL to link to. A definite string renders `<a role="button">`; omit it
342
- (or pass `undefined`) to render `<a-button>`, so `href={maybeUrl}`
343
- degrades to a plain button when the URL is absent. |
344
- | `icon?` | IconShape | — | Leading icon shape. When set alone (no `label`, no `iconTrailing`, no
345
- `children`), the button renders as a square icon-only control and
346
- the wrapper auto-supplies `aria-label={icon}` (override by passing
347
- your own `aria-label`). |
348
- | `iconPlacement?` | 'leading' \| 'trailing' \| 'none' | 'leading' | Where the copy glyph sits relative to the label — or `'none'` to omit it.
349
- Without a glyph, a successful copy shows a small confirmation label near
350
- the pointer and leaves the button unchanged. |
340
+ | `href?` | string | — | URL to link to. A definite string renders `<a role="button">`; omit it (or pass `undefined`) to render `<a-button>`, so `href={maybeUrl}` degrades to a plain button when the URL is absent. |
341
+ | `icon?` | IconShape | — | Leading icon shape. When set alone (no `label`, no `iconTrailing`, no `children`), the button renders as a square icon-only control and the wrapper auto-supplies `aria-label={icon}` (override by passing your own `aria-label`). |
342
+ | `iconPlacement?` | 'leading' \| 'trailing' \| 'none' | 'leading' | Where the copy glyph sits relative to the label — or `'none'` to omit it. Without a glyph, a successful copy shows a small confirmation label near the pointer and leaves the button unchanged. |
351
343
  | `iconTrailing?` | IconShape | — | Trailing icon shape. Renders after `children`, last in the slot order. |
352
344
  | `label?` | string | — | Label text. Renders between the leading icon and `children`. |
353
- | `loading?` | boolean | — | Show a rotating loading indicator. Blocks clicks and keyboard
354
- activation, and removes the button from the tab order while active. |
345
+ | `loading?` | boolean | — | Show a rotating loading indicator. Blocks clicks and keyboard activation, and removes the button from the tab order while active. |
355
346
  | `onClick?` | (e) => void | — | Click handler. |
356
347
  | `onCopied?` | (ok) => void | — | Fires after the copy attempt with whether it succeeded. |
357
- | `onCopyRequest?` | () => void | — | Refresh a dynamic `copy` value before activation. Set the new string in
358
- application state so the next render updates `copy`. Return values are
359
- ignored. Fires on pointerdown and Enter/Space keydown. |
348
+ | `onCopyRequest?` | () => void | — | Refresh a dynamic `copy` value before activation. Set the new string in application state so the next render updates `copy`. Return values are ignored. Fires on pointerdown and Enter/Space keydown. |
360
349
  | `paddingless?` | boolean | — | Drops outer padding to zero. |
361
350
  | `ping?` | string | — | Space-separated URLs the browser pings on navigation. |
362
351
  | `priority?` | 'primary' \| 'secondary' \| 'tertiary' \| 'quaternary' | secondary | Visual emphasis. |
363
352
  | `rel?` | string | — | Anchor rel. |
364
- | `role?` | string | button | ARIA role override (e.g. `'gridcell'` when a button is a cell in a grid).
365
- Forwarded to the underlying element. |
366
- | `round?` | boolean \| number \| string | — | Fully-round corners — a pill for text buttons, a circle for icon-only ones
367
- (`border-radius: 999px`, clamped to the element's height). Pass a `number`
368
- (px) or a CSS length string (`'1rem'`) for a custom radius instead. |
353
+ | `role?` | string | button | ARIA role override (e.g. `'gridcell'` when a button is a cell in a grid). Forwarded to the underlying element. |
354
+ | `round?` | boolean \| number \| string | — | Fully-round corners — a pill for text buttons, a circle for icon-only ones (`border-radius: 999px`, clamped to the element's height). Pass a `number` (px) or a CSS length string (`'1rem'`) for a custom radius instead. |
369
355
  | `selected?` | boolean | — | Toggled-on / pressed state, e.g. for filter chips. |
370
- | `size?` | 'small' \| 'medium' \| 'large' | medium | Size variant. small=24px, medium=28px, large=32px. Omit the
371
- attribute or pass `'medium'` for the default — both render
372
- identically and emit no DOM attribute. |
373
- | `tabIndex?` | number | 0 | Tab order. The button is keyboard-focusable by default (`0`) and
374
- becomes `-1` automatically while `disabled` or `loading` — `<a-button>`
375
- and `<a role="button">` aren't focusable without an explicit tabindex,
376
- and a loading button must stay out of the tab order so Enter/Space can't
377
- fire it mid-flight. |
356
+ | `size?` | 'small' \| 'medium' \| 'large' | medium | Size variant. small=24px, medium=28px, large=32px. Omit the attribute or pass `'medium'` for the default — both render identically and emit no DOM attribute. |
357
+ | `tabIndex?` | number | 0 | Tab order. The button is keyboard-focusable by default (`0`) and becomes `-1` automatically while `disabled` or `loading` — `<a-button>` and `<a role="button">` aren't focusable without an explicit tabindex, and a loading button must stay out of the tab order so Enter/Space can't fire it mid-flight. |
378
358
  | `target?` | string | — | Anchor target. |
379
- | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | neutral | Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`)
380
- for a one-off custom tone. Primary uses the color as-is; secondary,
381
- tertiary, and quaternary take its hue and pin lightness/chroma to the
382
- brand curve so any input stays legible. |
359
+ | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | neutral | Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) for a one-off custom tone. Primary uses the color as-is; secondary, tertiary, and quaternary take its hue and pin lightness/chroma to the brand curve so any input stays legible. |
383
360
  | `type?` | 'button' \| 'submit' \| 'reset' | — | Form submission type. |
384
361
  | `underline?` | 'solid' \| 'dashed' \| 'dotted' | — | Underline style. |
385
362
  | `underlineOnHover?` | boolean | — | Hide the underline at rest and reveal it on hover. |
@@ -405,6 +382,8 @@ split or conditional spread:
405
382
  <Button href={reportUrl} disabled={!reportUrl} iconTrailing="external-link" label="View report" />
406
383
  ```
407
384
 
385
+ ### Routing libraries
386
+
408
387
  Anta's CSS targets `a-button, a[role="button"][data-anta]` — an anchor (`<a>`)
409
388
  with `role="button"`, the `data-anta` opt-in marker, and the right attributes
410
389
  gets the styling. That means anta doesn't need an `as` / `asChild` /
@@ -453,6 +432,8 @@ Usage:
453
432
  This approach would work for Next.js `<Link>`, TanStack Router, or any
454
433
  other routing library.
455
434
 
435
+ ## Special events
436
+
456
437
  Beyond a plain click, a `Button` can drive a native form or emit your own
457
438
  event:
458
439
 
@@ -483,7 +464,35 @@ without taking ownership of `onClick`.
483
464
  <Button tone="brand" label="Save" data-custom-event="save-clicked" />
484
465
  ```
485
466
 
486
- ### Props
467
+ ## Component props
468
+
469
+ | Prop | Type | Default | Description |
470
+ |------|------|---------|-------------|
471
+ | `disabled?` | boolean | — | Disable the button. |
472
+ | `download?` | string \| boolean | — | Anchor download attribute. Empty string / `true` triggers a download with the resource's default name; a string overrides the filename. |
473
+ | `form?` | string | — | Form id when the button isn't a descendant of its form. |
474
+ | `href?` | string | — | URL to link to. A definite string renders `<a role="button">`; omit it (or pass `undefined`) to render `<a-button>`, so `href={maybeUrl}` degrades to a plain button when the URL is absent. |
475
+ | `icon?` | IconShape | — | Leading icon shape. When set alone (no `label`, no `iconTrailing`, no `children`), the button renders as a square icon-only control and the wrapper auto-supplies `aria-label={icon}` (override by passing your own `aria-label`). |
476
+ | `iconTrailing?` | IconShape | — | Trailing icon shape. Renders after `children`, last in the slot order. |
477
+ | `label?` | string | — | Label text. Renders between the leading icon and `children`. |
478
+ | `loading?` | boolean | — | Show a rotating loading indicator. Blocks clicks and keyboard activation, and removes the button from the tab order while active. |
479
+ | `onClick?` | (e) => void | — | Click handler. |
480
+ | `paddingless?` | boolean | — | Drops outer padding to zero. |
481
+ | `ping?` | string | — | Space-separated URLs the browser pings on navigation. |
482
+ | `priority?` | 'primary' \| 'secondary' \| 'tertiary' \| 'quaternary' | secondary | Visual emphasis. |
483
+ | `rel?` | string | — | Anchor rel. |
484
+ | `role?` | string | button | ARIA role override (e.g. `'gridcell'` when a button is a cell in a grid). Forwarded to the underlying element. |
485
+ | `round?` | boolean \| number \| string | — | Fully-round corners — a pill for text buttons, a circle for icon-only ones (`border-radius: 999px`, clamped to the element's height). Pass a `number` (px) or a CSS length string (`'1rem'`) for a custom radius instead. |
486
+ | `selected?` | boolean | — | Toggled-on / pressed state, e.g. for filter chips. |
487
+ | `size?` | 'small' \| 'medium' \| 'large' | medium | Size variant. small=24px, medium=28px, large=32px. Omit the attribute or pass `'medium'` for the default — both render identically and emit no DOM attribute. |
488
+ | `tabIndex?` | number | 0 | Tab order. The button is keyboard-focusable by default (`0`) and becomes `-1` automatically while `disabled` or `loading` — `<a-button>` and `<a role="button">` aren't focusable without an explicit tabindex, and a loading button must stay out of the tab order so Enter/Space can't fire it mid-flight. |
489
+ | `target?` | string | — | Anchor target. |
490
+ | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | neutral | Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) for a one-off custom tone. Primary uses the color as-is; secondary, tertiary, and quaternary take its hue and pin lightness/chroma to the brand curve so any input stays legible. |
491
+ | `type?` | 'button' \| 'submit' \| 'reset' | — | Form submission type. |
492
+ | `underline?` | 'solid' \| 'dashed' \| 'dotted' | — | Underline style. |
493
+ | `underlineOnHover?` | boolean | — | Hide the underline at rest and reveal it on hover. |
494
+
495
+ ## Web Component
487
496
 
488
497
  Use the web component directly when you are not using React or Preact and a native control does not fit.
489
498
 
@@ -520,6 +529,8 @@ wrapper sets them for you). A native `<button>` also carries its own default
520
529
  <button data-anta tone="critical" priority="tertiary">Delete</button>
521
530
  ```
522
531
 
532
+ ## Styling
533
+
523
534
  Reach for the props first: **`tone`** sets the color (any CSS color for a custom
524
535
  tone — it derives the whole tone × priority × state curve in oklch), **`priority`**
525
536
  the emphasis, **`size`** the dimensions. The focus ring is the global