@antadesign/anta 0.3.34 → 0.3.35

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 (184) hide show
  1. package/LICENSE.md +14 -1
  2. package/README.md +9 -0
  3. package/dist/anta_helpers.d.ts +46 -30
  4. package/dist/anta_helpers.js +66 -25
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +2 -1333
  7. package/dist/components/Banner.d.ts +25 -40
  8. package/dist/components/Banner.js +15 -17
  9. package/dist/components/Button.js +1 -0
  10. package/dist/components/ButtonCopy.js +3 -2
  11. package/dist/components/Calendar.js +13 -13
  12. package/dist/components/Card.d.ts +9 -17
  13. package/dist/components/Card.js +50 -46
  14. package/dist/components/Dialog.d.ts +1 -0
  15. package/dist/components/Dialog.js +16 -10
  16. package/dist/components/Expander.d.ts +6 -21
  17. package/dist/components/Expander.js +24 -23
  18. package/dist/components/Icon.d.ts +8 -14
  19. package/dist/components/Input.d.ts +77 -96
  20. package/dist/components/Input.js +23 -27
  21. package/dist/components/InputAutocomplete.d.ts +29 -10
  22. package/dist/components/InputAutocomplete.js +25 -8
  23. package/dist/components/InputDate.js +2 -2
  24. package/dist/components/InputTime.d.ts +10 -4
  25. package/dist/components/InputTime.js +20 -16
  26. package/dist/components/Loader.d.ts +2 -2
  27. package/dist/components/Menu.d.ts +5 -4
  28. package/dist/components/Menu.js +13 -8
  29. package/dist/components/MenuItem.js +1 -14
  30. package/dist/components/MenuItemCopy.js +2 -2
  31. package/dist/components/Panel.d.ts +3 -1
  32. package/dist/components/Panel.js +17 -11
  33. package/dist/components/Progress.d.ts +21 -23
  34. package/dist/components/Progress.js +13 -9
  35. package/dist/components/RadioGroup.js +6 -8
  36. package/dist/components/{select-parts.css → Select.css} +1 -1
  37. package/dist/components/Select.d.ts +53 -35
  38. package/dist/components/Select.js +53 -97
  39. package/dist/components/SelectFaceted.d.ts +7 -3
  40. package/dist/components/SelectFaceted.js +21 -9
  41. package/dist/components/Slider.d.ts +28 -11
  42. package/dist/components/Slider.js +20 -20
  43. package/dist/components/Steps.css +1 -1
  44. package/dist/components/Steps.js +1 -11
  45. package/dist/components/Tabs.d.ts +17 -20
  46. package/dist/components/Tabs.js +5 -8
  47. package/dist/components/Text.d.ts +55 -36
  48. package/dist/components/Text.js +35 -22
  49. package/dist/components/Title.d.ts +16 -26
  50. package/dist/components/Title.js +2 -1
  51. package/dist/components/Toaster.js +9 -2
  52. package/dist/components/Tooltip.d.ts +10 -15
  53. package/dist/components/copy-props.d.ts +14 -3
  54. package/dist/components/copy-props.js +14 -3
  55. package/dist/components/select-tree.d.ts +24 -0
  56. package/dist/components/select-tree.js +35 -0
  57. package/dist/element-base.d.ts +10 -0
  58. package/dist/element-base.js +15 -0
  59. package/dist/elements/a-banner.css +1 -1
  60. package/dist/elements/a-banner.d.ts +4 -1
  61. package/dist/elements/a-banner.js +22 -112
  62. package/dist/elements/a-button.d.ts +2 -1
  63. package/dist/elements/a-button.js +18 -1
  64. package/dist/elements/a-calendar.d.ts +14 -13
  65. package/dist/elements/a-calendar.js +29 -24
  66. package/dist/elements/a-card.css +1 -1
  67. package/dist/elements/a-card.d.ts +0 -9
  68. package/dist/elements/a-card.js +0 -184
  69. package/dist/elements/a-checkbox.css +1 -1
  70. package/dist/elements/a-copy.css +1 -1
  71. package/dist/elements/a-copy.d.ts +1 -5
  72. package/dist/elements/a-copy.js +129 -108
  73. package/dist/elements/a-dialog.css +1 -1
  74. package/dist/elements/a-dialog.d.ts +1 -1
  75. package/dist/elements/a-dialog.js +66 -194
  76. package/dist/elements/a-expander.css +1 -1
  77. package/dist/elements/a-expander.d.ts +4 -30
  78. package/dist/elements/a-expander.js +85 -344
  79. package/dist/elements/a-icon.d.ts +5 -23
  80. package/dist/elements/a-icon.js +1 -2
  81. package/dist/elements/a-input-time.css +1 -1
  82. package/dist/elements/a-input-time.d.ts +2 -1
  83. package/dist/elements/a-input-time.js +101 -168
  84. package/dist/elements/a-input.css +1 -1
  85. package/dist/elements/a-input.d.ts +10 -8
  86. package/dist/elements/a-input.js +155 -230
  87. package/dist/elements/a-loader.d.ts +5 -8
  88. package/dist/elements/a-loader.js +1 -2
  89. package/dist/elements/a-menu-item.css +1 -1
  90. package/dist/elements/a-menu-item.d.ts +5 -3
  91. package/dist/elements/a-menu-item.js +5 -1
  92. package/dist/elements/a-menu.css +1 -1
  93. package/dist/elements/a-menu.d.ts +5 -7
  94. package/dist/elements/a-menu.js +383 -299
  95. package/dist/elements/a-panel.css +1 -1
  96. package/dist/elements/a-panel.js +19 -37
  97. package/dist/elements/a-progress.css +1 -1
  98. package/dist/elements/a-progress.d.ts +0 -22
  99. package/dist/elements/a-progress.js +0 -100
  100. package/dist/elements/a-radio-group.d.ts +1 -1
  101. package/dist/elements/a-radio-group.js +6 -4
  102. package/dist/elements/a-select-faceted.d.ts +1 -1
  103. package/dist/elements/a-select-faceted.js +1 -1
  104. package/dist/elements/a-select.d.ts +1 -1
  105. package/dist/elements/a-select.js +1 -1
  106. package/dist/elements/a-slider.css +1 -1
  107. package/dist/elements/a-slider.d.ts +11 -3
  108. package/dist/elements/a-slider.js +244 -242
  109. package/dist/elements/a-switch.css +1 -1
  110. package/dist/elements/a-tab.css +1 -1
  111. package/dist/elements/a-tabs.css +1 -1
  112. package/dist/elements/a-tabs.d.ts +1 -1
  113. package/dist/elements/a-tabs.js +6 -4
  114. package/dist/elements/a-tag.css +1 -1
  115. package/dist/elements/a-text.css +1 -1
  116. package/dist/elements/a-text.d.ts +6 -43
  117. package/dist/elements/a-text.js +110 -193
  118. package/dist/elements/a-title.css +1 -1
  119. package/dist/elements/a-toast.css +1 -1
  120. package/dist/elements/a-toast.d.ts +10 -45
  121. package/dist/elements/a-toast.js +80 -66
  122. package/dist/elements/a-toaster.css +1 -1
  123. package/dist/elements/a-toaster.js +9 -44
  124. package/dist/elements/a-tooltip.css +1 -1
  125. package/dist/elements/a-tooltip.d.ts +1 -1
  126. package/dist/elements/a-tooltip.js +142 -136
  127. package/dist/elements/copy-behavior.d.ts +1 -1
  128. package/dist/elements/copy-behavior.js +21 -21
  129. package/dist/elements/index.d.ts +3 -3
  130. package/dist/elements/index.js +3 -7
  131. package/dist/elements/input-focus-modality.d.ts +15 -0
  132. package/dist/elements/input-focus-modality.js +44 -0
  133. package/dist/elements/input-trailing-actions.d.ts +5 -0
  134. package/dist/elements/input-trailing-actions.js +38 -0
  135. package/dist/elements/shadow-aria.d.ts +2 -0
  136. package/dist/elements/shadow-aria.js +2 -1
  137. package/dist/elements/value-input.d.ts +3 -0
  138. package/dist/elements/value-input.js +12 -0
  139. package/dist/general_types.d.ts +103 -96
  140. package/dist/index.d.ts +1 -1
  141. package/dist/input-events.d.ts +4 -0
  142. package/dist/input-events.js +15 -0
  143. package/dist/jsx-runtime.d.ts +70 -23
  144. package/dist/jsx-runtime.js +26 -19
  145. package/dist/native-event-props.d.ts +2 -0
  146. package/dist/native-event-props.js +10 -0
  147. package/dist/reset.css +1 -1
  148. package/dist/theme-antithesis.css +10 -1
  149. package/dist/theme-antune.css +1 -1
  150. package/docs/accessibility.md +17 -3
  151. package/docs/changelog.md +348 -2
  152. package/docs/comparison.md +2 -2
  153. package/docs/components/avatar.md +5 -0
  154. package/docs/components/banner.md +117 -187
  155. package/docs/components/button.md +22 -0
  156. package/docs/components/card.md +74 -28
  157. package/docs/components/checkbox.md +9 -10
  158. package/docs/components/dialog.md +83 -32
  159. package/docs/components/expander.md +198 -435
  160. package/docs/components/icon.md +11 -17
  161. package/docs/components/input-autocomplete.md +152 -52
  162. package/docs/components/input-date.md +175 -148
  163. package/docs/components/input-time.md +81 -38
  164. package/docs/components/input.md +343 -349
  165. package/docs/components/loader.md +2 -1
  166. package/docs/components/menu.md +35 -6
  167. package/docs/components/panel.md +18 -0
  168. package/docs/components/progress.md +83 -49
  169. package/docs/components/radio.md +39 -43
  170. package/docs/components/select-faceted.md +54 -7
  171. package/docs/components/select.md +390 -386
  172. package/docs/components/slider.md +136 -19
  173. package/docs/components/steps.md +2 -1
  174. package/docs/components/switch.md +8 -9
  175. package/docs/components/tabs.md +110 -104
  176. package/docs/components/text.md +110 -86
  177. package/docs/components/title.md +47 -33
  178. package/docs/components/toaster.md +242 -84
  179. package/docs/components/tooltip.md +204 -113
  180. package/docs/install-config.md +183 -26
  181. package/docs/packages/plot.md +170 -148
  182. package/docs/theming.md +7 -0
  183. package/package.json +41 -3
  184. package/theme-antithesis-license.md +66 -0
