@antadesign/anta 0.3.26 → 0.3.28

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 (133) hide show
  1. package/README.md +26 -28
  2. package/dist/anta_helpers.d.ts +8 -0
  3. package/dist/anta_helpers.js +18 -0
  4. package/dist/box-types.d.ts +1 -1
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +36 -42
  7. package/dist/capture-types.d.ts +156 -0
  8. package/dist/components/Banner.js +2 -2
  9. package/dist/components/Box.d.ts +15 -0
  10. package/dist/components/Box.js +3 -11
  11. package/dist/components/Button.js +2 -2
  12. package/dist/components/Capture.d.ts +39 -0
  13. package/dist/components/Capture.js +36 -0
  14. package/dist/components/Card.js +2 -2
  15. package/dist/components/Checkbox.d.ts +10 -11
  16. package/dist/components/Checkbox.js +5 -13
  17. package/dist/components/Expander.js +2 -2
  18. package/dist/components/Input.js +2 -2
  19. package/dist/components/InputTime.js +2 -2
  20. package/dist/components/Loader.js +2 -1
  21. package/dist/components/MenuItem.d.ts +7 -8
  22. package/dist/components/MenuItem.js +4 -4
  23. package/dist/components/Progress.js +2 -2
  24. package/dist/components/RadioGroup.d.ts +12 -13
  25. package/dist/components/RadioGroup.js +7 -23
  26. package/dist/components/Select.d.ts +12 -7
  27. package/dist/components/Select.js +4 -3
  28. package/dist/components/SelectFaceted.d.ts +7 -5
  29. package/dist/components/SelectFaceted.js +4 -3
  30. package/dist/components/Slider.js +3 -3
  31. package/dist/components/Steps.css +1 -1
  32. package/dist/components/Switch.d.ts +7 -8
  33. package/dist/components/Switch.js +3 -11
  34. package/dist/components/Tabs.js +2 -2
  35. package/dist/components/Tag.d.ts +7 -9
  36. package/dist/components/Tag.js +2 -2
  37. package/dist/components/Text.js +2 -2
  38. package/dist/components/Title.js +2 -2
  39. package/dist/components/capture-props.d.ts +30 -0
  40. package/dist/components/capture-props.js +44 -0
  41. package/dist/elements/a-avatar.css +1 -1
  42. package/dist/elements/a-banner.css +1 -1
  43. package/dist/elements/a-box.d.ts +1 -1
  44. package/dist/elements/a-box.js +11 -3
  45. package/dist/elements/a-button.css +1 -1
  46. package/dist/elements/a-button.d.ts +7 -9
  47. package/dist/elements/a-calendar.css +1 -1
  48. package/dist/elements/a-capture.css +1 -0
  49. package/dist/elements/a-capture.d.ts +10 -0
  50. package/dist/elements/a-capture.js +24 -0
  51. package/dist/elements/a-card.css +1 -1
  52. package/dist/elements/a-checkbox.css +1 -1
  53. package/dist/elements/a-checkbox.js +4 -4
  54. package/dist/elements/a-dialog.css +1 -1
  55. package/dist/elements/a-expander.css +1 -1
  56. package/dist/elements/a-expander.js +1 -0
  57. package/dist/elements/a-input-time.css +1 -1
  58. package/dist/elements/a-input-time.js +5 -7
  59. package/dist/elements/a-input.css +1 -1
  60. package/dist/elements/a-input.js +4 -6
  61. package/dist/elements/a-menu-item.css +1 -1
  62. package/dist/elements/a-menu.css +1 -1
  63. package/dist/elements/a-progress.css +1 -1
  64. package/dist/elements/a-radio.css +1 -1
  65. package/dist/elements/a-slider.css +1 -1
  66. package/dist/elements/a-slider.js +6 -9
  67. package/dist/elements/a-switch.css +1 -1
  68. package/dist/elements/a-tab.css +1 -1
  69. package/dist/elements/a-tabs.css +1 -1
  70. package/dist/elements/a-tag.css +1 -1
  71. package/dist/elements/a-text.css +1 -1
  72. package/dist/elements/a-text.js +1 -0
  73. package/dist/elements/a-title.css +1 -1
  74. package/dist/elements/a-tooltip.css +1 -1
  75. package/dist/elements/a-tooltip.d.ts +3 -4
  76. package/dist/elements/a-tooltip.js +0 -1
  77. package/dist/elements/capture-input.d.ts +5 -0
  78. package/dist/elements/capture-input.js +609 -0
  79. package/dist/elements/index.d.ts +1 -0
  80. package/dist/elements/index.js +3 -0
  81. package/dist/general_types.d.ts +56 -23
  82. package/dist/index.d.ts +4 -1
  83. package/dist/index.js +2 -0
  84. package/dist/jsx-runtime.d.ts +2 -1
  85. package/dist/reset.css +1 -1
  86. package/dist/theme-antithesis.css +1 -0
  87. package/dist/theme-antune.css +1 -0
  88. package/dist/tokens.css +1 -1
  89. package/docs/accessibility.md +24 -0
  90. package/docs/changelog.md +79 -0
  91. package/docs/colors.md +141 -0
  92. package/docs/comparison.md +463 -28
  93. package/docs/components/avatar.md +13 -17
  94. package/docs/components/banner.md +13 -27
  95. package/docs/components/box.md +226 -154
  96. package/docs/components/breadcrumbs.md +49 -12
  97. package/docs/components/button.md +48 -37
  98. package/docs/components/capture.md +345 -0
  99. package/docs/components/card.md +17 -38
  100. package/docs/components/checkbox.md +27 -50
  101. package/docs/components/dialog.md +14 -36
  102. package/docs/components/expander.md +15 -40
  103. package/docs/components/icon.md +111 -9
  104. package/docs/components/input-autocomplete.md +9 -11
  105. package/docs/components/input-date.md +33 -23
  106. package/docs/components/input-time.md +15 -23
  107. package/docs/components/input.md +27 -76
  108. package/docs/components/loader.md +7 -5
  109. package/docs/components/menu.md +75 -80
  110. package/docs/components/progress.md +10 -14
  111. package/docs/components/radio.md +28 -46
  112. package/docs/components/select-faceted.md +8 -25
  113. package/docs/components/select.md +33 -105
  114. package/docs/components/slider.md +16 -21
  115. package/docs/components/steps.md +38 -8
  116. package/docs/components/switch.md +16 -19
  117. package/docs/components/tabs.md +52 -40
  118. package/docs/components/tag.md +15 -24
  119. package/docs/components/text.md +10 -23
  120. package/docs/components/title.md +7 -8
  121. package/docs/components/toaster.md +6 -3
  122. package/docs/components/tooltip.md +13 -23
  123. package/docs/index.md +3 -1
  124. package/docs/install-config.md +42 -8
  125. package/docs/normalization.md +48 -3
  126. package/docs/packages/stickers.md +56 -0
  127. package/docs/theming.md +362 -14
  128. package/package.json +7 -4
  129. package/dist/components/InputDate.module.css +0 -1
  130. package/dist/components/Select.module.css +0 -1
  131. package/dist/components/SelectFaceted.module.css +0 -1
  132. package/dist/theme-anta.css +0 -1
  133. /package/dist/{search-index.json → capture-types.js} +0 -0
