@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
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "libVersion": "1.0.0-beta.30",
4
- "generatedAt": "2026-07-04T16:57:54.773Z",
5
- "componentCount": 142,
3
+ "libVersion": "1.0.0-beta.31",
4
+ "generatedAt": "2026-07-31T11:06:30.310Z",
5
+ "componentCount": 147,
6
6
  "components": [
7
7
  {
8
8
  "name": "Accordion",
@@ -60,7 +60,7 @@
60
60
  "cssVariables": [
61
61
  "--color-border",
62
62
  "--form-radius",
63
- "--color-background-secondary",
63
+ "--color-surface",
64
64
  "--color-primary",
65
65
  "--color-text-primary"
66
66
  ],
@@ -160,7 +160,7 @@
160
160
  "description": "A render prop for the footer, which receives a `close` function. Use this to render action buttons."
161
161
  }
162
162
  },
163
- "codeExample": "import { AlertDialog, Button } from \"@flikk/ui\";\nimport { ExclamationTriangleIcon } from \"@heroicons/react/24/solid\";\n\n<AlertDialog\n trigger={<Button color=\"danger\">Delete Account</Button>}\n icon={<ExclamationTriangleIcon className=\"w-6 h-6 text-[var(--color-danger)]\" />}\n title=\"Are you absolutely sure?\"\n subtitle=\"This action cannot be undone. This will permanently delete your account and remove your data from our servers.\"\n footer={(close) => (\n <>\n <Button variant=\"outline\" color=\"neutral\" onClick={close}>\n Cancel\n </Button>\n <Button color=\"danger\" onClick={close}>\n Yes, delete account\n </Button>\n </>\n )}\n/>"
163
+ "codeExample": "import { AlertDialog, Button } from \"@flikk/ui\";\n\n<AlertDialog\n trigger={<Button color=\"danger\">Delete Account</Button>}\n icon={<ExclamationTriangleIcon className=\"w-6 h-6 text-[var(--color-danger)]\" />}\n title=\"Are you absolutely sure?\"\n subtitle=\"This action cannot be undone. This will permanently delete your account and remove your data from our servers.\"\n footer={(close) => (\n <>\n <Button variant=\"outline\" color=\"mono\" onClick={close}>\n Cancel\n </Button>\n <Button color=\"danger\" onClick={close}>\n Yes, delete account\n </Button>\n </>\n )}\n/>"
164
164
  },
165
165
  {
166
166
  "name": "AspectRatio",
@@ -170,7 +170,7 @@
170
170
  "description": "Maintains a consistent width-to-height ratio for its children. Useful for images, videos, maps, and embedded content.",
171
171
  "status": "stable",
172
172
  "productionReady": true,
173
- "generative": false,
173
+ "generative": true,
174
174
  "props": {
175
175
  "ratio": {
176
176
  "type": "number",
@@ -200,14 +200,7 @@
200
200
  "size": {
201
201
  "type": "AvatarSize",
202
202
  "default": "md",
203
- "description": "The size of the avatar",
204
- "options": [
205
- "xs",
206
- "sm",
207
- "md",
208
- "lg",
209
- "xl"
210
- ]
203
+ "description": "The size of the avatar — a named rung (`\"md\"`) or an exact pixel size (`30`). Prefer this over a `className=\"size-[30px]\"` override: the shipped stylesheet only contains the classes used by this library's own source, so an arbitrary size utility resolves to nothing for consumers who don't run Tailwind themselves."
211
204
  },
212
205
  "status": {
213
206
  "type": "AvatarStatus",
@@ -291,7 +284,8 @@
291
284
  },
292
285
  "themeKeys": [
293
286
  "baseStyle",
294
- "sizes",
287
+ "sizeStyle",
288
+ "glyphSizes",
295
289
  "xs",
296
290
  "sm",
297
291
  "md",
@@ -303,6 +297,19 @@
303
297
  "busy",
304
298
  "away",
305
299
  "none",
300
+ "statusPositionStyle",
301
+ "statusSizes",
302
+ "xs",
303
+ "sm",
304
+ "md",
305
+ "lg",
306
+ "xl",
307
+ "verifiedSizes",
308
+ "xs",
309
+ "sm",
310
+ "md",
311
+ "lg",
312
+ "xl",
306
313
  "titleStyle",
307
314
  "subtitleStyle",
308
315
  "textSizes",
@@ -324,15 +331,12 @@
324
331
  "--avatar-radius",
325
332
  "--color-border",
326
333
  "--color-primary",
327
- "--avatar-size-xs",
328
- "--avatar-size-sm",
329
- "--avatar-size-md",
330
- "--avatar-size-lg",
331
- "--avatar-size-xl",
334
+ "--avatar-size",
332
335
  "--color-success",
333
- "--color-text-muted",
336
+ "--color-mono-500",
334
337
  "--color-danger",
335
- "--color-warning"
338
+ "--color-warning",
339
+ "--color-text-muted"
336
340
  ],
337
341
  "codeExample": "import { Avatar } from \"@flikk/ui\";\n\n<Avatar src=\"...\" name=\"Sarah Chen\" size=\"md\" />"
338
342
  },
@@ -341,7 +345,7 @@
341
345
  "category": "core",
342
346
  "pattern": "simple",
343
347
  "importPath": "@flikk/ui/core",
344
- "description": "Displays multiple overlapping avatars in a group with overflow handling and customizable spacing.",
348
+ "description": "Displays multiple overlapping avatars in a group with overflow handling.",
345
349
  "status": "stable",
346
350
  "productionReady": true,
347
351
  "generative": true,
@@ -361,11 +365,6 @@
361
365
  "default": "md",
362
366
  "description": "Size for all avatars in the group"
363
367
  },
364
- "spacing": {
365
- "type": "AvatarGroupSpacing",
366
- "default": "normal",
367
- "description": "Amount of overlap between avatars (higher value = more overlap)"
368
- },
369
368
  "direction": {
370
369
  "type": "AvatarGroupDirection",
371
370
  "default": "row",
@@ -388,17 +387,14 @@
388
387
  },
389
388
  "themeKeys": [
390
389
  "baseStyle",
391
- "spacingStyles",
392
- "tight",
393
- "normal",
394
- "loose",
390
+ "spacingStyle",
395
391
  "overflowAvatarStyle"
396
392
  ],
397
393
  "cssVariables": [
398
394
  "--color-surface",
399
395
  "--color-text-secondary"
400
396
  ],
401
- "codeExample": "import { AvatarGroup } from \"@flikk/ui\";\n\n<AvatarGroup\n avatars={[\n { src: \"...\", name: \"Sarah Chen\" },\n { src: \"...\", name: \"Michael Park\" },\n { src: \"...\", name: \"Emma Wilson\" },\n { src: \"...\", name: \"David Martinez\" },\n ]}\n size=\"md\"\n spacing=\"normal\"\n/>"
397
+ "codeExample": "import { AvatarGroup } from \"@flikk/ui\";\n\n<AvatarGroup\n avatars={[\n { src: \"...\", name: \"Sarah Chen\" },\n { src: \"...\", name: \"Michael Park\" },\n { src: \"...\", name: \"Emma Wilson\" },\n { src: \"...\", name: \"David Martinez\" },\n ]}\n size=\"md\"\n/>"
402
398
  },
403
399
  {
404
400
  "name": "Badge",
@@ -479,19 +475,19 @@
479
475
  "soft",
480
476
  "variantColors",
481
477
  "filled",
482
- "neutral",
478
+ "mono",
483
479
  "primary",
484
480
  "success",
485
481
  "warning",
486
482
  "danger",
487
483
  "outline",
488
- "neutral",
484
+ "mono",
489
485
  "primary",
490
486
  "success",
491
487
  "warning",
492
488
  "danger",
493
489
  "soft",
494
- "neutral",
490
+ "mono",
495
491
  "primary",
496
492
  "success",
497
493
  "warning",
@@ -512,7 +508,7 @@
512
508
  "sm",
513
509
  "md",
514
510
  "dotColors",
515
- "neutral",
511
+ "mono",
516
512
  "primary",
517
513
  "success",
518
514
  "warning",
@@ -522,8 +518,8 @@
522
518
  "hover"
523
519
  ],
524
520
  "cssVariables": [
525
- "--color-neutral-900",
526
- "--color-neutral-700",
521
+ "--color-mono-900",
522
+ "--color-mono-700",
527
523
  "--color-primary",
528
524
  "--color-primary-contrast",
529
525
  "--color-success-600",
@@ -542,7 +538,7 @@
542
538
  "--color-success-400",
543
539
  "--color-warning-400",
544
540
  "--color-danger-400",
545
- "--color-neutral-100",
541
+ "--color-mono-100",
546
542
  "--color-primary-50",
547
543
  "--color-primary-700",
548
544
  "--color-primary-300",
@@ -551,7 +547,13 @@
551
547
  "--color-warning-50",
552
548
  "--color-warning-700",
553
549
  "--color-danger-50",
554
- "--color-danger-700"
550
+ "--color-danger-700",
551
+ "--badge-px-sm",
552
+ "--badge-py-sm",
553
+ "--badge-px-md",
554
+ "--badge-py-md",
555
+ "--badge-pill-px-sm",
556
+ "--badge-pill-px-md"
555
557
  ],
556
558
  "codeExample": "import { Badge } from \"@flikk/ui\";\n\n<Badge variant=\"filled\" color=\"primary\">Admin</Badge>"
557
559
  },
@@ -621,7 +623,7 @@
621
623
  "type": "ButtonColor",
622
624
  "description": "The semantic color/intent of the button",
623
625
  "options": [
624
- "neutral",
626
+ "mono",
625
627
  "primary",
626
628
  "danger"
627
629
  ]
@@ -662,6 +664,14 @@
662
664
  "type": "boolean",
663
665
  "description": "Whether the button should be full width"
664
666
  },
667
+ "iconStart": {
668
+ "type": "React.ReactNode",
669
+ "description": "Small decorative icon before the label, auto-sized to the button's `size`. The SERIALIZABLE front door — composing the icon into `children` stays the idiomatic hand-written form (`<Button><SearchIcon className=\"size-4\" />Search</Button>`) and is unchanged. This slot exists because a generative UI spec is JSON: it can name an icon but cannot pass a React element, so `children` alone leaves an LLM unable to put an icon on a button at all. Same \"one contract, two front doors\" shape as Card's `title`/`subtitle` slot-props and the collection `items` APIs (CLAUDE.md §2). Deliberately NO `contentStart`/`contentEnd` counterpart: those take arbitrary ReactNode, which is not serializable, so they would buy the generative path nothing — compose those into `children`."
670
+ },
671
+ "iconEnd": {
672
+ "type": "React.ReactNode",
673
+ "description": "Small decorative icon after the label, auto-sized to the button's `size`. See `iconStart`."
674
+ },
665
675
  "enableRipple": {
666
676
  "type": "boolean",
667
677
  "description": "Whether to enable ripple effect on click"
@@ -697,19 +707,19 @@
697
707
  "ghost",
698
708
  "variantColors",
699
709
  "filled",
700
- "neutral",
710
+ "mono",
701
711
  "primary",
702
712
  "danger",
703
713
  "outline",
704
- "neutral",
714
+ "mono",
705
715
  "primary",
706
716
  "danger",
707
717
  "soft",
708
- "neutral",
718
+ "mono",
709
719
  "primary",
710
720
  "danger",
711
721
  "ghost",
712
- "neutral",
722
+ "mono",
713
723
  "primary",
714
724
  "danger",
715
725
  "sizes",
@@ -722,6 +732,10 @@
722
732
  "lg",
723
733
  "default",
724
734
  "iconOnly",
735
+ "iconSizes",
736
+ "sm",
737
+ "md",
738
+ "lg",
725
739
  "states",
726
740
  "disabled",
727
741
  "loading",
@@ -729,10 +743,9 @@
729
743
  ],
730
744
  "cssVariables": [
731
745
  "--button-radius",
732
- "--color-neutral-900",
733
- "--color-border",
734
- "--color-neutral-800",
735
- "--color-neutral-200",
746
+ "--color-mono",
747
+ "--color-mono-contrast",
748
+ "--color-mono-800",
736
749
  "--color-primary",
737
750
  "--color-primary-contrast",
738
751
  "--color-primary-600",
@@ -741,7 +754,7 @@
741
754
  "--color-danger-600",
742
755
  "--color-text-primary",
743
756
  "--color-border-secondary",
744
- "--color-neutral-100",
757
+ "--color-mono-100",
745
758
  "--color-text-secondary",
746
759
  "--color-background-secondary",
747
760
  "--color-primary-100",
@@ -750,6 +763,8 @@
750
763
  "--color-danger-300",
751
764
  "--color-danger-400",
752
765
  "--color-danger-900",
766
+ "--color-mono-200",
767
+ "--color-mono-900",
753
768
  "--color-primary-50",
754
769
  "--color-primary-300",
755
770
  "--color-primary-900",
@@ -758,16 +773,22 @@
758
773
  "--button-min-h-sm",
759
774
  "--button-px-sm",
760
775
  "--button-py-sm",
776
+ "--button-text-size-sm",
777
+ "--button-line-height-sm",
761
778
  "--button-icon-size-sm",
762
779
  "--button-icon-p-sm",
763
780
  "--button-min-h-md",
764
781
  "--button-px-md",
765
782
  "--button-py-md",
783
+ "--button-text-size-md",
784
+ "--button-line-height-md",
766
785
  "--button-icon-size-md",
767
786
  "--button-icon-p-md",
768
787
  "--button-min-h-lg",
769
788
  "--button-px-lg",
770
789
  "--button-py-lg",
790
+ "--button-text-size-lg",
791
+ "--button-line-height-lg",
771
792
  "--button-icon-size-lg",
772
793
  "--button-icon-p-lg"
773
794
  ],
@@ -781,7 +802,7 @@
781
802
  "description": "Groups related buttons together with consistent styling, shared borders, and connected corners.",
782
803
  "status": "stable",
783
804
  "productionReady": true,
784
- "generative": false,
805
+ "generative": true,
785
806
  "props": {
786
807
  "orientation": {
787
808
  "type": "ButtonGroupOrientation",
@@ -812,7 +833,7 @@
812
833
  "--color-border",
813
834
  "--color-text-primary"
814
835
  ],
815
- "codeExample": "import { ButtonGroup, Button } from \"@flikk/ui\";\nimport { DocumentDuplicateIcon } from \"@heroicons/react/24/outline\";\n\n<ButtonGroup>\n <Button variant=\"outline\" color=\"neutral\" showReflection={false}>\n <DocumentDuplicateIcon className=\"size-4\" />\n Copy\n </Button>\n <Button variant=\"outline\" color=\"neutral\" showReflection={false}>\n Cut\n </Button>\n <Button variant=\"outline\" color=\"neutral\" showReflection={false}>\n Paste\n </Button>\n</ButtonGroup>"
836
+ "codeExample": "import { ButtonGroup, Button } from \"@flikk/ui\";\n\n<ButtonGroup>\n <Button variant=\"outline\" color=\"mono\" showReflection={false}>\n <DocumentDuplicateIcon className=\"size-4\" />\n Copy\n </Button>\n <Button variant=\"outline\" color=\"mono\" showReflection={false}>\n Cut\n </Button>\n <Button variant=\"outline\" color=\"mono\" showReflection={false}>\n Paste\n </Button>\n</ButtonGroup>"
816
837
  },
817
838
  {
818
839
  "name": "Calendar",
@@ -822,7 +843,7 @@
822
843
  "description": "Month-grid date picker with single and range selection, dropdown navigation, and date-restriction support. Powers the DatePicker.",
823
844
  "status": "stable",
824
845
  "productionReady": true,
825
- "generative": false,
846
+ "generative": true,
826
847
  "props": {
827
848
  "mode": {
828
849
  "type": "CalendarMode",
@@ -917,7 +938,6 @@
917
938
  "headerStyle",
918
939
  "titleStyle",
919
940
  "headerDropdownsStyle",
920
- "navButtonStyle",
921
941
  "weekdaysStyle",
922
942
  "weekdayStyle",
923
943
  "daysGridStyle",
@@ -930,19 +950,16 @@
930
950
  ],
931
951
  "cssVariables": [
932
952
  "--color-text-primary",
933
- "--radius-base",
934
953
  "--color-text-muted",
935
- "--color-primary-50",
954
+ "--color-primary-300",
955
+ "--color-primary-500",
936
956
  "--color-primary",
937
- "--color-neutral-500",
938
- "--color-neutral-200",
939
- "--color-neutral-800",
940
- "--color-neutral-900",
941
- "--color-primary-900",
957
+ "--color-primary-50",
942
958
  "--color-primary-contrast",
943
959
  "--color-primary-600",
944
960
  "--color-primary-400",
945
- "--color-neutral-600"
961
+ "--color-mono-200",
962
+ "--color-mono-900"
946
963
  ],
947
964
  "codeExample": "import { Calendar } from \"@flikk/ui\";\n\n<Calendar showToday onChange={(date) => console.log(date)} />"
948
965
  },
@@ -999,10 +1016,13 @@
999
1016
  "cssVariables": [
1000
1017
  "--card-radius",
1001
1018
  "--color-border",
1019
+ "--card-px",
1020
+ "--card-py",
1021
+ "--card-title-size",
1002
1022
  "--color-text-primary",
1003
1023
  "--color-text-secondary"
1004
1024
  ],
1005
- "codeExample": "import { Card, Input, Select, Button } from \"@flikk/ui\";\n\n<Card\n title=\"Create project\"\n subtitle=\"Deploy your new project in one-click.\"\n footer={\n <>\n <Button variant=\"outline\" color=\"neutral\" className=\"flex-1\">Cancel</Button>\n <Button variant=\"filled\" className=\"flex-1\">Deploy</Button>\n </>\n }\n className=\"w-full max-w-[380px]\"\n>\n <div className=\"grid w-full items-center gap-4\">\n <Input label=\"Name\" placeholder=\"Name of your project\" />\n <Select\n label=\"Framework\"\n placeholder=\"Select framework\"\n options={[\n { id: \"next\", value: \"next\", label: \"Next.js\" },\n { id: \"nuxt\", value: \"nuxt\", label: \"Nuxt.js\" },\n { id: \"remix\", value: \"remix\", label: \"Remix\" },\n ]}\n />\n </div>\n</Card>"
1025
+ "codeExample": "import { Card, Input, Select, Button } from \"@flikk/ui\";\n\n<Card\n title=\"Create project\"\n subtitle=\"Deploy your new project in one-click.\"\n footer={\n <>\n <Button variant=\"outline\" color=\"mono\" className=\"flex-1\">Cancel</Button>\n <Button variant=\"filled\" className=\"flex-1\">Deploy</Button>\n </>\n }\n className=\"w-full max-w-[380px]\"\n>\n <div className=\"grid w-full items-center gap-4\">\n <Input label=\"Name\" placeholder=\"Name of your project\" />\n <Select\n label=\"Framework\"\n placeholder=\"Select framework\"\n options={[\n { id: \"next\", value: \"next\", label: \"Next.js\" },\n { id: \"nuxt\", value: \"nuxt\", label: \"Nuxt.js\" },\n { id: \"remix\", value: \"remix\", label: \"Remix\" },\n ]}\n />\n </div>\n</Card>"
1006
1026
  },
1007
1027
  {
1008
1028
  "name": "CardStack",
@@ -1197,7 +1217,7 @@
1197
1217
  "description": "A command-K style command palette for quick navigation and actions. Supports keyboard navigation, search filtering, grouping, and keyboard shortcuts.",
1198
1218
  "status": "beta",
1199
1219
  "productionReady": false,
1200
- "generative": false,
1220
+ "generative": true,
1201
1221
  "statusWarning": "⚠️ BETA: This component is not production-ready. API may change without notice.",
1202
1222
  "props": {
1203
1223
  "isOpen": {
@@ -1266,6 +1286,10 @@
1266
1286
  "lift": {
1267
1287
  "type": "boolean",
1268
1288
  "description": "`false` opts out of the relative lift — paints at the palette's base rung."
1289
+ },
1290
+ "onCommandSelect": {
1291
+ "type": "(id: string) => void",
1292
+ "description": "Fired with the selected command's id, in addition to that command's own onSelect."
1269
1293
  }
1270
1294
  },
1271
1295
  "themeKeys": [
@@ -1283,7 +1307,6 @@
1283
1307
  "--color-background",
1284
1308
  "--color-text-primary",
1285
1309
  "--color-text-placeholder",
1286
- "--color-neutral-500",
1287
1310
  "--color-text-muted"
1288
1311
  ],
1289
1312
  "codeExample": "import { CommandPalette } from \"@flikk/ui\";\n\nconst [isOpen, setIsOpen] = useState(false);\n\n<CommandPalette\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n commands={commands}\n grouped\n/>"
@@ -1337,7 +1360,7 @@
1337
1360
  "description": "A small inline dot for separating text and metadata, like a middot between items. Decorative (aria-hidden) and flows with surrounding text.",
1338
1361
  "status": "stable",
1339
1362
  "productionReady": true,
1340
- "generative": false,
1363
+ "generative": true,
1341
1364
  "props": {
1342
1365
  "size": {
1343
1366
  "type": "DotSeparatorSize",
@@ -1477,10 +1500,13 @@
1477
1500
  "cssVariables": [
1478
1501
  "--color-border",
1479
1502
  "--drawer-radius",
1503
+ "--drawer-px",
1504
+ "--drawer-py",
1480
1505
  "--color-text-primary",
1506
+ "--drawer-title-size",
1481
1507
  "--color-text-secondary"
1482
1508
  ],
1483
- "codeExample": "import { Drawer, Button, Input, Textarea } from \"@flikk/ui\";\nimport { UserIcon } from \"@heroicons/react/24/outline\";\nimport { useState } from \"react\";\n\nfunction EditProfileDrawer() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setIsOpen(true)}>Edit Profile</Button>\n <Drawer isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <Drawer.Header icon={<UserIcon className=\"size-5\" />}>\n <Drawer.Title>Edit Profile</Drawer.Title>\n <Drawer.Subtitle>Update your personal information</Drawer.Subtitle>\n </Drawer.Header>\n <Drawer.Body>\n <div className=\"space-y-4\">\n <Input label=\"Full Name\" defaultValue=\"John Doe\" />\n <Input label=\"Email\" type=\"email\" defaultValue=\"john.doe@example.com\" />\n <Textarea label=\"Bio\" rows={4} defaultValue=\"Product designer and frontend developer.\" />\n </div>\n </Drawer.Body>\n <Drawer.Footer>\n <Button variant=\"outline\" color=\"neutral\" onClick={() => setIsOpen(false)}>Cancel</Button>\n <Button onClick={() => setIsOpen(false)}>Save Changes</Button>\n </Drawer.Footer>\n </Drawer>\n </>\n );\n}"
1509
+ "codeExample": "import { Drawer, Button, Input, Textarea } from \"@flikk/ui\";\n\nimport { useState } from \"react\";\n\nfunction EditProfileDrawer() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setIsOpen(true)}>Edit Profile</Button>\n <Drawer isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <Drawer.Header icon={<UserIcon className=\"size-5\" />}>\n <Drawer.Title>Edit Profile</Drawer.Title>\n <Drawer.Subtitle>Update your personal information</Drawer.Subtitle>\n </Drawer.Header>\n <Drawer.Body>\n <div className=\"space-y-4\">\n <Input label=\"Full Name\" defaultValue=\"John Doe\" />\n <Input label=\"Email\" type=\"email\" defaultValue=\"john.doe@example.com\" />\n <Textarea label=\"Bio\" rows={4} defaultValue=\"Product designer and frontend developer.\" />\n </div>\n </Drawer.Body>\n <Drawer.Footer>\n <Button variant=\"outline\" color=\"mono\" onClick={() => setIsOpen(false)}>Cancel</Button>\n <Button onClick={() => setIsOpen(false)}>Save Changes</Button>\n </Drawer.Footer>\n </Drawer>\n </>\n );\n}"
1484
1510
  },
1485
1511
  {
1486
1512
  "name": "Dropdown",
@@ -1555,7 +1581,7 @@
1555
1581
  "--color-border",
1556
1582
  "--color-text-secondary"
1557
1583
  ],
1558
- "codeExample": "import { Dropdown, Button } from \"@flikk/ui\";\nimport { ChevronDownIcon } from \"@heroicons/react/24/outline\";\n\n<Dropdown>\n <Dropdown.Trigger>\n <Button variant=\"outline\" color=\"neutral\">\n Actions <ChevronDownIcon className=\"size-4\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu aria-label=\"Document actions\">\n <Dropdown.Item itemKey=\"edit\">Edit</Dropdown.Item>\n <Dropdown.Item itemKey=\"duplicate\">Duplicate</Dropdown.Item>\n <Dropdown.Item itemKey=\"archive\">Archive</Dropdown.Item>\n <Dropdown.Item itemKey=\"delete\" isDanger>Delete</Dropdown.Item>\n </Dropdown.Menu>\n</Dropdown>"
1584
+ "codeExample": "import { Dropdown, Button } from \"@flikk/ui\";\n\n<Dropdown>\n <Dropdown.Trigger>\n <Button variant=\"outline\" color=\"mono\">\n Actions <ChevronDownIcon className=\"size-4\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu aria-label=\"Document actions\">\n <Dropdown.Item itemKey=\"edit\">Edit</Dropdown.Item>\n <Dropdown.Item itemKey=\"duplicate\">Duplicate</Dropdown.Item>\n <Dropdown.Item itemKey=\"archive\">Archive</Dropdown.Item>\n <Dropdown.Item itemKey=\"delete\" isDanger>Delete</Dropdown.Item>\n </Dropdown.Menu>\n</Dropdown>"
1559
1585
  },
1560
1586
  {
1561
1587
  "name": "Empty",
@@ -1601,7 +1627,7 @@
1601
1627
  "--color-text-primary",
1602
1628
  "--color-text-muted"
1603
1629
  ],
1604
- "codeExample": "import { Empty, Button } from \"@flikk/ui\";\nimport { FolderPlusIcon } from \"@heroicons/react/24/outline\";\n\n<Empty\n icon={<FolderPlusIcon className=\"w-full h-full\" />}\n title=\"No projects yet\"\n subtitle=\"Get started by creating your first project.\"\n action={<Button>New project</Button>}\n/>"
1630
+ "codeExample": "import { Empty, Button } from \"@flikk/ui\";\n\n<Empty\n icon={<FolderPlusIcon className=\"w-full h-full\" />}\n title=\"No projects yet\"\n subtitle=\"Get started by creating your first project.\"\n action={<Button>New project</Button>}\n/>"
1605
1631
  },
1606
1632
  {
1607
1633
  "name": "HeroCard",
@@ -1611,7 +1637,7 @@
1611
1637
  "description": "A gradient hero shell with an ambient blurred backdrop image — drop any content inside. The gradient follows the app theme by default; override it (and the backdrop) via",
1612
1638
  "status": "stable",
1613
1639
  "productionReady": true,
1614
- "generative": false,
1640
+ "generative": true,
1615
1641
  "props": {
1616
1642
  "image": {
1617
1643
  "type": "string | null",
@@ -1670,7 +1696,7 @@
1670
1696
  "--color-primary-500",
1671
1697
  "--color-primary"
1672
1698
  ],
1673
- "codeExample": "import { HeroCard, Button } from \"@flikk/ui\";\n\n<HeroCard className=\"from-indigo-600 via-purple-700 to-fuchsia-800\">\n <h2 className=\"text-3xl font-semibold\">Good morning, Maya</h2>\n <p className=\"mt-2 max-w-md text-white/70\">\n You have 3 reviews waiting and a design critique at 2:00 PM.\n </p>\n <Button color=\"neutral\" className=\"mt-6\">View agenda</Button>\n</HeroCard>"
1699
+ "codeExample": "import { HeroCard, Button } from \"@flikk/ui\";\n\n<HeroCard className=\"from-indigo-600 via-purple-700 to-fuchsia-800\">\n <h2 className=\"text-3xl font-semibold\">Good morning, Maya</h2>\n <p className=\"mt-2 max-w-md text-white/70\">\n You have 3 reviews waiting and a design critique at 2:00 PM.\n </p>\n <Button color=\"mono\" className=\"mt-6\">View agenda</Button>\n</HeroCard>"
1674
1700
  },
1675
1701
  {
1676
1702
  "name": "Icon",
@@ -1680,7 +1706,7 @@
1680
1706
  "description": "A unified brand icon component for payment networks, social platforms, and file types. The icon set is auto-detected from the",
1681
1707
  "status": "stable",
1682
1708
  "productionReady": true,
1683
- "generative": false,
1709
+ "generative": true,
1684
1710
  "props": {
1685
1711
  "icon": {
1686
1712
  "type": "IconName",
@@ -1763,7 +1789,7 @@
1763
1789
  "description": "Displays keyboard keys and shortcuts inline within text or instructions.",
1764
1790
  "status": "stable",
1765
1791
  "productionReady": true,
1766
- "generative": false,
1792
+ "generative": true,
1767
1793
  "props": {
1768
1794
  "keys": {
1769
1795
  "type": "KbdKey[]",
@@ -1787,6 +1813,8 @@
1787
1813
  "--color-surface-raised",
1788
1814
  "--color-border",
1789
1815
  "--color-text-secondary",
1816
+ "--kbd-px-sm",
1817
+ "--kbd-px-md",
1790
1818
  "--color-text-muted"
1791
1819
  ],
1792
1820
  "codeExample": "import { Kbd } from \"@flikk/ui\";\n\n<Kbd keys={[\"command\", \"enter\"]} />"
@@ -1799,7 +1827,7 @@
1799
1827
  "description": "A text-styled link with an animated underline. Polymorphic by behavior: pass",
1800
1828
  "status": "stable",
1801
1829
  "productionReady": true,
1802
- "generative": false,
1830
+ "generative": true,
1803
1831
  "props": {
1804
1832
  "size": {
1805
1833
  "type": "LinkSize",
@@ -1848,7 +1876,7 @@
1848
1876
  "description": "A responsive masonry layout that packs variable-height items into balanced columns for optimal space utilization.",
1849
1877
  "status": "stable",
1850
1878
  "productionReady": true,
1851
- "generative": false,
1879
+ "generative": true,
1852
1880
  "props": {
1853
1881
  "columns": {
1854
1882
  "type": "number | Record<number, number>",
@@ -1904,7 +1932,7 @@
1904
1932
  "description": "Shared base item used by Dropdown and ContextMenu. Handles visual layout, keyboard activation (Enter/Space), and focus tracking. Compose",
1905
1933
  "status": "stable",
1906
1934
  "productionReady": true,
1907
- "generative": false,
1935
+ "generative": true,
1908
1936
  "props": {
1909
1937
  "startContent": {
1910
1938
  "type": "ReactNode",
@@ -1963,7 +1991,7 @@
1963
1991
  "--color-primary-400",
1964
1992
  "--color-text-secondary"
1965
1993
  ],
1966
- "codeExample": "import { MenuItem } from \"@flikk/ui\";\nimport { CogIcon, TrashIcon } from \"@heroicons/react/24/outline\";\n\n<MenuItem startContent={<CogIcon className=\"size-4\" />} shortcut=\"⌘,\">\n Settings\n</MenuItem>\n\n<MenuItem startContent={<TrashIcon className=\"size-4\" />} isDanger>\n Delete\n</MenuItem>"
1994
+ "codeExample": "import { MenuItem } from \"@flikk/ui\";\n\n<MenuItem startContent={<CogIcon className=\"size-4\" />} shortcut=\"⌘,\">\n Settings\n</MenuItem>\n\n<MenuItem startContent={<TrashIcon className=\"size-4\" />} isDanger>\n Delete\n</MenuItem>"
1967
1995
  },
1968
1996
  {
1969
1997
  "name": "Message",
@@ -1973,7 +2001,7 @@
1973
2001
  "description": "Chat message bubble with a props-based and a compound API. Supports AI roles (user/assistant/system) and chat variants (sender/receiver/system), delivery status, streaming, attachments, reactions, replies, grouping, and a scrollable Message.List.",
1974
2002
  "status": "stable",
1975
2003
  "productionReady": true,
1976
- "generative": false,
2004
+ "generative": true,
1977
2005
  "props": {
1978
2006
  "role": {
1979
2007
  "type": "MessageRole",
@@ -2143,14 +2171,15 @@
2143
2171
  "senderNameStyle"
2144
2172
  ],
2145
2173
  "cssVariables": [
2146
- "--radius-base",
2174
+ "--message-bubble-radius",
2147
2175
  "--color-text-placeholder",
2148
- "--color-neutral-500",
2149
- "--color-neutral-900",
2150
- "--color-neutral-100",
2176
+ "--color-mono-900",
2177
+ "--color-mono-100",
2151
2178
  "--color-text-secondary",
2152
2179
  "--color-background",
2153
2180
  "--color-text-muted",
2181
+ "--radius-base",
2182
+ "--surface-radius-cap-xs",
2154
2183
  "--color-primary",
2155
2184
  "--color-danger",
2156
2185
  "--color-border",
@@ -2225,10 +2254,13 @@
2225
2254
  "cssVariables": [
2226
2255
  "--modal-radius",
2227
2256
  "--color-border",
2257
+ "--modal-px",
2258
+ "--modal-py",
2259
+ "--modal-title-size",
2228
2260
  "--color-text-primary",
2229
2261
  "--color-text-secondary"
2230
2262
  ],
2231
- "codeExample": "import { useState } from \"react\";\nimport { Modal, Button, Input, Select } from \"@flikk/ui\";\n\nfunction Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setIsOpen(true)}>Open Account Settings</Button>\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} size=\"md\">\n <Modal.Header>\n <Modal.Title>Account Settings</Modal.Title>\n <Modal.Subtitle>Manage your account preferences and settings</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>\n <div className=\"space-y-3\">\n <Input label=\"Display Name\" placeholder=\"Enter your name...\" />\n <Input label=\"Email Address\" type=\"email\" placeholder=\"email@example.com\" />\n <Select\n label=\"Language\"\n placeholder=\"Select language...\"\n options={[\n { id: \"en\", value: \"en\", label: \"English\" },\n { id: \"es\", value: \"es\", label: \"Spanish\" },\n { id: \"fr\", value: \"fr\", label: \"French\" },\n ]}\n />\n </div>\n </Modal.Body>\n <Modal.Footer>\n <Button color=\"neutral\" variant=\"outline\" onClick={() => setIsOpen(false)}>Cancel</Button>\n <Button onClick={() => setIsOpen(false)}>Save Changes</Button>\n </Modal.Footer>\n </Modal>\n </>\n );\n}"
2263
+ "codeExample": "import { useState } from \"react\";\nimport { Modal, Button, Input, Select } from \"@flikk/ui\";\n\nfunction Example() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setIsOpen(true)}>Open Account Settings</Button>\n <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} size=\"md\">\n <Modal.Header>\n <Modal.Title>Account Settings</Modal.Title>\n <Modal.Subtitle>Manage your account preferences and settings</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>\n <div className=\"space-y-3\">\n <Input label=\"Display Name\" placeholder=\"Enter your name...\" />\n <Input label=\"Email Address\" type=\"email\" placeholder=\"email@example.com\" />\n <Select\n label=\"Language\"\n placeholder=\"Select language...\"\n options={[\n { id: \"en\", value: \"en\", label: \"English\" },\n { id: \"es\", value: \"es\", label: \"Spanish\" },\n { id: \"fr\", value: \"fr\", label: \"French\" },\n ]}\n />\n </div>\n </Modal.Body>\n <Modal.Footer>\n <Button color=\"mono\" variant=\"outline\" onClick={() => setIsOpen(false)}>Cancel</Button>\n <Button onClick={() => setIsOpen(false)}>Save Changes</Button>\n </Modal.Footer>\n </Modal>\n </>\n );\n}"
2232
2264
  },
2233
2265
  {
2234
2266
  "name": "ModalStack",
@@ -2266,7 +2298,7 @@
2266
2298
  "--color-text-secondary",
2267
2299
  "--color-text-primary"
2268
2300
  ],
2269
- "codeExample": "import { useState } from \"react\";\nimport { ModalStack, Modal, Button, Link, Input, Select } from \"@flikk/ui\";\n\nfunction Example() {\n const [isMainOpen, setMainOpen] = useState(false);\n const [isDetailOpen, setDetailOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setMainOpen(true)}>Open Settings</Button>\n <ModalStack isOpen={isMainOpen} onClose={() => setMainOpen(false)}>\n <ModalStack.Modal size=\"lg\">\n <Modal.Header>\n <Modal.Title>Settings</Modal.Title>\n <Modal.Subtitle>Manage your account preferences</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>\n <div className=\"space-y-4\">\n <Input label=\"Display Name\" placeholder=\"John Doe\" />\n <Input label=\"Email Address\" type=\"email\" placeholder=\"john@example.com\" />\n <Link onClick={() => setDetailOpen(true)}>Edit Preferences</Link>\n </div>\n </Modal.Body>\n <Modal.Footer>\n <Button color=\"neutral\" variant=\"outline\" onClick={() => setMainOpen(false)}>Cancel</Button>\n <Button onClick={() => setMainOpen(false)}>Save Changes</Button>\n </Modal.Footer>\n </ModalStack.Modal>\n\n <ModalStack.Modal\n isOpen={isDetailOpen}\n onClose={() => setDetailOpen(false)}\n showBackButton\n size=\"md\"\n >\n <Modal.Header>\n <Modal.Title>Notification Preferences</Modal.Title>\n <Modal.Subtitle>Choose how you want to be notified</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>Notification settings here</Modal.Body>\n <Modal.Footer>\n <Button color=\"neutral\" variant=\"outline\" onClick={() => setDetailOpen(false)}>Cancel</Button>\n <Button onClick={() => setDetailOpen(false)}>Save Preferences</Button>\n </Modal.Footer>\n </ModalStack.Modal>\n </ModalStack>\n </>\n );\n}"
2301
+ "codeExample": "import { useState } from \"react\";\nimport { ModalStack, Modal, Button, Link, Input, Select } from \"@flikk/ui\";\n\nfunction Example() {\n const [isMainOpen, setMainOpen] = useState(false);\n const [isDetailOpen, setDetailOpen] = useState(false);\n\n return (\n <>\n <Button onClick={() => setMainOpen(true)}>Open Settings</Button>\n <ModalStack isOpen={isMainOpen} onClose={() => setMainOpen(false)}>\n <ModalStack.Modal size=\"lg\">\n <Modal.Header>\n <Modal.Title>Settings</Modal.Title>\n <Modal.Subtitle>Manage your account preferences</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>\n <div className=\"space-y-4\">\n <Input label=\"Display Name\" placeholder=\"John Doe\" />\n <Input label=\"Email Address\" type=\"email\" placeholder=\"john@example.com\" />\n <Link onClick={() => setDetailOpen(true)}>Edit Preferences</Link>\n </div>\n </Modal.Body>\n <Modal.Footer>\n <Button color=\"mono\" variant=\"outline\" onClick={() => setMainOpen(false)}>Cancel</Button>\n <Button onClick={() => setMainOpen(false)}>Save Changes</Button>\n </Modal.Footer>\n </ModalStack.Modal>\n\n <ModalStack.Modal\n isOpen={isDetailOpen}\n onClose={() => setDetailOpen(false)}\n showBackButton\n size=\"md\"\n >\n <Modal.Header>\n <Modal.Title>Notification Preferences</Modal.Title>\n <Modal.Subtitle>Choose how you want to be notified</Modal.Subtitle>\n </Modal.Header>\n <Modal.Body>Notification settings here</Modal.Body>\n <Modal.Footer>\n <Button color=\"mono\" variant=\"outline\" onClick={() => setDetailOpen(false)}>Cancel</Button>\n <Button onClick={() => setDetailOpen(false)}>Save Preferences</Button>\n </Modal.Footer>\n </ModalStack.Modal>\n </ModalStack>\n </>\n );\n}"
2270
2302
  },
2271
2303
  {
2272
2304
  "name": "NavItem",
@@ -2384,12 +2416,12 @@
2384
2416
  "--color-background",
2385
2417
  "--color-primary-400"
2386
2418
  ],
2387
- "codeExample": "import { NavItem } from \"@flikk/ui\";\nimport { HomeIcon } from \"@heroicons/react/20/solid\";\n\n<NavItem startContent={<HomeIcon className=\"size-4\" />} active>\n Dashboard\n</NavItem>"
2419
+ "codeExample": "import { NavItem } from \"@flikk/ui\";\n\n<NavItem startContent={<HomeIcon className=\"size-4\" />} active>\n Dashboard\n</NavItem>"
2388
2420
  },
2389
2421
  {
2390
2422
  "name": "OfflineIndicator",
2391
2423
  "category": "core",
2392
- "pattern": "simple",
2424
+ "pattern": "enhanced",
2393
2425
  "importPath": "@flikk/ui/core",
2394
2426
  "description": "A page-level network status indicator. It mounts a fixed overlay that appears automatically when the browser goes offline (and briefly confirms reconnection). Visibility is driven by",
2395
2427
  "status": "stable",
@@ -2431,6 +2463,10 @@
2431
2463
  "onlineMessage": {
2432
2464
  "type": "string",
2433
2465
  "description": "Custom online message (shown briefly when reconnecting)"
2466
+ },
2467
+ "action": {
2468
+ "type": "OfflineIndicatorAction | ReactNode",
2469
+ "description": "Action shown next to the message while offline — pass `{ }` for a link-styled button (mirrors Toast's `action`), or any ReactNode."
2434
2470
  }
2435
2471
  },
2436
2472
  "themeKeys": [
@@ -2438,19 +2474,23 @@
2438
2474
  "positions",
2439
2475
  "top",
2440
2476
  "bottom",
2477
+ "bannerPositions",
2478
+ "top",
2479
+ "bottom",
2441
2480
  "variants",
2442
2481
  "banner",
2443
2482
  "toast",
2444
2483
  "offline",
2445
2484
  "online",
2485
+ "action",
2446
2486
  "icon",
2447
2487
  "message",
2448
2488
  "queueCount"
2449
2489
  ],
2450
2490
  "cssVariables": [
2451
- "--radius-base",
2452
- "--color-neutral-900",
2453
- "--color-neutral-100",
2491
+ "--toast-radius",
2492
+ "--color-mono",
2493
+ "--color-mono-contrast",
2454
2494
  "--color-success",
2455
2495
  "--color-success-contrast"
2456
2496
  ],
@@ -2501,12 +2541,13 @@
2501
2541
  "separatorStyle"
2502
2542
  ],
2503
2543
  "cssVariables": [
2544
+ "--page-heading-title-size",
2504
2545
  "--color-text-primary",
2505
2546
  "--color-text-secondary",
2506
2547
  "--color-text-muted",
2507
2548
  "--color-border"
2508
2549
  ],
2509
- "codeExample": "import { PageHeading, Button } from \"@flikk/ui\";\nimport { PlusIcon, ArrowDownTrayIcon } from \"@heroicons/react/24/outline\";\n\n<PageHeading>\n <div className=\"flex flex-col items-start sm:flex-row sm:items-center gap-4\">\n <div className=\"min-w-0 flex-1\">\n <PageHeading.Title>Team Members</PageHeading.Title>\n <PageHeading.Subtitle>\n Manage your team and their account permissions\n </PageHeading.Subtitle>\n </div>\n <PageHeading.Actions>\n <Button variant=\"outline\" color=\"neutral\">\n <ArrowDownTrayIcon className=\"size-4\" />\n Download\n </Button>\n <Button>\n <PlusIcon className=\"size-4\" />\n Add Member\n </Button>\n </PageHeading.Actions>\n </div>\n</PageHeading>"
2550
+ "codeExample": "import { PageHeading, Button } from \"@flikk/ui\";\n\n<PageHeading>\n <div className=\"flex flex-col items-start sm:flex-row sm:items-center gap-4\">\n <div className=\"min-w-0 flex-1\">\n <PageHeading.Title>Team Members</PageHeading.Title>\n <PageHeading.Subtitle>\n Manage your team and their account permissions\n </PageHeading.Subtitle>\n </div>\n <PageHeading.Actions>\n <Button variant=\"outline\" color=\"mono\">\n <ArrowDownTrayIcon className=\"size-4\" />\n Download\n </Button>\n <Button>\n <PlusIcon className=\"size-4\" />\n Add Member\n </Button>\n </PageHeading.Actions>\n </div>\n</PageHeading>"
2510
2551
  },
2511
2552
  {
2512
2553
  "name": "Pagination",
@@ -2516,7 +2557,7 @@
2516
2557
  "description": "Pagination component with previous/next buttons, page numbers, and ellipsis for large page counts.",
2517
2558
  "status": "stable",
2518
2559
  "productionReady": true,
2519
- "generative": false,
2560
+ "generative": true,
2520
2561
  "props": {
2521
2562
  "currentPage": {
2522
2563
  "type": "number",
@@ -2568,15 +2609,14 @@
2568
2609
  "cssVariables": [
2569
2610
  "--form-radius",
2570
2611
  "--color-primary",
2571
- "--color-neutral-900",
2612
+ "--color-mono-900",
2572
2613
  "--color-text-muted",
2573
2614
  "--color-text-secondary",
2574
2615
  "--color-text-primary",
2575
2616
  "--color-background-secondary",
2576
2617
  "--color-border",
2577
2618
  "--color-surface-hover",
2578
- "--color-neutral-800",
2579
- "--color-neutral-500"
2619
+ "--color-mono-800"
2580
2620
  ],
2581
2621
  "codeExample": "import { useState } from \"react\";\nimport { Pagination } from \"@flikk/ui\";\n\nconst [currentPage, setCurrentPage] = useState(1);\n\n<Pagination\n totalPages={10}\n currentPage={currentPage}\n onPageChange={setCurrentPage}\n size=\"md\"\n showPrevNext\n/>"
2582
2622
  },
@@ -2636,7 +2676,13 @@
2636
2676
  "--color-border",
2637
2677
  "--color-primary",
2638
2678
  "--color-surface-hover",
2639
- "--color-border-hover"
2679
+ "--color-border-hover",
2680
+ "--pill-px-sm",
2681
+ "--pill-py-sm",
2682
+ "--pill-px-md",
2683
+ "--pill-py-md",
2684
+ "--pill-px-lg",
2685
+ "--pill-py-lg"
2640
2686
  ],
2641
2687
  "codeExample": "import { Pill } from \"@flikk/ui\";\n\n<Pill>Design</Pill>"
2642
2688
  },
@@ -2841,7 +2887,7 @@
2841
2887
  "--color-warning-400",
2842
2888
  "--color-success",
2843
2889
  "--color-danger",
2844
- "--color-neutral-300"
2890
+ "--color-mono-300"
2845
2891
  ],
2846
2892
  "codeExample": "import { Rating } from \"@flikk/ui\";\n\n<Rating defaultValue={3} max={5} size=\"md\" color=\"warning\" />"
2847
2893
  },
@@ -2853,7 +2899,7 @@
2853
2899
  "description": "A scrollable container with styled, overlay-friendly scrollbars. Supports vertical, horizontal, or both directions, scroll snapping, drag-to-scroll, and optional smooth momentum-based scrolling with a programmatic ref API.",
2854
2900
  "status": "stable",
2855
2901
  "productionReady": true,
2856
- "generative": false,
2902
+ "generative": true,
2857
2903
  "props": {
2858
2904
  "type": {
2859
2905
  "type": "ScrollAreaType",
@@ -2973,6 +3019,7 @@
2973
3019
  ],
2974
3020
  "cssVariables": [
2975
3021
  "--segmented-radius",
3022
+ "--color-surface-sunken",
2976
3023
  "--color-border",
2977
3024
  "--segmented-padding",
2978
3025
  "--segmented-min-h-sm",
@@ -2981,8 +3028,14 @@
2981
3028
  "--segmented-inner-radius",
2982
3029
  "--color-surface",
2983
3030
  "--color-primary-500",
3031
+ "--segmented-text-size-sm",
3032
+ "--segmented-line-height-sm",
2984
3033
  "--segmented-px-sm",
3034
+ "--segmented-text-size-md",
3035
+ "--segmented-line-height-md",
2985
3036
  "--segmented-px-md",
3037
+ "--segmented-text-size-lg",
3038
+ "--segmented-line-height-lg",
2986
3039
  "--segmented-px-lg",
2987
3040
  "--color-text-primary",
2988
3041
  "--color-text-secondary"
@@ -3116,7 +3169,7 @@
3116
3169
  "--color-border",
3117
3170
  "--color-background-secondary"
3118
3171
  ],
3119
- "codeExample": "import { Sidebar, NavItem, Dropdown } from \"@flikk/ui\";\nimport { HomeIcon, InboxIcon, UsersIcon, ChartBarIcon, FolderIcon, CogIcon, BellIcon, UserCircleIcon, CreditCardIcon, Cog6ToothIcon, ArrowRightStartOnRectangleIcon } from \"@heroicons/react/20/solid\";\n\n<Sidebar defaultCollapsed={false}>\n <Sidebar.Header\n logo={\n <Sidebar.Logo\n icon={\n <div className=\"size-8 bg-[var(--color-primary)] rounded-lg flex items-center justify-center\">\n <span className=\"text-[var(--color-primary-contrast)] font-bold text-sm\">F</span>\n </div>\n }\n text=\"FlikkUI\"\n />\n }\n />\n\n <Sidebar.Content>\n <Sidebar.Nav>\n <Sidebar.NavGroup title=\"Main\">\n <NavItem startContent={<HomeIcon />} active>Dashboard</NavItem>\n <NavItem startContent={<InboxIcon />} notification={5}>Inbox</NavItem>\n <NavItem\n startContent={<UsersIcon />}\n items={[\n { children: \"All Users\", href: \"/users\" },\n { children: \"Pending Invites\", notification: 3 },\n { children: \"Roles & Permissions\" },\n ]}\n >\n Users\n </NavItem>\n <NavItem startContent={<ChartBarIcon />}>Analytics</NavItem>\n <NavItem startContent={<FolderIcon />} notification>Documents</NavItem>\n </Sidebar.NavGroup>\n\n <Sidebar.NavGroup title=\"Settings\">\n <NavItem startContent={<CogIcon />}>Preferences</NavItem>\n <NavItem startContent={<BellIcon />}>Notifications</NavItem>\n </Sidebar.NavGroup>\n </Sidebar.Nav>\n </Sidebar.Content>\n\n <Sidebar.Footer>\n <Sidebar.UserProfile\n name=\"Sarah Wilson\"\n email=\"sarah@company.com\"\n avatar=\"https://i.pravatar.cc/150?u=sarah-wilson\"\n status=\"online\"\n dropdownContent={\n <>\n <Dropdown.Item itemKey=\"profile\" startContent={<UserCircleIcon className=\"size-4\" />}>View profile</Dropdown.Item>\n <Dropdown.Item itemKey=\"billing\" startContent={<CreditCardIcon className=\"size-4\" />}>Billing</Dropdown.Item>\n <Dropdown.Item itemKey=\"settings\" startContent={<Cog6ToothIcon className=\"size-4\" />}>Settings</Dropdown.Item>\n <Dropdown.Separator />\n <Dropdown.Item itemKey=\"logout\" isDanger startContent={<ArrowRightStartOnRectangleIcon className=\"size-4\" />}>Log out</Dropdown.Item>\n </>\n }\n />\n </Sidebar.Footer>\n</Sidebar>"
3172
+ "codeExample": "import { Sidebar, NavItem, Dropdown } from \"@flikk/ui\";\n\n<Sidebar defaultCollapsed={false}>\n <Sidebar.Header\n logo={\n <Sidebar.Logo\n icon={\n <div className=\"size-8 bg-[var(--color-primary)] rounded-lg flex items-center justify-center\">\n <span className=\"text-[var(--color-primary-contrast)] font-bold text-sm\">F</span>\n </div>\n }\n text=\"FlikkUI\"\n />\n }\n />\n\n <Sidebar.Content>\n <Sidebar.Nav>\n <Sidebar.NavGroup title=\"Main\">\n <NavItem startContent={<HomeIcon />} active>Dashboard</NavItem>\n <NavItem startContent={<InboxIcon />} notification={5}>Inbox</NavItem>\n <NavItem\n startContent={<UsersIcon />}\n items={[\n { children: \"All Users\", href: \"/users\" },\n { children: \"Pending Invites\", notification: 3 },\n { children: \"Roles & Permissions\" },\n ]}\n >\n Users\n </NavItem>\n <NavItem startContent={<ChartBarIcon />}>Analytics</NavItem>\n <NavItem startContent={<FolderIcon />} notification>Documents</NavItem>\n </Sidebar.NavGroup>\n\n <Sidebar.NavGroup title=\"Settings\">\n <NavItem startContent={<CogIcon />}>Preferences</NavItem>\n <NavItem startContent={<BellIcon />}>Notifications</NavItem>\n </Sidebar.NavGroup>\n </Sidebar.Nav>\n </Sidebar.Content>\n\n <Sidebar.Footer>\n <Sidebar.UserProfile\n name=\"Sarah Wilson\"\n email=\"sarah@company.com\"\n avatar=\"https://i.pravatar.cc/150?u=sarah-wilson\"\n status=\"online\"\n dropdownContent={\n <>\n <Dropdown.Item itemKey=\"profile\" startContent={<UserCircleIcon className=\"size-4\" />}>View profile</Dropdown.Item>\n <Dropdown.Item itemKey=\"billing\" startContent={<CreditCardIcon className=\"size-4\" />}>Billing</Dropdown.Item>\n <Dropdown.Item itemKey=\"settings\" startContent={<Cog6ToothIcon className=\"size-4\" />}>Settings</Dropdown.Item>\n <Dropdown.Separator />\n <Dropdown.Item itemKey=\"logout\" isDanger startContent={<ArrowRightStartOnRectangleIcon className=\"size-4\" />}>Log out</Dropdown.Item>\n </>\n }\n />\n </Sidebar.Footer>\n</Sidebar>"
3120
3173
  },
3121
3174
  {
3122
3175
  "name": "Skeleton",
@@ -3126,7 +3179,7 @@
3126
3179
  "description": "A loading placeholder that mimics content shape, with text, circular, and rectangle variants and an optional pulse animation.",
3127
3180
  "status": "stable",
3128
3181
  "productionReady": true,
3129
- "generative": false,
3182
+ "generative": true,
3130
3183
  "props": {
3131
3184
  "variant": {
3132
3185
  "type": "SkeletonVariant",
@@ -3272,7 +3325,7 @@
3272
3325
  "description": "A loading spinner for indicating processing states, with multiple sizes and semantic color options.",
3273
3326
  "status": "stable",
3274
3327
  "productionReady": true,
3275
- "generative": false,
3328
+ "generative": true,
3276
3329
  "props": {
3277
3330
  "size": {
3278
3331
  "type": "SpinnerSize",
@@ -3437,6 +3490,11 @@
3437
3490
  "--color-surface-raised",
3438
3491
  "--color-border",
3439
3492
  "--color-text-primary",
3493
+ "--tag-px-sm",
3494
+ "--tag-py-sm",
3495
+ "--tag-px-md",
3496
+ "--tag-pl-md",
3497
+ "--tag-py-md",
3440
3498
  "--color-surface-hover",
3441
3499
  "--color-text-muted",
3442
3500
  "--color-primary"
@@ -3619,6 +3677,23 @@
3619
3677
  "lift": {
3620
3678
  "type": "boolean",
3621
3679
  "description": "`false` opts out of the relative lift — paints at the tooltip's base rung."
3680
+ },
3681
+ "isOpen": {
3682
+ "type": "boolean",
3683
+ "description": "Controlled visibility — when provided, visibility is driven entirely by this prop instead of internal hover/focus state (delay is bypassed). Use for triggers whose \"show tooltip\" moment isn't a plain hover, e.g. a value bubble shown only while dragging a Slider thumb."
3684
+ },
3685
+ "defaultIsOpen": {
3686
+ "type": "boolean",
3687
+ "default": "false",
3688
+ "description": "Initial visibility for uncontrolled usage."
3689
+ },
3690
+ "onOpenChange": {
3691
+ "type": "(isOpen: boolean) => void",
3692
+ "description": "Called when internal hover/focus logic changes visibility (uncontrolled mode). In controlled mode visibility is owned by `isOpen` and the internal triggers are bypassed entirely, so this never fires — update your own state instead."
3693
+ },
3694
+ "recalcTrigger": {
3695
+ "type": "unknown",
3696
+ "description": "Opt-in escape hatch for triggers that move on their own (e.g. a dragged slider thumb) without a scroll/resize/content-resize event to key off of. Position recalculates whenever this value changes."
3622
3697
  }
3623
3698
  },
3624
3699
  "themeKeys": [
@@ -3640,7 +3715,7 @@
3640
3715
  "description": "A data-driven tree for hierarchical data: expand/collapse, single selection, and checkbox multi-selection with parent-child (indeterminate) propagation. Arrow keys navigate; ArrowRight expands, ArrowLeft collapses or moves to the parent.",
3641
3716
  "status": "stable",
3642
3717
  "productionReady": true,
3643
- "generative": false,
3718
+ "generative": true,
3644
3719
  "props": {
3645
3720
  "data": {
3646
3721
  "type": "TreeNode[]",
@@ -3795,7 +3870,7 @@
3795
3870
  "--color-primary",
3796
3871
  "--color-primary-700"
3797
3872
  ],
3798
- "codeExample": "import { Feed, Avatar } from \"@flikk/ui\";\nimport { CheckCircleIcon, ChatBubbleLeftIcon } from \"@heroicons/react/20/solid\";\n\n<Feed\n className=\"max-w-lg\"\n items={[\n {\n icon: <CheckCircleIcon className=\"size-5 text-[var(--color-success)]\" />,\n indicatorClassName: \"bg-[var(--color-success-50)]\",\n timestamp: \"1h ago\",\n content: <p>Sarah Wilson deployed v2.5.0 to production.</p>,\n },\n {\n icon: <ChatBubbleLeftIcon className=\"size-5 text-[var(--color-primary)]\" />,\n indicatorClassName: \"bg-[var(--color-primary-50)]\",\n timestamp: \"2h ago\",\n content: <p>Tom Cook commented on PR #247.</p>,\n },\n {\n icon: <Avatar src=\"...\" name=\"Eduardo Benz\" className=\"size-8\" />,\n timestamp: \"5h ago\",\n content: <p>Eduardo Benz reviewed the pull request.</p>,\n },\n ]}\n/>"
3873
+ "codeExample": "import { Feed, Avatar } from \"@flikk/ui\";\n\n<Feed\n className=\"max-w-lg\"\n items={[\n {\n icon: <CheckCircleIcon className=\"size-5 text-[var(--color-success)]\" />,\n indicatorClassName: \"bg-[var(--color-success-50)]\",\n timestamp: \"1h ago\",\n content: <p>Sarah Wilson deployed v2.5.0 to production.</p>,\n },\n {\n icon: <ChatBubbleLeftIcon className=\"size-5 text-[var(--color-primary)]\" />,\n indicatorClassName: \"bg-[var(--color-primary-50)]\",\n timestamp: \"2h ago\",\n content: <p>Tom Cook commented on PR #247.</p>,\n },\n {\n icon: <Avatar src=\"...\" name=\"Eduardo Benz\" className=\"size-8\" />,\n timestamp: \"5h ago\",\n content: <p>Eduardo Benz reviewed the pull request.</p>,\n },\n ]}\n/>"
3799
3874
  },
3800
3875
  {
3801
3876
  "name": "GanttChart",
@@ -3805,7 +3880,7 @@
3805
3880
  "description": "Data-driven project timeline / Gantt chart — tasks with start/end dates, progress, dependencies, milestones and grouped swimlanes; drag to move, resize and reschedule.",
3806
3881
  "status": "beta",
3807
3882
  "productionReady": false,
3808
- "generative": false,
3883
+ "generative": true,
3809
3884
  "statusWarning": "⚠️ BETA: This component is not production-ready. API may change without notice.",
3810
3885
  "props": {
3811
3886
  "data": {
@@ -3963,6 +4038,7 @@
3963
4038
  "splitterStyle"
3964
4039
  ],
3965
4040
  "cssVariables": [
4041
+ "--gantt-chart-radius",
3966
4042
  "--color-border",
3967
4043
  "--color-background",
3968
4044
  "--color-background-secondary",
@@ -4035,7 +4111,10 @@
4035
4111
  }
4036
4112
  },
4037
4113
  "cssVariables": [
4114
+ "--kpi-value-size-sm",
4038
4115
  "--color-text-primary",
4116
+ "--kpi-value-size-md",
4117
+ "--kpi-value-size-lg",
4039
4118
  "--color-success",
4040
4119
  "--color-danger",
4041
4120
  "--color-text-muted",
@@ -4061,7 +4140,6 @@
4061
4140
  },
4062
4141
  "label": {
4063
4142
  "type": "React.ReactNode",
4064
- "required": true,
4065
4143
  "description": "Label describing the metric"
4066
4144
  },
4067
4145
  "subtitle": {
@@ -4110,12 +4188,15 @@
4110
4188
  "filled",
4111
4189
  "ghost",
4112
4190
  "iconColors",
4113
- "neutral",
4191
+ "mono",
4114
4192
  "primary",
4115
4193
  "success",
4116
4194
  "warning",
4117
4195
  "danger",
4118
4196
  "contentPaddingSizes",
4197
+ "sm",
4198
+ "md",
4199
+ "lg",
4119
4200
  "iconContainerSizes",
4120
4201
  "labelIconAlignSizes",
4121
4202
  "labelSizes",
@@ -4123,6 +4204,9 @@
4123
4204
  "md",
4124
4205
  "lg",
4125
4206
  "valueSizes",
4207
+ "sm",
4208
+ "md",
4209
+ "lg",
4126
4210
  "subtitleSizes",
4127
4211
  "labelStyle",
4128
4212
  "valueStyle",
@@ -4130,6 +4214,7 @@
4130
4214
  "iconContainerStyle"
4131
4215
  ],
4132
4216
  "cssVariables": [
4217
+ "--metric-radius",
4133
4218
  "--color-border",
4134
4219
  "--color-surface-raised",
4135
4220
  "--color-text-primary",
@@ -4141,6 +4226,12 @@
4141
4226
  "--color-warning-400",
4142
4227
  "--color-danger",
4143
4228
  "--color-danger-400",
4229
+ "--metric-content-p-sm",
4230
+ "--metric-content-p-md",
4231
+ "--metric-content-p-lg",
4232
+ "--metric-value-size-sm",
4233
+ "--metric-value-size-md",
4234
+ "--metric-value-size-lg",
4144
4235
  "--color-text-secondary"
4145
4236
  ],
4146
4237
  "codeExample": "import { Metric } from \"@flikk/ui\";\n\n<Metric\n value=\"12,547\"\n label=\"Active Users\"\n subtitle=\"Total registered users\"\n trendValue=\"12.5%\"\n trendDirection=\"up\"\n/>"
@@ -4326,14 +4417,14 @@
4326
4417
  ],
4327
4418
  "cssVariables": [
4328
4419
  "--color-border",
4329
- "--color-neutral-700",
4330
- "--color-neutral-50",
4331
- "--color-neutral-800",
4420
+ "--color-mono-700",
4421
+ "--color-mono-50",
4422
+ "--color-mono-800",
4332
4423
  "--color-text-primary",
4333
4424
  "--color-surface-hover",
4334
4425
  "--color-primary",
4335
- "--color-neutral-200",
4336
- "--color-neutral-900",
4426
+ "--color-mono-200",
4427
+ "--color-mono-900",
4337
4428
  "--radius-base",
4338
4429
  "--color-primary-500",
4339
4430
  "--color-surface"
@@ -4400,7 +4491,7 @@
4400
4491
  "--color-text-secondary",
4401
4492
  "--color-text-placeholder"
4402
4493
  ],
4403
- "codeExample": "import { Timeline } from \"@flikk/ui\";\nimport { ShoppingBagIcon, CreditCardIcon, TruckIcon, CheckCircleIcon } from \"@heroicons/react/24/outline\";\n\n<Timeline\n items={[\n {\n status: \"completed\",\n icon: <ShoppingBagIcon className=\"w-4 h-4\" />,\n title: \"Order Placed\",\n description: \"Your order #12847 has been confirmed.\",\n timestamp: \"March 15, 2025 at 9:30 AM\",\n },\n {\n status: \"completed\",\n icon: <CreditCardIcon className=\"w-4 h-4\" />,\n title: \"Payment Confirmed\",\n description: \"Payment of $249.99 was charged to Visa ending in 4242.\",\n timestamp: \"March 15, 2025 at 9:32 AM\",\n },\n {\n status: \"active\",\n icon: <TruckIcon className=\"w-4 h-4\" />,\n title: \"In Transit\",\n description: \"Your package is on its way via Express Shipping.\",\n timestamp: \"Expected delivery: March 18, 2025\",\n },\n {\n status: \"pending\",\n icon: <CheckCircleIcon className=\"w-4 h-4\" />,\n title: \"Delivered\",\n description: \"Package will be delivered to your doorstep.\",\n },\n ]}\n/>"
4494
+ "codeExample": "import { Timeline } from \"@flikk/ui\";\n\n<Timeline\n items={[\n {\n status: \"completed\",\n icon: <ShoppingBagIcon className=\"w-4 h-4\" />,\n title: \"Order Placed\",\n description: \"Your order #12847 has been confirmed.\",\n timestamp: \"March 15, 2025 at 9:30 AM\",\n },\n {\n status: \"completed\",\n icon: <CreditCardIcon className=\"w-4 h-4\" />,\n title: \"Payment Confirmed\",\n description: \"Payment of $249.99 was charged to Visa ending in 4242.\",\n timestamp: \"March 15, 2025 at 9:32 AM\",\n },\n {\n status: \"active\",\n icon: <TruckIcon className=\"w-4 h-4\" />,\n title: \"In Transit\",\n description: \"Your package is on its way via Express Shipping.\",\n timestamp: \"Expected delivery: March 18, 2025\",\n },\n {\n status: \"pending\",\n icon: <CheckCircleIcon className=\"w-4 h-4\" />,\n title: \"Delivered\",\n description: \"Package will be delivered to your doorstep.\",\n },\n ]}\n/>"
4404
4495
  },
4405
4496
  {
4406
4497
  "name": "Checkbox",
@@ -4410,7 +4501,7 @@
4410
4501
  "description": "A checkbox for selecting one or more options, with support for an indeterminate state, descriptions, and three sizes. Use standalone (it tracks its own checked state) or compose with Checkbox.Group for centralized, multi-value state.",
4411
4502
  "status": "stable",
4412
4503
  "productionReady": true,
4413
- "generative": false,
4504
+ "generative": true,
4414
4505
  "props": {
4415
4506
  "id": {
4416
4507
  "type": "string"
@@ -4465,9 +4556,9 @@
4465
4556
  "--color-primary-600",
4466
4557
  "--color-primary-500",
4467
4558
  "--color-background-disabled",
4468
- "--color-neutral-800",
4469
- "--color-neutral-600",
4470
- "--color-neutral-700",
4559
+ "--color-mono-800",
4560
+ "--color-mono-600",
4561
+ "--color-mono-700",
4471
4562
  "--color-text-secondary",
4472
4563
  "--color-danger"
4473
4564
  ],
@@ -4635,7 +4726,7 @@
4635
4726
  "description": "Accessible autocomplete combining a text input with a filtered listbox. Type to search options, click or press Enter to select, and optionally create new options on the fly. Manages its own selection state — pass",
4636
4727
  "status": "stable",
4637
4728
  "productionReady": true,
4638
- "generative": false,
4729
+ "generative": true,
4639
4730
  "props": {
4640
4731
  "options": {
4641
4732
  "type": "ComboboxOption<T>[]",
@@ -4986,9 +5077,7 @@
4986
5077
  "--color-primary",
4987
5078
  "--color-surface",
4988
5079
  "--color-text-muted",
4989
- "--color-neutral-400",
4990
5080
  "--color-text-disabled",
4991
- "--color-neutral-600",
4992
5081
  "--color-danger",
4993
5082
  "--color-danger-400"
4994
5083
  ],
@@ -5192,10 +5281,8 @@
5192
5281
  "--color-primary-50",
5193
5282
  "--color-primary-950",
5194
5283
  "--color-primary-300",
5195
- "--color-neutral-400",
5196
5284
  "--color-text-muted",
5197
5285
  "--color-text-disabled",
5198
- "--color-neutral-600",
5199
5286
  "--color-danger",
5200
5287
  "--color-danger-400"
5201
5288
  ],
@@ -5371,7 +5458,7 @@
5371
5458
  "description": "A versatile input component with support for icons, addons, password toggle, number controls, and various states. Follows the four-slot system with iconStart, iconEnd, contentStart, and contentEnd.",
5372
5459
  "status": "stable",
5373
5460
  "productionReady": true,
5374
- "generative": false,
5461
+ "generative": true,
5375
5462
  "props": {
5376
5463
  "size": {
5377
5464
  "type": "InputSize",
@@ -5529,12 +5616,11 @@
5529
5616
  "--color-danger",
5530
5617
  "--color-danger-500",
5531
5618
  "--color-text-muted",
5532
- "--color-neutral-500",
5533
5619
  "--color-text-primary",
5534
- "--color-neutral-200",
5535
- "--color-background-secondary",
5620
+ "--color-surface-sunken",
5536
5621
  "--color-surface-hover",
5537
- "--color-neutral-700",
5622
+ "--checkbox-radius",
5623
+ "--color-mono-700",
5538
5624
  "--color-danger-400",
5539
5625
  "--color-warning",
5540
5626
  "--color-warning-400",
@@ -5643,7 +5729,7 @@
5643
5729
  "description": "A numeric counter component with animated sliding number display. Features increment/decrement buttons, min/max constraints, keyboard navigation, and custom step sizes including decimals.",
5644
5730
  "status": "stable",
5645
5731
  "productionReady": true,
5646
- "generative": false,
5732
+ "generative": true,
5647
5733
  "props": {
5648
5734
  "value": {
5649
5735
  "type": "number",
@@ -5805,7 +5891,7 @@
5805
5891
  "description": "A masked date input with automatic slash insertion. Type numbers continuously (e.g.,",
5806
5892
  "status": "stable",
5807
5893
  "productionReady": true,
5808
- "generative": false,
5894
+ "generative": true,
5809
5895
  "props": {
5810
5896
  "value": {
5811
5897
  "type": "string",
@@ -5842,13 +5928,18 @@
5842
5928
  "description": "A one-time password input for authentication and verification flows. Supports customizable length, auto-focus, paste handling, and keyboard navigation between fields. Manages its own value internally — pass",
5843
5929
  "status": "stable",
5844
5930
  "productionReady": true,
5845
- "generative": false,
5931
+ "generative": true,
5846
5932
  "props": {
5847
5933
  "length": {
5848
5934
  "type": "number",
5849
5935
  "default": "6",
5850
5936
  "description": "Number of OTP input fields"
5851
5937
  },
5938
+ "size": {
5939
+ "type": "InputOTPSize",
5940
+ "default": "lg",
5941
+ "description": "Size of the OTP slots."
5942
+ },
5852
5943
  "value": {
5853
5944
  "type": "string",
5854
5945
  "description": "Current OTP value (controlled)"
@@ -5865,6 +5956,11 @@
5865
5956
  "type": "(value: string) => void",
5866
5957
  "description": "Callback when OTP is complete (all fields filled)"
5867
5958
  },
5959
+ "charset": {
5960
+ "type": "InputOTPCharset",
5961
+ "default": "alphanumeric",
5962
+ "description": "Which characters the code accepts. Drives the sanitizer (typed and pasted characters outside the set are stripped), the native `pattern` attribute, and the mobile keyboard via `inputMode` (`'numeric'` → numeric keypad, `'alphanumeric'` → standard text keyboard)."
5963
+ },
5868
5964
  "state": {
5869
5965
  "type": "InputOTPState",
5870
5966
  "default": "default",
@@ -5900,13 +5996,37 @@
5900
5996
  "themeKeys": [
5901
5997
  "wrapperStyle",
5902
5998
  "containerStyle",
5903
- "inputStyle",
5904
- "inputGroupStyle",
5999
+ "inputGroupSizes",
6000
+ "sm",
6001
+ "md",
6002
+ "lg",
6003
+ "xl",
6004
+ "charSizes",
6005
+ "sm",
6006
+ "md",
6007
+ "lg",
6008
+ "xl",
6009
+ "slotActiveHoverGuard",
5905
6010
  "separatorStyle",
5906
6011
  "helperText"
5907
6012
  ],
5908
6013
  "cssVariables": [
5909
- "--color-text-primary",
6014
+ "--otp-slot-size-sm",
6015
+ "--otp-slot-size-md",
6016
+ "--otp-slot-size-lg",
6017
+ "--otp-slot-size-xl",
6018
+ "--x",
6019
+ "--otp-line-height-*",
6020
+ "--otp-text-size-sm",
6021
+ "--otp-line-height-sm",
6022
+ "--otp-text-size-md",
6023
+ "--otp-line-height-md",
6024
+ "--otp-text-size-lg",
6025
+ "--otp-line-height-lg",
6026
+ "--otp-text-size-xl",
6027
+ "--otp-line-height-xl",
6028
+ "--color-primary-600",
6029
+ "--color-primary-500",
5910
6030
  "--color-text-muted"
5911
6031
  ],
5912
6032
  "codeExample": "import { InputOTP } from \"@flikk/ui\";\n\n<InputOTP\n length={6}\n label=\"Enter verification code\"\n helperText=\"Check your email for the 6-digit code\"\n/>"
@@ -5919,7 +6039,7 @@
5919
6039
  "description": "InputTag component for entering multiple tags or keywords. Supports Enter, comma, and paste for adding tags. Backspace removes the last tag when input is empty. Optionally supports dropdown suggestions.",
5920
6040
  "status": "stable",
5921
6041
  "productionReady": true,
5922
- "generative": false,
6042
+ "generative": true,
5923
6043
  "props": {
5924
6044
  "value": {
5925
6045
  "type": "string[]",
@@ -6265,8 +6385,8 @@
6265
6385
  "--color-primary-600",
6266
6386
  "--color-primary-500",
6267
6387
  "--color-background-disabled",
6268
- "--color-neutral-700",
6269
- "--color-neutral-600",
6388
+ "--color-mono-700",
6389
+ "--color-mono-600",
6270
6390
  "--color-primary-contrast",
6271
6391
  "--color-text-secondary",
6272
6392
  "--color-danger"
@@ -6415,7 +6535,7 @@
6415
6535
  "description": "Accessible select with labels, helper text, searchable options, typeahead, multi-select, and portal-based dropdown positioning. Manages its own selection state — pass",
6416
6536
  "status": "stable",
6417
6537
  "productionReady": true,
6418
- "generative": false,
6538
+ "generative": true,
6419
6539
  "props": {
6420
6540
  "id": {
6421
6541
  "type": "string",
@@ -6518,7 +6638,8 @@
6518
6638
  },
6519
6639
  "searchPlaceholder": {
6520
6640
  "type": "string",
6521
- "description": "Placeholder text for the search input"
6641
+ "default": "Search...",
6642
+ "description": "Placeholder text for the search input shown when `searchable` is true."
6522
6643
  },
6523
6644
  "portal": {
6524
6645
  "type": "boolean",
@@ -6608,8 +6729,6 @@
6608
6729
  "cssVariables": [
6609
6730
  "--field-fill",
6610
6731
  "--color-text-primary",
6611
- "--color-border",
6612
- "--radius-base",
6613
6732
  "--color-primary",
6614
6733
  "--color-primary-400",
6615
6734
  "--color-text-muted"
@@ -6806,7 +6925,7 @@
6806
6925
  "description": "A customizable slider component with single and range support. Features include value display, tick marks, min/max labels, icons, and full keyboard navigation for accessibility.",
6807
6926
  "status": "stable",
6808
6927
  "productionReady": true,
6809
- "generative": false,
6928
+ "generative": true,
6810
6929
  "props": {
6811
6930
  "state": {
6812
6931
  "type": "SliderState",
@@ -6920,6 +7039,7 @@
6920
7039
  "--color-primary-700",
6921
7040
  "--color-background-disabled",
6922
7041
  "--color-danger",
7042
+ "--color-surface",
6923
7043
  "--color-border",
6924
7044
  "--color-text-secondary",
6925
7045
  "--color-text-muted"
@@ -6934,7 +7054,7 @@
6934
7054
  "description": "A toggle switch component for binary on/off states. Supports controlled and uncontrolled modes, labels with descriptions, and customizable positioning.",
6935
7055
  "status": "stable",
6936
7056
  "productionReady": true,
6937
- "generative": false,
7057
+ "generative": true,
6938
7058
  "props": {
6939
7059
  "id": {
6940
7060
  "type": "string",
@@ -7014,8 +7134,8 @@
7014
7134
  "cssVariables": [
7015
7135
  "--color-border",
7016
7136
  "--color-primary-600",
7017
- "--color-neutral-200",
7018
- "--color-neutral-700",
7137
+ "--color-mono-200",
7138
+ "--color-mono-700",
7019
7139
  "--color-primary",
7020
7140
  "--color-background-disabled",
7021
7141
  "--color-text-muted"
@@ -7030,7 +7150,7 @@
7030
7150
  "description": "A flexible multiline text input with sizes, states, label, and helper text following the shadcn approach.",
7031
7151
  "status": "stable",
7032
7152
  "productionReady": true,
7033
- "generative": false,
7153
+ "generative": true,
7034
7154
  "props": {
7035
7155
  "size": {
7036
7156
  "type": "TextareaSize",
@@ -7110,7 +7230,7 @@
7110
7230
  "description": "A time picker with masked input trigger and iOS-style scroll wheel. Type directly or scroll the wheels — both stay in sync. Supports 12-hour and 24-hour formats, time validation, and step intervals. Manages its own value internally; pass",
7111
7231
  "status": "stable",
7112
7232
  "productionReady": true,
7113
- "generative": false,
7233
+ "generative": true,
7114
7234
  "props": {
7115
7235
  "value": {
7116
7236
  "type": "string",
@@ -7218,21 +7338,18 @@
7218
7338
  ],
7219
7339
  "cssVariables": [
7220
7340
  "--color-text-primary",
7221
- "--color-neutral-200",
7222
7341
  "--color-text-muted",
7223
7342
  "--color-background-secondary",
7224
7343
  "--color-border",
7225
7344
  "--form-radius",
7226
- "--color-neutral-400",
7227
7345
  "--color-text-disabled",
7228
- "--color-neutral-600",
7229
7346
  "--color-danger",
7230
7347
  "--color-danger-400",
7231
7348
  "--color-text-placeholder",
7232
- "--color-neutral-500",
7233
7349
  "--color-surface-sunken",
7234
7350
  "--color-surface-hover",
7235
- "--color-neutral-700"
7351
+ "--color-mono-700",
7352
+ "--color-mono-600"
7236
7353
  ],
7237
7354
  "codeExample": "import { TimePicker } from \"@flikk/ui\";\n\n<TimePicker\n label=\"Meeting Time\"\n placeholder=\"HH:MM\"\n helperText=\"Type a time or use the scroll wheels\"\n/>"
7238
7355
  },
@@ -7244,7 +7361,7 @@
7244
7361
  "description": "Concentric circular progress rings inspired by Apple Activity. Each ring is a value 0–100; supports custom colors, a center label, and up to 5 rings.",
7245
7362
  "status": "stable",
7246
7363
  "productionReady": true,
7247
- "generative": false,
7364
+ "generative": true,
7248
7365
  "props": {
7249
7366
  "rings": {
7250
7367
  "type": "RingData[]",
@@ -7364,10 +7481,11 @@
7364
7481
  ],
7365
7482
  "cssVariables": [
7366
7483
  "--color-text-placeholder",
7367
- "--color-primary",
7368
- "--color-warning",
7369
- "--color-success",
7370
- "--color-danger"
7484
+ "--color-chart-1",
7485
+ "--color-chart-2",
7486
+ "--color-chart-3",
7487
+ "--color-chart-4",
7488
+ "--color-chart-5"
7371
7489
  ],
7372
7490
  "codeExample": "import { AreaChart, ChartContainer } from \"@flikk/ui/charts\";\n\n<ChartContainer\n data={[\n { name: \"Jan\", revenue: 32 },\n { name: \"Feb\", revenue: 41 },\n { name: \"Mar\", revenue: 38 },\n { name: \"Apr\", revenue: 54 },\n { name: \"May\", revenue: 49 },\n { name: \"Jun\", revenue: 67 },\n ]}\n config={{ revenue: { label: \"Revenue ($k)\", color: \"var(--color-primary)\" } }}\n className=\"w-full max-w-[600px] h-[300px]\"\n>\n <AreaChart\n data={[\n { name: \"Jan\", revenue: 32 },\n { name: \"Feb\", revenue: 41 },\n { name: \"Mar\", revenue: 38 },\n { name: \"Apr\", revenue: 54 },\n { name: \"May\", revenue: 49 },\n { name: \"Jun\", revenue: 67 },\n ]}\n config={{ revenue: { label: \"Revenue ($k)\", color: \"var(--color-primary)\" } }}\n minValue={0}\n maxValue={80}\n curved\n showDots\n />\n</ChartContainer>"
7373
7491
  },
@@ -7479,7 +7597,7 @@
7479
7597
  "--color-text-secondary",
7480
7598
  "--color-text-primary",
7481
7599
  "--color-background",
7482
- "--color-neutral",
7600
+ "--color-mono",
7483
7601
  "--color-text-muted",
7484
7602
  "--color-primary-400",
7485
7603
  "--color-primary-600",
@@ -7574,7 +7692,7 @@
7574
7692
  "description": "A conversion funnel chart with trapezoid stages showing progressive dropoff and stage-to-stage conversion. Supports horizontal/vertical orientations and curved or linear edges.",
7575
7693
  "status": "beta",
7576
7694
  "productionReady": false,
7577
- "generative": false,
7695
+ "generative": true,
7578
7696
  "statusWarning": "⚠️ BETA: This component is not production-ready. API may change without notice.",
7579
7697
  "props": {
7580
7698
  "data": {
@@ -7673,7 +7791,7 @@
7673
7791
  "description": "A CSS-grid heatmap for visualizing intensity across two categorical dimensions (e.g. activity by day and time). Drive it with a",
7674
7792
  "status": "stable",
7675
7793
  "productionReady": true,
7676
- "generative": false,
7794
+ "generative": true,
7677
7795
  "props": {
7678
7796
  "data": {
7679
7797
  "type": "HeatmapDataPoint[]",
@@ -7740,6 +7858,44 @@
7740
7858
  ],
7741
7859
  "codeExample": "import { Heatmap, ChartContainer } from \"@flikk/ui/charts\";\n\n<ChartContainer\n data={[\n { x: \"Mon\", y: \"Morning\", value: 18 },\n { x: \"Tue\", y: \"Morning\", value: 24 },\n { x: \"Wed\", y: \"Morning\", value: 21 },\n { x: \"Thu\", y: \"Morning\", value: 30 },\n { x: \"Fri\", y: \"Morning\", value: 27 },\n { x: \"Mon\", y: \"Afternoon\", value: 32 },\n { x: \"Tue\", y: \"Afternoon\", value: 41 },\n { x: \"Wed\", y: \"Afternoon\", value: 38 },\n { x: \"Thu\", y: \"Afternoon\", value: 47 },\n { x: \"Fri\", y: \"Afternoon\", value: 44 },\n { x: \"Mon\", y: \"Evening\", value: 14 },\n { x: \"Tue\", y: \"Evening\", value: 19 },\n { x: \"Wed\", y: \"Evening\", value: 16 },\n { x: \"Thu\", y: \"Evening\", value: 22 },\n { x: \"Fri\", y: \"Evening\", value: 20 },\n ]}\n config={{ value: { label: \"Tickets\" } }}\n className=\"w-full max-w-[600px] h-[240px]\"\n>\n <Heatmap\n color=\"primary\"\n colorScale={{ steps: 10, minOpacity: 0.1 }}\n layout={{ gap: 4 }}\n axis={{ showXAxis: true, showYAxis: true }}\n legend={{ enabled: true, labels: { min: \"Quiet\", max: \"Busy\" } }}\n />\n</ChartContainer>"
7742
7860
  },
7861
+ {
7862
+ "name": "HorizontalBarChart",
7863
+ "category": "charts",
7864
+ "pattern": "simple",
7865
+ "importPath": "@flikk/ui/charts",
7866
+ "description": "Bar chart with categories running down the left and values extending right. Use it when category names are long or numerous, or when the chart ranks items — a column chart cannot fit labels like \\",
7867
+ "status": "stable",
7868
+ "productionReady": true,
7869
+ "generative": true,
7870
+ "props": {
7871
+ "categoryGap": {
7872
+ "type": "number",
7873
+ "description": "Gap between category rows."
7874
+ },
7875
+ "categoryWidth": {
7876
+ "type": "number",
7877
+ "default": "120",
7878
+ "description": "Width reserved for the category labels running down the left. Category names are arbitrary (\"United Kingdom\"), so unlike a bottom axis there is no shared constant that can know how much room they need — hence a prop rather than `X_AXIS_MARGIN`."
7879
+ },
7880
+ "colors": {
7881
+ "type": "string[]",
7882
+ "description": "Custom color palette for bar series, applied in order and cycled if there are more series than colors. Any valid CSS color, including CSS variables. @example ['var(--color-primary)', 'var(--color-success)']"
7883
+ },
7884
+ "showAnimation": {
7885
+ "type": "boolean",
7886
+ "description": "Whether to play the staggered grow-from-left entrance on mount."
7887
+ },
7888
+ "showValidationWarnings": {
7889
+ "type": "boolean",
7890
+ "default": "true in development",
7891
+ "description": "Log data-validation warnings to the console."
7892
+ },
7893
+ "valueFormatter": {
7894
+ "type": "(value: number) => string",
7895
+ "description": "Formats the value shown in the tooltip."
7896
+ }
7897
+ }
7898
+ },
7743
7899
  {
7744
7900
  "name": "LineChart",
7745
7901
  "category": "charts",
@@ -7774,6 +7930,86 @@
7774
7930
  },
7775
7931
  "codeExample": "import { LineChart, ChartContainer } from \"@flikk/ui/charts\";\n\n<ChartContainer\n data={[\n { name: \"Mon\", visitors: 2400 },\n { name: \"Tue\", visitors: 3100 },\n { name: \"Wed\", visitors: 2900 },\n { name: \"Thu\", visitors: 4200 },\n { name: \"Fri\", visitors: 3800 },\n { name: \"Sat\", visitors: 2200 },\n { name: \"Sun\", visitors: 1900 },\n ]}\n config={{ visitors: { label: \"Visitors\", color: \"var(--color-primary)\" } }}\n className=\"w-full max-w-[600px] h-[300px]\"\n>\n <LineChart\n data={[\n { name: \"Mon\", visitors: 2400 },\n { name: \"Tue\", visitors: 3100 },\n { name: \"Wed\", visitors: 2900 },\n { name: \"Thu\", visitors: 4200 },\n { name: \"Fri\", visitors: 3800 },\n { name: \"Sat\", visitors: 2200 },\n { name: \"Sun\", visitors: 1900 },\n ]}\n config={{ visitors: { label: \"Visitors\", color: \"var(--color-primary)\" } }}\n curved\n showDots\n strokeWidth={3}\n />\n</ChartContainer>"
7776
7932
  },
7933
+ {
7934
+ "name": "LollipopChart",
7935
+ "category": "charts",
7936
+ "pattern": "simple",
7937
+ "importPath": "@flikk/ui/charts",
7938
+ "description": "Single-series magnitude-by-category chart: a dot + stem mark per category, circle-badge axis ticks, and a selectable column that pins a value badge with a spotlight highlight.",
7939
+ "status": "stable",
7940
+ "productionReady": true,
7941
+ "generative": false,
7942
+ "props": {
7943
+ "config": {
7944
+ "type": "ChartConfig",
7945
+ "required": true
7946
+ },
7947
+ "axis": {
7948
+ "type": "just floating\n // dot+stem marks above the shared XAxis (same tick/label component every\n // other Cartesian chart uses — this chart isn't restricted to day-of-week\n // or any other specific category shape).\n showGrid?: boolean",
7949
+ "required": true
7950
+ },
7951
+ "showXAxis": {
7952
+ "type": "boolean"
7953
+ },
7954
+ "showYAxis": {
7955
+ "type": "boolean"
7956
+ },
7957
+ "minValue": {
7958
+ "type": "number"
7959
+ },
7960
+ "maxValue": {
7961
+ "type": "number"
7962
+ },
7963
+ "selectedIndex": {
7964
+ "type": "number | null",
7965
+ "description": "Controlled selected category index. `null`/`undefined` = no selection."
7966
+ },
7967
+ "defaultSelectedIndex": {
7968
+ "type": "number | null",
7969
+ "description": "Uncontrolled initial selection."
7970
+ },
7971
+ "onSelectedIndexChange": {
7972
+ "type": "(index: number | null) => void",
7973
+ "description": "Payload is the index, not the event (CLAUDE.md §9 naming convention)."
7974
+ },
7975
+ "valueFormatter": {
7976
+ "type": "(value: number, item: ChartDataPoint) => string",
7977
+ "description": "Formats the pinned badge's value text. Defaults to `String(value)`."
7978
+ },
7979
+ "dotRadius": {
7980
+ "type": "number"
7981
+ },
7982
+ "stemWidth": {
7983
+ "type": "number"
7984
+ },
7985
+ "color": {
7986
+ "type": "string",
7987
+ "description": "Series color for the dot + stem. Falls back to the single `config` key's `color`, then `var(--color-primary)`."
7988
+ },
7989
+ "showAnimation": {
7990
+ "type": "boolean"
7991
+ },
7992
+ "enableKeyboardNavigation": {
7993
+ "type": "boolean"
7994
+ },
7995
+ "showValidationWarnings": {
7996
+ "type": "boolean"
7997
+ },
7998
+ "title": {
7999
+ "type": "string"
8000
+ },
8001
+ "description": {
8002
+ "type": "string"
8003
+ },
8004
+ "width": {
8005
+ "type": "string | number"
8006
+ },
8007
+ "height": {
8008
+ "type": "string | number"
8009
+ }
8010
+ },
8011
+ "codeExample": "import { LollipopChart, ChartContainer } from \"@flikk/ui/charts\";\n\n<ChartContainer\n data={[\n { name: \"Sunday\", spend: 1200 },\n { name: \"Monday\", spend: 1850 },\n { name: \"Tuesday\", spend: 2567 },\n { name: \"Wednesday\", spend: 1500 },\n { name: \"Thursday\", spend: 2100 },\n { name: \"Friday\", spend: 1700 },\n { name: \"Saturday\", spend: 1300 },\n ]}\n config={{ spend: { label: \"Spend\", color: \"var(--color-primary)\" } }}\n className=\"w-full max-w-2xl h-[280px]\"\n>\n <LollipopChart\n data={[/* same data */]}\n config={{ spend: { label: \"Spend\" } }}\n defaultSelectedIndex={2}\n valueFormatter={(value) => \\"
8012
+ },
7777
8013
  {
7778
8014
  "name": "RadarChart",
7779
8015
  "category": "charts",
@@ -7782,7 +8018,7 @@
7782
8018
  "description": "A radar (spider) chart for comparing multi-dimensional data across categories. Supports multiple overlapping series, configurable grid rings, and optional entrance animations.",
7783
8019
  "status": "stable",
7784
8020
  "productionReady": true,
7785
- "generative": false,
8021
+ "generative": true,
7786
8022
  "props": {
7787
8023
  "axes": {
7788
8024
  "type": "string[]",
@@ -7861,7 +8097,7 @@
7861
8097
  "description": "SVG-based scatter plot for visualizing correlation between two numeric variables across dual axes. Supports category coloring (multi-series) and an optional bubble-size dimension.",
7862
8098
  "status": "stable",
7863
8099
  "productionReady": true,
7864
- "generative": false,
8100
+ "generative": true,
7865
8101
  "props": {
7866
8102
  "data": {
7867
8103
  "type": "ScatterPlotDataPoint[]",
@@ -7941,9 +8177,6 @@
7941
8177
  "barRadius": {
7942
8178
  "type": "number"
7943
8179
  },
7944
- "gap": {
7945
- "type": "number"
7946
- },
7947
8180
  "categoryGap": {
7948
8181
  "type": "number"
7949
8182
  },
@@ -8154,7 +8387,7 @@
8154
8387
  "default",
8155
8388
  "user",
8156
8389
  "cursorFollowColors",
8157
- "neutral",
8390
+ "mono",
8158
8391
  "dark",
8159
8392
  "primary",
8160
8393
  "success",
@@ -8165,7 +8398,7 @@
8165
8398
  "md",
8166
8399
  "lg",
8167
8400
  "colors",
8168
- "neutral",
8401
+ "mono",
8169
8402
  "dark",
8170
8403
  "primary",
8171
8404
  "success",
@@ -8256,7 +8489,7 @@
8256
8489
  "fadeDirection": {
8257
8490
  "type": "DotPatternFadeDirection",
8258
8491
  "default": "radial",
8259
- "description": "Direction of the fade gradient. - \"radial\" fades from center outward - \"top\" | \"bottom\" | \"left\" | \"right\" fades toward that edge"
8492
+ "description": "Direction of the fade gradient. - \"radial\" fades the edges out (solid center, transparent edges) - \"center\" fades the center out (transparent center, solid edges — a vignette that keeps content-area behind it clear) - \"top\" | \"bottom\" | \"left\" | \"right\" fades toward that edge"
8260
8493
  },
8261
8494
  "fadeSize": {
8262
8495
  "type": "number",
@@ -8269,7 +8502,7 @@
8269
8502
  "description": "Whether to apply a subtle pulse animation to the dots. Respects prefers-reduced-motion automatically."
8270
8503
  }
8271
8504
  },
8272
- "codeExample": "import { DotPattern } from \"@flikk/ui/effects\";\n\n<div className=\"relative overflow-hidden rounded-lg bg-white h-80\">\n <DotPattern spacing={20} dotSize={1} fadeDirection=\"radial\" />\n <div className=\"relative z-10 flex items-center justify-center h-full\">\n <h2 className=\"text-2xl font-bold text-gray-900\">Ship with confidence</h2>\n </div>\n</div>"
8505
+ "codeExample": "import { DotPattern } from \"@flikk/ui/effects\";\n\n<div className=\"relative overflow-hidden rounded-lg bg-[var(--color-surface)] h-80\">\n <DotPattern spacing={20} dotSize={1} fadeDirection=\"radial\" />\n <div className=\"relative z-10 flex items-center justify-center h-full\">\n <h2 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">Ship with confidence</h2>\n </div>\n</div>"
8273
8506
  },
8274
8507
  {
8275
8508
  "name": "FlutedGlass",
@@ -10154,7 +10387,7 @@
10154
10387
  "--color-text-primary",
10155
10388
  "--color-border"
10156
10389
  ],
10157
- "codeExample": "import { AppShell, Sidebar, NavItem, Button, Breadcrumbs, Avatar, Card, Badge } from \"@flikk/ui\";\nimport { HomeIcon, InboxIcon, UsersIcon, ChartBarIcon, MagnifyingGlassIcon, BellIcon, PlusIcon } from \"@heroicons/react/24/outline\";\n\n<AppShell scroll=\"viewport\" contentWidth=\"wide\" contentPadding=\"lg\">\n {/* topbarSpan=\"full\" (default) — runs edge-to-edge over the Sidebar */}\n <AppShell.Topbar>\n <div className=\"flex h-14 items-center justify-between gap-4 px-4\">\n <span className=\"text-sm font-semibold\">Flikk Workspace</span>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"ghost\" size=\"sm\" aria-label=\"Search\"><MagnifyingGlassIcon className=\"size-4\" /></Button>\n <Button variant=\"ghost\" size=\"sm\" aria-label=\"Notifications\"><BellIcon className=\"size-4\" /></Button>\n <Avatar src=\"...\" name=\"Maya Patel\" size=\"sm\" />\n </div>\n </div>\n </AppShell.Topbar>\n\n {/* width=\"auto\" lets core/Sidebar own its width; theme makes AppShell.Sidebar a transparent flex slot so core/Sidebar provides all visual chrome */}\n <AppShell.Sidebar width=\"auto\" collapsedOnMobile={false} theme={{ sidebar: \"flex flex-col shrink-0\" }}>\n <Sidebar>\n <Sidebar.Content>\n <Sidebar.Nav>\n <Sidebar.NavGroup title=\"Main\">\n <NavItem startContent={<HomeIcon />} active>Dashboard</NavItem>\n <NavItem startContent={<InboxIcon />} notification={5}>Inbox</NavItem>\n <NavItem startContent={<UsersIcon />}>Customers</NavItem>\n <NavItem startContent={<ChartBarIcon />}>Analytics</NavItem>\n </Sidebar.NavGroup>\n </Sidebar.Nav>\n </Sidebar.Content>\n <Sidebar.Footer>\n <Sidebar.Toggle />\n <Sidebar.UserProfile name=\"Maya Patel\" email=\"maya@flikk.io\" status=\"online\" />\n </Sidebar.Footer>\n </Sidebar>\n </AppShell.Sidebar>\n\n <AppShell.Main>\n {/* AppShell.Header sticks inside the Main scroll region */}\n <AppShell.Header>\n <div className=\"flex items-center justify-between gap-4 py-4\">\n <div>\n <Breadcrumbs items={[{ label: \"Home\", href: \"#\" }, { label: \"Dashboard\", href: \"#\" }]} variant=\"muted\" />\n <h1 className=\"mt-1 text-xl font-semibold\">Operating snapshot</h1>\n </div>\n <Button size=\"sm\"><PlusIcon className=\"size-4\" />New report</Button>\n </div>\n </AppShell.Header>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Revenue</p><span className=\"text-3xl font-semibold\">$48.2k</span></Card.Body></Card>\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Active accounts</p><span className=\"text-3xl font-semibold\">2,847</span></Card.Body></Card>\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Conversion</p><span className=\"text-3xl font-semibold\">8.4%</span></Card.Body></Card>\n </div>\n </AppShell.Main>\n</AppShell>"
10390
+ "codeExample": "import { AppShell, Sidebar, NavItem, Button, Breadcrumbs, Avatar, Card, Badge } from \"@flikk/ui\";\n\n<AppShell scroll=\"viewport\" contentWidth=\"wide\" contentPadding=\"lg\">\n {/* topbarSpan=\"full\" (default) — runs edge-to-edge over the Sidebar */}\n <AppShell.Topbar>\n <div className=\"flex h-14 items-center justify-between gap-4 px-4\">\n <span className=\"text-sm font-semibold\">Flikk Workspace</span>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"ghost\" size=\"sm\" aria-label=\"Search\"><MagnifyingGlassIcon className=\"size-4\" /></Button>\n <Button variant=\"ghost\" size=\"sm\" aria-label=\"Notifications\"><BellIcon className=\"size-4\" /></Button>\n <Avatar src=\"...\" name=\"Maya Patel\" size=\"sm\" />\n </div>\n </div>\n </AppShell.Topbar>\n\n {/* width=\"auto\" lets core/Sidebar own its width; theme makes AppShell.Sidebar a transparent flex slot so core/Sidebar provides all visual chrome */}\n <AppShell.Sidebar width=\"auto\" collapsedOnMobile={false} theme={{ sidebar: \"flex flex-col shrink-0\" }}>\n <Sidebar>\n <Sidebar.Content>\n <Sidebar.Nav>\n <Sidebar.NavGroup title=\"Main\">\n <NavItem startContent={<HomeIcon />} active>Dashboard</NavItem>\n <NavItem startContent={<InboxIcon />} notification={5}>Inbox</NavItem>\n <NavItem startContent={<UsersIcon />}>Customers</NavItem>\n <NavItem startContent={<ChartBarIcon />}>Analytics</NavItem>\n </Sidebar.NavGroup>\n </Sidebar.Nav>\n </Sidebar.Content>\n <Sidebar.Footer>\n <Sidebar.Toggle />\n <Sidebar.UserProfile name=\"Maya Patel\" email=\"maya@flikk.io\" status=\"online\" />\n </Sidebar.Footer>\n </Sidebar>\n </AppShell.Sidebar>\n\n <AppShell.Main>\n {/* AppShell.Header sticks inside the Main scroll region */}\n <AppShell.Header>\n <div className=\"flex items-center justify-between gap-4 py-4\">\n <div>\n <Breadcrumbs items={[{ label: \"Home\", href: \"#\" }, { label: \"Dashboard\", href: \"#\" }]} variant=\"muted\" />\n <h1 className=\"mt-1 text-xl font-semibold\">Operating snapshot</h1>\n </div>\n <Button size=\"sm\"><PlusIcon className=\"size-4\" />New report</Button>\n </div>\n </AppShell.Header>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Revenue</p><span className=\"text-3xl font-semibold\">$48.2k</span></Card.Body></Card>\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Active accounts</p><span className=\"text-3xl font-semibold\">2,847</span></Card.Body></Card>\n <Card><Card.Body className=\"p-5\"><p className=\"text-sm text-[var(--color-text-muted)]\">Conversion</p><span className=\"text-3xl font-semibold\">8.4%</span></Card.Body></Card>\n </div>\n </AppShell.Main>\n</AppShell>"
10158
10391
  },
10159
10392
  {
10160
10393
  "name": "FormLayout",
@@ -10186,7 +10419,7 @@
10186
10419
  "--color-text-muted",
10187
10420
  "--color-border"
10188
10421
  ],
10189
- "codeExample": "import { FormLayout, Input, Select, Button, Link } from \"@flikk/ui\";\n\n<FormLayout>\n <FormLayout.Section\n title=\"Personal Information\"\n subtitle=\"Use a permanent address where you can receive mail.\"\n action={<Link size=\"sm\">Add address</Link>}\n >\n <Input label=\"First name\" placeholder=\"John\" />\n <Input label=\"Last name\" placeholder=\"Doe\" />\n <div className=\"col-span-full\">\n <Input label=\"Email address\" type=\"email\" placeholder=\"john@example.com\" />\n </div>\n <Input label=\"Phone number\" type=\"tel\" placeholder=\"+1 (555) 000-0000\" />\n <Select\n label=\"Country\"\n placeholder=\"Select country\"\n options={[\n { id: \"us\", label: \"United States\", value: \"us\" },\n { id: \"ca\", label: \"Canada\", value: \"ca\" },\n { id: \"uk\", label: \"United Kingdom\", value: \"uk\" },\n ]}\n />\n </FormLayout.Section>\n\n <FormLayout.Footer>\n <span>All fields are required unless marked optional.</span>\n <div className=\"flex gap-3\">\n <Button variant=\"outline\" color=\"neutral\">Cancel</Button>\n <Button>Save changes</Button>\n </div>\n </FormLayout.Footer>\n</FormLayout>"
10422
+ "codeExample": "import { FormLayout, Input, Select, Button, Link } from \"@flikk/ui\";\n\n<FormLayout>\n <FormLayout.Section\n title=\"Personal Information\"\n subtitle=\"Use a permanent address where you can receive mail.\"\n action={<Link size=\"sm\">Add address</Link>}\n >\n <Input label=\"First name\" placeholder=\"John\" />\n <Input label=\"Last name\" placeholder=\"Doe\" />\n <div className=\"col-span-full\">\n <Input label=\"Email address\" type=\"email\" placeholder=\"john@example.com\" />\n </div>\n <Input label=\"Phone number\" type=\"tel\" placeholder=\"+1 (555) 000-0000\" />\n <Select\n label=\"Country\"\n placeholder=\"Select country\"\n options={[\n { id: \"us\", label: \"United States\", value: \"us\" },\n { id: \"ca\", label: \"Canada\", value: \"ca\" },\n { id: \"uk\", label: \"United Kingdom\", value: \"uk\" },\n ]}\n />\n </FormLayout.Section>\n\n <FormLayout.Footer>\n <span>All fields are required unless marked optional.</span>\n <div className=\"flex gap-3\">\n <Button variant=\"outline\" color=\"mono\">Cancel</Button>\n <Button>Save changes</Button>\n </div>\n </FormLayout.Footer>\n</FormLayout>"
10190
10423
  },
10191
10424
  {
10192
10425
  "name": "Grid",
@@ -10303,6 +10536,7 @@
10303
10536
  "bodyGaps"
10304
10537
  ],
10305
10538
  "cssVariables": [
10539
+ "--section-title-size",
10306
10540
  "--color-text-primary",
10307
10541
  "--color-text-secondary"
10308
10542
  ],
@@ -10360,6 +10594,144 @@
10360
10594
  ],
10361
10595
  "codeExample": "import { Stack } from \"@flikk/ui/layout\";\n\n<Stack direction=\"col\" gap={4}>\n <div>Profile</div>\n <div>Billing</div>\n <div>Notifications</div>\n</Stack>"
10362
10596
  },
10597
+ {
10598
+ "name": "AgentStatus",
10599
+ "category": "ai",
10600
+ "pattern": "enhanced",
10601
+ "importPath": "@flikk/ui/ai",
10602
+ "description": "Compact live-region status for AI and agent activity. Active labels use a high-contrast, brand-tinted Shimmer sweep and become static when settled.",
10603
+ "status": "stable",
10604
+ "productionReady": true,
10605
+ "generative": false,
10606
+ "props": {
10607
+ "mode": {
10608
+ "type": "AgentStatusMode",
10609
+ "default": "status",
10610
+ "description": "Single status row (default) or a collapsible reasoning disclosure.",
10611
+ "options": [
10612
+ "status",
10613
+ "reasoning"
10614
+ ]
10615
+ },
10616
+ "status": {
10617
+ "type": "AgentStatusState",
10618
+ "description": "Current execution state. Active labels shimmer; settled labels are static."
10619
+ },
10620
+ "label": {
10621
+ "type": "React.ReactNode",
10622
+ "required": true,
10623
+ "description": "Human-readable activity, for example \"Thinking\" or \"Searching sources\"."
10624
+ },
10625
+ "duration": {
10626
+ "type": "number",
10627
+ "description": "Elapsed or final duration in seconds. Takes precedence over `startedAt`, so pass it when the duration is authoritative (for example, returned by the server)."
10628
+ },
10629
+ "startedAt": {
10630
+ "type": "number",
10631
+ "description": "Epoch milliseconds the activity began. The duration then ticks on its own while `status` is `\"active\"` and freezes the moment it settles — no timer wiring in the consumer. Ignored when `duration` is supplied."
10632
+ },
10633
+ "icon": {
10634
+ "type": "React.ReactNode",
10635
+ "description": "Optional icon. When omitted, the animated semantic indicator is rendered."
10636
+ },
10637
+ "indicator": {
10638
+ "type": "boolean",
10639
+ "default": "true in `status` mode; active-only in `reasoning` mode",
10640
+ "description": "Show the leading status indicator (or custom `icon`). Set `false` for an icon-less, text-only row — the label then sits flush left. Defaults differ by mode: a `status` row always shows one, while a `reasoning` summary shows one only while active (the chevron carries the affordance once settled) — unless an `icon` is supplied, which opts back in. Pass explicitly to override either default."
10641
+ },
10642
+ "wrap": {
10643
+ "type": "boolean",
10644
+ "default": "false",
10645
+ "description": "Let the label wrap onto multiple lines instead of truncating. Steps render with this on; the standalone/summary row truncates by default."
10646
+ },
10647
+ "activeSuffix": {
10648
+ "type": "React.ReactNode",
10649
+ "default": "…",
10650
+ "description": "Text appended while active."
10651
+ },
10652
+ "shimmerDuration": {
10653
+ "type": "number",
10654
+ "default": "2",
10655
+ "description": "Active shimmer cycle duration in seconds."
10656
+ },
10657
+ "shimmerSpread": {
10658
+ "type": "number",
10659
+ "default": "16",
10660
+ "description": "Width of the active shimmer highlight band."
10661
+ },
10662
+ "shimmerColor": {
10663
+ "type": "string",
10664
+ "description": "Base color for the active shimmer text."
10665
+ },
10666
+ "shimmerHighlightColor": {
10667
+ "type": "string",
10668
+ "description": "Highlight color for the active shimmer sweep."
10669
+ },
10670
+ "live": {
10671
+ "type": "\"off\" | \"polite\" | \"assertive\"",
10672
+ "default": "polite",
10673
+ "description": "Accessible announcement behavior. `\"polite\"` waits for a pause rather than interrupting, which is what a background activity warrants."
10674
+ },
10675
+ "steps": {
10676
+ "type": "AgentStatusStepData[]",
10677
+ "description": "Structured reasoning steps. Rendered as a list of AgentStatus rows. Ignored unless `mode=\"reasoning\"`."
10678
+ },
10679
+ "open": {
10680
+ "type": "boolean",
10681
+ "description": "Controlled expanded state (reasoning mode)."
10682
+ },
10683
+ "defaultOpen": {
10684
+ "type": "boolean",
10685
+ "default": "false",
10686
+ "description": "Initial expanded state for uncontrolled reasoning usage."
10687
+ },
10688
+ "onOpenChange": {
10689
+ "type": "(open: boolean) => void"
10690
+ },
10691
+ "divider": {
10692
+ "type": "boolean",
10693
+ "default": "true",
10694
+ "description": "Render the full-width hairline under the reasoning trigger."
10695
+ }
10696
+ },
10697
+ "themeKeys": [
10698
+ "baseStyle",
10699
+ "iconStyle",
10700
+ "labelStyle",
10701
+ "durationStyle",
10702
+ "stateStyles",
10703
+ "idle",
10704
+ "active",
10705
+ "complete",
10706
+ "pending",
10707
+ "error",
10708
+ "indicatorStyles",
10709
+ "idle",
10710
+ "active",
10711
+ "complete",
10712
+ "pending",
10713
+ "error",
10714
+ "reasoningRootStyle",
10715
+ "triggerStyle",
10716
+ "triggerContentStyle",
10717
+ "chevronStyle",
10718
+ "dividerStyle",
10719
+ "contentStyle",
10720
+ "contentInnerStyle",
10721
+ "stepsStyle",
10722
+ "stepItemStyle",
10723
+ "proseStyle"
10724
+ ],
10725
+ "cssVariables": [
10726
+ "--color-text-muted",
10727
+ "--color-text-secondary",
10728
+ "--color-text-placeholder",
10729
+ "--color-danger",
10730
+ "--color-primary",
10731
+ "--color-success",
10732
+ "--color-border"
10733
+ ]
10734
+ },
10363
10735
  {
10364
10736
  "name": "CodeBlock",
10365
10737
  "category": "ai",
@@ -10441,8 +10813,8 @@
10441
10813
  "--color-text-muted",
10442
10814
  "--color-primary-50",
10443
10815
  "--color-primary",
10444
- "--color-neutral-400",
10445
- "--color-neutral-200",
10816
+ "--color-mono-400",
10817
+ "--color-mono-200",
10446
10818
  "--color-success-50",
10447
10819
  "--color-success",
10448
10820
  "--color-success-600",
@@ -10716,8 +11088,8 @@
10716
11088
  "--color-primary-900",
10717
11089
  "--color-danger",
10718
11090
  "--color-danger-50",
10719
- "--color-danger-500",
10720
- "--color-danger-950"
11091
+ "--color-danger-950",
11092
+ "--color-danger-500"
10721
11093
  ],
10722
11094
  "codeExample": "import { PromptInput } from \"@flikk/ui/ai\";\n\n<PromptInput placeholder=\"Ask me anything...\" />"
10723
11095
  },
@@ -10752,7 +11124,115 @@
10752
11124
  "--color-background-secondary",
10753
11125
  "--color-primary"
10754
11126
  ],
10755
- "codeExample": "import { PromptSuggestion } from \"@flikk/ui/ai\";\nimport { SparklesIcon } from \"@heroicons/react/16/solid\";\n\n<PromptSuggestion icon={<SparklesIcon className=\"size-4\" />}>\n Write a professional email\n</PromptSuggestion>"
11127
+ "codeExample": "import { PromptSuggestion } from \"@flikk/ui/ai\";\n\n<PromptSuggestion icon={<SparklesIcon className=\"size-4\" />}>\n Write a professional email\n</PromptSuggestion>"
11128
+ },
11129
+ {
11130
+ "name": "Reasoning",
11131
+ "category": "ai",
11132
+ "pattern": "compound",
11133
+ "importPath": "@flikk/ui/ai",
11134
+ "description": "Collapsed-by-default disclosure for concise, developer-provided reasoning summaries. Do not use it to expose private chain-of-thought.",
11135
+ "status": "stable",
11136
+ "productionReady": true,
11137
+ "generative": false,
11138
+ "props": {},
11139
+ "subComponents": [
11140
+ "Reasoning.Step"
11141
+ ]
11142
+ },
11143
+ {
11144
+ "name": "SourceCitation",
11145
+ "category": "ai",
11146
+ "pattern": "simple",
11147
+ "importPath": "@flikk/ui/ai",
11148
+ "description": "Inline citation chip that opens an accessible source preview popover. Group related citations with SourceCitationGroup.",
11149
+ "status": "stable",
11150
+ "productionReady": true,
11151
+ "generative": false,
11152
+ "props": {
11153
+ "index": {
11154
+ "type": "React.ReactNode",
11155
+ "description": "Citation number or compact identifier displayed in the chip."
11156
+ },
11157
+ "title": {
11158
+ "type": "React.ReactNode",
11159
+ "required": true,
11160
+ "description": "Source title displayed in the preview."
11161
+ },
11162
+ "domain": {
11163
+ "type": "React.ReactNode",
11164
+ "description": "Source domain displayed in both the chip and preview."
11165
+ },
11166
+ "excerpt": {
11167
+ "type": "React.ReactNode",
11168
+ "description": "Supporting source excerpt."
11169
+ },
11170
+ "href": {
11171
+ "type": "string",
11172
+ "description": "Destination URL."
11173
+ },
11174
+ "icon": {
11175
+ "type": "React.ReactNode",
11176
+ "description": "Optional source or favicon icon."
11177
+ },
11178
+ "preview": {
11179
+ "type": "React.ReactNode",
11180
+ "description": "Fully custom preview content."
11181
+ },
11182
+ "placement": {
11183
+ "type": "PopoverPlacement",
11184
+ "description": "Popover placement relative to the citation chip."
11185
+ },
11186
+ "open": {
11187
+ "type": "boolean",
11188
+ "description": "Controlled popover state."
11189
+ },
11190
+ "defaultOpen": {
11191
+ "type": "boolean",
11192
+ "description": "Initial popover state for uncontrolled usage."
11193
+ },
11194
+ "onOpenChange": {
11195
+ "type": "(open: boolean) => void"
11196
+ },
11197
+ "openInNewTab": {
11198
+ "type": "boolean",
11199
+ "default": "true",
11200
+ "description": "Open the source link in a new tab."
11201
+ },
11202
+ "linkLabel": {
11203
+ "type": "React.ReactNode",
11204
+ "default": "Open source",
11205
+ "description": "Label for the link at the foot of the preview. Overridable so the string is not trapped in English."
11206
+ }
11207
+ },
11208
+ "separateExports": [
11209
+ "SourceCitationGroup"
11210
+ ],
11211
+ "themeKeys": [
11212
+ "triggerStyle",
11213
+ "indexStyle",
11214
+ "faviconStyle",
11215
+ "domainStyle",
11216
+ "popoverStyle",
11217
+ "previewHeaderStyle",
11218
+ "previewIconStyle",
11219
+ "previewTitleStyle",
11220
+ "previewDomainStyle",
11221
+ "excerptStyle",
11222
+ "linkStyle",
11223
+ "groupStyle"
11224
+ ],
11225
+ "cssVariables": [
11226
+ "--color-border",
11227
+ "--color-surface",
11228
+ "--color-text-secondary",
11229
+ "--color-border-hover",
11230
+ "--color-surface-hover",
11231
+ "--color-text-primary",
11232
+ "--color-primary",
11233
+ "--color-surface-sunken",
11234
+ "--color-text-muted"
11235
+ ]
10756
11236
  },
10757
11237
  {
10758
11238
  "name": "StreamingResponse",
@@ -10893,7 +11373,7 @@
10893
11373
  "loadingDotStyle"
10894
11374
  ],
10895
11375
  "cssVariables": [
10896
- "--radius-base",
11376
+ "--alert-radius",
10897
11377
  "--color-danger-200",
10898
11378
  "--color-danger-50",
10899
11379
  "--color-danger",
@@ -10901,7 +11381,7 @@
10901
11381
  "--color-danger-700",
10902
11382
  "--color-text-placeholder"
10903
11383
  ],
10904
- "codeExample": "import { StreamingResponse } from \"@flikk/ui/ai\";\nimport { CpuChipIcon } from \"@heroicons/react/24/outline\";\n\n<StreamingResponse\n url=\"/api/chat\"\n method=\"POST\"\n body={{ prompt: \"Hello!\" }}\n format=\"openai\"\n animated\n showCursor\n role=\"assistant\"\n avatar={{ name: \"AI Assistant\", fallback: <CpuChipIcon /> }}\n showTimestamp\n showActions\n/>"
11384
+ "codeExample": "import { StreamingResponse } from \"@flikk/ui/ai\";\n\n<StreamingResponse\n url=\"/api/chat\"\n method=\"POST\"\n body={{ prompt: \"Hello!\" }}\n format=\"openai\"\n animated\n showCursor\n role=\"assistant\"\n avatar={{ name: \"AI Assistant\", fallback: <CpuChipIcon /> }}\n showTimestamp\n showActions\n/>"
10905
11385
  },
10906
11386
  {
10907
11387
  "name": "TokenCounter",
@@ -11004,25 +11484,40 @@
11004
11484
  "Icon",
11005
11485
  "Separator"
11006
11486
  ],
11007
- "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n AvatarGroup,\n Badge,\n Button,\n Icon,\n Separator,\n} from \"../../components/core\";\nimport { Feed } from \"../../components/data-display\";\nimport {\n CodeBracketIcon,\n RocketLaunchIcon,\n DocumentCheckIcon,\n BugAntIcon,\n TagIcon,\n ArrowPathIcon,\n FunnelIcon,\n ChatBubbleLeftEllipsisIcon,\n UserPlusIcon,\n} from \"@heroicons/react/24/solid\";\n\nconst meta: Meta = {\n title: \"Blocks/ActivityTimelineLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nconst avatars = {\n sarah:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n james:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n emily:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n david:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n alex: \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst ActivityPage = () => {\n return (\n <div className=\"py-8 sm:py-12 px-6\">\n <div className=\"max-w-3xl mx-auto\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-8\">\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)]\">\n Activity\n </h1>\n <p className=\"text-[var(--color-text-muted)] mt-1\">\n Everything happening across your projects.\n </p>\n </div>\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n <FunnelIcon className=\"size-4\" /> Filter\n </Button>\n </div>\n\n {/* Timeline feed */}\n <div className=\"space-y-1\">\n {/* Date section: Today */}\n <div className=\"flex items-center gap-3 mb-4\">\n <span className=\"text-xs font-semibold text-[var(--color-text-muted)] uppercase tracking-wider\">\n Today\n </span>\n <Separator className=\"flex-1\" />\n </div>\n\n <Feed>\n {/* Deploy */}\n <Feed.Item\n icon={\n <RocketLaunchIcon className=\"size-5 text-[var(--color-success)]\" />\n }\n indicatorClassName=\"bg-[var(--color-success-50)]\"\n timestamp=\"35m ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.sarah} name=\"Sarah Chen\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Sarah Chen\n </span>\n deployed\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n v2.5.0\n </span>\n to production\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Production\n </Badge>\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n 3 services updated\n </span>\n </div>\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Healthy\n </Badge>\n </div>\n </div>\n </Feed.Item>\n\n {/* Commits */}\n <Feed.Item\n icon={\n <CodeBracketIcon className=\"size-5 text-[var(--color-secondary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-secondary-50)]\"\n timestamp=\"1h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.james} name=\"James Wilson\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n James Wilson\n </span>\n pushed 4 commits to\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n feature/table-refactor\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] space-y-1.5\">\n {[\n \"Refactor Table to support dual API pattern\",\n \"Add compound component sub-types\",\n \"Fix column alignment for right-aligned cells\",\n ].map((msg) => (\n <div key={msg} className=\"flex items-start gap-2 text-xs\">\n <CodeBracketIcon className=\"size-3.5 text-[var(--color-text-muted)] shrink-0 mt-0.5\" />\n <span className=\"text-[var(--color-text-secondary)]\">\n {msg}\n </span>\n </div>\n ))}\n </div>\n </div>\n </Feed.Item>\n\n {/* Code review */}\n <Feed.Item\n icon={\n <DocumentCheckIcon className=\"size-5 text-[var(--color-success)]\" />\n }\n indicatorClassName=\"bg-[var(--color-success-50)]\"\n timestamp=\"2h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.emily} name=\"Emily Rodriguez\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Emily Rodriguez\n </span>\n approved\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n PR #247 — Add dark mode support\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <DocumentCheckIcon className=\"size-4 text-[var(--color-success)]\" />\n <span className=\"text-xs text-[var(--color-text-secondary)]\">\n +1,247 / -342 lines\n </span>\n </div>\n <AvatarGroup\n max={3}\n size=\"xs\"\n avatars={[\n { src: avatars.emily, name: \"Emily\" },\n { src: avatars.david, name: \"David\" },\n ]}\n />\n </div>\n </div>\n </Feed.Item>\n\n {/* Bug fix */}\n <Feed.Item\n icon={\n <BugAntIcon className=\"size-5 text-[var(--color-danger)]\" />\n }\n indicatorClassName=\"bg-[var(--color-danger-50)]\"\n timestamp=\"3h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.david} name=\"David Kim\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n David Kim\n </span>\n resolved issue\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n #312 — Modal focus trap not releasing\n </span>\n </div>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge color=\"danger\" variant=\"soft\" size=\"sm\">\n Bug\n </Badge>\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Closed\n </Badge>\n </div>\n </div>\n </Feed.Item>\n\n {/* Comment */}\n <Feed.Item\n icon={\n <ChatBubbleLeftEllipsisIcon className=\"size-5 text-[var(--color-primary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"4h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.alex} name=\"Alex Rivera\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Alex Rivera\n </span>\n commented on\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n PR #245\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2.5 rounded-md border border-[var(--color-border)]\">\n <p className=\"text-sm text-[var(--color-text-secondary)] italic\">\n \"The new chart API is much cleaner. Let's ship it after we\n add the missing tooltip tests.\"\n </p>\n </div>\n </div>\n </Feed.Item>\n </Feed>\n\n {/* Date section: Yesterday */}\n <div className=\"flex items-center gap-3 my-6\">\n <span className=\"text-xs font-semibold text-[var(--color-text-muted)] uppercase tracking-wider\">\n Yesterday\n </span>\n <Separator className=\"flex-1\" />\n </div>\n\n <Feed>\n {/* Release */}\n <Feed.Item\n icon={<TagIcon className=\"size-5 text-[var(--color-primary)]\" />}\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.alex} name=\"Alex Rivera\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Alex Rivera\n </span>\n created release\n <Badge color=\"primary\" variant=\"soft\" size=\"sm\">\n v2.4.1\n </Badge>\n with 8 bug fixes and 3 improvements\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center gap-3\">\n <Icon icon=\"pdf\" size=\"lg\" />\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)] text-sm\">\n CHANGELOG-v2.4.1.pdf\n </p>\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n 148 KB\n </p>\n </div>\n </div>\n </div>\n </Feed.Item>\n\n {/* Revert */}\n <Feed.Item\n icon={\n <ArrowPathIcon className=\"size-5 text-[var(--color-warning)]\" />\n }\n indicatorClassName=\"bg-[var(--color-warning-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.james} name=\"James Wilson\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n James Wilson\n </span>\n reverted commit\n <span className=\"font-mono text-xs text-[var(--color-text-muted)]\">\n a3f8c21\n </span>\n due to CI failure\n </div>\n </Feed.Item>\n\n {/* Assignment */}\n <Feed.Item\n icon={\n <UserPlusIcon className=\"size-5 text-[var(--color-primary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.sarah} name=\"Sarah Chen\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Sarah Chen\n </span>\n assigned\n <Avatar src={avatars.david} name=\"David Kim\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n David Kim\n </span>\n to issue\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n #318\n </span>\n </div>\n </Feed.Item>\n </Feed>\n\n {/* Load more */}\n <div className=\"text-center pt-6\">\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n Load More Activity\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport const Default: Story = {\n render: () => <ActivityPage />,\n parameters: {\n controls: { disable: true },\n },\n};"
11487
+ "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n AvatarGroup,\n Badge,\n Button,\n Icon,\n Separator,\n} from \"../../components/core\";\nimport { Feed } from \"../../components/data-display\";\nimport {\n Code as CodeBracketIcon,\n RocketLaunch as RocketLaunchIcon,\n ListChecks as DocumentCheckIcon,\n Bug as BugAntIcon,\n Tag as TagIcon,\n ArrowsClockwise as ArrowPathIcon,\n Funnel as FunnelIcon,\n ChatCircleDots as ChatBubbleLeftEllipsisIcon,\n UserPlus as UserPlusIcon,\n} from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/ActivityTimelineLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nconst avatars = {\n sarah:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n james:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n emily:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n david:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n alex: \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst ActivityPage = () => {\n return (\n <div className=\"py-8 sm:py-12 px-6\">\n <div className=\"max-w-3xl mx-auto\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-8\">\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold text-[var(--color-text-primary)]\">\n Activity\n </h1>\n <p className=\"text-[var(--color-text-muted)] mt-1\">\n Everything happening across your projects.\n </p>\n </div>\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n <FunnelIcon className=\"size-4\" /> Filter\n </Button>\n </div>\n\n {/* Timeline feed */}\n <div className=\"space-y-1\">\n {/* Date section: Today */}\n <div className=\"flex items-center gap-3 mb-4\">\n <span className=\"text-xs font-semibold text-[var(--color-text-muted)] uppercase tracking-wider\">\n Today\n </span>\n <Separator className=\"flex-1\" />\n </div>\n\n <Feed>\n {/* Deploy */}\n <Feed.Item\n icon={\n <RocketLaunchIcon className=\"size-5 text-[var(--color-success)]\" />\n }\n indicatorClassName=\"bg-[var(--color-success-50)]\"\n timestamp=\"35m ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.sarah} name=\"Sarah Chen\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Sarah Chen\n </span>\n deployed\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n v2.5.0\n </span>\n to production\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Production\n </Badge>\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n 3 services updated\n </span>\n </div>\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Healthy\n </Badge>\n </div>\n </div>\n </Feed.Item>\n\n {/* Commits */}\n <Feed.Item\n icon={\n <CodeBracketIcon className=\"size-5 text-[var(--color-secondary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-secondary-50)]\"\n timestamp=\"1h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.james} name=\"James Wilson\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n James Wilson\n </span>\n pushed 4 commits to\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n feature/table-refactor\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] space-y-1.5\">\n {[\n \"Refactor Table to support dual API pattern\",\n \"Add compound component sub-types\",\n \"Fix column alignment for right-aligned cells\",\n ].map((msg) => (\n <div key={msg} className=\"flex items-start gap-2 text-xs\">\n <CodeBracketIcon className=\"size-3.5 text-[var(--color-text-muted)] shrink-0 mt-0.5\" />\n <span className=\"text-[var(--color-text-secondary)]\">\n {msg}\n </span>\n </div>\n ))}\n </div>\n </div>\n </Feed.Item>\n\n {/* Code review */}\n <Feed.Item\n icon={\n <DocumentCheckIcon className=\"size-5 text-[var(--color-success)]\" />\n }\n indicatorClassName=\"bg-[var(--color-success-50)]\"\n timestamp=\"2h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.emily} name=\"Emily Rodriguez\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Emily Rodriguez\n </span>\n approved\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n PR #247 — Add dark mode support\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <DocumentCheckIcon className=\"size-4 text-[var(--color-success)]\" />\n <span className=\"text-xs text-[var(--color-text-secondary)]\">\n +1,247 / -342 lines\n </span>\n </div>\n <AvatarGroup\n max={3}\n size=\"xs\"\n avatars={[\n { src: avatars.emily, name: \"Emily\" },\n { src: avatars.david, name: \"David\" },\n ]}\n />\n </div>\n </div>\n </Feed.Item>\n\n {/* Bug fix */}\n <Feed.Item\n icon={\n <BugAntIcon className=\"size-5 text-[var(--color-danger)]\" />\n }\n indicatorClassName=\"bg-[var(--color-danger-50)]\"\n timestamp=\"3h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.david} name=\"David Kim\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n David Kim\n </span>\n resolved issue\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n #312 — Modal focus trap not releasing\n </span>\n </div>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge color=\"danger\" variant=\"soft\" size=\"sm\">\n Bug\n </Badge>\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n Closed\n </Badge>\n </div>\n </div>\n </Feed.Item>\n\n {/* Comment */}\n <Feed.Item\n icon={\n <ChatBubbleLeftEllipsisIcon className=\"size-5 text-[var(--color-primary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"4h ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.alex} name=\"Alex Rivera\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Alex Rivera\n </span>\n commented on\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n PR #245\n </span>\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2.5 rounded-md border border-[var(--color-border)]\">\n <p className=\"text-sm text-[var(--color-text-secondary)] italic\">\n \"The new chart API is much cleaner. Let's ship it after we\n add the missing tooltip tests.\"\n </p>\n </div>\n </div>\n </Feed.Item>\n </Feed>\n\n {/* Date section: Yesterday */}\n <div className=\"flex items-center gap-3 my-6\">\n <span className=\"text-xs font-semibold text-[var(--color-text-muted)] uppercase tracking-wider\">\n Yesterday\n </span>\n <Separator className=\"flex-1\" />\n </div>\n\n <Feed>\n {/* Release */}\n <Feed.Item\n icon={<TagIcon className=\"size-5 text-[var(--color-primary)]\" />}\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm\">\n <div className=\"flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.alex} name=\"Alex Rivera\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Alex Rivera\n </span>\n created release\n <Badge color=\"primary\" variant=\"soft\" size=\"sm\">\n v2.4.1\n </Badge>\n with 8 bug fixes and 3 improvements\n </div>\n <div className=\"mt-2 bg-[var(--color-background)] p-2 rounded-md border border-[var(--color-border)] flex items-center gap-3\">\n <Icon icon=\"pdf\" size=\"lg\" />\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)] text-sm\">\n CHANGELOG-v2.4.1.pdf\n </p>\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n 148 KB\n </p>\n </div>\n </div>\n </div>\n </Feed.Item>\n\n {/* Revert */}\n <Feed.Item\n icon={\n <ArrowPathIcon className=\"size-5 text-[var(--color-warning)]\" />\n }\n indicatorClassName=\"bg-[var(--color-warning-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.james} name=\"James Wilson\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n James Wilson\n </span>\n reverted commit\n <span className=\"font-mono text-xs text-[var(--color-text-muted)]\">\n a3f8c21\n </span>\n due to CI failure\n </div>\n </Feed.Item>\n\n {/* Assignment */}\n <Feed.Item\n icon={\n <UserPlusIcon className=\"size-5 text-[var(--color-primary)]\" />\n }\n indicatorClassName=\"bg-[var(--color-primary-50)]\"\n timestamp=\"1d ago\"\n >\n <div className=\"text-sm flex items-center flex-wrap gap-1.5 text-[var(--color-text-secondary)]\">\n <Avatar src={avatars.sarah} name=\"Sarah Chen\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n Sarah Chen\n </span>\n assigned\n <Avatar src={avatars.david} name=\"David Kim\" size=\"xs\" />\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n David Kim\n </span>\n to issue\n <span className=\"font-medium text-[var(--color-text-primary)]\">\n #318\n </span>\n </div>\n </Feed.Item>\n </Feed>\n\n {/* Load more */}\n <div className=\"text-center pt-6\">\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n Load More Activity\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport const Default: Story = {\n render: () => <ActivityPage />,\n parameters: {\n controls: { disable: true },\n },\n};"
11008
11488
  },
11009
11489
  {
11010
11490
  "name": "AIAssistantLayout",
11011
11491
  "title": "Blocks/AIAssistantLayout",
11012
- "description": "Full-page composition using AIOrb, Badge, Button, CodeBlock, ….",
11492
+ "description": "Full-page composition using AIOrb, Badge, Button, Card, ….",
11013
11493
  "componentsUsed": [
11014
11494
  "AIOrb",
11015
11495
  "Badge",
11016
11496
  "Button",
11497
+ "Card",
11017
11498
  "CodeBlock",
11018
11499
  "DotPattern",
11500
+ "Drawer",
11019
11501
  "GlassSurface",
11020
11502
  "Message",
11021
11503
  "ProgressiveBlur",
11022
11504
  "PromptInput",
11505
+ "Reasoning",
11506
+ "SourceCitation",
11023
11507
  "Table"
11024
11508
  ],
11025
- "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Badge, Button, Message } from \"../../components/core\";\nimport {\n PromptInput,\n CodeBlock,\n} from \"../../components/ai\";\nimport { ArchiveBoxIcon, ArrowUpRightIcon } from \"@heroicons/react/24/outline\";\nimport {\n DotPattern,\n GlassSurface,\n ProgressiveBlur,\n} from \"../../components/effects\";\nimport { AIOrb } from \"../../components/effects/AIOrb\";\n\nconst meta: Meta = {\n title: \"Blocks/AIAssistantLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Message content blocks ---\n\nconst assistantAvatar = { name: \"AI\", fallback: \"AI\" as React.ReactNode };\nconst userAvatar = {\n src: \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n name: \"Sarah Chen\",\n};\n\nconst message2Content = (\n <div className=\"space-y-4\">\n <p>\n Great question! A dual API pattern lets users choose between\n simplicity and flexibility. Here&apos;s the approach:\n </p>\n <p>\n <strong>1. Simple prop-based API</strong> — Pass data and columns as\n props:\n </p>\n <CodeBlock\n language=\"tsx\"\n code={`<Table data={users} columns={columns} rowKey=\"id\" />`}\n />\n <p>\n <strong>2. Compound component API</strong> — Full composition control:\n </p>\n <CodeBlock\n language=\"tsx\"\n code={`<Table>\n <Table.Header>\n <Table.Row>\n <Table.HeaderCell>Name</Table.HeaderCell>\n <Table.HeaderCell>Email</Table.HeaderCell>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n <Table.Row>\n <Table.Cell>Sarah Chen</Table.Cell>\n <Table.Cell>sarah@company.com</Table.Cell>\n </Table.Row>\n </Table.Body>\n</Table>`}\n />\n <p>\n The key is to detect which API the user is using inside the root{\" \"}\n <code>Table</code> component. If <code>data</code> and{\" \"}\n <code>columns</code> props are provided, render automatically.\n Otherwise, render <code>children</code>.\n </p>\n </div>\n);\n\nconst message4Content = (\n <div className=\"space-y-4\">\n <p>Here&apos;s the detection pattern:</p>\n <CodeBlock\n language=\"tsx\"\n code={`const Table = ({ data, columns, children, ...props }) => {\n const isSimpleAPI = data !== undefined && columns !== undefined;\n\n if (isSimpleAPI) {\n return (\n <table {...props}>\n <thead>\n <tr>\n {columns.map(col => (\n <th key={col.id}>{col.header}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map(row => (\n <tr key={row[rowKey]}>\n {columns.map(col => (\n <td key={col.id}>\n {col.cell ? col.cell(row) : row[col.accessor]}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n\n // Compound API — render children as-is\n return <table {...props}>{children}</table>;\n};`}\n />\n <p>\n This pattern is clean and backwards-compatible. The compound\n sub-components (<code>Table.Header</code>, <code>Table.Body</code>,\n etc.) are assigned as static properties on the <code>Table</code>{\" \"}\n component.\n </p>\n </div>\n);\n\n// --- Models ---\n\nconst models = [\n { key: \"claude-4\", label: \"Claude 4 Opus\", description: \"Most capable\" },\n {\n key: \"claude-4-sonnet\",\n label: \"Claude 4 Sonnet\",\n description: \"Fast & smart\",\n },\n { key: \"claude-4-haiku\", label: \"Claude 4 Haiku\", description: \"Fastest\" },\n];\n\nexport const Default: Story = {\n render: () => (\n <div className=\"h-[100dvh] relative overflow-hidden bg-white dark:bg-[var(--color-background)] flex flex-col\">\n <DotPattern spacing={24} dotSize={1.5} fade fadeSize={100} />\n\n {/* Header */}\n <div className=\"relative z-10 flex items-center justify-between px-3 sm:px-6 py-3 sm:py-4 border-b border-[var(--color-border)]/60\">\n <div className=\"flex items-center gap-2 sm:gap-3 min-w-0\">\n <div className=\"size-2 shrink-0 rounded-full bg-[var(--color-primary)]\" />\n <h1 className=\"font-semibold text-sm sm:text-base text-[var(--color-text-primary)] truncate\">\n Refactor Table component\n </h1>\n <Badge color=\"neutral\" variant=\"soft\" size=\"xs\" className=\"hidden sm:inline-flex\">\n 4 messages\n </Badge>\n </div>\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly className=\"shrink-0\">\n <ArchiveBoxIcon className=\"size-4\" />\n </Button>\n </div>\n\n {/* Messages */}\n <div className=\"relative z-10 flex-1 overflow-hidden\">\n <Message.List\n className=\"h-full\"\n theme={{\n innerStyle:\n \"flex flex-col gap-8 sm:gap-12 p-3 sm:p-6 max-w-3xl mx-auto w-full\",\n }}\n >\n <Message\n key=\"1\"\n role=\"user\"\n content=\"How do I refactor the Table component to support both a simple prop-based API and a compound component API?\"\n timestamp=\"10:24 AM\"\n avatar={userAvatar}\n onCopy={() => {}}\n />\n <Message\n key=\"2\"\n role=\"assistant\"\n content={message2Content}\n timestamp=\"10:25 AM\"\n avatar={assistantAvatar}\n onCopy={() => {}}\n onRegenerate={() => {}}\n />\n <Message\n key=\"3\"\n role=\"user\"\n content=\"Can you show me how to detect which API is being used in the component?\"\n timestamp=\"10:26 AM\"\n avatar={userAvatar}\n onCopy={() => {}}\n />\n <Message\n key=\"4\"\n role=\"assistant\"\n content={message4Content}\n timestamp=\"10:27 AM\"\n avatar={assistantAvatar}\n onCopy={() => {}}\n onRegenerate={() => {}}\n />\n </Message.List>\n <ProgressiveBlur\n position=\"bottom\"\n size=\"80px\"\n blurIntensity={6}\n className=\"bottom-0\"\n style={{ marginBottom: -1 }}\n />\n </div>\n\n {/* Input zone */}\n <div className=\"relative z-10 px-3 py-2 sm:p-4\">\n <div className=\"max-w-3xl mx-auto\">\n <PromptInput\n placeholder=\"Ask a follow-up question...\"\n models={models}\n defaultSelectedModel=\"claude-4\"\n showAttachmentButton\n showVoiceButton={false}\n showSettingsButton={false}\n onSubmit={() => {}}\n className=\"min-w-0\"\n />\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};\n\nconst suggestionCards = [\n {\n title: \"Marketing Insights\",\n description:\n \"Discover the best marketing strategies to showcase your properties.\",\n },\n {\n title: \"Negotiation Tactics\",\n description: \"Learn expert negotiation tips to close deals effectively.\",\n },\n {\n title: \"Sales Strategies\",\n description:\n \"Get tailored advice on increasing property visibility and driving sales.\",\n },\n];\n\nexport const Empty: Story = {\n render: () => (\n <div className=\"h-[100dvh] relative overflow-hidden bg-white dark:bg-[var(--color-background)] flex flex-col\">\n <DotPattern\n spacing={24}\n dotSize={1.5}\n fade\n fadeSize={100}\n />\n\n {/* Centered hero content */}\n <div className=\"relative z-10 flex-1 flex flex-col items-center justify-center px-4 sm:px-6\">\n <div className=\"mb-4 sm:mb-6\">\n <AIOrb\n size={100}\n backgroundColor=\"transparent\"\n className=\"rounded-full sm:hidden\"\n >\n <AIOrb.DotSphere />\n </AIOrb>\n <AIOrb\n size={140}\n backgroundColor=\"transparent\"\n className=\"rounded-full hidden sm:block\"\n >\n <AIOrb.DotSphere />\n </AIOrb>\n </div>\n\n <h1 className=\"text-2xl sm:text-4xl lg:text-5xl font-bold text-[var(--color-text-primary)] tracking-tight text-center\">\n How can we <span className=\"text-[var(--color-primary)]\">assist</span>{\" \"}\n you today?\n </h1>\n\n <p className=\"text-[var(--color-text-muted)] mt-2 sm:mt-3 max-w-lg text-center text-sm sm:text-base px-2\">\n Your AI-powered companion for real estate insights, strategies, and\n expert guidance — available around the clock.\n </p>\n\n {/* Suggestion cards */}\n <div className=\"relative grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 mt-6 sm:mt-10 w-full max-w-4xl\">\n {suggestionCards.map((card) => (\n <GlassSurface\n key={card.title}\n borderRadius={24}\n borderWidth={1.5}\n redOffset={0}\n greenOffset={15}\n blueOffset={35}\n className=\"h-full\"\n >\n <button\n type=\"button\"\n className=\"group relative flex flex-col items-start text-left rounded-[24px] bg-white/10 dark:bg-[var(--color-background-secondary)]/60 backdrop-blur-md p-4 sm:p-5 transition-all duration-300 cursor-pointer w-full h-full hover:bg-[var(--color-background-secondary)]/10 hover:ring-2 hover:ring-[var(--color-border)]\"\n >\n <ArrowUpRightIcon className=\"size-4 sm:size-5 text-[var(--color-text-muted)] absolute top-3 right-3 sm:top-4 sm:right-4 transition-all duration-300 group-hover:text-[var(--color-text-primary)]\" />\n <h3 className=\"font-medium text-[var(--color-text-primary)] text-base sm:text-lg pr-6\">\n {card.title}\n </h3>\n <p className=\"text-[var(--color-text-muted)] text-sm sm:text-base mt-1 sm:mt-2\">\n {card.description}\n </p>\n </button>\n </GlassSurface>\n ))}\n </div>\n </div>\n\n {/* PromptInput at bottom */}\n <div className=\"relative z-10 px-3 py-2 sm:p-4 lg:p-6\">\n <div className=\"max-w-4xl mx-auto\">\n <PromptInput\n placeholder=\"Type your prompt here\"\n showAttachmentButton\n showVoiceButton\n showModelSelector={false}\n showSettingsButton={false}\n onSubmit={() => {}}\n />\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11509
+ "source": "import React, { useState } from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Badge, Button, Card, Drawer, Message } from \"../../components/core\";\nimport {\n PromptInput,\n CodeBlock,\n Reasoning,\n SourceCitation,\n SourceCitationGroup,\n} from \"../../components/ai\";\nimport { Archive as ArchiveBoxIcon, ArrowUpRight as ArrowUpRightIcon, CodeBlock as CodeBracketSquareIcon } from \"@phosphor-icons/react\";\nimport {\n DotPattern,\n GlassSurface,\n ProgressiveBlur,\n} from \"../../components/effects\";\nimport { AIOrb } from \"../../components/effects/AIOrb\";\n\nconst meta: Meta = {\n title: \"Blocks/AIAssistantLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Message content blocks ---\n\nconst assistantAvatar = { name: \"AI\", fallback: \"AI\" as React.ReactNode };\nconst userAvatar = {\n src: \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n name: \"Sarah Chen\",\n};\n\nconst message2Content = (\n <div className=\"space-y-4\">\n <p>\n Great question! A dual API pattern lets users choose between\n simplicity and flexibility. Here&apos;s the approach:\n </p>\n <p>\n <strong>1. Simple prop-based API</strong> — Pass data and columns as\n props:\n </p>\n <CodeBlock\n language=\"tsx\"\n code={`<Table data={users} columns={columns} rowKey=\"id\" />`}\n />\n <p>\n <strong>2. Compound component API</strong> — Full composition control:\n </p>\n <CodeBlock\n language=\"tsx\"\n code={`<Table>\n <Table.Header>\n <Table.Row>\n <Table.HeaderCell>Name</Table.HeaderCell>\n <Table.HeaderCell>Email</Table.HeaderCell>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n <Table.Row>\n <Table.Cell>Sarah Chen</Table.Cell>\n <Table.Cell>sarah@company.com</Table.Cell>\n </Table.Row>\n </Table.Body>\n</Table>`}\n />\n <p>\n The key is to detect which API the user is using inside the root{\" \"}\n <code>Table</code> component. If <code>data</code> and{\" \"}\n <code>columns</code> props are provided, render automatically.\n Otherwise, render <code>children</code>.\n </p>\n </div>\n);\n\nconst artifactCode = `const Table = ({ data, columns, children, ...props }) => {\n const isSimpleAPI = data !== undefined && columns !== undefined;\n\n if (isSimpleAPI) {\n return <GeneratedTable data={data} columns={columns} {...props} />;\n }\n\n return <table {...props}>{children}</table>;\n};`;\n\nconst createMessage4Content = (onOpenArtifact: () => void) => (\n <div className=\"space-y-4\">\n <Reasoning\n label=\"Thought\"\n status=\"complete\"\n duration={4}\n steps={[\n { label: \"Reviewed the existing Table API\", status: \"complete\", duration: 1 },\n { label: \"Compared prop-based and compound patterns\", status: \"complete\", duration: 2 },\n { label: \"Prepared a backwards-compatible implementation\", status: \"complete\", duration: 1 },\n ]}\n />\n <p>Here&apos;s the detection pattern:</p>\n <CodeBlock\n language=\"tsx\"\n code={`const Table = ({ data, columns, children, ...props }) => {\n const isSimpleAPI = data !== undefined && columns !== undefined;\n\n if (isSimpleAPI) {\n return (\n <table {...props}>\n <thead>\n <tr>\n {columns.map(col => (\n <th key={col.id}>{col.header}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map(row => (\n <tr key={row[rowKey]}>\n {columns.map(col => (\n <td key={col.id}>\n {col.cell ? col.cell(row) : row[col.accessor]}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n\n // Compound API — render children as-is\n return <table {...props}>{children}</table>;\n};`}\n />\n <p>\n This pattern is clean and backwards-compatible. The compound\n sub-components (<code>Table.Header</code>, <code>Table.Body</code>,\n etc.) are assigned as static properties on the <code>Table</code>{\" \"}\n component.\n </p>\n <SourceCitationGroup>\n <SourceCitation\n index={1}\n title=\"Thinking in React\"\n domain=\"react.dev\"\n excerpt=\"A practical guide to decomposing an interface into reusable component boundaries.\"\n href=\"https://react.dev/learn/thinking-in-react\"\n />\n <SourceCitation\n index={2}\n title=\"WAI-ARIA Authoring Practices\"\n domain=\"w3.org\"\n excerpt=\"Accessible interaction patterns for reusable web components.\"\n href=\"https://www.w3.org/WAI/ARIA/apg/\"\n />\n </SourceCitationGroup>\n <Button\n variant=\"soft\"\n color=\"mono\"\n size=\"sm\"\n onClick={onOpenArtifact}\n >\n <CodeBracketSquareIcon className=\"size-4\" />\n Open generated artifact\n </Button>\n </div>\n);\n\n// --- Models ---\n\nconst models = [\n { key: \"claude-4\", label: \"Claude 4 Opus\", description: \"Most capable\" },\n {\n key: \"claude-4-sonnet\",\n label: \"Claude 4 Sonnet\",\n description: \"Fast & smart\",\n },\n { key: \"claude-4-haiku\", label: \"Claude 4 Haiku\", description: \"Fastest\" },\n];\n\nconst AIAssistantDefault = () => {\n const [artifactOpen, setArtifactOpen] = useState(false);\n\n return (\n <>\n <div\n data-flik-drawer-wrapper\n className=\"h-[100dvh] relative overflow-hidden bg-white dark:bg-[var(--color-background)] flex flex-col\"\n >\n <DotPattern spacing={24} dotSize={1.5} fade fadeSize={100} />\n\n {/* Header */}\n <div className=\"relative z-10 flex items-center justify-between px-3 sm:px-6 py-3 sm:py-4 border-b border-[var(--color-border)]/60\">\n <div className=\"flex items-center gap-2 sm:gap-3 min-w-0\">\n <div className=\"size-2 shrink-0 rounded-full bg-[var(--color-primary)]\" />\n <h1 className=\"font-semibold text-sm sm:text-base text-[var(--color-text-primary)] truncate\">\n Refactor Table component\n </h1>\n <Badge color=\"mono\" variant=\"soft\" size=\"xs\" className=\"hidden sm:inline-flex\">\n 4 messages\n </Badge>\n </div>\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly className=\"shrink-0\">\n <ArchiveBoxIcon className=\"size-4\" />\n </Button>\n </div>\n\n {/* Messages */}\n <div className=\"relative z-10 flex-1 overflow-hidden\">\n <Message.List\n className=\"h-full\"\n theme={{\n innerStyle:\n \"flex flex-col gap-8 sm:gap-12 p-3 sm:p-6 max-w-3xl mx-auto w-full\",\n }}\n >\n <Message\n key=\"1\"\n role=\"user\"\n content=\"How do I refactor the Table component to support both a simple prop-based API and a compound component API?\"\n timestamp=\"10:24 AM\"\n avatar={userAvatar}\n onCopy={() => {}}\n />\n <Message\n key=\"2\"\n role=\"assistant\"\n content={message2Content}\n timestamp=\"10:25 AM\"\n avatar={assistantAvatar}\n onCopy={() => {}}\n onRegenerate={() => {}}\n />\n <Message\n key=\"3\"\n role=\"user\"\n content=\"Can you show me how to detect which API is being used in the component?\"\n timestamp=\"10:26 AM\"\n avatar={userAvatar}\n onCopy={() => {}}\n />\n <Message\n key=\"4\"\n role=\"assistant\"\n content={createMessage4Content(() => setArtifactOpen(true))}\n timestamp=\"10:27 AM\"\n avatar={assistantAvatar}\n onCopy={() => {}}\n onRegenerate={() => {}}\n />\n </Message.List>\n <ProgressiveBlur\n position=\"bottom\"\n size=\"80px\"\n blurIntensity={6}\n className=\"bottom-0\"\n style={{ marginBottom: -1 }}\n />\n </div>\n\n {/* Input zone */}\n <div className=\"relative z-10 px-3 py-2 sm:p-4\">\n <div className=\"max-w-3xl mx-auto\">\n <PromptInput\n placeholder=\"Ask a follow-up question...\"\n models={models}\n defaultSelectedModel=\"claude-4\"\n showAttachmentButton\n showVoiceButton={false}\n showSettingsButton={false}\n onSubmit={() => {}}\n className=\"min-w-0\"\n />\n </div>\n </div>\n </div>\n <Drawer\n isOpen={artifactOpen}\n onClose={() => setArtifactOpen(false)}\n title=\"Generated artifact\"\n subtitle=\"Review the complete implementation\"\n position=\"right\"\n size=\"lg\"\n >\n <Drawer.Body>\n {/* An \"artifact\" surface is just a Card wrapping a CodeBlock. The Card\n header names the file, so CodeBlock omits `filename` and its own\n header carries only the language label and copy button. */}\n <Card\n title=\"Table.tsx\"\n subtitle=\"Backwards-compatible dual API\"\n actions={<Badge color=\"mono\" variant=\"soft\">v1</Badge>}\n >\n <CodeBlock language=\"tsx\">{artifactCode}</CodeBlock>\n </Card>\n </Drawer.Body>\n <Drawer.Footer>\n <Button\n variant=\"ghost\"\n color=\"mono\"\n onClick={() => setArtifactOpen(false)}\n >\n Close\n </Button>\n <Button onClick={() => setArtifactOpen(false)}>Accept artifact</Button>\n </Drawer.Footer>\n </Drawer>\n </>\n );\n};\n\nexport const Default: Story = {\n render: () => <AIAssistantDefault />,\n parameters: {\n controls: { disable: true },\n },\n};\n\nconst suggestionCards = [\n {\n title: \"Marketing Insights\",\n description:\n \"Discover the best marketing strategies to showcase your properties.\",\n },\n {\n title: \"Negotiation Tactics\",\n description: \"Learn expert negotiation tips to close deals effectively.\",\n },\n {\n title: \"Sales Strategies\",\n description:\n \"Get tailored advice on increasing property visibility and driving sales.\",\n },\n];\n\nexport const Empty: Story = {\n render: () => (\n <div className=\"h-[100dvh] relative overflow-hidden bg-white dark:bg-[var(--color-background)] flex flex-col\">\n <DotPattern\n spacing={24}\n dotSize={1.5}\n fade\n fadeSize={100}\n />\n\n {/* Centered hero content */}\n <div className=\"relative z-10 flex-1 flex flex-col items-center justify-center px-4 sm:px-6\">\n <div className=\"mb-4 sm:mb-6\">\n <AIOrb\n size={100}\n backgroundColor=\"transparent\"\n className=\"rounded-full sm:hidden\"\n >\n <AIOrb.DotSphere />\n </AIOrb>\n <AIOrb\n size={140}\n backgroundColor=\"transparent\"\n className=\"rounded-full hidden sm:block\"\n >\n <AIOrb.DotSphere />\n </AIOrb>\n </div>\n\n <h1 className=\"text-2xl sm:text-4xl lg:text-5xl font-bold text-[var(--color-text-primary)] tracking-tight text-center\">\n How can we <span className=\"text-[var(--color-primary)]\">assist</span>{\" \"}\n you today?\n </h1>\n\n <p className=\"text-[var(--color-text-muted)] mt-2 sm:mt-3 max-w-lg text-center text-sm sm:text-base px-2\">\n Your AI-powered companion for real estate insights, strategies, and\n expert guidance — available around the clock.\n </p>\n\n {/* Suggestion cards */}\n <div className=\"relative grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4 mt-6 sm:mt-10 w-full max-w-4xl\">\n {suggestionCards.map((card) => (\n <GlassSurface\n key={card.title}\n borderRadius={24}\n borderWidth={1.5}\n redOffset={0}\n greenOffset={15}\n blueOffset={35}\n className=\"h-full\"\n >\n <button\n type=\"button\"\n className=\"group relative flex flex-col items-start text-left rounded-[24px] bg-white/10 dark:bg-[var(--color-background-secondary)]/60 backdrop-blur-md p-4 sm:p-5 transition-all duration-300 cursor-pointer w-full h-full hover:bg-[var(--color-background-secondary)]/10 hover:ring-2 hover:ring-[var(--color-border)]\"\n >\n <ArrowUpRightIcon className=\"size-4 sm:size-5 text-[var(--color-text-muted)] absolute top-3 right-3 sm:top-4 sm:right-4 transition-all duration-300 group-hover:text-[var(--color-text-primary)]\" />\n <h3 className=\"font-medium text-[var(--color-text-primary)] text-base sm:text-lg pr-6\">\n {card.title}\n </h3>\n <p className=\"text-[var(--color-text-muted)] text-sm sm:text-base mt-1 sm:mt-2\">\n {card.description}\n </p>\n </button>\n </GlassSurface>\n ))}\n </div>\n </div>\n\n {/* PromptInput at bottom */}\n <div className=\"relative z-10 px-3 py-2 sm:p-4 lg:p-6\">\n <div className=\"max-w-4xl mx-auto\">\n <PromptInput\n placeholder=\"Type your prompt here\"\n showAttachmentButton\n showVoiceButton\n showModelSelector={false}\n showSettingsButton={false}\n onSubmit={() => {}}\n />\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11510
+ },
11511
+ {
11512
+ "name": "AnalyticsHeroLayout",
11513
+ "title": "Blocks/AnalyticsHeroLayout",
11514
+ "description": "Full-page composition using BarChart, Button, HeroCard.",
11515
+ "componentsUsed": [
11516
+ "BarChart",
11517
+ "Button",
11518
+ "HeroCard"
11519
+ ],
11520
+ "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Button, HeroCard } from \"../../components/core\";\nimport { BarChart } from \"../../components/charts\";\n\nconst meta: Meta = {\n title: \"Blocks/AnalyticsHeroLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Default: Story = {\n render: () => (\n <div className=\"p-10\">\n <HeroCard\n image=\"/bg/4.webp\"\n imageOpacity={0.2}\n imageBlend=\"hard-light\"\n parallax\n className=\"h-[460px] max-w-6xl from-teal-600 via-indigo-800 to-indigo-900 p-0\"\n contentClassName=\"h-full\"\n >\n <div className=\"grid h-full grid-cols-2 gap-10\">\n <div className=\"flex h-full flex-col justify-between p-14\">\n <div>\n <p className=\"text-3xl font-medium tracking-tight text-white/60\">\n You have <span className=\"font-semibold text-white\">completed 5 topics</span> in Physics, with an{\" \"}\n <span className=\"font-semibold text-white\">average score of 85%</span>. Best topic so far has been{\" \"}\n <span className=\"font-semibold text-white\">Electricity</span>.\n </p>\n <p className=\"mt-6 text-white/70\">You're progressing well in Physics — above the class average of 80%.</p>\n </div>\n <Button color=\"mono\" variant=\"soft\" className=\"self-start\">\n Learn more\n </Button>\n </div>\n <div className=\"mr-4\">\n <BarChart\n height={\"100%\"}\n data={[\n { name: \"Kinematics\", score: 64 },\n { name: \"Forces\", score: 72 },\n { name: \"Energy\", score: 88 },\n { name: \"Waves\", score: 93 },\n { name: \"Electricity\", score: 84 },\n ]}\n config={{ score: { label: \"Physics Score\", color: \"sky-400\" } }}\n variant=\"minimal\"\n showGrid={false}\n showYAxis={false}\n showXAxis={false}\n darkMode\n />\n </div>\n </div>\n </HeroCard>\n </div>\n ),\n};"
11026
11521
  },
11027
11522
  {
11028
11523
  "name": "AuthLayout",
@@ -11041,7 +11536,31 @@
11041
11536
  "Segmented",
11042
11537
  "Separator"
11043
11538
  ],
11044
- "source": "import { Avatar, AvatarGroup, Button, Link, Separator, Icon } from \"@flikk/ui\";\nimport { Checkbox, Input } from \"@flikk/ui\";\nimport { StarIcon } from \"@heroicons/react/24/solid\";\n\n<div className=\"w-full min-h-screen bg-[var(--color-surface)] grid grid-cols-1 lg:grid-cols-2\">\n {/* Left — hero panel */}\n <div className=\"hidden lg:flex bg-[var(--color-primary-700)] text-white h-full rounded-4xl p-8 xl:p-16 bg-image bg-image-4 bg-image-blur-lg bg-image-scale-125\">\n <div className=\"relative z-10 flex flex-col h-full\">\n <div className=\"font-semibold text-sm bg-white/10 backdrop-blur-sm p-1 px-3 rounded-full w-fit flex items-center gap-1.5 text-white/80\">\n <StarIcon className=\"size-3.5 text-yellow-300\" />\n Trusted by 10,000+ developers\n </div>\n <div className=\"w-3/4\">\n <div className=\"font-normal text-5xl xl:text-8xl mt-6 tracking-tight leading-[0.9em]\">\n Build beautiful interfaces in{\" \"}\n <span className=\"italic text-[var(--color-warning-400)] font-cursive\">\n half the time\n </span>\n </div>\n <div className=\"text-xl mt-4 opacity-80 leading-relaxed\">\n Production-ready React components with built-in accessibility,\n theming, and animations. Ship faster without sacrificing quality.\n </div>\n </div>\n\n <div className=\"mt-auto space-y-6\">\n <div className=\"bg-white/10 backdrop-blur-sm rounded-2xl p-6 space-y-4\">\n <p className=\"text-base leading-relaxed opacity-90\">\n \"Flikkui cut our development time by 40%. The components are\n polished, accessible, and just work out of the box.\"\n </p>\n <div className=\"flex items-center gap-3\">\n <Avatar name=\"Sarah Chen\" size=\"sm\" src=\"...\" />\n <div>\n <div className=\"font-medium text-sm\">Sarah Chen</div>\n <div className=\"text-xs opacity-70\">Engineering Lead, Vercel</div>\n </div>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between text-sm\">\n <div className=\"flex items-center gap-3\">\n <AvatarGroup max={4} size=\"sm\" avatars={[\n { name: \"James W\", src: \"...\" },\n { name: \"Emily R\", src: \"...\" },\n { name: \"David K\", src: \"...\" },\n ]} />\n <span>2,400+ stars on GitHub</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Right — sign-up form */}\n <div className=\"flex items-center justify-center min-h-screen lg:min-h-0 lg:h-full px-6 sm:px-8 lg:px-0 py-10 lg:py-0\">\n <div className=\"w-full max-w-sm space-y-6\">\n <div>\n <div className=\"text-2xl font-bold text-[var(--color-text-primary)]\">Get Started Now</div>\n <div className=\"text-base text-[var(--color-text-muted)] mt-1\">\n Start building for free. No credit card required.\n </div>\n </div>\n\n <div className=\"space-y-3\">\n <Input label=\"Full name\" placeholder=\"Sarah Chen\" />\n <Input label=\"Work email\" placeholder=\"sarah@company.com\" type=\"email\" />\n <Input label=\"Password\" placeholder=\"Min. 8 characters\" type=\"password\" />\n <div className=\"flex items-center gap-2\">\n <Checkbox id=\"terms\" name=\"terms\" value=\"\" size=\"sm\" />\n <span className=\"text-[var(--color-text-muted)] text-xs mt-0.5\">\n I agree to the <Link className=\"text-[var(--color-text-muted)] underline\">Terms of Service</Link>\n {\" \"}and <Link className=\"text-[var(--color-text-muted)] underline\">Privacy Policy</Link>\n </span>\n </div>\n\n <div className=\"mt-6 space-y-3\">\n <Button className=\"w-full\">Get Started</Button>\n <div className=\"text-center text-sm text-[var(--color-text-muted)]\">\n Already have an account? <Link>Sign in</Link>\n </div>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Separator />\n <div className=\"text-xs font-medium text-[var(--color-text-muted)]/60 min-w-fit\">OR</div>\n <Separator />\n </div>\n <div className=\"flex items-center justify-center gap-2\">\n <Button variant=\"outline\" color=\"neutral\" iconOnly>\n <Icon icon=\"google\" size=\"sm\" />\n </Button>\n <Button variant=\"outline\" color=\"neutral\" iconOnly>\n <Icon icon=\"github\" size=\"sm\" colorMode=\"mono\" />\n </Button>\n <Button variant=\"outline\" color=\"neutral\" iconOnly>\n <Icon icon=\"apple\" size=\"sm\" colorMode=\"mono\" />\n </Button>\n </div>\n </div>\n </div>\n </div>\n</div>"
11539
+ "source": "import { Avatar, AvatarGroup, Button, Link, Separator, Icon } from \"@flikk/ui\";\nimport { Checkbox, Input } from \"@flikk/ui\";\n\n<div className=\"w-full min-h-screen bg-[var(--color-surface)] grid grid-cols-1 lg:grid-cols-2\">\n {/* Left — hero panel */}\n <div className=\"hidden lg:flex bg-[var(--color-primary-700)] text-white h-full rounded-4xl p-8 xl:p-16 bg-image bg-image-4 bg-image-blur-lg bg-image-scale-125\">\n <div className=\"relative z-10 flex flex-col h-full\">\n <div className=\"font-semibold text-sm bg-white/10 backdrop-blur-sm p-1 px-3 rounded-full w-fit flex items-center gap-1.5 text-white/80\">\n <StarIcon className=\"size-3.5 text-yellow-300\" />\n Trusted by 10,000+ developers\n </div>\n <div className=\"w-3/4\">\n <div className=\"font-normal text-5xl xl:text-8xl mt-6 tracking-tight leading-[0.9em]\">\n Build beautiful interfaces in{\" \"}\n <span className=\"italic text-[var(--color-warning-400)]\" style={{ fontFamily: '\"Birthstone\", cursive' }}>\n half the time\n </span>\n </div>\n <div className=\"text-xl mt-4 opacity-80 leading-relaxed\">\n Production-ready React components with built-in accessibility,\n theming, and animations. Ship faster without sacrificing quality.\n </div>\n </div>\n\n <div className=\"mt-auto space-y-6\">\n <div className=\"bg-white/10 backdrop-blur-sm rounded-2xl p-6 space-y-4\">\n <p className=\"text-base leading-relaxed opacity-90\">\n \"Flikkui cut our development time by 40%. The components are\n polished, accessible, and just work out of the box.\"\n </p>\n <div className=\"flex items-center gap-3\">\n <Avatar name=\"Sarah Chen\" size=\"sm\" src=\"...\" />\n <div>\n <div className=\"font-medium text-sm\">Sarah Chen</div>\n <div className=\"text-xs opacity-70\">Engineering Lead, Vercel</div>\n </div>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between text-sm\">\n <div className=\"flex items-center gap-3\">\n <AvatarGroup max={4} size=\"sm\" avatars={[\n { name: \"James W\", src: \"...\" },\n { name: \"Emily R\", src: \"...\" },\n { name: \"David K\", src: \"...\" },\n ]} />\n <span>2,400+ stars on GitHub</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Right — sign-up form */}\n <div className=\"flex items-center justify-center min-h-screen lg:min-h-0 lg:h-full px-6 sm:px-8 lg:px-0 py-10 lg:py-0\">\n <div className=\"w-full max-w-sm space-y-6\">\n <div>\n <div className=\"text-2xl font-bold text-[var(--color-text-primary)]\">Get Started Now</div>\n <div className=\"text-base text-[var(--color-text-muted)] mt-1\">\n Start building for free. No credit card required.\n </div>\n </div>\n\n <div className=\"space-y-3\">\n <Input label=\"Full name\" placeholder=\"Sarah Chen\" />\n <Input label=\"Work email\" placeholder=\"sarah@company.com\" type=\"email\" />\n <Input label=\"Password\" placeholder=\"Min. 8 characters\" type=\"password\" />\n <div className=\"flex items-center gap-2\">\n <Checkbox id=\"terms\" name=\"terms\" value=\"\" size=\"sm\" />\n <span className=\"text-[var(--color-text-muted)] text-xs mt-0.5\">\n I agree to the <Link className=\"text-[var(--color-text-muted)] underline\">Terms of Service</Link>\n {\" \"}and <Link className=\"text-[var(--color-text-muted)] underline\">Privacy Policy</Link>\n </span>\n </div>\n\n <div className=\"mt-6 space-y-3\">\n <Button className=\"w-full\">Get Started</Button>\n <div className=\"text-center text-sm text-[var(--color-text-muted)]\">\n Already have an account? <Link>Sign in</Link>\n </div>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Separator />\n <div className=\"text-xs font-medium text-[var(--color-text-muted)]/60 min-w-fit\">OR</div>\n <Separator />\n </div>\n <div className=\"flex items-center justify-center gap-2\">\n <Button variant=\"outline\" color=\"mono\" iconOnly>\n <Icon icon=\"google\" size=\"sm\" />\n </Button>\n <Button variant=\"outline\" color=\"mono\" iconOnly>\n <Icon icon=\"github\" size=\"sm\" colorMode=\"mono\" />\n </Button>\n <Button variant=\"outline\" color=\"mono\" iconOnly>\n <Icon icon=\"apple\" size=\"sm\" colorMode=\"mono\" />\n </Button>\n </div>\n </div>\n </div>\n </div>\n</div>"
11540
+ },
11541
+ {
11542
+ "name": "Dashboard",
11543
+ "title": "Riverside loft renovation",
11544
+ "description": "Full-page composition using AppShell, Avatar, Badge, Button, ….",
11545
+ "componentsUsed": [
11546
+ "AppShell",
11547
+ "Avatar",
11548
+ "Badge",
11549
+ "Button",
11550
+ "Card",
11551
+ "DotPattern",
11552
+ "Dropdown",
11553
+ "GradientMesh",
11554
+ "Grid",
11555
+ "HeroCard",
11556
+ "Input",
11557
+ "Link",
11558
+ "LollipopChart",
11559
+ "Metric",
11560
+ "Progress",
11561
+ "Segmented"
11562
+ ],
11563
+ "source": "import React, { useState } from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Badge,\n Button,\n Card,\n Dropdown,\n HeroCard,\n Link,\n Progress,\n Segmented,\n} from \"../../components/core\";\nimport { AppShell, Grid } from \"../../components/layout\";\nimport { Input } from \"../../components/forms\";\nimport { DotPattern, GradientMesh } from \"../../components/effects\";\nimport { ChartContainer, LollipopChart, MultiSegmentDonutChart } from \"../../components/charts\";\nimport type { DonutSegment } from \"../../components/charts\";\nimport {\n Bell as BellIcon,\n CaretDown as ChevronDownIcon,\n CaretRight as ChevronRightIcon,\n CheckCircle as CheckCircleIcon,\n HouseLine as HomeModernIcon,\n MagnifyingGlass as MagnifyingGlassIcon,\n MapPin as MapPinIcon,\n Plus as PlusIcon,\n Sparkle as SparklesIcon,\n} from \"@phosphor-icons/react\";\nimport { Metric } from \"../../components/data-display\";\n\n// --- Mock data -------------------------------------------------------------\n// Niche: Atelier, a freelance marketplace for independent architects and\n// interior designers.\n\nconst weeklyEarnings = [\n { name: \"Sunday\", earnings: 3200 },\n { name: \"Monday\", earnings: 4650 },\n { name: \"Tuesday\", earnings: 5980 },\n { name: \"Wednesday\", earnings: 4200 },\n { name: \"Thursday\", earnings: 5100 },\n { name: \"Friday\", earnings: 4700 },\n { name: \"Saturday\", earnings: 2900 },\n];\n\nconst earningsConfig = {\n earnings: { label: \"Earnings\", color: \"var(--color-primary)\" },\n};\n\n// Commitment-type mix across active briefs, weighted by $/hour rate:\n// Contract = Riverside Loft Renovation ($120/hr), Full-time = Downtown Office\n// Fit-Out ($95/hr), Part-time = Coastal House Landscape Design ($85/hr).\nconst commitmentData: DonutSegment[] = [\n { value: 120, percentage: 40, label: \"Contract\", color: \"var(--color-primary)\" },\n { value: 95, percentage: 31.7, label: \"Full-time\", color: \"var(--color-success)\" },\n { value: 85, percentage: 28.3, label: \"Part-time\", color: \"var(--color-warning)\" },\n];\n\ninterface Connection {\n id: string;\n name: string;\n role: string;\n level: \"Senior\" | \"Middle\";\n avatarSrc: string;\n}\n\nconst connections: Connection[] = [\n {\n id: \"elena-voss\",\n name: \"Elena Voss\",\n role: \"Structural Engineer\",\n level: \"Senior\",\n avatarSrc: \"https://i.pravatar.cc/150?u=elena-voss\",\n },\n {\n id: \"marcus-webb\",\n name: \"Marcus Webb\",\n role: \"Lighting Designer\",\n level: \"Middle\",\n avatarSrc: \"https://i.pravatar.cc/150?u=marcus-webb\",\n },\n {\n id: \"naomi-chen\",\n name: \"Naomi Chen\",\n role: \"Material Consultant\",\n level: \"Senior\",\n avatarSrc: \"https://i.pravatar.cc/150?u=naomi-chen\",\n },\n];\n\nconst proposalStats = [\n { label: \"Briefs sent\", value: 48 },\n { label: \"Interviews\", value: 9 },\n { label: \"Commissions\", value: 6 },\n];\n\nconst pipelineStages = [\n { label: \"Sent\", value: 48, progress: 82, color: \"bg-[var(--color-primary)]\" },\n { label: \"Interview\", value: 9, progress: 46, color: \"bg-[var(--color-success)]\" },\n { label: \"Won\", value: 6, progress: 34, color: \"bg-[var(--color-warning)]\" },\n];\n\nconst priorityBriefs = [\n { title: \"Riverside loft renovation\", budget: \"$18.5k\", status: \"Interview\" },\n { title: \"Boutique hotel lobby\", budget: \"$24k\", status: \"Proposal due\" },\n];\n\nconst navItems = [\n { label: \"Home\", active: true },\n { label: \"Briefs\", active: false },\n { label: \"Portfolio\", active: false },\n { label: \"Clients\", active: false },\n { label: \"Messages\", active: false },\n];\n\n// --- Story -------------------------------------------------------------\n\nconst meta: Meta = {\n title: \"Blocks/Dashboard\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Default: Story = {\n render: () => {\n const [range, setRange] = useState(\"week\");\n\n return (\n <AppShell scroll=\"page\" topbarSpan=\"full\" contentWidth=\"full\" contentPadding=\"lg\">\n <AppShell.Topbar className=\"border-b-0\">\n <div className=\"flex min-h-16 flex-wrap items-center justify-between gap-4 px-6 py-3\">\n <div className=\"flex flex-wrap items-center gap-4 lg:gap-8\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex size-8 items-center justify-center rounded-full bg-[var(--color-primary)] text-[var(--color-primary-contrast)]\">\n <HomeModernIcon className=\"size-4\" />\n </div>\n <span className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n Atelier\n </span>\n </div>\n <nav className=\"hidden items-center gap-1 md:flex\">\n {navItems.map((item) => (\n <Button\n key={item.label}\n variant={item.active ? \"soft\" : \"ghost\"}\n color=\"mono\"\n size=\"sm\"\n >\n {item.label}\n </Button>\n ))}\n </nav>\n </div>\n <div className=\"flex min-w-0 flex-1 items-center justify-end gap-3 lg:flex-none\">\n <Input\n placeholder=\"Search briefs, clients, or projects...\"\n iconEnd={<MagnifyingGlassIcon className=\"size-4\" />}\n className=\"hidden w-full max-w-80 md:flex\"\n />\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" aria-label=\"Location\">\n <MapPinIcon className=\"size-4\" />\n </Button>\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" aria-label=\"Notifications\">\n <BellIcon className=\"size-4\" />\n </Button>\n <Avatar\n src=\"https://i.pravatar.cc/150?u=maren-kessler\"\n name=\"Maren Kessler\"\n size=\"sm\"\n />\n </div>\n </div>\n </AppShell.Topbar>\n\n <AppShell.Main>\n <div className=\"flex flex-col gap-6 max-w-7xl mx-auto\">\n <Grid cols={{ base: 1, lg: 3 }} gap={6}>\n <Card\n className=\"lg:col-span-2\"\n title=\"Earnings Tracker\"\n subtitle=\"Track your studio's weekly earnings and payment status across every active brief\"\n actions={\n <Segmented value={range} onChange={setRange} size=\"sm\">\n <Segmented.Item value=\"week\">Week</Segmented.Item>\n <Segmented.Item value=\"month\">Month</Segmented.Item>\n <Segmented.Item value=\"year\">Year</Segmented.Item>\n </Segmented>\n }\n >\n <div className=\"flex flex-col items-stretch justify-between gap-8 xl:flex-row xl:gap-12\">\n <ChartContainer\n data={weeklyEarnings}\n config={earningsConfig}\n className=\"h-[280px] w-full xl:h-[320px]\"\n >\n <LollipopChart\n data={weeklyEarnings}\n config={earningsConfig}\n defaultSelectedIndex={2}\n valueFormatter={(value: number) => `$${value.toLocaleString()}`}\n />\n </ChartContainer>\n\n <div className=\"flex w-full flex-col justify-between gap-4 pb-3 xl:max-w-64\">\n <Metric\n value=\"$12,547\"\n label=\"Collected this week\"\n subtitle=\"Payments cleared\"\n trendValue=\"12.5%\"\n trendDirection=\"up\"\n size=\"lg\"\n variant=\"ghost\"\n />\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Growth is being driven by independent interior designers\n joining the network, with studio signups up across\n every region this week.\n </p>\n </div>\n </div>\n </Card>\n\n <Card\n title=\"Commitment Mix\"\n subtitle=\"Hourly rate by engagement type across active briefs\"\n >\n <div className=\"flex justify-center py-2\">\n <MultiSegmentDonutChart\n data={commitmentData}\n size={180}\n thickness={3}\n showLegend\n legendPosition=\"bottom\"\n centerContent={\n <div className=\"text-center\">\n <div className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n $300/hr\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)]\">\n Combined rate\n </div>\n </div>\n }\n />\n </div>\n </Card>\n </Grid>\n\n <Grid cols={{ base: 1, lg: 3 }} gap={6}>\n <Card className=\"flex h-full flex-col\">\n <Card.Header className=\"flex-row items-start justify-between gap-4\">\n <div className=\"flex flex-col\">\n <Card.Title>Studio Network</Card.Title>\n <Card.Subtitle>Specialists available for active briefs</Card.Subtitle>\n </div>\n <div className=\"flex items-center gap-2 shrink-0\">\n <Link size=\"sm\" href=\"#\">\n See all\n </Link>\n </div>\n </Card.Header>\n <Card.Body className=\"flex flex-1 flex-col\">\n <div className=\"flex flex-col divide-y divide-[var(--color-border)]\">\n {connections.map((connection) => (\n <div key={connection.id} className=\"flex items-center gap-2 py-2.5 first:pt-0 last:pb-0\">\n <Avatar src={connection.avatarSrc} name={connection.name} size=\"lg\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-[var(--color-text-primary)]\">\n {connection.name}\n </span>\n <Badge\n color={connection.level === \"Senior\" ? \"primary\" : \"mono\"}\n variant=\"soft\"\n size=\"sm\"\n >\n {connection.level}\n </Badge>\n </div>\n <p className=\"truncate text-sm text-[var(--color-text-muted)]\">\n {connection.role}\n </p>\n </div>\n <Button\n variant=\"soft\"\n color=\"mono\"\n size=\"sm\"\n iconOnly\n aria-label={`Connect with ${connection.name}`}\n >\n <PlusIcon className=\"size-4\" />\n </Button>\n </div>\n ))}\n </div>\n <div className=\"mt-auto border-t border-[var(--color-border)] pt-10\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex size-9 shrink-0 items-center justify-center rounded-full bg-[var(--color-primary)]/10 text-[var(--color-primary)]\">\n <SparklesIcon className=\"size-5\" />\n </div>\n <div>\n <p className=\"text-sm font-medium text-[var(--color-text-primary)]\">\n 6 matching collaborators\n </p>\n <p className=\"mt-1 text-sm leading-relaxed text-[var(--color-text-muted)]\">\n Best fits are based on project type, rate, and timezone overlap.\n </p>\n </div>\n </div>\n </div>\n </Card.Body>\n </Card>\n\n <HeroCard\n image=\"/bg/2.webp\"\n imageBlend=\"overlay\"\n imageOpacity={0.5}\n parallax\n className=\"h-full bg-gradient-to-br from-[var(--color-primary-500)] via-teal-600 to-indigo-900 p-8 ring-0 border-0\"\n contentClassName=\"flex h-full flex-col justify-between gap-6\"\n >\n <DotPattern spacing={20} dotSize={1} fadeDirection=\"radial\" className=\"inset-0 -m-8\" />\n <GradientMesh\n colors={[\"var(--color-primary-400)\", \"var(--color-primary)\", \"var(--color-primary-800)\"]}\n distortion={0.8}\n swirl={0.3}\n speed={0.5}\n className=\"inset-0 -m-8 opacity-40\"\n />\n\n <div className=\"relative z-10\">\n <Badge className=\"border-0 bg-white/20 rounded-full text-white font-medium mb-4\">\n Special Offer\n </Badge>\n <h3 className=\"text-4xl font-semibold tracking-tight text-white\">\n Unlock Studio Pro\n </h3>\n <p className=\"mt-2 text-sm text-white/90 leading-relaxed\">\n Get priority access to high-value briefs and grow your\n studio's client roster\n </p>\n </div>\n <Button\n className=\"relative z-10 mt-auto w-fit\"\n color=\"mono\"\n darkMode\n >\n Upgrade now <ChevronRightIcon className=\"size-4 stroke-[2]\" />\n </Button>\n </HeroCard>\n <Card\n title=\"Brief Pipeline\"\n subtitle=\"Monitor active proposals from first contact to signed contract\"\n actions={\n <Dropdown placement=\"bottom-end\">\n <Dropdown.Trigger>\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n May 6, 2024\n <ChevronDownIcon className=\"size-3\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu aria-label=\"Select date range\">\n <Dropdown.Item itemKey=\"this-week\">This week</Dropdown.Item>\n <Dropdown.Item itemKey=\"last-week\">Last week</Dropdown.Item>\n <Dropdown.Item itemKey=\"this-month\">This month</Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n }\n >\n <div className=\"flex flex-col gap-6\">\n <div className=\"grid grid-cols-3 gap-4\">\n {proposalStats.map((stat) => (\n <div key={stat.label}>\n <p className=\"text-sm text-[var(--color-text-muted)]\">{stat.label}</p>\n <p className=\"mt-1 text-2xl font-semibold text-[var(--color-text-primary)]\">\n {stat.value}\n </p>\n </div>\n ))}\n </div>\n <div className=\"flex flex-col gap-4\">\n {pipelineStages.map((stage) => (\n <div key={stage.label} className=\"space-y-2\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-sm font-medium text-[var(--color-text-primary)]\">\n {stage.label}\n </span>\n <span className=\"text-sm text-[var(--color-text-muted)]\">\n {stage.value}\n </span>\n </div>\n <Progress\n value={stage.progress}\n size=\"sm\"\n className={stage.color}\n aria-label={`${stage.label} pipeline progress`}\n />\n </div>\n ))}\n </div>\n </div>\n </Card>\n </Grid>\n </div>\n </AppShell.Main>\n </AppShell>\n );\n },\n};"
11045
11564
  },
11046
11565
  {
11047
11566
  "name": "ErrorLayout",
@@ -11050,7 +11569,7 @@
11050
11569
  "componentsUsed": [
11051
11570
  "Button"
11052
11571
  ],
11053
- "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Button } from \"../../components/core\";\nimport {\n HomeIcon,\n ArrowPathIcon,\n ArrowLeftIcon,\n ExclamationTriangleIcon,\n} from \"@heroicons/react/24/outline\";\n\nconst meta: Meta = {\n title: \"Blocks/ErrorLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const NotFound: Story = {\n render: () => (\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--color-background)] px-6\">\n <div className=\"text-center max-w-md\">\n <div className=\"text-8xl font-bold text-[var(--color-primary)] mb-4\">\n 404\n </div>\n <h1 className=\"text-2xl font-semibold text-[var(--color-text-primary)] mb-2\">\n Page not found\n </h1>\n <p className=\"text-[var(--color-text-muted)] mb-8\">\n Sorry, we couldn't find the page you're looking for. The page may have\n been moved or deleted.\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <Button variant=\"outline\" color=\"neutral\">\n <ArrowLeftIcon className=\"size-4\" /> Go Back\n </Button>\n <Button>\n <HomeIcon className=\"size-4\" /> Go Home\n </Button>\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};\n\nexport const ServerError: Story = {\n render: () => (\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--color-background)] px-6\">\n <div className=\"text-center max-w-md\">\n <div className=\"flex justify-center mb-6\">\n <div className=\"p-4 rounded-full bg-[var(--color-danger-50)]\">\n <ExclamationTriangleIcon className=\"size-12 text-[var(--color-danger)]\" />\n </div>\n </div>\n <div className=\"text-8xl font-bold text-[var(--color-danger)] mb-4\">\n 500\n </div>\n <h1 className=\"text-2xl font-semibold text-[var(--color-text-primary)] mb-2\">\n Internal Server Error\n </h1>\n <p className=\"text-[var(--color-text-muted)] mb-8\">\n We're experiencing a temporary outage. Our team has been notified and\n is working on a fix. Please try again in a few minutes.\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <Button variant=\"outline\" color=\"neutral\">\n <ArrowLeftIcon className=\"size-4\" /> Go Back\n </Button>\n <Button>\n <ArrowPathIcon className=\"size-4\" /> Refresh Page\n </Button>\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11572
+ "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Button } from \"../../components/core\";\nimport { House as HomeIcon, ArrowsClockwise as ArrowPathIcon, ArrowLeft as ArrowLeftIcon, Warning as ExclamationTriangleIcon } from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/ErrorLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const NotFound: Story = {\n render: () => (\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--color-background)] px-6\">\n <div className=\"text-center max-w-md\">\n <div className=\"text-8xl font-bold text-[var(--color-primary)] mb-4\">\n 404\n </div>\n <h1 className=\"text-2xl font-semibold text-[var(--color-text-primary)] mb-2\">\n Page not found\n </h1>\n <p className=\"text-[var(--color-text-muted)] mb-8\">\n Sorry, we couldn't find the page you're looking for. The page may have\n been moved or deleted.\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <Button variant=\"outline\" color=\"mono\">\n <ArrowLeftIcon className=\"size-4\" /> Go Back\n </Button>\n <Button>\n <HomeIcon className=\"size-4\" /> Go Home\n </Button>\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};\n\nexport const ServerError: Story = {\n render: () => (\n <div className=\"min-h-screen flex items-center justify-center bg-[var(--color-background)] px-6\">\n <div className=\"text-center max-w-md\">\n <div className=\"flex justify-center mb-6\">\n <div className=\"p-4 rounded-full bg-[var(--color-danger-50)]\">\n <ExclamationTriangleIcon className=\"size-12 text-[var(--color-danger)]\" />\n </div>\n </div>\n <div className=\"text-8xl font-bold text-[var(--color-danger)] mb-4\">\n 500\n </div>\n <h1 className=\"text-2xl font-semibold text-[var(--color-text-primary)] mb-2\">\n Internal Server Error\n </h1>\n <p className=\"text-[var(--color-text-muted)] mb-8\">\n We're experiencing a temporary outage. Our team has been notified and\n is working on a fix. Please try again in a few minutes.\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <Button variant=\"outline\" color=\"mono\">\n <ArrowLeftIcon className=\"size-4\" /> Go Back\n </Button>\n <Button>\n <ArrowPathIcon className=\"size-4\" /> Refresh Page\n </Button>\n </div>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11054
11573
  },
11055
11574
  {
11056
11575
  "name": "GenerativeUI",
@@ -11081,7 +11600,7 @@
11081
11600
  "Separator",
11082
11601
  "Tooltip"
11083
11602
  ],
11084
- "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Badge,\n Button,\n ScrollArea,\n Separator,\n Tooltip,\n} from \"../../components/core\";\nimport { Input } from \"../../components/forms\";\nimport {\n InboxIcon,\n PaperAirplaneIcon,\n ArchiveBoxIcon,\n TrashIcon,\n StarIcon,\n MagnifyingGlassIcon,\n ArrowUturnLeftIcon,\n ArrowUturnRightIcon,\n EllipsisHorizontalIcon,\n PaperClipIcon,\n TagIcon,\n} from \"@heroicons/react/24/outline\";\nimport { StarIcon as StarSolidIcon } from \"@heroicons/react/24/solid\";\n\nconst meta: Meta = {\n title: \"Blocks/InboxLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Email data ---\n\nconst emails = [\n {\n id: \"1\",\n from: \"Alex Rivera\",\n avatar:\n \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n subject: \"Q4 Product Roadmap Review\",\n preview:\n \"Hey team, I've attached the updated Q4 roadmap with the prioritized features we discussed in yesterday's meeting...\",\n time: \"10:24 AM\",\n unread: true,\n starred: true,\n hasAttachment: true,\n labels: [\"Product\"],\n },\n {\n id: \"2\",\n from: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n subject: \"Component Library v2.5 Release Notes\",\n preview:\n \"The new release includes 12 new components, performance improvements across the board, and full dark mode support...\",\n time: \"9:15 AM\",\n unread: true,\n starred: false,\n hasAttachment: false,\n labels: [\"Engineering\"],\n },\n {\n id: \"3\",\n from: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n subject: \"Re: Design system feedback\",\n preview:\n \"I've reviewed the spacing tokens and have a few suggestions. The 4px base unit works well but I think we should...\",\n time: \"Yesterday\",\n unread: false,\n starred: false,\n hasAttachment: false,\n labels: [\"Design\"],\n },\n {\n id: \"4\",\n from: \"Emily Rodriguez\",\n avatar:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n subject: \"Team standup notes — Feb 14\",\n preview:\n \"Here's a summary from today's standup: Sarah is working on the Table refactor, James is finishing the icon migration...\",\n time: \"Yesterday\",\n unread: false,\n starred: true,\n hasAttachment: false,\n labels: [],\n },\n {\n id: \"5\",\n from: \"David Kim\",\n avatar:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n subject: \"CI pipeline update\",\n preview:\n \"I've updated the CI config to include visual regression testing. Build times are down 30% with the new caching strategy...\",\n time: \"Feb 13\",\n unread: false,\n starred: false,\n hasAttachment: true,\n labels: [\"DevOps\"],\n },\n {\n id: \"6\",\n from: \"Lisa Thompson\",\n avatar:\n \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n subject: \"Client presentation slides\",\n preview:\n \"Attached the final deck for Friday's presentation. I've incorporated all the feedback from the dry run...\",\n time: \"Feb 12\",\n unread: false,\n starred: false,\n hasAttachment: true,\n labels: [\"Sales\"],\n },\n];\n\nconst labelColors: Record<string, string> = {\n Product: \"bg-[var(--color-primary-100)] text-[var(--color-primary-700)]\",\n Engineering: \"bg-[var(--color-success-100)] text-[var(--color-success-700)]\",\n Design: \"bg-[var(--color-warning-100)] text-[var(--color-warning-700)]\",\n DevOps: \"bg-[var(--color-danger-100)] text-[var(--color-danger-700)]\",\n Sales: \"bg-[var(--color-primary-100)] text-[var(--color-primary-700)]\",\n};\n\n// --- Active email content ---\n\nconst activeEmail = emails[0];\n\nexport const Default: Story = {\n render: () => (\n <div className=\"h-screen flex bg-[var(--color-background)]\">\n {/* Left icon strip */}\n <div className=\"hidden sm:flex w-14 flex-col items-center py-4 gap-2 border-r border-[var(--color-border)] bg-[var(--color-background-secondary)]\">\n <div className=\"w-9 h-9 rounded-xl bg-[var(--color-primary)] flex items-center justify-center text-white font-bold text-sm mb-2\">\n F\n </div>\n <Separator className=\"w-8\" />\n <Tooltip content=\"Inbox\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center bg-[var(--color-primary)]/10 text-[var(--color-primary)]\">\n <InboxIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Sent\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <PaperAirplaneIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Starred\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <StarIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Archive\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <ArchiveBoxIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Trash\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <TrashIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Labels\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <TagIcon className=\"size-5\" />\n </button>\n </Tooltip>\n </div>\n\n {/* Email list */}\n <div className=\"w-full sm:w-80 lg:w-96 flex flex-col border-r border-[var(--color-border)]\">\n <div className=\"p-4 space-y-3 border-b border-[var(--color-border)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n Inbox\n </h2>\n <Badge\n color=\"primary\"\n variant=\"filled\"\n size=\"sm\"\n className=\"rounded-full\"\n >\n 2\n </Badge>\n </div>\n <Input\n placeholder=\"Search emails...\"\n iconStart={<MagnifyingGlassIcon className=\"size-4\" />}\n size=\"sm\"\n />\n </div>\n <ScrollArea className=\"flex-1\">\n <div className=\"divide-y divide-[var(--color-border)]\">\n {emails.map((email) => (\n <div\n key={email.id}\n className={`p-4 cursor-pointer transition-colors ${\n email.id === activeEmail.id\n ? \"bg-[var(--color-primary-50)]\"\n : \"hover:bg-[var(--color-background-secondary)]\"\n }`}\n >\n <div className=\"flex items-start gap-3\">\n <Avatar src={email.avatar} name={email.from} size=\"sm\" />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between\">\n <span\n className={`text-sm truncate ${email.unread ? \"font-semibold text-[var(--color-text-primary)]\" : \"font-medium text-[var(--color-text-secondary)]\"}`}\n >\n {email.from}\n </span>\n <span className=\"text-xs text-[var(--color-text-muted)] flex-shrink-0 ml-2\">\n {email.time}\n </span>\n </div>\n <div\n className={`text-sm truncate mt-0.5 ${email.unread ? \"font-medium text-[var(--color-text-primary)]\" : \"text-[var(--color-text-secondary)]\"}`}\n >\n {email.subject}\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)] truncate mt-0.5\">\n {email.preview}\n </div>\n <div className=\"flex items-center gap-2 mt-1.5\">\n {email.starred && (\n <StarSolidIcon className=\"size-3.5 text-[var(--color-warning)]\" />\n )}\n {email.hasAttachment && (\n <PaperClipIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n )}\n {email.labels.map((label) => (\n <span\n key={label}\n className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium ${labelColors[label] || \"\"}`}\n >\n {label}\n </span>\n ))}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n </ScrollArea>\n </div>\n\n {/* Email detail */}\n <div className=\"hidden sm:flex flex-1 flex-col min-w-0\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between px-6 py-3 border-b border-[var(--color-border)]\">\n <div className=\"flex items-center gap-1\">\n <Tooltip content=\"Reply\">\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly>\n <ArrowUturnLeftIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Forward\">\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly>\n <ArrowUturnRightIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Archive\">\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly>\n <ArchiveBoxIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Delete\">\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly>\n <TrashIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n <Button variant=\"soft\" color=\"neutral\" size=\"sm\" iconOnly>\n <EllipsisHorizontalIcon className=\"size-4\" />\n </Button>\n </div>\n\n {/* Email content */}\n <ScrollArea className=\"flex-1\">\n <div className=\"max-w-3xl mx-auto px-6 lg:px-8 py-6 space-y-6\">\n {/* Subject */}\n <div>\n <div className=\"flex items-start justify-between gap-4\">\n <h1 className=\"text-xl font-semibold text-[var(--color-text-primary)]\">\n {activeEmail.subject}\n </h1>\n <button className=\"flex-shrink-0 mt-1\">\n <StarSolidIcon className=\"size-5 text-[var(--color-warning)]\" />\n </button>\n </div>\n <div className=\"flex flex-wrap items-center gap-2 mt-2\">\n {activeEmail.labels.map((label) => (\n <Badge key={label} color=\"primary\" variant=\"soft\" size=\"sm\">\n {label}\n </Badge>\n ))}\n </div>\n </div>\n\n {/* Sender */}\n <div className=\"flex items-center gap-3\">\n <Avatar\n src={activeEmail.avatar}\n name={activeEmail.from}\n size=\"md\"\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2\">\n <span className=\"font-semibold text-sm text-[var(--color-text-primary)]\">\n {activeEmail.from}\n </span>\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n alex@company.com\n </span>\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)]\">\n To: you, sarah@company.com, james@company.com\n </div>\n </div>\n <span className=\"text-xs text-[var(--color-text-muted)] flex-shrink-0\">\n {activeEmail.time}\n </span>\n </div>\n\n <Separator />\n\n {/* Body */}\n <div className=\"text-sm text-[var(--color-text-secondary)] leading-relaxed space-y-4\">\n <p>Hey team,</p>\n <p>\n I've attached the updated Q4 roadmap with the prioritized\n features we discussed in yesterday's meeting. Here are the key\n highlights:\n </p>\n <ul className=\"list-disc pl-5 space-y-1\">\n <li>\n <strong>Chart Components v2</strong> — Complete rewrite with\n simplified API, accessibility improvements, and CSS variable\n theming\n </li>\n <li>\n <strong>Dark Mode</strong> — Full dark mode support across all\n 50+ components with automatic system preference detection\n </li>\n <li>\n <strong>Performance</strong> — Tree-shaking optimization\n targeting a 40% reduction in bundle size\n </li>\n <li>\n <strong>AI Components</strong> — New suite of components for\n building AI-powered chat interfaces\n </li>\n </ul>\n <p>\n I've also included a timeline and resource allocation breakdown\n in the attached document. Let me know if you have any questions\n or if we need to adjust priorities.\n </p>\n <p>\n Best,\n <br />\n Alex\n </p>\n </div>\n\n {/* Attachment */}\n <div className=\"border border-[var(--color-border)] rounded-lg p-3 flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-primary-50)] flex items-center justify-center flex-shrink-0\">\n <PaperClipIcon className=\"size-5 text-[var(--color-primary)]\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-[var(--color-text-primary)] truncate\">\n Q4-Roadmap-2026.pdf\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)]\">\n 2.4 MB\n </div>\n </div>\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n Download\n </Button>\n </div>\n\n <Separator />\n\n {/* Quick reply */}\n <div>\n <Input placeholder=\"Write a quick reply...\" size=\"md\" />\n <div className=\"flex justify-end mt-3 gap-2\">\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n Discard\n </Button>\n <Button size=\"sm\">\n <PaperAirplaneIcon className=\"size-4\" /> Send\n </Button>\n </div>\n </div>\n </div>\n </ScrollArea>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11603
+ "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Badge,\n Button,\n ScrollArea,\n Separator,\n Tooltip,\n} from \"../../components/core\";\nimport { Input } from \"../../components/forms\";\nimport {\n Tray as InboxIcon,\n PaperPlaneTilt as PaperAirplaneIcon,\n Archive as ArchiveBoxIcon,\n Trash as TrashIcon,\n Star as StarIcon,\n MagnifyingGlass as MagnifyingGlassIcon,\n ArrowUUpLeft as ArrowUturnLeftIcon,\n ArrowUUpRight as ArrowUturnRightIcon,\n DotsThree as EllipsisHorizontalIcon,\n Paperclip as PaperClipIcon,\n Tag as TagIcon,\n Star as StarSolidIcon,\n} from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/InboxLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Email data ---\n\nconst emails = [\n {\n id: \"1\",\n from: \"Alex Rivera\",\n avatar:\n \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n subject: \"Q4 Product Roadmap Review\",\n preview:\n \"Hey team, I've attached the updated Q4 roadmap with the prioritized features we discussed in yesterday's meeting...\",\n time: \"10:24 AM\",\n unread: true,\n starred: true,\n hasAttachment: true,\n labels: [\"Product\"],\n },\n {\n id: \"2\",\n from: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n subject: \"Component Library v2.5 Release Notes\",\n preview:\n \"The new release includes 12 new components, performance improvements across the board, and full dark mode support...\",\n time: \"9:15 AM\",\n unread: true,\n starred: false,\n hasAttachment: false,\n labels: [\"Engineering\"],\n },\n {\n id: \"3\",\n from: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n subject: \"Re: Design system feedback\",\n preview:\n \"I've reviewed the spacing tokens and have a few suggestions. The 4px base unit works well but I think we should...\",\n time: \"Yesterday\",\n unread: false,\n starred: false,\n hasAttachment: false,\n labels: [\"Design\"],\n },\n {\n id: \"4\",\n from: \"Emily Rodriguez\",\n avatar:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n subject: \"Team standup notes — Feb 14\",\n preview:\n \"Here's a summary from today's standup: Sarah is working on the Table refactor, James is finishing the icon migration...\",\n time: \"Yesterday\",\n unread: false,\n starred: true,\n hasAttachment: false,\n labels: [],\n },\n {\n id: \"5\",\n from: \"David Kim\",\n avatar:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n subject: \"CI pipeline update\",\n preview:\n \"I've updated the CI config to include visual regression testing. Build times are down 30% with the new caching strategy...\",\n time: \"Feb 13\",\n unread: false,\n starred: false,\n hasAttachment: true,\n labels: [\"DevOps\"],\n },\n {\n id: \"6\",\n from: \"Lisa Thompson\",\n avatar:\n \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n subject: \"Client presentation slides\",\n preview:\n \"Attached the final deck for Friday's presentation. I've incorporated all the feedback from the dry run...\",\n time: \"Feb 12\",\n unread: false,\n starred: false,\n hasAttachment: true,\n labels: [\"Sales\"],\n },\n];\n\nconst labelColors: Record<string, string> = {\n Product: \"bg-[var(--color-primary-100)] text-[var(--color-primary-700)]\",\n Engineering: \"bg-[var(--color-success-100)] text-[var(--color-success-700)]\",\n Design: \"bg-[var(--color-warning-100)] text-[var(--color-warning-700)]\",\n DevOps: \"bg-[var(--color-danger-100)] text-[var(--color-danger-700)]\",\n Sales: \"bg-[var(--color-primary-100)] text-[var(--color-primary-700)]\",\n};\n\n// --- Active email content ---\n\nconst activeEmail = emails[0];\n\nexport const Default: Story = {\n render: () => (\n <div className=\"h-screen flex bg-[var(--color-background)]\">\n {/* Left icon strip */}\n <div className=\"hidden sm:flex w-14 flex-col items-center py-4 gap-2 border-r border-[var(--color-border)] bg-[var(--color-background-secondary)]\">\n <div className=\"w-9 h-9 rounded-xl bg-[var(--color-primary)] flex items-center justify-center text-white font-bold text-sm mb-2\">\n F\n </div>\n <Separator className=\"w-8\" />\n <Tooltip content=\"Inbox\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center bg-[var(--color-primary)]/10 text-[var(--color-primary)]\">\n <InboxIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Sent\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <PaperAirplaneIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Starred\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <StarIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Archive\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <ArchiveBoxIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Trash\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <TrashIcon className=\"size-5\" />\n </button>\n </Tooltip>\n <Tooltip content=\"Labels\" placement=\"right\">\n <button className=\"w-9 h-9 rounded-lg flex items-center justify-center text-[var(--color-text-muted)] hover:bg-[var(--color-background-tertiary)] transition-colors\">\n <TagIcon className=\"size-5\" />\n </button>\n </Tooltip>\n </div>\n\n {/* Email list */}\n <div className=\"w-full sm:w-80 lg:w-96 flex flex-col border-r border-[var(--color-border)]\">\n <div className=\"p-4 space-y-3 border-b border-[var(--color-border)]\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n Inbox\n </h2>\n <Badge\n color=\"primary\"\n variant=\"filled\"\n size=\"sm\"\n className=\"rounded-full\"\n >\n 2\n </Badge>\n </div>\n <Input\n placeholder=\"Search emails...\"\n iconStart={<MagnifyingGlassIcon className=\"size-4\" />}\n size=\"sm\"\n />\n </div>\n <ScrollArea className=\"flex-1\">\n <div className=\"divide-y divide-[var(--color-border)]\">\n {emails.map((email) => (\n <div\n key={email.id}\n className={`p-4 cursor-pointer transition-colors ${\n email.id === activeEmail.id\n ? \"bg-[var(--color-primary-50)]\"\n : \"hover:bg-[var(--color-background-secondary)]\"\n }`}\n >\n <div className=\"flex items-start gap-3\">\n <Avatar src={email.avatar} name={email.from} size=\"sm\" />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between\">\n <span\n className={`text-sm truncate ${email.unread ? \"font-semibold text-[var(--color-text-primary)]\" : \"font-medium text-[var(--color-text-secondary)]\"}`}\n >\n {email.from}\n </span>\n <span className=\"text-xs text-[var(--color-text-muted)] flex-shrink-0 ml-2\">\n {email.time}\n </span>\n </div>\n <div\n className={`text-sm truncate mt-0.5 ${email.unread ? \"font-medium text-[var(--color-text-primary)]\" : \"text-[var(--color-text-secondary)]\"}`}\n >\n {email.subject}\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)] truncate mt-0.5\">\n {email.preview}\n </div>\n <div className=\"flex items-center gap-2 mt-1.5\">\n {email.starred && (\n <StarSolidIcon className=\"size-3.5 text-[var(--color-warning)]\" />\n )}\n {email.hasAttachment && (\n <PaperClipIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n )}\n {email.labels.map((label) => (\n <span\n key={label}\n className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium ${labelColors[label] || \"\"}`}\n >\n {label}\n </span>\n ))}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n </ScrollArea>\n </div>\n\n {/* Email detail */}\n <div className=\"hidden sm:flex flex-1 flex-col min-w-0\">\n {/* Toolbar */}\n <div className=\"flex items-center justify-between px-6 py-3 border-b border-[var(--color-border)]\">\n <div className=\"flex items-center gap-1\">\n <Tooltip content=\"Reply\">\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly>\n <ArrowUturnLeftIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Forward\">\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly>\n <ArrowUturnRightIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Archive\">\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly>\n <ArchiveBoxIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Delete\">\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly>\n <TrashIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n <Button variant=\"soft\" color=\"mono\" size=\"sm\" iconOnly>\n <EllipsisHorizontalIcon className=\"size-4\" />\n </Button>\n </div>\n\n {/* Email content */}\n <ScrollArea className=\"flex-1\">\n <div className=\"max-w-3xl mx-auto px-6 lg:px-8 py-6 space-y-6\">\n {/* Subject */}\n <div>\n <div className=\"flex items-start justify-between gap-4\">\n <h1 className=\"text-xl font-semibold text-[var(--color-text-primary)]\">\n {activeEmail.subject}\n </h1>\n <button className=\"flex-shrink-0 mt-1\">\n <StarSolidIcon className=\"size-5 text-[var(--color-warning)]\" />\n </button>\n </div>\n <div className=\"flex flex-wrap items-center gap-2 mt-2\">\n {activeEmail.labels.map((label) => (\n <Badge key={label} color=\"primary\" variant=\"soft\" size=\"sm\">\n {label}\n </Badge>\n ))}\n </div>\n </div>\n\n {/* Sender */}\n <div className=\"flex items-center gap-3\">\n <Avatar\n src={activeEmail.avatar}\n name={activeEmail.from}\n size=\"md\"\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2\">\n <span className=\"font-semibold text-sm text-[var(--color-text-primary)]\">\n {activeEmail.from}\n </span>\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n alex@company.com\n </span>\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)]\">\n To: you, sarah@company.com, james@company.com\n </div>\n </div>\n <span className=\"text-xs text-[var(--color-text-muted)] flex-shrink-0\">\n {activeEmail.time}\n </span>\n </div>\n\n <Separator />\n\n {/* Body */}\n <div className=\"text-sm text-[var(--color-text-secondary)] leading-relaxed space-y-4\">\n <p>Hey team,</p>\n <p>\n I've attached the updated Q4 roadmap with the prioritized\n features we discussed in yesterday's meeting. Here are the key\n highlights:\n </p>\n <ul className=\"list-disc pl-5 space-y-1\">\n <li>\n <strong>Chart Components v2</strong> — Complete rewrite with\n simplified API, accessibility improvements, and CSS variable\n theming\n </li>\n <li>\n <strong>Dark Mode</strong> — Full dark mode support across all\n 50+ components with automatic system preference detection\n </li>\n <li>\n <strong>Performance</strong> — Tree-shaking optimization\n targeting a 40% reduction in bundle size\n </li>\n <li>\n <strong>AI Components</strong> — New suite of components for\n building AI-powered chat interfaces\n </li>\n </ul>\n <p>\n I've also included a timeline and resource allocation breakdown\n in the attached document. Let me know if you have any questions\n or if we need to adjust priorities.\n </p>\n <p>\n Best,\n <br />\n Alex\n </p>\n </div>\n\n {/* Attachment */}\n <div className=\"border border-[var(--color-border)] rounded-lg p-3 flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-primary-50)] flex items-center justify-center flex-shrink-0\">\n <PaperClipIcon className=\"size-5 text-[var(--color-primary)]\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-[var(--color-text-primary)] truncate\">\n Q4-Roadmap-2026.pdf\n </div>\n <div className=\"text-xs text-[var(--color-text-muted)]\">\n 2.4 MB\n </div>\n </div>\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n Download\n </Button>\n </div>\n\n <Separator />\n\n {/* Quick reply */}\n <div>\n <Input placeholder=\"Write a quick reply...\" size=\"md\" />\n <div className=\"flex justify-end mt-3 gap-2\">\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n Discard\n </Button>\n <Button size=\"sm\">\n <PaperAirplaneIcon className=\"size-4\" /> Send\n </Button>\n </div>\n </div>\n </div>\n </ScrollArea>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11085
11604
  },
11086
11605
  {
11087
11606
  "name": "InvoiceLayout",
@@ -11095,30 +11614,7 @@
11095
11614
  "Separator",
11096
11615
  "Table"
11097
11616
  ],
11098
- "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Badge,\n Button,\n ButtonGroup,\n Card,\n Separator,\n} from \"../../components/core\";\nimport { Table } from \"../../components/data-display\";\nimport {\n ArrowDownTrayIcon,\n PaperAirplaneIcon,\n CheckIcon,\n} from \"@heroicons/react/24/outline\";\n\nconst meta: Meta = {\n title: \"Blocks/InvoiceLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\ntype InvoiceItem = {\n description: string;\n detail: string;\n quantity: string;\n unitPrice: string;\n amount: string;\n};\n\ntype Invoice = {\n status: \"paid\" | \"overdue\";\n title: string;\n customer: string;\n customerEmail: string;\n customerAddress: string;\n issued: string;\n due: string;\n paidOn?: string;\n terms: string;\n subtotal: string;\n tax: string;\n total: string;\n noteTitle: string;\n note: string;\n items: InvoiceItem[];\n};\n\nconst paidInvoice: Invoice = {\n status: \"paid\",\n title: \"INV-2024-001\",\n customer: \"Acme Corporation\",\n customerEmail: \"billing@acme.com\",\n customerAddress: \"456 Business Ave, New York, NY 10001\",\n issued: \"Jan 15, 2025\",\n due: \"Feb 15, 2025\",\n paidOn: \"Feb 10, 2025\",\n terms: \"Net 30\",\n subtotal: \"$1,273.00\",\n tax: \"$127.30\",\n total: \"$1,400.30\",\n noteTitle: \"Payment received\",\n note: \"Bank transfer cleared on Feb 10, 2025. Receipt sent to billing@acme.com.\",\n items: [\n {\n description: \"UI Component Library License\",\n detail: \"Pro plan, annual billing\",\n quantity: \"1\",\n unitPrice: \"$299.00\",\n amount: \"$299.00\",\n },\n {\n description: \"Priority Support Package\",\n detail: \"Annual SLA with email and chat coverage\",\n quantity: \"1\",\n unitPrice: \"$149.00\",\n amount: \"$149.00\",\n },\n {\n description: \"Custom Theme Development\",\n detail: \"Brand token setup and interaction states\",\n quantity: \"3\",\n unitPrice: \"$75.00\",\n amount: \"$225.00\",\n },\n {\n description: \"Design Consultation\",\n detail: \"Implementation review and component guidance\",\n quantity: \"5\",\n unitPrice: \"$120.00\",\n amount: \"$600.00\",\n },\n ],\n};\n\nconst overdueInvoice: Invoice = {\n status: \"overdue\",\n title: \"INV-2025-019\",\n customer: \"Globex Corporation\",\n customerEmail: \"accounts@globex.com\",\n customerAddress: \"789 Industry Blvd, Chicago, IL 60601\",\n issued: \"Dec 1, 2025\",\n due: \"Dec 31, 2025\",\n terms: \"Net 30\",\n subtotal: \"$4,950.00\",\n tax: \"$495.00\",\n total: \"$5,445.00\",\n noteTitle: \"Payment overdue\",\n note: \"A reminder was sent to accounts@globex.com. Keep the payment link active until the balance is settled.\",\n items: [\n {\n description: \"Enterprise License\",\n detail: \"Unlimited seats and advanced permissions\",\n quantity: \"1\",\n unitPrice: \"$2,400.00\",\n amount: \"$2,400.00\",\n },\n {\n description: \"Dedicated Onboarding\",\n detail: \"Two live training sessions for admins\",\n quantity: \"2\",\n unitPrice: \"$800.00\",\n amount: \"$1,600.00\",\n },\n {\n description: \"Custom SSO Integration\",\n detail: \"SAML configuration and launch support\",\n quantity: \"1\",\n unitPrice: \"$950.00\",\n amount: \"$950.00\",\n },\n ],\n};\n\nconst InvoiceLayout = ({ invoice }: { invoice: Invoice }) => {\n const isPaid = invoice.status === \"paid\";\n\n return (\n <div className=\"min-h-screen bg-[var(--color-background)] px-4 py-6 text-[var(--color-text-primary)] sm:px-6 lg:px-8\">\n <div className=\"mx-auto max-w-5xl space-y-5\">\n <div className=\"flex flex-col gap-4 rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)]/80 px-4 py-4 shadow-[0_16px_40px_rgba(50,50,93,0.08)] backdrop-blur sm:flex-row sm:items-center sm:justify-between sm:px-5\">\n <div className=\"min-w-0\">\n <div className=\"mb-2 flex items-center gap-2\">\n {isPaid ? (\n <Badge color=\"success\" variant=\"soft\" withDot pill>\n Paid\n </Badge>\n ) : (\n <Badge color=\"danger\" variant=\"soft\" withDot pill>\n Past due\n </Badge>\n )}\n <span className=\"text-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]\">\n Flikkui Billing\n </span>\n </div>\n <h1 className=\"truncate text-xl font-semibold text-[var(--color-text-primary)] sm:text-2xl\">\n Invoice {invoice.title}\n </h1>\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <ButtonGroup>\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n <ArrowDownTrayIcon className=\"size-4\" />\n Download\n </Button>\n <Button variant=\"outline\" color=\"neutral\" size=\"sm\">\n <PaperAirplaneIcon className=\"size-4\" />\n {isPaid ? \"Send receipt\" : \"Send reminder\"}\n </Button>\n </ButtonGroup>\n {!isPaid && (\n <Button variant=\"filled\" color=\"primary\" size=\"sm\">\n <CheckIcon className=\"size-4\" />\n Mark as paid\n </Button>\n )}\n </div>\n </div>\n\n <Card className=\"overflow-hidden border-[var(--color-border)] bg-[var(--color-surface)] shadow-[0_24px_64px_rgba(50,50,93,0.12)]\">\n <Card.Body className=\"p-0\">\n <div className=\"grid gap-8 border-b border-[var(--color-border)] px-5 py-8 sm:px-8 lg:grid-cols-[1fr_300px] lg:px-10\">\n <div className=\"space-y-10\">\n <div>\n <div className=\"mb-8 flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-primary)] text-sm font-bold text-[var(--color-primary-contrast)] shadow-[0_8px_24px_rgba(99,91,255,0.28)]\">\n F\n </div>\n <div>\n <div className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n Flikkui Inc.\n </div>\n <div className=\"text-sm text-[var(--color-text-secondary)]\">\n hello@flikkui.com\n </div>\n </div>\n </div>\n\n <p className=\"max-w-xl text-4xl font-semibold leading-tight text-[var(--color-text-primary)] sm:text-5xl\">\n {invoice.total}\n </p>\n <p className=\"mt-2 text-sm text-[var(--color-text-secondary)]\">\n Due {invoice.due} for {invoice.customer}\n </p>\n </div>\n\n <div className=\"grid gap-6 sm:grid-cols-2\">\n <div>\n <div className=\"text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n Bill to\n </div>\n <div className=\"mt-3 text-sm font-medium text-[var(--color-text-primary)]\">\n {invoice.customer}\n </div>\n <div className=\"mt-1 max-w-xs text-sm leading-6 text-[var(--color-text-secondary)]\">\n {invoice.customerAddress}\n <br />\n {invoice.customerEmail}\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <InvoiceFact label=\"Invoice\" value={invoice.title} />\n <InvoiceFact label=\"Terms\" value={invoice.terms} />\n <InvoiceFact label=\"Issued\" value={invoice.issued} />\n <InvoiceFact\n label={isPaid ? \"Paid\" : \"Due\"}\n value={\n isPaid ? invoice.paidOn || invoice.due : invoice.due\n }\n tone={isPaid ? \"success\" : \"danger\"}\n />\n </div>\n </div>\n </div>\n\n <div className=\"self-start rounded-2xl border border-[var(--color-border)] p-5\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <div className=\"text-sm font-semibold text-[var(--color-text-primary)]\">\n Amount {isPaid ? \"paid\" : \"due\"}\n </div>\n <div className=\"mt-1 text-sm text-[var(--color-text-secondary)]\">\n {isPaid\n ? \"Settled by bank transfer\"\n : \"Awaiting customer payment\"}\n </div>\n </div>\n {isPaid ? (\n <Badge color=\"success\" variant=\"soft\" size=\"sm\" pill>\n Complete\n </Badge>\n ) : (\n <Badge color=\"danger\" variant=\"soft\" size=\"sm\" pill>\n Action needed\n </Badge>\n )}\n </div>\n\n <Separator className=\"my-4\" />\n\n <div className=\"space-y-2.5 text-sm\">\n <SummaryRow label=\"Subtotal\" value={invoice.subtotal} />\n <SummaryRow label=\"Tax\" value={invoice.tax} muted />\n </div>\n\n <div className=\"mt-4 flex items-baseline justify-between border-t border-[var(--color-border)] pt-4\">\n <span className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n Total\n </span>\n <span className=\"text-xl font-semibold text-[var(--color-text-primary)]\">\n {invoice.total}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"px-5 py-6 sm:px-8 lg:px-10\">\n <Table\n padding=\"flush\"\n className=\"min-w-[680px] border-separate border-spacing-0\"\n >\n <Table.Header>\n <Table.Row className=\"hover:bg-transparent dark:hover:bg-transparent\">\n <Table.HeaderCell className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n Description\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"center\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Qty\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"right\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Unit price\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"right\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Amount\n </Table.HeaderCell>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {invoice.items.map((item, idx) => {\n const border =\n idx === invoice.items.length - 1 ? \"border-b-0\" : \"\";\n return (\n <Table.Row\n key={item.description}\n className=\"hover:bg-transparent dark:hover:bg-transparent\"\n >\n <Table.Cell className={`${border} py-5`}>\n <div className=\"font-medium text-[var(--color-text-primary)]\">\n {item.description}\n </div>\n <div className=\"mt-1 text-sm text-[var(--color-text-secondary)]\">\n {item.detail}\n </div>\n </Table.Cell>\n <Table.Cell\n align=\"center\"\n className={`${border} py-5 text-[var(--color-text-secondary)]`}\n >\n {item.quantity}\n </Table.Cell>\n <Table.Cell\n align=\"right\"\n className={`${border} py-5 text-[var(--color-text-secondary)]`}\n >\n {item.unitPrice}\n </Table.Cell>\n <Table.Cell\n align=\"right\"\n className={`${border} py-5 font-medium text-[var(--color-text-primary)]`}\n >\n {item.amount}\n </Table.Cell>\n </Table.Row>\n );\n })}\n </Table.Body>\n </Table>\n </div>\n\n <div className=\"border-t border-[var(--color-border)] bg-[var(--color-surface)] px-5 py-5 sm:px-8 lg:px-10\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div className=\"text-sm font-semibold text-[var(--color-text-primary)]\">\n {invoice.noteTitle}\n </div>\n <div className=\"mt-1 max-w-2xl text-sm leading-6 text-[var(--color-text-secondary)]\">\n {invoice.note}\n </div>\n </div>\n <div className=\"text-sm font-medium text-[var(--color-primary)]\">\n flikkui.com/pay/{invoice.title.toLowerCase()}\n </div>\n </div>\n </div>\n </Card.Body>\n </Card>\n </div>\n </div>\n );\n};\n\nconst InvoiceFact = ({\n label,\n value,\n tone,\n}: {\n label: string;\n value: string;\n tone?: \"success\" | \"danger\";\n}) => {\n const toneClass =\n tone === \"success\"\n ? \"text-[var(--color-success)]\"\n : tone === \"danger\"\n ? \"text-[var(--color-danger)]\"\n : \"text-[var(--color-text-primary)]\";\n\n return (\n <div>\n <div className=\"text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n {label}\n </div>\n <div className={`mt-2 font-medium ${toneClass}`}>{value}</div>\n </div>\n );\n};\n\nconst SummaryRow = ({\n label,\n value,\n muted = false,\n}: {\n label: string;\n value: string;\n muted?: boolean;\n}) => (\n <div\n className={`flex items-center justify-between ${\n muted ? \"text-[var(--color-text-secondary)]\" : \"text-[var(--color-text-primary)]\"\n }`}\n >\n <span>{label}</span>\n <span className=\"font-medium\">{value}</span>\n </div>\n);\n\nexport const Default: Story = {\n render: () => <InvoiceLayout invoice={paidInvoice} />,\n parameters: {\n controls: { disable: true },\n },\n};\n\nexport const Overdue: Story = {\n render: () => <InvoiceLayout invoice={overdueInvoice} />,\n parameters: {\n controls: { disable: true },\n },\n};"
11099
- },
11100
- {
11101
- "name": "LMSDashboardLayout",
11102
- "title": "Blocks/LMSDashboardLayout",
11103
- "description": "Full-page composition using AppShell, Avatar, Badge, Button, ….",
11104
- "componentsUsed": [
11105
- "AppShell",
11106
- "Avatar",
11107
- "Badge",
11108
- "Button",
11109
- "Card",
11110
- "Grid",
11111
- "Metric",
11112
- "NavItem",
11113
- "Progress",
11114
- "PromptInput",
11115
- "PromptSuggestion",
11116
- "Section",
11117
- "Sidebar",
11118
- "Table",
11119
- "Timeline"
11120
- ],
11121
- "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Badge,\n Button,\n Card,\n NavItem,\n Progress,\n Sidebar,\n} from \"../../components/core\";\nimport { AppShell, Grid, Section } from \"../../components/layout\";\nimport { Metric, Table, Timeline } from \"../../components/data-display\";\nimport type { Column } from \"../../components/data-display\";\nimport { PromptInput, PromptSuggestion } from \"../../components/ai\";\nimport {\n AcademicCapIcon,\n ArrowRightIcon,\n BookOpenIcon,\n ChartBarIcon,\n ChatBubbleLeftRightIcon,\n CheckCircleIcon,\n ClockIcon,\n FireIcon,\n HomeIcon,\n PresentationChartLineIcon,\n ShieldCheckIcon,\n SparklesIcon,\n Squares2X2Icon,\n TrophyIcon,\n UserGroupIcon,\n VideoCameraIcon,\n} from \"@heroicons/react/24/outline\";\nimport { StarIcon as StarSolidIcon } from \"@heroicons/react/24/solid\";\n\nconst meta: Meta = {\n title: \"Blocks/LMSDashboardLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- To do: assigned learning, sorted by due date ---\n\ninterface Assignment {\n id: string;\n title: string;\n detail: string;\n type: \"Course\" | \"Path\" | \"Live\";\n due: string;\n urgency: \"overdue\" | \"soon\" | \"later\";\n progress: number;\n icon: React.ReactNode;\n iconClassName: string;\n}\n\nconst assignments: Assignment[] = [\n {\n id: \"1\",\n title: \"Security & Data Privacy Essentials\",\n detail: \"Annual compliance · 6 lessons\",\n type: \"Course\",\n due: \"Overdue · Jun 10\",\n urgency: \"overdue\",\n progress: 45,\n icon: <ShieldCheckIcon className=\"size-4\" />,\n iconClassName: \"bg-[var(--color-danger-50)] text-[var(--color-danger-600)]\",\n },\n {\n id: \"2\",\n title: \"Giving Effective Feedback\",\n detail: \"Manager Essentials path · Step 3 of 5\",\n type: \"Path\",\n due: \"Due tomorrow\",\n urgency: \"soon\",\n progress: 70,\n icon: <ChatBubbleLeftRightIcon className=\"size-4\" />,\n iconClassName:\n \"bg-[var(--color-primary-50)] text-[var(--color-primary-600)]\",\n },\n {\n id: \"3\",\n title: \"Q3 Product Deep-Dive\",\n detail: \"Live session · Hosted by Product team\",\n type: \"Live\",\n due: \"Jun 16 · 4:00 PM\",\n urgency: \"later\",\n progress: 0,\n icon: <VideoCameraIcon className=\"size-4\" />,\n iconClassName:\n \"bg-[var(--color-success-50)] text-[var(--color-success-600)]\",\n },\n {\n id: \"4\",\n title: \"Figma for Cross-Functional Teams\",\n detail: \"Design fundamentals · 9 lessons\",\n type: \"Course\",\n due: \"Due Jun 24\",\n urgency: \"later\",\n progress: 20,\n icon: <Squares2X2Icon className=\"size-4\" />,\n iconClassName:\n \"bg-[var(--color-warning-50)] text-[var(--color-warning-600)]\",\n },\n];\n\nconst dueBadgeColor: Record<Assignment[\"urgency\"], \"danger\" | \"warning\" | \"neutral\"> = {\n overdue: \"danger\",\n soon: \"warning\",\n later: \"neutral\",\n};\n\nconst assignmentColumns: Column<Assignment>[] = [\n {\n id: \"title\",\n header: \"Assignment\",\n accessor: \"title\",\n cell: (row) => (\n <div className=\"flex items-center gap-3\">\n <div\n className={`flex size-9 shrink-0 items-center justify-center rounded-lg ${row.iconClassName}`}\n >\n {row.icon}\n </div>\n <div className=\"min-w-0\">\n <div className=\"truncate font-medium text-[var(--color-text-primary)]\">\n {row.title}\n </div>\n <div className=\"truncate text-xs text-[var(--color-text-muted)]\">\n {row.detail}\n </div>\n </div>\n </div>\n ),\n },\n {\n id: \"type\",\n header: \"Type\",\n accessor: \"type\",\n cell: (row) => (\n <Badge color=\"neutral\" variant=\"soft\" size=\"sm\">\n {row.type}\n </Badge>\n ),\n },\n {\n id: \"due\",\n header: \"Due\",\n accessor: \"due\",\n cell: (row) => (\n <Badge color={dueBadgeColor[row.urgency]} variant=\"soft\" size=\"sm\">\n {row.due}\n </Badge>\n ),\n },\n {\n id: \"progress\",\n header: \"Progress\",\n accessor: \"progress\",\n width: 180,\n cell: (row) =>\n row.type === \"Live\" ? (\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n Enrolled\n </span>\n ) : (\n <Progress value={row.progress} size=\"sm\" showLabel />\n ),\n },\n {\n id: \"action\",\n header: \"\",\n accessor: \"id\",\n align: \"right\",\n cell: (row) => (\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\">\n {row.type === \"Live\" ? \"Join\" : \"Continue\"}\n <ArrowRightIcon className=\"size-3.5\" />\n </Button>\n ),\n },\n];\n\n// --- Continue learning ---\n\nconst inProgressCourses = [\n {\n title: \"Advanced Prompt Engineering\",\n category: \"AI & Data\",\n lessons: \"Lesson 12 of 18\",\n progress: 68,\n timeLeft: \"24 min left\",\n gradient:\n \"from-[var(--color-primary-400)] to-[var(--color-primary-700)]\",\n icon: <SparklesIcon className=\"size-7\" />,\n },\n {\n title: \"Storytelling with Data\",\n category: \"Communication\",\n lessons: \"Lesson 4 of 11\",\n progress: 35,\n timeLeft: \"1h 10m left\",\n gradient:\n \"from-[var(--color-warning-400)] to-[var(--color-warning-600)]\",\n icon: <PresentationChartLineIcon className=\"size-7\" />,\n },\n {\n title: \"Negotiation Fundamentals\",\n category: \"Sales\",\n lessons: \"Lesson 9 of 10\",\n progress: 82,\n timeLeft: \"15 min left\",\n gradient:\n \"from-[var(--color-success-400)] to-[var(--color-success-700)]\",\n icon: <UserGroupIcon className=\"size-7\" />,\n },\n];\n\n// --- Leaderboard ---\n\nconst leaderboard = [\n {\n rank: 1,\n name: \"Jonas Lindqvist\",\n team: \"Engineering\",\n points: 2840,\n avatar: \"https://i.pravatar.cc/150?u=jonas-lindqvist\",\n },\n {\n rank: 2,\n name: \"Priya Sharma\",\n team: \"Product\",\n points: 2615,\n avatar: \"https://i.pravatar.cc/150?u=priya-sharma\",\n },\n {\n rank: 3,\n name: \"Tom Becker\",\n team: \"Sales\",\n points: 2390,\n avatar: \"https://i.pravatar.cc/150?u=tom-becker\",\n },\n {\n rank: 4,\n name: \"Maya Patel\",\n team: \"Design\",\n points: 2210,\n avatar: \"https://i.pravatar.cc/150?u=maya-patel\",\n isYou: true,\n },\n {\n rank: 5,\n name: \"Sofia Reyes\",\n team: \"Marketing\",\n points: 2045,\n avatar: \"https://i.pravatar.cc/150?u=sofia-reyes\",\n },\n];\n\n// --- AI recommendations ---\n\nconst recommendations = [\n {\n title: \"Running Inclusive Meetings\",\n category: \"Leadership\",\n duration: \"35 min\",\n rating: 4.8,\n icon: <UserGroupIcon className=\"size-5\" />,\n iconClassName:\n \"bg-[var(--color-primary-50)] text-[var(--color-primary-600)]\",\n },\n {\n title: \"SQL for Product Managers\",\n category: \"AI & Data\",\n duration: \"1h 20m\",\n rating: 4.9,\n icon: <ChartBarIcon className=\"size-5\" />,\n iconClassName:\n \"bg-[var(--color-success-50)] text-[var(--color-success-600)]\",\n },\n {\n title: \"Writing Crisp Product Specs\",\n category: \"Communication\",\n duration: \"50 min\",\n rating: 4.7,\n icon: <BookOpenIcon className=\"size-5\" />,\n iconClassName:\n \"bg-[var(--color-warning-50)] text-[var(--color-warning-600)]\",\n },\n {\n title: \"Coaching Through Change\",\n category: \"Leadership\",\n duration: \"45 min\",\n rating: 4.6,\n icon: <ChatBubbleLeftRightIcon className=\"size-5\" />,\n iconClassName:\n \"bg-[var(--color-danger-50)] text-[var(--color-danger-600)]\",\n },\n];\n\nexport const Default: Story = {\n render: () => (\n <AppShell contentPadding=\"lg\" contentWidth=\"wide\">\n <AppShell.Sidebar\n width=\"auto\"\n collapsedOnMobile={false}\n theme={{ sidebar: \"flex flex-col shrink-0\" }}\n >\n <Sidebar variant=\"floating\">\n <Sidebar.Header\n logo={\n <Sidebar.Logo\n icon={\n <div className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-primary)] text-white\">\n <AcademicCapIcon className=\"size-5\" />\n </div>\n }\n text=\"Flikk Learn\"\n />\n }\n />\n <Sidebar.Search placeholder=\"Search learning…\" />\n <Sidebar.Content>\n <Sidebar.Nav>\n <Sidebar.NavGroup title=\"Learn\">\n <NavItem startContent={<HomeIcon />} active>\n Home\n </NavItem>\n <NavItem startContent={<BookOpenIcon />} notification={3}>\n My Learning\n </NavItem>\n <NavItem startContent={<Squares2X2Icon />}>Library</NavItem>\n <NavItem startContent={<VideoCameraIcon />}>\n Live Sessions\n </NavItem>\n <NavItem startContent={<TrophyIcon />}>Skills</NavItem>\n </Sidebar.NavGroup>\n <Sidebar.NavGroup title=\"Manage\">\n <NavItem startContent={<ChartBarIcon />}>Insights</NavItem>\n </Sidebar.NavGroup>\n </Sidebar.Nav>\n </Sidebar.Content>\n <Sidebar.Footer>\n <Sidebar.Toggle />\n <Sidebar.UserProfile\n name=\"Maya Patel\"\n email=\"maya@flikk.io\"\n avatar=\"https://i.pravatar.cc/150?u=maya-patel\"\n status=\"online\"\n />\n </Sidebar.Footer>\n </Sidebar>\n </AppShell.Sidebar>\n\n {/* Recessed floor (NodeCanvas-style) so the borderless white cards read\n as panels above the canvas — the GenerativeUI-block look. */}\n <AppShell.Main\n theme={{ mainScroll: \"min-h-0 flex-1 bg-[var(--color-surface-sunken)]\" }}\n >\n <div className=\"mx-auto max-w-6xl space-y-10 pb-12\">\n {/* Hero — greeting + AI ask bar (the Sana signature) */}\n <div className=\"flex flex-col items-center pt-8 text-center\">\n <h1 className=\"text-3xl font-semibold tracking-tight text-[var(--color-text-primary)]\">\n Good morning, Maya\n </h1>\n <p className=\"mt-2 text-sm text-[var(--color-text-muted)]\">\n You have 2 assignments due this week and a live session today at\n 4:00 PM.\n </p>\n <div className=\"mt-6 w-full max-w-2xl\">\n <PromptInput\n placeholder=\"Ask anything — find a course, company knowledge, or get help…\"\n showAttachmentButton={false}\n showVoiceButton={false}\n showModelSelector={false}\n showSettingsButton={false}\n onSubmit={() => {}}\n />\n </div>\n <div className=\"mt-4 flex flex-wrap items-center justify-center gap-2\">\n <PromptSuggestion\n icon={<SparklesIcon className=\"size-4\" />}\n onSelect={() => {}}\n >\n What should I learn next?\n </PromptSuggestion>\n <PromptSuggestion\n icon={<SparklesIcon className=\"size-4\" />}\n onSelect={() => {}}\n >\n Summarize my overdue work\n </PromptSuggestion>\n <PromptSuggestion\n icon={<SparklesIcon className=\"size-4\" />}\n onSelect={() => {}}\n >\n Find courses on negotiation\n </PromptSuggestion>\n </div>\n </div>\n\n {/* Stats strip — bare ghost Metrics on the canvas (GenerativeUI\n treatment). Metric renders its own Card shell internally, so it\n must NOT be wrapped in another Card. */}\n <Grid cols={4} gap={4}>\n <Metric\n label=\"Courses completed\"\n value={12}\n trendValue=\"+3 this month\"\n trendDirection=\"up\"\n icon={<CheckCircleIcon />}\n color=\"success\"\n size=\"sm\"\n variant=\"ghost\"\n />\n <Metric\n label=\"Learning streak\"\n value=\"8 days\"\n subtitle=\"Best: 21 days\"\n icon={<FireIcon />}\n color=\"warning\"\n size=\"sm\"\n variant=\"ghost\"\n />\n <Metric\n label=\"Time this month\"\n value=\"14.5h\"\n trendValue=\"+2.1h\"\n trendDirection=\"up\"\n icon={<ClockIcon />}\n color=\"primary\"\n size=\"sm\"\n variant=\"ghost\"\n />\n <Metric\n label=\"Badges earned\"\n value={6}\n subtitle=\"2 skills in progress\"\n icon={<TrophyIcon />}\n color=\"neutral\"\n size=\"sm\"\n variant=\"ghost\"\n />\n </Grid>\n\n {/* To do */}\n <Section\n title=\"To do\"\n subtitle=\"Assigned learning, sorted by due date\"\n actions={\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\">\n View all\n </Button>\n }\n >\n <Card>\n <Table\n data={assignments}\n columns={assignmentColumns}\n rowKey=\"id\"\n padding=\"flush\"\n />\n </Card>\n </Section>\n\n {/* Continue learning */}\n <Section\n title=\"Continue learning\"\n subtitle=\"Pick up where you left off\"\n >\n <Grid cols={3} gap={4}>\n {inProgressCourses.map((course) => (\n <Card key={course.title} className=\"overflow-hidden\">\n <div\n className={`flex h-28 items-center justify-center bg-gradient-to-br text-white ${course.gradient}`}\n >\n {course.icon}\n </div>\n <Card.Body>\n <Badge color=\"neutral\" variant=\"soft\" size=\"sm\">\n {course.category}\n </Badge>\n <h3 className=\"mt-2 font-medium text-[var(--color-text-primary)]\">\n {course.title}\n </h3>\n <p className=\"mt-0.5 text-xs text-[var(--color-text-muted)]\">\n {course.lessons}\n </p>\n <div className=\"mt-3\">\n <Progress value={course.progress} size=\"sm\" showLabel />\n </div>\n <div className=\"mt-4 flex items-center justify-between\">\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n {course.timeLeft}\n </span>\n <Button size=\"sm\">\n Resume\n <ArrowRightIcon className=\"size-3.5\" />\n </Button>\n </div>\n </Card.Body>\n </Card>\n ))}\n </Grid>\n </Section>\n\n {/* Sessions + leaderboard */}\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <Card\n title=\"Upcoming live sessions\"\n subtitle=\"Self-enroll while seats last\"\n actions={\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\">\n View calendar\n </Button>\n }\n className=\"lg:col-span-2\"\n >\n <Timeline\n items={[\n {\n status: \"active\",\n title: \"Q3 Product Deep-Dive\",\n description: (\n <span className=\"flex flex-wrap items-center gap-2\">\n Hosted by the Product team\n <Badge color=\"success\" variant=\"soft\" size=\"sm\">\n 14 seats left\n </Badge>\n </span>\n ),\n timestamp: \"Today · 4:00 PM\",\n icon: <VideoCameraIcon className=\"size-3.5\" />,\n },\n {\n status: \"pending\",\n title: \"Manager AMA with the People team\",\n description: \"Open Q&A — bring your trickiest situations\",\n timestamp: \"Jun 16 · 11:00 AM\",\n },\n {\n status: \"pending\",\n title: \"Workshop: Storytelling with Data\",\n description: (\n <span className=\"flex flex-wrap items-center gap-2\">\n Hands-on, capped at 20 participants\n <Badge color=\"warning\" variant=\"soft\" size=\"sm\">\n 3 seats left\n </Badge>\n </span>\n ),\n timestamp: \"Jun 19 · 2:00 PM\",\n },\n ]}\n />\n </Card>\n\n <Card title=\"Skills leaderboard\" subtitle=\"This quarter\">\n <div className=\"space-y-1\">\n {leaderboard.map((person) => (\n <div\n key={person.rank}\n className={`flex items-center gap-3 rounded-lg px-2 py-2 ${\n person.isYou ? \"bg-[var(--color-primary-50)]\" : \"\"\n }`}\n >\n <span className=\"w-5 text-center text-sm font-semibold text-[var(--color-text-muted)]\">\n {person.rank}\n </span>\n <Avatar src={person.avatar} name={person.name} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium text-[var(--color-text-primary)]\">\n {person.name}\n </div>\n <div className=\"truncate text-xs text-[var(--color-text-muted)]\">\n {person.team}\n {person.isYou && (\n <span className=\"text-[var(--color-primary-600)]\">\n {\" \"}\n · You\n </span>\n )}\n </div>\n </div>\n <span className=\"text-sm font-semibold text-[var(--color-text-secondary)]\">\n {person.points.toLocaleString()}\n </span>\n {person.rank === 1 && (\n <TrophyIcon className=\"size-4 text-[var(--color-warning-500)]\" />\n )}\n </div>\n ))}\n </div>\n </Card>\n </div>\n\n {/* AI recommendations */}\n <Section\n title=\"You might like\"\n subtitle=\"Picked for you based on your role and recent learning\"\n >\n <Grid cols={4} gap={4}>\n {recommendations.map((course) => (\n <Card key={course.title} className=\"transition-shadow hover:shadow-md\">\n <Card.Body>\n <div\n className={`flex size-10 items-center justify-center rounded-lg ${course.iconClassName}`}\n >\n {course.icon}\n </div>\n <h3 className=\"mt-3 text-sm font-medium text-[var(--color-text-primary)]\">\n {course.title}\n </h3>\n <div className=\"mt-2 flex items-center gap-2 text-xs text-[var(--color-text-muted)]\">\n <span>{course.duration}</span>\n <span aria-hidden=\"true\">·</span>\n <span className=\"flex items-center gap-0.5\">\n <StarSolidIcon className=\"size-3.5 text-[var(--color-warning-500)]\" />\n {course.rating}\n </span>\n </div>\n <div className=\"mt-3\">\n <Badge color=\"neutral\" variant=\"soft\" size=\"sm\">\n {course.category}\n </Badge>\n </div>\n </Card.Body>\n </Card>\n ))}\n </Grid>\n </Section>\n </div>\n </AppShell.Main>\n </AppShell>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11617
+ "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Badge,\n Button,\n ButtonGroup,\n Card,\n Separator,\n} from \"../../components/core\";\nimport { Table } from \"../../components/data-display\";\nimport { DownloadSimple as ArrowDownTrayIcon, PaperPlaneTilt as PaperAirplaneIcon, Check as CheckIcon } from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/InvoiceLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\ntype InvoiceItem = {\n description: string;\n detail: string;\n quantity: string;\n unitPrice: string;\n amount: string;\n};\n\ntype Invoice = {\n status: \"paid\" | \"overdue\";\n title: string;\n customer: string;\n customerEmail: string;\n customerAddress: string;\n issued: string;\n due: string;\n paidOn?: string;\n terms: string;\n subtotal: string;\n tax: string;\n total: string;\n noteTitle: string;\n note: string;\n items: InvoiceItem[];\n};\n\nconst paidInvoice: Invoice = {\n status: \"paid\",\n title: \"INV-2024-001\",\n customer: \"Acme Corporation\",\n customerEmail: \"billing@acme.com\",\n customerAddress: \"456 Business Ave, New York, NY 10001\",\n issued: \"Jan 15, 2025\",\n due: \"Feb 15, 2025\",\n paidOn: \"Feb 10, 2025\",\n terms: \"Net 30\",\n subtotal: \"$1,273.00\",\n tax: \"$127.30\",\n total: \"$1,400.30\",\n noteTitle: \"Payment received\",\n note: \"Bank transfer cleared on Feb 10, 2025. Receipt sent to billing@acme.com.\",\n items: [\n {\n description: \"UI Component Library License\",\n detail: \"Pro plan, annual billing\",\n quantity: \"1\",\n unitPrice: \"$299.00\",\n amount: \"$299.00\",\n },\n {\n description: \"Priority Support Package\",\n detail: \"Annual SLA with email and chat coverage\",\n quantity: \"1\",\n unitPrice: \"$149.00\",\n amount: \"$149.00\",\n },\n {\n description: \"Custom Theme Development\",\n detail: \"Brand token setup and interaction states\",\n quantity: \"3\",\n unitPrice: \"$75.00\",\n amount: \"$225.00\",\n },\n {\n description: \"Design Consultation\",\n detail: \"Implementation review and component guidance\",\n quantity: \"5\",\n unitPrice: \"$120.00\",\n amount: \"$600.00\",\n },\n ],\n};\n\nconst overdueInvoice: Invoice = {\n status: \"overdue\",\n title: \"INV-2025-019\",\n customer: \"Globex Corporation\",\n customerEmail: \"accounts@globex.com\",\n customerAddress: \"789 Industry Blvd, Chicago, IL 60601\",\n issued: \"Dec 1, 2025\",\n due: \"Dec 31, 2025\",\n terms: \"Net 30\",\n subtotal: \"$4,950.00\",\n tax: \"$495.00\",\n total: \"$5,445.00\",\n noteTitle: \"Payment overdue\",\n note: \"A reminder was sent to accounts@globex.com. Keep the payment link active until the balance is settled.\",\n items: [\n {\n description: \"Enterprise License\",\n detail: \"Unlimited seats and advanced permissions\",\n quantity: \"1\",\n unitPrice: \"$2,400.00\",\n amount: \"$2,400.00\",\n },\n {\n description: \"Dedicated Onboarding\",\n detail: \"Two live training sessions for admins\",\n quantity: \"2\",\n unitPrice: \"$800.00\",\n amount: \"$1,600.00\",\n },\n {\n description: \"Custom SSO Integration\",\n detail: \"SAML configuration and launch support\",\n quantity: \"1\",\n unitPrice: \"$950.00\",\n amount: \"$950.00\",\n },\n ],\n};\n\nconst InvoiceLayout = ({ invoice }: { invoice: Invoice }) => {\n const isPaid = invoice.status === \"paid\";\n\n return (\n <div className=\"min-h-screen bg-[var(--color-background)] px-4 py-6 text-[var(--color-text-primary)] sm:px-6 lg:px-8\">\n <div className=\"mx-auto max-w-5xl space-y-5\">\n <div className=\"flex flex-col gap-4 rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)]/80 px-4 py-4 shadow-[0_16px_40px_rgba(50,50,93,0.08)] backdrop-blur sm:flex-row sm:items-center sm:justify-between sm:px-5\">\n <div className=\"min-w-0\">\n <div className=\"mb-2 flex items-center gap-2\">\n {isPaid ? (\n <Badge color=\"success\" variant=\"soft\" withDot pill>\n Paid\n </Badge>\n ) : (\n <Badge color=\"danger\" variant=\"soft\" withDot pill>\n Past due\n </Badge>\n )}\n <span className=\"text-xs font-medium uppercase tracking-wide text-[var(--color-text-muted)]\">\n Flikkui Billing\n </span>\n </div>\n <h1 className=\"truncate text-xl font-semibold text-[var(--color-text-primary)] sm:text-2xl\">\n Invoice {invoice.title}\n </h1>\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <ButtonGroup>\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n <ArrowDownTrayIcon className=\"size-4\" />\n Download\n </Button>\n <Button variant=\"outline\" color=\"mono\" size=\"sm\">\n <PaperAirplaneIcon className=\"size-4\" />\n {isPaid ? \"Send receipt\" : \"Send reminder\"}\n </Button>\n </ButtonGroup>\n {!isPaid && (\n <Button variant=\"filled\" color=\"primary\" size=\"sm\">\n <CheckIcon className=\"size-4\" />\n Mark as paid\n </Button>\n )}\n </div>\n </div>\n\n <Card className=\"overflow-hidden border-[var(--color-border)] bg-[var(--color-surface)] shadow-[0_24px_64px_rgba(50,50,93,0.12)]\">\n <Card.Body className=\"p-0\">\n <div className=\"grid gap-8 border-b border-[var(--color-border)] px-5 py-8 sm:px-8 lg:grid-cols-[1fr_300px] lg:px-10\">\n <div className=\"space-y-10\">\n <div>\n <div className=\"mb-8 flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-primary)] text-sm font-bold text-[var(--color-primary-contrast)] shadow-[0_8px_24px_rgba(99,91,255,0.28)]\">\n F\n </div>\n <div>\n <div className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n Flikkui Inc.\n </div>\n <div className=\"text-sm text-[var(--color-text-secondary)]\">\n hello@flikkui.com\n </div>\n </div>\n </div>\n\n <p className=\"max-w-xl text-4xl font-semibold leading-tight text-[var(--color-text-primary)] sm:text-5xl\">\n {invoice.total}\n </p>\n <p className=\"mt-2 text-sm text-[var(--color-text-secondary)]\">\n Due {invoice.due} for {invoice.customer}\n </p>\n </div>\n\n <div className=\"grid gap-6 sm:grid-cols-2\">\n <div>\n <div className=\"text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n Bill to\n </div>\n <div className=\"mt-3 text-sm font-medium text-[var(--color-text-primary)]\">\n {invoice.customer}\n </div>\n <div className=\"mt-1 max-w-xs text-sm leading-6 text-[var(--color-text-secondary)]\">\n {invoice.customerAddress}\n <br />\n {invoice.customerEmail}\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <InvoiceFact label=\"Invoice\" value={invoice.title} />\n <InvoiceFact label=\"Terms\" value={invoice.terms} />\n <InvoiceFact label=\"Issued\" value={invoice.issued} />\n <InvoiceFact\n label={isPaid ? \"Paid\" : \"Due\"}\n value={\n isPaid ? invoice.paidOn || invoice.due : invoice.due\n }\n tone={isPaid ? \"success\" : \"danger\"}\n />\n </div>\n </div>\n </div>\n\n <div className=\"self-start rounded-2xl border border-[var(--color-border)] p-5\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <div className=\"text-sm font-semibold text-[var(--color-text-primary)]\">\n Amount {isPaid ? \"paid\" : \"due\"}\n </div>\n <div className=\"mt-1 text-sm text-[var(--color-text-secondary)]\">\n {isPaid\n ? \"Settled by bank transfer\"\n : \"Awaiting customer payment\"}\n </div>\n </div>\n {isPaid ? (\n <Badge color=\"success\" variant=\"soft\" size=\"sm\" pill>\n Complete\n </Badge>\n ) : (\n <Badge color=\"danger\" variant=\"soft\" size=\"sm\" pill>\n Action needed\n </Badge>\n )}\n </div>\n\n <Separator className=\"my-4\" />\n\n <div className=\"space-y-2.5 text-sm\">\n <SummaryRow label=\"Subtotal\" value={invoice.subtotal} />\n <SummaryRow label=\"Tax\" value={invoice.tax} muted />\n </div>\n\n <div className=\"mt-4 flex items-baseline justify-between border-t border-[var(--color-border)] pt-4\">\n <span className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n Total\n </span>\n <span className=\"text-xl font-semibold text-[var(--color-text-primary)]\">\n {invoice.total}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"px-5 py-6 sm:px-8 lg:px-10\">\n <Table\n padding=\"flush\"\n className=\"min-w-[680px] border-separate border-spacing-0\"\n >\n <Table.Header>\n <Table.Row className=\"hover:bg-transparent dark:hover:bg-transparent\">\n <Table.HeaderCell className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n Description\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"center\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Qty\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"right\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Unit price\n </Table.HeaderCell>\n <Table.HeaderCell\n align=\"right\"\n className=\"border-b border-[var(--color-border)] bg-[var(--color-surface)] pb-3 text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\"\n >\n Amount\n </Table.HeaderCell>\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {invoice.items.map((item, idx) => {\n const border =\n idx === invoice.items.length - 1 ? \"border-b-0\" : \"\";\n return (\n <Table.Row\n key={item.description}\n className=\"hover:bg-transparent dark:hover:bg-transparent\"\n >\n <Table.Cell className={`${border} py-5`}>\n <div className=\"font-medium text-[var(--color-text-primary)]\">\n {item.description}\n </div>\n <div className=\"mt-1 text-sm text-[var(--color-text-secondary)]\">\n {item.detail}\n </div>\n </Table.Cell>\n <Table.Cell\n align=\"center\"\n className={`${border} py-5 text-[var(--color-text-secondary)]`}\n >\n {item.quantity}\n </Table.Cell>\n <Table.Cell\n align=\"right\"\n className={`${border} py-5 text-[var(--color-text-secondary)]`}\n >\n {item.unitPrice}\n </Table.Cell>\n <Table.Cell\n align=\"right\"\n className={`${border} py-5 font-medium text-[var(--color-text-primary)]`}\n >\n {item.amount}\n </Table.Cell>\n </Table.Row>\n );\n })}\n </Table.Body>\n </Table>\n </div>\n\n <div className=\"border-t border-[var(--color-border)] bg-[var(--color-surface)] px-5 py-5 sm:px-8 lg:px-10\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div className=\"text-sm font-semibold text-[var(--color-text-primary)]\">\n {invoice.noteTitle}\n </div>\n <div className=\"mt-1 max-w-2xl text-sm leading-6 text-[var(--color-text-secondary)]\">\n {invoice.note}\n </div>\n </div>\n <div className=\"text-sm font-medium text-[var(--color-primary)]\">\n flikkui.com/pay/{invoice.title.toLowerCase()}\n </div>\n </div>\n </div>\n </Card.Body>\n </Card>\n </div>\n </div>\n );\n};\n\nconst InvoiceFact = ({\n label,\n value,\n tone,\n}: {\n label: string;\n value: string;\n tone?: \"success\" | \"danger\";\n}) => {\n const toneClass =\n tone === \"success\"\n ? \"text-[var(--color-success)]\"\n : tone === \"danger\"\n ? \"text-[var(--color-danger)]\"\n : \"text-[var(--color-text-primary)]\";\n\n return (\n <div>\n <div className=\"text-xs font-semibold uppercase tracking-wide text-[var(--color-text-muted)]\">\n {label}\n </div>\n <div className={`mt-2 font-medium ${toneClass}`}>{value}</div>\n </div>\n );\n};\n\nconst SummaryRow = ({\n label,\n value,\n muted = false,\n}: {\n label: string;\n value: string;\n muted?: boolean;\n}) => (\n <div\n className={`flex items-center justify-between ${\n muted ? \"text-[var(--color-text-secondary)]\" : \"text-[var(--color-text-primary)]\"\n }`}\n >\n <span>{label}</span>\n <span className=\"font-medium\">{value}</span>\n </div>\n);\n\nexport const Default: Story = {\n render: () => <InvoiceLayout invoice={paidInvoice} />,\n parameters: {\n controls: { disable: true },\n },\n};\n\nexport const Overdue: Story = {\n render: () => <InvoiceLayout invoice={overdueInvoice} />,\n parameters: {\n controls: { disable: true },\n },\n};"
11122
11618
  },
11123
11619
  {
11124
11620
  "name": "MailComposerLayout",
@@ -11136,7 +11632,7 @@
11136
11632
  "Tag",
11137
11633
  "Tooltip"
11138
11634
  ],
11139
- "source": "import React, { useState } from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Button,\n Card,\n Dropdown,\n Icon,\n Kbd,\n Separator,\n Tag,\n Tooltip,\n} from \"../../components/core\";\nimport type { FileTypeName } from \"../../components/core\";\nimport { RichTextEditor } from \"../../components/forms\";\nimport {\n PaperAirplaneIcon,\n PaperClipIcon,\n PhotoIcon,\n LinkIcon,\n FaceSmileIcon,\n TrashIcon,\n ChevronDownIcon,\n XMarkIcon,\n ClockIcon,\n} from \"@heroicons/react/24/outline\";\n\nconst meta: Meta = {\n title: \"Blocks/MailComposerLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\ntype Recipient = { name: string; email: string; src?: string };\n\nconst sender = {\n name: \"Sarah Chen\",\n email: \"sarah@flikkui.com\",\n src: \"https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst altAccount = {\n name: \"Sarah Chen\",\n email: \"sarah@personal.com\",\n src: \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst initialRecipients: Recipient[] = [\n {\n name: \"James Wilson\",\n email: \"james@acme.co\",\n src: \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n },\n {\n name: \"Emily Rodriguez\",\n email: \"emily@acme.co\",\n src: \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n },\n];\n\nconst initialAttachments: { name: string; size: string }[] = [\n { name: \"Q4-Roadmap-2026.pdf\", size: \"2.4 MB\" },\n { name: \"timeline-chart.png\", size: \"340 KB\" },\n];\n\nconst SUPPORTED_FILE_TYPES: FileTypeName[] = [\n \"pdf\", \"doc\", \"docx\", \"txt\", \"xls\", \"xlsx\", \"csv\", \"ppt\",\n \"mp3\", \"wav\", \"mp4\", \"mov\", \"jpg\", \"png\", \"svg\", \"gif\", \"zip\", \"rar\",\n];\n\nconst fileTypeFromName = (name: string): FileTypeName | null => {\n const ext = name.split(\".\").pop()?.toLowerCase();\n if (ext && (SUPPORTED_FILE_TYPES as string[]).includes(ext)) {\n return ext as FileTypeName;\n }\n return null;\n};\n\nconst initialBody = `<p>Hi James and Emily,</p>\n<p>I've finalized the Q4 product roadmap based on our discussion last week. Here are the key priorities:</p>\n<ol>\n <li>AI Components — New chat interface suite (MessageHistory, PromptInput, CodeBlock)</li>\n <li>Dark Mode — Full theming support across all 50+ components</li>\n <li>Performance — Target 40% bundle size reduction with tree-shaking</li>\n <li>Charts v2 — Simplified API with CSS variable theming</li>\n</ol>\n<p>I've attached the detailed document with timelines and resource allocation. Please review and share any feedback by Friday.</p>\n<p>Let me know if we need to schedule a follow-up meeting.</p>\n<p>Best,<br/>Sarah</p>`;\n\nconst MailComposer: React.FC = () => {\n const [recipients, setRecipients] = useState<Recipient[]>(initialRecipients);\n const [recipientInput, setRecipientInput] = useState(\"\");\n const [subject, setSubject] = useState(\n \"Q4 Product Roadmap — Review & Feedback\",\n );\n const [body, setBody] = useState(initialBody);\n const [attachments, setAttachments] = useState(initialAttachments);\n\n const addRecipient = (raw: string) => {\n const value = raw.trim().replace(/[,;]$/, \"\").trim();\n if (!value) return;\n if (recipients.some((r) => r.email === value || r.name === value)) return;\n const name = value.includes(\"@\") ? value.split(\"@\")[0] : value;\n setRecipients([\n ...recipients,\n { name, email: value.includes(\"@\") ? value : `${name}@example.com` },\n ]);\n setRecipientInput(\"\");\n };\n\n const removeRecipient = (email: string) => {\n setRecipients(recipients.filter((r) => r.email !== email));\n };\n\n const handleRecipientKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" || e.key === \",\" || e.key === \"Tab\") {\n if (recipientInput.trim()) {\n e.preventDefault();\n addRecipient(recipientInput);\n }\n } else if (\n e.key === \"Backspace\" &&\n recipientInput === \"\" &&\n recipients.length > 0\n ) {\n e.preventDefault();\n setRecipients(recipients.slice(0, -1));\n }\n };\n\n const totalSize =\n attachments.length > 0\n ? `${attachments.length} attachment${attachments.length === 1 ? \"\" : \"s\"}`\n : \"\";\n\n return (\n <div className=\"min-h-screen bg-[var(--color-background)] flex items-center justify-center p-4 sm:p-8\">\n <Card className=\"w-full max-w-2xl rounded-2xl shadow-xl shadow-black/[0.06] overflow-hidden\">\n {/* Header — sender + status + window controls */}\n <div className=\"flex items-center justify-between gap-4 px-5 sm:px-6 py-4 border-b border-[var(--color-border)]\">\n <Dropdown placement=\"bottom-start\">\n <Dropdown.Trigger>\n <button\n type=\"button\"\n className=\"group flex items-center gap-3 -ml-1 px-1 py-1 rounded-lg hover:bg-[var(--color-surface-hover)] transition-colors\"\n >\n <Avatar src={sender.src} name={sender.name} size=\"sm\" />\n <div className=\"flex flex-col items-start leading-tight\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)]\">\n From\n </span>\n <span className=\"flex items-center gap-1 text-sm font-medium text-[var(--color-text-primary)]\">\n {sender.email}\n <ChevronDownIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n </span>\n </div>\n </button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Select sending account\"\n className=\"min-w-[220px]\"\n >\n <Dropdown.Item\n itemKey=\"work\"\n startContent={\n <Avatar src={sender.src} name={sender.name} size=\"xs\" />\n }\n >\n {sender.email}\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"personal\"\n startContent={\n <Avatar\n src={altAccount.src}\n name={altAccount.name}\n size=\"xs\"\n />\n }\n >\n {altAccount.email}\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n\n <div className=\"flex items-center gap-3\">\n <span className=\"hidden sm:inline-flex items-center gap-1.5 text-xs text-[var(--color-text-muted)]\">\n <span className=\"size-1.5 rounded-full bg-[var(--color-success)]\" />\n Saved · just now\n </span>\n <div className=\"flex items-center gap-1\">\n <Tooltip content=\"Minimize\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <ChevronDownIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Discard\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <XMarkIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n </div>\n </div>\n\n {/* Recipients */}\n <div className=\"flex items-start gap-3 px-5 sm:px-6 py-2.5 border-b border-[var(--color-border)]\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)] flex-shrink-0 pt-1.5\">\n To\n </span>\n <div className=\"flex-1 flex items-center gap-1.5 flex-wrap min-h-[28px]\">\n {recipients.map((person) => (\n <Tag\n key={person.email}\n avatar={\n person.src\n ? { src: person.src, name: person.name }\n : { name: person.name }\n }\n onRemove={() => removeRecipient(person.email)}\n >\n {person.name}\n </Tag>\n ))}\n <input\n type=\"email\"\n value={recipientInput}\n onChange={(e) => setRecipientInput(e.target.value)}\n onKeyDown={handleRecipientKey}\n onBlur={() =>\n recipientInput.trim() && addRecipient(recipientInput)\n }\n placeholder={\n recipients.length === 0\n ? \"name@company.com\"\n : \"Add recipient…\"\n }\n aria-label=\"Add recipient\"\n className=\"flex-1 min-w-[140px] py-1 bg-transparent outline-none text-sm text-[var(--color-text-primary)] placeholder:text-[var(--color-text-placeholder)]\"\n />\n </div>\n <Dropdown placement=\"bottom-end\">\n <Dropdown.Trigger>\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\">\n Cc/Bcc\n <ChevronDownIcon className=\"size-3.5\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Add recipient fields\"\n className=\"min-w-[180px]\"\n >\n <Dropdown.Item itemKey=\"cc\">Add Cc</Dropdown.Item>\n <Dropdown.Item itemKey=\"bcc\">Add Bcc</Dropdown.Item>\n <Dropdown.Item itemKey=\"reply-to\">Set Reply-To</Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n </div>\n\n {/* Subject */}\n <div className=\"flex items-center gap-3 px-5 sm:px-6 py-2.5 border-b border-[var(--color-border)]\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)] flex-shrink-0\">\n Subject\n </span>\n <input\n type=\"text\"\n value={subject}\n onChange={(e) => setSubject(e.target.value)}\n placeholder=\"What is this about?\"\n aria-label=\"Subject\"\n className=\"flex-1 bg-transparent outline-none text-sm font-medium text-[var(--color-text-primary)] placeholder:text-[var(--color-text-placeholder)]\"\n />\n </div>\n\n {/* Body — RichTextEditor with floating toolbar */}\n <div className=\"px-5 sm:px-6 py-3\">\n <RichTextEditor\n value={body}\n onChange={setBody}\n placeholder=\"Write your message…\"\n minHeight={280}\n maxHeight={420}\n toolbar={{\n position: \"floating\",\n tools: [\n \"bold\",\n \"italic\",\n \"underline\",\n \"separator\",\n \"alignLeft\",\n \"alignCenter\",\n \"alignRight\",\n \"separator\",\n \"textColor\",\n ],\n }}\n theme={{\n wrapperStyle:\n \"w-full text-[15px] leading-7 text-[var(--color-text-primary)]\",\n containerStyle: \"border-0 shadow-none bg-transparent p-0\",\n editorStyle: [\n \"min-h-[280px] outline-none focus:outline-none px-0 py-0 overflow-y-auto\",\n \"[&_p]:my-3 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0\",\n \"[&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:my-3 [&_ol]:space-y-1\",\n \"[&_ul]:list-disc [&_ul]:pl-6 [&_ul]:my-3 [&_ul]:space-y-1\",\n \"[&_li]:leading-7\",\n \"[&_strong]:font-semibold [&_em]:italic [&_u]:underline\",\n \"[&_a]:text-[var(--color-primary)] [&_a]:underline\",\n \"empty:before:content-[attr(data-placeholder)] empty:before:text-[var(--color-text-placeholder)] empty:before:pointer-events-none\",\n ].join(\" \"),\n }}\n />\n </div>\n\n {/* Attachments — refined inline chips (no sunken panel) */}\n {attachments.length > 0 && (\n <div className=\"px-5 sm:px-6 pb-4\">\n <div className=\"mb-2\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)]\">\n {totalSize}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {attachments.map(({ name, size }) => {\n const type = fileTypeFromName(name);\n return (\n <div\n key={name}\n className=\"group inline-flex items-center gap-2.5 px-1.5 py-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] hover:border-[var(--color-border-hover)] transition-all duration-300\"\n >\n <span className=\"flex items-center justify-center size-8 rounded-md\">\n {type ? (\n <Icon icon={type} size=\"md\" />\n ) : (\n <PaperClipIcon className=\"size-4 text-[var(--color-text-muted)]\" />\n )}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-xs font-medium text-[var(--color-text-primary)] max-w-[200px] truncate\">\n {name}\n </span>\n <span className=\"text-[11px] text-[var(--color-text-muted)]\">\n {size}\n </span>\n </span>\n <button\n type=\"button\"\n aria-label={`Remove ${name}`}\n onClick={() =>\n setAttachments(attachments.filter((a) => a.name !== name))\n }\n className=\"flex items-center justify-center size-6 rounded-md text-[var(--color-text-muted)] opacity-0 group-hover:opacity-100 hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] transition-all\"\n >\n <XMarkIcon className=\"size-4\" />\n </button>\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* Footer toolbar */}\n <div className=\"flex items-center justify-between gap-3 px-5 sm:px-6 py-3 border-t border-[var(--color-border)]\">\n <div className=\"flex items-center gap-0.5\">\n <Tooltip content=\"Attach file\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <PaperClipIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Insert image\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <PhotoIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Separator vertical margin=\"sm\" className=\"h-5\" />\n <Tooltip content=\"Insert link\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <LinkIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Insert emoji\">\n <Button variant=\"ghost\" color=\"neutral\" size=\"sm\" iconOnly>\n <FaceSmileIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Tooltip content=\"Discard draft\">\n <Button variant=\"ghost\" color=\"danger\" size=\"sm\" iconOnly>\n <TrashIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n\n {/* Schedule — its own button + dropdown (Superhuman pattern) */}\n <Dropdown placement=\"top-end\">\n <Dropdown.Trigger>\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"md\"\n aria-label=\"Schedule send\"\n >\n <ClockIcon className=\"size-4\" />\n <ChevronDownIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Schedule send\"\n className=\"min-w-[240px]\"\n >\n <Dropdown.Item\n itemKey=\"tonight\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n 9:00 PM\n </span>\n }\n >\n Tonight\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"tomorrow\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n Tomorrow, 8:00 AM\n </span>\n }\n >\n Tomorrow morning\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"monday\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n Mon, 9:00 AM\n </span>\n }\n >\n Next week\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"custom\"\n startContent={<ClockIcon className=\"size-4\" />}\n >\n Pick date & time…\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n\n {/* Send — single primary action */}\n <Tooltip\n content={\n <span className=\"inline-flex items-center gap-1.5\">\n Send\n <Kbd keys={[\"command\", \"enter\"]} />\n </span>\n }\n >\n <Button size=\"md\">\n <PaperAirplaneIcon className=\"size-4\" /> Send\n </Button>\n </Tooltip>\n </div>\n </div>\n </Card>\n </div>\n );\n};\n\nexport const Default: Story = {\n render: () => <MailComposer />,\n parameters: {\n controls: { disable: true },\n },\n};"
11635
+ "source": "import React, { useState } from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Button,\n Card,\n Dropdown,\n Icon,\n Kbd,\n Separator,\n Tag,\n Tooltip,\n} from \"../../components/core\";\nimport type { FileTypeName } from \"../../components/core\";\nimport { RichTextEditor } from \"../../components/forms\";\nimport {\n PaperPlaneTilt as PaperAirplaneIcon,\n Paperclip as PaperClipIcon,\n Image as PhotoIcon,\n Link as LinkIcon,\n Smiley as FaceSmileIcon,\n Trash as TrashIcon,\n CaretDown as ChevronDownIcon,\n X as XMarkIcon,\n Clock as ClockIcon,\n} from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/MailComposerLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\ntype Recipient = { name: string; email: string; src?: string };\n\nconst sender = {\n name: \"Sarah Chen\",\n email: \"sarah@flikkui.com\",\n src: \"https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst altAccount = {\n name: \"Sarah Chen\",\n email: \"sarah@personal.com\",\n src: \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n};\n\nconst initialRecipients: Recipient[] = [\n {\n name: \"James Wilson\",\n email: \"james@acme.co\",\n src: \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n },\n {\n name: \"Emily Rodriguez\",\n email: \"emily@acme.co\",\n src: \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n },\n];\n\nconst initialAttachments: { name: string; size: string }[] = [\n { name: \"Q4-Roadmap-2026.pdf\", size: \"2.4 MB\" },\n { name: \"timeline-chart.png\", size: \"340 KB\" },\n];\n\nconst SUPPORTED_FILE_TYPES: FileTypeName[] = [\n \"pdf\", \"doc\", \"docx\", \"txt\", \"xls\", \"xlsx\", \"csv\", \"ppt\",\n \"mp3\", \"wav\", \"mp4\", \"mov\", \"jpg\", \"png\", \"svg\", \"gif\", \"zip\", \"rar\",\n];\n\nconst fileTypeFromName = (name: string): FileTypeName | null => {\n const ext = name.split(\".\").pop()?.toLowerCase();\n if (ext && (SUPPORTED_FILE_TYPES as string[]).includes(ext)) {\n return ext as FileTypeName;\n }\n return null;\n};\n\nconst initialBody = `<p>Hi James and Emily,</p>\n<p>I've finalized the Q4 product roadmap based on our discussion last week. Here are the key priorities:</p>\n<ol>\n <li>AI Components — New chat interface suite (MessageHistory, PromptInput, CodeBlock)</li>\n <li>Dark Mode — Full theming support across all 50+ components</li>\n <li>Performance — Target 40% bundle size reduction with tree-shaking</li>\n <li>Charts v2 — Simplified API with CSS variable theming</li>\n</ol>\n<p>I've attached the detailed document with timelines and resource allocation. Please review and share any feedback by Friday.</p>\n<p>Let me know if we need to schedule a follow-up meeting.</p>\n<p>Best,<br/>Sarah</p>`;\n\nconst MailComposer: React.FC = () => {\n const [recipients, setRecipients] = useState<Recipient[]>(initialRecipients);\n const [recipientInput, setRecipientInput] = useState(\"\");\n const [subject, setSubject] = useState(\n \"Q4 Product Roadmap — Review & Feedback\",\n );\n const [body, setBody] = useState(initialBody);\n const [attachments, setAttachments] = useState(initialAttachments);\n\n const addRecipient = (raw: string) => {\n const value = raw.trim().replace(/[,;]$/, \"\").trim();\n if (!value) return;\n if (recipients.some((r) => r.email === value || r.name === value)) return;\n const name = value.includes(\"@\") ? value.split(\"@\")[0] : value;\n setRecipients([\n ...recipients,\n { name, email: value.includes(\"@\") ? value : `${name}@example.com` },\n ]);\n setRecipientInput(\"\");\n };\n\n const removeRecipient = (email: string) => {\n setRecipients(recipients.filter((r) => r.email !== email));\n };\n\n const handleRecipientKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" || e.key === \",\" || e.key === \"Tab\") {\n if (recipientInput.trim()) {\n e.preventDefault();\n addRecipient(recipientInput);\n }\n } else if (\n e.key === \"Backspace\" &&\n recipientInput === \"\" &&\n recipients.length > 0\n ) {\n e.preventDefault();\n setRecipients(recipients.slice(0, -1));\n }\n };\n\n const totalSize =\n attachments.length > 0\n ? `${attachments.length} attachment${attachments.length === 1 ? \"\" : \"s\"}`\n : \"\";\n\n return (\n <div className=\"min-h-screen bg-[var(--color-background)] flex items-center justify-center p-4 sm:p-8\">\n <Card className=\"w-full max-w-2xl rounded-2xl shadow-xl shadow-black/[0.06] overflow-hidden\">\n {/* Header — sender + status + window controls */}\n <div className=\"flex items-center justify-between gap-4 px-5 sm:px-6 py-4 border-b border-[var(--color-border)]\">\n <Dropdown placement=\"bottom-start\">\n <Dropdown.Trigger>\n <button\n type=\"button\"\n className=\"group flex items-center gap-3 -ml-1 px-1 py-1 rounded-lg hover:bg-[var(--color-surface-hover)] transition-colors\"\n >\n <Avatar src={sender.src} name={sender.name} size=\"sm\" />\n <div className=\"flex flex-col items-start leading-tight\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)]\">\n From\n </span>\n <span className=\"flex items-center gap-1 text-sm font-medium text-[var(--color-text-primary)]\">\n {sender.email}\n <ChevronDownIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n </span>\n </div>\n </button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Select sending account\"\n className=\"min-w-[220px]\"\n >\n <Dropdown.Item\n itemKey=\"work\"\n startContent={\n <Avatar src={sender.src} name={sender.name} size=\"xs\" />\n }\n >\n {sender.email}\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"personal\"\n startContent={\n <Avatar\n src={altAccount.src}\n name={altAccount.name}\n size=\"xs\"\n />\n }\n >\n {altAccount.email}\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n\n <div className=\"flex items-center gap-3\">\n <span className=\"hidden sm:inline-flex items-center gap-1.5 text-xs text-[var(--color-text-muted)]\">\n <span className=\"size-1.5 rounded-full bg-[var(--color-success)]\" />\n Saved · just now\n </span>\n <div className=\"flex items-center gap-1\">\n <Tooltip content=\"Minimize\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <ChevronDownIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Discard\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <XMarkIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n </div>\n </div>\n\n {/* Recipients */}\n <div className=\"flex items-start gap-3 px-5 sm:px-6 py-2.5 border-b border-[var(--color-border)]\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)] flex-shrink-0 pt-1.5\">\n To\n </span>\n <div className=\"flex-1 flex items-center gap-1.5 flex-wrap min-h-[28px]\">\n {recipients.map((person) => (\n <Tag\n key={person.email}\n avatar={\n person.src\n ? { src: person.src, name: person.name }\n : { name: person.name }\n }\n onRemove={() => removeRecipient(person.email)}\n >\n {person.name}\n </Tag>\n ))}\n <input\n type=\"email\"\n value={recipientInput}\n onChange={(e) => setRecipientInput(e.target.value)}\n onKeyDown={handleRecipientKey}\n onBlur={() =>\n recipientInput.trim() && addRecipient(recipientInput)\n }\n placeholder={\n recipients.length === 0\n ? \"name@company.com\"\n : \"Add recipient…\"\n }\n aria-label=\"Add recipient\"\n className=\"flex-1 min-w-[140px] py-1 bg-transparent outline-none text-sm text-[var(--color-text-primary)] placeholder:text-[var(--color-text-placeholder)]\"\n />\n </div>\n <Dropdown placement=\"bottom-end\">\n <Dropdown.Trigger>\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\">\n Cc/Bcc\n <ChevronDownIcon className=\"size-3.5\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Add recipient fields\"\n className=\"min-w-[180px]\"\n >\n <Dropdown.Item itemKey=\"cc\">Add Cc</Dropdown.Item>\n <Dropdown.Item itemKey=\"bcc\">Add Bcc</Dropdown.Item>\n <Dropdown.Item itemKey=\"reply-to\">Set Reply-To</Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n </div>\n\n {/* Subject */}\n <div className=\"flex items-center gap-3 px-5 sm:px-6 py-2.5 border-b border-[var(--color-border)]\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)] flex-shrink-0\">\n Subject\n </span>\n <input\n type=\"text\"\n value={subject}\n onChange={(e) => setSubject(e.target.value)}\n placeholder=\"What is this about?\"\n aria-label=\"Subject\"\n className=\"flex-1 bg-transparent outline-none text-sm font-medium text-[var(--color-text-primary)] placeholder:text-[var(--color-text-placeholder)]\"\n />\n </div>\n\n {/* Body — RichTextEditor with floating toolbar */}\n <div className=\"px-5 sm:px-6 py-3\">\n <RichTextEditor\n value={body}\n onChange={setBody}\n placeholder=\"Write your message…\"\n minHeight={280}\n maxHeight={420}\n toolbar={{\n position: \"floating\",\n tools: [\n \"bold\",\n \"italic\",\n \"underline\",\n \"separator\",\n \"alignLeft\",\n \"alignCenter\",\n \"alignRight\",\n \"separator\",\n \"textColor\",\n ],\n }}\n theme={{\n wrapperStyle:\n \"w-full text-[15px] leading-7 text-[var(--color-text-primary)]\",\n containerStyle: \"border-0 shadow-none bg-transparent p-0\",\n editorStyle: [\n \"min-h-[280px] outline-none focus:outline-none px-0 py-0 overflow-y-auto\",\n \"[&_p]:my-3 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0\",\n \"[&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:my-3 [&_ol]:space-y-1\",\n \"[&_ul]:list-disc [&_ul]:pl-6 [&_ul]:my-3 [&_ul]:space-y-1\",\n \"[&_li]:leading-7\",\n \"[&_strong]:font-semibold [&_em]:italic [&_u]:underline\",\n \"[&_a]:text-[var(--color-primary)] [&_a]:underline\",\n \"empty:before:content-[attr(data-placeholder)] empty:before:text-[var(--color-text-placeholder)] empty:before:pointer-events-none\",\n ].join(\" \"),\n }}\n />\n </div>\n\n {/* Attachments — refined inline chips (no sunken panel) */}\n {attachments.length > 0 && (\n <div className=\"px-5 sm:px-6 pb-4\">\n <div className=\"mb-2\">\n <span className=\"text-[11px] tracking-wider uppercase text-[var(--color-text-muted)]\">\n {totalSize}\n </span>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {attachments.map(({ name, size }) => {\n const type = fileTypeFromName(name);\n return (\n <div\n key={name}\n className=\"group inline-flex items-center gap-2.5 px-1.5 py-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] hover:border-[var(--color-border-hover)] transition-all duration-300\"\n >\n <span className=\"flex items-center justify-center size-8 rounded-md\">\n {type ? (\n <Icon icon={type} size=\"md\" />\n ) : (\n <PaperClipIcon className=\"size-4 text-[var(--color-text-muted)]\" />\n )}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-xs font-medium text-[var(--color-text-primary)] max-w-[200px] truncate\">\n {name}\n </span>\n <span className=\"text-[11px] text-[var(--color-text-muted)]\">\n {size}\n </span>\n </span>\n <button\n type=\"button\"\n aria-label={`Remove ${name}`}\n onClick={() =>\n setAttachments(attachments.filter((a) => a.name !== name))\n }\n className=\"flex items-center justify-center size-6 rounded-md text-[var(--color-text-muted)] opacity-0 group-hover:opacity-100 hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] transition-all\"\n >\n <XMarkIcon className=\"size-4\" />\n </button>\n </div>\n );\n })}\n </div>\n </div>\n )}\n\n {/* Footer toolbar */}\n <div className=\"flex items-center justify-between gap-3 px-5 sm:px-6 py-3 border-t border-[var(--color-border)]\">\n <div className=\"flex items-center gap-0.5\">\n <Tooltip content=\"Attach file\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <PaperClipIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Insert image\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <PhotoIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Separator vertical margin=\"sm\" className=\"h-5\" />\n <Tooltip content=\"Insert link\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <LinkIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n <Tooltip content=\"Insert emoji\">\n <Button variant=\"ghost\" color=\"mono\" size=\"sm\" iconOnly>\n <FaceSmileIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Tooltip content=\"Discard draft\">\n <Button variant=\"ghost\" color=\"danger\" size=\"sm\" iconOnly>\n <TrashIcon className=\"size-4\" />\n </Button>\n </Tooltip>\n\n {/* Schedule — its own button + dropdown (Superhuman pattern) */}\n <Dropdown placement=\"top-end\">\n <Dropdown.Trigger>\n <Button\n variant=\"outline\"\n color=\"mono\"\n size=\"md\"\n aria-label=\"Schedule send\"\n >\n <ClockIcon className=\"size-4\" />\n <ChevronDownIcon className=\"size-3.5 text-[var(--color-text-muted)]\" />\n </Button>\n </Dropdown.Trigger>\n <Dropdown.Menu\n aria-label=\"Schedule send\"\n className=\"min-w-[240px]\"\n >\n <Dropdown.Item\n itemKey=\"tonight\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n 9:00 PM\n </span>\n }\n >\n Tonight\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"tomorrow\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n Tomorrow, 8:00 AM\n </span>\n }\n >\n Tomorrow morning\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"monday\"\n endContent={\n <span className=\"text-xs text-[var(--color-text-muted)]\">\n Mon, 9:00 AM\n </span>\n }\n >\n Next week\n </Dropdown.Item>\n <Dropdown.Item\n itemKey=\"custom\"\n startContent={<ClockIcon className=\"size-4\" />}\n >\n Pick date & time…\n </Dropdown.Item>\n </Dropdown.Menu>\n </Dropdown>\n\n {/* Send — single primary action */}\n <Tooltip\n content={\n <span className=\"inline-flex items-center gap-1.5\">\n Send\n <Kbd keys={[\"command\", \"enter\"]} />\n </span>\n }\n >\n <Button size=\"md\">\n <PaperAirplaneIcon className=\"size-4\" /> Send\n </Button>\n </Tooltip>\n </div>\n </div>\n </Card>\n </div>\n );\n};\n\nexport const Default: Story = {\n render: () => <MailComposer />,\n parameters: {\n controls: { disable: true },\n },\n};"
11140
11636
  },
11141
11637
  {
11142
11638
  "name": "MediaGalleryLayout",
@@ -11150,7 +11646,23 @@
11150
11646
  "Segmented",
11151
11647
  "Tooltip"
11152
11648
  ],
11153
- "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Button,\n Masonry,\n Segmented,\n Tooltip,\n} from \"../../components/core\";\nimport { Input } from \"../../components/forms\";\nimport { cn } from \"../../utils\";\nimport {\n MagnifyingGlassIcon,\n ArrowUpTrayIcon,\n HeartIcon,\n ArrowDownTrayIcon,\n EyeIcon,\n} from \"@heroicons/react/24/outline\";\nimport { HeartIcon as HeartSolidIcon } from \"@heroicons/react/24/solid\";\n\nconst meta: Meta = {\n title: \"Blocks/MediaGalleryLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Gallery items with varied heights ---\n\ntype GalleryItem = {\n id: string;\n src: string;\n title: string;\n author: string;\n avatar: string;\n likes: number;\n views: string;\n liked: boolean;\n heightClassName: string;\n};\n\nconst galleryItems: GalleryItem[] = [\n {\n id: \"1\",\n src: \"https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&h=400&fit=crop\",\n title: \"Mountain Sunrise\",\n author: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n likes: 342,\n views: \"2.1k\",\n liked: true,\n heightClassName: \"h-48 sm:h-56\",\n },\n {\n id: \"2\",\n src: \"https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&h=800&fit=crop\",\n title: \"Misty Forest\",\n author: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n likes: 218,\n views: \"1.4k\",\n liked: false,\n heightClassName: \"h-64 sm:h-80\",\n },\n {\n id: \"3\",\n src: \"https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=600&h=400&fit=crop\",\n title: \"Ocean Waves\",\n author: \"Emily Rodriguez\",\n avatar:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n likes: 567,\n views: \"3.8k\",\n liked: true,\n heightClassName: \"h-48 sm:h-52\",\n },\n {\n id: \"4\",\n src: \"https://images.unsplash.com/photo-1501854140801-50d01698950b?w=600&h=600&fit=crop\",\n title: \"Autumn Valley\",\n author: \"David Kim\",\n avatar:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n likes: 891,\n views: \"5.2k\",\n liked: false,\n heightClassName: \"h-56 sm:h-64\",\n },\n {\n id: \"5\",\n src: \"https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=600&h=400&fit=crop\",\n title: \"Sunlit Meadow\",\n author: \"Lisa Thompson\",\n avatar:\n \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n likes: 156,\n views: \"890\",\n liked: false,\n heightClassName: \"h-44 sm:h-48\",\n },\n {\n id: \"6\",\n src: \"https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=600&h=700&fit=crop\",\n title: \"Northern Lights\",\n author: \"Alex Rivera\",\n avatar:\n \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n likes: 1203,\n views: \"8.4k\",\n liked: true,\n heightClassName: \"h-60 sm:h-72\",\n },\n {\n id: \"7\",\n src: \"https://images.unsplash.com/photo-1473580044384-7ba9967e16a0?w=600&h=400&fit=crop\",\n title: \"Desert Dunes\",\n author: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n likes: 445,\n views: \"2.9k\",\n liked: false,\n heightClassName: \"h-48 sm:h-56\",\n },\n {\n id: \"8\",\n src: \"https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=600&h=500&fit=crop\",\n title: \"Spring Bloom\",\n author: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n likes: 312,\n views: \"1.7k\",\n liked: true,\n heightClassName: \"h-52 sm:h-60\",\n },\n];\n\nconst galleryColumns = { 640: 1, 768: 2, 1024: 3, 1280: 4 };\nconst noop = () => undefined;\n\ntype GalleryActionButtonProps = {\n label: string;\n delayClassName?: string;\n children: React.ReactNode;\n};\n\nconst GalleryActionButton = ({\n label,\n delayClassName,\n children,\n}: GalleryActionButtonProps) => (\n <Tooltip content={label}>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex size-8 translate-y-2 scale-95 items-center justify-center rounded-full bg-white/20 text-white opacity-0 backdrop-blur-sm transition-[opacity,transform,background-color] duration-300 ease-out hover:bg-white/30 focus:outline-none focus:ring-2 focus:ring-white/70 group-hover:translate-y-0 group-hover:scale-100 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:scale-100 group-focus-within:opacity-100\",\n delayClassName,\n )}\n >\n {children}\n </button>\n </Tooltip>\n);\n\nconst GalleryCard = ({ item }: { item: GalleryItem }) => (\n <article className=\"group relative overflow-hidden rounded-lg bg-[var(--color-background-tertiary)]\">\n <div className={cn(item.heightClassName, \"overflow-hidden\")}>\n <img\n src={item.src}\n alt={item.title}\n loading=\"lazy\"\n decoding=\"async\"\n className=\"h-full w-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n </div>\n\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/65 via-black/10 to-transparent opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-within:opacity-100\">\n <div className=\"absolute right-3 top-3 flex gap-2\">\n <GalleryActionButton\n label={item.liked ? \"Unlike\" : \"Like\"}\n delayClassName=\"delay-75\"\n >\n {item.liked ? (\n <HeartSolidIcon className=\"size-4 text-red-400\" />\n ) : (\n <HeartIcon className=\"size-4\" />\n )}\n </GalleryActionButton>\n <GalleryActionButton\n label={`Download ${item.title}`}\n delayClassName=\"delay-150\"\n >\n <ArrowDownTrayIcon className=\"size-4\" />\n </GalleryActionButton>\n </div>\n\n <div className=\"absolute inset-x-0 bottom-0 p-4\">\n <h3 className=\"translate-y-3 truncate text-sm font-medium text-white opacity-0 transition-[opacity,transform] delay-100 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n {item.title}\n </h3>\n <div className=\"mt-2 flex items-center justify-between gap-3\">\n <div className=\"flex min-w-0 translate-y-3 items-center gap-2 opacity-0 transition-[opacity,transform] delay-150 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n <Avatar src={item.avatar} name={item.author} size=\"xs\" />\n <span className=\"truncate text-xs text-white/80\">\n {item.author}\n </span>\n </div>\n <div className=\"flex shrink-0 translate-y-3 items-center gap-3 text-xs text-white/70 opacity-0 transition-[opacity,transform] delay-200 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n <span className=\"flex items-center gap-1\">\n <HeartIcon className=\"size-3\" aria-hidden=\"true\" />\n {item.likes}\n </span>\n <span className=\"flex items-center gap-1\">\n <EyeIcon className=\"size-3\" aria-hidden=\"true\" />\n {item.views}\n </span>\n </div>\n </div>\n </div>\n </div>\n </article>\n);\n\nexport const Default: Story = {\n render: () => (\n <div className=\"min-h-screen bg-[var(--color-background)]\">\n {/* Header */}\n <div className=\"sticky top-0 z-10 bg-[var(--color-background)]/80 backdrop-blur-md border-b border-[var(--color-border)]\">\n <div className=\"max-w-7xl mx-auto px-4 sm:px-6 py-4\">\n <div className=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n <div className=\"shrink-0\">\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n Gallery\n </h1>\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Explore the community collection\n </p>\n </div>\n <div className=\"flex min-w-0 flex-col gap-3 sm:flex-row sm:items-center md:flex-1 md:justify-end\">\n <Input\n placeholder=\"Search...\"\n iconStart={<MagnifyingGlassIcon className=\"size-4\" />}\n size=\"sm\"\n className=\"w-full sm:w-56 lg:w-72 xl:w-96\"\n />\n <Segmented value=\"all\" onChange={noop} size=\"sm\">\n <Segmented.Item value=\"all\">All</Segmented.Item>\n <Segmented.Item value=\"photos\">Photos</Segmented.Item>\n <Segmented.Item value=\"videos\">Videos</Segmented.Item>\n </Segmented>\n <Button size=\"sm\" className=\"w-full shrink-0 sm:w-auto\">\n <ArrowUpTrayIcon className=\"size-4\" /> Upload\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Gallery grid */}\n <div className=\"max-w-7xl mx-auto px-4 sm:px-6 py-6\">\n <Masonry columns={galleryColumns} gap={16}>\n {galleryItems.map((item) => (\n <GalleryCard key={item.id} item={item} />\n ))}\n </Masonry>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11649
+ "source": "import React from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport {\n Avatar,\n Button,\n Masonry,\n Segmented,\n Tooltip,\n} from \"../../components/core\";\nimport { Input } from \"../../components/forms\";\nimport { cn } from \"../../utils\";\nimport {\n MagnifyingGlass as MagnifyingGlassIcon,\n UploadSimple as ArrowUpTrayIcon,\n Heart as HeartIcon,\n DownloadSimple as ArrowDownTrayIcon,\n Eye as EyeIcon,\n Heart as HeartSolidIcon,\n} from \"@phosphor-icons/react\";\n\nconst meta: Meta = {\n title: \"Blocks/MediaGalleryLayout\",\n parameters: { layout: \"fullscreen\" },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// --- Gallery items with varied heights ---\n\ntype GalleryItem = {\n id: string;\n src: string;\n title: string;\n author: string;\n avatar: string;\n likes: number;\n views: string;\n liked: boolean;\n heightClassName: string;\n};\n\nconst galleryItems: GalleryItem[] = [\n {\n id: \"1\",\n src: \"https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&h=400&fit=crop\",\n title: \"Mountain Sunrise\",\n author: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n likes: 342,\n views: \"2.1k\",\n liked: true,\n heightClassName: \"h-48 sm:h-56\",\n },\n {\n id: \"2\",\n src: \"https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&h=800&fit=crop\",\n title: \"Misty Forest\",\n author: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n likes: 218,\n views: \"1.4k\",\n liked: false,\n heightClassName: \"h-64 sm:h-80\",\n },\n {\n id: \"3\",\n src: \"https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=600&h=400&fit=crop\",\n title: \"Ocean Waves\",\n author: \"Emily Rodriguez\",\n avatar:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=80&h=80&fit=crop&crop=face\",\n likes: 567,\n views: \"3.8k\",\n liked: true,\n heightClassName: \"h-48 sm:h-52\",\n },\n {\n id: \"4\",\n src: \"https://images.unsplash.com/photo-1501854140801-50d01698950b?w=600&h=600&fit=crop\",\n title: \"Autumn Valley\",\n author: \"David Kim\",\n avatar:\n \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face\",\n likes: 891,\n views: \"5.2k\",\n liked: false,\n heightClassName: \"h-56 sm:h-64\",\n },\n {\n id: \"5\",\n src: \"https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=600&h=400&fit=crop\",\n title: \"Sunlit Meadow\",\n author: \"Lisa Thompson\",\n avatar:\n \"https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face\",\n likes: 156,\n views: \"890\",\n liked: false,\n heightClassName: \"h-44 sm:h-48\",\n },\n {\n id: \"6\",\n src: \"https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=600&h=700&fit=crop\",\n title: \"Northern Lights\",\n author: \"Alex Rivera\",\n avatar:\n \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face\",\n likes: 1203,\n views: \"8.4k\",\n liked: true,\n heightClassName: \"h-60 sm:h-72\",\n },\n {\n id: \"7\",\n src: \"https://images.unsplash.com/photo-1473580044384-7ba9967e16a0?w=600&h=400&fit=crop\",\n title: \"Desert Dunes\",\n author: \"Sarah Chen\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face\",\n likes: 445,\n views: \"2.9k\",\n liked: false,\n heightClassName: \"h-48 sm:h-56\",\n },\n {\n id: \"8\",\n src: \"https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=600&h=500&fit=crop\",\n title: \"Spring Bloom\",\n author: \"James Wilson\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face\",\n likes: 312,\n views: \"1.7k\",\n liked: true,\n heightClassName: \"h-52 sm:h-60\",\n },\n];\n\nconst galleryColumns = { 640: 1, 768: 2, 1024: 3, 1280: 4 };\nconst noop = () => undefined;\n\ntype GalleryActionButtonProps = {\n label: string;\n delayClassName?: string;\n children: React.ReactNode;\n};\n\nconst GalleryActionButton = ({\n label,\n delayClassName,\n children,\n}: GalleryActionButtonProps) => (\n <Tooltip content={label}>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex size-8 translate-y-2 scale-95 items-center justify-center rounded-full bg-white/20 text-white opacity-0 backdrop-blur-sm transition-[opacity,transform,background-color] duration-300 ease-out hover:bg-white/30 focus:outline-none focus:ring-2 focus:ring-white/70 group-hover:translate-y-0 group-hover:scale-100 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:scale-100 group-focus-within:opacity-100\",\n delayClassName,\n )}\n >\n {children}\n </button>\n </Tooltip>\n);\n\nconst GalleryCard = ({ item }: { item: GalleryItem }) => (\n <article className=\"group relative overflow-hidden rounded-lg bg-[var(--color-background-tertiary)]\">\n <div className={cn(item.heightClassName, \"overflow-hidden\")}>\n <img\n src={item.src}\n alt={item.title}\n loading=\"lazy\"\n decoding=\"async\"\n className=\"h-full w-full object-cover transition-transform duration-300 group-hover:scale-105\"\n />\n </div>\n\n <div className=\"absolute inset-0 bg-gradient-to-t from-black/65 via-black/10 to-transparent opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-within:opacity-100\">\n <div className=\"absolute right-3 top-3 flex gap-2\">\n <GalleryActionButton\n label={item.liked ? \"Unlike\" : \"Like\"}\n delayClassName=\"delay-75\"\n >\n {item.liked ? (\n <HeartSolidIcon className=\"size-4 text-red-400\" />\n ) : (\n <HeartIcon className=\"size-4\" />\n )}\n </GalleryActionButton>\n <GalleryActionButton\n label={`Download ${item.title}`}\n delayClassName=\"delay-150\"\n >\n <ArrowDownTrayIcon className=\"size-4\" />\n </GalleryActionButton>\n </div>\n\n <div className=\"absolute inset-x-0 bottom-0 p-4\">\n <h3 className=\"translate-y-3 truncate text-sm font-medium text-white opacity-0 transition-[opacity,transform] delay-100 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n {item.title}\n </h3>\n <div className=\"mt-2 flex items-center justify-between gap-3\">\n <div className=\"flex min-w-0 translate-y-3 items-center gap-2 opacity-0 transition-[opacity,transform] delay-150 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n <Avatar src={item.avatar} name={item.author} size=\"xs\" />\n <span className=\"truncate text-xs text-white/80\">\n {item.author}\n </span>\n </div>\n <div className=\"flex shrink-0 translate-y-3 items-center gap-3 text-xs text-white/70 opacity-0 transition-[opacity,transform] delay-200 duration-300 ease-out group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100\">\n <span className=\"flex items-center gap-1\">\n <HeartIcon className=\"size-3\" aria-hidden=\"true\" />\n {item.likes}\n </span>\n <span className=\"flex items-center gap-1\">\n <EyeIcon className=\"size-3\" aria-hidden=\"true\" />\n {item.views}\n </span>\n </div>\n </div>\n </div>\n </div>\n </article>\n);\n\nexport const Default: Story = {\n render: () => (\n <div className=\"min-h-screen bg-[var(--color-background)]\">\n {/* Header */}\n <div className=\"sticky top-0 z-10 bg-[var(--color-background)]/80 backdrop-blur-md border-b border-[var(--color-border)]\">\n <div className=\"max-w-7xl mx-auto px-4 sm:px-6 py-4\">\n <div className=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n <div className=\"shrink-0\">\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n Gallery\n </h1>\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n Explore the community collection\n </p>\n </div>\n <div className=\"flex min-w-0 flex-col gap-3 sm:flex-row sm:items-center md:flex-1 md:justify-end\">\n <Input\n placeholder=\"Search...\"\n iconStart={<MagnifyingGlassIcon className=\"size-4\" />}\n size=\"sm\"\n className=\"w-full sm:w-56 lg:w-72 xl:w-96\"\n />\n <Segmented value=\"all\" onChange={noop} size=\"sm\">\n <Segmented.Item value=\"all\">All</Segmented.Item>\n <Segmented.Item value=\"photos\">Photos</Segmented.Item>\n <Segmented.Item value=\"videos\">Videos</Segmented.Item>\n </Segmented>\n <Button size=\"sm\" className=\"w-full shrink-0 sm:w-auto\">\n <ArrowUpTrayIcon className=\"size-4\" /> Upload\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Gallery grid */}\n <div className=\"max-w-7xl mx-auto px-4 sm:px-6 py-6\">\n <Masonry columns={galleryColumns} gap={16}>\n {galleryItems.map((item) => (\n <GalleryCard key={item.id} item={item} />\n ))}\n </Masonry>\n </div>\n </div>\n ),\n parameters: {\n controls: { disable: true },\n },\n};"
11650
+ },
11651
+ {
11652
+ "name": "MissionCardsLayout",
11653
+ "title": "Blocks/MissionCardsLayout",
11654
+ "description": "Full-page composition using AreaChart, AvatarGroup, Badge, Button, ….",
11655
+ "componentsUsed": [
11656
+ "AreaChart",
11657
+ "AvatarGroup",
11658
+ "Badge",
11659
+ "Button",
11660
+ "HeroCard",
11661
+ "Progress",
11662
+ "ScrollArea",
11663
+ "TiltCard"
11664
+ ],
11665
+ "source": "import type { Meta, StoryObj } from \"@storybook/react-webpack5\";\nimport { Badge, Button, HeroCard, ScrollArea, AvatarGroup, Progress } from \"../../components/core\";\nimport { AreaChart } from \"../../components/charts\";\nimport { TiltCard } from \"../../components/effects\";\n\nconst meta: Meta = {\n title: \"Blocks/MissionCardsLayout\",\n parameters: {\n layout: \"fullscreen\",\n },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nconst avatar = (img: number, name: string) => ({ src: `https://i.pravatar.cc/80?img=${img}`, name });\n\ntype Avatar = { src: string; name: string };\n\n// Each mission ends on a different \"stat\" footer so the deck reads as a dashboard,\n// not six identical team cards — progress, headline metric, ship date, open roles, team.\ntype MissionStat =\n | { kind: \"progress\"; label: string; value: number }\n | { kind: \"metric\"; value: string; label: string; delta?: string }\n | { kind: \"trend\"; value: string; label: string; delta?: string; data: { name: string; v: number }[] }\n | { kind: \"milestone\"; label: string; date: string; avatars: Avatar[] }\n | { kind: \"roles\"; label: string; open: number; avatars: Avatar[] }\n | { kind: \"team\"; members: string[]; avatars: Avatar[] };\n\ninterface Mission {\n title: string;\n blurb: string;\n gradient: string;\n image: string;\n status: { label: string; className: string };\n stat: MissionStat;\n}\n\nconst MISSIONS: Mission[] = [\n {\n title: \"Wiki\",\n blurb: \"One source of truth for every team doc.\",\n gradient: \"from-[#a87de8] via-[#b09ae4] to-[#a3cbe8]\",\n image: \"/bg/2.webp\",\n status: { label: \"On track\", className: \"bg-emerald-400/90 text-emerald-950\" },\n stat: { kind: \"progress\", label: \"Pages migrated\", value: 72 },\n },\n {\n title: \"Search\",\n blurb: \"Instant answers across every workspace.\",\n gradient: \"from-[#f44d62] via-[#ec3a2c] to-[#f8ab3d]\",\n image: \"/bg/5.webp\",\n status: { label: \"Hiring\", className: \"bg-white/90 text-neutral-900\" },\n stat: {\n kind: \"roles\",\n label: \"Backend engineers\",\n open: 2,\n avatars: [avatar(47, \"Lena Fischer\"), avatar(11, \"Tom Okafor\"), avatar(26, \"Priya Nair\"), avatar(59, \"Hugo Lindqvist\")],\n },\n },\n {\n title: \"Workflows\",\n blurb: \"No-code automations that run themselves.\",\n gradient: \"from-[#a9c6de] via-[#8fb2d2] to-[#7aa3c8]\",\n image: \"/bg/9.webp\",\n status: { label: \"New\", className: \"bg-white/90 text-neutral-900\" },\n stat: {\n kind: \"trend\",\n value: \"240\",\n label: \"automations live\",\n delta: \"+38 this week\",\n data: [\n { name: \"Wk 1\", v: 80 },\n { name: \"Wk 2\", v: 96 },\n { name: \"Wk 3\", v: 162 },\n { name: \"Wk 4\", v: 134 },\n { name: \"Wk 5\", v: 300 },\n { name: \"Wk 6\", v: 158 },\n { name: \"Wk 7\", v: 180 },\n { name: \"Wk 8\", v: 260 },\n ],\n },\n },\n {\n title: \"Assistant\",\n blurb: \"Your always-on AI teammate.\",\n gradient: \"from-[#8fd6bd] via-[#6fc3ad] to-[#5bb1a4]\",\n image: \"/bg/14.webp\",\n status: { label: \"Beta\", className: \"bg-amber-300/90 text-amber-950\" },\n stat: {\n kind: \"milestone\",\n label: \"GA release\",\n date: \"Apr 18\",\n avatars: [avatar(53, \"Noah Becker\"), avatar(32, \"Yuki Tanaka\"), avatar(15, \"Sam Whitfield\")],\n },\n },\n {\n title: \"Insights\",\n blurb: \"Live product analytics, zero setup.\",\n gradient: \"from-[#f4a6b8] via-[#ef8aa4] to-[#e8718f]\",\n image: \"/bg/17.webp\",\n status: { label: \"On track\", className: \"bg-emerald-400/90 text-emerald-950\" },\n stat: { kind: \"metric\", value: \"3.2M\", label: \"events tracked / day\", delta: \"+18% WoW\" },\n },\n {\n title: \"Mobile\",\n blurb: \"Flikk in your pocket — iOS & Android.\",\n gradient: \"from-[#f7c277] via-[#f2a45c] to-[#ec8552]\",\n image: \"/bg/21.webp\",\n status: { label: \"Q3\", className: \"bg-white/90 text-neutral-900\" },\n stat: {\n kind: \"team\",\n members: [\"Grace Liu\", \"Mateo Silva\", \"Ida Sørensen\"],\n avatars: [avatar(28, \"Grace Liu\"), avatar(60, \"Mateo Silva\"), avatar(45, \"Ida Sørensen\")],\n },\n },\n];\n\nfunction MissionCard({ mission }: { mission: (typeof MISSIONS)[number] }) {\n return (\n <TiltCard className=\"shrink-0\">\n <HeroCard\n image={mission.image}\n imageBlend=\"soft-light\"\n imageOpacity={0.4}\n parallax\n className={`aspect-[3/4] w-[400px] p-10 ring-0 bg-gradient-to-br ${mission.gradient}`}\n contentClassName=\"flex h-full flex-col\"\n >\n <div className=\"flex items-start justify-between\">\n <Badge className=\"border-0 bg-white/20 rounded-full text-white text-sm py-1 px-2\">Mission</Badge>\n <Badge className={`border-0 rounded-full text-sm py-1 px-2 ${mission.status.className}`}>{mission.status.label}</Badge>\n </div>\n <h3 className=\"mt-5 text-5xl font-semibold tracking-tight\">{mission.title}</h3>\n <p className=\"mt-3 max-w-[18rem] text-sm leading-snug text-white/70\">{mission.blurb}</p>\n <div className=\"mt-auto\">\n <MissionStatFooter stat={mission.stat} />\n </div>\n </HeroCard>\n </TiltCard>\n );\n}\n\n// Renders the per-mission footer — one of five shapes so no two cards read alike.\nfunction MissionStatFooter({ stat }: { stat: MissionStat }) {\n switch (stat.kind) {\n case \"progress\":\n return (\n <div>\n <div className=\"flex items-center justify-between text-sm font-semibold\">\n <span>{stat.label}</span>\n <span className=\"text-white/70\">{stat.value}%</span>\n </div>\n <Progress\n value={stat.value}\n size=\"sm\"\n className=\"mt-2 bg-white\"\n theme={{ trackStyle: \"rounded-full bg-white/20\" }}\n />\n </div>\n );\n case \"metric\":\n return (\n <div>\n <div className=\"flex items-end gap-2\">\n <span className=\"text-4xl font-semibold tracking-tight\">{stat.value}</span>\n {stat.delta && <span className=\"mb-1.5 text-sm font-medium text-white/70\">{stat.delta}</span>}\n </div>\n <p className=\"mt-1 text-sm text-white/70\">{stat.label}</p>\n </div>\n );\n case \"trend\":\n return (\n <div>\n <div className=\"flex items-end gap-2\">\n <span className=\"text-4xl font-semibold tracking-tight\">{stat.value}</span>\n {stat.delta && <span className=\"mb-1.5 text-sm font-medium text-white/70\">{stat.delta}</span>}\n </div>\n <p className=\"mt-1 text-sm text-white/70\">{stat.label}</p>\n {/* Edge-to-edge: negative margins cancel the card's p-10 so the area meets the card's side + bottom edges. */}\n <div className=\"-mx-10 -mb-10 mt-5 h-32\">\n <AreaChart\n height=\"100%\"\n data={stat.data}\n config={{ v: { label: \"Automations\", color: \"sky-200\" } }}\n showGrid={false}\n showXAxis={false}\n showYAxis={false}\n strokeWidth={3}\n />\n </div>\n </div>\n );\n case \"milestone\":\n return (\n <div className=\"flex items-end justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-sm font-semibold text-white/70\">{stat.label}</div>\n <p className=\"mt-1 text-2xl font-semibold tracking-tight\">{stat.date}</p>\n </div>\n <AvatarGroup size=\"sm\" max={3} avatars={stat.avatars} className=\"shrink-0\" />\n </div>\n );\n case \"roles\":\n return (\n <div className=\"flex items-end justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-sm font-semibold text-white/70\">{stat.label}</div>\n <p className=\"mt-1 text-2xl font-semibold tracking-tight\">{stat.open} open</p>\n </div>\n <AvatarGroup size=\"sm\" max={3} avatars={stat.avatars} className=\"shrink-0\" />\n </div>\n );\n case \"team\":\n return (\n <div className=\"flex items-end justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-sm font-semibold\">Team</div>\n <p className=\"mt-1 text-sm leading-snug text-white/70\">{stat.members.join(\", \")}</p>\n </div>\n <AvatarGroup size=\"sm\" max={3} avatars={stat.avatars} className=\"shrink-0\" />\n </div>\n );\n }\n}\n\nexport const Default: Story = {\n render: () => (\n <div className=\"p-10\">\n <p className=\"text-sm font-medium text-gray-500\">Your guide to Flikk</p>\n <h2 className=\"mt-1 text-5xl font-bold tracking-tight text-gray-900\">SS26 Missions</h2>\n <ScrollArea orientation=\"horizontal\" type=\"hover\" dragToScroll className=\"mt-8 w-full\">\n <div className=\"flex gap-3 py-2\">\n <MissionCard mission={MISSIONS[0]} />\n\n {/* statement card — flat near-black, no backdrop */}\n <TiltCard className=\"shrink-0\">\n <HeroCard\n image={'/bg/19.webp'}\n imageOpacity={0.1}\n imageBlend=\"hard-light\"\n className=\"aspect-[3/4] w-[400px] bg-[#111113] p-10 ring-0\"\n contentClassName=\"flex h-full flex-col\"\n >\n <Badge className=\"self-start border-0 bg-white/15 rounded-full text-white/80 text-sm py-1 px-2\">Mission</Badge>\n <p className=\"mt-6 text-xl leading-snug\">\n <span className=\"font-semibold\">The Workflows mission aims to{\" \"}</span>\n <span className=\"text-white/50\">\n help teams ship automations that feel effortless — fewer clicks, happier admins.\n </span>\n </p>\n <div className=\"mt-auto flex gap-2\">\n <Button size=\"sm\" variant=\"ghost\" color=\"mono\" className=\"text-white hover:bg-white/10\">\n Front\n </Button>\n <Button size=\"sm\" color=\"mono\" className=\"bg-white/10 text-white hover:bg-white/25\">\n Back\n </Button>\n </div>\n </HeroCard>\n </TiltCard>\n\n {MISSIONS.slice(1).map((m) => (\n <MissionCard key={m.title} mission={m} />\n ))}\n </div>\n </ScrollArea>\n </div>\n ),\n};"
11154
11666
  },
11155
11667
  {
11156
11668
  "name": "NodeCanvasEditorLayout",
@@ -11172,7 +11684,33 @@
11172
11684
  "--color-text-placeholder",
11173
11685
  "--color-text-muted",
11174
11686
  "--color-text-disabled",
11175
- "--color-text-inverse"
11687
+ "--color-text-inverse",
11688
+ "--text-xs",
11689
+ "--text-sm",
11690
+ "--text-base",
11691
+ "--text-lg",
11692
+ "--text-xl",
11693
+ "--text-2xl",
11694
+ "--text-3xl",
11695
+ "--text-4xl",
11696
+ "--text-5xl",
11697
+ "--text-6xl",
11698
+ "--text-7xl",
11699
+ "--text-8xl",
11700
+ "--text-9xl",
11701
+ "--form-text-size-sm",
11702
+ "--form-text-size-md",
11703
+ "--form-text-size-lg",
11704
+ "--otp-text-size-sm",
11705
+ "--otp-text-size-md",
11706
+ "--otp-text-size-lg",
11707
+ "--otp-text-size-xl",
11708
+ "--button-text-size-sm",
11709
+ "--button-text-size-md",
11710
+ "--button-text-size-lg",
11711
+ "--segmented-text-size-sm",
11712
+ "--segmented-text-size-md",
11713
+ "--segmented-text-size-lg"
11176
11714
  ],
11177
11715
  "background": [
11178
11716
  "--color-background",
@@ -11187,10 +11725,6 @@
11187
11725
  "--color-border",
11188
11726
  "--color-border-secondary",
11189
11727
  "--color-border-hover",
11190
- "--glass-layer-border-width",
11191
- "--chat-bubble-border-sender",
11192
- "--chat-bubble-border-receiver",
11193
- "--popover-border-width",
11194
11728
  "--neu-raised-border",
11195
11729
  "--neu-inset-border"
11196
11730
  ],
@@ -11208,6 +11742,9 @@
11208
11742
  "--color-surface-overlay",
11209
11743
  "--color-surface-sunken",
11210
11744
  "--color-surface-hover",
11745
+ "--surface-radius-cap-xs",
11746
+ "--surface-radius-cap-sm",
11747
+ "--surface-radius-cap-lg",
11211
11748
  "--shimmer-surface-highlight",
11212
11749
  "--elevation-surface-1",
11213
11750
  "--elevation-surface-2",
@@ -11283,35 +11820,53 @@
11283
11820
  "--color-warning-900",
11284
11821
  "--color-warning-950",
11285
11822
  "--color-warning",
11286
- "--color-warning-contrast",
11287
- "--shadow-color-primary",
11288
- "--shadow-color-success",
11289
- "--shadow-color-warning",
11290
- "--shadow-color-danger",
11291
- "--shadow-color-secondary"
11823
+ "--color-warning-contrast"
11292
11824
  ],
11293
11825
  "other": [
11294
11826
  "--field-fill",
11295
11827
  "--color-chart-track",
11296
- "--color-neutral-50",
11297
- "--color-neutral-100",
11298
- "--color-neutral-200",
11299
- "--color-neutral-300",
11300
- "--color-neutral-400",
11301
- "--color-neutral-500",
11302
- "--color-neutral-600",
11303
- "--color-neutral-700",
11304
- "--color-neutral-800",
11305
- "--color-neutral-900",
11306
- "--color-neutral-950",
11828
+ "--color-chart-1",
11829
+ "--color-chart-1-contrast",
11830
+ "--color-chart-2",
11831
+ "--color-chart-2-contrast",
11832
+ "--color-chart-3",
11833
+ "--color-chart-3-contrast",
11834
+ "--color-chart-4",
11835
+ "--color-chart-4-contrast",
11836
+ "--color-chart-5",
11837
+ "--color-chart-5-contrast",
11838
+ "--color-mono-50",
11839
+ "--color-mono-100",
11840
+ "--color-mono-200",
11841
+ "--color-mono-300",
11842
+ "--color-mono-400",
11843
+ "--color-mono-500",
11844
+ "--color-mono-600",
11845
+ "--color-mono-700",
11846
+ "--color-mono-800",
11847
+ "--color-mono-900",
11848
+ "--color-mono-950",
11849
+ "--color-mono",
11850
+ "--color-mono-contrast",
11307
11851
  "--font-family-base",
11308
- "--font-cursive",
11852
+ "--font-scale",
11309
11853
  "--font-weight-light",
11310
11854
  "--font-weight-normal",
11311
11855
  "--font-weight-medium",
11312
11856
  "--font-weight-semibold",
11313
11857
  "--font-weight-bold",
11314
11858
  "--font-weight-extrabold",
11859
+ "--card-title-size",
11860
+ "--modal-title-size",
11861
+ "--drawer-title-size",
11862
+ "--page-heading-title-size",
11863
+ "--section-title-size",
11864
+ "--metric-value-size-sm",
11865
+ "--metric-value-size-md",
11866
+ "--metric-value-size-lg",
11867
+ "--kpi-value-size-sm",
11868
+ "--kpi-value-size-md",
11869
+ "--kpi-value-size-lg",
11315
11870
  "--form-min-h-sm",
11316
11871
  "--form-min-h-md",
11317
11872
  "--form-min-h-lg",
@@ -11322,6 +11877,18 @@
11322
11877
  "--form-py-sm",
11323
11878
  "--form-py-md",
11324
11879
  "--form-py-lg",
11880
+ "--form-line-height-sm",
11881
+ "--form-line-height-md",
11882
+ "--form-line-height-lg",
11883
+ "--form-min-h-xl",
11884
+ "--otp-slot-size-sm",
11885
+ "--otp-slot-size-md",
11886
+ "--otp-slot-size-lg",
11887
+ "--otp-slot-size-xl",
11888
+ "--otp-line-height-sm",
11889
+ "--otp-line-height-md",
11890
+ "--otp-line-height-lg",
11891
+ "--otp-line-height-xl",
11325
11892
  "--radius-base",
11326
11893
  "--form-radius",
11327
11894
  "--checkbox-radius",
@@ -11333,15 +11900,12 @@
11333
11900
  "--toast-radius",
11334
11901
  "--drawer-radius",
11335
11902
  "--metric-radius",
11903
+ "--message-bubble-radius",
11904
+ "--gantt-chart-radius",
11336
11905
  "--card-radius",
11337
11906
  "--modal-radius",
11338
11907
  "--segmented-radius",
11339
11908
  "--avatar-radius",
11340
- "--form-focus-ring-width",
11341
- "--form-focus-ring-offset",
11342
- "--form-focus-ring-opacity",
11343
- "--form-outline-width",
11344
- "--form-outline-focused-width",
11345
11909
  "--button-radius",
11346
11910
  "--button-min-h-sm",
11347
11911
  "--button-min-h-md",
@@ -11352,6 +11916,9 @@
11352
11916
  "--button-py-md",
11353
11917
  "--button-px-lg",
11354
11918
  "--button-py-lg",
11919
+ "--button-line-height-sm",
11920
+ "--button-line-height-md",
11921
+ "--button-line-height-lg",
11355
11922
  "--button-icon-p-sm",
11356
11923
  "--button-icon-p-md",
11357
11924
  "--button-icon-p-lg",
@@ -11359,6 +11926,25 @@
11359
11926
  "--button-icon-size-md",
11360
11927
  "--button-icon-size-lg",
11361
11928
  "--badge-radius",
11929
+ "--badge-px-sm",
11930
+ "--badge-px-md",
11931
+ "--badge-py-sm",
11932
+ "--badge-py-md",
11933
+ "--badge-pill-px-sm",
11934
+ "--badge-pill-px-md",
11935
+ "--pill-px-sm",
11936
+ "--pill-px-md",
11937
+ "--pill-px-lg",
11938
+ "--pill-py-sm",
11939
+ "--pill-py-md",
11940
+ "--pill-py-lg",
11941
+ "--tag-px-sm",
11942
+ "--tag-px-md",
11943
+ "--tag-pl-md",
11944
+ "--tag-py-sm",
11945
+ "--tag-py-md",
11946
+ "--kbd-px-sm",
11947
+ "--kbd-px-md",
11362
11948
  "--segmented-min-h-sm",
11363
11949
  "--segmented-min-h-md",
11364
11950
  "--segmented-min-h-lg",
@@ -11368,12 +11954,20 @@
11368
11954
  "--segmented-py-sm",
11369
11955
  "--segmented-py-md",
11370
11956
  "--segmented-py-lg",
11957
+ "--segmented-line-height-sm",
11958
+ "--segmented-line-height-md",
11959
+ "--segmented-line-height-lg",
11960
+ "--card-px",
11961
+ "--card-py",
11962
+ "--modal-px",
11963
+ "--modal-py",
11964
+ "--drawer-px",
11965
+ "--drawer-py",
11966
+ "--metric-content-p-sm",
11967
+ "--metric-content-p-md",
11968
+ "--metric-content-p-lg",
11371
11969
  "--segmented-padding",
11372
11970
  "--segmented-inner-radius",
11373
- "--segmented-active-bg",
11374
- "--segmented-active-shadow",
11375
- "--glass-layer-padding",
11376
- "--glass-layer-inner-offset",
11377
11971
  "--glass-gradient-outer",
11378
11972
  "--glass-gradient-inner",
11379
11973
  "--avatar-size-xs",
@@ -11381,27 +11975,7 @@
11381
11975
  "--avatar-size-md",
11382
11976
  "--avatar-size-lg",
11383
11977
  "--avatar-size-xl",
11384
- "--carousel-container-width",
11385
- "--carousel-slide-width",
11386
- "--carousel-slide-height",
11387
- "--carousel-slide-gap",
11388
- "--carousel-controls-size",
11389
- "--carousel-controls-offset",
11390
- "--popover-shadow",
11391
- "--popover-backdrop-opacity",
11392
- "--popover-offset-sm",
11393
- "--popover-offset-md",
11394
- "--popover-offset-lg",
11395
- "--popover-max-width-sm",
11396
- "--popover-max-width-md",
11397
- "--popover-max-width-lg",
11398
- "--popover-padding-sm",
11399
- "--popover-padding-md",
11400
- "--popover-padding-lg",
11401
11978
  "--nav-item-radius",
11402
- "--nav-item-min-h",
11403
- "--nav-item-px",
11404
- "--nav-item-py",
11405
11979
  "--overlay-bg",
11406
11980
  "--overlay-blur",
11407
11981
  "--neu-raised-shadow",
@@ -11442,7 +12016,7 @@
11442
12016
  },
11443
12017
  "peerDependencies": {
11444
12018
  "required": {
11445
- "@heroicons/react": ">=2.0.0",
12019
+ "@phosphor-icons/react": ">=2.1.0",
11446
12020
  "motion": ">=12.0.0",
11447
12021
  "react": ">=18.0.0",
11448
12022
  "react-dom": ">=18.0.0"