@@ -1,27 +1,42 @@
1
1
  # Title
2
2
 
3
- A margin-free heading with six `level`s. `level` sets the type scale and the
4
- `aria-level` exposed to assistive technology. `priority` runs from `primary`
5
- through `quaternary` (`--text-1` through `--text-4`); `tone` accepts `neutral`
6
- (the default), a named tone, or a literal CSS color.
3
+ Use Title for page, section, and component headings. Choose a heading level,
4
+ then adjust its emphasis with `priority` and `tone`.
7
5
 
8
- Use a raw `<h1>`–`<h6>` for document-outline or SEO semantics. Anta's reset
9
- gives those headings the same type scale and document margins. Use `<Title>` in
10
- component layouts when you need tone, priority, or parent-controlled spacing.
11
-
12
- > **`<Title>` has no margins.** Space it with the parent’s `gap` or padding. For
13
- > a one-off, add `marginBlock` to the title itself.
6
+ Title has no margins. Use the parent's `gap` or padding to space it within a
7
+ layout. For native HTML heading elements, use `<h1>`–`<h6>` with Anta's reset.
14
8
 
15
9
  ## Levels
16
10
 
17
- The parent supplies the `16px` gap between these titles.
11
+ Choose `level` to match the heading hierarchy. It sets the type scale and the
12
+ heading level announced by screen readers. This example uses a parent `gap`
13
+ to space the titles.
14
+
15
+ ## Typeface
16
+
17
+ Use `serif` for page and section titles, `sans-serif` for cards, panels, and
18
+ metrics, and `monospace` for identifiers such as run IDs and file paths.
19
+
20
+ Omit `font` to use the theme's choice. The Antithesis theme uses serif for
21
+ levels 1–3 and sans serif for levels 4–6. Other themes use sans serif throughout.
22
+ Changing `font` preserves the heading's size and line height.
23
+
24
+ ```tsx
25
+ <Title level={2}>Recent runs</Title>
26
+ <Title level={2} font="sans-serif">Run 4821: 12 failures</Title>
27
+ <Title level={2} font="monospace">checkout-service/run_4821</Title>
28
+ ```
29
+
30
+ Each typeface covers all six levels.
31
+
32
+ ```tsx
33
+ <Title level={1} font="serif">Serif 1</Title>
34
+ <Title level={1} font="sans-serif">Sans serif 1</Title>
35
+ <Title level={1} font="monospace">Monospace 1</Title>
36
+ ```
18
37
 