@@ -6,12 +6,41 @@ More menu without measuring the available width.
6
6
 
7
7
  ## Items
8
8
 
9
- Pass ordered data through `items`. An `href` renders a native link with the
10
- Button appearance; omit it for an action button. Each item accepts `label`,
11
- `icon`, `iconTrailing`, `tone`, `disabled`, `onClick`, `className`, `style`,
12
- `id`, `title`, and `data-*` / `aria-*` attributes. `size`, priority, and
13
- underline treatment belong to the whole trail so every visible control retains
14
- the same height.
9
+ Pass ordered `BreadcrumbItem` objects through `items`. Each item is a link,
10
+ action, or copy control. `size`, `priority`, and underline treatment belong to
11
+ the whole trail.
12
+
13
+ ### BreadcrumbItem reference
14
+
15
+ | Property | Possible values | Description |
16
+ | --- | --- | --- |
17
+ | `label` | `React.ReactNode` | Required content, such as text, an image, or JSX. Also used as the label when the item folds into More. |
18
+ | `icon` | `IconShape` | Leading Anta icon shape. |
19
+ | `iconTrailing` | `IconShape` | Trailing Anta icon shape. Available on link and action items. |
20
+ | `tone` | `'neutral'`, `'brand'`, `'info'`, `'success'`, `'warning'`, `'critical'`, or a CSS color string | Item color. Defaults to neutral. |
21
+ | `disabled` | `boolean` | Disables the item. |
22
+ | `current` | `boolean` | Sets `aria-current="page"`. Does not change the tone. |
23
+ | `onClick` | `(event: any) => void` | Activation handler. Folded items call it on menu selection. |
24
+ | `href` | `string` | Destination URL for a link item. |
25
+ | `target` | `string` | Link target, such as `'_blank'`. Requires `href`. |
26
+ | `copy` | `string` | Literal text to copy. |
27
+ | `copyNode` | `boolean` or `string` | `true` copies the nearest ancestor marked `data-copy-source`; a CSS selector chooses an ancestor region. `false` disables the node target. |
28
+ | `copyUrl` | `true` | Copies the current page URL. |
29
+ | `copyWithUrl` | `boolean` | Prefixes literal `copy` text with the current page URL. |
30
+ | `onCopyRequest` | `() => void` | Refreshes a literal `copy` value before activation. Update application state; return values are ignored. |
31
+ | `onCopied` | `(ok: boolean) => void` | Reports whether a copy attempt succeeded. Available on copy items. |
32
+ | `iconPlacement` | `'leading'`, `'trailing'`, or `'none'` | Copy glyph placement. Defaults to `'leading'`. |
33
+ | `copiedLabel` | `string` | Confirmation text for a copy item with no icon. Defaults to `'Copied'`. |
34
+ | `className` | `string` | CSS class on the item control. |
35
+ | `style` | `React.CSSProperties` | Inline styles on the item control. |
36
+ | `id` | `string` | HTML ID on the item control. |
37
+ | `title` | `string` | Native browser tooltip text. |
38
+ | `data-*`, `aria-*` | Attribute-specific values | Attributes forwarded to the item control. |
39
+
40
+ Use `href` for a link, omit navigation and copy props for an action, or choose
41
+ exactly one of `copy`, `copyNode`, and `copyUrl` for a copy item. Copy items
42
+ cannot use `href`, `target`, or `iconTrailing`. `copyWithUrl` and
43
+ `onCopyRequest` apply only to literal `copy` text.
15
44
 
