@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,364 @@
1
+ export const initialsOnly = { headRadiusTop: { mode: 'off' }, headRadiusBottom: { mode: 'off' }, bodyBorderRadius: { mode: 'off' } }
2
+
3
+ export const brandRange = { bgColor: { mode: 'range', l: [0.5, 0.62], c: [0.09, 0.15], h: [255, 285] }, harmony: true }
4
+
5
+ export const palette = { bgColor: { mode: 'list', values: ['#6c5ce7', '#00b894', '#e17055', '#0984e3', '#fdcb6e'] }, headRadiusTop: { mode: 'off' }, headRadiusBottom: { mode: 'off' }, bodyBorderRadius: { mode: 'off' } }
6
+
7
+ # Avatar
8
+
9
+ A userpic container. `Avatar` shows one of three things, in priority order: a
10
+ supplied image, a seed-generated placeholder figure, or initials. The generated
11
+ figure imitates a framed portrait — a head and shoulders over a colored
12
+ background — with no face or gender indicators, so an app can fill an empty slot
13
+ with a distinct, on-brand picture per user without an uploaded photo.
14
+
15
+ An alphanumeric `seed` drives the result deterministically: the same seed always
16
+ renders the same avatar, and different seeds are distinguishable. A `generator`
17
+ config caps each dimension to your brand.
18
+
19
+ ## Generated userpic
20
+
21
+ Pass a `seed` (a stable user id) and a `name`. With no `generator`, each seed
22
+ draws a varied figure: background, head, and body colors, the figure's scale, the
23
+ head and shoulder angles, and the corner radius of each shape all move with the
24
+ seed, while the head and body hues stay coordinated with the background.
25
+
26
+ ```tsx
27
+ <Avatar seed="user-42" name="Vlad Korobov" />
28
+ <Avatar seed="lena-r" name="Lena Rossi" />
29
+ <Avatar seed="8f21ac" name="Sam Okafor" />
30
+ ```
31
+
32
+ ## Initials
33
+
34
+ Turn the shape dimensions off in the `generator` and the avatar falls back to
35
+ initials — the first letter of each of the first three words of `name` — over the
36
+ generated background. The background color still varies with the seed.
37
+
38
+ ```tsx
39
+ const initials = {
40
+ headRadiusTop: { mode: 'off' },
41
+ headRadiusBottom: { mode: 'off' },
42
+ bodyBorderRadius: { mode: 'off' },
43
+ }
44
+
45
+ <Avatar name="Vlad Korobov" generator={initials} />
46
+ <Avatar name="Marie Skłodowska Curie" generator={initials} />
47
+ <Avatar name="Madonna" generator={initials} />
48
+ ```
49
+
50
+ ## Image and badge
51
+
52
+ Set `src` to show an uploaded photo instead of a generated figure, cropped to
53
+ fill the container.
54
+
55
+ `badge` adds a corner badge, colored by tone, on any avatar — image or generated.
56
+ It takes any named tone, so the application decides what each one means:
57
+ `success` for online, `critical` for busy, `warning` for idle, `neutral` for
58
+ offline. Named tones track light and dark mode automatically.
59
+
60
+ The badge sits in a hole masked out of the picture rather than behind a painted
61
+ ring, so whatever is behind the avatar shows through the gap and no ring color
62
+ has to track the surface.
63
+
64
+ ```tsx
65
+ <Avatar round src="/anta-logo.svg" name="Anta" badge="success" />
66
+ <Avatar seed="lena-r" name="Lena Rossi" badge="critical" />
67
+ <Avatar seed="8f21ac" name="Sam Okafor" badge="warning" />
68
+ <Avatar seed="k-tanaka" name="Kenji Tanaka" badge="info" />
69
+ ```
70
+
71
+ `badge` also accepts any literal CSS color for a one-off badge, derived in oklch
72
+ the same way a named tone is.
73
+
74
+ ```tsx
75
+ <Avatar seed="a-lee" name="Ann Lee" badge="#ff1493" />
76
+ <Avatar seed="b-qi" name="Bo Qi" badge="rebeccapurple" />
77
+ ```
78
+
79
+ ## Size
80
+
81
+ `size` is `small` (32px), `medium` (44px, the default), or `large` (64px). Pass a
82
+ number for a pixel size.
83
+
84
+ ```tsx
85
+ <Avatar seed="user-42" name="Vlad Korobov" size="small" />
86
+ <Avatar seed="user-42" name="Vlad Korobov" size="large" />
87
+ <Avatar seed="user-42" name="Vlad Korobov" size={96} />
88
+ ```
89
+
90
+ ## Round
91
+
92
+ `round` makes the frame a circle. Pass a number (px) or a CSS length for a custom
93
+ radius instead. The badge hugs the circle's edge on a round frame.
94
+
95
+ ```tsx
96
+ <Avatar round seed="user-42" name="Vlad Korobov" />
97
+ <Avatar round seed="lena-r" name="Lena Rossi" badge="success" />
98
+ <Avatar seed="k-tanaka" name="Kenji Tanaka" round={10} />
99
+ ```
100
+
101
+ ## Brand constraints
102
+
103
+ The `generator` config caps the space so every avatar sits on your brand. Each
104
+ dimension takes one of four modes: `off` (excluded, a fixed default), `any` (its
105
+ full natural range), `range` (an explicit range), or `list` (a set of values the
106
+ seed picks from). Edit the config in the playground's **Code** tab to try them.
107
+
108
+ **Color ranges** cap OKLCH per channel — lightness, chroma, and hue. Narrow the
109
+ hue to your brand's, keep chroma modest, and every generated color stays in band
110
+ (chroma is clamped into sRGB, so it never clips). `harmony` ties the head and
111
+ body hue to the background.
112
+
113
+ ```tsx
114
+ const brand = {
115
+ bgColor: { mode: 'range', l: [0.5, 0.62], c: [0.09, 0.15], h: [255, 285] },
116
+ harmony: true,
117
+ }
118
+
119
+ <Avatar seed={user.id} name={user.name} generator={brand} />
120
+ ```
121
+
122
+ **Color lists** pass an explicit palette — a scheme the seed picks from at
123
+ random. Combine with `off` shapes for a classic initials avatar restricted to
124
+ your palette.
125
+
126
+ ```tsx
127
+ const palette = {
128
+ bgColor: { mode: 'list', values: ['#6c5ce7', '#00b894', '#e17055', '#0984e3', '#fdcb6e'] },
129
+ headRadiusTop: { mode: 'off' },
130
+ headRadiusBottom: { mode: 'off' },
131
+ bodyBorderRadius: { mode: 'off' },
132
+ }
133
+
134
+ <Avatar name={user.name} generator={palette} />
135
+ ```
136
+
137
+ ### The dimensions
138
+
139
+ | Dimension | Range |
140
+ | --- | --- |
141
+ | `bgColor`, `headColor`, `bodyColor` | OKLCH `l` / `c` / `h` caps, or a palette via `list` |
142
+ | `figureScale` | Relative size of the whole figure |
143
+ | `figureTranslate` | X and Y shift from the centered position |
144
+ | `figureAngle` | Rotation of the whole figure |
145
+ | `headAngle`, `bodyAngle` | Rotation of each part within the figure |
146
+ | `figureGap` | Space between head and body, `0` to `1` of head height |
147
+ | `headRadiusTop`, `headRadiusBottom` | `0` square, `1` fully round, above `1` elongated |
148
+ | `bodyBorderRadius` | `0` square to `1` fully round shoulders |
149
+
150
+ Corner radius is normalized: `0` is a square corner and `1` is fully round, so a
151
+ head with both radii at `1` is a circle. **Above `1` the head elongates** into an
152
+ oval, spending the excess on that half's height — `1.3` on both radii is a tall
153
+ oval, and more at the bottom than the top is an egg.
154
+
155
+ Two rules keep the head reading as a head. The bottom is never rounded less than
156
+ the top, so a value below the top radius is raised to match it: a rounder crown
157
+ over a squarer jaw reads mechanical, and the reverse reads natural. And under
158
+ `any` both radii average near or above `1`, so heads read round to oval unless
159
+ you narrow them yourself.
160
+
161
+ ## Generator config
162
+
163
+ `generator` takes an `AvatarGenConfig`. Every field is optional — anything you
164
+ leave out keeps its default from the table above.
165
+
166
+ ```ts
167
+ interface AvatarGenConfig {
168
+ bgColor?: ColorDim
169
+ headColor?: ColorDim
170
+ bodyColor?: ColorDim
171
+ figureScale?: ScalarDim
172
+ figureTranslate?: Vec2Dim
173
+ figureAngle?: ScalarDim
174
+ headAngle?: ScalarDim
175
+ bodyAngle?: ScalarDim
176
+ figureGap?: ScalarDim
177
+ headRadiusTop?: ScalarDim
178
+ headRadiusBottom?: ScalarDim
179
+ bodyBorderRadius?: ScalarDim
180
+ harmony?: boolean
181
+ }
182
+
183
+ type DimMode = 'off' | 'any' | 'range' | 'list'
184
+ ```
185
+
186
+ ### Modes
187
+
188
+ Every dimension carries a `mode`. It decides which of the dimension's other
189
+ fields are read; the rest are ignored.
190
+
191
+ | `mode` | Behavior | Fields read |
192
+ | --- | --- | --- |
193
+ | `off` | Excluded. The dimension holds a fixed neutral default. | none |
194
+ | `any` | Varies across the dimension's full natural range (the default). | none |
195
+ | `range` | Varies within an explicit range. | `min` / `max`, or `l` / `c` / `h`, or `x` / `y` |
196
+ | `list` | Picks one value at random from an explicit set. | `values` |
197
+
198
+ ### Dimension types
199
+
200
+ **`ScalarDim`** — a single number: scale, an angle, the gap, a corner radius.
201
+
202
+ ```ts
203
+ interface ScalarDim {
204
+ mode?: DimMode
205
+ min?: number // range: lower bound
206
+ max?: number // range: upper bound
207
+ values?: number[] // list: the allowed values
208
+ }
209
+ ```
210
+
211
+ **`ColorDim`** — a color. `range` caps OKLCH per channel as `[min, max]` pairs,
212
+ with chroma clamped into sRGB so a value can never clip. `list` passes a palette
213
+ of any CSS colors.
214
+
215
+ ```ts
216
+ interface ColorDim {
217
+ mode?: DimMode
218
+ l?: [number, number] // range: lightness, 0 to 1
219
+ c?: [number, number] // range: chroma, 0 to ~0.4
220
+ h?: [number, number] // range: hue, 0 to 360
221
+ values?: string[] // list: the allowed CSS colors
222
+ }
223
+ ```
224
+
225
+ **`Vec2Dim`** — the figure's offset from center, used only by `figureTranslate`.
226
+ Each axis runs from −50 to 50 in the frame's coordinates, where 0 centers the
227
+ head.
228
+
229
+ ```ts
230
+ interface Vec2Dim {
231
+ mode?: DimMode // 'list' is not used here
232
+ x?: [number, number] // range: horizontal bounds
233
+ y?: [number, number] // range: vertical bounds
234
+ values?: [number, number][] // list: allowed [x, y] points
235
+ }
236
+ ```
237
+
238
+ `harmony` is a plain boolean rather than a dimension: when true, `headColor` and
239
+ `bodyColor` take their hue from the background so the parts stay coordinated.
240
+
241
+ ### Defaults per dimension
242
+
243
+ What `off` pins each dimension to, and what `any` samples. Corner radii are
244
+ sampled toward the top of their range, so heads average round to oval.
245
+
246
+ | Dimension | `off` | `any` samples |
247
+ | --- | --- | --- |
248
+ | `bgColor` | mid grey | `l` 0.5–0.82, `c` 0.02–0.12, any hue |
249
+ | `headColor` | light grey | `l` 0.78–0.96, `c` 0.015–0.075, any hue |
250
+ | `bodyColor` | light grey | `l` 0.68–0.9, `c` 0.015–0.09, any hue |
251
+ | `figureScale` | `1` | 0.76–1.2 |
252
+ | `figureTranslate` | `[0, 0]` | X −15 to 15; Y −14 to 4 |
253
+ | `figureAngle` | `0` | −15° to 15° |
254
+ | `headAngle` | `0` | −20° to 20° |
255
+ | `bodyAngle` | `0` | −16° to 16° |
256
+ | `figureGap` | `0.25` | 0.12–0.42 |
257
+ | `headRadiusTop` | `1` | 0.35–1.25 |
258
+ | `headRadiusBottom` | `1` | 0.45–1.5 |
259
+ | `bodyBorderRadius` | `1` | 0.25–1 |
260
+ | `harmony` | — | `true` |
261
+
262
+ With every shape dimension (`headRadiusTop`, `headRadiusBottom`,
263
+ `bodyBorderRadius`) set to `off`, no figure shape is configured and the avatar
264
+ renders initials instead.
265
+
266
+ The generation helpers are exported too, for a consumer that needs the result
267
+ outside a component: `resolveAvatar(config, seed)` returns the resolved colors
268
+ and geometry, `avatarToSvg(resolved)` renders it, and `getInitials(name)` derives
269
+ the fallback letters.
270
+
271
+ ## Component props
272
+
273
+ | Prop | Type | Default | Description |
274
+ |------|------|---------|-------------|
275
+ | `badge?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | — | Corner badge, colored by tone. Pass a named tone or any literal CSS color; the application decides what each tone means (`success` for online, `critical` for busy, `neutral` for offline). Omit for no badge. |
276
+ | `generator?` | AvatarGenConfig | — | Brand generation constraints — each dimension is OFF / ANY / RANGE / LIST. Colors cap OKLCH ranges or pass an explicit palette. Omit for the default varied figure. Define one config for the app and reuse it across avatars. |
277
+ | `name?` | string | — | Person or entity name. Supplies the initials fallback (up to 3 letters from the first 3 words) and the accessible name, and seeds generation when `seed` is absent. |
278
+ | `round?` | boolean \| number \| string | — | Fully-round (circular) frame. Pass a `number` (px) or a CSS length string for a custom radius instead. |
279
+ | `seed?` | string | — | Alphanumeric seed that deterministically drives the generated userpic. The same seed always renders the same avatar. Falls back to `name` when omitted, so a stable user id or name is a good value. |
280
+ | `size?` | 'small' \| 'medium' \| 'large' \| number | medium | Size of the square container. A number is a pixel size. |
281
+ | `src?` | string | — | Image URL. When set, the image is shown instead of a generated userpic, cropped to fill the container. |
282
+
283
+ ## Vanilla web component
284
+
285
+ Use the web component directly when you are not using React or Preact. The
286
+ generation config rides the `config` attribute as a JSON string, so the element
287
+ generates from plain markup with no JavaScript of your own.
288
+
289
+ ```html
290
+ <a-avatar seed="user-42" name="Vlad Korobov"></a-avatar>
291
+
292
+ <a-avatar
293
+ name="Vlad Korobov"
294
+ config='{"headRadiusTop":{"mode":"off"},"headRadiusBottom":{"mode":"off"},"bodyBorderRadius":{"mode":"off"}}'
295
+ ></a-avatar>
296
+ ```
297
+
298
+ ## Styling
299
+
300
+ Reach for the props first: **`size`** sets the dimensions and **`generator`** the
301
+ generated look. Everything else is `--avatar-*` custom properties on the host and
302
+ `::part()` on the shadow content.
303
+
304
+ The container is a rounded square by default; `round` makes it a circle and takes
305
+ a length for a custom radius, so reach for the prop before the custom property.
306
+ The badge is sized and placed with `--avatar-badge-ratio` (its size as a fraction
307
+ of the frame), `--avatar-badge-inset`, and `--avatar-badge-gap` (the width of the
308
+ cutout around it). Its fill comes from `badge`, so route color through the prop
309
+ rather than overriding `--avatar-badge-color`.
310
+
311
+ ```css
312
+ a-avatar.badge-dot {
313
+ --avatar-badge-ratio: 0.34; /* a larger badge */
314
+ --avatar-badge-gap: 4px; /* in a wider cutout */
315
+ }
316
+ ```
317
+
318
+ The shadow content exposes `::part(frame)` (the picture — the generated figure or
319
+ the image, whichever is showing), `::part(image)` (only the `src` image), and
320
+ `::part(badge)` (the corner badge) for anything the custom properties do not
321
+ cover.
322
+
323
+ ## Example
324
+
325
+ ```tsx
326
+ import { Avatar, type AvatarGenConfig } from '@antadesign/anta'
327
+
328
+ /**
329
+ * @play props Generator
330
+ * The avatar's JSON-like generation settings. Nested values become editable
331
+ * fields in the Props panel.
332
+ */
333
+ const generator = {
334
+ // Every dimension takes one mode: 'off' | 'any' | 'range' | 'list'.
335
+ bgColor: { mode: 'range', l: [0.55, 0.72], c: [0.05, 0.12], h: [0, 360] },
336
+ headColor: { mode: 'any' },
337
+ bodyColor: { mode: 'any' },
338
+ // Corner radius: 0 square, 1 fully round, above 1 elongated into an oval.
339
+ // The bottom is never rounded less than the top, so an egg leans jaw-down.
340
+ headRadiusTop: { mode: 'range', min: 0.5, max: 1.15 },
341
+ headRadiusBottom: { mode: 'range', min: 0.6, max: 1.35 },
342
+ bodyBorderRadius: { mode: 'any' },
343
+ // Space between head and body, as a fraction of head height (0 to 1).
344
+ figureGap: { mode: 'range', min: 0, max: 0.3 },
345
+ figureScale: { mode: 'any' },
346
+ headAngle: { mode: 'any' },
347
+ bodyAngle: { mode: 'any' },
348
+ harmony: true,
349
+ } satisfies AvatarGenConfig
350
+
351
+ function Demo() {
352
+ return (
353
+ /** @play props Avatar */
354
+ <Avatar
355
+ seed="user-42"
356
+ name="Vlad Korobov"
357
+ size={96}
358
+ badge="success"
359
+ round
360
+ generator={generator}
361
+ />
362
+ )
363
+ }
364
+ ```
@@ -196,39 +196,23 @@ applies anything, so a vanilla `<a-banner>` listener can `preventDefault()` a
196
196
  dismiss. The `<Banner>` wrapper's `onDismiss` is notification-only — drive rejection
197
197
  through `dismissed` instead.
198
198
 
199
- ### Props
199
+ ## Component props
200
200
 
201
201
  | Prop | Type | Default | Description |
202
202
  |------|------|---------|-------------|
203
- | `actions?` | ReactNode | — | Trailing controls (buttons, links) rendered as a compact row after the
204
- message and `children`. |
205
- | `align?` | 'start' \| 'center' | 'start' | Positions the content row. `'start'` aligns it to the inline edge; `'center'`
206
- centers it. Wrapped message text follows the selected alignment. |
203
+ | `actions?` | ReactNode | — | Trailing controls (buttons, links) rendered as a compact row after the message and `children`. |
204
+ | `align?` | 'start' \| 'center' | 'start' | Positions the content row. `'start'` aligns it to the inline edge; `'center'` centers it. Wrapped message text follows the selected alignment. |
207
205
  | `children?` | ReactNode | — | Free content placed BETWEEN the message and the actions. |
208
- | `closable?` | boolean | true | Whether the trailing ✕ dismiss button is present. `false` removes it — drive
209
- dismissal yourself (a controlled `dismissed`, or your own control) instead.
210
- It removes the built-in ✕ without making the banner un-dismissible. |
206
+ | `closable?` | boolean | true | Whether the trailing ✕ dismiss button is present. `false` removes it — drive dismissal yourself (a controlled `dismissed`, or your own control) instead. It removes the built-in ✕ without making the banner un-dismissible. |
211
207
  | `defaultDismissed?` | boolean | — | Initial dismissed state for the uncontrolled case (read once on mount). |
212
- | `dismissed?` | boolean | — | Controlled dismissed state. When provided, the consumer owns visibility: the
213
- banner follows this prop only, and clicking ✕ *requests* dismissal (reject by
214
- not updating). **Requires `onDismiss`** — controlled mode never self-hides, so
215
- without a handler to set `dismissed` the ✕ can't close the banner. Leave
216
- undefined for uncontrolled. |
208
+ | `dismissed?` | boolean | — | Controlled dismissed state. When provided, the consumer owns visibility: the banner follows this prop only, and clicking ✕ *requests* dismissal (reject by not updating). **Requires `onDismiss`** — controlled mode never self-hides, so without a handler to set `dismissed` the ✕ can't close the banner. Leave undefined for uncontrolled. |
217
209
  | `message?` | ReactNode | — | Leading message: a string at the banner type scale or any node. |
218
- | `onDismiss?` | () => void | — | Fired when the user dismisses the banner (clicks ✕). Uncontrolled, the banner
219
- hides itself and this notifies. Controlled, use it to accept the
220
- request — set `dismissed` to `true` (or ignore to reject); pair it with
221
- `dismissed`, or the banner can't be closed. |
222
- | `role?` | string | 'status' | ARIA role for the strip host. `'status'` (a polite live region, so the notice
223
- reaches assistive tech) by default; pass `'alert'` for an urgent notice that
224
- should interrupt, or a landmark role. |
225
- | `round?` | boolean \| number \| string | — | Rounded corners for a standalone, floating banner (`border-radius: 999px`,
226
- which clamps to a stadium) instead of the edge-to-edge strip. Still borderless
227
- by default. Pass a `number` (px) or a CSS length string for a custom radius. |
228
- | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | 'neutral' | Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) for
229
- a one-off custom tone. Named tones re-point the surface, text, and border
230
- color (used if you opt into a border); a custom color keeps its hue while
231
- lightness/chroma are pinned. `'neutral'` (the default) is the same as omitting it. |
210
+ | `onDismiss?` | () => void | — | Fired when the user dismisses the banner (clicks ✕). Uncontrolled, the banner hides itself and this notifies. Controlled, use it to accept the request — set `dismissed` to `true` (or ignore to reject); pair it with `dismissed`, or the banner can't be closed. |
211
+ | `role?` | string | 'status' | ARIA role for the strip host. `'status'` (a polite live region, so the notice reaches assistive tech) by default; pass `'alert'` for an urgent notice that should interrupt, or a landmark role. |
212
+ | `round?` | boolean \| number \| string | — | Rounded corners for a standalone, floating banner (`border-radius: 999px`, which clamps to a stadium) instead of the edge-to-edge strip. Still borderless by default. Pass a `number` (px) or a CSS length string for a custom radius. |
213
+ | `tone?` | 'neutral' \| 'brand' \| 'info' \| 'success' \| 'warning' \| 'critical' \| (string & {}) | 'neutral' | Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`) for a one-off custom tone. Named tones re-point the surface, text, and border color (used if you opt into a border); a custom color keeps its hue while lightness/chroma are pinned. `'neutral'` (the default) is the same as omitting it. |
214
+
215
+ ## Web Component
232
216
 
233
217
  Use the web component directly when you are not using React or Preact and a native control does not fit.
234
218
 
@@ -246,6 +230,8 @@ Slots hold the message, actions, and close control. A close button dispatches
246
230
  </a-banner>
247
231
  ```
248
232
 
233
+ ## Styling
234
+
249
235
  Reach for the props first: **`tone`** sets the color (any CSS color for a custom
250
236
  tone — it derives the surface, text, and border color in oklch), **`round`** the
251
237
  corners. The one knob worth keeping is **`--banner-tone-source`** — the color a