19
- Level 1: Workspace settings
20
- Level 2: Recent activity
21
- Level 3: Security alerts
22
- Level 4: Sign-in policy
23
- Level 5: Session timeout
24
- Level 6: Updated five minutes ago
38
+ A string `header` on a [Card](./card.md) renders a sans-serif title at every card
39
+ size.
25
40
 
26
41
  ## Inline content
27
42
 
@@ -63,14 +78,15 @@ Use a number for multi-line titles.
63
78
  | 1 | 28px | 32px |
64
79
  | 2 | 24px | 28px |
65
80
  | 3 | 20px | 24px |
66
- | 4 | 17px | 20px |
81
+ | 4 | 17px | 22px |
67
82
  | 5 | 15px | 20px |
68
83
  | 6 | 13px | 16px |
69
84
 
70
85
  ## Tone × priority
71
86
 
72
- The four priorities are shown across every named tone at `level={3}`. Omit
73
- `tone` for the neutral scale. The grid scrolls horizontally on narrow screens.
87
+ Use `priority` to choose emphasis, from `primary` through `quaternary`.
88
+ Use `tone` for a named color or a custom CSS color. Omit it for neutral text.
89
+ The examples compare every named tone at `level={3}`.
74
90
 
75
91
 
76
92
  Neutral primary
@@ -106,25 +122,25 @@ The four priorities are shown across every named tone at `level={3}`. Omit
106
122
 
107
123
  ## Accessibility
108
124
 