16
45
  ```tsx
17
46
  <Breadcrumbs
@@ -111,16 +140,13 @@ Use `copyUrl` to copy `location.href`, `copyNode` to copy a marked rendered
111
140
  region, or `copy` for a known string. For dynamic text, pass a controlled `copy`
112
141
  string and set it from `onCopyRequest`. `onCopied` receives the result.
113
142
 
114
- ### Props
143
+ ## Component props
115
144
 
116
145
  | Prop | Type | Default | Description |
117
146
  |------|------|---------|-------------|
118
147
  | `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. |
148
+ | `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. |
149
+ | `maxItems?` | number | — | Maximum number of original breadcrumb items left visible. The More control does not count. Omit to keep every item visible. |
124
150
  | `moreLabel?` | string | 'Show more breadcrumbs' | Accessible name for the More control. |
125
151
  | `paddingless?` | boolean | — | Remove horizontal padding from every visible breadcrumb control. |
126
152
  | `priority?` | 'quaternary' \| 'tertiary' | quaternary | Button priority applied to every visible item and the More control. |
@@ -129,6 +155,8 @@ string and set it from `onCopyRequest`. `onCopied` receives the result.
129
155
  | `underline?` | 'solid' \| 'dashed' \| 'dotted' | — | Underline style applied to every visible breadcrumb control. |
130
156
  | `underlineOnHover?` | boolean | — | Hide the underline at rest and reveal it on hover. |
131
157
 
158
+ ## Web Component
159
+
132
160
  `Breadcrumbs` deliberately adds no custom-element behavior: it assembles Anta
133
161
  Buttons, an optional Menu, and two light-DOM layout tags. When you are not using
134
162
  JSX, import the Breadcrumbs stylesheet and the primitives, then compose the same
@@ -161,17 +189,26 @@ import '@antadesign/anta/elements'
161
189
  </a-breadcrumbs>
162
190
  ```
163
191
 
192
+ ## Styling
193
+
164
194
  Use `priority`, `size`, and `separator` before adding CSS. A `className` on
165
195
  `Breadcrumbs` lands on the navigation wrapper; item `className` values land on
166
196
  their individual Buttons. The composed structure uses light-DOM tags, so plain
167
197
  CSS can style a separator directly.
168
198
 
