@flikk/ui 1.0.0-beta.30 → 1.0.0-beta.31

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 (295) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/components/ai/AgentStatus/AgentStatus.d.ts +3 -0
  3. package/dist/components/ai/AgentStatus/AgentStatus.js +144 -0
  4. package/dist/components/ai/AgentStatus/AgentStatus.theme.d.ts +2 -0
  5. package/dist/components/ai/AgentStatus/AgentStatus.theme.js +37 -0
  6. package/dist/components/ai/AgentStatus/AgentStatus.types.d.ts +116 -0
  7. package/dist/components/ai/AgentStatus/index.d.ts +3 -0
  8. package/dist/components/ai/CodeBlock/CodeBlock.js +3 -3
  9. package/dist/components/ai/CodeBlock/CodeBlock.theme.js +1 -1
  10. package/dist/components/ai/PromptInput/PromptInput.js +13 -14
  11. package/dist/components/ai/PromptInput/PromptInput.theme.js +1 -1
  12. package/dist/components/ai/PromptInput/VoiceRecorder.js +3 -3
  13. package/dist/components/ai/Reasoning/Reasoning.d.ts +5 -0
  14. package/dist/components/ai/Reasoning/Reasoning.js +16 -0
  15. package/dist/components/ai/Reasoning/Reasoning.types.d.ts +20 -0
  16. package/dist/components/ai/Reasoning/index.d.ts +2 -0
  17. package/dist/components/ai/SourceCitation/SourceCitation.d.ts +4 -0
  18. package/dist/components/ai/SourceCitation/SourceCitation.js +29 -0
  19. package/dist/components/ai/SourceCitation/SourceCitation.theme.d.ts +2 -0
  20. package/dist/components/ai/SourceCitation/SourceCitation.theme.js +23 -0
  21. package/dist/components/ai/SourceCitation/SourceCitation.types.d.ts +55 -0
  22. package/dist/components/ai/SourceCitation/index.d.ts +3 -0
  23. package/dist/components/ai/StreamingResponse/ErrorDisplay.js +2 -2
  24. package/dist/components/ai/StreamingResponse/StreamingResponse.js +1 -3
  25. package/dist/components/ai/StreamingResponse/StreamingResponse.theme.js +3 -1
  26. package/dist/components/ai/TokenCounter/TokenCounter.js +2 -2
  27. package/dist/components/ai/index.d.ts +3 -0
  28. package/dist/components/ai/index.js +6 -3
  29. package/dist/components/ai/shared/StatusIndicator.d.ts +8 -0
  30. package/dist/components/ai/shared/StatusIndicator.js +34 -0
  31. package/dist/components/canvas/CanvasToolbar.js +2 -2
  32. package/dist/components/canvas/NodeControls.js +2 -2
  33. package/dist/components/canvas/NodeRenderer.js +2 -2
  34. package/dist/components/charts/ActivityRings/ActivityRings.js +2 -2
  35. package/dist/components/charts/AreaChart/AreaChart.js +21 -32
  36. package/dist/components/charts/AreaChart/AreaChart.theme.d.ts +1 -6
  37. package/dist/components/charts/AreaChart/AreaChart.theme.js +7 -19
  38. package/dist/components/charts/AreaChart/AreaChart.types.d.ts +18 -11
  39. package/dist/components/charts/AreaChart/AreaChart.types.js +10 -3
  40. package/dist/components/charts/AreaChart/index.d.ts +1 -1
  41. package/dist/components/charts/BarChart/BarChart.js +9 -28
  42. package/dist/components/charts/BarChart/BarChart.types.d.ts +20 -16
  43. package/dist/components/charts/BarChart/BarChart.types.js +11 -4
  44. package/dist/components/charts/ComboChart/BarRenderer.js +8 -5
  45. package/dist/components/charts/ComboChart/ComboChart.js +11 -24
  46. package/dist/components/charts/ComboChart/ComboChart.types.d.ts +15 -13
  47. package/dist/components/charts/ComboChart/ComboChart.types.js +14 -2
  48. package/dist/components/charts/ComboChart/LineRenderer.js +15 -10
  49. package/dist/components/charts/HorizontalBarChart/HorizontalBarChart.d.ts +16 -0
  50. package/dist/components/charts/HorizontalBarChart/HorizontalBarChart.js +237 -0
  51. package/dist/components/charts/HorizontalBarChart/HorizontalBarChart.types.d.ts +62 -0
  52. package/dist/components/charts/HorizontalBarChart/HorizontalBarChart.types.js +21 -0
  53. package/dist/components/charts/HorizontalBarChart/index.d.ts +3 -0
  54. package/dist/components/charts/LineChart/LineChart.js +9 -26
  55. package/dist/components/charts/LineChart/LineChart.types.d.ts +11 -14
  56. package/dist/components/charts/LineChart/LineChart.types.js +11 -3
  57. package/dist/components/charts/LollipopChart/LollipopChart.d.ts +3 -0
  58. package/dist/components/charts/LollipopChart/LollipopChart.js +361 -0
  59. package/dist/components/charts/LollipopChart/LollipopChart.types.d.ts +42 -0
  60. package/dist/components/charts/LollipopChart/LollipopChart.types.js +12 -0
  61. package/dist/components/charts/LollipopChart/index.d.ts +3 -0
  62. package/dist/components/charts/ScatterPlot/ScatterPlot.js +5 -4
  63. package/dist/components/charts/ScatterPlot/ScatterPlot.types.d.ts +14 -19
  64. package/dist/components/charts/ScatterPlot/ScatterPlot.types.js +9 -2
  65. package/dist/components/charts/StackedBarChart/StackedBarChart.js +150 -132
  66. package/dist/components/charts/StackedBarChart/StackedBarChart.types.d.ts +20 -18
  67. package/dist/components/charts/StackedBarChart/StackedBarChart.types.js +10 -4
  68. package/dist/components/charts/hooks/useChartAccessibility.d.ts +1 -1
  69. package/dist/components/charts/hooks/useChartAccessibility.js +3 -0
  70. package/dist/components/charts/hooks/useTooltipPosition.js +18 -6
  71. package/dist/components/charts/index.d.ts +6 -0
  72. package/dist/components/charts/index.js +6 -0
  73. package/dist/components/charts/shared/ChartAxis/CategoryYAxis.d.ts +14 -0
  74. package/dist/components/charts/shared/ChartAxis/CategoryYAxis.js +35 -0
  75. package/dist/components/charts/shared/ChartAxis/ChartAxis.types.d.ts +69 -8
  76. package/dist/components/charts/shared/ChartAxis/ValueXAxis.d.ts +14 -0
  77. package/dist/components/charts/shared/ChartAxis/ValueXAxis.js +64 -0
  78. package/dist/components/charts/shared/ChartAxis/XAxis.js +1 -1
  79. package/dist/components/charts/shared/ChartAxis/YAxis.js +2 -2
  80. package/dist/components/charts/shared/ChartAxis/index.d.ts +3 -1
  81. package/dist/components/charts/shared/ChartGrid/HorizontalGrid.d.ts +0 -2
  82. package/dist/components/charts/shared/ChartGrid/HorizontalGrid.js +1 -1
  83. package/dist/components/charts/shared/ChartGrid/VerticalGrid.d.ts +29 -0
  84. package/dist/components/charts/shared/ChartGrid/VerticalGrid.js +26 -0
  85. package/dist/components/charts/shared/ChartGrid/index.d.ts +2 -0
  86. package/dist/components/charts/shared/ChartMarker/ChartMarker.js +7 -1
  87. package/dist/components/charts/theme/chart.theme.js +18 -23
  88. package/dist/components/charts/types/chart.types.d.ts +9 -5
  89. package/dist/components/charts/types/chart.types.js +1 -7
  90. package/dist/components/charts/utils/animation-utils.js +1 -3
  91. package/dist/components/charts/utils/bar-emphasis.d.ts +32 -3
  92. package/dist/components/charts/utils/bar-emphasis.js +24 -8
  93. package/dist/components/charts/utils/index.d.ts +1 -0
  94. package/dist/components/charts/utils/series-color.d.ts +7 -0
  95. package/dist/components/charts/utils/series-color.js +20 -0
  96. package/dist/components/core/Accordion/Accordion.theme.js +2 -2
  97. package/dist/components/core/Accordion/AccordionTrigger.js +2 -2
  98. package/dist/components/core/Alert/Alert.animations.d.ts +2 -1
  99. package/dist/components/core/Alert/Alert.animations.js +21 -6
  100. package/dist/components/core/Alert/Alert.js +7 -7
  101. package/dist/components/core/Avatar/Avatar.js +50 -42
  102. package/dist/components/core/Avatar/Avatar.theme.d.ts +8 -4
  103. package/dist/components/core/Avatar/Avatar.theme.js +64 -8
  104. package/dist/components/core/Avatar/Avatar.types.d.ts +13 -2
  105. package/dist/components/core/Avatar/index.d.ts +1 -1
  106. package/dist/components/core/AvatarGroup/AvatarGroup.js +6 -8
  107. package/dist/components/core/AvatarGroup/AvatarGroup.theme.d.ts +1 -2
  108. package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +2 -6
  109. package/dist/components/core/AvatarGroup/AvatarGroup.types.d.ts +0 -6
  110. package/dist/components/core/AvatarGroup/index.d.ts +1 -1
  111. package/dist/components/core/Badge/Badge.animations.js +4 -2
  112. package/dist/components/core/Badge/Badge.js +9 -4
  113. package/dist/components/core/Badge/Badge.theme.js +18 -12
  114. package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.d.ts +1 -4
  115. package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +2 -2
  116. package/dist/components/core/Button/Button.js +9 -17
  117. package/dist/components/core/Button/Button.ripple.js +2 -2
  118. package/dist/components/core/Button/Button.theme.d.ts +2 -0
  119. package/dist/components/core/Button/Button.theme.js +34 -21
  120. package/dist/components/core/Button/Button.types.d.ts +18 -1
  121. package/dist/components/core/Calendar/Calendar.js +20 -5
  122. package/dist/components/core/Calendar/Calendar.theme.js +14 -22
  123. package/dist/components/core/Calendar/Calendar.types.d.ts +0 -1
  124. package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +3 -3
  125. package/dist/components/core/Card/Card.theme.js +12 -4
  126. package/dist/components/core/Card/CardBody.js +1 -1
  127. package/dist/components/core/Card/CardFooter.js +1 -1
  128. package/dist/components/core/Card/CardHeader.js +1 -1
  129. package/dist/components/core/Carousel/CarouselNext.js +2 -2
  130. package/dist/components/core/Carousel/CarouselPrevious.js +2 -2
  131. package/dist/components/core/CommandPalette/CommandPalette.js +5 -4
  132. package/dist/components/core/CommandPalette/CommandPalette.theme.js +3 -7
  133. package/dist/components/core/CommandPalette/CommandPalette.types.d.ts +2 -0
  134. package/dist/components/core/ContextMenu/ContextMenuItem.js +2 -2
  135. package/dist/components/core/ContextMenu/ContextMenuSubTrigger.js +2 -2
  136. package/dist/components/core/Drawer/Drawer.theme.js +7 -4
  137. package/dist/components/core/Drawer/DrawerHeader.js +2 -2
  138. package/dist/components/core/Dropdown/Dropdown.theme.js +3 -1
  139. package/dist/components/core/Dropdown/DropdownItem.js +2 -2
  140. package/dist/components/core/Dropdown/DropdownTrigger.js +16 -5
  141. package/dist/components/core/HeroCard/HeroCard.theme.js +5 -2
  142. package/dist/components/core/Kbd/Kbd.theme.js +4 -2
  143. package/dist/components/core/Link/Link.js +6 -4
  144. package/dist/components/core/Message/Message.js +2 -2
  145. package/dist/components/core/Message/Message.theme.js +5 -7
  146. package/dist/components/core/Message/MessageAudio.js +2 -2
  147. package/dist/components/core/Message/MessageFile.js +2 -2
  148. package/dist/components/core/Message/MessageLink.js +2 -2
  149. package/dist/components/core/Message/MessageStatusIndicator.js +5 -5
  150. package/dist/components/core/Modal/Modal.d.ts +1 -1
  151. package/dist/components/core/Modal/Modal.js +2 -2
  152. package/dist/components/core/Modal/Modal.theme.js +9 -4
  153. package/dist/components/core/Modal/ModalHeader.js +2 -2
  154. package/dist/components/core/ModalStack/ModalStackModal.js +2 -2
  155. package/dist/components/core/NavItem/NavItem.js +6 -6
  156. package/dist/components/core/OfflineIndicator/OfflineIndicator.animations.d.ts +22 -0
  157. package/dist/components/core/OfflineIndicator/OfflineIndicator.animations.js +54 -0
  158. package/dist/components/core/OfflineIndicator/OfflineIndicator.js +23 -24
  159. package/dist/components/core/OfflineIndicator/OfflineIndicator.theme.js +25 -6
  160. package/dist/components/core/OfflineIndicator/OfflineIndicator.types.d.ts +17 -0
  161. package/dist/components/core/PageHeading/PageHeading.theme.js +1 -1
  162. package/dist/components/core/PageHeading/PageHeadingBackButton.js +2 -2
  163. package/dist/components/core/Pagination/Pagination.js +3 -3
  164. package/dist/components/core/Pagination/Pagination.theme.js +3 -3
  165. package/dist/components/core/Pill/Pill.js +4 -2
  166. package/dist/components/core/Pill/Pill.theme.js +6 -4
  167. package/dist/components/core/Rating/Rating.js +4 -5
  168. package/dist/components/core/Rating/Rating.theme.js +1 -1
  169. package/dist/components/core/Segmented/Segmented.theme.js +9 -6
  170. package/dist/components/core/Sidebar/Sidebar.types.d.ts +4 -2
  171. package/dist/components/core/Sidebar/SidebarHeader.js +2 -2
  172. package/dist/components/core/Sidebar/SidebarMobileTrigger.js +2 -2
  173. package/dist/components/core/Sidebar/SidebarSearch.js +3 -3
  174. package/dist/components/core/Sidebar/SidebarToggle.js +3 -3
  175. package/dist/components/core/Sidebar/SidebarUserProfile.js +2 -2
  176. package/dist/components/core/Sortable/Sortable.js +2 -2
  177. package/dist/components/core/Tag/Tag.js +2 -2
  178. package/dist/components/core/Tag/Tag.theme.js +4 -2
  179. package/dist/components/core/Toast/Toast.js +3 -3
  180. package/dist/components/core/Toast/Toast.types.d.ts +1 -1
  181. package/dist/components/core/Toast/useToast.js +5 -5
  182. package/dist/components/core/Tooltip/Tooltip.d.ts +1 -1
  183. package/dist/components/core/Tooltip/Tooltip.js +42 -10
  184. package/dist/components/core/Tooltip/Tooltip.types.d.ts +25 -0
  185. package/dist/components/core/Tree/Tree.js +2 -2
  186. package/dist/components/core/shared/interaction.animations.d.ts +51 -0
  187. package/dist/components/core/shared/interaction.animations.js +59 -0
  188. package/dist/components/data-display/Feed/Feed.js +2 -2
  189. package/dist/components/data-display/GanttChart/GanttChart.theme.js +1 -1
  190. package/dist/components/data-display/GanttChart/GanttChartPanel.js +2 -2
  191. package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +3 -3
  192. package/dist/components/data-display/GanttChart/GanttTaskContextMenu.js +2 -2
  193. package/dist/components/data-display/GanttChart/GanttToolbar.js +2 -2
  194. package/dist/components/data-display/KPI/KPI.js +2 -2
  195. package/dist/components/data-display/KPI/KPI.theme.js +4 -4
  196. package/dist/components/data-display/Metric/Metric.js +2 -2
  197. package/dist/components/data-display/Metric/Metric.theme.js +25 -8
  198. package/dist/components/data-display/Metric/Metric.types.d.ts +1 -1
  199. package/dist/components/data-display/Table/Table.theme.js +9 -9
  200. package/dist/components/data-display/Table/TableActions.js +2 -2
  201. package/dist/components/data-display/Table/TableActionsMenu.js +1 -1
  202. package/dist/components/data-display/Table/TableColumnManager.js +2 -2
  203. package/dist/components/data-display/Table/TableDeclarative.js +3 -3
  204. package/dist/components/data-display/Table/TableFilter.js +4 -4
  205. package/dist/components/data-display/Table/TableHeader.js +3 -3
  206. package/dist/components/data-display/Table/TableRow.js +2 -2
  207. package/dist/components/data-display/Table/TableSelectionHeader.js +3 -3
  208. package/dist/components/data-display/Timeline/TimelineMarker.js +2 -2
  209. package/dist/components/effects/CustomCursor/CustomCursor.js +2 -2
  210. package/dist/components/effects/CustomCursor/CustomCursor.theme.js +2 -2
  211. package/dist/components/effects/DotPattern/DotPattern.js +6 -0
  212. package/dist/components/effects/DotPattern/DotPattern.types.d.ts +4 -2
  213. package/dist/components/effects/MeshGradient/MeshGradient.utils.d.ts +1 -1
  214. package/dist/components/effects/MeshGradient/MeshGradient.utils.js +1 -1
  215. package/dist/components/forms/Checkbox/Checkbox.js +2 -1
  216. package/dist/components/forms/Checkbox/Checkbox.theme.js +2 -2
  217. package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +2 -2
  218. package/dist/components/forms/ColorPicker/ColorPickerGradient.js +2 -2
  219. package/dist/components/forms/ColorPicker/ColorPickerHeader.js +2 -2
  220. package/dist/components/forms/ColorPicker/ColorPickerImage.js +3 -3
  221. package/dist/components/forms/ColorPicker/ColorPickerInput.js +2 -2
  222. package/dist/components/forms/ColorPicker/ColorPickerPresets.js +2 -2
  223. package/dist/components/forms/ColorPicker/ColorPickerSavedColors.js +2 -2
  224. package/dist/components/forms/Combobox/Combobox.js +3 -3
  225. package/dist/components/forms/Combobox/Combobox.theme.js +2 -2
  226. package/dist/components/forms/DatePicker/DatePicker.animations.js +16 -25
  227. package/dist/components/forms/DatePicker/DatePicker.theme.js +2 -2
  228. package/dist/components/forms/DatePicker/DatePickerBody.js +1 -1
  229. package/dist/components/forms/DatePicker/DatePickerTrigger.js +2 -2
  230. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +3 -3
  231. package/dist/components/forms/DateRangePicker/DateRangePickerBody.js +1 -1
  232. package/dist/components/forms/DateRangePicker/DateRangePickerPresets.js +2 -2
  233. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +2 -2
  234. package/dist/components/forms/FileUpload/FileUpload.js +4 -4
  235. package/dist/components/forms/FileUpload/FileUpload.theme.js +5 -1
  236. package/dist/components/forms/FileUpload/FileUploadProgress.js +7 -7
  237. package/dist/components/forms/Input/Input.js +6 -7
  238. package/dist/components/forms/Input/Input.theme.js +19 -15
  239. package/dist/components/forms/InputAddress/InputAddress.js +10 -3
  240. package/dist/components/forms/InputCounter/InputCounter.js +3 -3
  241. package/dist/components/forms/InputOTP/InputOTP.d.ts +3 -12
  242. package/dist/components/forms/InputOTP/InputOTP.js +140 -151
  243. package/dist/components/forms/InputOTP/InputOTP.theme.d.ts +5 -1
  244. package/dist/components/forms/InputOTP/InputOTP.theme.js +40 -5
  245. package/dist/components/forms/InputOTP/InputOTP.types.d.ts +45 -2
  246. package/dist/components/forms/InputOTP/index.d.ts +1 -1
  247. package/dist/components/forms/InputTag/InputTag.js +5 -5
  248. package/dist/components/forms/InputTag/InputTag.theme.js +1 -2
  249. package/dist/components/forms/Mention/Mention.theme.js +3 -5
  250. package/dist/components/forms/Radio/Radio.js +3 -2
  251. package/dist/components/forms/Radio/Radio.theme.js +2 -2
  252. package/dist/components/forms/RichTextEditor/RichTextEditor.js +22 -23
  253. package/dist/components/forms/Select/Select.d.ts +5 -1
  254. package/dist/components/forms/Select/Select.js +12 -11
  255. package/dist/components/forms/Select/Select.theme.js +4 -4
  256. package/dist/components/forms/Select/Select.types.d.ts +4 -1
  257. package/dist/components/forms/SelectableCard/SelectableCard.animations.d.ts +1 -2
  258. package/dist/components/forms/SelectableCard/SelectableCard.animations.js +6 -7
  259. package/dist/components/forms/SelectableCard/SelectableCard.js +1 -1
  260. package/dist/components/forms/Signature/Signature.js +1 -1
  261. package/dist/components/forms/Slider/Slider.js +24 -11
  262. package/dist/components/forms/Slider/Slider.theme.js +9 -3
  263. package/dist/components/forms/Switch/Switch.theme.js +1 -1
  264. package/dist/components/forms/TimePicker/TimePicker.theme.js +6 -7
  265. package/dist/components/forms/TimePicker/TimePickerContent.js +1 -1
  266. package/dist/components/forms/TimePicker/TimePickerTrigger.js +3 -3
  267. package/dist/components/forms/forms.theme.js +23 -12
  268. package/dist/components/forms/index.js +1 -1
  269. package/dist/components/generative/registry.js +195 -2
  270. package/dist/components/generative/resolvers.js +16 -16
  271. package/dist/components/generative/schema.generated.js +2687 -379
  272. package/dist/components/layout/Section/Section.theme.js +1 -1
  273. package/dist/generative.schema.json +2687 -379
  274. package/dist/hooks/index.d.ts +2 -0
  275. package/dist/hooks/useElapsedTime.d.ts +28 -0
  276. package/dist/hooks/useElapsedTime.js +37 -0
  277. package/dist/hooks/useSelectPortal.d.ts +10 -2
  278. package/dist/hooks/useSelectPortal.js +6 -3
  279. package/dist/index.js +1 -1
  280. package/dist/registry.json +835 -261
  281. package/dist/shadcn-compat.css +1 -1
  282. package/dist/styles.css +1 -1
  283. package/dist/theme.css +5 -1
  284. package/dist/themes/ember.css +131 -0
  285. package/dist/themes/iris.css +94 -0
  286. package/dist/themes/jade.css +139 -0
  287. package/dist/tools.json +2705 -361
  288. package/dist/utils/colorUtils.d.ts +6 -6
  289. package/dist/utils/colorUtils.js +8 -8
  290. package/package.json +9 -6
  291. package/src/global.scss +15 -4
  292. package/src/styles/theme.css +440 -152
  293. package/tailwind.preset.cjs +52 -34
  294. package/dist/components/core/Pill/Pill.animations.d.ts +0 -32
  295. package/dist/components/core/Pill/Pill.animations.js +0 -16
