@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
package/CHANGELOG.md CHANGED
@@ -5,6 +5,103 @@ All notable changes to Flikkui will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [1.0.0-beta.31] - 2026-07-31
11
+
12
+ ### Breaking Changes
13
+
14
+ - **Icon library swapped: `@heroicons/react` → `@phosphor-icons/react`** — The required icon peer dependency is now Phosphor (`>=2.1.0`); Heroicons is no longer used anywhere in the library. Migration for consumers: `yarn remove @heroicons/react && yarn add @phosphor-icons/react`. **No component API changes** — every icon slot stays `ReactNode`, so icons you pass in (from any library) keep working; only the *built-in* glyphs (chevrons, dismiss ✕, check marks, status icons, etc.) changed shape from Heroicons to the visually close Phosphor equivalents at `regular` weight (`bold` where the old icons used `strokeWidth≥2`, replacing the old `24/solid` uses — one consistent weight voice). Rationale: the Figma design kit standardised on the Phosphor library, and this aligns code with design 1:1. Bundle note: Phosphor modules carry all six weights (~3–6× per icon, ~10–15 KB gzipped total for the ~25 built-in chrome icons); the generative icon vocabulary (`DEFAULT_ICONS`) keeps its library-agnostic names, so generative specs and `generative.schema.json` are unchanged.
15
+
16
+ - **Color role `neutral` renamed to `mono`** — The gray/low-emphasis color role is now `mono` everywhere: the prop value (`color="mono"` on Button, Badge, Alert, Toast, KPI, Metric, Link, Spinner, CustomCursor), the `SemanticColor` / `ButtonColor` unions, and the CSS variables (`--color-mono-50…950`, `--color-mono`, `--color-mono-contrast`). The old name collided with Tailwind's own `neutral` color palette — mapping `neutral` in `tailwind.preset.cjs` shadowed Tailwind's real neutral so consumers couldn't reach it, and it blocked the goal of every role being usable as a shorthand (`bg-mono`, `bg-primary`, …) without stealing a Tailwind palette name. The preset now maps `mono` and no longer maps `neutral`, so `bg-neutral-*` / `bg-slate-*` / `bg-zinc-*` all resolve to Tailwind's real palettes again. There is **no `neutral` alias** at the prop level. Migration: replace `color="neutral"` → `color="mono"` and `var(--color-neutral-*)` → `var(--color-mono-*)`. Note: `--color-neutral-*` still resolves (to Tailwind's own neutral, a near-identical gray in the default theme) but no longer tracks the themed role — use `--color-mono-*` for the role.
17
+ - **Charts — ~25 dead props removed from the public API** — `BarChart`, `StackedBarChart` and `AreaChart` each declared `extends StandardVisualProps` with no `Omit`. That interface is the *union* of every chart's visual props, so each chart inherited the others': they type-checked, appeared in the generative schema (an LLM could emit them), and were never read. `BaseChartProps` doesn't extend `HTMLAttributes` and the spread targets are plain `<div>`s, so they couldn't even be forwarded — `<BarChart curved />` reached a div as an unknown attribute. Each chart's props are now narrowed with `Omit` to what it implements, matching what `LineChart`/`ComboChart`/`HorizontalBarChart` already did. Removed:
18
+ - **`BarChart`** — `orientation`, `curved`, `curveType`, `showDots`, `fillOpacity`, `showStroke`, `stacked`, `dotRadius`, `cellRadius`, `strokeWidth`. For horizontal bars use the new `HorizontalBarChart` (`orientation` was a second, non-functional way to ask for the same thing).
19
+ - **`StackedBarChart`** — the same ten, plus `gap` (segment separation is a fixed hairline, not a tunable) and `radius` (its `@deprecated` → `barRadius` mapping was never implemented, so unlike `BarChart`/`AreaChart`/`LineChart` it never worked at all).
20
+ - **`AreaChart`** — `barRadius`, `cellRadius`, `gap`.
21
+ - **`ComboChart`** — `fillOpacity`, `showStroke`, `cellRadius`. Its `SeriesType` is `'bar' | 'line'` with no area member, so the area-fill props had nothing to apply to.
22
+ - **`ScatterPlot`** — `variant`. Scatter points are flat single-colour marks; there is no gradient/minimal treatment to select.
23
+ - **`cellRadius` is gone library-wide** — it was declared "for heatmap cells" and `Heatmap` never referenced it.
24
+ - **Axis family** — `color` and `fontSize` are removed from `BaseAxisProps` and `AxisTickProps` (so from `XAxis`, `YAxis`, `ValueXAxis`, `CategoryYAxis`), and `color` from `HorizontalGrid`. Axis lines and labels are themed via CSS variables (`stroke-[var(--color-border)]`); `color` was accepted, defaulted to `"currentColor"`, and ignored, and `fontSize` had no implementation anywhere. Restyle an axis with `className`, or change the token.
25
+ - **Charts — `CHART_DEFAULTS` and the exported `*_DEFAULTS` objects lost their dead keys** — each `*_DEFAULTS` spread `...CHART_DEFAULTS`, so every chart published a default for every other chart's props. They now list only what their component reads. `CHART_DEFAULTS` also drops `cellRadius`, `orientation`, and `radius` (nothing consulted the last one — the deprecated `radius` *prop* still works on `BarChart`/`AreaChart`/`LineChart`, falling back to `barRadius`/`dotRadius`). These objects are publicly exported, so reads like `BAR_CHART_DEFAULTS.curved` no longer compile.
26
+ - **`AvatarGroup` — `spacing` prop removed** — The group now renders one fixed overlap (the former `"normal"`, `-ml-3`). The three-value scale was a styling axis with an inverted, confusing vocabulary — `"tight"` meant *more* overlap (`-ml-5`) and `"loose"` meant *less* (`-ml-2`), the reverse of how the words read — and it duplicated what `className` already does better. The `AvatarGroupSpacing` type is no longer exported. Migration: drop the prop; to restore a custom overlap, pass it through `className` (e.g. `className="[&>*+*]:-ml-5"`). Internal call sites that used `"loose"`/`"tight"` (`CalendarEvent`, Popover stories) now use the single default, so their avatars sit fractionally differently.
27
+ - **`Segmented` — default width is now fit-content** — The control previously stretched to fill its parent by default (its `flex` root is block-level, so it spanned full width regardless of the `block` prop, which was effectively a no-op). It now shrinks to fit its segments by default, and `block` genuinely opts into full width — matching the documented `block` contract and the iOS/shadcn segmented-control convention. Migration: add `block` to any `Segmented` that should span its container.
28
+ - **Control heights and button padding retuned — every form control and Button changes size** — No API change, but the default values move, so consumer layouts shift. Heights (`--form-min-h-sm/md/lg`) go from **32/40/48px → 32/36/40px**, an even 4px step where the old ramp jumped 8px; button horizontal padding (`--button-px-sm/md/lg`) goes from **12/12/20px → 10/12/14px**, a consistent +2 ramp (`sm` and `md` previously collided at 12px and `lg` was an outlier). This lands the ramp on the same scale Untitled UI and shadcn use, with our `lg` (40px) at the industry-standard default height. Blast radius is wider than the token names suggest: `--button-min-h-*` and `--button-icon-size-*` both alias `--form-min-h-*`, so this resizes every form control, every Button, and every icon-only Button. Icon-only `sm` stays 32×32, clear of WCAG 2.2 SC 2.5.8's 24×24 floor. `--form-px-*` is deliberately untouched (12/14/16) — controls get shorter but keep their horizontal padding. To keep the old sizing, override the three height tokens in your own CSS.
29
+ - **`--radius-base` default is now 8px** (was 12px) — Every derived radius in the library scales from this one token, so the default theme is uniformly less round. Set `--radius-base: 12px` to restore the previous look.
30
+ - **Default chart series colors are no longer the semantic status palette** — Multi-series charts previously drew from `primary`/`warning`/`success`/`danger` at two lightness steps, which meant a categorical series could read as a *status* (a red series looking like an error). They now resolve from the new dedicated `--color-chart-1…5` palette. An explicit `config[key].color` is unaffected and still wins, including the bare-token shorthand (`"success"` → `var(--color-success)`). To restore the old look, set the colors explicitly in `config`, or override `--color-chart-1…5`.
31
+ - **`--hero-card-radius` retired** — `HeroCard` had its own radius token at 3× base (vs `Card`'s 1.5×) on the belief that it needed a rounder look. It is a *presentation* of Card, not a distinct container, so it now shares `--card-radius`. Per-instance overrides still work via `className`. Migration: if you set `--hero-card-radius`, move that value onto the HeroCard's `className` or override `--card-radius`.
32
+
33
+ ### Added
34
+
35
+ - **AI — `AgentStatus`, `Reasoning` and `SourceCitation`** (`@flikk/ui/ai`) — `AgentStatus` is the single agent-activity-row primitive and owns the reasoning disclosure through a `mode` prop, so one component covers the three ways a chat surfaces the same row: a live status line (`Thinking… 4s`), a collapsible "show your work", and each step inside it. `mode` and the lifecycle `status` stay **orthogonal** — a reasoning block is itself active or settled. The reasoning body is not always a step list: `steps={[{label,status,duration}]}` renders an `<ol>` of nested rows, while `children` render **raw**, so prose and markdown stay valid HTML. `Reasoning` is a thin preset over `mode="reasoning"` (`Reasoning.Step` aliases a status row). `SourceCitation` renders inline citation chips with preview popovers. Both share one `StatusIndicator` glyph, whose active spinner is a CSS `animate-spin` comet — motion only does enter/exit, since a single-value `rotate` target flattens to a static transform. New public hook **`useElapsedTime`** powers `startedAt`: the duration ticks on its own while active, takes one exact final reading on settle, then freezes, and the clock is only read inside an effect so there is no `Date.now()` in render to hydrate-mismatch.
36
+ - **`HorizontalBarChart`** (`@flikk/ui/charts`) — Categories run down the left, values extend right. It shares `BarChart`'s data model and none of its axis wiring (the value/category axes are swapped), so it ships as its own component rather than an `orientation` flag. Use it when category names are long or numerous, or when the chart ranks items — a column chart cannot fit "United Kingdom" under its axis. Three new shared axis primitives came with it, because the axis layer had no horizontal support at all: `ValueXAxis` (a value axis rendered horizontally, Heckbert nice ticks), `CategoryYAxis` (a category axis rendered vertically), and `VerticalGrid`. 🔴 Note the axis family splits by what an axis **measures**, not which way it points — `XAxis` is a category axis despite being horizontal.
37
+ - **`LollipopChart`** (`@flikk/ui/charts`) — Stem-and-dot marks with a staggered entrance, an always-on stem gradient + soft glow, hover/keyboard-focus/pinned-selection states (controlled and uncontrolled `selected`/`defaultSelected`), and a dot↔pill morph that animates a single `rx`-interpolating `motion.rect`. Uses the shared `XAxis` and `X_AXIS_MARGIN` so its baseline aligns with every other chart.
38
+ - **`Button` — `iconStart` / `iconEnd`** — Button had no icon prop at all: `children` covers icons via the flex gap, which holds for hand-written code, but **a generative UI spec is JSON** — it can *name* an icon, never pass a React element — so an LLM literally could not put an icon on a button. This is the "one contract, two front doors" pattern §2 already established for collection `items` arrays and Card's flat `title`/`subtitle` slot-props. Button deliberately takes the **icon slots only** and *not* `contentStart`/`contentEnd`: an icon can be named, an arbitrary `ReactNode` cannot, so content slots would buy the generative path nothing. Composite stays the idiom and every existing call site is untouched — pass neither slot and `children` renders exactly as before. `theme.iconSizes` uses `[&>svg]:size-*` so a bare `<SearchIcon />` with no `className` still lands at the right size per button size (14/16/20 for sm/md/lg); a caller's own `className` still wins. The icon wrappers are `aria-hidden`, so the accessible name stays the label alone.
39
+ - **`Tooltip` — controlled mode** — New `isOpen` / `defaultIsOpen` / `onOpenChange` props, plus a `recalcTrigger` escape hatch for triggers that move without firing a scroll or resize event (a dragged `Slider` thumb, for instance). `aria-describedby` is now merged with any existing value instead of clobbering it.
40
+ - **`Modal` — `darkMode` prop** — Mirrors `Button`'s: applies the `dark` class to the modal container so a modal can render dark while the page is light.
41
+ - **`InputAddress` — `showCountrySelector` / `showPostalCode`** — Lets either field be hidden for address formats that don't use them. Because the fields render as one merged perimeter, the corner radii are position-aware: the last visible field carries the bottom corners, and a lone bottom field spans the full row instead of splitting into two columns.
42
+ - **`InputOTP` — `charset` prop (`numeric | alphanumeric`)** — Drives the sanitizer, `pattern` and `inputMode` together, so the on-screen keyboard, the accepted characters and the validation hint can't drift apart.
43
+ - **`OfflineIndicator` — `action` prop** — Takes `{ label, onClick }` for a link-styled button (mirroring `Toast`'s `action`) or any `ReactNode`. Also gains full-bleed banner positions and reduced-motion fallback variants.
44
+ - **`CommandPalette` — `onCommandSelect(id)`** — Fires alongside each command's own `onSelect`, so a single top-level callback can observe selection (this is what lets the generative registry bind commands through the standard action mechanism instead of synthesizing per-item callbacks).
45
+ - **`Checkbox` / `Radio` — selection ripple** — A shared ripple animation on check, with reduced-motion coverage.
46
+ - **Preset theme "Ember"** — A third shipped theme: orange primary, zinc neutrals, Plus Jakarta Sans, pill geometry and a 24px base radius. Registered in the Storybook theme switcher alongside Iris and Jade.
47
+ - **Four new themeable token systems** — (1) **Per-container padding**: `--card-px/py`, `--modal-px/py`, `--drawer-px/py`, `--metric-content-p-sm/md/lg`, so a theme can make the brand-visible containers roomier or tighter without touching every padded element in the library. (2) **Three-tier radius ceilings**: `--surface-radius-cap-xs/sm/lg` wrap every content-bearing container's derived radius in a `min()`, so a theme chasing pill *controls* at a large `--radius-base` can't round a padded container past what its own padding can absorb (a curve-vs-padding collision that visually eats into header text). Controls stay uncapped — going fully pill there is correct. (3) **Per-role font sizes**: `--card-title-size`, `--modal-title-size`, `--drawer-title-size`, `--page-heading-title-size`, `--section-title-size`, `--metric-value-size-*`, `--kpi-value-size-*` — `--font-scale` can only resize the *whole* UI, so these let a theme resize a single role. Each defaults to a `--text-*` rung, so `--font-scale` still flows through. (4) **`--color-chart-1…5`**: a categorical chart palette decoupled from the semantic status colors. Sixteen components whose radius/padding/title-size had drifted into a bare uncapped `calc()` were wired onto these systems.
48
+ - **Generative UI — curated set expanded from 32 to 66 components** — Forms were entirely uncurated before this (Input, Select, Combobox, Textarea, Checkbox, Switch, Slider, InputOTP, TimePicker, InputDate, InputCounter, InputTag), joined by 16 more Core/Data Display entries (Spinner, Skeleton, Link, Kbd, DotSeparator, Icon, Pagination, Message, MenuItem, Calendar, GanttChart, AspectRatio, ButtonGroup, Masonry, ScrollArea, HeroCard), `Tree` and `CommandPalette`, and the five remaining charts the manifest had deferred as "bespoke prop systems" (RadarChart, ScatterPlot, FunnelChart, ActivityRings, Heatmap). Notable: `Calendar`'s schema carries ISO strings with a `render:` wrapper coercing string→Date inbound and Date→ISO outbound; `CommandPalette` forces `isOpen: true` (it renders through the shared `Overlay`, so a spec node is always a full-screen modal) and supports only the flat `CommandItem[]` shape.
49
+ - **`flikkui init` CLI** (separate `flikkui` package, `npx flikkui init`) — Implements the setup command the installation docs have long referenced. Detects framework, package manager and Tailwind; installs `@flikk/ui@beta` plus any missing required peers; injects the `styles.css` (and optional preset theme) import; and wires the Tailwind v4 dark variant. Zero runtime dependencies. Every project ends in exactly one explicit outcome — auto-wired (Next App/Pages Router, Vite), a named-framework manual snippet (CRA, Remix/RR7, Gatsby, Astro), a generic snippet, or a refusal with a stated reason (no `package.json`, React Native/Expo, React < 18). Theme imports are capability-checked against the installed package version. 128 unit tests + fixtures. Tracked in `packages/cli/CHANGELOG.md`.
50
+ - **Figma design-kit generator (`yarn build:figma-tokens`)** — Design-ops tooling, deliberately **not** wired into `yarn build`. Parses `src/styles/theme.css` and emits `dist/figma-variables.json`: variables split across `Flikk/Primitives` (single mode) and `Flikk/Semantic` (Light/Dark), plus shadow effect styles derived from the `--elevation-surface-*` ladder. Mode-dependence is **derived, not curated** — a token is Semantic iff `.dark` overrides it *or it transitively references something that is*. Unknown value forms are a **hard failure (exit 1), never a guess**: the evaluator understands exactly four computed families, so adding a new one must break this build. See `docs/figma-component.md`.
51
+
52
+ - **`Avatar` / `AvatarGroup` — `size` now accepts an exact pixel number** — `size={30}` sizes the circle to exactly 30px alongside the existing `"xs" | "sm" | "md" | "lg" | "xl"` rungs (`AvatarSize = AvatarSizeToken | number`; the new `AvatarSizeToken` type is exported). The type already admitted `number` but no implementation backed it: the theme's `Record<AvatarSize, string>` lookup returned `undefined` for a number, so `size={30}` type-checked and rendered an avatar with **no size class at all**. This is a fix as much as a feature. Note that `className="size-[30px]"` is not an equivalent workaround — the shipped `styles.css` only contains classes found in this library's own source and `tailwindcss` is an optional peer, so an arbitrary size utility resolves to nothing for consumers who don't run Tailwind themselves. Geometry is exact; decorations (glyph, status dot, verified badge, text gap) snap to the nearest rung (30 → `sm`). Token sizes render byte-for-byte identical to before. Implementation note: the circle now always carries the class `size-[var(--avatar-size)]` with the value supplied inline via the `--avatar-size` custom property, so anything targeting the old per-token `size-[var(--avatar-size-md)]` class in CSS will no longer match.
53
+ - **Preset themes (`flikkui/themes/*`) + first theme "Iris"** — The library now ships swappable preset theme files: plain CSS-variable override files imported after `styles.css` (`import 'flikkui/themes/iris.css'`) — no config, no JS, no rebuild. The default look is unchanged and needs no import ("Neutral" is baked into `styles.css`). **Iris** restyles the whole library: Tailwind indigo primary ramp, slate-tinted neutrals and borders, Bricolage Grotesque type, and a rounder 16px base radius — with its own dark-mode values (theme files carry explicit `.dark` overrides inside `@layer theme` so dark mode composes correctly). Storybook gets a toolbar theme switcher (paintbrush icon) that live-swaps themes, including combined with dark mode. Custom themes are the same file format — see the Preset themes section in `docs/INSTALLATION.md`. A second preset, **Jade**, reshapes geometry and type as well as color: Tailwind emerald primary, warm stone neutrals (hueless in dark), Poppins on a 14px text scale, and pill-leaning controls (`--radius-base: 20px`, taller form/button heights with wider padding).
54
+ - **Chip-tier padding tokens — themeable Badge / Pill / Tag / Kbd spacing** — The four small "chip" controls now read their padding from CSS variables instead of hardcoded Tailwind literals, so a theme can grow (or tighten) them alongside its buttons and inputs — the same reasoning as the per-component container padding and type-role tokens (a global knob can't make *only* badges roomier). New tokens: `--badge-px-sm/md`, `--badge-py-sm/md`, `--badge-pill-px-sm/md`; `--pill-px-sm/md/lg`, `--pill-py-sm/md/lg`; `--tag-px-sm/md`, `--tag-pl-md`, `--tag-py-sm/md`; `--kbd-px-sm/md`. Defaults are byte-for-byte identical to the previous literals, so the default theme is unchanged. Radius needs no new token — `--badge-radius` now derives from `--radius-base` (`calc(var(--radius-base) * 0.75)`, was a hardcoded `6px` that silently ignored the base, so a large `--radius-base` now rounds badges too), Kbd already derived, and Pill/Tag are intrinsic `rounded-full`. The `jade` and `ember` presets set these so their badges/pills/tags match their spacious geometry. Chip **gap** and Kbd **height** stay literal for now.
55
+ - **`--font-scale` — one-knob type scale** — The base theme now defines the whole Tailwind `--text-xs…9xl` ramp as `calc(<tailwind default> * var(--font-scale))`. At the default `1` every utility is byte-for-byte Tailwind (`text-sm` = 14px); a theme or consumer sets a single factor (Jade: `0.875` → 14px-based text) and the entire ramp plus line-heights follow. Each step is `round()`ed to a whole pixel so scaled sizes stay clean (13px, not 13.125px). Text-only — spacing and px geometry tokens are unaffected.
56
+ - **Control type-size tokens — themeable Button / Input / Segmented label size** — The control tier had every *box* axis tokenised (`--form-min-h-*`, `--form-px/py-*`, `--form-radius`) while its *type* stayed a hardcoded `text-sm` / `text-base` in each `.theme.ts`, so a theme could retune a control's height and padding but never its label. New tokens: `--form-text-size-sm/md/lg` with `--button-text-size-*` and `--segmented-text-size-*` aliasing it (mirroring how `--button-min-h-*` already aliases `--form-min-h-*`), each paired with a `--*-line-height-*` token. Consumed by Button, Segmented, and — via `formsBaseTheme.sizes.*.text` — Input, Select, Textarea, Combobox, DatePicker, DateRangePicker, TimePicker and RichTextEditor. Defaults are byte-for-byte identical to the literals they replaced (sm/md 14px/20px, lg 16px/24px) and each points at a `--text-*` rung, so `--font-scale` still flows through and the default theme is visually unchanged apart from the Segmented fix below. Note the ramp is deliberately **two rungs across three sizes** — sm and md share 14px and only lg steps to 16px; the small sizes are separated by box, not type.
57
+ - **`InputOTP` — `size` prop (`sm | md | lg | xl`)** — `InputOTP` was the only text-entry form control without one, so an OTP could not be lined up with an adjacent `sm` or `lg` `Input`. `sm`/`md`/`lg` resolve to the same heights as the equivalent `Input` size; **`xl` is a new OTP-only rung** (48px in the default theme) for standalone verification screens where the code is the focus of the page. Defaults to `lg`. New tokens: `--otp-slot-size-sm/md/lg/xl`, `--otp-text-size-*` and `--otp-line-height-*`. `sm`/`md`/`lg` alias `--form-min-h-*` and `xl` derives from `--form-min-h-lg` (`calc(… * 1.2)`), so all four track a theme that retunes the form ramp — a hardcoded `xl` would have rendered *smaller than `lg`* under the `jade` (36/44/52) and `ember` (40/48/56) presets. The digit type ramp (16/16/18/20px) deliberately runs one rung hotter than form body text: an OTP numeral is a display glyph, not label text. The digit and the caret now scale with the slot; both were previously fixed at 18px and 20px regardless of size.
58
+ - **`DotPattern` — `fadeDirection="center"`** — A new inverse-radial fade: dots stay solid toward the edges and fade out in the center (the opposite of `"radial"`), producing a vignette that keeps the content area behind the pattern clear. Tunable via `fadeSize` like the other directions. `DotPatternFadeDirection` is now `"radial" | "center" | "top" | "bottom" | "left" | "right"`.
59
+
60
+ ### Changed
61
+
62
+ - **`InputOTP` slots are no longer responsive** — They previously stepped from `--form-min-h-md` to `--form-min-h-lg` at the `sm` breakpoint, which cannot coexist with an explicit `size` prop. The default `size="lg"` renders identically to the previous desktop output; narrow viewports now render at the same size rather than one rung smaller, and can opt into `size="sm"` — something that was impossible before. **Breaking for custom themes:** `InputOTPTheme.inputGroupStyle` (a single string) is replaced by `inputGroupSizes` and `charSizes`, both `Record<InputOTPSize, string>`. This only affects consumers passing a custom `theme` to `InputOTP`, and it is a compile-time type error, never a silent visual change.
63
+ - **`--color-neutral` + `--color-neutral-contrast`** — neutral gains the same bare-default machinery as the semantic hues (900 in light, 200 in dark, auto-derived contrast text). `Button`'s filled-neutral now uses the token pair instead of hand-picked rungs + hardcoded `text-white`/`dark:` inversions (its light-mode per-color border classes were also removed — dead code, always beaten by the universal `border-black/25` edge; the live color-matched `dark:border-*` classes remain).
64
+ - **Muted/placeholder/disabled text — one token source, no dark-mode bypasses** — `--color-text-placeholder` and `--color-text-muted` are now alpha-derived from `--color-text-primary` via `color-mix` (40% / 57% light, 40% / 50% dark), so they automatically track the theme's text color in both modes and on any surface. The ~30 hardcoded `dark:text-[var(--color-neutral-N)]` / `dark:placeholder:text-[var(--color-neutral-500)]` classes scattered across forms, CommandPalette, Calendar, Message, Pagination, Sidebar and the date/time pickers are removed — they bypassed the tokens and pinned dark text to neutral ramp rungs, which broke preset themes (an Iris dark placeholder rendered slate-blue; same disease as the Segmented fix below). Dark `--color-text-disabled` is now `neutral-600` (the value every picker was overriding to) instead of `neutral-400`. Visual deltas in the default theme are minor: dark helper text slightly dimmer, dark input icons slightly brighter (the two camps now share one muted value), dark disabled text dimmer.
65
+ - **`Table` — smaller row-expand toggle** — The data-driven expand/collapse control was a full 32px outlined `Button` (form-control height), which read as oversized against row content. It's now a compact ~24px borderless ghost icon button (`variant="ghost"`, `size-6`), matching the conventional table expand affordance. Behavior and a11y labels are unchanged.
66
+ - **`--color-success` default is now the `-600` step** (was `-500`) — matches danger/warning, and the auto-derived white `-contrast` text now passes WCAG AA on filled success surfaces (white on success-500 was ~2.7:1). Filled success Badges/Alerts/Toasts render a slightly darker teal; the full 50–950 ramp is unchanged.
67
+ - **Dark glass gradients moved onto the surface ladder** — `--glass-gradient-outer/inner` dark values now reference `--surface-1/3/4` instead of the deprecated `--color-background-secondary/tertiary` aliases (visually near-identical), so the aliases' scheduled removal can't break `GlassEffect` in dark mode.
68
+ - **`InputOTP` rebuilt around a single native input** — The control was N separate `Input` elements; it is now one invisible native input overlaying the visual slots. This fixes paste-with-separators truncation (`123-456` no longer loses characters) and caret drift, and is what makes the new `charset` prop able to drive sanitizer, `pattern` and `inputMode` from one place. Public API is otherwise unchanged.
69
+ - **`Slider` — drag tooltip rebuilt on the shared `Tooltip`** — The bespoke SVG liquid-lens filter and custom drag bubble are replaced by the shared `Tooltip` (in its new controlled mode, with `recalcTrigger` so the tooltip follows the dragged thumb). The solid glass-look thumb styling moved into the theme file, so it's overridable like every other component's.
70
+ - **`Link` — primary variant tints from the base `--color-primary` token** — Was pinned to the fixed `-600`/`-300` rungs, so it ignored whatever rung a theme parks the token at. Under every shipped preset this resolves to `primary-600` in light — identical to before — and one rung deeper in dark. The default Neutral theme, where primary aliases the mono ramp, renders a darker link than before. The animated underline is also offset 1px so it clears descenders.
71
+ - **Form dropdowns — one option treatment across `Select` / `Combobox` / `Mention` / `InputTag`** — Combobox and InputTag rendered full-bleed square option rows while Select and Mention rendered inset rounded ones. All four already shared `formsBaseTheme.dropdownStyles`; the base simply withheld the two classes the treatment needs, so each call site re-decided it and two got it wrong. The `p-1` container inset and the option's `rounded-[var(--radius-base)]` now live in the shared base — which already assumed this treatment, since it sets `gap-0.5` between rows and draws an inset hairline ring on hover, neither of which reads correctly on a square full-bleed row.
72
+ - **Press/hover feedback consolidated into one shared module** — `src/components/core/shared/interaction.animations.ts` (`createPressVariants` + press/release/hover transitions) is now the single source for Button, Pill and Badge; `Pill.animations.ts` is removed. Press-down is a fast ~80ms tween (feedback must be near-instant), release a stiff spring with slight overshoot. `Alert`, `DatePicker` and `SelectableCard` also drop their one-off transitions for the shared spring presets.
73
+
74
+ ### Removed
75
+
76
+ - **Unused internal theme tokens** — deleted from `theme.css`; never consumed by any component nor documented: `--form-focus-ring-*`, `--form-outline-*`, `--glass-layer-*`, `--segmented-active-bg/-shadow`, `--chat-bubble-border-*`, all `--carousel-*`, the dead `--popover-*` set (shadow, border-width, backdrop-opacity, offsets, max-widths, paddings — `--popover-radius` stays), `--nav-item-min-h/-px/-py` (`--nav-item-radius` stays), the `--shadow-color-*` presets, and `--font-cursive` (its font was only ever loaded inside Storybook).
77
+
78
+ ### Fixed
79
+
80
+ - **`PromptInput` — the invalid focus ring now uses the shared `--color-danger` token** — Its invalid state drew the `ring-4` glow from `--color-danger-500` in light mode, while every other form control (via `formsBaseTheme.states.invalid`) uses `--color-danger` (the 600 rung). Dark mode already agreed on both sides (`--color-danger-500` at 20%), so the two disagreed *only* in light — and the inset danger border on the very same line already used `--color-danger`, making the rule internally inconsistent as well. The light ring is now marginally deeper red and consistent with Input/Select/Textarea/OTP. No API change; the `dark:` value is untouched. Regression test added. This also lets the component share the Figma kit's single `Rings/Invalid` effect style instead of needing a one-off.
81
+ - **`Segmented` — `size="lg"` now steps its label up to 16px** — Segmented's box tokens are straight aliases of the shared form ramp (`--segmented-min-h-*` → `--form-min-h-*`), but its type was pinned to `text-sm` at **all three** sizes, so `lg` grew its height and padding while the label stayed at 14px — out of step with Button and Input, which both step 14px → 16px at `lg`. `lg` labels now render at 16px/24px like every other large control. **The control's height is unchanged** (still 40px; the taller line-height fits inside the existing `min-h`), so this is a type fix, not a layout shift. `sm` and `md` are untouched. The Figma design kit's `Segmented item` `lg` variants were re-pushed to match. Regression test added.
82
+ - **Dead props — five public props were accepted and typed but never read** — each silently did nothing when passed. All five are now implemented, with regression tests:
83
+ - **`ScatterPlot` — `legend`** — inherited from `StandardChartDisplayProps` but never destructured, so the legend was hardcoded to always-render-at-bottom and every value (`"top"`, `"bottom"`, `"none"`) did nothing. It now honours all three, resolved through the same shared `resolveLegendPosition` every other chart uses, satisfying the documented contract that ScatterPlot renders the shared `ChartLegend` from `legend`. **Behavior change:** an omitted `legend` now resolves to `"bottom"` for multi-category data and `"none"` for single-category — so a single-category scatter no longer shows a one-item legend by default. Pass `legend="bottom"` to keep it.
84
+ - **`Modal` — `darkMode`** — documented as applying the `dark` class to the container, but never destructured, so it fell through `...props` into `Overlay` (which doesn't declare it either) and dead-ended. It now applies `dark` to the modal container, matching the existing `Input`/`BarChart`/`LollipopChart` implementations of the same prop.
85
+ - **`Sidebar.Toggle` — `expandIcon` / `collapseIcon`** — destructured but unused; the toggle always rendered its hardcoded chevron. Both are now wired, falling back to the default chevron when omitted. Semantics are **action-based**, matching the button's own aria-label: `expandIcon` shows while the sidebar is *collapsed* (clicking expands), `collapseIcon` while *expanded*. A custom icon renders as-is — the default chevron's 180° flip is only applied to the chevron itself. The JSDoc, which described the opposite (state-based) meaning, was corrected.
86
+ - **`InputAddress` — `showCountrySelector` / `showPostalCode`** — typed but never read (the component has no rest spread, so they dead-ended entirely). Both now hide their field. Because the fields render as one merged perimeter, the radii are position-aware: the last visible field carries the bottom corners, and a lone bottom field spans the full row.
87
+ - **`ScatterPlot` — `gridClassName`** — destructured but unused, while `svgClassName`/`dotClassName`/`axisClassName` all worked. It now styles the grid lines (plumbed through the shared `YAxis`, which draws ScatterPlot's grid), matching `AreaChart`'s existing `gridClassName`.
88
+ - **`tailwind.preset.cjs` — `bg-primary` now matches component colors** — Each semantic color's `DEFAULT` was pinned to a fixed rung (`primary-600`, `success-500`, …), so consumer shorthands like `bg-primary` resolved to a different color than the library's own components (which paint the bare `--color-primary` base — `-900` in the monochrome base theme, `-600` in a colored theme). DEFAULTs now point at the bare `var(--color-*)` base, so `bg-primary` equals what components render and follows the active theme and dark mode. Also pruned deprecated `background-quaternary/quinary` maps, added the surface ladder + `border-secondary`/`border-hover`, and corrected the `--form-radius`/`--button-radius` token names. The `@flikk/ui/theme.css` v4 entry's broken `dist` relative import and a stale `--form-rounded` token in `shadcn-compat.css` were fixed too.
89
+ - **Dark-mode active scrollbar thumb color** — `--ui-scrollbar-thumb-active` used invalid mixed rgb syntax (`rgb(75 85 99, 0.75)`), so the declaration failed at computed-value time and the active thumb lost its intended dark tint. Now `rgb(75 85 99 / 0.75)`.
90
+ - **`Badge` — `iconStart` no longer hugs the edge** — the icon wrapper applied a `-ml-1` optical tuck unconditionally, which cancelled the regular badge's 4px padding and left the icon ~1px from the border. The tuck is now pill-only (pills have the extra `pillSizes` padding to absorb it), mirroring the avatar slot's existing pill/non-pill conditional. Badge width with text-only content is unchanged.
91
+ - **`PromptInput` — model-menu icon stacked above the label** — The model selector passed its icon inside `Dropdown.Item` children, where MenuItem's block-level `truncate` label span (plus Tailwind preflight's `svg { display: block }`) broke it onto its own line. The icon now goes through the proper `startContent` slot and renders inline with the label.
92
+ - **`Dropdown` — menu gets a `max-w-[20rem]` cap** — A long item label stretched the menu unboundedly (MenuItem's `truncate` could never engage without a width bound). Long labels now ellipsize at 320px.
93
+ - **`Dropdown.Trigger` — no longer overrides a `Button` trigger's styling** — The trigger injected a translucent `surface-hover` tint (on hover, and while the menu is open) onto whatever it wrapped. For a *filled* `Button` — which hovers via a `brightness` filter, not a `hover:bg-*` — that tint had nothing to override and instead replaced the solid fill, so a filled trigger (e.g. the chevron half of a filled split button) went see-through/dark on hover and mismatched its sibling. The tint is now skipped for `Button` children (Buttons are self-styled and bring their own hover/active/variant states); plain/custom trigger elements still get it. Fixes the `ButtonGroup` "Split Button" filled example.
94
+ - **`Calendar` — consistent selected & hover styling across single/range modes** — Range start/end days had their own fill/text rules and no hover override, so hovering an endpoint fell through to the generic neutral day-hover (a muddy grey with poor contrast) and looked different from a single-selected day. Endpoints now route through `data-selected`, inheriting the exact same fill, text, top-border, and hover as a single-selected cell (one source of truth for "a selected day"). In-range (between) days no longer carry a bespoke hover either — they use the same base day-hover as normal days, so a hovered cell looks identical whether or not it sits inside a range.
95
+ - **`Table` — jerk at the end of row collapse** — Expanding rows use a height-animating container inside a full-width colspan `<td>`. That cell was picking up ~20px of vertical padding from the table's `[&_td]:py-*` descendant rule (which out-specifies the cell's own `p-0`), so the cell held a ~21px residual height after the animator had already collapsed to 0 — then snapped to 0 when the row unmounted, jerking the rows below. The expanded cell now forces `!p-0` so it tracks the animator down to ~0 (mirrors Accordion, where the animating container carries no padding and the inner content owns it). Padding for expanded content is owned by `expandedRowRender`, as before.
96
+ - **`Segmented` — dark-mode background no longer collides with consumer utilities** — The theme hardcoded raw Tailwind classes (`bg-neutral-100 dark:bg-neutral-900` on the track, `dark:bg-neutral-800` on the sliding indicator). These emit global class names that a consumer's own `bg-neutral-*` utility could override by source order, permanently pinning the control's background to one tone regardless of the `.dark` class. The track now paints from `--color-surface-sunken` and the indicator from `--color-surface` (theme-aware CSS variables, no `dark:` variants), so it follows the theme correctly and can't collide. Visually unchanged. (PER-292)
97
+ - **`Avatar` — status dot stranded outside the circle** — The dot was corner-anchored (`left-0 bottom-0`), but an avatar is a *circle*: its bounding-box corner sits ~41% further from the centre than the edge does, so the dot floated off the arc. It now centres on the circle's 45° point via one proportional rule (`left-[14.6%] bottom-[14.6%]` plus half-translates), which holds at every size including the new arbitrary numeric ones. Three further fixes fell out of the same pass: **(1)** the ring was a flat 2px at every rung, making it proportionally 3.3× heavier on `xs` than `xl` — dot and ring now ramp together, holding the badge's total footprint near 30% of the avatar across the ladder (was 42%→25%); **(2)** the `offline` dot moved off `--color-text-muted` — the text tokens are `color-mix` alpha derivations, so as a *fill* the dot went translucent and the photo showed through; it now uses `--color-mono-500`, the only rung clearing WCAG 1.4.11's 3:1 against its ring in **both** modes; **(3)** `isolate` added to the circle, since `relative` with `z-index: auto` creates no stacking context, so the contents' `z-10` escaped and painted over the sibling status dot.
98
+ - **`Select` — `searchPlaceholder` was ignored** — The prop was declared and documented, but the search input hardcoded `"Search..."`, trapping a user-facing string (every built-in visible string must be overridable). It's now threaded through the Select context to the input. The default was inconsistent too — `SelectProps` documented `"Search..."` while the implementation defaulted to `"Search options..."`; both are `"Search..."` now. This is also what `InputAddress`'s new `showCountrySelector` depended on, since it was already passing `searchPlaceholder` to the country Select.
99
+ - **`Message` — system bubble radius bypassed the surface cap** — It derived from a bare `calc()` on `--radius-base`. It's a tiny, tight-padding chip, so it now takes `--surface-radius-cap-xs`; without the cap, a theme chasing pill controls at a large base rounded the corners past what the bubble's own padding could absorb.
100
+ - **`Metric` — `label` is now optional** — It was required with no reason to be; a metric can legitimately render a value alone. The generative schema is regenerated to match.
101
+ - **Generative — `registry.tsx` was missing `"use client"`** — It renders JSX with a real event handler (Calendar's `render` wraps the underlying `onChange`) but carried no directive, a genuine gap under the RSC deep-import rule. Separately, the `audit-use-client` script's browser-global heuristic was flagging `schema.generated.ts` on the literal word "navigator" inside an unrelated description string; that file is pure JSON-shaped data and is now excluded from the audit rather than given a directive the generator would strip on the next run.
102
+ - **Generative schema was stale for `InputOTP`** — The new `size` prop landed without a `yarn build:generative` regen, so the committed schema still advertised OTP without it and an LLM had no way to emit a sized OTP. Regenerated and committed as part of this release.
103
+ - **`Calendar` — focus rings clipped by the height animation** — The days grid is inside a container animating height with `overflow: hidden`, which cropped the focus ring on edge cells. The grid is now padded so the ring clears. An unused `navButtonStyle` theme key was also removed.
104
+
8
105
  ## [1.0.0-beta.30] - 2026-07-04
9
106
 
10
107
  ### Breaking Changes
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { AgentStatusProps } from "./AgentStatus.types";
3
+ export declare const AgentStatus: React.ForwardRefExoticComponent<AgentStatusProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,144 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import React__default, { useMemo, useId, useState, useEffect } from 'react';
4
+ import { CaretRight } from '@phosphor-icons/react';
5
+ import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
6
+ import { cn } from '../../../utils/cn.js';
7
+ import { useElapsedTime } from '../../../hooks/useElapsedTime.js';
8
+ import { Shimmer } from '../../effects/Shimmer/Shimmer.js';
9
+ import { AIStatusIndicator } from '../shared/StatusIndicator.js';
10
+ import { createTriggerIconVariants, accordionAnimations, accordionContentAnimations } from '../../core/Accordion/Accordion.animations.js';
11
+ import { agentStatusTheme } from './AgentStatus.theme.js';
12
+
13
+ const formatDuration = (duration) => {
14
+ const safe = Math.max(0, duration);
15
+ // Round once, up front. Rounding the minutes and seconds halves independently
16
+ // lets a value like 119.7 render as "1m 60s".
17
+ const rounded = safe < 60 ? Math.round(safe * 10) / 10 : Math.round(safe);
18
+ if (rounded < 60) {
19
+ return `${rounded.toFixed(Number.isInteger(rounded) ? 0 : 1)}s`;
20
+ }
21
+ return `${Math.floor(rounded / 60)}m ${rounded % 60}s`;
22
+ };
23
+ // The indicator + shimmering label + duration, without a root element. Both the
24
+ // standalone status row (a <div role="status">) and the reasoning summary (a
25
+ // phrasing <span> inside the trigger <button>) render this, so the visual row is
26
+ // identical while each host picks a content-model-valid wrapper — a <div> may not
27
+ // nest inside a <button>.
28
+ const StatusRowInner = ({ theme, status, label, isActive, indicator, icon, wrap, activeSuffix, shimmerDuration, shimmerSpread, shimmerColor, shimmerHighlightColor, shownDuration, }) => {
29
+ const labelClass = cn(theme.labelStyle, wrap ? "" : "truncate");
30
+ return (jsxs(Fragment, { children: [indicator && (jsx("span", { className: theme.iconStyle, "aria-hidden": "true", children: icon !== null && icon !== void 0 ? icon : (jsx(AIStatusIndicator, { state: status, className: theme.indicatorStyles[status] })) })), isActive ? (jsx(Shimmer, { active: true, duration: shimmerDuration, spread: shimmerSpread, color: shimmerColor, highlightColor: shimmerHighlightColor, className: labelClass, children: jsxs(Fragment, { children: [label, activeSuffix] }) })) : (jsx("span", { className: labelClass, children: label })), shownDuration !== undefined && (
31
+ // aria-hidden: inside an aria-atomic live region a ticking timer would
32
+ // re-announce the whole label on every tick.
33
+ jsx("span", { className: theme.durationStyle, "aria-hidden": "true", children: formatDuration(shownDuration) }))] }));
34
+ };
35
+ const AgentStatus = React__default.forwardRef(({ mode = "status", status = "active", label, duration, startedAt, icon, indicator, wrap = false, activeSuffix = "…", shimmerDuration = 2, shimmerSpread = 16, shimmerColor = "color-mix(in oklab, var(--color-text-muted) 75%, transparent)", shimmerHighlightColor = "var(--color-text-primary)", live = "polite", steps, children, open, defaultOpen = false, onOpenChange, divider = true, className, theme: themeOverrides, ...rest }, ref) => {
36
+ // All hooks run unconditionally, before the mode branch.
37
+ const theme = useMemo(() => ({
38
+ ...agentStatusTheme,
39
+ ...themeOverrides,
40
+ stateStyles: {
41
+ ...agentStatusTheme.stateStyles,
42
+ ...themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.stateStyles,
43
+ },
44
+ indicatorStyles: {
45
+ ...agentStatusTheme.indicatorStyles,
46
+ ...themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.indicatorStyles,
47
+ },
48
+ }), [themeOverrides]);
49
+ const isReasoning = mode === "reasoning";
50
+ const isActive = status === "active";
51
+ // Ticks while active, freezes on settle. An explicit `duration` wins outright, so
52
+ // don't read the clock at all in that case — passing `startedAt` anyway would leave
53
+ // an interval re-rendering this row 10x/second only to discard every reading.
54
+ const ticked = useElapsedTime(duration === undefined ? startedAt : undefined, {
55
+ active: isActive,
56
+ });
57
+ const shownDuration = duration !== null && duration !== void 0 ? duration : ticked;
58
+ // A status row always carries an indicator; a reasoning summary drops it once
59
+ // settled, because the chevron carries the affordance from there. Either default
60
+ // yields to an explicit `indicator`, and a custom `icon` opts back in — you only
61
+ // pass an icon in order to see it.
62
+ const showIndicator = indicator !== null && indicator !== void 0 ? indicator : (isReasoning ? isActive || icon !== undefined : true);
63
+ const reactId = useId();
64
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
65
+ const shouldReduceMotion = useReducedMotion();
66
+ const isControlled = open !== undefined;
67
+ const hasOnOpenChange = onOpenChange !== undefined;
68
+ const hasSteps = steps !== undefined;
69
+ const hasChildren = children !== undefined;
70
+ // Dev warnings belong in an effect, not the render body: `startedAt` re-renders this
71
+ // component ten times a second, and a render-body warning reprints on every tick.
72
+ // The deps are booleans on purpose — depending on `steps`/`children`/`onOpenChange`
73
+ // directly would re-fire on every parent render and bring the flood back.
74
+ useEffect(() => {
75
+ if (process.env.NODE_ENV === "production" || !isReasoning)
76
+ return;
77
+ /* eslint-disable no-console */
78
+ if (isControlled && defaultOpen) {
79
+ console.warn("[AgentStatus]: both `open` and `defaultOpen` were provided — `open` (controlled) wins.");
80
+ }
81
+ if (isControlled && !hasOnOpenChange) {
82
+ console.warn("[AgentStatus]: `open` was provided without `onOpenChange`, so the reasoning block can never be toggled. Pass `defaultOpen` for uncontrolled usage.");
83
+ }
84
+ if (hasSteps && hasChildren) {
85
+ console.warn("[AgentStatus]: both `steps` and `children` were provided — `steps` takes precedence.");
86
+ }
87
+ /* eslint-enable no-console */
88
+ }, [
89
+ isReasoning,
90
+ isControlled,
91
+ defaultOpen,
92
+ hasOnOpenChange,
93
+ hasSteps,
94
+ hasChildren,
95
+ ]);
96
+ // Shimmer + theme config shared with the nested rows a reasoning block renders.
97
+ // Memoized so a ticking summary duration doesn't churn the step list's props.
98
+ const sharedRowProps = useMemo(() => ({
99
+ activeSuffix,
100
+ shimmerDuration,
101
+ shimmerSpread,
102
+ shimmerColor,
103
+ shimmerHighlightColor,
104
+ theme: themeOverrides,
105
+ }), [
106
+ activeSuffix,
107
+ shimmerDuration,
108
+ shimmerSpread,
109
+ shimmerColor,
110
+ shimmerHighlightColor,
111
+ themeOverrides,
112
+ ]);
113
+ // steps => structured list of rows; otherwise raw children (prose / markdown
114
+ // / mixed). Memoized so it survives the 100ms duration ticks while active —
115
+ // only the summary row's duration should re-render, not the whole step list.
116
+ const reasoningBody = useMemo(() => {
117
+ if (steps) {
118
+ return (jsx("ol", { className: theme.stepsStyle, children: steps.map((step, index) => {
119
+ var _a, _b;
120
+ return (jsx("li", { className: theme.stepItemStyle, children: jsx(AgentStatus, { mode: "status", status: (_a = step.status) !== null && _a !== void 0 ? _a : "complete", label: step.label, duration: step.duration, wrap: true, live: "off", ...sharedRowProps }) }, (_b = step.id) !== null && _b !== void 0 ? _b : index));
121
+ }) }));
122
+ }
123
+ return children !== undefined ? (jsx("div", { className: theme.proseStyle, children: children })) : null;
124
+ }, [steps, children, theme, sharedRowProps]);
125
+ // ===== STATUS MODE: a single activity row =====
126
+ if (!isReasoning) {
127
+ return (jsx("div", { ref: ref, role: "status", "aria-live": live, "aria-atomic": "true", "data-state": status, className: cn(theme.baseStyle, theme.stateStyles[status], className), ...rest, children: jsx(StatusRowInner, { theme: theme, status: status, label: label, isActive: isActive, indicator: showIndicator, icon: icon, wrap: wrap, activeSuffix: activeSuffix, shimmerDuration: shimmerDuration, shimmerSpread: shimmerSpread, shimmerColor: shimmerColor, shimmerHighlightColor: shimmerHighlightColor, shownDuration: shownDuration }) }));
128
+ }
129
+ // ===== REASONING MODE: a collapsible disclosure of the same rows =====
130
+ const contentId = `${reactId}-reasoning`;
131
+ const triggerId = `${contentId}-trigger`;
132
+ const isOpen = isControlled ? open : uncontrolledOpen;
133
+ const instantTransition = shouldReduceMotion ? { duration: 0 } : undefined;
134
+ const toggle = () => {
135
+ const next = !isOpen;
136
+ if (!isControlled)
137
+ setUncontrolledOpen(next);
138
+ onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
139
+ };
140
+ return (jsxs("div", { ref: ref, "data-state": isOpen ? "open" : "closed", className: cn(theme.reasoningRootStyle, className), ...rest, children: [jsx("button", { id: triggerId, type: "button", className: theme.triggerStyle, "aria-expanded": isOpen, "aria-controls": isOpen ? contentId : undefined, onClick: toggle, children: jsxs("span", { className: theme.triggerContentStyle, children: [jsx("span", { className: cn(theme.baseStyle, theme.stateStyles[status]), "aria-live": live, "aria-atomic": "true", children: jsx(StatusRowInner, { theme: theme, status: status, label: label, isActive: isActive, indicator: showIndicator, icon: icon, wrap: false, activeSuffix: activeSuffix, shimmerDuration: shimmerDuration, shimmerSpread: shimmerSpread, shimmerColor: shimmerColor, shimmerHighlightColor: shimmerHighlightColor, shownDuration: shownDuration }) }), jsx(motion.span, { className: theme.chevronStyle, initial: false, animate: isOpen ? "open" : "closed", variants: createTriggerIconVariants(90), transition: instantTransition, "aria-hidden": "true", children: jsx(CaretRight, { className: "size-full" }) })] }) }), divider && jsx("div", { className: theme.dividerStyle, "aria-hidden": "true" }), jsx(AnimatePresence, { initial: false, children: isOpen && (jsx(motion.div, { id: contentId, role: "region", "aria-labelledby": triggerId, className: theme.contentStyle, "data-state": "open", initial: "collapsed", animate: "open", exit: "collapsed", variants: accordionAnimations, transition: instantTransition, children: jsx(motion.div, { className: theme.contentInnerStyle, initial: "collapsed", animate: "open", exit: "collapsed", variants: accordionContentAnimations, transition: instantTransition, children: reasoningBody }) })) })] }));
141
+ });
142
+ AgentStatus.displayName = "AgentStatus";
143
+
144
+ export { AgentStatus };
@@ -0,0 +1,2 @@
1
+ import type { AgentStatusTheme } from "./AgentStatus.types";
2
+ export declare const agentStatusTheme: AgentStatusTheme;
@@ -0,0 +1,37 @@
1
+ const agentStatusTheme = {
2
+ baseStyle: "inline-flex min-w-0 items-center gap-2 text-sm",
3
+ iconStyle: "flex size-4 shrink-0 items-center justify-center",
4
+ // truncate is applied at the call site (only when `wrap` is off) so steps can wrap.
5
+ labelStyle: "min-w-0 font-medium",
6
+ durationStyle: "shrink-0 text-sm tabular-nums text-[var(--color-text-muted)]",
7
+ stateStyles: {
8
+ idle: "text-[var(--color-text-muted)]",
9
+ active: "text-[var(--color-text-secondary)]",
10
+ complete: "text-[var(--color-text-muted)]",
11
+ pending: "text-[var(--color-text-placeholder)]",
12
+ error: "text-[var(--color-danger)]",
13
+ },
14
+ indicatorStyles: {
15
+ idle: "text-[var(--color-text-muted)]",
16
+ active: "text-[var(--color-primary)]",
17
+ complete: "text-[var(--color-success)]",
18
+ pending: "text-[var(--color-text-placeholder)]",
19
+ error: "text-[var(--color-danger)]",
20
+ },
21
+ // --- reasoning mode: borderless inline disclosure ---
22
+ reasoningRootStyle: "w-full min-w-0",
23
+ triggerStyle: "flex w-full items-center py-2 text-left transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--color-primary)]",
24
+ triggerContentStyle: "inline-flex min-w-0 items-center gap-1.5",
25
+ chevronStyle: "inline-flex size-3.5 shrink-0 items-center justify-center text-[var(--color-text-muted)]",
26
+ dividerStyle: "h-px w-full bg-[var(--color-border)]",
27
+ contentStyle: "w-full min-w-0 overflow-hidden",
28
+ contentInnerStyle: "w-full min-w-0 pt-3",
29
+ stepsStyle: "space-y-2",
30
+ stepItemStyle: "min-w-0",
31
+ // Raw children (prose / markdown / mixed). flex-col so any child — a <p>, a
32
+ // MarkdownRenderer, or an inline-flex AgentStatus row — stacks vertically; the
33
+ // gap lives on the container, so it survives child margin resets.
34
+ proseStyle: "flex flex-col gap-3 text-sm leading-relaxed text-[var(--color-text-secondary)] [&_p]:m-0",
35
+ };
36
+
37
+ export { agentStatusTheme };
@@ -0,0 +1,116 @@
1
+ import React from "react";
2
+ export type AgentStatusState = "idle" | "active" | "complete" | "pending" | "error";
3
+ /**
4
+ * Presentation mode. `status` is a single activity row; `reasoning` turns that
5
+ * same row into a collapsible disclosure whose body holds steps and/or prose.
6
+ * The two axes are independent — a `reasoning` block is itself `active`,
7
+ * `complete`, etc.
8
+ */
9
+ export type AgentStatusMode = "status" | "reasoning";
10
+ /** A single reasoning step — a serializable AgentStatus row. */
11
+ export interface AgentStatusStepData {
12
+ id?: React.Key;
13
+ label: React.ReactNode;
14
+ status?: AgentStatusState;
15
+ /** Elapsed or final step duration in seconds. */
16
+ duration?: number;
17
+ }
18
+ export interface AgentStatusTheme {
19
+ baseStyle: string;
20
+ iconStyle: string;
21
+ labelStyle: string;
22
+ durationStyle: string;
23
+ stateStyles: Record<AgentStatusState, string>;
24
+ indicatorStyles: Record<AgentStatusState, string>;
25
+ reasoningRootStyle: string;
26
+ triggerStyle: string;
27
+ triggerContentStyle: string;
28
+ chevronStyle: string;
29
+ dividerStyle: string;
30
+ contentStyle: string;
31
+ contentInnerStyle: string;
32
+ stepsStyle: string;
33
+ stepItemStyle: string;
34
+ proseStyle: string;
35
+ }
36
+ export interface AgentStatusThemeOverrides extends Omit<Partial<AgentStatusTheme>, "stateStyles" | "indicatorStyles"> {
37
+ stateStyles?: Partial<AgentStatusTheme["stateStyles"]>;
38
+ indicatorStyles?: Partial<AgentStatusTheme["indicatorStyles"]>;
39
+ }
40
+ export interface AgentStatusProps extends React.HTMLAttributes<HTMLDivElement> {
41
+ /** Single status row (default) or a collapsible reasoning disclosure. @default "status" */
42
+ mode?: AgentStatusMode;
43
+ /** Current execution state. Active labels shimmer; settled labels are static. */
44
+ status?: AgentStatusState;
45
+ /** Human-readable activity, for example "Thinking" or "Searching sources". */
46
+ label: React.ReactNode;
47
+ /**
48
+ * Elapsed or final duration in seconds. Takes precedence over `startedAt`, so
49
+ * pass it when the duration is authoritative (for example, returned by the server).
50
+ */
51
+ duration?: number;
52
+ /**
53
+ * Epoch milliseconds the activity began. The duration then ticks on its own
54
+ * while `status` is `"active"` and freezes the moment it settles — no timer
55
+ * wiring in the consumer. Ignored when `duration` is supplied.
56
+ */
57
+ startedAt?: number;
58
+ /** Optional icon. When omitted, the animated semantic indicator is rendered. */
59
+ icon?: React.ReactNode;
60
+ /**
61
+ * Show the leading status indicator (or custom `icon`). Set `false` for an
62
+ * icon-less, text-only row — the label then sits flush left.
63
+ *
64
+ * Defaults differ by mode: a `status` row always shows one, while a `reasoning`
65
+ * summary shows one only while active (the chevron carries the affordance once
66
+ * settled) — unless an `icon` is supplied, which opts back in. Pass explicitly
67
+ * to override either default.
68
+ * @default true in `status` mode; active-only in `reasoning` mode
69
+ */
70
+ indicator?: boolean;
71
+ /**
72
+ * Let the label wrap onto multiple lines instead of truncating. Steps render
73
+ * with this on; the standalone/summary row truncates by default.
74
+ * @default false
75
+ */
76
+ wrap?: boolean;
77
+ /** Text appended while active. @default "…" */
78
+ activeSuffix?: React.ReactNode;
79
+ /** Active shimmer cycle duration in seconds. @default 2 */
80
+ shimmerDuration?: number;
81
+ /** Width of the active shimmer highlight band. @default 16 */
82
+ shimmerSpread?: number;
83
+ /** Base color for the active shimmer text. */
84
+ shimmerColor?: string;
85
+ /** Highlight color for the active shimmer sweep. */
86
+ shimmerHighlightColor?: string;
87
+ /**
88
+ * Accessible announcement behavior. `"polite"` waits for a pause rather than
89
+ * interrupting, which is what a background activity warrants.
90
+ * @default "polite"
91
+ */
92
+ live?: "off" | "polite" | "assertive";
93
+ /**
94
+ * Structured reasoning steps. Rendered as a list of AgentStatus rows.
95
+ * Ignored unless `mode="reasoning"`.
96
+ */
97
+ steps?: AgentStatusStepData[];
98
+ /**
99
+ * Free-form reasoning body — prose, a `<MarkdownRenderer>`, or a mix of prose
100
+ * and `<AgentStatus>` rows. Rendered raw (not wrapped in a list), so paragraphs
101
+ * are valid. `steps` takes precedence when both are supplied.
102
+ */
103
+ children?: React.ReactNode;
104
+ /** Controlled expanded state (reasoning mode). */
105
+ open?: boolean;
106
+ /** Initial expanded state for uncontrolled reasoning usage. @default false */
107
+ defaultOpen?: boolean;
108
+ onOpenChange?: (open: boolean) => void;
109
+ /**
110
+ * Render the full-width hairline under the reasoning trigger.
111
+ * @default true
112
+ */
113
+ divider?: boolean;
114
+ className?: string;
115
+ theme?: AgentStatusThemeOverrides;
116
+ }
@@ -0,0 +1,3 @@
1
+ export { AgentStatus } from "./AgentStatus";
2
+ export { agentStatusTheme } from "./AgentStatus.theme";
3
+ export type { AgentStatusProps, AgentStatusState, AgentStatusMode, AgentStatusStepData, AgentStatusTheme, AgentStatusThemeOverrides, } from "./AgentStatus.types";
@@ -3,7 +3,7 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import React__default, { useState, useMemo, useCallback, useRef } from 'react';
4
4
  import { Prism } from 'react-syntax-highlighter';
5
5
  import { oneDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
6
- import { DocumentTextIcon, DocumentCheckIcon, DocumentDuplicateIcon } from '@heroicons/react/24/outline';
6
+ import { FileText, ListChecks, Copy } from '@phosphor-icons/react';
7
7
  import { codeBlockTheme } from './CodeBlock.theme.js';
8
8
  import { LanguageIcon } from './LanguageIcon.js';
9
9
  import { cn } from '../../../utils/cn.js';
@@ -177,7 +177,7 @@ const CodeBlock = React__default.forwardRef(({ children, language = "text", show
177
177
  // `lineProps` starts counting from line 1 every time, regardless of
178
178
  // `showLineNumbers`.
179
179
  lineCounterRef.current = 0;
180
- return (jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), ...props, children: [showHeader && (jsxs("div", { className: mergedTheme.header, children: [jsx("div", { className: mergedTheme.headerLeft, children: filename && (jsxs(Fragment, { children: [jsx(DocumentTextIcon, { className: "size-4 text-[var(--color-text-muted)]" }), jsx("span", { className: mergedTheme.filename, children: filename })] })) }), jsxs("div", { className: mergedTheme.headerRight, children: [showLanguage && (jsxs("div", { className: "flex items-center gap-2", children: [jsx(LanguageIcon, { language: language, className: "size-4" }), jsx("span", { className: mergedTheme.languageLabel, children: displayLanguage })] })), copyable && (jsx("button", { onClick: handleCopy, className: cn(mergedTheme.copyButton, copied && mergedTheme.copySuccess), "aria-label": copied ? "Copied!" : "Copy code", title: copied ? "Copied!" : "Copy code", children: copied ? (jsx(DocumentCheckIcon, { className: "size-4" })) : (jsx(DocumentDuplicateIcon, { className: "size-4" })) }))] })] })), jsx("div", { className: mergedTheme.codeWrapper, style: {
180
+ return (jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), ...props, children: [showHeader && (jsxs("div", { className: mergedTheme.header, children: [jsx("div", { className: mergedTheme.headerLeft, children: filename && (jsxs(Fragment, { children: [jsx(FileText, { className: "size-4 text-[var(--color-text-muted)]" }), jsx("span", { className: mergedTheme.filename, children: filename })] })) }), jsxs("div", { className: mergedTheme.headerRight, children: [showLanguage && (jsxs("div", { className: "flex items-center gap-2", children: [jsx(LanguageIcon, { language: language, className: "size-4" }), jsx("span", { className: mergedTheme.languageLabel, children: displayLanguage })] })), copyable && (jsx("button", { onClick: handleCopy, className: cn(mergedTheme.copyButton, copied && mergedTheme.copySuccess), "aria-label": copied ? "Copied!" : "Copy code", title: copied ? "Copied!" : "Copy code", children: copied ? (jsx(ListChecks, { className: "size-4" })) : (jsx(Copy, { className: "size-4" })) }))] })] })), jsx("div", { className: mergedTheme.codeWrapper, style: {
181
181
  maxHeight: maxHeight,
182
182
  overflowY: maxHeight ? "auto" : undefined,
183
183
  }, children: jsx(Prism, { language: language, style: syntaxTheme === "dark" ? oneDark : oneLight, showLineNumbers: showLineNumbers, wrapLines: true, wrapLongLines: wrapLines, lineProps: lineProps, lineNumberStyle: {
@@ -192,7 +192,7 @@ const CodeBlock = React__default.forwardRef(({ children, language = "text", show
192
192
  fontSize: "0.875rem",
193
193
  lineHeight: "1.5",
194
194
  background: "transparent",
195
- }, children: code }) }), !showHeader && copyable && (jsx("button", { onClick: handleCopy, className: cn("absolute top-2 right-2", mergedTheme.copyButton, copied && mergedTheme.copySuccess), "aria-label": copied ? "Copied!" : "Copy code", title: copied ? "Copied!" : "Copy code", children: copied ? (jsx(DocumentCheckIcon, { className: "size-4" })) : (jsx(DocumentDuplicateIcon, { className: "size-4" })) }))] }));
195
+ }, children: code }) }), !showHeader && copyable && (jsx("button", { onClick: handleCopy, className: cn("absolute top-2 right-2", mergedTheme.copyButton, copied && mergedTheme.copySuccess), "aria-label": copied ? "Copied!" : "Copy code", title: copied ? "Copied!" : "Copy code", children: copied ? (jsx(ListChecks, { className: "size-4" })) : (jsx(Copy, { className: "size-4" })) }))] }));
196
196
  });
197
197
  CodeBlock.displayName = "CodeBlock";
198
198
 
@@ -6,7 +6,7 @@ const codeBlockTheme = {
6
6
  filename: "text-sm font-medium text-[var(--color-text-secondary)] truncate",
7
7
  languageLabel: "text-xs uppercase tracking-wider font-semibold text-[var(--color-text-muted)]",
8
8
  codeWrapper: "overflow-x-auto",
9
- highlightedLine: " -mx-4 px-4 bg-[var(--color-primary-50)] border-l-2 border-l-[var(--color-primary)] dark:bg-[var(--color-neutral-400)]/5 dark:border-l-[var(--color-neutral-200)]",
9
+ highlightedLine: " -mx-4 px-4 bg-[var(--color-primary-50)] border-l-2 border-l-[var(--color-primary)] dark:bg-[var(--color-mono-400)]/5 dark:border-l-[var(--color-mono-200)]",
10
10
  diffAddition: "-mx-4 px-4 bg-[var(--color-success-50)] border-l-4 border-l-[var(--color-success)] dark:bg-[var(--color-success-600)]/20 dark:border-l-[var(--color-success-700)]",
11
11
  diffDeletion: "-mx-4 px-4 bg-[var(--color-danger-50)] border-l-4 border-l-[var(--color-danger)] dark:bg-[var(--color-danger-600)]/20 dark:border-l-[var(--color-danger-700)]",
12
12
  copyButton: "p-1.5 rounded-[calc(var(--radius-base)*0.75)] text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-surface-hover)] transition-colors cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)]",