109
- `<Title>` renders an `<a-title>` tag with `role="heading"` and
110
- `aria-level={level}`. It is not a real `<h*>`. Use a raw heading when the HTML
111
- document outline or SEO needs heading elements; the reset applies the same type
112
- scale.
125
+ Title exposes `role="heading"` and an `aria-level` matching `level`. Choose
126
+ levels that follow the page's heading hierarchy. When your integration requires
127
+ native HTML headings, use `<h1>`–`<h6>` with Anta's reset for the same type scale
128
+ and document margins.
113
129
 
114
130
  ## Component props
115
131
 
116
132
  | Prop | Type | Default | Description |
117
133
  |------|------|---------|-------------|
118
- | `level?` | 1 \| 2 \| 3 \| 4 \| 5 \| 6 | 2 | Heading level, 1-6. Drives font-size, line-height, and vertical rhythm. Also surfaced to assistive tech via `aria-level` (h1 is typically reserved for the page title). |
134
+ | `font?` | 'serif' \| 'sans-serif' \| 'monospace' | — | Typeface. Serif names the page and its parts; sans serif names objects on the page, such as cards, panels, and metrics; monospace names technical identifiers, such as run IDs, hashes, and file paths. Omit it to let the theme choose by level: the Antithesis theme sets levels 1–3 in serif and 4–6 in sans serif, and other themes use sans serif throughout. |
135
+ | `level?` | 1 \| 2 \| 3 \| 4 \| 5 \| 6 | 2 | Heading level, 1–6. Sets the type scale and the `aria-level` exposed to assistive technology (h1 is typically reserved for the page title). |
119
136
  | `priority?` | 'primary' \| 'secondary' \| 'tertiary' \| 'quaternary' | primary | Visual priority. Maps to text-1..text-4 (`primary` = text-1). |
120
137
  | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | neutral | Color tint. `neutral` (the default) is the untinted `--text-{N}` scale; a named tone applies the matching `--text-{N}-{tone}` palette. Any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) is a one-off custom tone — its hue is kept while lightness/chroma are pinned per priority in oklch. |
121
138
  | `truncate?` | boolean \| number | — | Truncate with a trailing ellipsis. `true` (or `1`) clamps to a single line; any integer ≥ 2 clamps to that many lines; `0` or a negative value means no truncation. A clipped JSX `Title` shows its text content in a tooltip by default. Nest a `<Tooltip>` to provide your own tooltip instead. |
122
139
 
123
140
  ## Web Component
124
141
 
125
- Use the web component directly when you are not using React or Preact and a native control does not fit.
126
-
127
- Set the heading role and level when writing `<a-title>` directly.
142
+ Use `<a-title>` directly outside JSX. Set both `role="heading"` and
143
+ `aria-level` to describe its place in the heading hierarchy.
128
144
 
129
145
  ```html
130
146
  <a-title level="2" tone="brand" role="heading" aria-level="2">
@@ -134,17 +150,15 @@ Set the heading role and level when writing `<a-title>` directly.
134
150
 
135
151
  ## Styling
136
152
 
137
- `priority` selects a neutral text level. Named `tone`s use the matching global
138
- text tokens. A literal `tone` is stored in `--title-tone-source` and resolved
139
- into the four priority levels.
153
+ Start with `priority` and `tone` for emphasis and color:
140
154
 
141
155
  ```tsx
142
156
  <Title priority="secondary">Supporting heading</Title>
143
157
  <Title tone="#0d9488">Custom-tone heading</Title>
144
158
  ```
145
159
 
146
- `<a-title>` is light DOM, so local type treatment is ordinary CSS. The class is
147
- only for this example.
160
+ Target `a-title` with ordinary CSS to adjust its typography. The
161
+ `.release-heading` class scopes this example. Replace it with your own selector.
148
162
 
149
163
  ```css