@@ -4,9 +4,9 @@ const accordionTheme = {
4
4
  // Base container styles for stacked variant (unified card)
5
5
  baseStyleStacked: "w-full border border-[var(--color-border)] rounded-[var(--form-radius)] overflow-hidden",
6
6
  // Item styles for separated variant (individual cards with spacing)
7
- itemStyle: "border border-[var(--color-border)] rounded-[var(--form-radius)] bg-white dark:bg-[var(--color-background-secondary)] overflow-hidden mb-2 last-of-type:mb-0",
7
+ itemStyle: "border border-[var(--color-border)] rounded-[var(--form-radius)] bg-[var(--color-surface)] overflow-hidden mb-2 last-of-type:mb-0",
8
8
  // Item styles for stacked variant (shared borders, no spacing)
9
- itemStyleStacked: "bg-white border-t border-[var(--color-border)] first-of-type:border-t-0",
9
+ itemStyleStacked: "bg-[var(--color-surface)] border-t border-[var(--color-border)] first-of-type:border-t-0",
10
10
  // Trigger styles (shared across variants)
11
11
  triggerStyle: "flex w-full gap-3 items-center px-4 py-2.5 text-left font-medium transition-all duration-200 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 text-[var(--color-text-primary)] text-sm",
12
12
  // Body styles (shared across variants)
@@ -5,7 +5,7 @@ import { cn } from '../../../utils/cn.js';
5
5
  import { useAccordionContext } from './AccordionContext.js';
6
6
  import { useAccordionItemContext } from './AccordionItem.js';
7
7
  import { motion } from 'motion/react';
8
- import { PlusIcon } from '@heroicons/react/24/outline';
8
+ import { Plus } from '@phosphor-icons/react';
9
9
  import { createTriggerIconVariants } from './Accordion.animations.js';
10
10
 
11
11
  const AccordionTrigger = React__default.forwardRef(({ children, className, chevron, chevronRotation, iconRotation, chevronPosition = "right", ...props }, ref) => {
@@ -14,7 +14,7 @@ const AccordionTrigger = React__default.forwardRef(({ children, className, chevr
14
14
  const { isOpen, disabled, toggle, triggerId, contentId } = useAccordionItemContext();
15
15
  const resolvedChevronRotation = (_a = chevronRotation !== null && chevronRotation !== void 0 ? chevronRotation : iconRotation) !== null && _a !== void 0 ? _a : 45;
16
16
  // Resolve the indicator icon
17
- const defaultChevronIcon = jsx(PlusIcon, { className: "size-4", strokeWidth: 2 });
17
+ const defaultChevronIcon = jsx(Plus, { className: "size-4", weight: "bold" });
18
18
  const resolvedChevron = chevron === null
19
19
  ? null
20
20
  : chevron !== undefined
@@ -1,8 +1,9 @@
1
1
  import { Variants } from "motion/react";
2
2
  /**
3
3
  * Alert entrance/exit animation variants
4
- * Entrance: slide down from -8px + fade in
4
+ * Entrance: slide down from -12px + fade in
5
5
  * Exit: fade out + collapse height
6
+ * Uses library spring presets for a premium feel
6
7
  */
7
8
  export declare const alertVariants: Variants;
8
9
  /**
@@ -1,13 +1,18 @@
1
1
  "use client";
2
+ import '../../../theme/ThemeContext.js';
3
+ import '../../../theme/SurfaceContext.js';
4
+ import { springs } from '../../../theme/animations.js';
5
+
2
6
  /**
3
7
  * Alert entrance/exit animation variants
4
- * Entrance: slide down from -8px + fade in
8
+ * Entrance: slide down from -12px + fade in
5
9
  * Exit: fade out + collapse height
10
+ * Uses library spring presets for a premium feel
6
11
  */
7
12
  const alertVariants = {
8
13
  hidden: {
9
14
  opacity: 0,
10
- y: -8,
15
+ y: -12,
11
16
  height: 0,
12
17
  paddingTop: 0,
13
18
  paddingBottom: 0,
@@ -15,8 +20,13 @@ const alertVariants = {
15
20
  marginBottom: 0,
16
21
  overflow: "hidden",
17
22
  transition: {
18
- duration: 0.15,
19
- ease: [0.4, 0, 1, 1],
23
+ height: springs.smooth,
24
+ paddingTop: springs.smooth,
25
+ paddingBottom: springs.smooth,
26
+ marginTop: springs.smooth,
27
+ marginBottom: springs.smooth,
28
+ y: springs.premium,
29
+ opacity: { duration: 0.15 },
20
30
  },
21
31
  },
22
32
  visible: {
@@ -29,8 +39,13 @@ const alertVariants = {
29
39
  marginBottom: undefined,
30
40
  overflow: "visible",
31
41
  transition: {
32
- duration: 0.2,
33
- ease: [0.4, 0, 0.2, 1],
42
+ y: springs.premium,
43
+ height: springs.smooth,
44
+ paddingTop: springs.smooth,
45
+ paddingBottom: springs.smooth,
46
+ marginTop: springs.smooth,
47
+ marginBottom: springs.smooth,
48
+ opacity: { duration: 0.25 },
34
49
  },
35
50
  },
36
51
  };
@@ -5,15 +5,15 @@ import { useReducedMotion, motion } from 'motion/react';
5
5
  import { cn } from '../../../utils/cn.js';
6
6
  import { alertTheme } from './Alert.theme.js';
7
7
  import { reducedMotionAlertVariants, alertVariants } from './Alert.animations.js';
8
- import { XMarkIcon, XCircleIcon, ExclamationTriangleIcon, CheckCircleIcon, InformationCircleIcon, BellIcon } from '@heroicons/react/24/solid';
8
+ import { X, XCircle, Warning, CheckCircle, Info, Bell } from '@phosphor-icons/react';
9
9
  import { Button } from '../Button/Button.js';
10
10
 
11
11
  const defaultIcons = {
12
- neutral: BellIcon,
13
- primary: InformationCircleIcon,
14
- success: CheckCircleIcon,
15
- warning: ExclamationTriangleIcon,
16
- danger: XCircleIcon,
12
+ mono: Bell,
13
+ primary: Info,
14
+ success: CheckCircle,
15
+ warning: Warning,
16
+ danger: XCircle,
17
17
  };
18
18
  const Alert = React__default.forwardRef(({ color = "primary", title, subtitle, dismissible, icon, showIcon = true, avatar, actions, onDismiss, className, children, darkMode = false, ...props }, ref) => {
19
19
  var _a;
@@ -46,7 +46,7 @@ const Alert = React__default.forwardRef(({ color = "primary", title, subtitle, d
46
46
  ? jsx("div", { className: cn("font-semibold text-[var(--color-text-primary)]"), children: title })
47
47
  : title), subtitle && (typeof subtitle === 'string'
48
48
  ? jsx("div", { className: "text-[var(--color-text-secondary)]/90 mt-1", children: subtitle })
49
- : subtitle), children && jsx("div", { className: "mt-2", children: children }), actions && (jsx("div", { className: "flex items-center gap-2 mt-6", children: actions }))] }), showDismiss && (jsx(Button, { variant: "ghost", color: "neutral", size: "sm", iconOnly: true, onClick: handleDismiss, "aria-label": "Dismiss alert", className: "rounded-full absolute top-2 right-2 flex-shrink-0", children: jsx(XMarkIcon, { className: "size-4", strokeWidth: 2 }) }))] }));
49
+ : subtitle), children && jsx("div", { className: "mt-2", children: children }), actions && (jsx("div", { className: "flex items-center gap-2 mt-6", children: actions }))] }), showDismiss && (jsx(Button, { variant: "ghost", color: "mono", size: "sm", iconOnly: true, onClick: handleDismiss, "aria-label": "Dismiss alert", className: "rounded-full absolute top-2 right-2 flex-shrink-0", children: jsx(X, { className: "size-4", weight: "bold" }) }))] }));
50
50
  const alertNode = (jsx(motion.div, { variants: shouldReduceMotion ? reducedMotionAlertVariants : alertVariants, initial: "hidden", animate: isDismissing ? "hidden" : "visible", onAnimationComplete: (definition) => {
51
51
  if (definition === "hidden" && isDismissing) {
52
52
  onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss();
@@ -7,25 +7,64 @@ import { Tooltip } from '../Tooltip/Tooltip.js';
7
7
  import '../Tooltip/Tooltip.animations.js';
8
8
  import { MeshGradient } from '../../effects/MeshGradient/MeshGradient.js';
9
9
  import { MESH_PALETTE_BY_NAME, DEFAULT_MESH_COLORS, getMeshTextTone } from '../../effects/MeshGradient/MeshGradient.utils.js';
10
- import { CheckBadgeIcon, UserIcon } from '@heroicons/react/24/solid';
10
+ import { SealCheck, User } from '@phosphor-icons/react';
11
11
 
12
12
  // Number of marble shapes the gradient renders — shared by the render and the
13
13
  // text-tone calc so both read the same deterministic field. The gradient's blur
14
14
  // is resolution-independent (SVG viewBox units), so no per-size tuning is needed.
15
15
  const MESH_COUNT = 2;
16
+ // Each token's geometry, as the CSS variable that carries its px value. Keeping
17
+ // the indirection means a themed `--avatar-size-*` still flows through.
18
+ const SIZE_TOKEN_VAR = {
19
+ xs: "var(--avatar-size-xs)",
20
+ sm: "var(--avatar-size-sm)",
21
+ md: "var(--avatar-size-md)",
22
+ lg: "var(--avatar-size-lg)",
23
+ xl: "var(--avatar-size-xl)",
24
+ };
25
+ // The default px ladder from `theme.css`, mirrored here for ONE purpose: picking
26
+ // which rung a numeric size's decorations (glyph, status dot, verified badge,
27
+ // text gap) should borrow. Geometry never reads this — it always resolves
28
+ // through the CSS variable above — so a theme that retunes the ladder still
29
+ // sizes correctly; only the rung chosen for a numeric size reads the defaults.
30
+ const SIZE_TOKEN_PX = {
31
+ xs: 24,
32
+ sm: 32,
33
+ md: 40,
34
+ lg: 48,
35
+ xl: 64,
36
+ };
37
+ const isSizeToken = (size) => typeof size === "string";
38
+ /** The rung a size sits closest to. Identity for tokens. */
39
+ const nearestSizeToken = (size) => {
40
+ if (isSizeToken(size))
41
+ return size;
42
+ return Object.keys(SIZE_TOKEN_PX).reduce((best, token) => Math.abs(SIZE_TOKEN_PX[token] - size) < Math.abs(SIZE_TOKEN_PX[best] - size)
43
+ ? token
44
+ : best);
45
+ };
16
46
  const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "none", fallback, gradient = false, gradientVariant = "marble", gradientColors, className, role, lazyLoad = true, retryCount = 0, retryDelay = 1000, contextualLabel, groupPosition, showTooltip = false, initialsCount = 2, title, subtitle, verified = false, ...props }, ref) => {
17
47
  var _a;
18
48
  const [imageError, setImageError] = useState(false);
19
49
  const [retries, setRetries] = useState(0);
20
50
  const retryTimerRef = useRef(null);
51
+ if (process.env.NODE_ENV !== "production" &&
52
+ typeof size === "number" &&
53
+ (!Number.isFinite(size) || size <= 0)) {
54
+ // eslint-disable-next-line no-console
55
+ console.warn(`[Avatar]: \`size\` must be a positive number of pixels; received ${size}.`);
56
+ }
57
+ // Exact geometry for the circle; nearest rung for everything hung off it.
58
+ const sizeValue = isSizeToken(size) ? SIZE_TOKEN_VAR[size] : `${size}px`;
59
+ const sizeToken = nearestSizeToken(size);
21
60
  // Normalize null to undefined for internal use
22
61
  const resolvedName = name !== null && name !== void 0 ? name : undefined;
23
- // Initials derived from the name (xs shows a single initial).
62
+ // Initials derived from the name (the xs rung shows a single initial).
24
63
  const initials = resolvedName
25
64
  ? resolvedName
26
65
  .split(" ")
27
66
  .map((part) => part[0])
28
- .slice(0, size === "xs" ? 1 : initialsCount)
67
+ .slice(0, sizeToken === "xs" ? 1 : initialsCount)
29
68
  .join("")
30
69
  .toUpperCase()
31
70
  : "";
@@ -40,8 +79,8 @@ const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "no
40
79
  // theme-stable neutral tokens (so the choice holds in light AND dark mode).
41
80
  const gradientTextColor = gradient
42
81
  ? getMeshTextTone(gradientSeed, gradientPalette, MESH_COUNT) === "dark"
43
- ? "text-[var(--color-neutral-950)]"
44
- : "text-[var(--color-neutral-50)]"
82
+ ? "text-[var(--color-mono-950)]"
83
+ : "text-[var(--color-mono-50)]"
45
84
  : undefined;
46
85
  // Glyph shown over the gradient: explicit fallback, else initials, else none
47
86
  // (a clean gradient — no default user icon when there's no name).
@@ -88,41 +127,7 @@ const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "no
88
127
  return jsx("span", { "aria-hidden": "true", children: initials });
89
128
  }
90
129
  // 3. Default placeholder icon
91
- return jsx(UserIcon, { className: "w-1/2 h-1/2" });
92
- };
93
- // Determine status indicator size based on avatar size
94
- const getStatusSize = () => {
95
- switch (size) {
96
- case "xs":
97
- return "size-1.5 left-0 bottom-0.5";
98
- case "sm":
99
- return "size-2 left-0 bottom-0";
100
- case "md":
101
- return "size-2 left-0 bottom-0";
102
- case "lg":
103
- return "size-2.5 left-0 bottom-0";
104
- case "xl":
105
- return "size-3 left-0 bottom-0";
106
- default:
107
- return "size-2 left-0 bottom-0";
108
- }
109
- };
110
- // Determine verified badge size based on avatar size
111
- const getVerifiedBadgeSize = () => {
112
- switch (size) {
113
- case "xs":
114
- return "size-2.5 -right-0.5 -bottom-0.5";
115
- case "sm":
116
- return "size-3.5 -right-0.5 -bottom-0.5";
117
- case "md":
118
- return "size-4 -right-0.5 -bottom-0.5";
119
- case "lg":
120
- return "size-5 -right-1 -bottom-1";
121
- case "xl":
122
- return "size-6 -right-1.5 -bottom-1.5";
123
- default:
124
- return "size-4 -right-0.5 -bottom-0.5";
125
- }
130
+ return jsx(User, { className: "w-1/2 h-1/2" });
126
131
  };
127
132
  // Create full accessibility label including context if provided
128
133
  const accessibilityLabel = contextualLabel
@@ -133,7 +138,10 @@ const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "no
133
138
  const resolvedTitle = title !== null && title !== void 0 ? title : (subtitle ? resolvedName : undefined);
134
139
  const hasTextSection = !!(resolvedTitle || subtitle);
135
140
  // The avatar circle with status indicator
136
- const avatarCircle = (jsxs("div", { className: cn("relative inline-flex avatar-wrapper shrink-0", groupPosition), children: [jsxs("div", { className: cn(avatarTheme.baseStyle, avatarTheme.sizes[size], className), "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-size": size, children: [gradient && (jsx(MeshGradient, { seed: gradientSeed, colors: gradientPalette, count: MESH_COUNT })), src && !imageError ? (jsx("img", { src: src, alt: resolvedName !== null && resolvedName !== void 0 ? resolvedName : "Avatar", className: "relative z-10 size-full object-cover object-top", onError: handleImageError, loading: lazyLoad ? "lazy" : undefined, "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-loaded": "true" })) : (jsx("div", { className: cn("avatar-fallback relative z-10 flex items-center justify-center size-full", gradient && cn(gradientTextColor, "drop-shadow")), children: gradient ? gradientGlyph : getFallbackContent() }))] }), status !== "none" && (jsx("span", { className: cn("absolute rounded-full ring-2 ring-[var(--color-background)]", getStatusSize(), avatarTheme.statuses[status]), "aria-label": `Status: ${status}`, role: "status", "data-status": status })), verified && (jsx("span", { className: cn("absolute rounded-full inline-grid place-items-center ring-2 ring-[var(--color-background)] bg-white dark:bg-[var(--color-surface)] shadow-sm", getVerifiedBadgeSize()), "aria-label": "Verified", children: jsx(CheckBadgeIcon, { className: "size-full text-[var(--color-primary)]" }) }))] }));
141
+ const avatarCircle = (jsxs("div", { className: cn("relative inline-flex avatar-wrapper shrink-0", groupPosition), children: [jsxs("div", { className: cn(avatarTheme.baseStyle, avatarTheme.sizeStyle, avatarTheme.glyphSizes[sizeToken], className), style: { "--avatar-size": sizeValue }, "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-size": size, children: [gradient && (jsx(MeshGradient, { seed: gradientSeed, colors: gradientPalette, count: MESH_COUNT })), src && !imageError ? (jsx("img", { src: src, alt: resolvedName !== null && resolvedName !== void 0 ? resolvedName : "Avatar", className: "relative z-10 size-full object-cover object-top", onError: handleImageError, loading: lazyLoad ? "lazy" : undefined, "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-loaded": "true" })) : (jsx("div", { className: cn("avatar-fallback relative z-10 flex items-center justify-center size-full", gradient && cn(gradientTextColor, "drop-shadow")), children: gradient ? gradientGlyph : getFallbackContent() }))] }), status !== "none" && (jsx("span", { className: cn(
142
+ // Ring WIDTH ramps per size (see `statusSizes`); only its colour
143
+ // is shared here.
144
+ "absolute rounded-full ring-[var(--color-background)]", avatarTheme.statusPositionStyle, avatarTheme.statusSizes[sizeToken], avatarTheme.statuses[status]), "aria-label": `Status: ${status}`, role: "status", "data-status": status })), verified && (jsx("span", { className: cn("absolute rounded-full z-10 inline-grid place-items-center ring-2 ring-[var(--color-background)] bg-white dark:bg-[var(--color-surface)] shadow-sm", avatarTheme.verifiedSizes[sizeToken]), "aria-label": "Verified", children: jsx(SealCheck, { className: "size-full text-[var(--color-primary)]" }) }))] }));
137
145
  // Wrap circle in tooltip if needed
138
146
  const avatarWithTooltip = showTooltip && resolvedName ? (jsx(Tooltip, { content: resolvedName, placement: "top", children: avatarCircle })) : (avatarCircle);
139
147
  // If no text section, render just the avatar
@@ -145,7 +153,7 @@ const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "no
145
153
  className: "inline-flex", role: ariaRole, "aria-label": ariaRole === "presentation" ? undefined : accessibilityLabel, "data-size": size, "data-status": status, "data-error": imageError ? "true" : "false", ...props, children: avatarWithTooltip }));
