@mortenbrudvik/waveui 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +157 -13
  2. package/dist/components/button/Link.cjs +1 -1
  3. package/dist/components/button/Link.cjs.map +1 -1
  4. package/dist/components/button/Link.mjs +4 -4
  5. package/dist/components/data-display/Avatar.cjs +1 -1
  6. package/dist/components/data-display/Avatar.cjs.map +1 -1
  7. package/dist/components/data-display/Avatar.colors.cjs +2 -0
  8. package/dist/components/data-display/Avatar.colors.cjs.map +1 -0
  9. package/dist/components/data-display/Avatar.colors.mjs +45 -0
  10. package/dist/components/data-display/Avatar.colors.mjs.map +1 -0
  11. package/dist/components/data-display/Avatar.context.cjs +1 -1
  12. package/dist/components/data-display/Avatar.context.cjs.map +1 -1
  13. package/dist/components/data-display/Avatar.context.mjs +4 -2
  14. package/dist/components/data-display/Avatar.context.mjs.map +1 -1
  15. package/dist/components/data-display/Avatar.mjs +103 -96
  16. package/dist/components/data-display/Avatar.mjs.map +1 -1
  17. package/dist/components/data-display/Avatar.sizes.cjs +2 -0
  18. package/dist/components/data-display/Avatar.sizes.cjs.map +1 -0
  19. package/dist/components/data-display/Avatar.sizes.mjs +41 -0
  20. package/dist/components/data-display/Avatar.sizes.mjs.map +1 -0
  21. package/dist/components/data-display/AvatarGroup.cjs +1 -1
  22. package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
  23. package/dist/components/data-display/AvatarGroup.context.cjs +2 -0
  24. package/dist/components/data-display/AvatarGroup.context.cjs.map +1 -0
  25. package/dist/components/data-display/AvatarGroup.context.mjs +9 -0
  26. package/dist/components/data-display/AvatarGroup.context.mjs.map +1 -0
  27. package/dist/components/data-display/AvatarGroup.mjs +65 -122
  28. package/dist/components/data-display/AvatarGroup.mjs.map +1 -1
  29. package/dist/components/data-display/AvatarGroup.partition.cjs +2 -0
  30. package/dist/components/data-display/AvatarGroup.partition.cjs.map +1 -0
  31. package/dist/components/data-display/AvatarGroup.partition.mjs +14 -0
  32. package/dist/components/data-display/AvatarGroup.partition.mjs.map +1 -0
  33. package/dist/components/data-display/AvatarGroup.parts.cjs +2 -0
  34. package/dist/components/data-display/AvatarGroup.parts.cjs.map +1 -0
  35. package/dist/components/data-display/AvatarGroup.parts.mjs +178 -0
  36. package/dist/components/data-display/AvatarGroup.parts.mjs.map +1 -0
  37. package/dist/components/data-display/InfoButton.cjs +1 -1
  38. package/dist/components/data-display/InfoButton.cjs.map +1 -1
  39. package/dist/components/data-display/InfoButton.mjs +12 -12
  40. package/dist/components/data-display/InteractionTag.cjs +1 -1
  41. package/dist/components/data-display/InteractionTag.cjs.map +1 -1
  42. package/dist/components/data-display/InteractionTag.mjs +36 -33
  43. package/dist/components/data-display/InteractionTag.mjs.map +1 -1
  44. package/dist/components/data-display/Persona.cjs +1 -1
  45. package/dist/components/data-display/Persona.cjs.map +1 -1
  46. package/dist/components/data-display/Persona.mjs +96 -37
  47. package/dist/components/data-display/Persona.mjs.map +1 -1
  48. package/dist/components/data-display/PresenceBadge.cjs +1 -1
  49. package/dist/components/data-display/PresenceBadge.cjs.map +1 -1
  50. package/dist/components/data-display/PresenceBadge.mjs +42 -28
  51. package/dist/components/data-display/PresenceBadge.mjs.map +1 -1
  52. package/dist/components/data-display/Tag.cjs +1 -1
  53. package/dist/components/data-display/Tag.cjs.map +1 -1
  54. package/dist/components/data-display/Tag.mjs +111 -108
  55. package/dist/components/data-display/Tag.mjs.map +1 -1
  56. package/dist/components/feedback/Toaster.cjs +1 -1
  57. package/dist/components/feedback/Toaster.cjs.map +1 -1
  58. package/dist/components/feedback/Toaster.mjs +235 -235
  59. package/dist/components/feedback/Toaster.mjs.map +1 -1
  60. package/dist/components/input/Combobox.cjs +1 -1
  61. package/dist/components/input/Combobox.cjs.map +1 -1
  62. package/dist/components/input/Combobox.mjs +176 -175
  63. package/dist/components/input/Combobox.mjs.map +1 -1
  64. package/dist/components/input/DatePicker.cjs +1 -1
  65. package/dist/components/input/DatePicker.cjs.map +1 -1
  66. package/dist/components/input/DatePicker.mjs +188 -187
  67. package/dist/components/input/DatePicker.mjs.map +1 -1
  68. package/dist/components/input/Dropdown.cjs +1 -1
  69. package/dist/components/input/Dropdown.cjs.map +1 -1
  70. package/dist/components/input/Dropdown.mjs +41 -40
  71. package/dist/components/input/Dropdown.mjs.map +1 -1
  72. package/dist/components/input/Option.cjs +1 -1
  73. package/dist/components/input/Option.cjs.map +1 -1
  74. package/dist/components/input/Option.mjs +89 -87
  75. package/dist/components/input/Option.mjs.map +1 -1
  76. package/dist/components/input/TagPicker.root.cjs +1 -1
  77. package/dist/components/input/TagPicker.root.cjs.map +1 -1
  78. package/dist/components/input/TagPicker.root.mjs +136 -135
  79. package/dist/components/input/TagPicker.root.mjs.map +1 -1
  80. package/dist/components/input/TimePicker.cjs +1 -1
  81. package/dist/components/input/TimePicker.cjs.map +1 -1
  82. package/dist/components/input/TimePicker.mjs +156 -154
  83. package/dist/components/input/TimePicker.mjs.map +1 -1
  84. package/dist/components/layout/Card.cjs +1 -1
  85. package/dist/components/layout/Card.cjs.map +1 -1
  86. package/dist/components/layout/Card.context.cjs +2 -0
  87. package/dist/components/layout/Card.context.cjs.map +1 -0
  88. package/dist/components/layout/Card.context.mjs +14 -0
  89. package/dist/components/layout/Card.context.mjs.map +1 -0
  90. package/dist/components/layout/Card.mjs +138 -92
  91. package/dist/components/layout/Card.mjs.map +1 -1
  92. package/dist/components/layout/Card.preview.cjs +2 -0
  93. package/dist/components/layout/Card.preview.cjs.map +1 -0
  94. package/dist/components/layout/Card.preview.mjs +22 -0
  95. package/dist/components/layout/Card.preview.mjs.map +1 -0
  96. package/dist/components/layout/Carousel.button.cjs +2 -0
  97. package/dist/components/layout/Carousel.button.cjs.map +1 -0
  98. package/dist/components/layout/Carousel.button.mjs +34 -0
  99. package/dist/components/layout/Carousel.button.mjs.map +1 -0
  100. package/dist/components/layout/Carousel.cjs +1 -1
  101. package/dist/components/layout/Carousel.cjs.map +1 -1
  102. package/dist/components/layout/Carousel.context.cjs +2 -0
  103. package/dist/components/layout/Carousel.context.cjs.map +1 -0
  104. package/dist/components/layout/Carousel.context.mjs +24 -0
  105. package/dist/components/layout/Carousel.context.mjs.map +1 -0
  106. package/dist/components/layout/Carousel.drag.cjs +2 -0
  107. package/dist/components/layout/Carousel.drag.cjs.map +1 -0
  108. package/dist/components/layout/Carousel.drag.mjs +79 -0
  109. package/dist/components/layout/Carousel.drag.mjs.map +1 -0
  110. package/dist/components/layout/Carousel.groups.cjs +2 -0
  111. package/dist/components/layout/Carousel.groups.cjs.map +1 -0
  112. package/dist/components/layout/Carousel.groups.mjs +23 -0
  113. package/dist/components/layout/Carousel.groups.mjs.map +1 -0
  114. package/dist/components/layout/Carousel.mjs +288 -150
  115. package/dist/components/layout/Carousel.mjs.map +1 -1
  116. package/dist/components/layout/Carousel.styles.cjs +2 -0
  117. package/dist/components/layout/Carousel.styles.cjs.map +1 -0
  118. package/dist/components/layout/Carousel.styles.mjs +30 -0
  119. package/dist/components/layout/Carousel.styles.mjs.map +1 -0
  120. package/dist/components/layout/TabList.cjs +1 -1
  121. package/dist/components/layout/TabList.cjs.map +1 -1
  122. package/dist/components/layout/TabList.mjs +163 -124
  123. package/dist/components/layout/TabList.mjs.map +1 -1
  124. package/dist/components/navigation/Menu.popover.cjs +1 -1
  125. package/dist/components/navigation/Menu.popover.cjs.map +1 -1
  126. package/dist/components/navigation/Menu.popover.mjs +137 -127
  127. package/dist/components/navigation/Menu.popover.mjs.map +1 -1
  128. package/dist/components/navigation/Menu.root.cjs +1 -1
  129. package/dist/components/navigation/Menu.root.cjs.map +1 -1
  130. package/dist/components/navigation/Menu.root.mjs +4 -4
  131. package/dist/components/overlays/Dialog.cjs +1 -1
  132. package/dist/components/overlays/Dialog.cjs.map +1 -1
  133. package/dist/components/overlays/Dialog.mjs +123 -123
  134. package/dist/components/overlays/Dialog.mjs.map +1 -1
  135. package/dist/components/overlays/Drawer.panel.cjs +1 -1
  136. package/dist/components/overlays/Drawer.panel.cjs.map +1 -1
  137. package/dist/components/overlays/Drawer.panel.mjs +12 -12
  138. package/dist/components/overlays/Drawer.panel.mjs.map +1 -1
  139. package/dist/components/overlays/Popover.cjs +1 -1
  140. package/dist/components/overlays/Popover.cjs.map +1 -1
  141. package/dist/components/overlays/Popover.mjs +173 -162
  142. package/dist/components/overlays/Popover.mjs.map +1 -1
  143. package/dist/components/overlays/TeachingPopover.cjs +1 -1
  144. package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
  145. package/dist/components/overlays/TeachingPopover.mjs +96 -91
  146. package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
  147. package/dist/components/overlays/Tooltip.cjs +1 -1
  148. package/dist/components/overlays/Tooltip.cjs.map +1 -1
  149. package/dist/components/overlays/Tooltip.mjs +47 -47
  150. package/dist/components/overlays/Tooltip.mjs.map +1 -1
  151. package/dist/components/portal/Portal.cjs +1 -1
  152. package/dist/components/portal/Portal.cjs.map +1 -1
  153. package/dist/components/portal/Portal.mjs +5 -5
  154. package/dist/components/table/DataGrid.cjs +1 -1
  155. package/dist/components/table/DataGrid.cjs.map +1 -1
  156. package/dist/components/table/DataGrid.mjs +1 -1
  157. package/dist/hooks/useDismiss.cjs.map +1 -1
  158. package/dist/hooks/useDismiss.mjs.map +1 -1
  159. package/dist/hooks/useFocusTrap.cjs.map +1 -1
  160. package/dist/hooks/useFocusTrap.mjs.map +1 -1
  161. package/dist/hooks/useFocusVisible.cjs +2 -0
  162. package/dist/hooks/useFocusVisible.cjs.map +1 -0
  163. package/dist/hooks/useFocusVisible.mjs +49 -0
  164. package/dist/hooks/useFocusVisible.mjs.map +1 -0
  165. package/dist/hooks/useFocusableGroup.cjs +2 -0
  166. package/dist/hooks/useFocusableGroup.cjs.map +1 -0
  167. package/dist/hooks/useFocusableGroup.mjs +70 -0
  168. package/dist/hooks/useFocusableGroup.mjs.map +1 -0
  169. package/dist/hooks/useModalLayer.cjs +1 -1
  170. package/dist/hooks/useModalLayer.cjs.map +1 -1
  171. package/dist/hooks/useModalLayer.mjs +4 -4
  172. package/dist/hooks/useModalOpen.cjs +2 -0
  173. package/dist/hooks/useModalOpen.cjs.map +1 -0
  174. package/dist/hooks/useModalOpen.mjs +14 -0
  175. package/dist/hooks/useModalOpen.mjs.map +1 -0
  176. package/dist/hooks/usePopupPosition.cjs +1 -1
  177. package/dist/hooks/usePopupPosition.cjs.map +1 -1
  178. package/dist/hooks/usePopupPosition.mjs +82 -53
  179. package/dist/hooks/usePopupPosition.mjs.map +1 -1
  180. package/dist/hooks/useResolvedTarget.cjs +2 -0
  181. package/dist/hooks/useResolvedTarget.cjs.map +1 -0
  182. package/dist/hooks/useResolvedTarget.mjs +37 -0
  183. package/dist/hooks/useResolvedTarget.mjs.map +1 -0
  184. package/dist/hooks/useRovingGrid.cjs +1 -1
  185. package/dist/hooks/useRovingGrid.cjs.map +1 -1
  186. package/dist/hooks/useRovingGrid.mjs +8 -57
  187. package/dist/hooks/useRovingGrid.mjs.map +1 -1
  188. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  189. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  190. package/dist/hooks/useRovingTabIndex.mjs +142 -107
  191. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  192. package/dist/index.cjs +1 -1
  193. package/dist/index.d.cts +1364 -66
  194. package/dist/index.d.ts +1364 -66
  195. package/dist/index.mjs +132 -115
  196. package/dist/lib/classNames.cjs +1 -1
  197. package/dist/lib/classNames.cjs.map +1 -1
  198. package/dist/lib/classNames.mjs +112 -92
  199. package/dist/lib/classNames.mjs.map +1 -1
  200. package/dist/lib/initials.cjs +2 -0
  201. package/dist/lib/initials.cjs.map +1 -0
  202. package/dist/lib/initials.mjs +21 -0
  203. package/dist/lib/initials.mjs.map +1 -0
  204. package/dist/lib/layers.cjs +1 -1
  205. package/dist/lib/layers.cjs.map +1 -1
  206. package/dist/lib/layers.mjs +112 -109
  207. package/dist/lib/layers.mjs.map +1 -1
  208. package/dist/styles.css +1 -1
  209. package/package.json +1 -1
  210. package/src/styles/tokens.css +102 -0