150
164
  a-title.release-heading {
@@ -1,20 +1,158 @@
1
1
  # Toaster
2
2
 
3
- A viewport-anchored region that shows toasts — short, self-dismissing notices
4
- stacked in a corner. It isn't a fixed "toast card": you toast **anything** — a
5
- `Banner`, a `Card`, a `Sticker`, a string, a bespoke node — and the region handles
6
- placement, stacking, and the auto-dismiss timer.
7
-
8
- Two pieces work together. **`<Toaster>`** is the region; you mount one and keep it
9
- mounted (a portal is fine). **`Toaster.manager`** is the store you drive from
10
- anywhere: `Toaster.manager.add(render)` adds a toast, where `render` is a function
11
- returning the content. The store holds no DOM — the mounted `<Toaster>` subscribes
12
- to it and renders each toast through React/Preact, so there's nowhere for a toast
13
- to go if no `<Toaster>` is mounted.
14
-
15
- Configure one toast and fire it — the playground shows the render function plus the
16
- options object you pass to `add`. Edit the `Banner` in the code (or the props panel)
17
- and the `{ placement, duration }` it's toasted with.
3
+ Show temporary notices in one of six viewport placements. Toast a `Banner`,
4
+ `Card`, string, JSX, or an existing DOM node. Toaster handles placement, stacking,
5
+ and dismissal timing.
6
+
7
+ Mount `Toaster` once in your application, then call `Toaster.manager.add()`
8
+ when an action needs feedback.
9
+
10
+ ```tsx title="ToasterDemo.tsx"
11
+ import { useState } from 'preact/hooks'
12
+ import { Toaster, Button, Input, Banner, Card } from '@antadesign/anta'
13
+ import { StickerClap } from '@antadesign/stickers'
14
+ import styles from './ToasterDemo.module.css'
15
+
16
+ export default function ToasterDemo() {
17
+ const [duration, setDuration] = useState('4000')
18
+
19
+ // Empty / zero / non-numeric → the 5000ms default (0 is not sticky; sticky is Infinity).
20
+ const opts = () => ({ placement: 'bottom-right' as const, duration: Number(duration) || 5000 })
21
+
22
+ return (
23
+ <div className={styles.demo}>
24
+ {/* The region — kept mounted for the store to render into. */}
25
+ <Toaster />
26
+
27
+ <div className={styles.controls}>
28
+ <Input
29
+ leading="Duration"
30
+ trailing="ms"
31
+ type="number"
32
+ defaultValue="4000"
33
+ onValueChange={(_e, a) => setDuration(a.value)}
34
+ />
35
+ </div>
36
+
37
+ <div className={styles.buttons}>
38
+ <Button
39
+ priority="secondary"
40
+ label="Toast text"
41
+ onClick={() => Toaster.manager.add(() => 'Your changes were saved.', opts())}
42
+ />
43
+ <Button
44
+ priority="secondary"
45
+ tone="success"
46
+ label="Toast a Banner"
47
+ onClick={() =>
48
+ Toaster.manager.add(
49
+ (id) => (
50
+ <Banner
51
+ tone="success"
52
+ round
53
+ message="Your changes were saved."
54
+ onDismiss={() => Toaster.manager.dismiss(id)}
55
+ />
56
+ ),
57
+ opts(),
58
+ )
59
+ }
60
+ />
61
+ <Button
62
+ priority="secondary"
63
+ tone="info"
64
+ label="Toast a Card"
65
+ onClick={() =>
66
+ Toaster.manager.add(
67
+ () => (
68
+ <Card tone="info" size="small" header="Deployment ready">
69
+ Your build passed all checks.{' '}
70
+ <Button size="small" priority="tertiary" label="Dismiss" data-toast-dismiss />
71
+ </Card>
72
+ ),
73
+ opts(),
74
+ )
75
+ }
76
+ />
77
+ <Button
78
+ priority="secondary"
79
+ tone="brand"
80
+ label="Toast a Sticker"
81
+ onClick={() => Toaster.manager.add(() => <StickerClap size={96} label="Nice work" />, opts())}
82
+ />
83
+ <Button
84
+ priority="secondary"
85
+ label="Toast with countdown"
86
+ onClick={() => {
87
+ const ms = Number(duration) || 5000
88
+ Toaster.manager.add(
89
+ (id) => (
90
+ <div className={styles.countdownToast}>
91
+ <Banner
92
+ tone="info"
93
+ round
94
+ message="Auto-dismissing — hover to pause"
95
+ onDismiss={() => Toaster.manager.dismiss(id)}
96
+ />
97
+ {/* Reads the toast's own --toast-remaining — no duration passed. */}
98
+ <span className={styles.countdownBar} />
99
+ </div>
100
+ ),
101
+ { placement: 'bottom-right', duration: ms },
102
+ )
103
+ }}
104
+ />
105
+ </div>
106
+ </div>
107
+ )
108
+ }
109
+ ```
110
+
111
+ ```css title="ToasterDemo.module.css"
112
+ .demo {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: 12px;
116
+ }
117
+
118
+ .controls {
119
+ display: flex;
120
+ gap: 12px;
121
+ align-items: center;
122
+ flex-wrap: wrap;
123
+ }
124
+
125
+ .buttons {
126
+ display: flex;
127
+ gap: 8px;
128
+ flex-wrap: wrap;
129
+ }
130
+
131
+ .countdownToast {
132
+ position: relative;
133
+ }
134
+
135
+ .countdownBar {
136
+ position: absolute;
137
+ left: 10px;
138
+ right: 10px;
139
+ bottom: 5px;
140
+ height: 3px;
141
+ border-radius: 999px;
142
+ transform-origin: left;
143
+ background: color-mix(in oklch, currentColor 35%, transparent);
144
+ transform: scaleX(var(--toast-remaining));
145
+ }
146
+
147
+ @media (prefers-reduced-motion: reduce) {
148
+ .countdownBar {
149
+ display: none;
150
+ }
151
+ }
152
+ ```
153
+
154
+ Use the playground to try notification content, placement, and duration.
155
+ Edit the Banner and the options passed to `add`.
18
156
 
19
157
  ## Mount the region, drive the store
20
158
 
@@ -33,8 +171,8 @@ function App() {
33
171
  }
34
172
  ```
35
173
 
36
- Then, from anywhere, add a toast by passing a render function. The simplest case is
37
- a string — it's wrapped in a dismissible `Banner` for you:
174
+ Add a toast by passing a function that returns its content. Returning a string
175
+ creates a dismissible Banner:
38
176
 
39
177
  ```tsx
40
178
  import { Toaster } from '@antadesign/anta'
@@ -42,16 +180,14 @@ import { Toaster } from '@antadesign/anta'
42
180
  Toaster.manager.add(() => 'Saved.', { placement: 'bottom-right' })
43
181
  ```
44
182
 
45
- `add` returns an `id`, and the render function receives it — so a toast can dismiss
46
- itself. See [Timing and dismissal](#timing-and-dismissal) for how each kind of
47
- content closes its toast.
183
+ `add` returns an `id` and passes it to the render function. Use it to update or
184
+ dismiss that notification. See [Timing and dismissal](#timing-and-dismissal).
48
185
 
49
186
  ## Toast anything
50
187
 
51
- The render function can return a **string, JSX, or a live DOM node** — the same
52
- `add` handles all three. A bare string / number is wrapped in a dismissible `Banner`;
53
- other JSX renders through the reconciler as-is; a DOM node is slotted by the element
54
- (return a *stable* node, created once, not a fresh one per call).
188
+ Return a string or number for a dismissible Banner, or JSX for custom content.
189
+ For an existing widget, return its DOM node. Use a stable node that is not owned
190
+ by another React or Preact tree.
55
191
 
56
192
  ```tsx
57
193
  // JSX — rendered as-is
@@ -68,10 +204,18 @@ el.textContent = '🎉'
68
204
  Toaster.manager.add(() => el)
69
205
  ```
70
206
 
71
- Returning a raw DOM node **into React errors** if you hand it to JSX directly —
72
- `add` avoids that by routing a `Node` to the element instead of the reconciler.
73
- (Toast a JSX component like `<Banner/>` by returning it; reach for a DOM node only
74
- when you already have one, e.g. from a non-React widget.)
207
+ ### Existing DOM nodes
208
+
209
+ Return a DOM node from the render function rather than placing it directly in
210
+ JSX. Toast moves the original node into its content region, preserving listeners
211
+ and widget state. It does not clone the node or restore its previous parent when
212
+ the toast is removed.
213
+
214
+ When using the raw `content` property, replacing or clearing it removes only
215
+ nodes previously supplied through that property. A fragment's children move into
216
+ the toast, leaving the fragment empty. Refill and reassign the fragment to
217
+ replace those children. The getter returns the assigned node, or `null` after
218
+ clearing. Never supply a node still owned by another renderer.
75
219
 
76
220
  ## Placement
77
221
 
@@ -80,29 +224,25 @@ grow upward (newest nearest the edge), top zones grow downward. Six values:
80
224
 
81
225
  `top-left`, `top-center`, `top-right`, `bottom-left`, `bottom-center`, `bottom-right`.
82
226
 
83
- One `<Toaster>` serves every placement — each toast routes to its own zone, so a
84
- single mounted region drops notices in any corner.
227
+ One Toaster serves all six placements. Choose a placement for each notification.
85
228
 
86
229
  ## Timing and dismissal
87
230
 
88
- Each toast auto-dismisses after `duration` (ms), 5000 by default; the countdown
89
- pauses while the pointer is over the toast **or** focus is inside it. `duration:
90
- Infinity` keeps it until dismissed (empty, zero, and non-positive values fall back
91
- to the default). On dismiss the toast animates out and then leaves.
231
+ Set `duration` in milliseconds to control how long a notification stays visible.
232
+ The default is 5000ms. The timer pauses while the toast is hovered or contains
233
+ focus. Pass `Infinity` to keep it until dismissed. Empty, zero, and non-positive
234
+ values use the default. Dismissing a toast plays its exit animation, then removes it.
92
235
 
93
236
  ```tsx
94
237
  Toaster.manager.add(() => 'Still here until you close it', { duration: Infinity }) // sticky
95
238
  ```
96
239
 
97
- The toast itself carries **no ✕** — dismissal comes from the content. Three ways,
98
- depending on what you toast:
240
+ Provide a dismissal action when a notification should be closable before its
241
+ timer ends:
99
242
 
100
- - **A string** auto-wraps in a `Banner`, so its ✕ is there for free.
101
- - **Any control carrying `data-toast-dismiss`** dismisses the toast on click. This is
102
- the simplest path — no handler, no `id`, no `onDismiss`; the render function doesn't
103
- even take an argument. Add the attribute to a button, link, or menu item inside
104
- the content (the same convention as `<a-banner>`'s `data-banner-dismiss` and
105
- `<a-dialog>`'s `data-dialog-close`):
243
+ - A string becomes a Banner with its own close button.
244
+ - Add `data-toast-dismiss` to a button, link, or menu item inside custom content
245
+ to dismiss its toast without a separate handler:
106
246
 
107
247
  ```tsx
108
248
  Toaster.manager.add(() => (
@@ -112,9 +252,8 @@ depending on what you toast:
112
252
  ))
113
253
  ```
114
254
 
115
- - **A `Banner` you toast yourself** dismisses through its own `onDismiss` — wire it
116
- to `dismiss(id)`, and its ✕ (plus any `data-banner-dismiss` action inside it)
117
- closes the toast:
255
+ - For a Banner you render yourself, connect `onDismiss` to `dismiss(id)`.
256
+ Its close button and any `data-banner-dismiss` actions then close the toast:
118
257
 
119
258
  ```tsx
120
259
  Toaster.manager.add((id) => (
@@ -131,9 +270,8 @@ Toaster.manager.update(id, () => 'Saved') // swap content in place
131
270
  Toaster.manager.clear() // dismiss all
132
271
  ```
133
272
 
134
- Pass your own `id` to **upsert** — a second `add` with the same id replaces the
135
- live toast's content and restarts its timer, instead of stacking a duplicate. Good
136
- for a step that reports progress, or to dedupe a repeated event:
273
+ Pass the same `id` to update an existing notification and restart its timer.
274
+ Use this for task progress or repeated events that should share one notice:
137
275
 
138
276
  ```tsx
139
277
  Toaster.manager.add(() => <Banner message="Saving…" />, { id: 'save' })
@@ -143,12 +281,11 @@ Toaster.manager.add(() => <Banner tone="success" message="Saved" />, { id: 'save
143
281
 
144
282
  ## Show the time left
145
283
 
146
- The toast exposes how much of its timer is left as **`--toast-remaining`** — a
147
- number that animates from `1` (just shown) to `0` (about to dismiss), inherited by
148
- the content. Draw a countdown with one CSS rule that reads it. No duration to pass,
149
- no keyframes, no timer of your own — and it pauses with the toast (hover / focus)
150
- because the variable itself pauses. Try **Toast with countdown** in the demo above
151
- and hover it.
284
+ Read `--toast-remaining` to draw a countdown. It decreases from `1` to `0` and
285
+ pauses while the toast is hovered or contains focus. Use the same value for the
286
+ bar so it follows the notification's timer.
287
+
288
+ Try **Toast with countdown** and hover the notification to pause it.
152
289
 
153
290
  ```tsx
154
291
  Toaster.manager.add(
@@ -172,23 +309,20 @@ Toaster.manager.add(
172
309
  }
173
310
  ```
174
311
 
175
- **Why a variable, not a prop?** You could instead pass `secondsLeft` into the render
176
- function and tick it. But updating a prop re-runs the render function and re-diffs the
177
- whole toast — the Banner, its ✕, everything — many times a second, which can disturb
178
- focus, text selection, or an in-progress animation inside the content. `--toast-remaining`
179
- updates a single inherited value the browser interpolates on the compositor: the
180
- content renders **once**, nothing reconciles, and it's smooth at display refresh rate
181
- instead of the application's tick interval. The toast already tracks its timer
182
- and pause state, so exposing the value keeps one source of truth.
312
+ The countdown is visual feedback. Dismissal still follows `duration` if the
313
+ browser cannot animate the custom property. With `duration: Infinity`, the
314
+ value stays at `1`.
315
+
316
+ Hide a custom countdown bar for people who prefer reduced motion:
183
317
 
184
- `--toast-remaining` is display only — the real dismissal is the toast's own timer — so
185
- where a browser can't animate a custom property it simply stays full. A **sticky**
186
- (`duration: Infinity`) toast has no countdown; the value stays `1`.
318
+ ```css
319
+ @media (prefers-reduced-motion: reduce) {
320
+ .countdown-bar { display: none; }
321
+ }
322
+ ```
187
323
 
188
- The bar is motion — if you draw one, gate it under `prefers-reduced-motion` yourself
189
- (e.g. `@media (prefers-reduced-motion: reduce) { .countdown-bar { display: none } }`).
190
- `a-toast`'s own enter/exit fades are already suppressed there; `--toast-remaining`
191
- keeps ticking so non-visual uses still work, and the toast still auto-dismisses.
324
+ Toast already suppresses its entrance and exit fades for reduced motion.
325
+ The timer continues, so notifications still dismiss on schedule.
192
326
 
193
327
  ## Multiple regions
194
328
 
@@ -207,17 +341,27 @@ export const alerts = createToaster()
207
341
  alerts.add(() => <Banner tone="critical" message="Connection lost" />, { placement: 'top-center' })
208
342
  ```
209
343
 
210
- One store drives one `<Toaster>`.
344
+ Use one Toaster per store.
345
+
346
+ ### Server rendering and shared stores
347
+
348
+ Keep toast stores empty during server rendering to avoid hydration mismatches.
349
+ Follow [Browser hydration](../install-config.md#browser-hydration) before mounting.
350
+
351
+ Use the same JSX entry for a region and its default `Toaster.manager`.
352
+ Independent full and granular builds have separate default stores. To coordinate
353
+ across those entries, pass the same `createToaster()` store explicitly.
211
354
 
212
355
  ## Announcements
213
356
 
214
- Announcement is opt-in **per toast**: pass `politeness` to give that toast an
215
- `aria-live` region — `'polite'` waits for a pause, `'assertive'` interrupts. Omit
216
- it for no announcement, which is right when the content carries its own live
217
- semantics (a `Banner` defaults to `role="status"`).
357
+ Use `politeness: 'polite'` for a routine screen reader announcement, or
358
+ `'assertive'` for an urgent notice that should interrupt. Omit it when the
359
+ content already supplies its announcement. Banner defaults to `role="status"`.
360
+ When Toaster supplies the announcement, set the Banner's role to `none` to
361
+ avoid nested live regions.
218
362
 
219
363
  ```tsx
220
- Toaster.manager.add(() => <Banner tone="critical" message="Connection lost" />, {
364
+ Toaster.manager.add(() => <Banner role="none" tone="critical" message="Connection lost" />, {
221
365
  politeness: 'assertive',
222
366
  })
223
367
  ```
@@ -231,11 +375,11 @@ Toaster.manager.add(() => <Banner tone="critical" message="Connection lost" />,
231
375
 
232
376
  ## Web Component
233
377
 
234
- Use the web component directly when you are not using React or Preact and a native control does not fit.
378
+ Use `<a-toaster>` and `<a-toast>` directly outside JSX. Place each toast in a
379
+ slot named for its placement, such as `bottom-center`. Add a dismissal control
380
+ with `data-toast-dismiss`, then listen for `dismiss` and remove that toast.
235
381
 
236
- Place each `<a-toast>` in a positional slot. This button clones the toast template
237
- into the toaster. `data-toast-dismiss` requests removal; listen for `dismiss` and
238
- remove the toast from the DOM.
382
+ This example adds a notification by cloning a template:
239
383
 
240
384
  ```html
241
385
  <div data-anta-composition="toaster">
@@ -245,8 +389,8 @@ remove the toast from the DOM.
245
389
  <template data-toast-template>
246
390
  <a-toast slot="bottom-center" aria-live="polite">
247
391
  <a-banner tone="info" round>
248
- <a-banner-message slot="message">A new version is available.</a-banner-message>
249
- <a-button slot="actions" role="button" tabindex="0" data-toast-dismiss><a-button-label>Dismiss</a-button-label></a-button>
392
+ <a-banner-message>A new version is available.</a-banner-message>
393
+ <a-banner-actions><a-button role="button" tabindex="0" data-toast-dismiss><a-button-label>Dismiss</a-button-label></a-button></a-banner-actions>
250
394
  </a-banner>
251
395
  </a-toast>
252
396
  </template>
@@ -267,10 +411,20 @@ remove the toast from the DOM.
267
411
  </script>
268
412
  ```
269
413
 
414
+ ### Raw toast timing
415
+
416
+ `duration="Infinity"` keeps a toast until dismissed. Missing, empty, zero,
417
+ negative, and invalid durations use 5000ms. Hover and focus each pause the timer.
418
+
419
+ Change `rev` or call `restart()` to restart the countdown. Changing `duration`
420
+ alone applies on the next restart. Reconnecting starts a fresh duration or
421
+ resumes a pending exit. The `dismiss` event fires after the exit animation.
422
+ The application then removes the element.
423
+
270
424
  ## Styling
271
425
 
272
426
  The region and item are plain custom elements — style them with ordinary CSS
273
- (`@layer anta`, so an un-layered rule of yours wins without `!important`).
427
+ (defaults use `@layer anta.components`, so an unlayered rule wins without `!important`).
274
428
 
275
429
  Region spacing lives on `a-toaster` as tokens: **`--toaster-inset`** (gap from the
276
430
  viewport edge), **`--toaster-gap`** (space between stacked toasts), and
@@ -288,8 +442,12 @@ a-toaster { --toaster-width: 420px; --toaster-gap: 10px; }
288
442
  a-toast { filter: drop-shadow(0 6px 20px color-mix(in oklch, black 22%, transparent)); }
289
443
  ```
290
444
 
291
- The content keeps its own styling — a toned `Banner` brings its surface, a `Card`
292
- its border.
445
+ The content keeps its own styling. A toned `Banner` brings its surface; a `Card`
446
+ brings its border. `a-toaster::part(region)` reaches the popover surface.
447
+ `::part(zone)` reaches all six columns, and `::part(top-left)` through
448
+ `::part(bottom-right)` reaches one placement. `a-toast::part(content)` reaches
449
+ the content slot. Keep columns and the region click-through when customizing
450
+ their appearance. Countdown timing belongs to `duration` and `restart()`.
293
451
 
294
452
  ## Example
295
453