146
154
  }
147
155
  // Render avatar with text section
148
- return (jsxs("div", { ref: ref, className: cn("inline-flex items-center", avatarTheme.gapSizes[size]), role: ariaRole, "aria-label": ariaRole === "presentation" ? undefined : accessibilityLabel, "data-size": size, "data-status": status, "data-error": imageError ? "true" : "false", ...props, children: [avatarWithTooltip, jsxs("div", { className: "min-w-0", children: [resolvedTitle && (jsx("div", { className: cn(avatarTheme.titleStyle, avatarTheme.textSizes[size]), children: resolvedTitle })), subtitle && (jsx("div", { className: cn(avatarTheme.subtitleStyle, avatarTheme.textSizes[size]), children: subtitle }))] })] }));
156
+ return (jsxs("div", { ref: ref, className: cn("inline-flex items-center", avatarTheme.gapSizes[sizeToken]), role: ariaRole, "aria-label": ariaRole === "presentation" ? undefined : accessibilityLabel, "data-size": size, "data-status": status, "data-error": imageError ? "true" : "false", ...props, children: [avatarWithTooltip, jsxs("div", { className: "min-w-0", children: [resolvedTitle && (jsx("div", { className: cn(avatarTheme.titleStyle, avatarTheme.textSizes[sizeToken]), children: resolvedTitle })), subtitle && (jsx("div", { className: cn(avatarTheme.subtitleStyle, avatarTheme.textSizes[sizeToken]), children: subtitle }))] })] }));
149
157
  });