package/README.md CHANGED
@@ -447,8 +447,9 @@ export function SaveArea() {
447
447
  | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
448
448
  | `Accordion` | `AccordionItem`, `AccordionTrigger`, `AccordionPanel` |
449
449
  | `Breadcrumb` | `BreadcrumbItem` |
450
- | `Card` | `CardHeader`, `CardBody`, `CardFooter` |
451
- | `Carousel` | `CarouselItem` |
450
+ | `AvatarGroup` | `AvatarGroupItem`, `AvatarGroupPopover` |
451
+ | `Card` | `CardHeader`, `CardPreview`, `CardBody`, `CardFooter` |
452
+ | `Carousel` | `CarouselItem`, `CarouselButton` |
452
453
  | `ColorPicker` | `ColorPickerHexField`, `ColorPickerSwatches`, `ColorPickerPreview` |
453
454
  | `Combobox` | `ComboboxOption`, `ComboboxOptionGroup` (also `Option`, `OptionGroup`) |
454
455
  | `DataGrid` | `DataGridHeader`, `DataGridHeaderCell`, `DataGridBody`, `DataGridRow`, `DataGridCell` |
@@ -531,17 +532,17 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
531
532
 
532
533
  | Component | Description |
533
534
  | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
534
- | `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge`. |
535
- | `AvatarGroup` | Overlapping avatars; `max` adds an overflow button that lists the hidden members. |
535
+ | `Avatar` | Image, initials or icon, with an image-failure fallback and an optional `badge`; `size` (named or 16 to 128 px), `shape`, `color` (`neutral`, `brand`, `colorful` or one of twelve named colors), `active` and `activeAppearance`, an `initials` slot (see [Avatars and people](#avatars-and-people)). |
536
+ | `AvatarGroup` | Avatars in a `stack`, `spread` or `pie` `layout`; `max` adds an overflow button (`99+` past 99) that lists the hidden members. Compound form: `AvatarGroup.Item` and `AvatarGroup.Popover`. |
536
537
  | `Badge` | Status or category label: `appearance` `filled`, `tint`, `outline`; semantic `color` (see [Badges](#badges)). |
537
538
  | `CounterBadge` | Count pill (`99+` above `overflowCount`) or, with `dot`, an unread dot; Badge's `color` palette; `showZero`. |
538
- | `PresenceBadge` | Availability badge with a distinct shape per status. |
539
+ | `PresenceBadge` | Availability badge with a distinct shape per status (`available`, `busy`, `away`, `offline`, `do-not-disturb`, `out-of-office`; `dnd` and `oof` are deprecated). |
539
540
  | `Tag` | Chip: `appearance` (`filled`, `outline`, `brand`), `size` (`medium` 28px, `small`, `extra-small`), `shape` (`circular`, `rounded`), `disabled`, a look-only `selected`, `value` (its key in a TagGroup) and the `media` (an Avatar), `icon` and `secondaryText` slots; an optional Dismiss button (`dismissible`, `onDismiss`, `dismissLabel`) that also dismisses on Delete and Backspace. `onDismiss` and `dismissIcon` need `dismissible` (a development warning says so). In a TagGroup focus moves for you when a tag is removed; on its own, move it yourself (see [Tags](#tags)). |
540
541
  | `TagGroup` | A set of tags: a toolbar (one Tab stop, arrow keys) or, with `role="list"`, a list; default `size`, `appearance`, `shape`, `dismissible` and `disabled` for its tags; `onDismiss(value)`, focus to the next tag (else the previous one, else `fallbackFocusRef`) when the focused tag is removed; selectable InteractionTags through `value`/`defaultValue`/`onValueChange`, with `name`, `form` and `required`. |
541
542
  | `InteractionTag` | A tag with an action: `InteractionTag.Primary` (a button, or a toggle in a selecting TagGroup; `media`, `icon`, `secondaryText`) and an optional `InteractionTag.Secondary` (a separate Dismiss button named "Dismiss <text>"); `size`, `appearance`, `shape`, `disabled`, `selected`, `value`. |
542
543
  | `InfoLabel` | A real `<label>` (`children`, `htmlFor`, `required`, `size`, `weight`, `disabled`) with an info button after it that shows `info` (text, links or other content) in a note; `openOnHover`, `infoButtonLabel`. Usable as the `label` of a Field. |
543
544
  | `InfoButton` | A button with the info glyph that shows `info` in a `role="note"` next to it, without moving focus: opens on click, on mouse hover and on keyboard focus (`openOnHover={false}`: click only); Tab from the button enters the note; `size`. Named "Information" (`aria-label`). |
544
- | `Persona` | Avatar with name, secondary text and presence. |
545
+ | `Persona` | Avatar with up to four lines of text (`primaryText` to `quaternaryText`), `textPosition` (`after`, `before`, `below`), `presenceOnly` and presence; sizes up to `huge`. |
545
546
  | `Divider` | Horizontal or vertical separator, optionally labelled. |
546
547
  | `Image` | `<img>` with `fit`, `shape`, `shadow`, `bordered`; warns in development when `alt` is missing. Never wider than its parent; with the default `fit` its height follows its width. `fit="none"` keeps the top-left corner in view, `"center"` the middle. |
547
548
  | `List` | Plain list, selectable listbox (single or multiple) or, with item `action`s, a grid; in a selectable List item values are unique (development warning). |
@@ -556,11 +557,11 @@ Your `className` is merged last with `cn()`, so it replaces a conflicting class
556
557
 
557
558
  | Component | Description |
558
559
  | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
559
- | `Card` | Surface with `Card.Header`, `Card.Body`, `Card.Footer`; optionally selectable (`onSelect`, `selected`, `selectionControl`). |
560
+ | `Card` | Surface with `Card.Header` (`image`, `action`), `Card.Preview`, `Card.Body`, `Card.Footer`; `appearance`, `size`, `orientation`; optionally selectable (`onSelect`, `selected`, `selectionControl`, `checkbox`) with a `floatingAction` (see [Cards, tabs and carousels](#cards-tabs-and-carousels)). |
560
561
  | `Accordion` | Disclosure sections (`Accordion.Item`, `.Trigger`, `.Panel`); single (default) or `type="multiple"`; `headingLevel`; item values are unique (development warning). |
561
- | `TabList` | Tabs (`TabList.Tab`, `.Panel`, `.Panels`) with automatic activation, or manual with `selectTabOnFocus={false}`; `orientation`; tab values are unique (development warning). |
562
+ | `TabList` | Tabs (`TabList.Tab`, `.Panel`, `.Panels`) with automatic activation, or manual with `selectTabOnFocus={false}`; `orientation`, `appearance` (`transparent`, `subtle`, `subtle-circular`, `filled-circular`), `size`, a `Tab` `icon` (alone: icon-only); tab values are unique (development warning). |
562
563
  | `Tree` | Hierarchical tree (`Tree.Item`) with expand/collapse and typeahead; single selection, or checkboxes with a cascading mixed state (`selectionMode="multiple"`); row `actions`, `aside` and `Tree.ItemPersonaLayout`; `navigationMode="treegrid"` (see [Trees](#trees)). Nested items are `Tree.Item` elements in their parent's children (directly, in Fragments or from a render function), not rendered by a recursive component; values are unique. |
563
- | `Carousel` | One slide at a time with previous/next, a slide picker and optional auto-rotation with a pause control. Slides are `Carousel.Item` children, directly or in Fragments (a component that renders `Carousel.Item` is not a slide). |
564
+ | `Carousel` | Slides (`Carousel.Item` children, directly or in Fragments; a component that renders `Carousel.Item` is not a slide) with previous/next, a slide picker and optional auto-rotation with a pause control. `groupSize` (a number or `auto`) shows several at once, `draggable` drags them, `Carousel.Item` `thumbnail` shows thumbnails, `controlsLayout` places the buttons and `Carousel.Button` replaces one. |
564
565
  | `Overflow` | Hides items that do not fit in one row and renders an overflow button (`useOverflowMenu` lists the hidden items); item ids are unique (development warning). The row has a 4px padding, so its items' focus rings are not clipped. |
565
566
  | `Grid` | CSS grid with a column count and token gaps. |
566
567
  | `Stack` | Vertical or horizontal stack (`orientation`, `gap`). |
@@ -1601,9 +1602,85 @@ export function Author() {
1601
1602
 
1602
1603
  - **Hover cards.** `openOnHover` opens a Popover when the mouse rests on its trigger (`openDelay`, 250ms) and closes it `closeDelay` (500ms) after the pointer has left the trigger and the content, unless focus is inside the content (or in a layer opened from it). Opening and closing by hover move no focus (neither does the close of a hover card opened inside it); Tab from the trigger enters the content, as for any open Popover. A click on the trigger pins it (it stays open and focus stays where it is), and a second click closes it. Focus left on the trigger does not keep an unpinned card open. The triangle safe zone, the touch rule and "stays closed after Escape until the pointer leaves" are Menu's.
1603
1604
  - **Context popovers.** `openOnContext` works as on Menu, with Popover's focus rules: a right click opens the popover at the pointer and leaves focus where it is (Tab from that element enters the content); Shift+F10 or the ContextMenu key opens it at the focused element and moves focus into the content, and Escape returns focus to that element. The region gets no `aria-haspopup` or `aria-expanded`, so name the content with `title`, `aria-label` or `aria-labelledby`.
1604
- - **`target`** on the Popover root (next to `side` and `align`; `PopupTarget`, as on `Menu.Popover`) places the content at an element held in state or at a `VirtualElement` instead of the trigger. A controlled popover with a `target` needs no trigger; a toggle button used as the target carries its own `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls` (give `Popover.Content` an `id`), a press on it does not count as outside, and Tab from it enters the content. TeachingPopover's `target` takes an element or a ref instead (it takes no `VirtualElement`, and Menu and Popover take no ref); a later release unifies them.
1605
+ - **`target`** on the Popover root (next to `side` and `align`; `PopupTarget`, as on `Menu.Popover`) places the content at an element held in state or at a `VirtualElement` instead of the trigger. A controlled popover with a `target` needs no trigger; a toggle button used as the target carries its own `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls` (give `Popover.Content` an `id`), a press on it does not count as outside, and Tab from it enters the content. `Popover`, `Menu.Popover` and TeachingPopover take the same `target`: an element held in state, a `VirtualElement` or a ref object (a ref is read after each render of the popup, and the popup stays hidden while it holds no element).
1605
1606
  - **Tooltip timing.** `openDelay` (default 200ms) is how long the pointer rests on the child, or the child has keyboard focus, before the tooltip appears: unlike Menu's and Popover's `openDelay`, it applies to focus too. `closeDelay` (default 100ms) is how long it stays once the pointer has left the child and the tooltip; blur and Escape hide it at once. `delay` is the deprecated name of `openDelay` (it warns once in development).
1606
1607
 
1608
+ ### Custom overlays
1609
+
1610
+ The hooks behind WaveUI's own surfaces are public, so a surface WaveUI does not ship (a command palette, a custom popup) joins the same layer stack: Escape closes the topmost layer first, a press in the Toaster or in a marked region closes nothing, and focus returns to the opener.
1611
+
1612
+ ```tsx
1613
+ import * as React from 'react';
1614
+ import {
1615
+ Portal,
1616
+ useMergedRefs,
1617
+ useModalLayer,
1618
+ usePopupPosition,
1619
+ useDismiss,
1620
+ useRestoreFocus,
1621
+ } from '@mortenbrudvik/waveui';
1622
+
1623
+ // A modal command palette: the page behind it is inert, Tab stays inside.
1624
+ function CommandPalette({ open, onOpenChange, triggerRef }) {
1625
+ const [surface, setSurface] = React.useState<HTMLDivElement | null>(null);
1626
+ const surfaceRef = React.useRef<HTMLDivElement | null>(null);
1627
+ const mergedRef = useMergedRefs(surfaceRef, setSurface);
1628
+ const { layerId } = useModalLayer({
1629
+ open,
1630
+ container: surface,
1631
+ onDismiss: () => onOpenChange(false),
1632
+ refs: [surfaceRef],
1633
+ triggerRef,
1634
+ });
1635
+ if (!open) return null;
1636
+ return (
1637
+ <Portal layerId={layerId}>
1638
+ <div ref={mergedRef} role="dialog" aria-label="Command palette">
1639
+ <input aria-label="Search commands" />
1640
+ </div>
1641
+ </Portal>
1642
+ );
1643
+ }
1644
+
1645
+ // A non-modal popup placed against its button.
1646
+ function Details() {
1647
+ const [open, setOpen] = React.useState(false);
1648
+ const [surface, setSurface] = React.useState<HTMLDivElement | null>(null);
1649
+ const triggerRef = React.useRef<HTMLButtonElement | null>(null);
1650
+ const surfaceRef = React.useRef<HTMLDivElement | null>(null);
1651
+ const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });
1652
+ const { layerId } = useDismiss({
1653
+ open,
1654
+ onDismiss: () => setOpen(false),
1655
+ refs: [triggerRef, surfaceRef],
1656
+ anchorRef: triggerRef,
1657
+ });
1658
+ useRestoreFocus({ enabled: open, container: surface, triggerRef });
1659
+ const buttonRef = useMergedRefs(triggerRef, setReference);
1660
+ const popupRef = useMergedRefs(surfaceRef, setSurface, setFloating);
1661
+ return (
1662
+ <>
1663
+ <button ref={buttonRef} onClick={() => setOpen((o) => !o)}>
1664
+ Details
1665
+ </button>
1666
+ {open && (
1667
+ <Portal layerId={layerId}>
1668
+ <div ref={popupRef} role="dialog" aria-label="Details" {...floatingProps}>
1669
+ …
1670
+ </div>
1671
+ </Portal>
1672
+ )}
1673
+ </>
1674
+ );
1675
+ }
1676
+ ```
1677
+
1678
+ - **Layers.** `useDismiss` registers a layer (Escape, outside press and, for listboxes, focus leaving it); give `Portal` the returned `layerId` so a Popover or Menu opened inside becomes the layer's child and closes first. `useModalLayer` adds the trap, the `inert` isolation (WaveUI isolates instead of setting `aria-modal`, so toasts stay announced), the scroll lock and focus restore, with `modalType` `'modal'`, `'alert'` or `'non-modal'`.
1679
+ - **Positioning.** `usePopupPosition` takes `side`, `align`, `offset`, `flip`, `fallbackPlacements`, `shift`, `fitViewport`, `matchReferenceWidth`, `strategy`, `hideWhenDetached` and `onPositioned`, and returns `update()`. The anchor is an element or a `VirtualElement`.
1680
+ - **App-owned regions.** Spread `modalAllowProps` on a region that a modal must leave usable (a notification area); `useModalOpen()` tells you when a modal is open, so global shortcuts can wait.
1681
+ - **`positioning` prop.** Popover, `Menu.Popover`, Tooltip, TeachingPopover, Combobox, Dropdown, TagPicker, DatePicker and TimePicker take `positioning={{ offset, fitViewport, matchReferenceWidth, fallbackPlacements }}` (and `target` where the component has one); `side` and `align` stay their own props.
1682
+ - **Stability.** These hooks are public but pre-1.0: their options may still change through the usual deprecation path.
1683
+
1607
1684
  ### Enter and exit motion
1608
1685
 
1609
1686
  Motion tokens are CSS variables on `:root`, the same in every theme: `--wave-duration-ultra-fast` (50ms), `-faster` (100ms), `-fast` (150ms), `-normal` (200ms), `-gentle` (250ms), `-slow` (300ms), `-slower` (400ms), `-ultra-slow` (500ms), and the curves `--wave-curve-accelerate-max`, `-accelerate-mid`, `-accelerate-min`, `-decelerate-max`, `-decelerate-mid`, `-decelerate-min`, `-easy-ease-max`, `-easy-ease` and `-linear`, with the values of Fluent's motion tokens (the guide's "Motion & Animation" chapter lists them). On the Tailwind path they are the utilities `duration-wave-*` and `ease-wave-*`; the precompiled `./styles` contains only the utilities Wave itself uses, so there use the variables in your own CSS.
@@ -1777,6 +1854,29 @@ export function UpdateNotice({ onUpdate, onLater }: { onUpdate: () => void; onLa
1777
1854
  - A badge whose text alone does not say what it means ("3") can be named: with `aria-label` or `aria-labelledby` a Badge or CounterBadge gets `role="img"`, so the name is announced (a `role` you pass wins; an empty or whitespace-only name counts as absent). `<CounterBadge dot aria-label="Unread messages" />` is a named unread dot.
1778
1855
  - The root carries `data-color` and `data-appearance` with the resolved values (and `data-dot` on a dot), for your own selectors.
1779
1856
 
1857
+ ### Avatars and people
1858
+
1859
+ - **Sizes and shape.** `size` takes the named sizes or a box in pixels (16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 96, 120, 128); `shape="square"` rounds the corners. An Avatar in a `Tag` with `shape="rounded"` is square.
1860
+ - **Initials** come from `getInitials(name, { dir, firstInitialOnly })`: two letters for a full name, one for a single name, brackets and punctuation dropped, a hyphen or apostrophe joins words. A name with digits only, emoji or a script without letter initials (Han, Kana, Hangul, Thai, Lao, Khmer, Myanmar, Tibetan) shows none, so an icon or the `initials` slot is the better content. `initials` replaces the text. On a right-to-left page the two letters of a left-to-right name swap; Hebrew and Arabic names keep their order.
1861
+ - **Color.** `color` is `neutral` (the default), `brand`, `colorful` or one of `red`, `pumpkin`, `gold`, `forest`, `teal`, `blue`, `navy`, `lavender`, `purple`, `magenta`, `brown`, `steel`. `colorful` picks a named color from `idForColor`, else from `name`: the same input is always the same color, so a person keeps their color across pages. The palette is the `--wave-palette-<name>` and `--wave-palette-<name>-foreground` tokens; high contrast paints a white fill with black text.
1862
+ - **`active`** is `active` (the `activeAppearance` around the avatar: `ring`, `ring-shadow`, `shadow` or `glow`), `inactive` (dimmed) or `unset`.
1863
+ - **Presence.** `PresenceBadge` `status` is `available`, `busy`, `away`, `offline`, `do-not-disturb` or `out-of-office` (Fluent's names); `dnd` and `oof` still work and log a deprecation warning. Inside an Avatar the badge takes the size that fits the avatar.
1864
+ - **`Persona`** shows `primaryText` (default: `name`), then `secondaryText`, `tertiaryText` and `quaternaryText`, after, before or below the avatar (`textPosition`; below, the text is centered unless `textAlignment="start"`). `presenceOnly` swaps the avatar for the presence badge. A Persona without a `name` or text needs an `aria-label`.
1865
+ - **`AvatarGroup`** `layout` is `stack` (overlapping), `spread` (a gap) or `pie` (up to three wedges of a circle). Members take the group's `size`; one with a size of its own keeps it. `max` splits the members; to write the split yourself, use `partitionAvatarGroupItems({ items, maxInlineItems, layout })` and render `AvatarGroup.Item`s with an `AvatarGroup.Popover` for the rest:
1866
+
1867
+ ```tsx
1868
+ const { inlineItems, overflowItems } = partitionAvatarGroupItems({ items: people, maxInlineItems: 3 });
1869
+
1870
+ <AvatarGroup aria-label="Project team">
1871
+ {inlineItems.map((name) => <AvatarGroup.Item key={name} name={name} />)}
1872
+ {overflowItems && (
1873
+ <AvatarGroup.Popover>
1874
+ {overflowItems.map((name) => <AvatarGroup.Item key={name} name={name} />)}
1875
+ </AvatarGroup.Popover>
1876
+ )}
1877
+ </AvatarGroup>;
1878
+ ```
1879
+
1780
1880
  ### Tags
1781
1881
 
1782
1882
  Put tags that belong together in a `TagGroup`. By default it is a toolbar: one Tab stop, Left/Right between the tags (mirrored in RTL), Delete or Backspace to dismiss. When the focused tag is removed, focus moves to the next tag, else the previous one, else `fallbackFocusRef`, so it never falls to the page:
@@ -2045,6 +2145,15 @@ export function Shell({ narrow }: { narrow: boolean }) {
2045
2145
  - **Width.** `size` defaults to `small` (320px), Drawer's scale; Fluent's navigation pane is 260px wide, `className="w-65"` on your Tailwind build (or a class of your own with `width: 260px`). `position` defaults to `start` (Drawer's to `end`), and `separator` to on.
2046
2146
  - **Server rendering.** An inline NavDrawer renders in the server HTML (open, or hidden when kept mounted); with `focusMode="arrow"` its Tab stop is set once it has mounted.
2047
2147
 
2148
+ ### Cards, tabs and carousels
2149
+
2150
+ - **Card** `appearance` is `filled` (the default), `filled-alternative`, `outline` or `subtle`; `size` (`small`, `medium`, `large`) sets the padding of its parts through `--wave-card-padding`; `orientation="horizontal"` puts a `Card.Preview` beside the text. `Card.Preview` takes a `logo` over its bottom start corner. `Card.Header` takes an `image` (an Avatar, say) and an `action` (a menu button). With `selectionControl="checkbox"`, `checkbox` merges onto the built-in checkbox (an object), replaces it (an element) or removes it (`null`, when you render the control elsewhere); `floatingAction` sits over the top end corner and moves the checkbox to the start corner.
2151
+ - **TabList** `appearance` is `transparent` (the default), `subtle`, `subtle-circular` or `filled-circular`, and `size` `small`, `medium` or `large`. A `TabList.Tab` with an `icon` and no text is icon-only: give it an `aria-label` (development warning `TabList.Tab:icon-only-name`).
2152
+ - **Carousel groups.** `groupSize={n}` shows `n` slides per page and `"auto"` as many as fit (the slides keep their width, which must be equal; `align` places a page that does not fill the width). `value`, `onValueChange` and `defaultValue` are the index of the first slide of the page; previous, next, the picker (one button per page), looping and autoplay move by page. `labels.slides(start, end, total)` names a page.
2153
+ - **Dragging.** `draggable` follows the pointer (mouse, touch, pen); a drag past a quarter of the width, or a release faster than 0.5 px/ms, changes the page, else the track snaps back. The click that ends a drag is dropped, a vertical swipe still scrolls the page, and autoplay pauses while dragging.
2154
+ - **Thumbnails.** `<Carousel.Item thumbnail="/a.png">` (or an object of `<img>` attributes) turns the picker into a row of thumbnails; each button keeps its slide name.
2155
+ - **Controls.** `controlsLayout` is `overlay` (the default, round buttons over the slides), `overlay-wide` (full-height edge strips), `inline` (buttons beside the slides) or `inline-wide`. `Carousel.Button` (`direction="previous"` or `"next"`) replaces the built-in button of that direction and keeps its name, `aria-controls` and disabled behaviour; its children replace the chevron. `appearance="elevated"` rounds the carousel and adds a shadow.
2156
+
2048
2157
  ### Slots
2049
2158
 
2050
2159
  Props such as `icon`, `contentBefore` and `dismiss` are slots. A slot accepts content (rendered inside the slot's element) or an object with `as`, `className`, `children` and any attribute of the slot's element:
@@ -2085,7 +2194,7 @@ The names and hidden texts that components render themselves are English by defa
2085
2194
  | `MessageBar`, `Toast` | `statusLabel` (the hidden severity text; also an option of both `dispatchToast` forms); `Toast` also `dismissLabel` (also an option of the text form) |
2086
2195
  | `Tag` | `dismissLabel` ("Dismiss", with the tag's text) |
2087
2196
  | `InteractionTag.Secondary` | `dismissLabel` ("Dismiss", with the primary text: "Dismiss Cherry") |
2088
- | `Carousel` | `labels` (`previous`, `next`, `picker`, `slide(index, total)` with a zero-based index, `carouselRoleDescription`, `slideRoleDescription`), `autoPlayLabels` |
2197
+ | `Carousel` | `labels` (`previous`, `next`, `picker`, `slide(index, total)` with a zero-based index, `slides(start, end, total)` with one-based numbers for a page of several slides, `carouselRoleDescription`, `slideRoleDescription`), `autoPlayLabels` |
2089
2198
  | `Stepper` | `statusLabels` (`completed`, `error`; `''` omits the text) |
2090
2199
  | `Pagination` | `getItemAriaLabel(type, page, selected)` |
2091
2200
  | `ColorPicker` | `labels` (the 0.7 strings, plus `area` (the name of a bound area's group, "Saturation and brightness"), `saturation`, `brightness`, `roleDescription`, `hue`, `transparency`, `colorName(color)` and `valueText(color, channel)` for bound parts) |
@@ -2157,7 +2266,7 @@ As implemented in 0.11. Buttons, links, checkboxes, switches and the trigger but
2157
2266
  | ColorArea | One Tab stop. Left/Right change saturation (mirrored in RTL), Up/Down brightness; Shift with an arrow by 10; PageUp/PageDown brightness by 10; Home/End saturation to 0/100. |
2158
2267
  | ColorSlider, AlphaSlider | The arrows of their axis by 1 (mirrored in RTL when horizontal), Shift with an arrow by 10, PageUp/PageDown by 10, Home/End to the minimum/maximum. |
2159
2268
 
2160
- Accordion and Carousel have no arrow-key navigation: their triggers and controls are Tab stops.
2269
+ Accordion and Carousel have no arrow-key navigation between their controls: their triggers and controls are Tab stops. With `groupSize` above 1 the slides of the shown page are one arrow-key group (the slide that last had focus is its Tab stop; an arrow past the end of the page shows the next one).
2161
2270
 
2162
2271
  Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters typed with AltGr, which Windows reports as Ctrl+Alt (Polish `ł`, Romanian `ș`); Ctrl+Alt with an arrow, Home, End or Space is left to the browser. An item that cannot take focus is passed over for the next match. Menu typeahead matches the item labels, not icons or shortcuts. Options and option groups with `hidden` are skipped like a native `<option hidden>`.
2163
2272
 
@@ -2166,7 +2275,16 @@ Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters ty
2166
2275
  | Export | Purpose |
2167
2276
  | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2168
2277
  | `useControllable(value, defaultValue, onChange)` | Controlled/uncontrolled state; returns `[value, setValue, isControlled]`; `setValue` accepts a value or an updater and skips no-op updates. |
2169
- | `useRovingTabIndex(options)` | Roving tab stop and arrow-key navigation for composite widgets; items marked `data-disabled-focusable` stay reachable, a composite marked `data-roving-transparent` (a toolbar radio group) adds its items to the enclosing arrow order, and `tabStop: 'none'` leaves every item out of the Tab order (a composite reached by arrow keys only). |
2278
+ | `useRovingTabIndex(options)` | Roving tab stop and arrow-key navigation for composite widgets (`orientation: 'grid'` with `columns` for two-dimensional grids); items marked `data-disabled-focusable` stay reachable, a composite marked `data-roving-transparent` (a toolbar radio group) adds its items to the enclosing arrow order, and `tabStop: 'none'` leaves every item out of the Tab order (a composite reached by arrow keys only). |
2279
+ | `usePopupPosition(options)` | Place a surface against an anchor (an element or a `VirtualElement`): `side`, `align`, `offset`, `flip`, `fallbackPlacements`, `shift`, `fitViewport`, `matchReferenceWidth`, `strategy`, `hideWhenDetached`, `onPositioned`; returns `floatingProps`, `update()` and the final placement. |
2280
+ | `useDismiss(options)`, `DismissLayerProvider` | Register a dismiss layer (Escape, outside press, focus leaving it) in WaveUI's layer stack; `Portal layerId` and `DismissLayerProvider` make layers opened inside its children. |
2281
+ | `useModalLayer(options)`, `useFocusTrap`, `useInitialFocus`, `useRestoreFocus` | A modal surface's dismissal, focus trap, `inert` isolation, scroll lock and focus restore (`modalType`: `modal`, `alert`, `non-modal`); the pieces are public too. |
2282
+ | `useModalOpen()`, `hasOpenModal()`, `modalAllowProps` | Whether a modal is open; props that keep an app-owned region usable over a modal. |
2283
+ | `useFocusableGroup(options)` | One tab stop that holds several focusable elements (`tabBehavior`: `unlimited`, `limited`, `limited-trap-focus`); Enter or F2 enters, Escape leaves. |
2284
+ | `useFocusVisible()` | `true` while the last input was the keyboard; `false` on the server. |
2285
+ | `useGridNavigation(options)` | Keyboard navigation of a static `<table role="grid">` (the Table's own). |
2286
+ | `getTabbableElements(container)`, `getFirstTabbable`, `getLastTabbable` | The tabbable elements of a container in Tab order (hidden, disabled and `inert` ones left out). |
2287
+ | `focusRing`, `focusRingInset`, `inputFocus`, `inputFocusWithin` | The focus class strings of the library, to compose with `cn()` on your own controls. |
2170
2288
  | `useId(prefix?)` | SSR-safe ids (`prefix-<react id>`; never parse the React part). |
2171
2289
  | `useEventCallback(fn)` | Stable callback that always calls the latest `fn`. |
2172
2290
  | `useMergedRefs(...refs)` | One stable callback ref for several refs. |
@@ -2184,6 +2302,8 @@ Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters ty
2184
2302
  | `createToaster()` | A toast controller for code outside components; bind it with `<Toaster toaster={handle}>` (see [Toasts](#toasts)). Server-safe. |
2185
2303
  | `useIsOverflowing(target)`, `useOverflowMenu()`, `useIsOverflowItemVisible(id)` | Overflow detection. |
2186
2304
  | `hsvToHex(color)`, `hexToHsv(hex)` | Convert between an `HsvColor` and a hex string (`#rrggbb`, or `#rrggbbaa` below full opacity); `hexToHsv` returns `null` for other text. Server-safe. |
2305
+ | `getInitials(name, options?)` | The initials Avatar shows (`dir`, `firstInitialOnly`); none for digits, emoji or scripts without letter initials. Server-safe. |
2306
+ | `partitionAvatarGroupItems({ items, maxInlineItems, layout })` | Split a list into the inline and overflow items of an AvatarGroup (`{ inlineItems, overflowItems }`); imports nothing. |
2187
2307
  | `addDays(date, amount)`, `addMonths(date, amount)`, `isSameDay(a, b)`, `startOfWeek(date, firstDayOfWeek?)`, `getWeekNumber(date, options?)` | Date helpers on calendar days: every returned date is local midnight (Fluent's keep the time of day). `addMonths` clamps the day to the target month (January 31 plus a month is February 28 or 29); `getWeekNumber` takes `firstDayOfWeek` and `firstWeekOfYear` (`GetWeekNumberOptions`; ISO 8601 is `{ firstDayOfWeek: 1, firstWeekOfYear: 'first-four-day-week' }`). With the types `DayOfWeek` (`0`–`6`, Sunday first) and `FirstWeekOfYear`. Server-safe. |
2188
2308
  | `buttonClassNames`, `toastTitleClassNames`, … | The stable class names of every component and part (see [Styling hooks](#styling-hooks)). Server-safe. |
2189
2309
  | `cn(...classes)` | clsx + tailwind-merge that knows Wave's type ramp and shadows; the last class wins over a conflicting class of the same variant. |
@@ -2192,6 +2312,30 @@ Typeahead (Menu, selectable List, Tree, Dropdown, Listbox) accepts characters ty
2192
2312
  | `resolveSlot`, `renderSlot` | The slot helpers the components use. |
2193
2313
  | `getThemeClassName(theme)` | The theme classes of a theme. |
2194
2314
 
2315
+ ## Upgrading from 0.12
2316
+
2317
+ 0.13 removes nothing public; these changes can still affect your types, tests and styles:
2318
+
2319
+ 1. **`PresenceStatus` gains `'do-not-disturb'` and `'out-of-office'`** (`dnd` and `oof` stay, deprecated): an exhaustive `switch` or a `Record` over it needs the cases. `PresenceBadge` `status` is optional.
2320
+ 2. **`Avatar` `size` also takes a number and `Persona` `size` gains `'huge'`:** code that narrows these unions needs the new members.
2321
+ 3. **An Avatar in a rounded Tag is square** (`Tag` and `InteractionTag` pass their shape to their `media`).
2322
+ 4. **Initials come from `getInitials`:** punctuation is dropped, a hyphen or apostrophe joins words, and names without letter initials show none.
2323
+ 5. **AvatarGroup's popup is `AvatarGroup.Popover`:** the count reads `99+` past 99 (the name keeps the real number).
2324
+ 6. **Card parts take their padding from `--wave-card-padding`** instead of a fixed `p-4`.
2325
+ 7. **Carousel has a viewport element** (`.wave-carousel__viewport`) that clips the track; the default layout's buttons sit inside it. Reach the track by `.wave-carousel__track`.
2326
+
2327
+ The CHANGELOG's [0.13.0 section](CHANGELOG.md) lists the additions.
2328
+
2329
+ ## Upgrading from 0.11
2330
+
2331
+ 0.12 removes nothing public; these changes can still affect your types and tests:
2332
+
2333
+ 1. **`target` widens.** `Popover` and `Menu.Popover` `target` also accept a ref object (`PopupTargetInput`), and `TeachingPopover` `target` a `VirtualElement`; code that reads `PopoverProps['target']` as `PopupTarget` needs the wider type.
2334
+ 2. **`useRovingTabIndex` `orientation` gains `'grid'`:** an exhaustive `switch` or a `Record` over the option's type needs the case.
2335
+ 3. **`usePopupPosition` results gain `update()`**, and `useListboxPopup` options gain `positioning`; nothing else about them changes.
2336
+
2337
+ The CHANGELOG's [0.12.0 section](CHANGELOG.md) lists the additions.
2338
+
2195
2339
  ## Upgrading from 0.10
2196
2340
 
2197
2341
  0.11 removes nothing public; these changes can still affect your tests, styles and types:
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("./Button.semantics.cjs"),a=require("../../lib/styles.cjs");let o=require("react");o=e.__toESM(o,1);let s=require("react/jsx-runtime");var c={inline:`text-primary underline not-disabled:not-aria-disabled:hover:decoration-2 focus-visible:decoration-2`,standalone:`font-semibold text-primary no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline`,subtle:`text-foreground no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline`},l=e=>{let{as:o,appearance:l,variant:u,disabled:d=!1,disabledFocusable:f=!1,className:p,onClick:m,onKeyDown:h,onKeyUp:g,onBlur:_,ref:v,...y}=e,b=n.resolveDeprecatedProp(`Link`,l,u,`variant`,`appearance`)??`inline`,x=o??`a`,{defaults:S,enforced:C,handlers:w}=i.useButtonSemantics({tag:typeof x==`string`?x:null,href:y.href,disabled:d,disabledFocusable:f,onClick:m,onKeyDown:h,onKeyUp:g,onBlur:_}),T={...y};for(let[e,t]of Object.entries(S))T[e]??=t;return(0,s.jsx)(x,{...T,...w,ref:v,className:t.cn(r.linkClassNames.root,`cursor-pointer transition-colors motion-reduce:transition-none`,a.focusRing,c[b],(d||f)&&`cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100`,p),...C})};l.displayName=`Link`,exports.Link=l;
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../lib/styles.cjs"),a=require("./Button.semantics.cjs");let o=require("react");o=e.__toESM(o,1);let s=require("react/jsx-runtime");var c={inline:`text-primary underline not-disabled:not-aria-disabled:hover:decoration-2 focus-visible:decoration-2`,standalone:`font-semibold text-primary no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline`,subtle:`text-foreground no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline`},l=e=>{let{as:o,appearance:l,variant:u,disabled:d=!1,disabledFocusable:f=!1,className:p,onClick:m,onKeyDown:h,onKeyUp:g,onBlur:_,ref:v,...y}=e,b=n.resolveDeprecatedProp(`Link`,l,u,`variant`,`appearance`)??`inline`,x=o??`a`,{defaults:S,enforced:C,handlers:w}=a.useButtonSemantics({tag:typeof x==`string`?x:null,href:y.href,disabled:d,disabledFocusable:f,onClick:m,onKeyDown:h,onKeyUp:g,onBlur:_}),T={...y};for(let[e,t]of Object.entries(S))T[e]??=t;return(0,s.jsx)(x,{...T,...w,ref:v,className:t.cn(r.linkClassNames.root,`cursor-pointer transition-colors motion-reduce:transition-none`,i.focusRing,c[b],(d||f)&&`cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100`,p),...C})};l.displayName=`Link`,exports.Link=l;
2
2
  //# sourceMappingURL=Link.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Link.cjs","names":["resolveDeprecatedProp","useButtonSemantics","cn","linkClassNames","focusRing","require_runtime","require_cn","require_dev","require_classNames","require_Button_semantics","require_styles","react","react_jsx_runtime","appearanceClasses","Link","appearanceProp","rest","props","appearance","variant","Component","as","elementProps","key","value","defaults","handlers","disabled","disabledFocusable","className","enforced"],"sources":["../../../src/components/button/Link.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { linkClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport { focusRing } from '../../lib/styles';\nimport type { PolymorphicComponent, PolymorphicProps } from '../../lib/polymorphic';\nimport { useButtonSemantics } from './Button.semantics';\n\n/**\n * Color treatment of a {@link Link}.\n *\n * - `inline` (default): for links in running text. Always underlined (the underline thickens on\n * hover and focus), because the link color alone does not stand out enough from body text.\n * - `standalone`: semibold, underlined on hover/focus only. Use it only where the position or\n * container already marks the text as a link (a list of links, a card footer, navigation).\n * - `subtle`: foreground color, underlined on hover/focus only. It cannot be told apart from body\n * text, so never use it inside a paragraph; only where the context makes the link obvious.\n */\nexport type LinkAppearance = 'inline' | 'standalone' | 'subtle';\n\n/** @deprecated Use {@link LinkAppearance}. */\nexport type LinkVariant = LinkAppearance;\n\n/**\n * The Link's own props (the XOwnProps rule of `PolymorphicProps`: component-specific props only).\n * Every other prop comes from the rendered element (`as`, default `'a'`).\n */\nexport interface LinkOwnProps {\n /** Color treatment (see {@link LinkAppearance} for where each one may be used).\n * @default 'inline'\n */\n appearance?: LinkAppearance;\n /** @deprecated Use `appearance` (same values). */\n variant?: LinkVariant;\n /**\n * Makes the link unavailable. An `<a>` drops its `href` (no navigation by middle-click, the\n * context menu or drag), keeps `role=\"link\"` (`role=\"button\"` when it had no `href`), and gets\n * `aria-disabled=\"true\"`, `data-disabled` and `tabIndex={-1}` (none can be overridden); a custom\n * `as` (router link) gets the same attributes. Clicks, Enter and Space are prevented: your\n * `onClick` is not called and the click does not reach ancestor click handlers. `as=\"button\"`\n * uses the native `disabled` attribute.\n * @default false\n */\n disabled?: boolean;\n /**\n * Marks the link unavailable but keeps it focusable and in the tab order: for a toolbar item or\n * a disabled link that needs a Tooltip. Renders `aria-disabled=\"true\"`, `data-disabled` and\n * `data-disabled-focusable`; an `<a>` drops its `href`, keeps `role=\"link\"` (`role=\"button\"`\n * when it had no `href`) and gets `tabIndex={0}`, and `as=\"button\"` gets these attributes\n * instead of the native `disabled`.\n * Clicks, Enter and Space are prevented; your `onClick` is not called and the click does not\n * reach ancestor click handlers. Wins over `disabled` when both are set. In a `Toolbar` it stays\n * in the arrow-key order.\n * @default false\n */\n disabledFocusable?: boolean;\n}\n\n/**\n * Props of {@link Link} rendered as `C` (default `'a'`). `LinkProps` without a type argument is\n * the 0.4 name: the props of a Link rendered as an `<a>`, including `ref`.\n */\nexport type LinkProps<C extends React.ElementType = 'a'> = PolymorphicProps<C, LinkOwnProps>;\n\n/** The props the implementation reads, for any `as`. */\ntype LinkImplProps = LinkOwnProps &\n Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'onKeyDown' | 'onKeyUp'> & {\n as?: React.ElementType;\n ref?: React.Ref<HTMLElement>;\n /** The destination: without one, the anchor gets button semantics. */\n href?: string;\n onClick?: React.MouseEventHandler<HTMLElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLElement>;\n };\n\nconst appearanceClasses: Record<LinkAppearance, string> = {\n inline:\n 'text-primary underline not-disabled:not-aria-disabled:hover:decoration-2 focus-visible:decoration-2',\n standalone:\n 'font-semibold text-primary no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline',\n subtle:\n 'text-foreground no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline',\n};\n\n/**\n * A hyperlink with Fluent link styling. Renders an `<a>` by default; `as` renders a router link\n * (`<Link as={RouterLink} to=\"/\">`) or a `<button>` styled as a link (`type=\"button\"` by default).\n *\n * - Without `href`, the `<a>` runs an action instead of navigating (\"Show more\"): it keeps its\n * element and gets `role=\"button\"`, a tab stop and Enter/Space activation (the consumer's\n * `role` and `tabIndex` win). A non-interactive `as` (`span`, `div`) is treated the same way;\n * any `href` string, `''` included, keeps the link semantics.\n *\n * @example\n * <p>Read the <Link href=\"/docs\">documentation</Link> first.</p>\n * <Link appearance=\"standalone\" href=\"/pricing\">See pricing</Link>\n * <Link onClick={showMore}>Show more</Link>\n */\nexport const Link: PolymorphicComponent<'a', LinkOwnProps> = (props) => {\n const {\n as,\n appearance: appearanceProp,\n variant,\n disabled = false,\n disabledFocusable = false,\n className,\n onClick,\n onKeyDown,\n onKeyUp,\n onBlur,\n ref,\n ...rest\n } = props as LinkImplProps;\n\n const appearance =\n resolveDeprecatedProp('Link', appearanceProp, variant, 'variant', 'appearance') ?? 'inline';\n\n const Component: React.ElementType = as ?? 'a';\n const tag = typeof Component === 'string' ? Component : null;\n // The activation semantics of Button: an `<a>` without `href` or a `span` is a button, and a\n // disabled link blocks its click (ancestors included), Enter and Space.\n const { defaults, enforced, handlers } = useButtonSemantics({\n tag,\n href: rest.href,\n disabled,\n disabledFocusable,\n onClick,\n onKeyDown,\n onKeyUp,\n onBlur,\n });\n\n // Defaults apply wherever the consumer's value is `undefined` or `null` (C-COMPOSE).\n const elementProps: Record<string, unknown> = { ...rest };\n for (const [key, value] of Object.entries(defaults)) elementProps[key] ??= value;\n\n return (\n <Component\n {...elementProps}\n {...handlers}\n ref={ref}\n className={cn(\n linkClassNames.root,\n 'cursor-pointer transition-colors motion-reduce:transition-none',\n focusRing,\n appearanceClasses[appearance],\n // Full opacity while a focusable disabled link shows its focus ring, which `opacity`\n // would dim below 3:1 (as for buttons).\n (disabled || disabledFocusable) &&\n 'cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100',\n className,\n )}\n {...enforced}\n />\n );\n};\n\nLink.displayName = 'Link';\n"],"mappings":"yTA4EA,IAAMa,EAAoD,CACxD,OACE,sGACF,WACE,iHACF,OACE,qGACJ,EAgBaC,EAAiD,GAAU,CACtE,GAAM,CACJ,KACA,WAAYC,EACZ,UACA,WAAW,GACX,oBAAoB,GACpB,YACA,UACA,YACA,UACA,SACA,MACA,GAAGC,GACDC,EAEEC,EACJlB,EAAAA,sBAAsB,OAAQe,EAAgBI,EAAS,UAAW,YAAY,GAAK,SAE/EC,EAA+BC,GAAM,IAIrC,CAAE,WAAU,WAAU,YAAapB,EAAAA,mBAAmB,CAC1D,IAJU,OAAOmB,GAAc,SAAWA,EAAY,KAKtD,KAAMJ,EAAK,KACX,WACA,oBACA,UACA,YACA,UACA,QACF,CAAC,EAGKM,EAAwC,CAAE,GAAGN,CAAK,EACxD,IAAK,GAAM,CAACO,EAAKC,KAAU,OAAO,QAAQC,CAAQ,EAAG,EAAaF,KAASC,EAE3E,OACE,EAAAZ,EAAA,IAAA,CAACQ,EAAD,CACE,GAAIE,EACJ,GAAII,EACC,MACL,UAAWxB,EAAAA,GACTC,EAAAA,eAAe,KACf,iEACAC,EAAAA,UACAS,EAAkBK,IAGjBS,GAAYC,IACX,wEACFC,CACF,EACA,GAAIC,CACL,CAAA,CAEL,EAEA,EAAK,YAAc"}
1
+ {"version":3,"file":"Link.cjs","names":["resolveDeprecatedProp","useButtonSemantics","cn","linkClassNames","focusRing","require_runtime","require_cn","require_dev","require_classNames","require_styles","require_Button_semantics","react","react_jsx_runtime","appearanceClasses","Link","appearanceProp","rest","props","appearance","variant","Component","as","elementProps","key","value","defaults","handlers","disabled","disabledFocusable","className","enforced"],"sources":["../../../src/components/button/Link.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { linkClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport { focusRing } from '../../lib/styles';\nimport type { PolymorphicComponent, PolymorphicProps } from '../../lib/polymorphic';\nimport { useButtonSemantics } from './Button.semantics';\n\n/**\n * Color treatment of a {@link Link}.\n *\n * - `inline` (default): for links in running text. Always underlined (the underline thickens on\n * hover and focus), because the link color alone does not stand out enough from body text.\n * - `standalone`: semibold, underlined on hover/focus only. Use it only where the position or\n * container already marks the text as a link (a list of links, a card footer, navigation).\n * - `subtle`: foreground color, underlined on hover/focus only. It cannot be told apart from body\n * text, so never use it inside a paragraph; only where the context makes the link obvious.\n */\nexport type LinkAppearance = 'inline' | 'standalone' | 'subtle';\n\n/** @deprecated Use {@link LinkAppearance}. */\nexport type LinkVariant = LinkAppearance;\n\n/**\n * The Link's own props (the XOwnProps rule of `PolymorphicProps`: component-specific props only).\n * Every other prop comes from the rendered element (`as`, default `'a'`).\n */\nexport interface LinkOwnProps {\n /** Color treatment (see {@link LinkAppearance} for where each one may be used).\n * @default 'inline'\n */\n appearance?: LinkAppearance;\n /** @deprecated Use `appearance` (same values). */\n variant?: LinkVariant;\n /**\n * Makes the link unavailable. An `<a>` drops its `href` (no navigation by middle-click, the\n * context menu or drag), keeps `role=\"link\"` (`role=\"button\"` when it had no `href`), and gets\n * `aria-disabled=\"true\"`, `data-disabled` and `tabIndex={-1}` (none can be overridden); a custom\n * `as` (router link) gets the same attributes. Clicks, Enter and Space are prevented: your\n * `onClick` is not called and the click does not reach ancestor click handlers. `as=\"button\"`\n * uses the native `disabled` attribute.\n * @default false\n */\n disabled?: boolean;\n /**\n * Marks the link unavailable but keeps it focusable and in the tab order: for a toolbar item or\n * a disabled link that needs a Tooltip. Renders `aria-disabled=\"true\"`, `data-disabled` and\n * `data-disabled-focusable`; an `<a>` drops its `href`, keeps `role=\"link\"` (`role=\"button\"`\n * when it had no `href`) and gets `tabIndex={0}`, and `as=\"button\"` gets these attributes\n * instead of the native `disabled`.\n * Clicks, Enter and Space are prevented; your `onClick` is not called and the click does not\n * reach ancestor click handlers. Wins over `disabled` when both are set. In a `Toolbar` it stays\n * in the arrow-key order.\n * @default false\n */\n disabledFocusable?: boolean;\n}\n\n/**\n * Props of {@link Link} rendered as `C` (default `'a'`). `LinkProps` without a type argument is\n * the 0.4 name: the props of a Link rendered as an `<a>`, including `ref`.\n */\nexport type LinkProps<C extends React.ElementType = 'a'> = PolymorphicProps<C, LinkOwnProps>;\n\n/** The props the implementation reads, for any `as`. */\ntype LinkImplProps = LinkOwnProps &\n Omit<React.HTMLAttributes<HTMLElement>, 'onClick' | 'onKeyDown' | 'onKeyUp'> & {\n as?: React.ElementType;\n ref?: React.Ref<HTMLElement>;\n /** The destination: without one, the anchor gets button semantics. */\n href?: string;\n onClick?: React.MouseEventHandler<HTMLElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLElement>;\n onKeyUp?: React.KeyboardEventHandler<HTMLElement>;\n };\n\nconst appearanceClasses: Record<LinkAppearance, string> = {\n inline:\n 'text-primary underline not-disabled:not-aria-disabled:hover:decoration-2 focus-visible:decoration-2',\n standalone:\n 'font-semibold text-primary no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline',\n subtle:\n 'text-foreground no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline',\n};\n\n/**\n * A hyperlink with Fluent link styling. Renders an `<a>` by default; `as` renders a router link\n * (`<Link as={RouterLink} to=\"/\">`) or a `<button>` styled as a link (`type=\"button\"` by default).\n *\n * - Without `href`, the `<a>` runs an action instead of navigating (\"Show more\"): it keeps its\n * element and gets `role=\"button\"`, a tab stop and Enter/Space activation (the consumer's\n * `role` and `tabIndex` win). A non-interactive `as` (`span`, `div`) is treated the same way;\n * any `href` string, `''` included, keeps the link semantics.\n *\n * @example\n * <p>Read the <Link href=\"/docs\">documentation</Link> first.</p>\n * <Link appearance=\"standalone\" href=\"/pricing\">See pricing</Link>\n * <Link onClick={showMore}>Show more</Link>\n */\nexport const Link: PolymorphicComponent<'a', LinkOwnProps> = (props) => {\n const {\n as,\n appearance: appearanceProp,\n variant,\n disabled = false,\n disabledFocusable = false,\n className,\n onClick,\n onKeyDown,\n onKeyUp,\n onBlur,\n ref,\n ...rest\n } = props as LinkImplProps;\n\n const appearance =\n resolveDeprecatedProp('Link', appearanceProp, variant, 'variant', 'appearance') ?? 'inline';\n\n const Component: React.ElementType = as ?? 'a';\n const tag = typeof Component === 'string' ? Component : null;\n // The activation semantics of Button: an `<a>` without `href` or a `span` is a button, and a\n // disabled link blocks its click (ancestors included), Enter and Space.\n const { defaults, enforced, handlers } = useButtonSemantics({\n tag,\n href: rest.href,\n disabled,\n disabledFocusable,\n onClick,\n onKeyDown,\n onKeyUp,\n onBlur,\n });\n\n // Defaults apply wherever the consumer's value is `undefined` or `null` (C-COMPOSE).\n const elementProps: Record<string, unknown> = { ...rest };\n for (const [key, value] of Object.entries(defaults)) elementProps[key] ??= value;\n\n return (\n <Component\n {...elementProps}\n {...handlers}\n ref={ref}\n className={cn(\n linkClassNames.root,\n 'cursor-pointer transition-colors motion-reduce:transition-none',\n focusRing,\n appearanceClasses[appearance],\n // Full opacity while a focusable disabled link shows its focus ring, which `opacity`\n // would dim below 3:1 (as for buttons).\n (disabled || disabledFocusable) &&\n 'cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100',\n className,\n )}\n {...enforced}\n />\n );\n};\n\nLink.displayName = 'Link';\n"],"mappings":"yTA4EA,IAAMa,EAAoD,CACxD,OACE,sGACF,WACE,iHACF,OACE,qGACJ,EAgBaC,EAAiD,GAAU,CACtE,GAAM,CACJ,KACA,WAAYC,EACZ,UACA,WAAW,GACX,oBAAoB,GACpB,YACA,UACA,YACA,UACA,SACA,MACA,GAAGC,GACDC,EAEEC,EACJlB,EAAAA,sBAAsB,OAAQe,EAAgBI,EAAS,UAAW,YAAY,GAAK,SAE/EC,EAA+BC,GAAM,IAIrC,CAAE,WAAU,WAAU,YAAapB,EAAAA,mBAAmB,CAC1D,IAJU,OAAOmB,GAAc,SAAWA,EAAY,KAKtD,KAAMJ,EAAK,KACX,WACA,oBACA,UACA,YACA,UACA,QACF,CAAC,EAGKM,EAAwC,CAAE,GAAGN,CAAK,EACxD,IAAK,GAAM,CAACO,EAAKC,KAAU,OAAO,QAAQC,CAAQ,EAAG,EAAaF,KAASC,EAE3E,OACE,EAAAZ,EAAA,IAAA,CAACQ,EAAD,CACE,GAAIE,EACJ,GAAII,EACC,MACL,UAAWxB,EAAAA,GACTC,EAAAA,eAAe,KACf,iEACAC,EAAAA,UACAS,EAAkBK,IAGjBS,GAAYC,IACX,wEACFC,CACF,EACA,GAAIC,CACL,CAAA,CAEL,EAEA,EAAK,YAAc"}
@@ -2,8 +2,8 @@
2
2
  import { cn as e } from "../../lib/cn.mjs";
3
3
  import { resolveDeprecatedProp as t } from "../../lib/dev.mjs";
4
4
  import { linkClassNames as n } from "../../lib/classNames.mjs";
5
- import { useButtonSemantics as r } from "./Button.semantics.mjs";
6
- import { focusRing as i } from "../../lib/styles.mjs";
5
+ import { focusRing as r } from "../../lib/styles.mjs";
6
+ import { useButtonSemantics as i } from "./Button.semantics.mjs";
7
7
  import "react";
8
8
  import { jsx as a } from "react/jsx-runtime";
9
9
  //#region src/components/button/Link.tsx
@@ -12,7 +12,7 @@ var o = {
12
12
  standalone: "font-semibold text-primary no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline",
13
13
  subtle: "text-foreground no-underline not-disabled:not-aria-disabled:hover:underline focus-visible:underline"
14
14
  }, s = (s) => {
15
- let { as: c, appearance: l, variant: u, disabled: d = !1, disabledFocusable: f = !1, className: p, onClick: m, onKeyDown: h, onKeyUp: g, onBlur: _, ref: v, ...y } = s, b = t("Link", l, u, "variant", "appearance") ?? "inline", x = c ?? "a", { defaults: S, enforced: C, handlers: w } = r({
15
+ let { as: c, appearance: l, variant: u, disabled: d = !1, disabledFocusable: f = !1, className: p, onClick: m, onKeyDown: h, onKeyUp: g, onBlur: _, ref: v, ...y } = s, b = t("Link", l, u, "variant", "appearance") ?? "inline", x = c ?? "a", { defaults: S, enforced: C, handlers: w } = i({
16
16
  tag: typeof x == "string" ? x : null,
17
17
  href: y.href,
18
18
  disabled: d,
@@ -27,7 +27,7 @@ var o = {
27
27
  ...T,
28
28
  ...w,
29
29
  ref: v,
30
- className: e(n.root, "cursor-pointer transition-colors motion-reduce:transition-none", i, o[b], (d || f) && "cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100", p),
30
+ className: e(n.root, "cursor-pointer transition-colors motion-reduce:transition-none", r, o[b], (d || f) && "cursor-not-allowed opacity-50 aria-disabled:focus-visible:opacity-100", p),
31
31
  ...C
32
32
  });
33
33
  };
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/slot.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../lib/classNames.cjs"),a=require("../../hooks/useMergedRefs.cjs"),o=require("../../lib/aria.cjs"),ee=require("../../lib/icons.cjs"),te=require("./Avatar.context.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");var l={"extra-small":`w-6 h-6 text-[10px]`,small:`w-8 h-8 text-xs`,medium:`w-10 h-10 text-sm`,large:`w-12 h-12 text-base`,"extra-large":`w-14 h-14 text-lg`},ne={24:l[`extra-small`],20:`w-5 h-5 text-[10px]`,16:`w-4 h-4 text-[10px]`},u=`w-full h-full object-cover`;function re(e){let t=e.trim().split(/\s+/).filter(Boolean);return t.length===0?``:((Array.from(t[0])[0]??``)+(t.length>1?Array.from(t[t.length-1])[0]??``:``)).toUpperCase()}function d(e){return e?.trim().replace(/\s+/g,` `)||void 0}function ie(e){if(s.isValidElement(e))return e.props;if(typeof e==`object`&&e&&!(Symbol.iterator in e))return e}function ae(e,t,n){if(e===void 0)return[void 0,void 0,n||void 0,void 0];if(typeof e==`string`)return[void 0,void 0,e,void 0];let r=s.isValidElement(e)?e:void 0;return[r?.type,r?.key,t?.src,t?.srcSet]}function f(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function p(e,t){if(Object.is(e,t))return!0;if(!f(e)||!f(t))return!1;let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&Object.is(e[n],t[n]))}function oe(e,t){return e.every((e,n)=>p(e,t[n]))}var m=({src:e,name:f,size:p,icon:m,image:h,badge:g,decorative:_=!1,className:v,ref:y,role:b,"aria-label":x,"aria-labelledby":S,"aria-describedby":C,"aria-description":se,"aria-details":ce,...w})=>{let T=s.useContext(te.AvatarSizeContext),E=h==null||typeof h==`boolean`||h===``?void 0:h,D=ie(E),O=ae(E,D,e),[le,k]=s.useState(!1),[ue,A]=s.useState(O);oe(ue,O)||(A(O),k(!1));let j=s.useRef(null);s.useLayoutEffect(()=>{let e=j.current?.querySelector(`img`);if(!e||!e.complete||e.naturalWidth!==0)return;let t=!0,n=e.getAttribute(`src`),r=e.getAttribute(`srcset`),i=()=>{t&&e.isConnected&&e.getAttribute(`src`)===n&&e.getAttribute(`srcset`)===r&&k(!0)};return typeof e.decode==`function`?e.decode().then(void 0,i):queueMicrotask(i),()=>{t=!1}},[]);let M=a.useMergedRefs(y,j),N=x!==void 0||S!==void 0,P=b!==void 0&&b!==`presentation`&&b!==`none`,F=d(f),I=_||N||P?``:F??``,L=()=>k(!0),R=D?.alt,z=R!=null,B=z?R:I,V={"aria-describedby":C,"aria-description":se,"aria-details":ce},H=!_&&!N&&!P&&typeof B==`string`&&B.trim()!==``,U=H?V:{},W=null;if(!le){if(typeof E==`string`)W=(0,c.jsx)(`img`,{src:E,alt:I,...U,className:t.cn(i.avatarClassNames.image,u),onError:L});else if(E!==void 0){let e={onError:r.composeEventHandlers(D?.onError,L)};if(z||(e.alt=I),H){let t=D?.[`aria-describedby`];e[`aria-describedby`]=o.joinIds(C,typeof t==`string`?t:void 0)}let a=s.isValidElement(E)?s.cloneElement(E,e):D?{...E,...e}:E;W=n.renderSlot(a,`img`,t.cn(i.avatarClassNames.image,u),{alt:I,...U})}else e&&(W=(0,c.jsx)(`img`,{src:e,alt:I,...U,className:t.cn(i.avatarClassNames.image,u),onError:L}))}let G=W!==null&&H?{}:V,K=W===null&&m&&n.slotRendersContent(m)?n.renderSlot(m,`span`,t.cn(i.avatarClassNames.icon,`inline-flex`),{"aria-hidden":!0}):null,q=W===null&&K===null&&f?re(f):``,J,Y;W===null?K===null?q?(J=(0,c.jsx)(`span`,{"aria-hidden":`true`,className:i.avatarClassNames.initials,children:q}),Y=`bg-primary text-primary-foreground`):(J=(0,c.jsx)(ee.PersonIcon,{size:`60%`,className:i.avatarClassNames.icon}),Y=`bg-muted text-muted-foreground`):(J=K,Y=`bg-muted text-muted-foreground`):J=W;let de=W!==null&&P&&typeof B==`string`?d(B):void 0,fe=typeof R==`string`?d(R):void 0,X=x??(W===null?F??fe:P?de??F:void 0),Z;Z=_?{"aria-hidden":!0,...G}:X!==void 0||S!==void 0?{role:b??`img`,"aria-label":X,"aria-labelledby":S,...G}:W!==null||b!==void 0?{role:b,...G}:{"aria-hidden":!0,...G};let Q=g&&n.slotRendersContent(g)?n.renderSlot(g,`span`,t.cn(i.avatarClassNames.badge,`absolute bottom-0 end-0 inline-flex`)):null,pe=Q!==null,me=p===void 0?T?ne[T.size]:l.medium:l[p],$=t.cn(i.avatarClassNames.visual,`inline-flex items-center justify-center rounded-full overflow-hidden shrink-0 font-bold`,me,Y);return pe?(0,c.jsxs)(`span`,{ref:y,...w,className:t.cn(i.avatarClassNames.root,`relative inline-flex shrink-0`,v),children:[(0,c.jsx)(`span`,{ref:j,...Z,className:$,children:J}),Q]}):(0,c.jsx)(`span`,{ref:M,...Z,...w,className:t.cn(i.avatarClassNames.root,$,v),children:J})};m.displayName=`Avatar`,exports.Avatar=m,exports.avatarSizeClasses=l;
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/slot.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../lib/classNames.cjs"),a=require("../../lib/initials.cjs"),ee=require("../../hooks/useMergedRefs.cjs"),te=require("../../lib/aria.cjs"),ne=require("../../hooks/useDirection.cjs"),re=require("../../lib/icons.cjs"),o=require("./Avatar.context.cjs"),ie=require("./AvatarGroup.context.cjs"),s=require("./Avatar.colors.cjs"),c=require("./Avatar.sizes.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");c.avatarBoxClasses[24],c.avatarBoxClasses[32],c.avatarBoxClasses[40],c.avatarBoxClasses[48],c.avatarBoxClasses[56];var d=`w-full h-full object-cover`,ae={ring:`ring-2 ring-primary ring-offset-2 ring-offset-background`,"ring-shadow":`ring-2 ring-primary ring-offset-2 ring-offset-background shadow-8`,shadow:`shadow-8`,glow:`shadow-[0_0_0.5rem_0.125rem_var(--wave-primary)]`};function f(e){return e?.trim().replace(/\s+/g,` `)||void 0}function oe(e){if(l.isValidElement(e))return e.props;if(typeof e==`object`&&e&&!(Symbol.iterator in e))return e}function se(e,t,n){if(e===void 0)return[void 0,void 0,n||void 0,void 0];if(typeof e==`string`)return[void 0,void 0,e,void 0];let r=l.isValidElement(e)?e:void 0;return[r?.type,r?.key,t?.src,t?.srcSet]}function p(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function m(e,t){if(Object.is(e,t))return!0;if(!p(e)||!p(t))return!1;let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>Object.prototype.hasOwnProperty.call(t,n)&&Object.is(e[n],t[n]))}function ce(e,t){return e.every((e,n)=>m(e,t[n]))}var h=({src:e,name:p,size:m,shape:h,color:le=`brand`,idForColor:ue,active:g=`unset`,activeAppearance:_=`ring`,initials:v,icon:y,image:b,badge:x,decorative:S=!1,className:C,ref:w,role:T,"aria-label":de,"aria-labelledby":E,"aria-describedby":fe,"aria-description":pe,"aria-details":me,...he})=>{let D=l.useContext(o.AvatarSizeContext),O=b==null||typeof b==`boolean`||b===``?void 0:b,k=oe(O),A=se(O,k,e),[ge,j]=l.useState(!1),[_e,ve]=l.useState(A);ce(_e,A)||(ve(A),j(!1));let M=l.useRef(null);l.useLayoutEffect(()=>{let e=M.current?.querySelector(`img`);if(!e||!e.complete||e.naturalWidth!==0)return;let t=!0,n=e.getAttribute(`src`),r=e.getAttribute(`srcset`),i=()=>{t&&e.isConnected&&e.getAttribute(`src`)===n&&e.getAttribute(`srcset`)===r&&j(!0)};return typeof e.decode==`function`?e.decode().then(void 0,i):queueMicrotask(i),()=>{t=!1}},[]);let ye=ee.useMergedRefs(w,M),N=de!==void 0||E!==void 0,P=T!==void 0&&T!==`presentation`&&T!==`none`,F=f(p),I=S||N||P?``:F??``,L=()=>j(!0),R=k?.alt,z=R!=null,B=z?R:I,V={"aria-describedby":fe,"aria-description":pe,"aria-details":me},H=!S&&!N&&!P&&typeof B==`string`&&B.trim()!==``,U=H?V:{},W=null;if(!ge){if(typeof O==`string`)W=(0,u.jsx)(`img`,{src:O,alt:I,...U,className:t.cn(i.avatarClassNames.image,d),onError:L});else if(O!==void 0){let e={onError:r.composeEventHandlers(k?.onError,L)};if(z||(e.alt=I),H){let t=k?.[`aria-describedby`];e[`aria-describedby`]=te.joinIds(fe,typeof t==`string`?t:void 0)}let a=l.isValidElement(O)?l.cloneElement(O,e):k?{...O,...e}:O;W=n.renderSlot(a,`img`,t.cn(i.avatarClassNames.image,d),{alt:I,...U})}else e&&(W=(0,u.jsx)(`img`,{src:e,alt:I,...U,className:t.cn(i.avatarClassNames.image,d),onError:L}))}let G=W!==null&&H?{}:V,K=W===null&&y&&n.slotRendersContent(y)?n.renderSlot(y,`span`,t.cn(i.avatarClassNames.icon,`inline-flex`),{"aria-hidden":!0}):null,be=ne.useDirection(),q=l.useContext(ie.AvatarGroupContext),xe=t.cn(i.avatarClassNames.initials,q?.layout===`pie`&&`invisible`),J=s.resolveAvatarColor(le,ue,p),Se=W===null&&K===null,Ce=Se&&p?a.getInitials(p,{dir:be}):``,we=Se?v&&n.slotRendersContent(v)?n.renderSlot(v,`span`,xe,{"aria-hidden":!0}):Ce?(0,u.jsx)(`span`,{"aria-hidden":`true`,className:xe,children:Ce}):null:null,Y,X;W===null?K===null?we?(Y=we,X=s.avatarColorClasses[J]):(Y=(0,u.jsx)(re.PersonIcon,{size:`60%`,className:i.avatarClassNames.icon}),X=`bg-muted text-muted-foreground`):(Y=K,X=`bg-muted text-muted-foreground`):Y=W;let Te=W!==null&&P&&typeof B==`string`?f(B):void 0,Ee=typeof R==`string`?f(R):void 0,De=de??(W===null?F??Ee:P?Te??F:void 0),Z;Z=S?{"aria-hidden":!0,...G}:De!==void 0||E!==void 0?{role:T??`img`,"aria-label":De,"aria-labelledby":E,...G}:W!==null||T!==void 0?{role:T,...G}:{"aria-hidden":!0,...G};let Oe=x&&n.slotRendersContent(x)?n.renderSlot(x,`span`,t.cn(i.avatarClassNames.badge,`absolute bottom-0 end-0 inline-flex`)):null,ke=Oe!==null,Q=m??q?.size??(D?D.size:`medium`),Ae=h??D?.shape??`circular`,je=c.avatarPixelSize(Q),Me={"data-size":String(Q),"data-shape":Ae,"data-color":J,"data-active":g,"data-active-appearance":_},$=t.cn(i.avatarClassNames.visual,`inline-flex items-center justify-center overflow-hidden shrink-0 font-bold`,c.avatarShapeClasses(Ae,je),c.avatarSizeClassesFor(Q),X,g===`active`&&ae[_],g===`inactive`&&`opacity-60 transition-opacity motion-reduce:transition-none`);return ke?(0,u.jsxs)(`span`,{ref:w,...Me,...he,className:t.cn(i.avatarClassNames.root,`relative inline-flex shrink-0`,C),children:[(0,u.jsx)(`span`,{ref:M,...Z,className:$,children:Y}),(0,u.jsx)(o.AvatarBadgeSizeContext.Provider,{value:c.avatarBadgeSize(je),children:Oe})]}):(0,u.jsx)(`span`,{ref:ye,...Z,...Me,...he,className:t.cn(i.avatarClassNames.root,$,C),children:Y})};h.displayName=`Avatar`,exports.Avatar=h;
2
2
  //# sourceMappingURL=Avatar.cjs.map