@signalflare-ai/ui 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/CHANGELOG.md +25 -4
  2. package/README.md +1 -1
  3. package/ai/component-registry.json +976 -182
  4. package/ai/component-registry.md +4183 -49
  5. package/ai/schemas.ts +99 -502
  6. package/dist/.build-complete +1 -1
  7. package/dist/ai/schemas.d.ts +76 -58
  8. package/dist/ai/schemas.d.ts.map +1 -1
  9. package/dist/{ai-actions-DSVeQn4e.js → ai-actions-BdUZI3Gk.js} +3 -3
  10. package/dist/{ai-actions-DSVeQn4e.js.map → ai-actions-BdUZI3Gk.js.map} +1 -1
  11. package/dist/{ai-agent-card-BXHwhWAU.js → ai-agent-card-BR2NIYhi.js} +1 -1
  12. package/dist/{ai-agent-card-BXHwhWAU.js.map → ai-agent-card-BR2NIYhi.js.map} +1 -1
  13. package/dist/{ai-approval-aa0qvjFN.js → ai-approval-Ba7mrKba.js} +2 -2
  14. package/dist/{ai-approval-aa0qvjFN.js.map → ai-approval-Ba7mrKba.js.map} +1 -1
  15. package/dist/{ai-code-block-BgtIxtZZ.js → ai-code-block-CZtoL73R.js} +3 -3
  16. package/dist/{ai-code-block-BgtIxtZZ.js.map → ai-code-block-CZtoL73R.js.map} +1 -1
  17. package/dist/ai-conversation-Cc7WlaBg.js +242 -0
  18. package/dist/ai-conversation-Cc7WlaBg.js.map +1 -0
  19. package/dist/{ai-info-banner-uFxHHwBA.js → ai-info-banner-C7EWPBj7.js} +7 -3
  20. package/dist/ai-info-banner-C7EWPBj7.js.map +1 -0
  21. package/dist/{ai-message-BjnFznXy.js → ai-message-Bp7L68U_.js} +27 -8
  22. package/dist/ai-message-Bp7L68U_.js.map +1 -0
  23. package/dist/{ai-mission-header-08__gULL.js → ai-mission-header-TiCJfTNt.js} +1 -1
  24. package/dist/{ai-mission-header-08__gULL.js.map → ai-mission-header-TiCJfTNt.js.map} +1 -1
  25. package/dist/{ai-part-group-DBtgTgAn.js → ai-part-group-DNb9I446.js} +3 -3
  26. package/dist/{ai-part-group-DBtgTgAn.js.map → ai-part-group-DNb9I446.js.map} +1 -1
  27. package/dist/{ai-prompt-input-CuluUzpf.js → ai-prompt-input-BVvov_KF.js} +29 -42
  28. package/dist/ai-prompt-input-BVvov_KF.js.map +1 -0
  29. package/dist/{ai-question-CHHoDJMg.js → ai-question-GPPMk7YM.js} +2 -2
  30. package/dist/{ai-question-CHHoDJMg.js.map → ai-question-GPPMk7YM.js.map} +1 -1
  31. package/dist/{ai-reasoning-CnL6ZSr5.js → ai-reasoning-_feFjk56.js} +2 -2
  32. package/dist/{ai-reasoning-CnL6ZSr5.js.map → ai-reasoning-_feFjk56.js.map} +1 -1
  33. package/dist/{ai-response-BEUg3xvd.js → ai-response-CvjV3WhV.js} +8 -3
  34. package/dist/ai-response-CvjV3WhV.js.map +1 -0
  35. package/dist/{ai-shimmer-By5_L05p.js → ai-shimmer-j6lKIrjj.js} +1 -1
  36. package/dist/{ai-shimmer-By5_L05p.js.map → ai-shimmer-j6lKIrjj.js.map} +1 -1
  37. package/dist/{ai-status-badge-BGYGWYF6.js → ai-status-badge-CSU_QOdz.js} +1 -1
  38. package/dist/{ai-status-badge-BGYGWYF6.js.map → ai-status-badge-CSU_QOdz.js.map} +1 -1
  39. package/dist/{ai-streaming-text-CMfoThV0.js → ai-streaming-text-IWW1BhvZ.js} +44 -16
  40. package/dist/ai-streaming-text-IWW1BhvZ.js.map +1 -0
  41. package/dist/{ai-subagent-DcPRqkAA.js → ai-subagent-JA4iIMW3.js} +13 -5
  42. package/dist/ai-subagent-JA4iIMW3.js.map +1 -0
  43. package/dist/{ai-suggestion-MgeCg5Ar.js → ai-suggestion-BdO6MBuH.js} +2 -2
  44. package/dist/{ai-suggestion-MgeCg5Ar.js.map → ai-suggestion-BdO6MBuH.js.map} +1 -1
  45. package/dist/{ai-task-list-Da9zIm00.js → ai-task-list-DYw4R1FA.js} +12 -5
  46. package/dist/ai-task-list-DYw4R1FA.js.map +1 -0
  47. package/dist/{ai-timeline-Cwu045IR.js → ai-timeline-C42tOUT8.js} +1 -1
  48. package/dist/{ai-timeline-Cwu045IR.js.map → ai-timeline-C42tOUT8.js.map} +1 -1
  49. package/dist/{ai-tool-Cn1O4xjP.js → ai-tool-03jOTwUI.js} +23 -10
  50. package/dist/ai-tool-03jOTwUI.js.map +1 -0
  51. package/dist/{ai-usage-bar-DjS12DMp.js → ai-usage-bar-BRf5LC_b.js} +1 -1
  52. package/dist/{ai-usage-bar-DjS12DMp.js.map → ai-usage-bar-BRf5LC_b.js.map} +1 -1
  53. package/dist/{badge-D_eaA6wv.js → badge-BheXjMc8.js} +2 -2
  54. package/dist/{badge-D_eaA6wv.js.map → badge-BheXjMc8.js.map} +1 -1
  55. package/dist/{banner-B_6oBrsu.js → banner-CcsjunJg.js} +7 -2
  56. package/dist/banner-CcsjunJg.js.map +1 -0
  57. package/dist/{breadcrumbs-BlmeYfgq.js → breadcrumbs-CouSyy3H.js} +3 -3
  58. package/dist/{breadcrumbs-BlmeYfgq.js.map → breadcrumbs-CouSyy3H.js.map} +1 -1
  59. package/dist/{button-De0267YU.js → button-CO6-qPax.js} +1 -1
  60. package/dist/{button-De0267YU.js.map → button-CO6-qPax.js.map} +1 -1
  61. package/dist/catalog.js +1 -1
  62. package/dist/{chart-BK3sVPnD.js → chart-Dg0qUeSc.js} +2 -2
  63. package/dist/{chart-BK3sVPnD.js.map → chart-Dg0qUeSc.js.map} +1 -1
  64. package/dist/{checkbox-DYhUmZNw.js → checkbox-D7p4QKsC.js} +2 -2
  65. package/dist/{checkbox-DYhUmZNw.js.map → checkbox-D7p4QKsC.js.map} +1 -1
  66. package/dist/{clipboard-text-ssybngLw.js → clipboard-text-kLaMogs3.js} +3 -3
  67. package/dist/{clipboard-text-ssybngLw.js.map → clipboard-text-kLaMogs3.js.map} +1 -1
  68. package/dist/{code-Cx-QSoOT.js → code-BN8InC0G.js} +2 -2
  69. package/dist/{code-Cx-QSoOT.js.map → code-BN8InC0G.js.map} +1 -1
  70. package/dist/{collapsible-DWsXeXmS.js → collapsible-D_ueZ0jz.js} +1 -1
  71. package/dist/{collapsible-DWsXeXmS.js.map → collapsible-D_ueZ0jz.js.map} +1 -1
  72. package/dist/{combobox-C0iW6a0r.js → combobox-B7TOK0U2.js} +3 -3
  73. package/dist/{combobox-C0iW6a0r.js.map → combobox-B7TOK0U2.js.map} +1 -1
  74. package/dist/{command-palette-DGzioeki.js → command-palette-CuNUyJca.js} +2 -2
  75. package/dist/{command-palette-DGzioeki.js.map → command-palette-CuNUyJca.js.map} +1 -1
  76. package/dist/components/ai-actions.js +1 -1
  77. package/dist/components/ai-agent-card.js +1 -1
  78. package/dist/components/ai-approval.js +1 -1
  79. package/dist/components/ai-code-block.js +1 -1
  80. package/dist/components/ai-conversation.js +2 -2
  81. package/dist/components/ai-info-banner.js +1 -1
  82. package/dist/components/ai-message.js +1 -1
  83. package/dist/components/ai-mission-header.js +1 -1
  84. package/dist/components/ai-part-group.js +1 -1
  85. package/dist/components/ai-prompt-input.js +1 -1
  86. package/dist/components/ai-question.js +1 -1
  87. package/dist/components/ai-reasoning.js +1 -1
  88. package/dist/components/ai-response.js +1 -1
  89. package/dist/components/ai-shimmer.js +1 -1
  90. package/dist/components/ai-status-badge.js +1 -1
  91. package/dist/components/ai-streaming-text.js +2 -2
  92. package/dist/components/ai-subagent.js +1 -1
  93. package/dist/components/ai-suggestion.js +1 -1
  94. package/dist/components/ai-task-list.js +1 -1
  95. package/dist/components/ai-timeline.js +1 -1
  96. package/dist/components/ai-tool.js +1 -1
  97. package/dist/components/ai-usage-bar.js +1 -1
  98. package/dist/components/badge.js +1 -1
  99. package/dist/components/banner.js +1 -1
  100. package/dist/components/breadcrumbs.js +1 -1
  101. package/dist/components/button.js +1 -1
  102. package/dist/components/chart.js +2 -2
  103. package/dist/components/checkbox.js +1 -1
  104. package/dist/components/clipboard-text.js +1 -1
  105. package/dist/components/code.js +1 -1
  106. package/dist/components/collapsible.js +1 -1
  107. package/dist/components/combobox.js +1 -1
  108. package/dist/components/command-palette.js +1 -1
  109. package/dist/components/data-grid.js +1 -1
  110. package/dist/components/date-picker.js +1 -1
  111. package/dist/components/date-range-picker.js +1 -1
  112. package/dist/components/dialog.js +1 -1
  113. package/dist/components/dropdown.js +1 -1
  114. package/dist/components/empty.js +1 -1
  115. package/dist/components/field.js +1 -1
  116. package/dist/components/filters.js +1 -1
  117. package/dist/components/flow.js +1 -1
  118. package/dist/components/grid.js +1 -1
  119. package/dist/components/input.js +2 -2
  120. package/dist/components/label.js +1 -1
  121. package/dist/components/layer-card.js +1 -1
  122. package/dist/components/loader.js +1 -1
  123. package/dist/components/menubar.js +1 -1
  124. package/dist/components/meter.js +1 -1
  125. package/dist/components/pagination.js +1 -1
  126. package/dist/components/popover.js +1 -1
  127. package/dist/components/radio.js +1 -1
  128. package/dist/components/select.js +1 -1
  129. package/dist/components/sensitive-input.js +1 -1
  130. package/dist/components/sidebar.js +1 -1
  131. package/dist/components/signalflare-ai-logo.js +1 -1
  132. package/dist/components/sparkline.js +1 -1
  133. package/dist/components/stat-card.js +1 -1
  134. package/dist/components/surface.js +1 -1
  135. package/dist/components/switch.js +1 -1
  136. package/dist/components/table.js +1 -1
  137. package/dist/components/tabs.js +1 -1
  138. package/dist/components/text-roll.js +1 -1
  139. package/dist/components/text.js +1 -1
  140. package/dist/components/theme-toggle.js +1 -1
  141. package/dist/components/toast.js +1 -1
  142. package/dist/components/tooltip.js +1 -1
  143. package/dist/components/use-agent-harness.js +1 -1
  144. package/dist/{data-grid-CG76N_hK.js → data-grid-DGHmU0w3.js} +8 -8
  145. package/dist/{data-grid-CG76N_hK.js.map → data-grid-DGHmU0w3.js.map} +1 -1
  146. package/dist/{date-picker-Dqg9L4xu.js → date-picker--ox89RBy.js} +1 -1
  147. package/dist/{date-picker-Dqg9L4xu.js.map → date-picker--ox89RBy.js.map} +1 -1
  148. package/dist/{date-range-picker-D75LLINc.js → date-range-picker-DVa7QBqE.js} +1 -1
  149. package/dist/{date-range-picker-D75LLINc.js.map → date-range-picker-DVa7QBqE.js.map} +1 -1
  150. package/dist/{dialog-CyHEQXEY.js → dialog-Bv1oSFOd.js} +2 -2
  151. package/dist/{dialog-CyHEQXEY.js.map → dialog-Bv1oSFOd.js.map} +1 -1
  152. package/dist/{dist-1-gcEL2L.js → dist-B6iWiWwp.js} +25 -25
  153. package/dist/{dist-1-gcEL2L.js.map → dist-B6iWiWwp.js.map} +1 -1
  154. package/dist/{dropdown-qnEYRFXZ.js → dropdown-B_nrGXjV.js} +2 -2
  155. package/dist/{dropdown-qnEYRFXZ.js.map → dropdown-B_nrGXjV.js.map} +1 -1
  156. package/dist/{echart-DURZEyai.js → echart-CdOUaT-r.js} +1 -1
  157. package/dist/{echart-DURZEyai.js.map → echart-CdOUaT-r.js.map} +1 -1
  158. package/dist/{empty-D2TypIId.js → empty-DZnN0zKX.js} +11 -6
  159. package/dist/empty-DZnN0zKX.js.map +1 -0
  160. package/dist/{field-Y_UK1_Cg.js → field-B_yVof52.js} +2 -2
  161. package/dist/{field-Y_UK1_Cg.js.map → field-B_yVof52.js.map} +1 -1
  162. package/dist/{filters-Bw_U6ZTx.js → filters-cpJCY21R.js} +7 -7
  163. package/dist/{filters-Bw_U6ZTx.js.map → filters-cpJCY21R.js.map} +1 -1
  164. package/dist/{flow-BRsYUCJa.js → flow-B4v198ot.js} +1 -1
  165. package/dist/{flow-BRsYUCJa.js.map → flow-B4v198ot.js.map} +1 -1
  166. package/dist/genui.js +1 -1
  167. package/dist/{grid-qUAN9hFx.js → grid-CEd64Lnh.js} +1 -1
  168. package/dist/{grid-qUAN9hFx.js.map → grid-CEd64Lnh.js.map} +1 -1
  169. package/dist/{highlight-to-react-ClEfL81q.js → highlight-to-react-D0Yav4jk.js} +1 -1
  170. package/dist/{highlight-to-react-ClEfL81q.js.map → highlight-to-react-D0Yav4jk.js.map} +1 -1
  171. package/dist/index.js +69 -69
  172. package/dist/{input-DXYUjGgD.js → input-B2bbijRh.js} +2 -2
  173. package/dist/{input-DXYUjGgD.js.map → input-B2bbijRh.js.map} +1 -1
  174. package/dist/{input-DddtBN-g.js → input-ClB_E4Lb.js} +4 -4
  175. package/dist/{input-DddtBN-g.js.map → input-ClB_E4Lb.js.map} +1 -1
  176. package/dist/{label-QtJxtJ4u.js → label-DUv_urO1.js} +2 -2
  177. package/dist/{label-QtJxtJ4u.js.map → label-DUv_urO1.js.map} +1 -1
  178. package/dist/{layer-card-BME0eljh.js → layer-card-BK7eYfwn.js} +1 -1
  179. package/dist/{layer-card-BME0eljh.js.map → layer-card-BK7eYfwn.js.map} +1 -1
  180. package/dist/layout-DJHMMap2.js +6103 -0
  181. package/dist/layout-DJHMMap2.js.map +1 -0
  182. package/dist/measured-text-BI3dTJmH.js +290 -0
  183. package/dist/measured-text-BI3dTJmH.js.map +1 -0
  184. package/dist/{menubar-C8NzAjfd.js → menubar-Cxf3xeAt.js} +2 -2
  185. package/dist/{menubar-C8NzAjfd.js.map → menubar-Cxf3xeAt.js.map} +1 -1
  186. package/dist/{meter-CpmTenEr.js → meter-BFFe9l5b.js} +1 -1
  187. package/dist/{meter-CpmTenEr.js.map → meter-BFFe9l5b.js.map} +1 -1
  188. package/dist/{pagination-BVqdlONY.js → pagination-yS372Tr4.js} +2 -2
  189. package/dist/{pagination-BVqdlONY.js.map → pagination-yS372Tr4.js.map} +1 -1
  190. package/dist/{popover-BRQZ2b6z.js → popover-SRoJaCZr.js} +1 -1
  191. package/dist/{popover-BRQZ2b6z.js.map → popover-SRoJaCZr.js.map} +1 -1
  192. package/dist/{radio-BNSwOt3B.js → radio-BcwhwYNB.js} +1 -1
  193. package/dist/{radio-BNSwOt3B.js.map → radio-BcwhwYNB.js.map} +1 -1
  194. package/dist/{select-1w2aebGQ.js → select-DMhdoHMa.js} +4 -4
  195. package/dist/{select-1w2aebGQ.js.map → select-DMhdoHMa.js.map} +1 -1
  196. package/dist/{sensitive-input-82Cez3vj.js → sensitive-input-CJUpIRal.js} +3 -3
  197. package/dist/{sensitive-input-82Cez3vj.js.map → sensitive-input-CJUpIRal.js.map} +1 -1
  198. package/dist/{sidebar-CAsCmSpM.js → sidebar-D4zrlYpn.js} +2 -2
  199. package/dist/{sidebar-CAsCmSpM.js.map → sidebar-D4zrlYpn.js.map} +1 -1
  200. package/dist/{signalflare-ai-logo-DDhxMJD6.js → signalflare-ai-logo-Bipogceq.js} +1 -1
  201. package/dist/{signalflare-ai-logo-DDhxMJD6.js.map → signalflare-ai-logo-Bipogceq.js.map} +1 -1
  202. package/dist/{skeleton-line-Do3UmGk9.js → skeleton-line-CH1-h6e2.js} +1 -1
  203. package/dist/{skeleton-line-Do3UmGk9.js.map → skeleton-line-CH1-h6e2.js.map} +1 -1
  204. package/dist/{sparkline-DdbeM4Ai.js → sparkline-DHmgj1d0.js} +2 -2
  205. package/dist/{sparkline-DdbeM4Ai.js.map → sparkline-DHmgj1d0.js.map} +1 -1
  206. package/dist/src/blocks/agent-harness/agent-harness.d.ts.map +1 -1
  207. package/dist/src/blocks/agent-harness/agent-harness.tsx +29 -5
  208. package/dist/src/components/ai-conversation/ai-conversation.d.ts +69 -37
  209. package/dist/src/components/ai-conversation/ai-conversation.d.ts.map +1 -1
  210. package/dist/src/components/ai-conversation/index.d.ts +2 -1
  211. package/dist/src/components/ai-conversation/index.d.ts.map +1 -1
  212. package/dist/src/components/ai-conversation/measurement-constants.d.ts +30 -0
  213. package/dist/src/components/ai-conversation/measurement-constants.d.ts.map +1 -0
  214. package/dist/src/components/ai-info-banner/ai-info-banner.d.ts.map +1 -1
  215. package/dist/src/components/ai-message/ai-message.d.ts +3 -0
  216. package/dist/src/components/ai-message/ai-message.d.ts.map +1 -1
  217. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts +13 -3
  218. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
  219. package/dist/src/components/ai-prompt-input/index.d.ts +1 -1
  220. package/dist/src/components/ai-prompt-input/index.d.ts.map +1 -1
  221. package/dist/src/components/ai-response/ai-response.d.ts +12 -1
  222. package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
  223. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts +27 -0
  224. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts.map +1 -1
  225. package/dist/src/components/ai-streaming-text/index.d.ts +1 -1
  226. package/dist/src/components/ai-streaming-text/index.d.ts.map +1 -1
  227. package/dist/src/components/ai-subagent/ai-subagent.d.ts.map +1 -1
  228. package/dist/src/components/ai-task-list/ai-task-list.d.ts.map +1 -1
  229. package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
  230. package/dist/src/components/banner/banner.d.ts.map +1 -1
  231. package/dist/src/components/empty/empty.d.ts.map +1 -1
  232. package/dist/src/components/stat-card/stat-card.d.ts +5 -0
  233. package/dist/src/components/stat-card/stat-card.d.ts.map +1 -1
  234. package/dist/src/components/text/text.d.ts +35 -1
  235. package/dist/src/components/text/text.d.ts.map +1 -1
  236. package/dist/src/components/tooltip/tooltip.d.ts.map +1 -1
  237. package/dist/src/index.d.ts +2 -2
  238. package/dist/src/index.d.ts.map +1 -1
  239. package/dist/src/utils/index.d.ts +2 -0
  240. package/dist/src/utils/index.d.ts.map +1 -1
  241. package/dist/src/utils/measured-text.d.ts +40 -0
  242. package/dist/src/utils/measured-text.d.ts.map +1 -0
  243. package/dist/src/utils/use-measured-text.d.ts +59 -0
  244. package/dist/src/utils/use-measured-text.d.ts.map +1 -0
  245. package/dist/{stat-card-CEZscNh8.js → stat-card-Ew-ofzEm.js} +28 -10
  246. package/dist/stat-card-Ew-ofzEm.js.map +1 -0
  247. package/dist/styles/sf-binding.css +1 -1
  248. package/dist/styles/sf-standalone.css +2 -2
  249. package/dist/styles/shadcn.css +1 -1
  250. package/dist/styles/theme-fedramp.css +12 -3
  251. package/dist/styles/theme-minimal.css +104 -26
  252. package/dist/styles/theme-sf.css +138 -39
  253. package/dist/styles/theme-vesper.css +91 -0
  254. package/dist/{surface-BduI7Ehl.js → surface-DGwRlC0o.js} +1 -1
  255. package/dist/{surface-BduI7Ehl.js.map → surface-DGwRlC0o.js.map} +1 -1
  256. package/dist/{switch-CzZBRBL7.js → switch-BxAMfHdt.js} +2 -2
  257. package/dist/{switch-CzZBRBL7.js.map → switch-BxAMfHdt.js.map} +1 -1
  258. package/dist/{table-Rv4JMy0B.js → table-BBeAtYVZ.js} +2 -2
  259. package/dist/{table-Rv4JMy0B.js.map → table-BBeAtYVZ.js.map} +1 -1
  260. package/dist/{tabs-1cHrYoel.js → tabs-CeHu7Scn.js} +1 -1
  261. package/dist/{tabs-1cHrYoel.js.map → tabs-CeHu7Scn.js.map} +1 -1
  262. package/dist/{text-KJmGkwnf.js → text-Cqryz7rk.js} +27 -5
  263. package/dist/text-Cqryz7rk.js.map +1 -0
  264. package/dist/{text-roll-BZ3I1umc.js → text-roll-Ch52hcQj.js} +1 -1
  265. package/dist/{text-roll-BZ3I1umc.js.map → text-roll-Ch52hcQj.js.map} +1 -1
  266. package/dist/{theme-toggle-Bhu681D7.js → theme-toggle-LDfIKEqx.js} +3 -3
  267. package/dist/{theme-toggle-Bhu681D7.js.map → theme-toggle-LDfIKEqx.js.map} +1 -1
  268. package/dist/{toast-Nw28a5Cx.js → toast-CaFQNYng.js} +2 -2
  269. package/dist/{toast-Nw28a5Cx.js.map → toast-CaFQNYng.js.map} +1 -1
  270. package/dist/{tooltip-Cb7QW-7H.js → tooltip-g9lFsvcT.js} +8 -2
  271. package/dist/tooltip-g9lFsvcT.js.map +1 -0
  272. package/dist/{use-agent-harness-BMyF8pTq.js → use-agent-harness-BTcNJdw4.js} +1 -1
  273. package/dist/{use-agent-harness-BMyF8pTq.js.map → use-agent-harness-BTcNJdw4.js.map} +1 -1
  274. package/dist/utils.js +2 -1
  275. package/package.json +2 -1
  276. package/scripts/css-build.ts +1 -1
  277. package/scripts/theme-generator/config.ts +27 -141
  278. package/scripts/theme-generator/generate-css.ts +0 -1
  279. package/scripts/theme-generator/index.ts +0 -1
  280. package/dist/ai-conversation-CArP7C8K.js +0 -184
  281. package/dist/ai-conversation-CArP7C8K.js.map +0 -1
  282. package/dist/ai-info-banner-uFxHHwBA.js.map +0 -1
  283. package/dist/ai-message-BjnFznXy.js.map +0 -1
  284. package/dist/ai-prompt-input-CuluUzpf.js.map +0 -1
  285. package/dist/ai-response-BEUg3xvd.js.map +0 -1
  286. package/dist/ai-streaming-text-CMfoThV0.js.map +0 -1
  287. package/dist/ai-subagent-DcPRqkAA.js.map +0 -1
  288. package/dist/ai-task-list-Da9zIm00.js.map +0 -1
  289. package/dist/ai-tool-Cn1O4xjP.js.map +0 -1
  290. package/dist/banner-B_6oBrsu.js.map +0 -1
  291. package/dist/empty-D2TypIId.js.map +0 -1
  292. package/dist/stat-card-CEZscNh8.js.map +0 -1
  293. package/dist/styles/theme-blue-tint.css +0 -98
  294. package/dist/text-KJmGkwnf.js.map +0 -1
  295. package/dist/tooltip-Cb7QW-7H.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"ai-tool-Cn1O4xjP.js","names":[],"sources":["../src/components/ai-tool/ai-tool.tsx"],"sourcesContent":["\"use client\";\n\nimport { Collapsible as BaseCollapsible } from \"@base-ui/react/collapsible\";\nimport {\n CaretDownIcon,\n CheckIcon,\n CircleIcon,\n CodeIcon,\n DatabaseIcon,\n FileTextIcon,\n GearIcon,\n GlobeIcon,\n ImageIcon,\n LightningIcon,\n MagnifyingGlassIcon,\n ChatCircleIcon,\n SpinnerGapIcon,\n TerminalIcon,\n WarningCircleIcon,\n XCircleIcon,\n ShieldWarningIcon,\n BrainIcon,\n} from \"@phosphor-icons/react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { AiStatusBadge, type AiStatusBadgeStatus } from \"../ai-status-badge\";\nimport { Button } from \"../button\";\nimport { Tooltip } from \"../tooltip\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_TOOL_VARIANTS = {\n variant: {\n default: {\n classes: \"\",\n description: \"Expandable card with collapsible input/output sections\",\n },\n inline: {\n classes: \"\",\n description: \"Compact single-line display with left accent border\",\n },\n minimal: {\n classes: \"\",\n description: \"Pill-shaped status badge\",\n },\n ephemeral: {\n classes: \"\",\n description:\n \"Single-status row that auto-dismisses after the call completes. Persists on error or when the user expands it.\",\n },\n },\n} as const;\n\nexport const SF_AI_TOOL_DEFAULT_VARIANTS = {\n variant: \"default\",\n} as const;\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Tool execution state — matches Vercel AI SDK ToolUIPart[\"state\"]. */\nexport type AiToolState =\n | \"input-streaming\"\n | \"input-available\"\n | \"approval-requested\"\n | \"approval-responded\"\n | \"output-available\"\n | \"output-error\"\n | \"output-denied\";\n\n/** Display variant for tool call rendering. */\nexport type AiToolCallVariant = keyof typeof SF_AI_TOOL_VARIANTS.variant;\n\n/** Approval state for tools requiring user confirmation. */\nexport type AiToolApprovalState =\n | \"awaiting\"\n | \"approved\"\n | \"declined\"\n | undefined;\n\n/**\n * Structured tool part — mirrors the shape of Vercel AI SDK's `ToolUIPart`\n * without requiring the `ai` package as a dependency.\n */\nexport interface AiToolPart {\n /** Tool call identifier. */\n toolCallId: string;\n /** Tool name or type identifier. */\n toolName: string;\n /** Current execution state. */\n state: AiToolState;\n /** Tool input parameters. */\n input?: unknown;\n /** Tool output result. */\n output?: unknown;\n /** Error text when state is \"output-error\". */\n errorText?: string;\n}\n\nexport type AiToolCallProps = Omit<ComponentProps<\"div\">, \"part\"> & {\n /** Structured tool part data. */\n part: AiToolPart;\n /** Display variant. @default \"default\" */\n variant?: AiToolCallVariant;\n /** Duration in milliseconds. */\n duration?: number;\n /** Summary text shown alongside the tool name. */\n summary?: string;\n /** Custom icon override. */\n icon?: ElementType;\n /** Approval state for tools requiring confirmation. */\n approvalState?: AiToolApprovalState;\n /** Called when user approves a tool call (only relevant when `approvalState=\"awaiting\"`). */\n onApprove?: () => void;\n /** Called when user rejects a tool call (only relevant when `approvalState=\"awaiting\"`). */\n onReject?: () => void;\n /** Default expanded state for the collapsible. @default false */\n defaultExpanded?: boolean;\n /**\n * For `variant=\"ephemeral\"`: ms to keep the completed row visible before\n * fading out. Set to `0` to disable auto-dismiss. @default 800\n */\n dismissDelay?: number;\n /**\n * For `variant=\"ephemeral\"`: when `true`, the row never auto-dismisses.\n * Errors and user-expanded rows are pinned automatically.\n */\n persist?: boolean;\n /** Called once the ephemeral row has finished its dismiss animation. */\n onDismiss?: () => void;\n};\n\nexport type AiToolCallGroupProps = Omit<ComponentProps<\"div\">, \"part\"> & {\n /** Array of tool parts. */\n parts: AiToolPart[];\n /** Group label. */\n label?: string;\n /** Duration map keyed by toolCallId. */\n durations?: Record<string, number>;\n /** Summary map keyed by toolCallId. */\n summaries?: Record<string, string>;\n /** Approval states map keyed by toolCallId. */\n approvalStates?: Record<string, AiToolApprovalState>;\n /** Called when user approves a tool call. Receives the `toolCallId`. */\n onApprove?: (toolCallId: string) => void;\n /** Called when user rejects a tool call. Receives the `toolCallId`. */\n onReject?: (toolCallId: string) => void;\n /** Default expanded state. @default false */\n defaultExpanded?: boolean;\n};\n\nexport type AiToolCallTimelineProps = ComponentProps<\"div\"> & {\n /** Array of tool parts. */\n parts: AiToolPart[];\n /** Duration map keyed by toolCallId. */\n durations?: Record<string, number>;\n};\n\n// ─── Icon Map ────────────────────────────────────────────────────────────────\n\nconst TOOL_ICONS: Record<string, ElementType> = {\n generateSuggestions: BrainIcon,\n searchDatabase: DatabaseIcon,\n searchWeb: GlobeIcon,\n search: MagnifyingGlassIcon,\n readFile: FileTextIcon,\n writeFile: FileTextIcon,\n executeQuery: LightningIcon,\n analyzeContent: BrainIcon,\n generateImage: ImageIcon,\n chat: ChatCircleIcon,\n runCode: TerminalIcon,\n settings: GearIcon,\n code: CodeIcon,\n};\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\n/** Extract the display-friendly tool name from a tool part. */\nexport function getToolDisplayName(part: AiToolPart): string {\n return part.toolName\n .replace(\"tool-\", \"\")\n .replace(\"Tool\", \"\")\n .replace(/([A-Z])/g, \" $1\")\n .replace(/_/g, \" \")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n}\n\n/** Get the best-matching icon for a tool part. */\nexport function getToolIcon(part: AiToolPart): ElementType {\n if (TOOL_ICONS[part.toolName]) return TOOL_ICONS[part.toolName];\n\n const lower = part.toolName.toLowerCase();\n for (const [key, icon] of Object.entries(TOOL_ICONS)) {\n if (lower.includes(key.toLowerCase())) return icon;\n }\n\n return MagnifyingGlassIcon;\n}\n\n/** Whether the tool is still loading (input phase). */\nexport function isToolLoading(part: AiToolPart): boolean {\n return part.state === \"input-streaming\" || part.state === \"input-available\";\n}\n\n/** Whether the tool has produced a result. */\nexport function hasToolResult(part: AiToolPart): boolean {\n return part.state === \"output-available\";\n}\n\n/** Whether the output itself contains an error flag. */\nexport function hasToolOutputError(part: AiToolPart): boolean {\n if (part.state !== \"output-available\") return false;\n const output = part.output as Record<string, unknown> | undefined;\n return output?.error === true;\n}\n\n/** Whether the tool is in any error state. */\nexport function hasToolError(part: AiToolPart): boolean {\n return part.state === \"output-error\" || hasToolOutputError(part);\n}\n\n/** Extract error text from either error state or output.error. */\nexport function getToolErrorText(part: AiToolPart): string | undefined {\n if (part.state === \"output-error\") return part.errorText;\n if (hasToolOutputError(part)) {\n const output = part.output as Record<string, unknown>;\n return (\n (output.message as string) ||\n (output.error as string) ||\n \"Tool returned an error\"\n );\n }\n return undefined;\n}\n\n// ─── State Config ────────────────────────────────────────────────────────────\n\ninterface StateConfig {\n colorClass: string;\n bgClass: string;\n icon: ElementType;\n spin: boolean;\n label: string;\n /** Solid dot color for the minimalist status indicator (ephemeral variant). */\n dotClass: string;\n /** Whether the dot should pulse (running / streaming states). */\n dotPulse: boolean;\n}\n\nfunction getStateConfig(\n part: AiToolPart,\n approvalState?: AiToolApprovalState\n): StateConfig {\n if (approvalState === \"awaiting\") {\n return {\n colorClass: \"text-sf-warning\",\n bgClass: \"bg-sf-warning/10\",\n icon: ShieldWarningIcon,\n spin: false,\n label: \"Awaiting Approval\",\n dotClass: \"bg-sf-warning\",\n dotPulse: true,\n };\n }\n\n if (approvalState === \"declined\") {\n return {\n colorClass: \"text-sf-danger\",\n bgClass: \"bg-sf-danger/10\",\n icon: XCircleIcon,\n spin: false,\n label: \"Declined\",\n dotClass: \"bg-sf-danger\",\n dotPulse: false,\n };\n }\n\n if (hasToolError(part)) {\n return {\n colorClass: \"text-sf-danger\",\n bgClass: \"bg-sf-danger/10\",\n icon: WarningCircleIcon,\n spin: false,\n label: \"Failed\",\n dotClass: \"bg-sf-danger\",\n dotPulse: false,\n };\n }\n\n switch (part.state) {\n case \"input-streaming\":\n return {\n colorClass: \"text-sf-brand\",\n bgClass: \"bg-sf-brand/10\",\n icon: CircleIcon,\n spin: false,\n label: \"Streaming\",\n dotClass: \"bg-sf-warning\",\n dotPulse: true,\n };\n case \"input-available\":\n return {\n colorClass: \"text-sf-brand\",\n bgClass: \"bg-sf-brand/10\",\n icon: SpinnerGapIcon,\n spin: true,\n label: \"Running\",\n dotClass: \"bg-sf-warning\",\n dotPulse: true,\n };\n case \"output-available\":\n return {\n colorClass: \"text-sf-success\",\n bgClass: \"bg-sf-tint\",\n icon: CheckIcon,\n spin: false,\n label: \"Complete\",\n dotClass: \"bg-sf-success\",\n dotPulse: false,\n };\n default:\n return {\n colorClass: \"text-sf-subtle\",\n bgClass: \"bg-sf-tint\",\n icon: CircleIcon,\n spin: false,\n label: \"Pending\",\n dotClass: \"bg-sf-subtle/40\",\n dotPulse: false,\n };\n }\n}\n\n// ─── AiToolCall ──────────────────────────────────────────────────────────────\n\n/**\n * Renders a single tool call. Supports three display variants:\n * - `\"default\"` — expandable card with collapsible input/output\n * - `\"inline\"` — compact single-line with left accent border\n * - `\"minimal\"` — pill-shaped status badge\n *\n * @example\n * ```tsx\n * <AiToolCall\n * part={{ toolCallId: \"1\", toolName: \"web_search\", state: \"output-available\", input: { q: \"ts\" }, output: \"...\" }}\n * />\n * ```\n */\nexport function AiToolCall({\n part,\n variant = \"default\",\n duration,\n summary,\n icon: CustomIcon,\n approvalState,\n onApprove,\n onReject,\n defaultExpanded = false,\n dismissDelay = 800,\n persist = false,\n onDismiss,\n className,\n ...props\n}: AiToolCallProps) {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded);\n\n const IconComponent = CustomIcon ?? getToolIcon(part);\n const displayName = getToolDisplayName(part);\n const config = getStateConfig(part, approvalState);\n const StatusIconEl = config.icon;\n const errorText = getToolErrorText(part);\n\n // ── Ephemeral ──────────────────────────────────────────────────────────────\n\n if (variant === \"ephemeral\") {\n return (\n <AiToolCallEphemeral\n part={part}\n approvalState={approvalState}\n duration={duration}\n summary={summary}\n icon={IconComponent}\n displayName={displayName}\n config={config}\n errorText={errorText}\n dismissDelay={dismissDelay}\n persist={persist}\n onDismiss={onDismiss}\n onApprove={onApprove}\n onReject={onReject}\n className={className}\n {...props}\n />\n );\n }\n\n // ── Minimal ────────────────────────────────────────────────────────────────\n\n if (variant === \"minimal\") {\n const handleGetToolStatus = (): AiStatusBadgeStatus => {\n if (hasToolError(part)) return \"error\";\n if (approvalState === \"awaiting\") return \"idle\";\n if (isToolLoading(part)) return \"running\";\n if (hasToolResult(part)) return \"success\";\n return \"idle\";\n };\n\n return (\n <AiStatusBadge\n className={cn(\n \"my-1.5 py-1\",\n hasToolError(part) && \"bg-sf-danger/10\",\n className\n )}\n icon={IconComponent}\n label={displayName}\n status={handleGetToolStatus()}\n {...props}\n />\n );\n }\n\n // ── Inline ─────────────────────────────────────────────────────────────────\n\n if (variant === \"inline\") {\n return (\n <div\n className={cn(\n \"my-1 flex w-full items-center gap-2 py-1.5 pl-1\",\n \"animate-in fade-in-0 slide-in-from-bottom-1 duration-200\",\n className\n )}\n {...props}\n >\n <div className={cn(\"shrink-0 rounded-md p-1\", config.bgClass)}>\n <IconComponent className={cn(\"size-3.5\", config.colorClass)} />\n </div>\n <span\n className={cn(\n \"min-w-0 grow truncate text-sm\",\n hasToolError(part) ? \"text-sf-danger\" : \"text-sf-subtle\"\n )}\n >\n {displayName}\n </span>\n {/* Right-aligned meta group */}\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {duration && hasToolResult(part) ? (\n <span className=\"text-xs tabular-nums text-sf-subtle\">\n {duration}ms\n </span>\n ) : null}\n {summary && !hasToolError(part) ? (\n <span className=\"max-w-[160px] truncate text-xs text-sf-subtle\">\n {summary}\n </span>\n ) : null}\n {errorText ? (\n <span\n className=\"max-w-[160px] truncate text-xs text-sf-danger\"\n title={errorText}\n >\n {errorText}\n </span>\n ) : null}\n {approvalState === \"awaiting\" && (onApprove || onReject) ? (\n <>\n {onReject && (\n <Button\n onClick={onReject}\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n Reject\n </Button>\n )}\n {onApprove && (\n <Button\n onClick={onApprove}\n size=\"sm\"\n type=\"button\"\n variant=\"primary\"\n >\n Approve\n </Button>\n )}\n </>\n ) : (\n <StatusIconEl\n className={cn(\n \"size-3.5\",\n config.colorClass,\n config.spin && \"animate-spin\"\n )}\n />\n )}\n </div>\n </div>\n );\n }\n\n // ── Default (compact expandable row) ─────────────────────────────────────\n\n return (\n <BaseCollapsible.Root open={isExpanded} onOpenChange={setIsExpanded}>\n <div\n className={cn(\n \"my-0.5 flex w-full max-w-sm flex-col\",\n \"animate-in fade-in-0 duration-150\",\n className\n )}\n {...props}\n >\n {/* Trigger — content-width: name + meta + caret */}\n <BaseCollapsible.Trigger\n render={\n <button\n type=\"button\"\n className={cn(\n \"flex w-fit items-center gap-1.5 rounded px-1 py-0.5 text-left\",\n \"transition-colors hover:bg-sf-tint\"\n )}\n />\n }\n >\n <span className=\"min-w-0 truncate text-sm text-sf-subtle\">\n {displayName}\n </span>\n {/* Meta group — part of the content-width trigger */}\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {duration && hasToolResult(part) && !isExpanded ? (\n <span className=\"text-xs tabular-nums text-sf-subtle\">\n {duration}ms\n </span>\n ) : null}\n {summary && !isExpanded && !errorText ? (\n <span className=\"max-w-[120px] truncate text-xs text-sf-subtle\">\n {summary}\n </span>\n ) : null}\n <StatusIconEl\n className={cn(\n \"size-3.5\",\n config.colorClass,\n config.spin && \"animate-spin\"\n )}\n />\n <CaretDownIcon\n className={cn(\n \"size-3 text-sf-subtle transition-transform duration-200\",\n !isExpanded && \"-rotate-90\"\n )}\n />\n </div>\n </BaseCollapsible.Trigger>\n\n {/* Detail panel */}\n <BaseCollapsible.Panel className=\"overflow-hidden\">\n <div className=\"mt-1 space-y-2 rounded-lg bg-sf-tint/50 px-3 py-2\">\n {/* Input */}\n {part.input &&\n typeof part.input === \"object\" &&\n Object.keys(part.input as object).length > 0 ? (\n <div>\n <p className=\"mb-1 text-[10px] uppercase tracking-wider text-sf-subtle\">\n Input\n </p>\n <pre className=\"overflow-x-auto rounded bg-sf-recessed p-1.5 font-mono text-xs text-sf-subtle\">\n {JSON.stringify(\n part.input as Record<string, unknown>,\n null,\n 2\n )}\n </pre>\n </div>\n ) : null}\n\n {/* Output */}\n {hasToolResult(part) &&\n part.output !== undefined &&\n !hasToolError(part) ? (\n <div>\n <p className=\"mb-1 text-[10px] uppercase tracking-wider text-sf-subtle\">\n Output\n </p>\n <pre className=\"max-h-28 overflow-x-auto overflow-y-auto rounded bg-sf-recessed p-1.5 font-mono text-xs text-sf-subtle\">\n {typeof part.output === \"string\"\n ? part.output\n : JSON.stringify(\n part.output as Record<string, unknown>,\n null,\n 2\n )}\n </pre>\n </div>\n ) : null}\n\n {/* Error */}\n {errorText ? (\n <div>\n <p className=\"mb-1 flex items-center gap-1 text-[10px] uppercase tracking-wider text-sf-danger\">\n <WarningCircleIcon className=\"size-3\" />\n Error\n </p>\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-sf-danger/10 p-1.5 font-mono text-xs text-sf-danger\">\n {errorText}\n </pre>\n </div>\n ) : null}\n\n {/* Approval actions */}\n {approvalState === \"awaiting\" && (onApprove || onReject) && (\n <div className=\"flex items-center justify-end gap-2 border-t border-sf-line/20 pt-2\">\n {onReject && (\n <Button\n onClick={onReject}\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n Reject\n </Button>\n )}\n {onApprove && (\n <Button\n onClick={onApprove}\n size=\"sm\"\n type=\"button\"\n variant=\"primary\"\n >\n Approve\n </Button>\n )}\n </div>\n )}\n\n {/* Tool call ID */}\n <p className=\"font-mono text-[10px] text-sf-subtle/50\">\n {part.toolCallId}\n </p>\n </div>\n </BaseCollapsible.Panel>\n </div>\n </BaseCollapsible.Root>\n );\n}\n\n// ─── AiToolCallEphemeral ─────────────────────────────────────────────────────\n\ninterface AiToolCallEphemeralInternalProps extends Omit<\n ComponentProps<\"div\">,\n \"part\"\n> {\n part: AiToolPart;\n approvalState?: AiToolApprovalState;\n duration?: number;\n summary?: string;\n icon: ElementType;\n displayName: string;\n config: StateConfig;\n errorText: string | undefined;\n dismissDelay: number;\n persist: boolean;\n onDismiss?: () => void;\n onApprove?: () => void;\n onReject?: () => void;\n}\n\n// Note: `icon` (tool icon) is accepted for API symmetry with other variants\n// but the ephemeral row leads with the status icon for at-a-glance state.\n\nconst FADE_OUT_MS = 200;\n\n/**\n * Internal renderer for `variant=\"ephemeral\"`. Shows a single-status row\n * that auto-dismisses once the tool call completes. Pins on error or when\n * the user expands the row.\n */\nfunction AiToolCallEphemeral({\n part,\n approvalState,\n duration,\n summary,\n icon: _icon,\n displayName,\n config,\n errorText,\n dismissDelay,\n persist,\n onDismiss,\n onApprove,\n onReject,\n className,\n ...props\n}: AiToolCallEphemeralInternalProps) {\n const [isExpanded, setIsExpanded] = useState(false);\n const [phase, setPhase] = useState<\"live\" | \"fading\" | \"gone\">(\"live\");\n const userExpandedRef = useRef(false);\n\n const hasError = hasToolError(part);\n const isComplete = hasToolResult(part);\n const isAwaitingApproval = approvalState === \"awaiting\";\n\n // Pin the row when: errored, user expanded, persist requested, or awaiting approval.\n const pinned =\n persist || hasError || userExpandedRef.current || isAwaitingApproval;\n\n // Auto-dismiss when complete (and not pinned).\n useEffect(() => {\n if (phase !== \"live\") return;\n if (!isComplete) return;\n if (pinned) return;\n if (dismissDelay <= 0) return;\n\n const settleTimer = setTimeout(() => {\n setPhase(\"fading\");\n }, dismissDelay);\n\n return () => clearTimeout(settleTimer);\n }, [phase, isComplete, pinned, dismissDelay]);\n\n // After fade animation, unmount.\n useEffect(() => {\n if (phase !== \"fading\") return;\n const fadeTimer = setTimeout(() => {\n setPhase(\"gone\");\n onDismiss?.();\n }, FADE_OUT_MS);\n return () => clearTimeout(fadeTimer);\n }, [phase, onDismiss]);\n\n if (phase === \"gone\") return null;\n\n const handleToggle = (next: boolean) => {\n if (next) userExpandedRef.current = true;\n setIsExpanded(next);\n };\n\n return (\n <BaseCollapsible.Root open={isExpanded} onOpenChange={handleToggle}>\n <div\n className={cn(\n \"my-0.5 flex w-full max-w-sm flex-col overflow-hidden\",\n \"transition-[opacity,max-height,margin] duration-200 ease-out\",\n phase === \"live\"\n ? \"max-h-40 opacity-100\"\n : \"pointer-events-none my-0 max-h-0 opacity-0\",\n phase === \"live\" && \"animate-in fade-in-0 duration-150\",\n className\n )}\n data-phase={phase}\n {...props}\n >\n <BaseCollapsible.Trigger\n render={\n <button\n type=\"button\"\n className={cn(\n \"flex w-fit items-center gap-1.5 rounded px-1 py-0.5 text-left\",\n \"transition-colors hover:bg-sf-tint\"\n )}\n />\n }\n >\n <span\n aria-label={config.label}\n className={cn(\n \"size-1.5 shrink-0 rounded-full\",\n config.dotClass,\n config.dotPulse && \"animate-pulse\"\n )}\n role=\"status\"\n />\n <span\n className={cn(\n \"min-w-0 truncate text-sm\",\n hasError ? \"text-sf-danger\" : \"text-sf-subtle\"\n )}\n >\n {displayName}\n </span>\n {duration && isComplete && !isExpanded ? (\n <span className=\"text-xs tabular-nums text-sf-subtle/60\">\n {duration}ms\n </span>\n ) : null}\n {summary && !isExpanded && !errorText ? (\n <span className=\"max-w-[120px] truncate text-xs text-sf-subtle/60\">\n {summary}\n </span>\n ) : null}\n <CaretDownIcon\n className={cn(\n \"size-3 text-sf-subtle/60 transition-transform duration-200\",\n !isExpanded && \"-rotate-90\"\n )}\n />\n </BaseCollapsible.Trigger>\n\n <BaseCollapsible.Panel className=\"overflow-hidden\">\n <div className=\"mt-1 space-y-2 rounded-lg bg-sf-tint/50 px-3 py-2\">\n {part.input &&\n typeof part.input === \"object\" &&\n Object.keys(part.input as object).length > 0 ? (\n <div>\n <p className=\"mb-1 text-[10px] uppercase tracking-wider text-sf-subtle\">\n Input\n </p>\n <pre className=\"overflow-x-auto rounded bg-sf-recessed p-1.5 font-mono text-xs text-sf-subtle\">\n {JSON.stringify(\n part.input as Record<string, unknown>,\n null,\n 2\n )}\n </pre>\n </div>\n ) : null}\n\n {hasToolResult(part) && part.output !== undefined && !hasError ? (\n <div>\n <p className=\"mb-1 text-[10px] uppercase tracking-wider text-sf-subtle\">\n Output\n </p>\n <pre className=\"max-h-28 overflow-x-auto overflow-y-auto rounded bg-sf-recessed p-1.5 font-mono text-xs text-sf-subtle\">\n {typeof part.output === \"string\"\n ? part.output\n : JSON.stringify(\n part.output as Record<string, unknown>,\n null,\n 2\n )}\n </pre>\n </div>\n ) : null}\n\n {errorText ? (\n <div>\n <p className=\"mb-1 flex items-center gap-1 text-[10px] uppercase tracking-wider text-sf-danger\">\n <WarningCircleIcon className=\"size-3\" />\n Error\n </p>\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded bg-sf-danger/10 p-1.5 font-mono text-xs text-sf-danger\">\n {errorText}\n </pre>\n </div>\n ) : null}\n\n {isAwaitingApproval && (onApprove || onReject) && (\n <div className=\"flex items-center justify-end gap-2 border-t border-sf-line/20 pt-2\">\n {onReject && (\n <Button\n onClick={onReject}\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n Reject\n </Button>\n )}\n {onApprove && (\n <Button\n onClick={onApprove}\n size=\"sm\"\n type=\"button\"\n variant=\"primary\"\n >\n Approve\n </Button>\n )}\n </div>\n )}\n </div>\n </BaseCollapsible.Panel>\n </div>\n </BaseCollapsible.Root>\n );\n}\n\n// ─── AiToolCallGroup ─────────────────────────────────────────────────────────\n\n/**\n * Collapsible group of tool calls. Shows a summary header with progress\n * counter and stacked tool icons when collapsed. Renders a single tool\n * directly if only one part is provided.\n *\n * @example\n * ```tsx\n * <AiToolCallGroup parts={toolParts} label=\"3 tools ran\" />\n * ```\n */\nexport function AiToolCallGroup({\n parts,\n label,\n durations = {},\n summaries = {},\n approvalStates = {},\n onApprove,\n onReject,\n defaultExpanded = false,\n className,\n ...props\n}: AiToolCallGroupProps) {\n const [isExpanded, setIsExpanded] = useState(defaultExpanded);\n\n const completedCount = parts.filter(\n (p) => p.state === \"output-available\"\n ).length;\n const errorCount = parts.filter(hasToolError).length;\n const totalCount = parts.length;\n\n // Single item — render directly\n if (parts.length === 1 && parts[0]) {\n const singlePart = parts[0];\n // Strip `part` from div props spread to avoid collision with HTML `part` attribute\n const { part: _part, ...restProps } = props as typeof props & {\n part?: unknown;\n };\n return (\n <AiToolCall\n part={singlePart}\n duration={durations[singlePart.toolCallId]}\n summary={summaries[singlePart.toolCallId]}\n approvalState={approvalStates[singlePart.toolCallId]}\n onApprove={\n onApprove ? () => onApprove(singlePart.toolCallId) : undefined\n }\n onReject={onReject ? () => onReject(singlePart.toolCallId) : undefined}\n className={className}\n {...restProps}\n />\n );\n }\n\n return (\n <BaseCollapsible.Root open={isExpanded} onOpenChange={setIsExpanded}>\n <div\n className={cn(\n \"my-1.5 w-full overflow-hidden rounded-lg bg-sf-tint/50\",\n \"animate-in fade-in-0 slide-in-from-bottom-2 duration-200\",\n className\n )}\n {...props}\n >\n <BaseCollapsible.Trigger\n render={\n <button\n type=\"button\"\n className=\"flex w-fit items-center gap-3 px-3 py-2.5 text-left transition-colors hover:bg-sf-tint\"\n />\n }\n >\n <span className=\"text-sm font-medium text-sf-subtle\">\n {label ?? `${totalCount} tool calls`}\n </span>\n <span className=\"text-xs text-sf-subtle\">\n {completedCount}/{totalCount}\n {errorCount > 0 ? (\n <span className=\"ml-1 text-sf-danger\">({errorCount} errors)</span>\n ) : null}\n </span>\n\n <div className=\"flex items-center gap-2\">\n {/* Tool icon stack when collapsed */}\n {!isExpanded ? (\n <div className=\"flex -space-x-1\">\n {parts.slice(0, 5).map((p) => {\n const Icon = getToolIcon(p);\n return (\n <div\n key={p.toolCallId}\n className={cn(\n \"flex size-6 items-center justify-center rounded-full border-2 border-sf-elevated\",\n p.state === \"output-available\" &&\n !hasToolError(p) &&\n \"bg-sf-tint\",\n isToolLoading(p) && \"bg-sf-tint\",\n hasToolError(p) && \"bg-sf-danger/20\"\n )}\n >\n <Icon className=\"size-3\" />\n </div>\n );\n })}\n {parts.length > 5 ? (\n <div className=\"flex size-6 items-center justify-center rounded-full border-2 border-sf-elevated bg-sf-tint text-[10px] text-sf-subtle\">\n +{parts.length - 5}\n </div>\n ) : null}\n </div>\n ) : null}\n <CaretDownIcon\n className={cn(\n \"size-4 text-sf-subtle transition-transform duration-200\",\n !isExpanded && \"-rotate-90\"\n )}\n />\n </div>\n </BaseCollapsible.Trigger>\n\n <BaseCollapsible.Panel className=\"overflow-hidden\">\n <div className=\"space-y-2 border-t border-sf-line/20 px-3 pt-1 pb-3\">\n {parts.map((p) => (\n <AiToolCall\n key={p.toolCallId}\n part={p}\n variant=\"inline\"\n duration={durations[p.toolCallId]}\n summary={summaries[p.toolCallId]}\n approvalState={approvalStates[p.toolCallId]}\n onApprove={\n onApprove ? () => onApprove(p.toolCallId) : undefined\n }\n onReject={onReject ? () => onReject(p.toolCallId) : undefined}\n />\n ))}\n </div>\n </BaseCollapsible.Panel>\n </div>\n </BaseCollapsible.Root>\n );\n}\n\n// ─── AiToolCallTimeline ──────────────────────────────────────────────────────\n\n/**\n * Horizontal timeline view of tool calls. Each tool is shown as a small\n * icon pill with a tooltip showing its name, duration, and any errors.\n *\n * @example\n * ```tsx\n * <AiToolCallTimeline parts={toolParts} durations={{ id1: 230, id2: 540 }} />\n * ```\n */\nexport function AiToolCallTimeline({\n parts,\n durations = {},\n className,\n ...props\n}: AiToolCallTimelineProps) {\n return (\n <div\n className={cn(\"flex flex-wrap items-center gap-1 py-2\", className)}\n {...props}\n >\n {parts.map((part, index) => {\n const IconComponent = getToolIcon(part);\n const displayName = getToolDisplayName(part);\n const config = getStateConfig(part);\n const duration = durations[part.toolCallId];\n const errorText = getToolErrorText(part);\n\n const tooltipLines = [\n displayName,\n duration ? `${duration}ms` : null,\n errorText ?? null,\n ]\n .filter(Boolean)\n .join(\" · \");\n\n return (\n <div key={part.toolCallId} className=\"flex items-center\">\n <Tooltip content={tooltipLines}>\n <div\n className={cn(\n \"flex cursor-default items-center gap-1.5 rounded-md px-2 py-1 transition-all\",\n config.bgClass\n )}\n >\n <IconComponent className={cn(\"size-3.5\", config.colorClass)} />\n {part.state === \"input-streaming\" ? (\n <CircleIcon\n className={cn(\"size-3 animate-pulse\", config.colorClass)}\n />\n ) : null}\n {part.state === \"input-available\" ? (\n <SpinnerGapIcon\n className={cn(\"size-3 animate-spin\", config.colorClass)}\n />\n ) : null}\n {hasToolResult(part) && !hasToolError(part) ? (\n <CheckIcon className={cn(\"size-3\", config.colorClass)} />\n ) : null}\n {hasToolError(part) ? (\n <WarningCircleIcon\n className={cn(\"size-3\", config.colorClass)}\n />\n ) : null}\n </div>\n </Tooltip>\n\n {/* Connector line */}\n {index < parts.length - 1 ? (\n <div\n className={cn(\n \"mx-0.5 h-px w-3\",\n (() => {\n const nextPart = parts[index + 1];\n if (!nextPart) return \"bg-sf-line\";\n return hasToolResult(nextPart) || isToolLoading(nextPart)\n ? \"bg-sf-success/50\"\n : \"bg-sf-line\";\n })()\n )}\n />\n ) : null}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"banner-B_6oBrsu.js","names":[],"sources":["../src/components/banner/banner.tsx"],"sourcesContent":["import { type ReactNode, isValidElement } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\n/** Base styles applied to all banner variants. */\nexport const SF_BANNER_BASE_STYLES =\n \"flex w-full items-center gap-2 rounded-lg border px-4 py-1.5 text-base\";\n\n/** Banner variant definitions mapping variant names to their Tailwind classes and descriptions. */\nexport const SF_BANNER_VARIANTS = {\n variant: {\n default: {\n classes:\n \"bg-sf-info/20 border-sf-info text-sf-link selection:bg-sf-info-tint\",\n description: \"Informational banner for general messages\",\n },\n alert: {\n classes:\n \"bg-sf-warning/20 border-sf-warning text-sf-warning selection:bg-sf-warning-tint\",\n description: \"Warning banner for cautionary messages\",\n },\n error: {\n classes:\n \"bg-sf-danger/20 border-sf-danger text-sf-danger selection:bg-sf-danger-tint\",\n description: \"Error banner for critical issues\",\n },\n },\n} as const;\n\nexport const SF_BANNER_DEFAULT_VARIANTS = {\n variant: \"default\",\n} as const;\n\n// Derived types from SF_BANNER_VARIANTS\nexport type SFBannerVariant = keyof typeof SF_BANNER_VARIANTS.variant;\n\nexport interface SFBannerVariantsProps {\n /**\n * Visual style of the banner.\n * - `\"default\"` — Informational banner for general messages\n * - `\"alert\"` — Warning banner for cautionary messages\n * - `\"error\"` — Error banner for critical issues\n * @default \"default\"\n */\n variant?: SFBannerVariant;\n}\n\nexport function bannerVariants({\n variant = SF_BANNER_DEFAULT_VARIANTS.variant,\n}: SFBannerVariantsProps = {}) {\n return cn(\n // Base styles (exported as SF_BANNER_BASE_STYLES for Figma plugin)\n SF_BANNER_BASE_STYLES,\n // Apply variant styles from SF_BANNER_VARIANTS\n SF_BANNER_VARIANTS.variant[variant].classes\n );\n}\n\n// Legacy enum for backwards compatibility\nexport enum BannerVariant {\n DEFAULT,\n ALERT,\n ERROR,\n}\n\n/**\n * Banner component props.\n *\n * @example\n * ```tsx\n * <Banner>This is an informational banner.</Banner>\n * <Banner variant=\"alert\">Your session will expire soon.</Banner>\n * <Banner variant=\"error\">We couldn't save your changes.</Banner>\n * ```\n */\nexport interface BannerProps {\n /** Icon element rendered before the banner text (e.g. from `@phosphor-icons/react`). */\n icon?: ReactNode;\n /** @deprecated Use `children` instead. Will be removed in a future major version. */\n text?: string;\n /** Banner message content. Accepts strings or custom React elements. */\n children?: ReactNode;\n /**\n * Visual style of the banner.\n * - `\"default\"` — Informational blue banner for general messages\n * - `\"alert\"` — Warning yellow banner for cautionary messages\n * - `\"error\"` — Error red banner for critical issues\n * @default \"default\"\n */\n variant?: SFBannerVariant;\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n}\n\n/**\n * Full-width message bar for informational, warning, or error notices.\n *\n * @example\n * ```tsx\n * <Banner variant=\"alert\" icon={<WarningCircle />}>\n * Review your billing information.\n * </Banner>\n * ```\n */\nexport function Banner({\n icon,\n children,\n text,\n variant = SF_BANNER_DEFAULT_VARIANTS.variant,\n className,\n}: BannerProps) {\n // Prefer children over deprecated text prop\n const value = children ?? text;\n\n const content = isValidElement(value) ? value : <p>{value}</p>;\n\n return (\n <div className={cn(bannerVariants({ variant }), className)}>\n {icon}\n {content}\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,IAAa,wBACX;;AAGF,IAAa,qBAAqB,EAChC,SAAS;CACP,SAAS;EACP,SACE;EACF,aAAa;EACd;CACD,OAAO;EACL,SACE;EACF,aAAa;EACd;CACD,OAAO;EACL,SACE;EACF,aAAa;EACd;CACF,EACF;AAED,IAAa,6BAA6B,EACxC,SAAS,WACV;AAgBD,SAAgB,eAAe,EAC7B,UAAU,2BAA2B,YACZ,EAAE,EAAE;AAC7B,QAAO,GAEL,uBAEA,mBAAmB,QAAQ,SAAS,QACrC;;AAIH,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,cAAA,aAAA,KAAA;AACA,eAAA,cAAA,WAAA,KAAA;AACA,eAAA,cAAA,WAAA,KAAA;;KACD;;;;;;;;;;;AAyCD,SAAgB,OAAO,EACrB,MACA,UACA,MACA,UAAU,2BAA2B,SACrC,aACc;CAEd,MAAM,QAAQ,YAAY;CAE1B,MAAM,UAAU,eAAe,MAAM,GAAG,QAAQ,oBAAC,KAAD,EAAA,UAAI,OAAU,CAAA;AAE9D,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,eAAe,EAAE,SAAS,CAAC,EAAE,UAAU;YAA1D,CACG,MACA,QACG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"empty-D2TypIId.js","names":[],"sources":["../src/components/empty/empty.tsx"],"sourcesContent":["import { CheckIcon, CopyIcon } from \"@phosphor-icons/react\";\nimport { useState } from \"react\";\n\nimport { Button } from \"../../components/button\";\nimport { cn } from \"../../utils/cn\";\n\n/** Empty state size variant definitions mapping sizes to their Tailwind classes. */\nexport const SF_EMPTY_VARIANTS = {\n size: {\n sm: {\n classes: \"px-6 py-8 gap-4\",\n description: \"Compact empty state for smaller containers\",\n },\n base: {\n classes: \"px-10 py-16 gap-6\",\n description: \"Default empty state size\",\n },\n lg: {\n classes: \"px-12 py-20 gap-8\",\n description: \"Large empty state for prominent placement\",\n },\n },\n} as const;\n\nexport const SF_EMPTY_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\nexport type SFEmptySize = keyof typeof SF_EMPTY_VARIANTS.size;\n\nexport interface SFEmptyVariantsProps {\n /**\n * Size of the empty state container.\n * - `\"sm\"` — Compact empty state for smaller containers\n * - `\"base\"` — Default empty state size\n * - `\"lg\"` — Large empty state for prominent placement\n * @default \"base\"\n */\n size?: SFEmptySize;\n}\n\nexport function emptyVariants({\n size = SF_EMPTY_DEFAULT_VARIANTS.size,\n}: SFEmptyVariantsProps = {}) {\n return cn(\n \"flex w-full flex-col items-center rounded-xl border border-sf-fill bg-sf-control text-sf-default\",\n SF_EMPTY_VARIANTS.size[size].classes\n );\n}\n\n/**\n * Empty state component props.\n *\n * @example\n * ```tsx\n * <Empty\n * icon={<PackageIcon size={48} />}\n * title=\"No packages found\"\n * description=\"Get started by installing your first package.\"\n * commandLine=\"npm install @signalflare-ai/ui\"\n * />\n * ```\n */\nexport interface EmptyProps extends SFEmptyVariantsProps {\n /** Decorative icon displayed above the title (e.g. from `@phosphor-icons/react`). */\n icon?: React.ReactNode;\n /** Primary heading text for the empty state. */\n title: string;\n /** Secondary description text displayed below the title. */\n description?: string;\n /** Shell command displayed in a copyable code block. */\n commandLine?: string;\n /** Additional content (buttons, links) rendered below the description. */\n contents?: React.ReactNode;\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n}\n\n/**\n * Placeholder shown when a list, table, or page has no content to display.\n *\n * @example\n * ```tsx\n * <Empty title=\"No results found\" description=\"Try adjusting your search.\" />\n * ```\n */\nexport function Empty({\n icon,\n title,\n description,\n commandLine,\n contents,\n size = \"base\",\n className,\n}: EmptyProps) {\n const [emptyStateCopied, setEmptyStateCopied] = useState<boolean>(false);\n\n return (\n <div className={cn(emptyVariants({ size }), className)}>\n {icon}\n <h2 className=\"text-2xl font-semibold\">{title}</h2>\n\n {description && (\n <p className=\"max-w-140 text-center text-sf-strong\">{description}</p>\n )}\n\n {commandLine && (\n <div\n className={cn(\n \"group/cmd relative inline-flex h-10 max-w-8/10 transform-gpu items-center gap-2 rounded-lg font-mono shadow-sm\",\n \"bg-sf-overlay pr-2 pl-3\",\n \"transition-all duration-300 hover:border-sf-interact/80 hover:shadow-md\",\n \"border border-sf-fill/60\"\n )}\n >\n <span className=\"text-xs text-sf-inactive select-none\">$</span>\n <span className=\"no-scrollbar overflow-scroll text-[14px] whitespace-nowrap text-sf-brand\">\n {commandLine}\n </span>\n <Button\n className=\"group\"\n size=\"sm\"\n variant=\"ghost\"\n shape=\"square\"\n aria-label=\"Copy command\"\n onClick={async () => {\n setEmptyStateCopied(true);\n setTimeout(() => {\n setEmptyStateCopied(false);\n }, 1000);\n await navigator.clipboard.writeText(commandLine);\n }}\n >\n {emptyStateCopied ? (\n <CheckIcon\n size={16}\n className=\"animate-bounce-in text-sf-success\"\n />\n ) : (\n <CopyIcon\n size={16}\n className=\"text-sf-inactive group-hover:text-sf-brand\"\n />\n )}\n </Button>\n </div>\n )}\n\n {contents}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAOA,IAAa,oBAAoB,EAC/B,MAAM;CACJ,IAAI;EACF,SAAS;EACT,aAAa;EACd;CACD,MAAM;EACJ,SAAS;EACT,aAAa;EACd;CACD,IAAI;EACF,SAAS;EACT,aAAa;EACd;CACF,EACF;AAED,IAAa,4BAA4B,EACvC,MAAM,QACP;AAeD,SAAgB,cAAc,EAC5B,OAAO,0BAA0B,SACT,EAAE,EAAE;AAC5B,QAAO,GACL,oGACA,kBAAkB,KAAK,MAAM,QAC9B;;;;;;;;;;AAuCH,SAAgB,MAAM,EACpB,MACA,OACA,aACA,aACA,UACA,OAAO,QACP,aACa;CACb,MAAM,CAAC,kBAAkB,uBAAuB,SAAkB,MAAM;AAExE,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,cAAc,EAAE,MAAM,CAAC,EAAE,UAAU;YAAtD;GACG;GACD,oBAAC,MAAD;IAAI,WAAU;cAA0B;IAAW,CAAA;GAElD,eACC,oBAAC,KAAD;IAAG,WAAU;cAAwC;IAAgB,CAAA;GAGtE,eACC,qBAAC,OAAD;IACE,WAAW,GACT,kHACA,2BACA,2EACA,2BACD;cANH;KAQE,oBAAC,QAAD;MAAM,WAAU;gBAAuC;MAAQ,CAAA;KAC/D,oBAAC,QAAD;MAAM,WAAU;gBACb;MACI,CAAA;KACP,oBAAC,QAAD;MACE,WAAU;MACV,MAAK;MACL,SAAQ;MACR,OAAM;MACN,cAAW;MACX,SAAS,YAAY;AACnB,2BAAoB,KAAK;AACzB,wBAAiB;AACf,4BAAoB,MAAM;UACzB,IAAK;AACR,aAAM,UAAU,UAAU,UAAU,YAAY;;gBAGjD,mBACC,oBAAC,WAAD;OACE,MAAM;OACN,WAAU;OACV,CAAA,GAEF,oBAAC,UAAD;OACE,MAAM;OACN,WAAU;OACV,CAAA;MAEG,CAAA;KACL;;GAGP;GACG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"stat-card-CEZscNh8.js","names":[],"sources":["../src/components/stat-card/stat-card.tsx"],"sourcesContent":["import { forwardRef, type ReactNode } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\n/** StatCard variant definitions (indexed by variant name) */\nexport const SF_STAT_CARD_VARIANTS = {\n size: {\n sm: {\n root: \"gap-1 p-3\",\n label: \"text-xs\",\n value: \"text-xl\",\n hint: \"text-xs\",\n },\n base: {\n root: \"gap-2 p-4\",\n label: \"text-sm\",\n value: \"text-3xl\",\n hint: \"text-xs\",\n },\n },\n} as const;\n\n/** Default variants applied when none are passed explicitly. */\nexport const SF_STAT_CARD_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\nexport interface SFStatCardVariantsProps {\n /** Size of the card. Defaults to `\"base\"`. */\n size?: keyof typeof SF_STAT_CARD_VARIANTS.size;\n}\n\n/** Describes a change in the metric over a comparison period. */\nexport interface StatCardDelta {\n /** Numeric delta (e.g. `0.12` for +12% or `-4` for a drop of 4). */\n value: number;\n /**\n * Override the arrow direction. By default, direction is inferred from the\n * sign of `value`.\n */\n direction?: \"up\" | \"down\" | \"flat\";\n /** Optional context label shown after the delta (e.g. `\"vs last week\"`). */\n label?: string;\n /**\n * Whether an \"up\" direction means \"good\" (green) or \"bad\" (red). For metrics\n * like error rate, set this to `\"down\"` so downward movement is coloured\n * green.\n * @default \"up\"\n */\n positiveDirection?: \"up\" | \"down\";\n}\n\n/** Props for `StatCard` */\nexport interface StatCardProps extends SFStatCardVariantsProps {\n /** Short descriptive label (e.g. `\"Active users\"`). */\n label: ReactNode;\n /** Primary value to emphasise (pre-formatted). */\n value: ReactNode;\n /** Optional secondary text displayed under the value. */\n hint?: ReactNode;\n /** Optional change indicator (arrow + number + label). */\n delta?: StatCardDelta;\n /**\n * Optional content slot rendered on the right-hand side — typically a\n * `Sparkline` showing the metric's trend.\n */\n trend?: ReactNode;\n /** When `true`, renders a skeleton placeholder in place of value + delta. */\n loading?: boolean;\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n}\n\nfunction inferDirection(\n value: number,\n override?: \"up\" | \"down\" | \"flat\"\n): \"up\" | \"down\" | \"flat\" {\n if (override) return override;\n if (value > 0) return \"up\";\n if (value < 0) return \"down\";\n return \"flat\";\n}\n\nfunction deltaColor(\n direction: \"up\" | \"down\" | \"flat\",\n positiveDirection: \"up\" | \"down\"\n): string {\n if (direction === \"flat\") return \"text-sf-subtle\";\n const isPositive = direction === positiveDirection;\n return isPositive ? \"text-sf-success\" : \"text-sf-danger\";\n}\n\nfunction deltaArrow(direction: \"up\" | \"down\" | \"flat\"): string {\n if (direction === \"up\") return \"↑\";\n if (direction === \"down\") return \"↓\";\n return \"→\";\n}\n\n/**\n * StatCard — compact KPI tile displaying a label, a primary value, and an\n * optional delta + trend sparkline.\n *\n * @example\n * ```tsx\n * <StatCard\n * label=\"Active users\"\n * value=\"12,384\"\n * delta={{ value: 0.12, label: \"vs last week\" }}\n * />\n * ```\n */\nexport const StatCard = forwardRef<HTMLDivElement, StatCardProps>(\n function StatCard(\n {\n label,\n value,\n hint,\n delta,\n trend,\n loading,\n size = SF_STAT_CARD_DEFAULT_VARIANTS.size,\n className,\n },\n ref\n ) {\n const sizeClasses = SF_STAT_CARD_VARIANTS.size[size];\n const direction = delta\n ? inferDirection(delta.value, delta.direction)\n : undefined;\n const deltaClass =\n delta && direction\n ? deltaColor(direction, delta.positiveDirection ?? \"up\")\n : undefined;\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col rounded-lg bg-sf-elevated text-sf-default\",\n sizeClasses.root,\n className\n )}\n >\n <div className={cn(\"text-sf-subtle\", sizeClasses.label)}>{label}</div>\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex flex-col gap-1\">\n {loading ? (\n <div\n aria-busy=\"true\"\n className={cn(\n \"h-8 w-24 animate-pulse rounded-md bg-sf-fill\",\n size === \"sm\" && \"h-6 w-20\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"font-semibold tabular-nums text-sf-strong\",\n sizeClasses.value\n )}\n >\n {value}\n </div>\n )}\n {delta && !loading ? (\n <div\n className={cn(\n \"flex items-baseline gap-1 tabular-nums\",\n sizeClasses.hint\n )}\n >\n <span className={cn(\"font-medium\", deltaClass)}>\n {deltaArrow(direction!)}{\" \"}\n {Math.abs(delta.value).toLocaleString(undefined, {\n maximumFractionDigits: 2,\n })}\n </span>\n {delta.label ? (\n <span className=\"text-sf-subtle\">{delta.label}</span>\n ) : null}\n </div>\n ) : null}\n {hint && !loading ? (\n <div className={cn(\"text-sf-subtle\", sizeClasses.hint)}>\n {hint}\n </div>\n ) : null}\n </div>\n {trend ? (\n <div className=\"pointer-events-none shrink-0\">{trend}</div>\n ) : null}\n </div>\n </div>\n );\n }\n);\n\nStatCard.displayName = \"StatCard\";\n"],"mappings":";;;;;;AAKA,IAAa,wBAAwB,EACnC,MAAM;CACJ,IAAI;EACF,MAAM;EACN,OAAO;EACP,OAAO;EACP,MAAM;EACP;CACD,MAAM;EACJ,MAAM;EACN,OAAO;EACP,OAAO;EACP,MAAM;EACP;CACF,EACF;;AAGD,IAAa,gCAAgC,EAC3C,MAAM,QACP;AAgDD,SAAS,eACP,OACA,UACwB;AACxB,KAAI,SAAU,QAAO;AACrB,KAAI,QAAQ,EAAG,QAAO;AACtB,KAAI,QAAQ,EAAG,QAAO;AACtB,QAAO;;AAGT,SAAS,WACP,WACA,mBACQ;AACR,KAAI,cAAc,OAAQ,QAAO;AAEjC,QADmB,cAAc,oBACb,oBAAoB;;AAG1C,SAAS,WAAW,WAA2C;AAC7D,KAAI,cAAc,KAAM,QAAO;AAC/B,KAAI,cAAc,OAAQ,QAAO;AACjC,QAAO;;;;;;;;;;;;;;;AAgBT,IAAa,WAAW,WACtB,SAAS,SACP,EACE,OACA,OACA,MACA,OACA,OACA,SACA,OAAO,8BAA8B,MACrC,aAEF,KACA;CACA,MAAM,cAAc,sBAAsB,KAAK;CAC/C,MAAM,YAAY,QACd,eAAe,MAAM,OAAO,MAAM,UAAU,GAC5C,KAAA;CACJ,MAAM,aACJ,SAAS,YACL,WAAW,WAAW,MAAM,qBAAqB,KAAK,GACtD,KAAA;AAEN,QACE,qBAAC,OAAD;EACO;EACL,WAAW,GACT,2DACA,YAAY,MACZ,UACD;YANH,CAQE,oBAAC,OAAD;GAAK,WAAW,GAAG,kBAAkB,YAAY,MAAM;aAAG;GAAY,CAAA,EACtE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACG,UACC,oBAAC,OAAD;MACE,aAAU;MACV,WAAW,GACT,gDACA,SAAS,QAAQ,WAClB;MACD,CAAA,GAEF,oBAAC,OAAD;MACE,WAAW,GACT,6CACA,YAAY,MACb;gBAEA;MACG,CAAA;KAEP,SAAS,CAAC,UACT,qBAAC,OAAD;MACE,WAAW,GACT,0CACA,YAAY,KACb;gBAJH,CAME,qBAAC,QAAD;OAAM,WAAW,GAAG,eAAe,WAAW;iBAA9C;QACG,WAAW,UAAW;QAAE;QACxB,KAAK,IAAI,MAAM,MAAM,CAAC,eAAe,KAAA,GAAW,EAC/C,uBAAuB,GACxB,CAAC;QACG;UACN,MAAM,QACL,oBAAC,QAAD;OAAM,WAAU;iBAAkB,MAAM;OAAa,CAAA,GACnD,KACA;UACJ;KACH,QAAQ,CAAC,UACR,oBAAC,OAAD;MAAK,WAAW,GAAG,kBAAkB,YAAY,KAAK;gBACnD;MACG,CAAA,GACJ;KACA;OACL,QACC,oBAAC,OAAD;IAAK,WAAU;cAAgC;IAAY,CAAA,GACzD,KACA;KACF;;EAGX;AAED,SAAS,cAAc"}
@@ -1,98 +0,0 @@
1
- /**
2
- * AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY
3
- *
4
- * This file is generated by the theme generator.
5
- * To modify tokens, edit: scripts/theme-generator/config.ts
6
- * Then run: bun run codegen:themes
7
- */
8
-
9
- [data-theme="blue-tint"] {
10
- --text-color-sf-default: light-dark(oklch(0.145 0 0), oklch(0.985 0 0));
11
- --text-color-sf-strong: light-dark(oklch(0.556 0 0), oklch(0.65 0 0));
12
- --text-color-sf-subtle: light-dark(
13
- var(--color-neutral-500, oklch(55.6% 0 0)),
14
- var(--color-neutral-50, oklch(98.5% 0 0))
15
- );
16
- --text-color-sf-inactive: light-dark(
17
- var(--color-neutral-400, oklch(70.8% 0 0)),
18
- var(--color-neutral-600, oklch(70.8% 0 0))
19
- );
20
- --text-color-sf-danger: light-dark(
21
- oklch(0.577 0.245 27.325),
22
- oklch(0.55 0.18 25)
23
- );
24
- --text-color-sf-warning: light-dark(
25
- var(--color-yellow-800, oklch(47.6% 0.114 61.907)),
26
- var(--color-yellow-400, oklch(85.2% 0.199 91.936))
27
- );
28
- --color-sf-canvas: light-dark(
29
- var(--color-neutral-50, oklch(0.985 0 0)),
30
- var(--color-neutral-950, oklch(0.14 0 0))
31
- );
32
- --color-sf-base: light-dark(oklch(1 0 0), oklch(0.21 0.005 252));
33
- --color-sf-elevated: light-dark(oklch(0.99 0 0), oklch(0.24 0.005 252));
34
- --color-sf-recessed: light-dark(
35
- var(--color-neutral-250, oklch(0.9 0 0)),
36
- var(--color-neutral-750, oklch(0.31 0 0))
37
- );
38
- --color-sf-overlay: light-dark(
39
- var(--color-neutral-50, oklch(98.5% 0 0)),
40
- var(--color-neutral-950, oklch(0.1 0 0))
41
- );
42
- --color-sf-contrast: light-dark(oklch(0.205 0 0), oklch(0.55 0.01 40));
43
- --color-sf-control: light-dark(
44
- var(--color-white, #fff),
45
- var(--color-neutral-900, oklch(21% 0.006 285.885))
46
- );
47
- --color-sf-tint: light-dark(
48
- var(--color-neutral-150, oklch(0.96 0 0)),
49
- var(--color-neutral-850, oklch(0.23 0 0))
50
- );
51
- --color-sf-fill: light-dark(
52
- var(--color-neutral-200, oklch(92.2% 0 0)),
53
- var(--color-neutral-800, oklch(26.9% 0 0))
54
- );
55
- --color-sf-fill-hover: light-dark(
56
- var(--color-neutral-200, oklch(92.2% 0 0)),
57
- var(--color-neutral-700, oklch(37.1% 0 0))
58
- );
59
- --color-sf-brand: light-dark(
60
- oklch(0.5772 0.2324 260),
61
- oklch(0.5772 0.2324 260)
62
- );
63
- --color-sf-brand-hover: light-dark(
64
- var(--color-blue-700, oklch(48.8% 0.243 264.376)),
65
- var(--color-blue-700, oklch(48.8% 0.243 264.376))
66
- );
67
- --color-sf-line: light-dark(oklch(0.922 0 0), oklch(0.3 0.015 250));
68
- --color-sf-ring: light-dark(oklch(0.708 0 0), oklch(0.465 0.015 250));
69
- --color-sf-tip-shadow: light-dark(
70
- var(--color-gray-200, oklch(92.8% 0.006 264.531)),
71
- transparent
72
- );
73
- --color-sf-tip-stroke: light-dark(
74
- transparent,
75
- var(--color-neutral-800, oklch(26.9% 0 0))
76
- );
77
- --color-sf-info: light-dark(
78
- var(--color-blue-500, oklch(62.3% 0.214 259.815)),
79
- var(--color-blue-700, oklch(48.8% 0.243 264.376))
80
- );
81
- --color-sf-info-tint: light-dark(
82
- var(--color-blue-300, oklch(80.9% 0.105 251.813)),
83
- var(--color-blue-900, oklch(37.9% 0.146 265.522))
84
- );
85
- --color-sf-warning: light-dark(
86
- var(--color-yellow-500, oklch(79.5% 0.184 86.047)),
87
- var(--color-yellow-700, oklch(55.4% 0.135 66.442))
88
- );
89
- --color-sf-warning-tint: light-dark(
90
- var(--color-yellow-300, oklch(90.5% 0.182 98.111)),
91
- var(--color-yellow-900, oklch(42.1% 0.095 57.708))
92
- );
93
- --color-sf-danger: light-dark(oklch(0.577 0.245 27.325), oklch(0.55 0.18 25));
94
- --color-sf-danger-tint: light-dark(
95
- var(--color-red-300, oklch(80.8% 0.114 19.571)),
96
- var(--color-red-900, oklch(39.6% 0.141 25.723))
97
- );
98
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"text-KJmGkwnf.js","names":[],"sources":["../src/components/text/text.tsx"],"sourcesContent":["import {\n type CSSProperties,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type ForwardedRef,\n forwardRef,\n useMemo,\n type ElementType,\n} from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\n/** Text variant and size definitions mapping names to their Tailwind classes. */\nexport const SF_TEXT_VARIANTS = {\n variant: {\n heading1: {\n classes: \"text-3xl font-semibold\",\n description: \"Large heading for page titles\",\n },\n heading2: {\n classes: \"text-2xl font-semibold\",\n description: \"Medium heading for section titles\",\n },\n heading3: {\n classes: \"text-lg font-semibold\",\n description: \"Small heading for subsections\",\n },\n body: {\n classes: \"text-sf-default\",\n description: \"Default body text\",\n },\n secondary: {\n classes: \"text-sf-subtle\",\n description: \"Muted text for secondary information\",\n },\n success: {\n classes: \"text-sf-link\",\n description: \"Success state text\",\n },\n error: {\n classes: \"text-sf-danger\",\n description: \"Error state text\",\n },\n mono: {\n classes: \"font-mono\",\n description: \"Monospace text for code\",\n },\n \"mono-secondary\": {\n classes: \"font-mono text-sf-subtle\",\n description: \"Muted monospace text\",\n },\n },\n size: {\n xs: {\n classes: \"text-xs\",\n description: \"Extra small text\",\n },\n sm: {\n classes: \"text-sm\",\n description: \"Small text\",\n },\n base: {\n classes: \"text-base\",\n description: \"Default text size\",\n },\n lg: {\n classes: \"text-lg\",\n description: \"Large text\",\n },\n },\n} as const;\n\nexport const SF_TEXT_DEFAULT_VARIANTS = {\n variant: \"body\",\n size: \"base\",\n} as const;\n\n/**\n * SF_TEXT_STYLING - Typography metadata for Figma generator\n *\n * This export provides structured styling information extracted from text.tsx\n * for use by the Figma plugin generator. It documents font sizes, weights,\n * colors, and font families used across all Text variants.\n *\n * Source of truth chain:\n * text.tsx (this file) → component-registry.json → text.ts (Figma generator)\n */\nexport const SF_TEXT_STYLING = {\n fontSizes: {\n xs: 12,\n sm: 14,\n base: 16,\n lg: 18,\n xl: 20,\n \"2xl\": 24,\n \"3xl\": 30,\n },\n fontWeights: {\n normal: 400,\n medium: 500,\n semibold: 600,\n },\n baseColor: \"text-sf-default\",\n variantColors: {\n body: \"text-sf-default\",\n secondary: \"text-sf-subtle\",\n success: \"text-sf-link\",\n error: \"text-sf-danger\",\n mono: \"text-sf-default\",\n \"mono-secondary\": \"text-sf-subtle\",\n },\n fontFamilies: {\n default: \"sans-serif\",\n mono: \"monospace\",\n },\n} as const;\n\n// Derived types from SF_TEXT_VARIANTS\nexport type SFTextVariant = keyof typeof SF_TEXT_VARIANTS.variant;\nexport type SFTextSize = keyof typeof SF_TEXT_VARIANTS.size;\n\nexport interface SFTextVariantsProps {\n variant?: SFTextVariant;\n size?: SFTextSize;\n}\n\nexport function textVariants({\n variant = SF_TEXT_DEFAULT_VARIANTS.variant,\n size = SF_TEXT_DEFAULT_VARIANTS.size,\n}: SFTextVariantsProps = {}) {\n return cn(\n SF_TEXT_VARIANTS.variant[variant].classes,\n SF_TEXT_VARIANTS.size[size].classes\n );\n}\n\n// Legacy types for backwards compatibility\ntype Heading = \"heading1\" | \"heading2\" | \"heading3\";\ntype Copy = \"body\" | \"secondary\" | \"success\" | \"error\";\ntype Monospace = \"mono\" | \"mono-secondary\";\ntype TextSize = SFTextSize;\ntype TextVariant = SFTextVariant;\n\ntype BaseTextProps = Omit<\n ComponentPropsWithoutRef<\"span\">,\n \"className\" | \"style\"\n> & {\n DANGEROUS_className?: string;\n DANGEROUS_style?: CSSProperties;\n as?: ElementType;\n};\n\ntype TextPropsInternal<Variant extends TextVariant = \"body\"> = BaseTextProps &\n (Variant extends Copy\n ? {\n variant?: Variant;\n bold?: boolean;\n size?: TextSize;\n }\n : Variant extends Monospace\n ? {\n variant?: Variant;\n bold?: never;\n size?: \"lg\";\n }\n : Variant extends Heading\n ? {\n variant?: Variant;\n bold?: never;\n size?: never;\n }\n : never);\n\n/**\n * Text component props.\n *\n * @example\n * ```tsx\n * <Text variant=\"heading1\">Page Title</Text>\n * <Text variant=\"body\">Default paragraph text.</Text>\n * <Text variant=\"secondary\" size=\"sm\">Muted helper text</Text>\n * <Text variant=\"error\">Something went wrong</Text>\n * <Text variant=\"mono\">console.log(\"code\")</Text>\n * ```\n */\nexport interface TextProps {\n /**\n * Text style variant. Determines color, font, and weight.\n * - `\"heading1\"` — Large page title (30px, semibold)\n * - `\"heading2\"` — Section title (24px, semibold)\n * - `\"heading3\"` — Subsection title (18px, semibold)\n * - `\"body\"` — Default body text\n * - `\"secondary\"` — Muted text for secondary information\n * - `\"success\"` — Success state text\n * - `\"error\"` — Error state text\n * - `\"mono\"` — Monospace text for code\n * - `\"mono-secondary\"` — Muted monospace text\n * @default \"body\"\n */\n variant?: SFTextVariant;\n /**\n * Text size (only applies to body/secondary/success/error variants).\n * - `\"xs\"` — 12px\n * - `\"sm\"` — 14px\n * - `\"base\"` — 16px\n * - `\"lg\"` — 18px\n * @default \"base\"\n */\n size?: SFTextSize;\n /** Whether to use bold font weight (only applies to body variants). */\n bold?: boolean;\n /** The HTML element type to render as (e.g. `\"span\"`, `\"p\"`, `\"h1\"`). Auto-selected based on variant if omitted. */\n as?: ElementType;\n /** Text content. */\n children?: React.ReactNode;\n}\n\n/**\n * Typography component for rendering text with consistent styling.\n * Automatically selects the appropriate HTML element based on variant\n * (`h1`/`h2`/`h3` for headings, `p` for body, `span` for mono).\n *\n * @example\n * ```tsx\n * <Text variant=\"heading1\">Dashboard</Text>\n * <Text>Default body text</Text>\n * ```\n */\nfunction _Text<Variant extends TextVariant = \"body\">(\n {\n variant = \"body\" as Variant,\n bold = false,\n size = \"base\",\n children,\n DANGEROUS_className,\n DANGEROUS_style,\n as,\n ...props\n }: TextPropsInternal<Variant>,\n ref: ForwardedRef<HTMLHeadingElement>\n) {\n const isCopy = [\"body\", \"secondary\", \"success\", \"error\"].includes(variant);\n const isMono = [\"mono\", \"mono-secondary\"].includes(variant);\n\n const Component = useMemo(() => {\n if (as) return as;\n if (variant === \"heading1\") return \"h1\";\n if (variant === \"heading2\") return \"h2\";\n if (variant === \"heading3\") return \"h3\";\n if ([\"mono\", \"mono-secondary\"].includes(variant)) return \"span\";\n return \"p\";\n }, [variant, as]);\n\n return (\n <Component\n ref={ref}\n className={cn(\n \"text-sf-default\",\n SF_TEXT_VARIANTS.variant[variant].classes,\n isCopy ? SF_TEXT_VARIANTS.size[size].classes : \"\",\n isCopy && bold ? \"font-medium\" : \"\",\n // Monospace fonts need to be 1pt smaller than body text to optically match\n isMono &&\n (size === \"lg\"\n ? SF_TEXT_VARIANTS.size.base.classes\n : SF_TEXT_VARIANTS.size.sm.classes),\n DANGEROUS_className\n )}\n style={DANGEROUS_style}\n {...props}\n >\n {children}\n </Component>\n );\n}\n\nexport const Text = forwardRef(_Text) as <Variant extends TextVariant = \"body\">(\n props: TextPropsInternal<Variant> & {\n ref?: ForwardedRef<ElementRef<\"span\">>;\n }\n) => React.ReactElement;\n"],"mappings":";;;;;;AAaA,IAAa,mBAAmB;CAC9B,SAAS;EACP,UAAU;GACR,SAAS;GACT,aAAa;GACd;EACD,UAAU;GACR,SAAS;GACT,aAAa;GACd;EACD,UAAU;GACR,SAAS;GACT,aAAa;GACd;EACD,MAAM;GACJ,SAAS;GACT,aAAa;GACd;EACD,WAAW;GACT,SAAS;GACT,aAAa;GACd;EACD,SAAS;GACP,SAAS;GACT,aAAa;GACd;EACD,OAAO;GACL,SAAS;GACT,aAAa;GACd;EACD,MAAM;GACJ,SAAS;GACT,aAAa;GACd;EACD,kBAAkB;GAChB,SAAS;GACT,aAAa;GACd;EACF;CACD,MAAM;EACJ,IAAI;GACF,SAAS;GACT,aAAa;GACd;EACD,IAAI;GACF,SAAS;GACT,aAAa;GACd;EACD,MAAM;GACJ,SAAS;GACT,aAAa;GACd;EACD,IAAI;GACF,SAAS;GACT,aAAa;GACd;EACF;CACF;;;;;;;;;;;;AA8JD,SAAS,MACP,EACE,UAAU,QACV,OAAO,OACP,OAAO,QACP,UACA,qBACA,iBACA,IACA,GAAG,SAEL,KACA;CACA,MAAM,SAAS;EAAC;EAAQ;EAAa;EAAW;EAAQ,CAAC,SAAS,QAAQ;CAC1E,MAAM,SAAS,CAAC,QAAQ,iBAAiB,CAAC,SAAS,QAAQ;AAW3D,QACE,oBAVgB,cAAc;AAC9B,MAAI,GAAI,QAAO;AACf,MAAI,YAAY,WAAY,QAAO;AACnC,MAAI,YAAY,WAAY,QAAO;AACnC,MAAI,YAAY,WAAY,QAAO;AACnC,MAAI,CAAC,QAAQ,iBAAiB,CAAC,SAAS,QAAQ,CAAE,QAAO;AACzD,SAAO;IACN,CAAC,SAAS,GAAG,CAAC,EAGf;EACO;EACL,WAAW,GACT,mBACA,iBAAiB,QAAQ,SAAS,SAClC,SAAS,iBAAiB,KAAK,MAAM,UAAU,IAC/C,UAAU,OAAO,gBAAgB,IAEjC,WACG,SAAS,OACN,iBAAiB,KAAK,KAAK,UAC3B,iBAAiB,KAAK,GAAG,UAC/B,oBACD;EACD,OAAO;EACP,GAAI;EAEH;EACS,CAAA;;AAIhB,IAAa,OAAO,WAAW,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tooltip-Cb7QW-7H.js","names":[],"sources":["../src/components/tooltip/tooltip.tsx"],"sourcesContent":["import { Tooltip as TooltipBase } from \"@base-ui/react/tooltip\";\nimport type { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\n/** Tooltip side variant definitions mapping positions to their Tailwind classes. */\nexport const SF_TOOLTIP_VARIANTS = {\n side: {\n top: {\n classes: \"\",\n description: \"Tooltip appears above the trigger\",\n },\n bottom: {\n classes: \"\",\n description: \"Tooltip appears below the trigger\",\n },\n left: {\n classes: \"\",\n description: \"Tooltip appears to the left of the trigger\",\n },\n right: {\n classes: \"\",\n description: \"Tooltip appears to the right of the trigger\",\n },\n },\n} as const;\n\nexport const SF_TOOLTIP_DEFAULT_VARIANTS = {\n side: \"top\",\n} as const;\n\n// Derived types from SF_TOOLTIP_VARIANTS\nexport type SFTooltipSide = keyof typeof SF_TOOLTIP_VARIANTS.side;\n\nexport interface SFTooltipVariantsProps {\n /**\n * Preferred side of the trigger to render the tooltip.\n * - `\"top\"` — Tooltip appears above the trigger\n * - `\"bottom\"` — Tooltip appears below the trigger\n * - `\"left\"` — Tooltip appears to the left of the trigger\n * - `\"right\"` — Tooltip appears to the right of the trigger\n * @default \"top\"\n */\n side?: SFTooltipSide;\n}\n\nexport function tooltipVariants({\n side = SF_TOOLTIP_DEFAULT_VARIANTS.side,\n}: SFTooltipVariantsProps = {}) {\n return cn(\n // Base styles\n \"flex origin-[var(--transform-origin)] flex-col rounded-md bg-sf-elevated px-2.5 py-1.5 text-sm text-sf-default\",\n \"shadow-lg shadow-sf-tip-shadow outline outline-1 outline-sf-fill\",\n \"transition-[transform,opacity] duration-150\",\n \"data-[starting-style]:scale-90 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-90 data-[ending-style]:opacity-0\",\n \"data-[instant]:duration-0\",\n // Apply side-specific styles (currently none, but extensible)\n SF_TOOLTIP_VARIANTS.side[side].classes\n );\n}\n\nexport const TooltipProvider = TooltipBase.Provider;\n\ntype BaseTooltipProps = ComponentPropsWithoutRef<typeof TooltipBase.Root>;\n\ntype TriggerProps = ComponentPropsWithoutRef<typeof TooltipBase.Trigger>;\n\n/** Alignment options for tooltip positioning. Source: PositionerProps[\"align\"] */\ntype TooltipAlign = \"start\" | \"center\" | \"end\";\n\n/**\n * Tooltip component props.\n *\n * @example\n * ```tsx\n * <TooltipProvider>\n * <Tooltip content=\"Add new item\">\n * <Button shape=\"square\" icon={PlusIcon} />\n * </Tooltip>\n * </TooltipProvider>\n * ```\n */\nexport type TooltipProps = BaseTooltipProps &\n SFTooltipVariantsProps & {\n /**\n * Alignment on the axis perpendicular to `side`.\n * - `\"start\"` — Align to the start edge\n * - `\"center\"` — Center-aligned\n * - `\"end\"` — Align to the end edge\n */\n align?: TooltipAlign;\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n /** Content to display inside the tooltip popup. */\n content: ReactNode;\n };\n\n/**\n * Accessible popup that shows additional information on hover/focus.\n * Wrap your app or section with `<TooltipProvider>` to enable delay grouping.\n *\n * @example\n * ```tsx\n * <Tooltip content=\"Save changes\">\n * <Button variant=\"primary\">Save</Button>\n * </Tooltip>\n * ```\n */\nexport function Tooltip({\n content,\n children,\n align,\n side,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipBase.Root {...props}>\n <TooltipBase.Trigger\n className={className}\n render={children as TriggerProps[\"render\"]}\n />\n <TooltipBase.Portal>\n <TooltipBase.Positioner align={align} side={side} sideOffset={10}>\n <TooltipBase.Popup\n className={cn(\n \"flex origin-[var(--transform-origin)] flex-col rounded-md bg-sf-elevated px-2.5 py-1.5 text-sm text-sf-default\",\n \"shadow-lg shadow-sf-tip-shadow outline outline-sf-fill\",\n \"transition-[transform,opacity] duration-150\",\n \"data-[starting-style]:scale-90 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-90 data-[ending-style]:opacity-0\",\n \"data-[instant]:duration-0\",\n \"sf-tooltip-popup\"\n )}\n >\n <TooltipBase.Arrow\n className={cn(\n \"flex\",\n \"data-[side=bottom]:top-[-8px]\",\n \"data-[side=left]:right-[-13px] data-[side=left]:rotate-90\",\n \"data-[side=right]:left-[-13px] data-[side=right]:-rotate-90\",\n \"data-[side=top]:bottom-[-8px] data-[side=top]:rotate-180\"\n )}\n >\n <ArrowSvg />\n </TooltipBase.Arrow>\n {content}\n </TooltipBase.Popup>\n </TooltipBase.Positioner>\n </TooltipBase.Portal>\n </TooltipBase.Root>\n );\n}\n\n/**\n * Arrow SVG with three paths for proper border rendering in both light and dark modes.\n * This approach matches Base UI's tooltip implementation.\n *\n * The three paths are:\n * 1. ArrowFill - The main arrow body, matches tooltip background\n * 2. ArrowOuterStroke - Border visible in light mode only (transparent in dark)\n * 3. ArrowInnerStroke - Border visible in dark mode only (transparent in light)\n *\n * This is necessary because the outer and inner stroke paths have different geometries,\n * and using both ensures the arrow border aligns perfectly with the tooltip's outline\n * in both color modes.\n *\n * @see https://base-ui.com/react/components/tooltip\n */\nfunction ArrowSvg(props: React.ComponentProps<\"svg\">) {\n return (\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\" fill=\"none\" {...props}>\n <path\n d=\"M9.66437 2.60207L4.80758 6.97318C4.07308 7.63423 3.11989 8 2.13172 8H0V10H20V8H18.5349C17.5468 8 16.5936 7.63423 15.8591 6.97318L11.0023 2.60207C10.622 2.2598 10.0447 2.25979 9.66437 2.60207Z\"\n className=\"fill-sf-elevated\"\n />\n <path\n d=\"M8.99542 1.85876C9.75604 1.17425 10.9106 1.17422 11.6713 1.85878L16.5281 6.22989C17.0789 6.72568 17.7938 7.00001 18.5349 7.00001L15.89 7L11.0023 2.60207C10.622 2.2598 10.0447 2.2598 9.66436 2.60207L4.77734 7L2.13171 7.00001C2.87284 7.00001 3.58774 6.72568 4.13861 6.22989L8.99542 1.85876Z\"\n className=\"fill-sf-tip-shadow\"\n />\n <path\n d=\"M10.3333 3.34539L5.47654 7.71648C4.55842 8.54279 3.36693 9 2.13172 9H0V8H2.13172C3.11989 8 4.07308 7.63423 4.80758 6.97318L9.66437 2.60207C10.0447 2.25979 10.622 2.2598 11.0023 2.60207L15.8591 6.97318C16.5936 7.63423 17.5468 8 18.5349 8H20V9H18.5349C17.2998 9 16.1083 8.54278 15.1901 7.71648L10.3333 3.34539Z\"\n className=\"fill-sf-tip-stroke\"\n />\n </svg>\n );\n}\n"],"mappings":";;;;;AA8DA,IAAa,kBAAkB,QAAY;;;;;;;;;;;;AA+C3C,SAAgB,UAAQ,EACtB,SACA,UACA,OACA,MACA,WACA,GAAG,SACY;AACf,QACE,qBAAC,QAAY,MAAb;EAAkB,GAAI;YAAtB,CACE,oBAAC,QAAY,SAAb;GACa;GACX,QAAQ;GACR,CAAA,EACF,oBAAC,QAAY,QAAb,EAAA,UACE,oBAAC,QAAY,YAAb;GAA+B;GAAa;GAAM,YAAY;aAC5D,qBAAC,QAAY,OAAb;IACE,WAAW,GACT,kHACA,0DACA,+CACA,kEACA,8DACA,6BACA,mBACD;cATH,CAWE,oBAAC,QAAY,OAAb;KACE,WAAW,GACT,QACA,iCACA,6DACA,+DACA,2DACD;eAED,oBAAC,UAAD,EAAY,CAAA;KACM,CAAA,EACnB,QACiB;;GACG,CAAA,EACN,CAAA,CACJ;;;;;;;;;;;;;;;;;;AAmBvB,SAAS,SAAS,OAAoC;AACpD,QACE,qBAAC,OAAD;EAAK,OAAM;EAAK,QAAO;EAAK,SAAQ;EAAY,MAAK;EAAO,GAAI;YAAhE;GACE,oBAAC,QAAD;IACE,GAAE;IACF,WAAU;IACV,CAAA;GACF,oBAAC,QAAD;IACE,GAAE;IACF,WAAU;IACV,CAAA;GACF,oBAAC,QAAD;IACE,GAAE;IACF,WAAU;IACV,CAAA;GACE"}