150
158
  // Set display name for dev tools and Storybook
151
159
  Avatar.displayName = "Avatar";
@@ -1,12 +1,16 @@
1
- import { AvatarSize, AvatarStatus } from "./Avatar.types";
1
+ import { AvatarSizeToken, AvatarStatus } from "./Avatar.types";
2
2
  interface AvatarTheme {
3
3
  baseStyle: string;
4
- sizes: Record<AvatarSize, string>;
4
+ sizeStyle: string;
5
+ glyphSizes: Record<AvatarSizeToken, string>;
5
6
  statuses: Record<AvatarStatus, string>;
7
+ statusPositionStyle: string;
8
+ statusSizes: Record<AvatarSizeToken, string>;
9
+ verifiedSizes: Record<AvatarSizeToken, string>;
6
10
  titleStyle: string;
7
11
  subtitleStyle: string;
8
- textSizes: Record<AvatarSize, string>;
9
- gapSizes: Record<AvatarSize, string>;
12
+ textSizes: Record<AvatarSizeToken, string>;
13
+ gapSizes: Record<AvatarSizeToken, string>;
10
14
  }
11
15
  export declare const avatarTheme: AvatarTheme;
12
16
  export {};
@@ -1,19 +1,75 @@
1
1
  const avatarTheme = {
2
- baseStyle: "relative inline-flex items-center justify-center overflow-hidden bg-[var(--color-surface)] text-[var(--color-text-primary)] font-bold tracking-tighter rounded-[var(--avatar-radius)] border border-[var(--color-border)] transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2",
3
- sizes: {
4
- xs: "size-[var(--avatar-size-xs)] text-xs",
5
- sm: "size-[var(--avatar-size-sm)] text-xs",
6
- md: "size-[var(--avatar-size-md)] text-sm",
7
- lg: "size-[var(--avatar-size-lg)] text-sm",
8
- xl: "size-[var(--avatar-size-xl)] text-sm",
2
+ // `isolate` is load-bearing, not decoration: the circle's contents raise
3
+ // themselves above the gradient with `z-10`, and a `relative` box with
4
+ // `z-index: auto` does NOT create a stacking context — so that z-10 escaped
5
+ // into the WRAPPER's context and painted over the sibling status dot, which
6
+ // sits at `z-index: auto`. Isolating keeps the circle's internal layering
7
+ // internal, so the dot and badge stack by DOM order as intended.
8
+ baseStyle: "relative isolate inline-flex items-center justify-center overflow-hidden bg-[var(--color-surface)] text-[var(--color-text-primary)] font-bold tracking-tighter rounded-[var(--avatar-radius)] border border-[var(--color-border)] transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2",
9
+ // One geometry class for EVERY size. The px value arrives through the
10
+ // `--avatar-size` custom property, which Avatar sets inline: a token maps to
11
+ // its `--avatar-size-*` var, a number to `${n}px`. It has to travel as a
12
+ // variable rather than a generated `size-[30px]` class because per-value
13
+ // classes can't be interpolated — Tailwind only ships what it finds in this
14
+ // library's source, so an interpolated class would resolve to nothing.
15
+ sizeStyle: "size-[var(--avatar-size)]",
16
+ // The circle's own glyph (initials) — distinct from `textSizes`, which sizes
17
+ // the adjacent title/subtitle block.
18
+ glyphSizes: {
19
+ xs: "text-xs",
20
+ sm: "text-xs",
21
+ md: "text-sm",
22
+ lg: "text-sm",
23
+ xl: "text-sm",
9
24
  },
10
25
  statuses: {
11
26
  online: "bg-[var(--color-success)]",
12
- offline: "bg-[var(--color-text-muted)]",
27
+ // NOT `--color-text-muted`: the text tokens are alpha derivations of
28
+ // `--color-text-primary` (57% opaque in light, 50% in dark), so using one
29
+ // as a FILL let the avatar photo show straight through the dot.
30
+ //
31
+ // A ramp rung rather than `--color-mono` (the §3 filled-neutral role) is a
32
+ // deliberate, measured exception — see CLAUDE.md §8. `--color-mono` is
33
+ // mono-900/200, tuned to carry `-contrast` TEXT; a status dot carries none,
34
+ // and at that weight the least-active state out-shouts the active ones.
35
+ // mono-500 is the only rung clearing WCAG 1.4.11's 3:1 against the dot's
36
+ // adjacent colour (its `--color-background` ring) in BOTH modes — 4.54
37
+ // light, 3.78 dark — which also puts it in the same band as its siblings
38
+ // (success 3.52, danger 4.57). One value, no `dark:` variant needed.
39
+ offline: "bg-[var(--color-mono-500)]",
13
40
  busy: "bg-[var(--color-danger)]",
14
41
  away: "bg-[var(--color-warning)]",
15
42
  none: "",
16
43
  },
44
+ // Placement, shared by every size. The avatar is a circle
45
+ // (`--avatar-radius: 50%`), so anchoring the dot to the bounding-box corner
46
+ // strands it outside the arc — the corner sits ~41% further from the centre
47
+ // than the edge does. The 45° point of a circle is `r(1 − 1/√2)` ≈ 14.6% of
48
+ // the diameter in from each edge; the half-translates then centre the dot on
49
+ // it, so it reads as attached at EVERY size, including arbitrary numeric ones
50
+ // (a px inset per rung can only ever be right for that rung's exact diameter).
51
+ statusPositionStyle: "left-[14.6%] bottom-[14.6%] -translate-x-1/2 translate-y-1/2",
52
+ // Dot AND ring ramp together, because what the eye reads is the badge's total
53
+ // footprint — and the ring used to be a flat 2px at every rung, making it
54
+ // proportionally 3.3× heavier on xs than on xl. Dot tracks ~20% of the
55
+ // diameter, ring ~5%, so the footprint stays near 30% across the ladder
56
+ // (was 42%→25%). xs is the one deliberate outlier at 33%: 20% of 24px is
57
+ // under 5px, which stops reading as a status colour at all, so the dot holds
58
+ // a 6px legibility floor there rather than scaling honestly.
59
+ statusSizes: {
60
+ xs: "size-1.5 ring-1",
61
+ sm: "size-1.5 ring-[1.5px]",
62
+ md: "size-2 ring-2",
63
+ lg: "size-2.5 ring-2",
64
+ xl: "size-3 ring-[3px]",
65
+ },
66
+ verifiedSizes: {
67
+ xs: "size-2.5 -right-0.5 -bottom-0.5",
68
+ sm: "size-3.5 -right-0.5 -bottom-0.5",
69
+ md: "size-4 -right-0.5 -bottom-0.5",
70
+ lg: "size-5 -right-0.5 -bottom-0.5",
71
+ xl: "size-5 -right-0.5 -bottom-0.5",
72
+ },
17
73
  titleStyle: "font-medium leading-tight text-[var(--color-text-primary)] truncate",
18
74
  subtitleStyle: "leading-tight text-[var(--color-text-muted)] truncate",
19
75
  textSizes: {
@@ -1,6 +1,13 @@
1
1
  import { ReactNode } from "react";
2
2
  import type { MeshPaletteName } from "../../effects/MeshGradient";
3
- export type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl" | number;
3
+ /** The named rungs of the avatar size ladder (px values live in `theme.css`). */
4
+ export type AvatarSizeToken = "xs" | "sm" | "md" | "lg" | "xl";
5
+ /**
6
+ * A named rung, or an exact pixel size. A number sizes the circle precisely
7
+ * (`size={30}` → 30px) while its decorations — glyph, status dot, verified
8
+ * badge, text gap — snap to the nearest rung.
9
+ */
10
+ export type AvatarSize = AvatarSizeToken | number;
4
11
  export type AvatarStatus = "online" | "offline" | "busy" | "away" | "none";
5
12
  export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
6
13
  /**
@@ -14,7 +21,11 @@ export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
14
21
  */
15
22
  name?: string | null;
16
23
  /**
17
- * The size of the avatar
24
+ * The size of the avatar — a named rung (`"md"`) or an exact pixel size
25
+ * (`30`). Prefer this over a `className="size-[30px]"` override: the shipped
26
+ * stylesheet only contains the classes used by this library's own source, so
27
+ * an arbitrary size utility resolves to nothing for consumers who don't run
28
+ * Tailwind themselves.
18
29
  * @default "md"
19
30
  */
20
31
  size?: AvatarSize;
@@ -1,2 +1,2 @@
1
1
  export { Avatar } from './Avatar';
2
- export type { AvatarProps, AvatarSize, AvatarStatus, } from './Avatar.types';
2
+ export type { AvatarProps, AvatarSize, AvatarSizeToken, AvatarStatus, } from './Avatar.types';
@@ -7,7 +7,7 @@ import { cn } from '../../../utils/cn.js';
7
7
  import { avatarGroupTheme } from './AvatarGroup.theme.js';
8
8
  import { getAnimationState, getAvatarGroupVariants } from './AvatarGroup.animations.js';
9
9
 
10
- const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "md", spacing = "normal", direction = "row", overflowIndicator, className, ariaLabel = "Group of users", shouldAnimate = true, ...props }, ref) => {
10
+ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "md", direction = "row", overflowIndicator, className, ariaLabel = "Group of users", shouldAnimate = true, ...props }, ref) => {
11
11
  const [hoveredIndex, setHoveredIndex] = useState(null);
12
12
  const shouldReduceMotion = useReducedMotion();
13
13
  const enableAnimations = shouldAnimate && !shouldReduceMotion;
@@ -15,7 +15,6 @@ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "
15
15
  const memoizedData = useMemo(() => {
16
16
  const visibleAvatars = avatars.slice(0, max);
17
17
  const overflowCount = avatars.length > max ? avatars.length - max : 0;
18
- const spacingClass = avatarGroupTheme.spacingStyles[spacing];
19
18
  const directionClass = direction === "row-reverse" ? "flex-row-reverse" : "flex-row";
20
19
  const totalPeople = avatars.length;
21
20
  const groupDescription = avatars
@@ -24,14 +23,13 @@ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "
24
23
  return {
25
24
  visibleAvatars,
26
25
  overflowCount,
27
- spacingClass,
28
26
  directionClass,
29
27
  totalPeople,
30
28
  groupDescription,
31
29
  };
32
- }, [avatars, max, spacing, direction]);
33
- const { visibleAvatars, overflowCount, spacingClass, directionClass, totalPeople, groupDescription, } = memoizedData;
34
- return (jsxs("div", { ref: ref, className: cn(avatarGroupTheme.baseStyle, directionClass, className), role: "group", "aria-label": ariaLabel, "aria-description": `Contains ${totalPeople} users: ${groupDescription}`, "data-size": size, "data-spacing": spacing, "data-direction": direction, "data-total": totalPeople, "data-visible": visibleAvatars.length, "data-overflow": overflowCount > 0 ? "true" : "false", onMouseLeave: () => enableAnimations && setHoveredIndex(null), ...props, children: [visibleAvatars.map((avatarProps, index) => {
30
+ }, [avatars, max, direction]);
31
+ const { visibleAvatars, overflowCount, directionClass, totalPeople, groupDescription, } = memoizedData;
32
+ return (jsxs("div", { ref: ref, className: cn(avatarGroupTheme.baseStyle, directionClass, className), role: "group", "aria-label": ariaLabel, "aria-description": `Contains ${totalPeople} users: ${groupDescription}`, "data-size": size, "data-direction": direction, "data-total": totalPeople, "data-visible": visibleAvatars.length, "data-overflow": overflowCount > 0 ? "true" : "false", onMouseLeave: () => enableAnimations && setHoveredIndex(null), ...props, children: [visibleAvatars.map((avatarProps, index) => {
35
33
  // Create contextual label for individual avatars in a group
36
34
  const position = index + 1;
37
35
  const contextLabel = avatarProps.contextualLabel || ` (${position} of ${totalPeople})`;
@@ -50,10 +48,10 @@ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "
50
48
  // inflating the row and dropping the self-centered overflow chip.
51
49
  "flex",
52
50
  // First avatar doesn't need negative margin
53
- index > 0 ? spacingClass : "z-10"), "data-position": position, "data-index": index, ...motionProps, children: jsx(Avatar, { size: size, ...avatarProps, contextualLabel: contextLabel,
51
+ index > 0 ? avatarGroupTheme.spacingStyle : "z-10"), "data-position": position, "data-index": index, ...motionProps, children: jsx(Avatar, { size: size, ...avatarProps, contextualLabel: contextLabel,
54
52
  // Ensure that groupPosition is not passed to avoid conflicts
55
53
  groupPosition: undefined }) }, index));
56
- }), overflowCount > 0 && (jsx("div", { className: cn("flex", spacingClass), "data-overflow-count": overflowCount, children: overflowIndicator ? (overflowIndicator(overflowCount)) : (jsx(Avatar, { size: size, name: `+${overflowCount} more`, fallback: jsxs("span", { children: ["+", overflowCount] }), className: avatarGroupTheme.overflowAvatarStyle, role: "img", "aria-label": `+ ${overflowCount} more users` })) }))] }));
54
+ }), overflowCount > 0 && (jsx("div", { className: cn("flex", avatarGroupTheme.spacingStyle), "data-overflow-count": overflowCount, children: overflowIndicator ? (overflowIndicator(overflowCount)) : (jsx(Avatar, { size: size, name: `+${overflowCount} more`, fallback: jsxs("span", { children: ["+", overflowCount] }), className: avatarGroupTheme.overflowAvatarStyle, role: "img", "aria-label": `+ ${overflowCount} more users` })) }))] }));
57
55
  });