199
+ To tighten the space between items, give the trail a class and set
200
+ `a-breadcrumb-separator` to `width: 8px` within that class. This changes the
201
+ separator's layout width while keeping the icon size unchanged. The website
202
+ header uses this approach. `project-breadcrumbs` is a demo class; replace it
203
+ with your own selector.
204
+
169
205
  ```tsx
170
206
  <Breadcrumbs className="project-breadcrumbs" separator="chevron-right" items={items} />
171
207
  ```
172
208
 
173
209
  ```css
174
210
  .project-breadcrumbs a-breadcrumb-separator {
211
+ width: 8px;
175
212
  color: var(--text-2);
176
213
  }
177
214
  ```
@@ -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
@@ -0,0 +1,345 @@
1
+ # Capture
2
+
3
+ `Capture` is a light-DOM input surface for custom tables, plots, and drag
4
+ interactions. Wheel capture, pointer capture, and panning are all disabled by default.
5
+
6
+ ## Usage
7
+
8
+ Each capability is opt-in; handlers alone enable nothing. Choose by interaction:
9
+
10
+ | Interaction | Capability | Your component handles |
11
+ | --- | --- | --- |
12
+ | Mouse wheel or trackpad scrolling | `wheelCapture` | Scroll offsets or zoom |
13
+ | Touchscreen drag to scroll | `pan` | Scroll offsets from pan deltas |
14
+ | Drag to select, resize, or draw | `pointerCapture` | Raw pointer samples |
15
+
16
+ Disabled Capture surfaces add no input state or listeners.
17
+
18
+ Capture cancels accepted native input on the browser thread, then sends plain data
19
+ to your handler. Your component performs the action. Forward the serializable
20
+ `detail` across worker boundaries. Handler return values cannot change cancellation.
21
+
22
+ For a 2D table, combine `wheelCapture` and `pan` for scrolling with
23
+ `pointerCapture={{ pointerTypes: ['mouse', 'pen'] }}` for selection. Each
24
+ handler updates the corresponding scroll or selection state.
25
+
26
+ ## Wheel ownership
27
+
28
+ Set `wheelCapture` to `true` for all directions, or update allowed directions
29
+ from your component's bounds. Declined input reaches the enclosing editor or
30
+ scroll container. The dominant axis decides ownership; both deltas are delivered.
31
+ All-false bounds preserve settling while declining input. Passing `false` or
32
+ removing `wheelCapture` disables capture and clears settling.
33
+
34
+ Enable **Capture wheel**, then scroll over the rows. The controls let you try
35
+ different activation and settling rules.
36
+
37
+ ```tsx title="Custom table wheel"
38
+ const [offset, setOffset] = useState(0)
39
+ const maxOffset = 28 * 32 - 192
40
+
41
+ // These settings come from the preview controls.
42
+ <div onKeyDown={event => {
43
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return
44
+ event.preventDefault()
45
+ const delta = event.key === 'ArrowDown' ? 32 : -32
46
+ setOffset(value => Math.max(0, Math.min(maxOffset, value + delta)))
47
+ }}>
48
+ <Capture
49
+ wheelCapture={enabled && { up: offset > 0, down: offset < maxOffset }}
50
+ wheelActivation={activation}
51
+ wheelSettle={{ delay, tolerance: 5, resetOnMove }}
52
+ tabIndex={0}
53
+ aria-label="Wheel capture surface"
54
+ style={{ height: 192, overflow: 'hidden' }}
55
+ onWheelInput={(_, { wheelEvent, boxHeight }) => {
56
+ const unit = wheelEvent.deltaMode === 1 ? 32 : wheelEvent.deltaMode === 2 ? boxHeight : 1
57
+ setOffset(value => Math.max(0, Math.min(maxOffset, value + wheelEvent.deltaY * unit)))
58
+ }}
59
+ >
60
+ <div style={{ transform: `translateY(${-offset}px)` }}>
61
+ {Array.from({ length: 28 }, (_, index) => (
62
+ <div key={index} style={{ height: 32 }}>Sample {index + 1}</div>
63
+ ))}
64
+ </div>
65
+ </Capture>
66
+ </div>
67
+ ```
68
+
69
+ The default `"settled"` activation waits for the pointer to rest inside Capture
70
+ (150ms, 5px tolerance). It stays active until the pointer leaves.
71
+ `wheelSettle.resetOnMove` requires settling again after movement beyond tolerance.
72
+ Scrolling a Capture under a stationary pointer does not activate it.
73
+
74
+ Use `"hover"` for immediate activation, `"focus"` for `:focus-within`, or
75
+ `"settled-or-focus"` for either condition. Wheel input must still target Capture.
76
+ Capture never takes focus automatically; provide `tabIndex` or a focusable child.
77
+
78
+ Modified input stays native by default, including Ctrl/pinch zoom. Use
79
+ `wheelModifier="ctrl"` to capture Ctrl-wheel, or `"any"` for all modifiers.
80
+ Named modifiers allow other keys too.
81
+
82
+ The innermost eligible Capture handles wheel input on its host. Canceled and
83
+ non-cancelable events are ignored; Capture cannot undo an ancestor's capture-phase
84
+ handler. Capture skips nested `textarea`, `select`, numeric/range inputs, and
85
+ Anta menus. Mark other native scroll panes with `data-capture-ignore`.
86
+
87
+ `detail.wheelEvent` preserves native event data, signs, and `deltaMode` units
88
+ (0: pixels, 1: lines, 2: pages). Capture does not infer OS scrolling preferences.
89
+ `localX` and `localY` are CSS pixels from Capture's viewport rectangle's top-left,
90
+ without undoing transforms. Native `offsetX` and `offsetY` refer to the original
91
+ target, which may be a child.
92
+
93
+ ## Pointer sessions
94
+
95
+ `pointerCapture` sends raw data for one primary mouse, pen, or touch pointer,
96
+ including movement outside Capture. Your component interprets the gesture.
97
+ Use `threshold` to delay capture until dragging starts. Drag an area in the
98
+ preview, or select **Select sample area** with the keyboard.
99
+
100
+ ```tsx title="Mouse or pen selection"
101
+ type Selection = { x: number; y: number; width: number; height: number }
102
+ const [selection, setSelection] = useState<Selection | null>(null)
103
+
104
+ <Button label="Select sample area" onClick={() => setSelection({ x: 24, y: 24, width: 100, height: 64 })} />
105
+ <Button label="Clear selection" onClick={() => setSelection(null)} />
106
+ <Capture
107
+ className="pointer-probe-surface"
108
+ aria-label="Pointer selection surface"
109
+ pointerCapture={{ pointerTypes: ['mouse', 'pen'], threshold: 3 }}
110
+ onPointerInput={(_, detail) => {
111
+ if (detail.phase === 'cancel') return
112
+ const x = Math.max(0, Math.min(detail.boxWidth, detail.localX))
113
+ const y = Math.max(0, Math.min(detail.boxHeight, detail.localY))
114
+ setSelection({
115
+ x: Math.min(detail.start.localX, x), y: Math.min(detail.start.localY, y),
116
+ width: Math.abs(x - detail.start.localX), height: Math.abs(y - detail.start.localY),
117
+ })
118
+ }}
119
+ >
120
+ <Text size="small" priority="tertiary">Drag to select an area.</Text>
121
+ {selection && <div className="pointer-probe-selection"
122
+ style={{ left: selection.x, top: selection.y, width: selection.width, height: selection.height }} />}
123
+ </Capture>
124
+ ```
125
+
126
+ ```css
127
+ .pointer-probe-surface { position: relative; height: 160px; overflow: hidden; border: 1px solid var(--border-4); border-radius: 8px; background: var(--bg-canvas); }
128
+ .pointer-probe-surface a-text { display: block; padding: 12px; }
129
+ .pointer-probe-selection { position: absolute; pointer-events: none; border: 1px solid var(--border-3-brand); background: color-mix(in oklch, var(--text-1-brand) 12%, transparent); }
130
+ ```
131
+
132
+ `onPointerInput` reports `start`, `move`, `end`, and `cancel`. `deltaX/Y` are
133
+ incremental movement; `movementX/Y` are totals from the press, positive right/down.
134
+
135
+ Presses below threshold emit nothing. Captured gestures suppress the following
136
+ pointer-generated click. Cancellation reports `cancelReason` on pointer
137
+ cancellation, lost capture, disabling, removal, or window blur/hiding.
138
+ Lifecycle cancellation sets `pointerEvent: null`.
139
+ Capture cancels native behavior without stopping pointer-event propagation.
140
+
141
+ Pointer and pan capture skip nested native/ARIA controls, links, and editable content.
142
+ `pointerCapture.includeInteractive` includes them. Use `data-capture-ignore`
143
+ to exclude a subtree from all capture, including wheel. It does not remove
144
+ ancestor `touch-action` restrictions.
145
+
146
+ ## Touch panning and inertia
147
+
148
+ `pan` converts touchscreen dragging into scroll deltas without inertia. It
149
+ captures the pointer internally; it does not require `pointerCapture`. Set
150
+ `pan.pointerTypes` to enable mouse or pen panning. If your component already
151
+ interprets touch gestures, use `pointerCapture` for touch and omit `pan`.
152
+
153
+ Enabling both for the same pointer type emits both streams. Assign separate
154
+ pointer types when each gesture should have one handler.
155
+
156
+ Try touch panning, or enable **Pan with mouse**. **Inertia** continues motion
157
+ after release; turn it off to stop when the pointer lifts.
158
+
159
+ ```tsx title="Custom touch scrolling"
160
+ const [offset, setOffset] = useState(0)
161
+ const maxOffset = 18 * 32 - 160
162
+ const move = (delta: number) => setOffset(value => Math.max(0, Math.min(maxOffset, value + delta)))
163
+
164
+ // mouse and inertia come from the preview checkboxes.
165
+ <div onKeyDown={event => {
166
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return
167
+ event.preventDefault()
168
+ move(event.key === 'ArrowDown' ? 32 : -32)
169
+ }}>
170
+ <Capture
171
+ className="pan-probe-surface"
172
+ tabIndex={0}
173
+ aria-label="Pan capture surface"
174
+ pan={{
175
+ axis: 'y',
176
+ pointerTypes: mouse ? ['touch', 'mouse'] : ['touch'],
177
+ directions: { up: offset > 0, down: offset < maxOffset },
178
+ inertia,
179
+ }}
180
+ onPanInput={(_, { deltaY }) => move(deltaY)}
181
+ >
182
+ <div style={{ transform: `translateY(${-offset}px)` }}>
183
+ {Array.from({ length: 18 }, (_, index) => (
184
+ <div className="pan-probe-row" key={index}>Sample {index + 1}</div>
185
+ ))}
186
+ </div>
187
+ </Capture>
188
+ </div>
189
+ ```
190
+
191
+ ```css
192
+ .pan-probe-surface { height: 160px; overflow: hidden; border: 1px solid var(--border-4); border-radius: 8px; background: var(--bg-canvas); }
193
+ .pan-probe-row { height: 32px; box-sizing: border-box; padding: 6px 12px; border-bottom: 1px solid var(--border-5); }
194
+ ```
195
+
196
+ Pan deltas oppose finger movement. Apply deltas from every phase, including
197
+ `release`. Inertia samples have `pointerEvent: null`. Motion stops on new input,
198
+ disabled directions, or cancellation.
199
+
200
+ Capture sets CSS `touch-action` before contact. Single-axis pan leaves the other
201
+ axis and pinch zoom to the browser. Both-axis pan or touch pointer capture owns
202
+ the whole gesture; mouse-only capture leaves touch unchanged. Unlike wheel,
203
+ an active touch gesture cannot return to native scrolling at a bound. Update
204
+ directions to stop custom motion and control the next gesture.
205
+ Empty pointer-type or button lists disable that capability without restricting
206
+ native text selection or touch gestures.
207
+
208
+ ## Component props
209
+
210
+ | Prop | Type | Default | Description |
211
+ |------|------|---------|-------------|
212
+ | `onPanInput?` | (event, detail) => void | — | Custom pan motion and its lifecycle. Inertial samples have no native pointer event. |
213
+ | `onPointerInput?` | (event, detail) => void | — | Start, movement, end, and cancellation of an opted-in pointer session. |
214
+ | `onWheelInput?` | (event, detail) => void | — | Accepted wheel input, with a serialized original event, Capture-relative geometry, focus state, and activation reason. Cancellation is already complete. |
215
+ | `pan?` | boolean \| CapturePan | — | Emit custom pan motion. `true` enables touch panning on both axes without momentum. Options select devices, axes, bounds directions, and optional inertia. Captures the pointer internally; `pointerCapture` is not required. Sets CSS touch-action through attributes before the gesture starts. |
216
+ | `pointerCapture?` | boolean \| CapturePointerCapture | — | Emit raw data for a primary pointer until release or cancellation. An options object filters devices/buttons and configures activation. Nested interactive controls are excluded unless explicitly included. A listener alone enables nothing. |
217
+ | `wheelActivation?` | CaptureWheelActivation | settled | Pointer or focus condition required before wheel input can be captured. Focus applies only to input targeted within this Capture. |
218
+ | `wheelCapture?` | CaptureInputDirections | — | Capture wheel input in the enabled directions and emit `onWheelInput`. `true` accepts all directions. Omit or pass `false` to leave wheel input alone. Nested native wheel controls and Anta menus are excluded. All-false direction bounds preserve pointer settling while declining input. A listener alone never enables capture. |
219
+ | `wheelModifier?` | CaptureInputModifier | none | Required modifier for wheel capture. `none` preserves browser Ctrl/pinch zoom. |
220
+ | `wheelSettle?` | CaptureWheelSettle | { delay: 150, tolerance: 5, resetOnMove: false } | Dwell delay, movement tolerance, and whether movement resets eligibility. |
221
+
222
+ ### CaptureWheelSettle
223
+
224
+ | Option | Type | Default | Description |
225
+ |------|------|---------|-------------|
226
+ | `delay?` | number | 150 | Pointer dwell time in milliseconds. |
227
+ | `resetOnMove?` | boolean | false | Restart dwell after movement beyond tolerance, including after activation. |
228
+ | `tolerance?` | number | 5 | Maximum movement from the dwell anchor on either axis, in CSS pixels. |
229
+
230
+ ### CapturePointerCapture
231
+
232
+ | Option | Type | Default | Description |
233
+ |------|------|---------|-------------|
234
+ | `buttons?` | readonly number[] | [0] | Accepted initiating buttons, using PointerEvent.button values. |
235
+ | `includeInteractive?` | boolean | false | Allow capture to start on nested native or ARIA controls, links, or editable regions. |
236
+ | `modifier?` | CaptureInputModifier | any | Modifier required to start a capture session. |
237
+ | `pointerTypes?` | readonly CapturePointerType[] | ['mouse', 'pen', 'touch'] | Accepted pointer devices. One primary pointer is tracked per Capture. |
238
+ | `threshold?` | number | 0 | Movement required before activation, in viewport CSS pixels. |
239
+
240
+ ### CapturePan
241
+
242
+ | Option | Type | Default | Description |
243
+ |------|------|---------|-------------|
244
+ | `axis?` | 'x' \| 'y' \| 'both' | both | Axes handled by custom panning. CSS touch-action leaves the other axis to the browser. |
245
+ | `directions?` | CaptureInputDirections | true | Allowed scroll directions. Updating these can stop motion at application bounds. |
246
+ | `inertia?` | boolean \| CapturePanInertia | false | Continue panning after release with browser-side velocity decay. |
247
+ | `pointerTypes?` | readonly CapturePointerType[] | ['touch'] | Accepted pointer devices. |
248
+ | `threshold?` | number | 3 | Movement required before activation, in viewport CSS pixels. |
249
+
250
+ ### CapturePanInertia
251
+
252
+ | Option | Type | Default | Description |
253
+ |------|------|---------|-------------|
254
+ | `minVelocity?` | number | 0.02 | Stop when speed on both axes falls below this value, in CSS pixels/ms. |
255
+ | `timeConstant?` | number | 325 | Exponential velocity decay time constant in milliseconds. |
256
+
257
+ ### CaptureWheelInput
258
+
259
+ | Field | Type | Default | Description |
260
+ |------|------|---------|-------------|
261
+ | `activationReason` | CaptureWheelActivationReason | — | |
262
+ | `boxHeight` | number | — | |
263
+ | `boxWidth` | number | — | Dimensions of the same viewport bounding rectangle, in CSS pixels. |
264
+ | `focusWithin` | boolean | — | |
265
+ | `inside` | boolean | — | Whether the pointer is inside that rectangle. Capture can continue outside it. |
266
+ | `localX` | number | — | Pointer position relative to the viewport bounding rectangle's top-left, in CSS pixels. |
267
+ | `localY` | number | — | |
268
+ | `wheelEvent` | SerializedWheelEvent | — | |
269
+
270
+ ### CapturePointerInput
271
+
272
+ | Field | Type | Default | Description |
273
+ |------|------|---------|-------------|
274
+ | `activationReason` | CapturePointerActivationReason | — | |
275
+ | `boxHeight` | number | — | |
276
+ | `boxWidth` | number | — | Dimensions of the same viewport bounding rectangle, in CSS pixels. |
277
+ | `deltaX` | number | — | Movement since the previous delivered sample, in viewport CSS pixels. |
278
+ | `deltaY` | number | — | |
279
+ | `focusWithin` | boolean | — | |
280
+ | `inside` | boolean | — | Whether the pointer is inside that rectangle. Capture can continue outside it. |
281
+ | `localX` | number | — | Pointer position relative to the viewport bounding rectangle's top-left, in CSS pixels. |
282
+ | `localY` | number | — | |
283
+ | `movementX` | number | — | Total movement from the initial press, in viewport CSS pixels. |
284
+ | `movementY` | number | — | |
285
+ | `phase` | 'start' \| 'move' \| 'end' \| 'cancel' | — | |
286
+ | `pointerEvent` | SerializedPointerEvent \| null | — | Null when cancellation comes from lifecycle or configuration changes. |
287
+ | `start` | CapturePointerStart | — | |
288
+ | `cancelReason?` | CaptureInputCancelReason | — | |
289
+
290
+ ### CapturePanInput
291
+
292
+ | Field | Type | Default | Description |
293
+ |------|------|---------|-------------|
294
+ | `activationReason` | CapturePointerActivationReason | — | |
295
+ | `boxHeight` | number | — | |
296
+ | `boxWidth` | number | — | Dimensions of the same viewport bounding rectangle, in CSS pixels. |
297
+ | `deltaX` | number | — | Incremental scroll motion in viewport CSS pixels. |
298
+ | `deltaY` | number | — | |
299
+ | `focusWithin` | boolean | — | |
300
+ | `inside` | boolean | — | Whether the pointer is inside that rectangle. Capture can continue outside it. |
301
+ | `localX` | number | — | Pointer position relative to the viewport bounding rectangle's top-left, in CSS pixels. |
302
+ | `localY` | number | — | |
303
+ | `phase` | 'start' \| 'move' \| 'release' \| 'inertia' \| 'end' \| 'cancel' | — | |
304
+ | `pointerEvent` | SerializedPointerEvent \| null | — | Null during momentum or cancellation without a pointer event. |
305
+ | `start` | CapturePointerStart | — | |
306
+ | `velocityX` | number | — | Scroll velocity in viewport CSS pixels/ms. |
307
+ | `velocityY` | number | — | |
308
+ | `cancelReason?` | CaptureInputCancelReason | — | |
309
+
310
+ ## Web component
311
+
312
+ Use `<a-capture>` without JSX. Events are non-bubbling `CustomEvent`s
313
+ with the same `detail`. Adding listeners enables no capabilities.
314
+
315
+ Import `@antadesign/anta/elements/a-capture` to register the element. A bare
316
+ Capture leaves wheel and touch scrolling native:
317
+
318
+ ```html title="a-capture"
319
+ <a-capture class="native-capture">
320
+ <p>Native scrolling stays enabled.</p>
321
+ <p>No wheel, pointer, or pan input is captured.</p>
322
+ <p>Scroll to the end of this content.</p>
323
+ <p>The browser owns this scroll position.</p>
324
+ </a-capture>
325
+ ```
326
+
327
+ ```css
328
+ .native-capture { width: 100%; height: 120px; overflow: auto; padding: 12px; border: 1px solid var(--border-4); border-radius: 8px; }
329
+ .native-capture p { margin: 0; padding-block: 12px; }
330
+ ```
331
+
332
+ Configure capture with attributes such as `wheel-capture="up down"` or `pan="y"`.
333
+ Bare capability attributes match passing `true` in JSX. Remove an attribute to
334
+ disable it. Listen for `wheelinput`, `pointerinput`, and `paninput` with
335
+ `addEventListener`; each event exposes the same `detail` as the JSX handler.
336
+
337
+ ## Styling
338
+
339
+ Capture renders a block container with no shadow root. Use `className` or
340
+ `style` for layout, size, and appearance. Keep a CSS box on the host so its
341
+ bounds define the input surface and local coordinates.
342
+
343
+ Use [Box](./box.md) around Capture when you also need measurements, context events,
344
+ or edge fades. Box measures its own bounds; Capture reports coordinates relative
345
+ to its own bounds.