58
56
  // Set display name for dev tools and Storybook
59
57
  AvatarGroup.displayName = "AvatarGroup";
@@ -1,10 +1,9 @@
1
- import { AvatarGroupSpacing } from "./AvatarGroup.types";
2
1
  /**
3
2
  * Internal theme structure for the AvatarGroup component
4
3
  */
5
4
  interface AvatarGroupTheme {
6
5
  baseStyle: string;
7
- spacingStyles: Record<AvatarGroupSpacing, string>;
6
+ spacingStyle: string;
8
7
  overflowAvatarStyle: string;
9
8
  }
10
9
  /**
@@ -6,12 +6,8 @@ const avatarGroupTheme = {
6
6
  baseStyle: "flex items-center",
7
7
  // NOTE: items-center only works because Avatar's wrapper no longer leaves a
8
8
  // baseline descender below the circle (Avatar.tsx wrapper is inline-flex).
9
- // Spacing options - separated from hover effects
10
- spacingStyles: {
11
- tight: "-ml-5 z-10",
12
- normal: "-ml-3 z-10",
13
- loose: "-ml-2 z-10",
14
- },
9
+ // Overlap between stacked avatars override per call site with className.
10
+ spacingStyle: "-ml-3 z-10",
15
11
  // Overflow avatar styles
16
12
  overflowAvatarStyle: "bg-[var(--color-surface)]/60 backdrop-blur-sm text-[var(--color-text-secondary)] font-bold tracking-tight text-[10px] flex items-center justify-center size-6",
17
13
  };
@@ -1,6 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
2
  import type { AvatarProps } from '../Avatar/Avatar.types';
3
- export type AvatarGroupSpacing = 'tight' | 'normal' | 'loose';
4
3
  export type AvatarGroupDirection = 'row' | 'row-reverse';
5
4
  export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
6
5
  /**
@@ -17,11 +16,6 @@ export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
17
16
  * @default "md"
18
17
  */
19
18
  size?: AvatarProps["size"];
20
- /**
21
- * Amount of overlap between avatars (higher value = more overlap)
22
- * @default "normal"
23
- */
24
- spacing?: AvatarGroupSpacing;
25
19
  /**
26
20
  * Direction of the avatar stack
27
21
  * @default "row"
@@ -1,2 +1,2 @@
1
1
  export { AvatarGroup } from './AvatarGroup';
2
- export type { AvatarGroupProps, AvatarGroupSpacing, AvatarGroupDirection } from './AvatarGroup.types';
2
+ export type { AvatarGroupProps, AvatarGroupDirection } from './AvatarGroup.types';
@@ -1,4 +1,6 @@
1
1
  "use client";
2
+ import { PRESS_TRANSITION, HOVER_TRANSITION } from '../shared/interaction.animations.js';
3
+
2
4
  // Main badge variants with optimized transitions
3
5
  const badgeVariants = {
4
6
  initial: {
@@ -58,11 +60,11 @@ const dismissButtonVariants = {
58
60
  },
59
61
  hover: {
60
62
  opacity: 1,
61
- transition: { duration: 0.15, ease: "easeOut" },
63
+ transition: HOVER_TRANSITION,
62
64
  },
63
65
  tap: {
64
66
  scale: 0.95,
65
- transition: { duration: 0.1, ease: "easeOut" },
67
+ transition: PRESS_TRANSITION,
66
68
  },
67
69
  };
68
70
  // Optimized dismiss animation sequence
@@ -2,7 +2,7 @@
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import React__default, { useState, useCallback } from 'react';
4
4
  import { useReducedMotion, AnimatePresence, motion } from 'motion/react';
5
- import { XMarkIcon } from '@heroicons/react/24/outline';
5
+ import { X } from '@phosphor-icons/react';
6
6
  import { cn } from '../../../utils/cn.js';
7
7
  import { Avatar } from '../Avatar/Avatar.js';
8
8
  import { animationTiming, dismissVariants, badgeVariants, dismissButtonVariants, dotVariants } from './Badge.animations.js';
@@ -131,7 +131,12 @@ const Badge = React__default.memo(React__default.forwardRef(({ children, variant
131
131
  return (jsx("span", { className: cn("inline-flex items-center justify-center shrink-0 overflow-hidden [&_div]:!size-full", (_a = theme.avatarSizes) === null || _a === void 0 ? void 0 : _a[size], pill ? "rounded-full -ml-2" : "rounded-full -ml-0"), children: jsx(Avatar, { src: avatar.src, name: avatar.name, gradient: avatar.gradient, gradientVariant: avatar.gradientVariant, gradientColors: avatar.gradientColors, fallback: avatar.fallback, initialsCount: avatar.initialsCount, size: "xs", className: cn("!size-full border-0", pill ? "rounded-full" : "rounded-md ring-0") }) }));
132
132
  }
133
133
  if (iconStart) {
134
- return (jsx("span", { className: cn("inline-flex items-center justify-center flex-shrink-0 -ml-1", (_b = theme.iconSizes) === null || _b === void 0 ? void 0 : _b[size]), "aria-hidden": "true", children: iconStart }));
134
+ return (jsx("span", { className: cn("inline-flex items-center justify-center flex-shrink-0",
135
+ // Optical tuck into the cap curve — pill only (it has the extra
136
+ // pillSizes padding to absorb it). On a regular badge the base
137
+ // px-1 padding is 4px, so -ml-1 left the icon ~1px from the
138
+ // border. Mirrors the avatar path's pill/non-pill conditional.
139
+ pill ? "-ml-1" : "-ml-0", (_b = theme.iconSizes) === null || _b === void 0 ? void 0 : _b[size]), "aria-hidden": "true", children: iconStart }));
135
140
  }
136
141
  if (withDot) {
137
142
  if (shouldAnimate) {
@@ -151,7 +156,7 @@ const Badge = React__default.memo(React__default.forwardRef(({ children, variant
151
156
  ? `${maxWidth}px`
152
157
  : maxWidth,
153
158
  }
154
- : undefined, children: children }), dismissible && (jsx("button", { type: "button", onClick: handleDismiss, className: "badge-dismiss-btn -mr-0.5 rounded-full p-0.5 cursor-pointer", "aria-label": "Dismiss", disabled: disabled, children: jsx(XMarkIcon, { className: cn("badge-dismiss-icon", (_p = theme.dismissSizes) === null || _p === void 0 ? void 0 : _p[size]), "aria-hidden": "true" }) }))] })) : null;
159
+ : undefined, children: children }), dismissible && (jsx("button", { type: "button", onClick: handleDismiss, className: "badge-dismiss-btn -mr-0.5 rounded-full p-0.5 cursor-pointer", "aria-label": "Dismiss", disabled: disabled, children: jsx(X, { className: cn("badge-dismiss-icon", (_p = theme.dismissSizes) === null || _p === void 0 ? void 0 : _p[size]), "aria-hidden": "true" }) }))] })) : null;
155
160
  }
156
161
  return (jsx(AnimatePresence, { mode: "wait", children: isVisible && (jsxs(motion.span, { ref: ref, className: baseStyles, onClick: handleClick, "aria-disabled": disabled || undefined, variants: dismissible ? dismissVariants : badgeVariants, initial: "initial", animate: "animate", exit: "exit", ...dataAttributes, ...props, children: [renderLeftContent(), jsx("span", { className: cn("badge-content", maxWidth && "truncate"), style: maxWidth
157
162
  ? {
@@ -159,7 +164,7 @@ const Badge = React__default.memo(React__default.forwardRef(({ children, variant
159
164
  ? `${maxWidth}px`
160
165
  : maxWidth,
161
166
  }
162
- : undefined, children: children }), dismissible && (jsx(motion.button, { type: "button", onClick: handleDismiss, className: "badge-dismiss-btn -mr-0.5 rounded-full p-0.5 cursor-pointer", "aria-label": "Dismiss", disabled: disabled, variants: dismissButtonVariants, initial: "initial", whileHover: "hover", whileTap: "tap", children: jsx(XMarkIcon, { className: cn("badge-dismiss-icon", (_q = theme.dismissSizes) === null || _q === void 0 ? void 0 : _q[size]), "aria-hidden": "true", strokeWidth: 2 }) }))] })) }));
167
+ : undefined, children: children }), dismissible && (jsx(motion.button, { type: "button", onClick: handleDismiss, className: "badge-dismiss-btn -mr-0.5 rounded-full p-0.5 cursor-pointer", "aria-label": "Dismiss", disabled: disabled, variants: dismissButtonVariants, initial: "initial", whileHover: "hover", whileTap: "tap", children: jsx(X, { className: cn("badge-dismiss-icon", (_q = theme.dismissSizes) === null || _q === void 0 ? void 0 : _q[size]), "aria-hidden": "true", weight: "bold" }) }))] })) }));
163
168
  }));
164
169
  Badge.displayName = "Badge";
165
170