@signalflare-ai/ui 1.1.0 → 1.3.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 (362) hide show
  1. package/CHANGELOG.md +102 -5
  2. package/README.md +1 -1
  3. package/ai/component-registry.json +531 -79
  4. package/ai/component-registry.md +4067 -6
  5. package/ai/schemas.ts +6 -1
  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-CBfz5XEf.js} +4 -4
  10. package/dist/{ai-actions-DSVeQn4e.js.map → ai-actions-CBfz5XEf.js.map} +1 -1
  11. package/dist/{ai-agent-card-BXHwhWAU.js → ai-agent-card-CByAUe0q.js} +3 -3
  12. package/dist/ai-agent-card-CByAUe0q.js.map +1 -0
  13. package/dist/{ai-approval-aa0qvjFN.js → ai-approval-Ci8N70a7.js} +4 -3
  14. package/dist/{ai-approval-aa0qvjFN.js.map → ai-approval-Ci8N70a7.js.map} +1 -1
  15. package/dist/{ai-code-block-BgtIxtZZ.js → ai-code-block-P9TJHvaC.js} +37 -39
  16. package/dist/ai-code-block-P9TJHvaC.js.map +1 -0
  17. package/dist/ai-conversation-Qslfdi1t.js +228 -0
  18. package/dist/ai-conversation-Qslfdi1t.js.map +1 -0
  19. package/dist/{ai-info-banner-uFxHHwBA.js → ai-info-banner-B_9vtGK3.js} +8 -4
  20. package/dist/ai-info-banner-B_9vtGK3.js.map +1 -0
  21. package/dist/{ai-message-BjnFznXy.js → ai-message-Ci3gwM7G.js} +29 -10
  22. package/dist/ai-message-Ci3gwM7G.js.map +1 -0
  23. package/dist/{ai-mission-header-08__gULL.js → ai-mission-header-CaBc19-t.js} +2 -2
  24. package/dist/{ai-mission-header-08__gULL.js.map → ai-mission-header-CaBc19-t.js.map} +1 -1
  25. package/dist/{ai-part-group-DBtgTgAn.js → ai-part-group-Dx1Mr92B.js} +5 -4
  26. package/dist/ai-part-group-Dx1Mr92B.js.map +1 -0
  27. package/dist/{ai-prompt-input-CuluUzpf.js → ai-prompt-input-Bm4XoSj2.js} +44 -55
  28. package/dist/ai-prompt-input-Bm4XoSj2.js.map +1 -0
  29. package/dist/{ai-question-CHHoDJMg.js → ai-question-OyJovxGe.js} +4 -3
  30. package/dist/{ai-question-CHHoDJMg.js.map → ai-question-OyJovxGe.js.map} +1 -1
  31. package/dist/{ai-reasoning-CnL6ZSr5.js → ai-reasoning-BLfBXx3F.js} +9 -5
  32. package/dist/ai-reasoning-BLfBXx3F.js.map +1 -0
  33. package/dist/{ai-response-BEUg3xvd.js → ai-response-hbVCZJmo.js} +9 -4
  34. package/dist/ai-response-hbVCZJmo.js.map +1 -0
  35. package/dist/{ai-shimmer-By5_L05p.js → ai-shimmer-BamNMNK3.js} +2 -2
  36. package/dist/{ai-shimmer-By5_L05p.js.map → ai-shimmer-BamNMNK3.js.map} +1 -1
  37. package/dist/{ai-status-badge-BGYGWYF6.js → ai-status-badge-BZLczdkI.js} +2 -2
  38. package/dist/{ai-status-badge-BGYGWYF6.js.map → ai-status-badge-BZLczdkI.js.map} +1 -1
  39. package/dist/{ai-streaming-text-CMfoThV0.js → ai-streaming-text-DgYu64UH.js} +44 -16
  40. package/dist/ai-streaming-text-DgYu64UH.js.map +1 -0
  41. package/dist/{ai-subagent-DcPRqkAA.js → ai-subagent-p97AI1h9.js} +14 -6
  42. package/dist/ai-subagent-p97AI1h9.js.map +1 -0
  43. package/dist/{ai-suggestion-MgeCg5Ar.js → ai-suggestion-Bj6vF7CT.js} +3 -3
  44. package/dist/{ai-suggestion-MgeCg5Ar.js.map → ai-suggestion-Bj6vF7CT.js.map} +1 -1
  45. package/dist/{ai-task-list-Da9zIm00.js → ai-task-list-C_UQYpk9.js} +15 -6
  46. package/dist/ai-task-list-C_UQYpk9.js.map +1 -0
  47. package/dist/{ai-timeline-Cwu045IR.js → ai-timeline-CePL1LOU.js} +3 -3
  48. package/dist/ai-timeline-CePL1LOU.js.map +1 -0
  49. package/dist/{ai-tool-Cn1O4xjP.js → ai-tool-CfRcwmHT.js} +35 -16
  50. package/dist/ai-tool-CfRcwmHT.js.map +1 -0
  51. package/dist/{ai-usage-bar-DjS12DMp.js → ai-usage-bar-45pVRCGA.js} +2 -2
  52. package/dist/{ai-usage-bar-DjS12DMp.js.map → ai-usage-bar-45pVRCGA.js.map} +1 -1
  53. package/dist/{badge-D_eaA6wv.js → badge-Beb-6uut.js} +5 -5
  54. package/dist/{badge-D_eaA6wv.js.map → badge-Beb-6uut.js.map} +1 -1
  55. package/dist/{banner-B_6oBrsu.js → banner-CCEksxPg.js} +8 -3
  56. package/dist/banner-CCEksxPg.js.map +1 -0
  57. package/dist/{breadcrumbs-BlmeYfgq.js → breadcrumbs-HiTmgaZ4.js} +5 -5
  58. package/dist/{breadcrumbs-BlmeYfgq.js.map → breadcrumbs-HiTmgaZ4.js.map} +1 -1
  59. package/dist/{button-De0267YU.js → button-BHOgXJRU.js} +4 -4
  60. package/dist/{button-De0267YU.js.map → button-BHOgXJRU.js.map} +1 -1
  61. package/dist/catalog.js +1 -1
  62. package/dist/catalog.js.map +1 -1
  63. package/dist/{chart-BK3sVPnD.js → chart-B9FfZdKs.js} +7 -7
  64. package/dist/chart-B9FfZdKs.js.map +1 -0
  65. package/dist/{checkbox-DYhUmZNw.js → checkbox-Cy_OCyay.js} +3 -3
  66. package/dist/{checkbox-DYhUmZNw.js.map → checkbox-Cy_OCyay.js.map} +1 -1
  67. package/dist/{clipboard-text-ssybngLw.js → clipboard-text-CKSvNp9L.js} +6 -5
  68. package/dist/clipboard-text-CKSvNp9L.js.map +1 -0
  69. package/dist/{cn-YROP2_ox.js → cn-CmAOpn49.js} +2 -2
  70. package/dist/{cn-YROP2_ox.js.map → cn-CmAOpn49.js.map} +1 -1
  71. package/dist/{code-Cx-QSoOT.js → code-JsQz-0G_.js} +4 -4
  72. package/dist/{code-Cx-QSoOT.js.map → code-JsQz-0G_.js.map} +1 -1
  73. package/dist/{collapsible-DWsXeXmS.js → collapsible-1kOZ-89L.js} +2 -2
  74. package/dist/{collapsible-DWsXeXmS.js.map → collapsible-1kOZ-89L.js.map} +1 -1
  75. package/dist/{combobox-C0iW6a0r.js → combobox-CQwDmqgA.js} +4 -4
  76. package/dist/{combobox-C0iW6a0r.js.map → combobox-CQwDmqgA.js.map} +1 -1
  77. package/dist/command-line/cli.js +3 -3
  78. package/dist/{command-palette-DGzioeki.js → command-palette-Bkuv3e6o.js} +20 -5
  79. package/dist/command-palette-Bkuv3e6o.js.map +1 -0
  80. package/dist/components/ai-actions.js +1 -1
  81. package/dist/components/ai-agent-card.js +1 -1
  82. package/dist/components/ai-approval.js +1 -1
  83. package/dist/components/ai-code-block.js +1 -1
  84. package/dist/components/ai-conversation.js +2 -2
  85. package/dist/components/ai-info-banner.js +1 -1
  86. package/dist/components/ai-message.js +1 -1
  87. package/dist/components/ai-mission-header.js +1 -1
  88. package/dist/components/ai-part-group.js +1 -1
  89. package/dist/components/ai-prompt-input.js +1 -1
  90. package/dist/components/ai-question.js +1 -1
  91. package/dist/components/ai-reasoning.js +1 -1
  92. package/dist/components/ai-response.js +1 -1
  93. package/dist/components/ai-shimmer.js +1 -1
  94. package/dist/components/ai-status-badge.js +1 -1
  95. package/dist/components/ai-streaming-text.js +2 -2
  96. package/dist/components/ai-subagent.js +1 -1
  97. package/dist/components/ai-suggestion.js +1 -1
  98. package/dist/components/ai-task-list.js +1 -1
  99. package/dist/components/ai-timeline.js +1 -1
  100. package/dist/components/ai-tool.js +1 -1
  101. package/dist/components/ai-usage-bar.js +1 -1
  102. package/dist/components/badge.js +1 -1
  103. package/dist/components/banner.js +1 -1
  104. package/dist/components/breadcrumbs.js +1 -1
  105. package/dist/components/button.js +1 -1
  106. package/dist/components/chart.js +2 -2
  107. package/dist/components/checkbox.js +1 -1
  108. package/dist/components/clipboard-text.js +1 -1
  109. package/dist/components/code.js +1 -1
  110. package/dist/components/collapsible.js +1 -1
  111. package/dist/components/combobox.js +1 -1
  112. package/dist/components/command-palette.js +1 -1
  113. package/dist/components/data-grid.js +1 -1
  114. package/dist/components/date-picker.js +1 -1
  115. package/dist/components/date-range-picker.js +1 -1
  116. package/dist/components/dialog.js +1 -1
  117. package/dist/components/dropdown.js +1 -1
  118. package/dist/components/empty.js +1 -1
  119. package/dist/components/field.js +1 -1
  120. package/dist/components/filters.js +1 -1
  121. package/dist/components/flow.js +1 -1
  122. package/dist/components/grid.js +1 -1
  123. package/dist/components/input.js +2 -2
  124. package/dist/components/label.js +1 -1
  125. package/dist/components/layer-card.js +1 -1
  126. package/dist/components/link.js +3 -3
  127. package/dist/components/link.js.map +1 -1
  128. package/dist/components/loader.js +2 -2
  129. package/dist/components/menubar.js +1 -1
  130. package/dist/components/meter.js +1 -1
  131. package/dist/components/pagination.js +1 -1
  132. package/dist/components/popover.js +1 -1
  133. package/dist/components/radio.js +1 -1
  134. package/dist/components/select.js +1 -1
  135. package/dist/components/sensitive-input.js +1 -1
  136. package/dist/components/sidebar.js +1 -1
  137. package/dist/components/signalflare-ai-logo.js +1 -1
  138. package/dist/components/sparkline.js +1 -1
  139. package/dist/components/stat-card.js +1 -1
  140. package/dist/components/surface.js +1 -1
  141. package/dist/components/switch.js +1 -1
  142. package/dist/components/table.js +1 -1
  143. package/dist/components/tabs.js +1 -1
  144. package/dist/components/text-roll.js +1 -1
  145. package/dist/components/text.js +1 -1
  146. package/dist/components/theme-toggle.js +1 -1
  147. package/dist/components/toast.js +1 -1
  148. package/dist/components/tooltip.js +1 -1
  149. package/dist/components/use-agent-harness.js +1 -1
  150. package/dist/{data-grid-CG76N_hK.js → data-grid-DDSFMHud.js} +136 -53
  151. package/dist/data-grid-DDSFMHud.js.map +1 -0
  152. package/dist/{date-picker-Dqg9L4xu.js → date-picker-O34AqG3f.js} +2 -2
  153. package/dist/{date-picker-Dqg9L4xu.js.map → date-picker-O34AqG3f.js.map} +1 -1
  154. package/dist/{date-range-picker-D75LLINc.js → date-range-picker-YKYvum_r.js} +29 -39
  155. package/dist/{date-range-picker-D75LLINc.js.map → date-range-picker-YKYvum_r.js.map} +1 -1
  156. package/dist/{dialog-CyHEQXEY.js → dialog-DYqu4aDO.js} +3 -3
  157. package/dist/{dialog-CyHEQXEY.js.map → dialog-DYqu4aDO.js.map} +1 -1
  158. package/dist/{dist-1-gcEL2L.js → dist-6AtBsaJE.js} +153 -47
  159. package/dist/dist-6AtBsaJE.js.map +1 -0
  160. package/dist/{dropdown-qnEYRFXZ.js → dropdown-XzbnRLYR.js} +15 -5
  161. package/dist/dropdown-XzbnRLYR.js.map +1 -0
  162. package/dist/{echart-DURZEyai.js → echart-DGBIVAv1.js} +23 -57
  163. package/dist/{echart-DURZEyai.js.map → echart-DGBIVAv1.js.map} +1 -1
  164. package/dist/{empty-D2TypIId.js → empty-C1tAkawe.js} +12 -7
  165. package/dist/empty-C1tAkawe.js.map +1 -0
  166. package/dist/{field-Y_UK1_Cg.js → field-DBpFzzBS.js} +3 -3
  167. package/dist/{field-Y_UK1_Cg.js.map → field-DBpFzzBS.js.map} +1 -1
  168. package/dist/{filters-Bw_U6ZTx.js → filters-SmEl93za.js} +10 -10
  169. package/dist/filters-SmEl93za.js.map +1 -0
  170. package/dist/{flow-BRsYUCJa.js → flow-BLzgbq1T.js} +6 -6
  171. package/dist/flow-BLzgbq1T.js.map +1 -0
  172. package/dist/genui.js +2 -2
  173. package/dist/genui.js.map +1 -1
  174. package/dist/{grid-qUAN9hFx.js → grid-CifjQL-5.js} +2 -2
  175. package/dist/{grid-qUAN9hFx.js.map → grid-CifjQL-5.js.map} +1 -1
  176. package/dist/{highlight-to-react-ClEfL81q.js → highlight-to-react-DN9dUCS2.js} +9 -15
  177. package/dist/highlight-to-react-DN9dUCS2.js.map +1 -0
  178. package/dist/index.js +72 -72
  179. package/dist/index.js.map +1 -1
  180. package/dist/{input-DddtBN-g.js → input-COmx2M_R.js} +5 -5
  181. package/dist/{input-DddtBN-g.js.map → input-COmx2M_R.js.map} +1 -1
  182. package/dist/{input-DXYUjGgD.js → input-GkfMQZC_.js} +3 -3
  183. package/dist/{input-DXYUjGgD.js.map → input-GkfMQZC_.js.map} +1 -1
  184. package/dist/{label-QtJxtJ4u.js → label-CiGZ464N.js} +3 -3
  185. package/dist/{label-QtJxtJ4u.js.map → label-CiGZ464N.js.map} +1 -1
  186. package/dist/{layer-card-BME0eljh.js → layer-card-8l8GuLQr.js} +2 -2
  187. package/dist/{layer-card-BME0eljh.js.map → layer-card-8l8GuLQr.js.map} +1 -1
  188. package/dist/layout-CWBE0qwx.js +6207 -0
  189. package/dist/layout-CWBE0qwx.js.map +1 -0
  190. package/dist/{link-provider-BUZKXaNE.js → link-provider-BSn8YJon.js} +2 -2
  191. package/dist/link-provider-BSn8YJon.js.map +1 -0
  192. package/dist/{loader-DAcc-Uag.js → loader-BEMz8pJO.js} +1 -1
  193. package/dist/{loader-DAcc-Uag.js.map → loader-BEMz8pJO.js.map} +1 -1
  194. package/dist/measured-text-CXkdw9Yr.js +305 -0
  195. package/dist/measured-text-CXkdw9Yr.js.map +1 -0
  196. package/dist/{menubar-C8NzAjfd.js → menubar-CoOr4ocj.js} +3 -3
  197. package/dist/{menubar-C8NzAjfd.js.map → menubar-CoOr4ocj.js.map} +1 -1
  198. package/dist/{meter-CpmTenEr.js → meter-Pf_VOl59.js} +2 -2
  199. package/dist/{meter-CpmTenEr.js.map → meter-Pf_VOl59.js.map} +1 -1
  200. package/dist/{pagination-BVqdlONY.js → pagination-DSY279Ta.js} +2 -2
  201. package/dist/{pagination-BVqdlONY.js.map → pagination-DSY279Ta.js.map} +1 -1
  202. package/dist/{popover-BRQZ2b6z.js → popover-BY-e9co1.js} +2 -2
  203. package/dist/{popover-BRQZ2b6z.js.map → popover-BY-e9co1.js.map} +1 -1
  204. package/dist/{radio-BNSwOt3B.js → radio-DZwL13j0.js} +2 -2
  205. package/dist/{radio-BNSwOt3B.js.map → radio-DZwL13j0.js.map} +1 -1
  206. package/dist/{select-1w2aebGQ.js → select-BFifYqHA.js} +6 -6
  207. package/dist/{select-1w2aebGQ.js.map → select-BFifYqHA.js.map} +1 -1
  208. package/dist/{sensitive-input-82Cez3vj.js → sensitive-input-DHLZcM73.js} +4 -4
  209. package/dist/{sensitive-input-82Cez3vj.js.map → sensitive-input-DHLZcM73.js.map} +1 -1
  210. package/dist/{sidebar-CAsCmSpM.js → sidebar-odGsdvG4.js} +6 -7
  211. package/dist/sidebar-odGsdvG4.js.map +1 -0
  212. package/dist/{signalflare-ai-logo-DDhxMJD6.js → signalflare-ai-logo-CNaDT_w8.js} +2 -2
  213. package/dist/{signalflare-ai-logo-DDhxMJD6.js.map → signalflare-ai-logo-CNaDT_w8.js.map} +1 -1
  214. package/dist/{skeleton-line-Do3UmGk9.js → skeleton-line-CxxYVTO2.js} +2 -2
  215. package/dist/{skeleton-line-Do3UmGk9.js.map → skeleton-line-CxxYVTO2.js.map} +1 -1
  216. package/dist/{sparkline-DdbeM4Ai.js → sparkline-BQ-4j2W2.js} +2 -2
  217. package/dist/{sparkline-DdbeM4Ai.js.map → sparkline-BQ-4j2W2.js.map} +1 -1
  218. package/dist/src/blocks/agent-harness/agent-harness.d.ts.map +1 -1
  219. package/dist/src/blocks/agent-harness/agent-harness.tsx +40 -16
  220. package/dist/src/blocks/commander/commander.tsx +15 -15
  221. package/dist/src/blocks/map-block/map-block.d.ts.map +1 -1
  222. package/dist/src/blocks/map-block/map-block.tsx +11 -7
  223. package/dist/src/components/ai-approval/ai-approval.d.ts.map +1 -1
  224. package/dist/src/components/ai-code-block/ai-code-block.d.ts +14 -13
  225. package/dist/src/components/ai-code-block/ai-code-block.d.ts.map +1 -1
  226. package/dist/src/components/ai-conversation/ai-conversation.d.ts +69 -37
  227. package/dist/src/components/ai-conversation/ai-conversation.d.ts.map +1 -1
  228. package/dist/src/components/ai-conversation/index.d.ts +2 -1
  229. package/dist/src/components/ai-conversation/index.d.ts.map +1 -1
  230. package/dist/src/components/ai-conversation/measurement-constants.d.ts +30 -0
  231. package/dist/src/components/ai-conversation/measurement-constants.d.ts.map +1 -0
  232. package/dist/src/components/ai-info-banner/ai-info-banner.d.ts.map +1 -1
  233. package/dist/src/components/ai-message/ai-message.d.ts +3 -0
  234. package/dist/src/components/ai-message/ai-message.d.ts.map +1 -1
  235. package/dist/src/components/ai-part-group/ai-part-group.d.ts.map +1 -1
  236. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts +13 -3
  237. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
  238. package/dist/src/components/ai-prompt-input/controller.d.ts.map +1 -1
  239. package/dist/src/components/ai-prompt-input/index.d.ts +1 -1
  240. package/dist/src/components/ai-prompt-input/index.d.ts.map +1 -1
  241. package/dist/src/components/ai-prompt-input/types.d.ts.map +1 -1
  242. package/dist/src/components/ai-question/ai-question.d.ts.map +1 -1
  243. package/dist/src/components/ai-reasoning/ai-reasoning.d.ts.map +1 -1
  244. package/dist/src/components/ai-response/ai-response.d.ts +12 -1
  245. package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
  246. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts +27 -0
  247. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts.map +1 -1
  248. package/dist/src/components/ai-streaming-text/index.d.ts +1 -1
  249. package/dist/src/components/ai-streaming-text/index.d.ts.map +1 -1
  250. package/dist/src/components/ai-subagent/ai-subagent.d.ts.map +1 -1
  251. package/dist/src/components/ai-task-list/ai-task-list.d.ts.map +1 -1
  252. package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
  253. package/dist/src/components/banner/banner.d.ts.map +1 -1
  254. package/dist/src/components/chart/echart.d.ts.map +1 -1
  255. package/dist/src/components/clipboard-text/clipboard-text.d.ts.map +1 -1
  256. package/dist/src/components/data-grid/data-grid.d.ts +2 -1
  257. package/dist/src/components/data-grid/data-grid.d.ts.map +1 -1
  258. package/dist/src/components/data-grid/features.d.ts +20 -0
  259. package/dist/src/components/data-grid/features.d.ts.map +1 -0
  260. package/dist/src/components/data-grid/types.d.ts +38 -7
  261. package/dist/src/components/data-grid/types.d.ts.map +1 -1
  262. package/dist/src/components/empty/empty.d.ts.map +1 -1
  263. package/dist/src/components/filters/filters.d.ts.map +1 -1
  264. package/dist/src/components/flow/use-children.d.ts +1 -1
  265. package/dist/src/components/link/link.d.ts.map +1 -1
  266. package/dist/src/components/sidebar/sidebar.d.ts +1 -1
  267. package/dist/src/components/signalflare-ai-logo/signalflare-ai-logo.d.ts.map +1 -1
  268. package/dist/src/components/stat-card/stat-card.d.ts +5 -0
  269. package/dist/src/components/stat-card/stat-card.d.ts.map +1 -1
  270. package/dist/src/components/text/text.d.ts +36 -1
  271. package/dist/src/components/text/text.d.ts.map +1 -1
  272. package/dist/src/components/text-roll/text-roll.d.ts.map +1 -1
  273. package/dist/src/components/theme-toggle/theme-toggle.d.ts.map +1 -1
  274. package/dist/src/components/toast/toast.d.ts.map +1 -1
  275. package/dist/src/components/tooltip/tooltip.d.ts.map +1 -1
  276. package/dist/src/index.d.ts +2 -2
  277. package/dist/src/index.d.ts.map +1 -1
  278. package/dist/src/utils/highlight-to-react.d.ts.map +1 -1
  279. package/dist/src/utils/index.d.ts +2 -0
  280. package/dist/src/utils/index.d.ts.map +1 -1
  281. package/dist/src/utils/measured-text.d.ts +40 -0
  282. package/dist/src/utils/measured-text.d.ts.map +1 -0
  283. package/dist/src/utils/use-measured-text.d.ts +59 -0
  284. package/dist/src/utils/use-measured-text.d.ts.map +1 -0
  285. package/dist/{stat-card-CEZscNh8.js → stat-card-Bspk4XFr.js} +30 -12
  286. package/dist/stat-card-Bspk4XFr.js.map +1 -0
  287. package/dist/styles/sf-binding.css +1 -1
  288. package/dist/styles/sf-standalone.css +2 -2
  289. package/dist/styles/shadcn.css +1 -1
  290. package/dist/styles/theme-minimal.css +9 -9
  291. package/dist/styles/theme-sf.css +14 -20
  292. package/dist/styles/theme-vesper.css +91 -0
  293. package/dist/{surface-BduI7Ehl.js → surface-CWdSFVUx.js} +3 -3
  294. package/dist/{surface-BduI7Ehl.js.map → surface-CWdSFVUx.js.map} +1 -1
  295. package/dist/{switch-CzZBRBL7.js → switch-TA4cByCJ.js} +5 -5
  296. package/dist/switch-TA4cByCJ.js.map +1 -0
  297. package/dist/{table-Rv4JMy0B.js → table-BM8JBGBs.js} +3 -3
  298. package/dist/{table-Rv4JMy0B.js.map → table-BM8JBGBs.js.map} +1 -1
  299. package/dist/{tabs-1cHrYoel.js → tabs-bnH2vGLv.js} +2 -2
  300. package/dist/{tabs-1cHrYoel.js.map → tabs-bnH2vGLv.js.map} +1 -1
  301. package/dist/{text-KJmGkwnf.js → text-iQ0YUFNg.js} +27 -6
  302. package/dist/text-iQ0YUFNg.js.map +1 -0
  303. package/dist/{text-roll-BZ3I1umc.js → text-roll-C3U2jd2u.js} +5 -2
  304. package/dist/text-roll-C3U2jd2u.js.map +1 -0
  305. package/dist/{theme-toggle-Bhu681D7.js → theme-toggle-BTVxD-fD.js} +10 -9
  306. package/dist/theme-toggle-BTVxD-fD.js.map +1 -0
  307. package/dist/{toast-Nw28a5Cx.js → toast-CgZVaAkw.js} +3 -3
  308. package/dist/{toast-Nw28a5Cx.js.map → toast-CgZVaAkw.js.map} +1 -1
  309. package/dist/{tooltip-Cb7QW-7H.js → tooltip-uobk6Oh-.js} +9 -3
  310. package/dist/tooltip-uobk6Oh-.js.map +1 -0
  311. package/dist/{use-agent-harness-BMyF8pTq.js → use-agent-harness-Dl8w6X5O.js} +3 -3
  312. package/dist/{use-agent-harness-BMyF8pTq.js.map → use-agent-harness-Dl8w6X5O.js.map} +1 -1
  313. package/dist/utils.js +4 -3
  314. package/package.json +27 -24
  315. package/scripts/component-registry/discovery.ts +11 -10
  316. package/scripts/component-registry/example-cleanup.ts +8 -8
  317. package/scripts/component-registry/index.ts +6 -6
  318. package/scripts/component-registry/schema-generator.ts +1 -1
  319. package/scripts/component-registry/sub-components.ts +35 -23
  320. package/scripts/component-registry/utils.ts +11 -11
  321. package/scripts/component-registry/variant-parser.ts +17 -15
  322. package/scripts/convert-demos-to-stories.ts +5 -5
  323. package/scripts/css-build.ts +1 -1
  324. package/scripts/theme-generator/config.ts +28 -146
  325. package/scripts/theme-generator/generate-css.ts +1 -2
  326. package/scripts/theme-generator/index.ts +0 -1
  327. package/scripts/theme-generator/migrate.ts +3 -3
  328. package/dist/ai-agent-card-BXHwhWAU.js.map +0 -1
  329. package/dist/ai-code-block-BgtIxtZZ.js.map +0 -1
  330. package/dist/ai-conversation-CArP7C8K.js +0 -184
  331. package/dist/ai-conversation-CArP7C8K.js.map +0 -1
  332. package/dist/ai-info-banner-uFxHHwBA.js.map +0 -1
  333. package/dist/ai-message-BjnFznXy.js.map +0 -1
  334. package/dist/ai-part-group-DBtgTgAn.js.map +0 -1
  335. package/dist/ai-prompt-input-CuluUzpf.js.map +0 -1
  336. package/dist/ai-reasoning-CnL6ZSr5.js.map +0 -1
  337. package/dist/ai-response-BEUg3xvd.js.map +0 -1
  338. package/dist/ai-streaming-text-CMfoThV0.js.map +0 -1
  339. package/dist/ai-subagent-DcPRqkAA.js.map +0 -1
  340. package/dist/ai-task-list-Da9zIm00.js.map +0 -1
  341. package/dist/ai-timeline-Cwu045IR.js.map +0 -1
  342. package/dist/ai-tool-Cn1O4xjP.js.map +0 -1
  343. package/dist/banner-B_6oBrsu.js.map +0 -1
  344. package/dist/chart-BK3sVPnD.js.map +0 -1
  345. package/dist/clipboard-text-ssybngLw.js.map +0 -1
  346. package/dist/command-palette-DGzioeki.js.map +0 -1
  347. package/dist/data-grid-CG76N_hK.js.map +0 -1
  348. package/dist/dist-1-gcEL2L.js.map +0 -1
  349. package/dist/dropdown-qnEYRFXZ.js.map +0 -1
  350. package/dist/empty-D2TypIId.js.map +0 -1
  351. package/dist/filters-Bw_U6ZTx.js.map +0 -1
  352. package/dist/flow-BRsYUCJa.js.map +0 -1
  353. package/dist/highlight-to-react-ClEfL81q.js.map +0 -1
  354. package/dist/link-provider-BUZKXaNE.js.map +0 -1
  355. package/dist/sidebar-CAsCmSpM.js.map +0 -1
  356. package/dist/stat-card-CEZscNh8.js.map +0 -1
  357. package/dist/styles/theme-blue-tint.css +0 -98
  358. package/dist/switch-CzZBRBL7.js.map +0 -1
  359. package/dist/text-KJmGkwnf.js.map +0 -1
  360. package/dist/text-roll-BZ3I1umc.js.map +0 -1
  361. package/dist/theme-toggle-Bhu681D7.js.map +0 -1
  362. package/dist/tooltip-Cb7QW-7H.js.map +0 -1
@@ -26,6 +26,25 @@ Container for a row of AI message action buttons.
26
26
 
27
27
  `text-sf-default`, `text-sf-subtle`
28
28
 
29
+ **Examples:**
30
+
31
+ ```tsx
32
+ <AiActions>
33
+ <AiAction tooltip="Copy">
34
+ <CopyIcon className="size-4" />
35
+ </AiAction>
36
+ <AiAction tooltip="Retry">
37
+ <ArrowCounterClockwiseIcon className="size-4" />
38
+ </AiAction>
39
+ <AiAction tooltip="Thumbs up">
40
+ <ThumbsUpIcon className="size-4" />
41
+ </AiAction>
42
+ <AiAction tooltip="Thumbs down">
43
+ <ThumbsDownIcon className="size-4" />
44
+ </AiAction>
45
+ </AiActions>
46
+ ```
47
+
29
48
  ---
30
49
 
31
50
  ### AiAgentCard
@@ -75,6 +94,105 @@ Container for a row of AI message action buttons.
75
94
 
76
95
  `bg-sf-brand`, `bg-sf-danger`, `bg-sf-elevated`, `bg-sf-fill`, `bg-sf-recessed`, `bg-sf-success`, `bg-sf-tint`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`, `text-sf-success`
77
96
 
97
+ **Examples:**
98
+
99
+ ```tsx
100
+ <div className="flex flex-wrap gap-3">
101
+ <AiAgentCard
102
+ name="Explore"
103
+ agentType="explore"
104
+ status="running"
105
+ modelId="claude-haiku-3.5"
106
+ currentTask="Scanning auth files for deprecated patterns..."
107
+ duration={4200}
108
+ toolCallCount={3}
109
+ />
110
+ <AiAgentCard
111
+ name="Execute"
112
+ agentType="execute"
113
+ status="running"
114
+ modelId="claude-sonnet-4"
115
+ currentTask="Rewriting jwt.ts using jose library..."
116
+ duration={8700}
117
+ toolCallCount={1}
118
+ />
119
+ </div>
120
+ ```
121
+
122
+ ```tsx
123
+ <div className="flex flex-wrap gap-3">
124
+ <AiAgentCard
125
+ name="Explore"
126
+ agentType="explore"
127
+ status="idle"
128
+ modelId="claude-haiku-3.5"
129
+ />
130
+ <AiAgentCard
131
+ name="Plan"
132
+ agentType="plan"
133
+ status="running"
134
+ modelId="claude-sonnet-4"
135
+ currentTask="Drafting migration steps..."
136
+ duration={2100}
137
+ toolCallCount={0}
138
+ />
139
+ <AiAgentCard
140
+ name="Execute"
141
+ agentType="execute"
142
+ status="completed"
143
+ modelId="claude-sonnet-4"
144
+ currentTask="Rewrote 4 files successfully."
145
+ duration={12_400}
146
+ toolCallCount={7}
147
+ />
148
+ <AiAgentCard
149
+ name="Test"
150
+ agentType="test"
151
+ status="error"
152
+ modelId="claude-haiku-3.5"
153
+ currentTask="3 tests failed: auth.spec.ts"
154
+ duration={3200}
155
+ toolCallCount={2}
156
+ />
157
+ </div>
158
+ ```
159
+
160
+ ```tsx
161
+ <div className="flex flex-wrap gap-3">
162
+ <AiAgentCard
163
+ name="Explore"
164
+ agentType="explore"
165
+ status="completed"
166
+ modelId="claude-haiku-3.5"
167
+ duration={4200}
168
+ toolCallCount={5}
169
+ />
170
+ <AiAgentCard
171
+ name="Execute"
172
+ agentType="execute"
173
+ status="running"
174
+ modelId="claude-sonnet-4"
175
+ currentTask="Patching consumers..."
176
+ duration={6100}
177
+ toolCallCount={3}
178
+ selected
179
+ />
180
+ </div>
181
+ ```
182
+
183
+ ```tsx
184
+ <div className="flex flex-wrap gap-2">
185
+ {[
186
+ { name: "Explore", agentType: "explore", status: "completed" as const },
187
+ { name: "Plan", agentType: "plan", status: "completed" as const },
188
+ { name: "Execute", agentType: "execute", status: "running" as const },
189
+ { name: "Review", agentType: "review", status: "idle" as const },
190
+ ].map((agent) => (
191
+ <AiAgentCard key={agent.name} size="sm" {...agent} />
192
+ ))}
193
+ </div>
194
+ ```
195
+
78
196
  ---
79
197
 
80
198
  ### AiApproval
@@ -119,11 +237,47 @@ Approval card for tool calls and plan submissions. Maps to harness events: `tool
119
237
 
120
238
  `bg-sf-base`, `bg-sf-brand`, `bg-sf-elevated`, `border-sf-line`, `border-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`, `text-sf-success`
121
239
 
240
+ **Examples:**
241
+
242
+ ```tsx
243
+ <div className="w-full max-w-md">
244
+ <AiApproval
245
+ kind="tool"
246
+ status={status}
247
+ title="Execute shell command"
248
+ description="rm -rf /tmp/cache"
249
+ onApprove={() => setStatus("approved")}
250
+ onReject={() => setStatus("rejected")}
251
+ />
252
+ </div>
253
+ ```
254
+
255
+ ```tsx
256
+ <div className="w-full max-w-md">
257
+ <AiApproval
258
+ kind="plan"
259
+ status={status}
260
+ title="Deployment plan"
261
+ description="The agent proposes the following steps:"
262
+ items={[
263
+ { id: "1", label: "Run test suite", description: "All 142 tests" },
264
+ { id: "2", label: "Build production bundle" },
265
+ { id: "3", label: "Deploy to staging", description: "us-east-1" },
266
+ { id: "4", label: "Run smoke tests" },
267
+ { id: "5", label: "Promote to production" },
268
+ ]}
269
+ showFeedback
270
+ onApprove={() => setStatus("approved")}
271
+ onReject={() => setStatus("rejected")}
272
+ />
273
+ </div>
274
+ ```
275
+
122
276
  ---
123
277
 
124
278
  ### AiCodeBlock
125
279
 
126
- Displays a code block with monospace formatting and an optional copy button. Does not include a syntax highlighter — avoids the heavy `react-syntax-highlighter` dependency. Wrap with `AiCodeBlockCopyButton` for clipboard support.
280
+ AiCodeBlock component
127
281
 
128
282
  **Type:** component
129
283
 
@@ -149,6 +303,32 @@ Displays a code block with monospace formatting and an optional copy button. Doe
149
303
 
150
304
  `bg-sf-recessed`, `border-sf-line`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`
151
305
 
306
+ **Sub-Components:**
307
+
308
+ This is a compound component. Use these sub-components:
309
+
310
+ #### AiCodeBlock.CopyButton
311
+
312
+ CopyButton sub-component
313
+
314
+ Props:
315
+
316
+ - `timeout`: number
317
+
318
+ **Examples:**
319
+
320
+ ```tsx
321
+ <AiCodeBlock code={CODE} language="tsx">
322
+ <AiCodeBlockCopyButton />
323
+ </AiCodeBlock>
324
+ ```
325
+
326
+ ```tsx
327
+ <AiCodeBlock code="npm install @signalflare-ai/ui">
328
+ <AiCodeBlockCopyButton />
329
+ </AiCodeBlock>
330
+ ```
331
+
152
332
  ---
153
333
 
154
334
  ### AiConversation
@@ -169,6 +349,24 @@ Outer scroll container for a conversation. Sticks to the bottom as new messages
169
349
  - `lang`: string
170
350
  - `title`: string
171
351
 
352
+ **Examples:**
353
+
354
+ ```tsx
355
+ <div className="h-80 w-full overflow-hidden rounded-lg border border-sf-line">
356
+ <AiConversation>
357
+ <AiConversationContent>
358
+ {MESSAGES.map((m) => (
359
+ <AiMessage key={m.id} from={m.from}>
360
+ <AiMessageContent>
361
+ <AiResponse>{m.text}</AiResponse>
362
+ </AiMessageContent>
363
+ </AiMessage>
364
+ ))}
365
+ </AiConversationContent>
366
+ </AiConversation>
367
+ </div>
368
+ ```
369
+
172
370
  ---
173
371
 
174
372
  ### AiInfoBanner
@@ -199,6 +397,18 @@ Inline conversation banner for system notices. Renders as a compact, horizontall
199
397
 
200
398
  `border-sf-danger`, `border-sf-info`, `border-sf-line`, `text-sf-danger`, `text-sf-info`, `text-sf-subtle`
201
399
 
400
+ **Examples:**
401
+
402
+ ```tsx
403
+ <div className="flex w-full flex-col gap-3">
404
+ <AiInfoBanner level="info">
405
+ Follow-up message queued — will send after current response completes
406
+ </AiInfoBanner>
407
+ <AiInfoBanner level="change">Switched to claude-opus-4-6</AiInfoBanner>
408
+ <AiInfoBanner level="error">Connection lost. Retrying in 3s…</AiInfoBanner>
409
+ </div>
410
+ ```
411
+
202
412
  ---
203
413
 
204
414
  ### AiMessage
@@ -227,6 +437,37 @@ Root message container. Sets layout, group class, and role context.
227
437
 
228
438
  `bg-sf-control`, `bg-sf-overlay`, `bg-sf-tint`, `text-sf-default`, `text-sf-subtle`
229
439
 
440
+ **Examples:**
441
+
442
+ ```tsx
443
+ <div className="flex w-full flex-col gap-2 p-4">
444
+ <AiMessage from="user">
445
+ <AiMessageContent>What is the capital of France?</AiMessageContent>
446
+ </AiMessage>
447
+ <AiMessage from="assistant">
448
+ <AiMessageContent>
449
+ <AiResponse>{"The capital of France is **Paris**."}</AiResponse>
450
+ </AiMessageContent>
451
+ <AiMessageToolbar>
452
+ <AiMessageActions>
453
+ <AiMessageAction tooltip="Copy">
454
+ <CopyIcon className="size-4" />
455
+ </AiMessageAction>
456
+ <AiMessageAction tooltip="Retry">
457
+ <ArrowCounterClockwiseIcon className="size-4" />
458
+ </AiMessageAction>
459
+ </AiMessageActions>
460
+ </AiMessageToolbar>
461
+ </AiMessage>
462
+ </div>
463
+ ```
464
+
465
+ ```tsx
466
+ <AiMessage from="user">
467
+ <AiMessageContent>Can you summarise this document?</AiMessageContent>
468
+ </AiMessage>
469
+ ```
470
+
230
471
  ---
231
472
 
232
473
  ### AiMissionHeader
@@ -269,6 +510,116 @@ Root message container. Sets layout, group class, and role context.
269
510
 
270
511
  `bg-sf-base`, `bg-sf-brand`, `bg-sf-danger`, `bg-sf-fill`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
271
512
 
513
+ **Examples:**
514
+
515
+ ```tsx
516
+ <AiMissionHeader
517
+ title="Refactor auth module"
518
+ taskList={{
519
+ title: "Refactor auth module",
520
+ tasks: [
521
+ {
522
+ id: "t1",
523
+ content: "Explore authentication codebase",
524
+ status: "completed",
525
+ priority: "high",
526
+ },
527
+ {
528
+ id: "t2",
529
+ content: "Identify deprecated patterns",
530
+ status: "completed",
531
+ priority: "high",
532
+ },
533
+ {
534
+ id: "t3",
535
+ content: "Write updated auth helpers",
536
+ status: "in_progress",
537
+ priority: "medium",
538
+ },
539
+ {
540
+ id: "t4",
541
+ content: "Update all consumers",
542
+ status: "pending",
543
+ priority: "medium",
544
+ },
545
+ {
546
+ id: "t5",
547
+ content: "Update tests",
548
+ status: "pending",
549
+ priority: "low",
550
+ },
551
+ ],
552
+ }}
553
+ usage={{
554
+ inputTokens: 12_480,
555
+ outputTokens: 3256,
556
+ totalTokens: 15_736,
557
+ cost: 0.04,
558
+ }}
559
+ activeAgentCount={2}
560
+ totalAgentCount={4}
561
+ startedAt={startedAt}
562
+ isRunning
563
+ />
564
+ ```
565
+
566
+ ```tsx
567
+ <AiMissionHeader
568
+ title="Deploy to production"
569
+ taskList={{
570
+ tasks: [
571
+ {
572
+ id: "t1",
573
+ content: "Run tests",
574
+ status: "completed",
575
+ priority: "high",
576
+ },
577
+ {
578
+ id: "t2",
579
+ content: "Build artifacts",
580
+ status: "completed",
581
+ priority: "high",
582
+ },
583
+ {
584
+ id: "t3",
585
+ content: "Deploy to staging",
586
+ status: "completed",
587
+ priority: "medium",
588
+ },
589
+ {
590
+ id: "t4",
591
+ content: "Smoke test",
592
+ status: "completed",
593
+ priority: "medium",
594
+ },
595
+ {
596
+ id: "t5",
597
+ content: "Deploy to production",
598
+ status: "completed",
599
+ priority: "high",
600
+ },
601
+ ],
602
+ }}
603
+ usage={{ totalTokens: 28_400, cost: 0.12 }}
604
+ activeAgentCount={0}
605
+ totalAgentCount={3}
606
+ startedAt={startedAt}
607
+ endedAt={endedAt}
608
+ isRunning={false}
609
+ />
610
+ ```
611
+
612
+ ```tsx
613
+ <AiMissionHeader
614
+ title="Analyze codebase"
615
+ activeAgentCount={1}
616
+ totalAgentCount={2}
617
+ startedAt={startedAt}
618
+ isRunning
619
+ variant="compact"
620
+ />
621
+ ```
622
+
272
623
  ---
273
624
 
274
625
  ### AiPartGroup
@@ -298,6 +649,49 @@ Groups streaming ephemeral activity (tool calls + reasoning) into a single rolli
298
649
 
299
650
  `bg-sf-tint`, `border-sf-line`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
300
651
 
652
+ **Examples:**
653
+
654
+ ```tsx
655
+ <div className="flex flex-col gap-3">
656
+ <div className="flex items-center justify-between gap-3">
657
+ <Text variant="secondary" size="sm">
658
+ Rolling window of 3 rows while streaming. Collapses to a single frozen
659
+ line when complete.
660
+ </Text>
661
+ <Button onClick={() => setRunId((n) => n + 1)} size="sm" variant="ghost">
662
+ Run again
663
+ </Button>
664
+ </div>
665
+ <div className="min-h-[6rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3">
666
+ <AiPartGroup
667
+ complete={complete}
668
+ groupKey={`activity-demo-${runId}`}
669
+ max={3}
670
+ title="Investigating failing auth tests"
671
+ >
672
+ {steps.map((s) =>
673
+ s.kind === "tool" ? (
674
+ <AiToolCall
675
+ duration={s.duration}
676
+ key={s.part.toolCallId}
677
+ part={s.part}
678
+ variant="ephemeral"
679
+ />
680
+ ) : (
681
+ <AiReasoning
682
+ duration={s.duration}
683
+ isStreaming={s.isStreaming}
684
+ key={s.id}
685
+ part={{ text: s.text }}
686
+ variant="ephemeral"
687
+ />
688
+ )
689
+ )}
690
+ </AiPartGroup>
691
+ </div>
692
+ </div>
693
+ ```
694
+
301
695
  ---
302
696
 
303
697
  ### AiQuestion
@@ -338,6 +732,55 @@ Agent question card. Renders when the agent uses the `ask_user` built-in tool an
338
732
 
339
733
  `bg-sf-base`, `bg-sf-brand`, `bg-sf-tint`, `border-sf-brand`, `border-sf-line`, `border-sf-ring`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-inverse`, `text-sf-subtle`, `text-sf-success`
340
734
 
735
+ **Examples:**
736
+
737
+ ```tsx
738
+ <div className="w-full max-w-md">
739
+ <AiQuestion
740
+ questionId="q-demo-1"
741
+ question="How should I handle the failing tests?"
742
+ header="Decision needed"
743
+ status={status}
744
+ answeredWith={answer}
745
+ options={[
746
+ {
747
+ label: "Fix them",
748
+ description: "Update the test expectations to match new behavior",
749
+ },
750
+ {
751
+ label: "Skip them",
752
+ description: "Mark as skipped for now and create a ticket",
753
+ },
754
+ {
755
+ label: "Delete them",
756
+ description: "Remove outdated tests entirely",
757
+ },
758
+ ]}
759
+ allowCustom
760
+ onAnswer={(_id, ans) => {
761
+ setAnswer(ans);
762
+ setStatus("answered");
763
+ }}
764
+ />
765
+ </div>
766
+ ```
767
+
768
+ ```tsx
769
+ <div className="w-full max-w-md">
770
+ <AiQuestion
771
+ questionId="q-demo-2"
772
+ question="What should the commit message be for these changes?"
773
+ status={status}
774
+ answeredWith={answer}
775
+ allowCustom
776
+ onAnswer={(_id, ans) => {
777
+ setAnswer(ans);
778
+ setStatus("answered");
779
+ }}
780
+ />
781
+ </div>
782
+ ```
783
+
341
784
  ---
342
785
 
343
786
  ### AiReasoning
@@ -387,6 +830,73 @@ Collapsible reasoning block. Supports three display variants: - `"default"` —
387
830
 
388
831
  `bg-sf-tint`, `border-sf-line`, `text-sf-subtle`, `text-sf-success`
389
832
 
833
+ **Examples:**
834
+
835
+ ```tsx
836
+ <AiReasoning
837
+ part={{ text: SAMPLE_REASONING }}
838
+ isStreaming={false}
839
+ duration={3}
840
+ defaultExpanded
841
+ />
842
+ ```
843
+
844
+ ```tsx
845
+ <AiReasoning
846
+ part={{ text: "Analysing context and forming a response..." }}
847
+ isStreaming
848
+ />
849
+ ```
850
+
851
+ ```tsx
852
+ <AiReasoning
853
+ variant="inline"
854
+ part={{ text: SAMPLE_REASONING }}
855
+ isStreaming={false}
856
+ />
857
+ ```
858
+
859
+ ```tsx
860
+ <div className="flex flex-col gap-3">
861
+ <div className="flex items-center justify-between gap-3">
862
+ <Text variant="secondary" size="sm">
863
+ Reasoning row evaporates 800ms after streaming ends.
864
+ </Text>
865
+ <Button onClick={() => setRunId((n) => n + 1)} size="sm" variant="ghost">
866
+ Think again
867
+ </Button>
868
+ </div>
869
+ <div
870
+ className={
871
+ "min-h-[3.5rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3"
872
+ }
873
+ >
874
+ <AiReasoning
875
+ // `key` ensures each replay re-mounts to reset the dismiss state.
876
+ key={runId}
877
+ variant="ephemeral"
878
+ part={{
879
+ text: "**Reviewing diff** — checking for breaking changes in the migration.",
880
+ }}
881
+ isStreaming={isStreaming}
882
+ />
883
+ </div>
884
+ </div>
885
+ ```
886
+
887
+ ```tsx
888
+ <AiReasoningGroup
889
+ parts={[
890
+ { text: "**Step 1** — Understood the user intent and context." },
891
+ { text: "**Step 2** — Reviewed relevant data and constraints." },
892
+ { text: "**Step 3** — Formulated the final response structure." },
893
+ ]}
894
+ isStreaming={false}
895
+ totalDuration={7}
896
+ defaultExpanded
897
+ />
898
+ ```
899
+
390
900
  ---
391
901
 
392
902
  ### AiResponse
@@ -410,6 +920,39 @@ Renders AI-generated markdown using Streamdown. Supports streaming animation, sy
410
920
 
411
921
  `text-sf-default`
412
922
 
923
+ **Examples:**
924
+
925
+ ```tsx
926
+ <AiResponse>{MARKDOWN_LIKE}</AiResponse>
927
+ ```
928
+
929
+ ```tsx
930
+ <AiResponse isAnimating={isAnimating}>{text}</AiResponse>
931
+ ```
932
+
933
+ ```tsx
934
+ <div className="flex w-full flex-col gap-4">
935
+ <AiResponse
936
+ components={{ a: LinkComponent } as Components}
937
+ linkSafety={{ enabled: false }}
938
+ >
939
+ {DEEP_LINK_MARKDOWN}
940
+ </AiResponse>
941
+ {activeFile && (
942
+ <div className="rounded-lg border border-sf-brand/30 bg-sf-brand/10 px-3 py-2 text-sm text-sf-default">
943
+ <span className="text-sf-subtle">Opened file:</span>{" "}
944
+ <code className="font-mono text-sf-brand">{activeFile}</code>
945
+ <button
946
+ onClick={() => setActiveFile(null)}
947
+ className="ml-3 text-xs text-sf-subtle hover:text-sf-default"
948
+ >
949
+ Dismiss
950
+ </button>
951
+ </div>
952
+ )}
953
+ </div>
954
+ ```
955
+
413
956
  ---
414
957
 
415
958
  ### AiShimmer
@@ -435,6 +978,26 @@ AiShimmer component
435
978
  - `spread`: number
436
979
  Shimmer width multiplier relative to text length.
437
980
 
981
+ **Examples:**
982
+
983
+ ```tsx
984
+ <AiShimmer>Thinking...</AiShimmer>
985
+ ```
986
+
987
+ ```tsx
988
+ <p className="text-sf-default text-sm">
989
+ The AI is{" "}
990
+ <AiShimmer as="span" duration={1.5}>
991
+ generating a response
992
+ </AiShimmer>
993
+ .
994
+ </p>
995
+ ```
996
+
997
+ ```tsx
998
+ <AiShimmer duration={4}>Analysing your request...</AiShimmer>
999
+ ```
1000
+
438
1001
  ---
439
1002
 
440
1003
  ### AiStatusBadge
@@ -470,6 +1033,45 @@ Compact pill-shaped badge showing an icon, label, and a status indicator. Used b
470
1033
 
471
1034
  `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
472
1035
 
1036
+ **Examples:**
1037
+
1038
+ ```tsx
1039
+ <AiStatusBadge icon={MagnifyingGlassIcon} label="web_search" status="idle" />
1040
+ ```
1041
+
1042
+ ```tsx
1043
+ <div className="flex flex-wrap gap-2">
1044
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="idle" />
1045
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="running" />
1046
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="success" />
1047
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="error" />
1048
+ </div>
1049
+ ```
1050
+
1051
+ ```tsx
1052
+ <div className="flex flex-wrap gap-2">
1053
+ <AiStatusBadge
1054
+ icon={DatabaseIcon}
1055
+ label="query_db"
1056
+ info="3/5"
1057
+ status="running"
1058
+ />
1059
+ <AiStatusBadge
1060
+ icon={BrainIcon}
1061
+ label="analyse"
1062
+ info="done"
1063
+ status="success"
1064
+ />
1065
+ </div>
1066
+ ```
1067
+
1068
+ ```tsx
1069
+ <div className="flex flex-wrap gap-2">
1070
+ <AiStatusBadge label="processing" status="running" />
1071
+ <AiStatusBadge label="complete" status="success" />
1072
+ </div>
1073
+ ```
1074
+
473
1075
  ---
474
1076
 
475
1077
  ### AiStreamingText
@@ -489,6 +1091,17 @@ AiStreamingText component
489
1091
  - `children`: ReactNode
490
1092
  Child elements
491
1093
 
1094
+ **Examples:**
1095
+
1096
+ ```tsx
1097
+ <p className="max-w-sm text-sf-default text-sm">
1098
+ {displayed}
1099
+ {streaming && (
1100
+ <span className="ml-0.5 inline-block h-4 w-0.5 animate-pulse bg-sf-brand" />
1101
+ )}
1102
+ </p>
1103
+ ```
1104
+
492
1105
  ---
493
1106
 
494
1107
  ### AiSubagent
@@ -529,7 +1142,92 @@ Collapsible wrapper for nested subagent activity. Shows the subagent name, statu
529
1142
 
530
1143
  **Colors (sf tokens used):**
531
1144
 
532
- `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
1145
+ `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
1146
+
1147
+ **Examples:**
1148
+
1149
+ ```tsx
1150
+ <div className="w-full max-w-lg">
1151
+ <AiSubagent
1152
+ name="Explore"
1153
+ agentType="explore"
1154
+ status="running"
1155
+ modelId="claude-haiku-3.5"
1156
+ defaultExpanded
1157
+ >
1158
+ <div className="flex flex-col gap-1.5 text-sm text-sf-subtle">
1159
+ <p>Searching codebase for authentication patterns...</p>
1160
+ <div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
1161
+ <span className="text-sf-brand">Glob</span>
1162
+ <span className="text-sf-subtle">src/**/*auth*</span>
1163
+ </div>
1164
+ <div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
1165
+ <span className="text-sf-brand">Read</span>
1166
+ <span className="text-sf-subtle">src/middleware/auth.ts</span>
1167
+ </div>
1168
+ </div>
1169
+ </AiSubagent>
1170
+ </div>
1171
+ ```
1172
+
1173
+ ```tsx
1174
+ <div className="w-full max-w-lg">
1175
+ <AiSubagent
1176
+ name="Execute"
1177
+ agentType="execute"
1178
+ status="completed"
1179
+ modelId="claude-sonnet-4"
1180
+ duration={12400}
1181
+ defaultExpanded={false}
1182
+ >
1183
+ <div className="text-sm text-sf-subtle">
1184
+ <p>Refactored 3 files, added 2 new tests. All tests passing.</p>
1185
+ </div>
1186
+ </AiSubagent>
1187
+ </div>
1188
+ ```
1189
+
1190
+ ```tsx
1191
+ <div className="w-full max-w-lg">
1192
+ <AiSubagent
1193
+ name="Plan"
1194
+ agentType="plan"
1195
+ status="completed"
1196
+ modelId="claude-sonnet-4"
1197
+ duration={28000}
1198
+ defaultExpanded
1199
+ >
1200
+ <div className="flex flex-col gap-2">
1201
+ <p className="text-sm text-sf-subtle">
1202
+ Breaking down the migration into subtasks...
1203
+ </p>
1204
+ <AiSubagent
1205
+ name="Explore"
1206
+ agentType="explore"
1207
+ status="completed"
1208
+ modelId="claude-haiku-3.5"
1209
+ duration={4200}
1210
+ defaultExpanded={false}
1211
+ >
1212
+ <p className="text-sm text-sf-subtle">
1213
+ Found 12 files using deprecated API.
1214
+ </p>
1215
+ </AiSubagent>
1216
+ <AiSubagent
1217
+ name="Execute"
1218
+ agentType="execute"
1219
+ status="running"
1220
+ modelId="claude-sonnet-4"
1221
+ defaultExpanded
1222
+ >
1223
+ <p className="text-sm text-sf-subtle">
1224
+ Updating import paths in batch 1/3...
1225
+ </p>
1226
+ </AiSubagent>
1227
+ </div>
1228
+ </AiSubagent>
1229
+ </div>
1230
+ ```
533
1231
 
534
1232
  ---
535
1233
 
@@ -582,6 +1280,14 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
582
1280
 
583
1281
  `bg-sf-brand`, `bg-sf-danger`, `bg-sf-subtle`, `bg-sf-success`, `bg-sf-tint`, `bg-sf-warning`, `text-sf-default`, `text-sf-subtle`
584
1282
 
1283
+ **Examples:**
1284
+
1285
+ ```tsx
1286
+ <div className="w-full max-w-sm">
1287
+ <AiTaskList title="Agent tasks" tasks={tasks} />
1288
+ </div>
1289
+ ```
1290
+
585
1291
  ---
586
1292
 
587
1293
  ### AiTimeline
@@ -618,6 +1324,95 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
618
1324
 
619
1325
  `bg-sf-base`, `bg-sf-brand`, `bg-sf-danger`, `bg-sf-elevated`, `bg-sf-fill`, `bg-sf-info`, `bg-sf-line`, `bg-sf-recessed`, `bg-sf-warning`, `border-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-inverse`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
620
1326
 
1327
+ **Examples:**
1328
+
1329
+ ```tsx
1330
+ <AiTimeline timeOrigin={T0} pixelsPerSecond={25} showNowMarker nowMs={nowMs}>
1331
+ <AiTimelineLane
1332
+ label="Main"
1333
+ agentType="main"
1334
+ status="running"
1335
+ modelId="claude-sonnet-4"
1336
+ blocks={mainBlocks}
1337
+ timeOrigin={T0}
1338
+ nowMs={nowMs}
1339
+ pxPerMs={pxPerMs}
1340
+ />
1341
+ <AiTimelineLane
1342
+ label="Explore"
1343
+ agentType="explore"
1344
+ status="completed"
1345
+ modelId="claude-haiku-3.5"
1346
+ blocks={exploreBlocks}
1347
+ timeOrigin={T0}
1348
+ nowMs={nowMs}
1349
+ pxPerMs={pxPerMs}
1350
+ />
1351
+ <AiTimelineLane
1352
+ label="Plan"
1353
+ agentType="plan"
1354
+ status="completed"
1355
+ modelId="claude-sonnet-4"
1356
+ blocks={planBlocks}
1357
+ timeOrigin={T0}
1358
+ nowMs={nowMs}
1359
+ pxPerMs={pxPerMs}
1360
+ />
1361
+ <AiTimelineLane
1362
+ label="Execute"
1363
+ agentType="execute"
1364
+ status="running"
1365
+ modelId="claude-sonnet-4"
1366
+ blocks={executeBlocks}
1367
+ timeOrigin={T0}
1368
+ nowMs={nowMs}
1369
+ pxPerMs={pxPerMs}
1370
+ />
1371
+ </AiTimeline>
1372
+ ```
1373
+
1374
+ ```tsx
1375
+ <AiTimeline timeOrigin={T0} pixelsPerSecond={25} showNowMarker nowMs={nowMs}>
1376
+ <AiTimelineLane
1377
+ label="Explore"
1378
+ agentType="explore"
1379
+ status="completed"
1380
+ blocks={exploreBlocks}
1381
+ timeOrigin={T0}
1382
+ nowMs={nowMs}
1383
+ pxPerMs={pxPerMs}
1384
+ density="compact"
1385
+ />
1386
+ <AiTimelineLane
1387
+ label="Execute"
1388
+ agentType="execute"
1389
+ status="running"
1390
+ blocks={executeBlocks}
1391
+ timeOrigin={T0}
1392
+ nowMs={nowMs}
1393
+ pxPerMs={pxPerMs}
1394
+ density="compact"
1395
+ />
1396
+ </AiTimeline>
1397
+ ```
1398
+
1399
+ ```tsx
1400
+ <AiTimeline
1401
+ timeOrigin={t}
1402
+ pixelsPerSecond={30}
1403
+ showNowMarker={false}
1404
+ nowMs={nowMs}
1405
+ >
1406
+ <AiTimelineLane
1407
+ label="Agent"
1408
+ blocks={allTypeBlocks}
1409
+ timeOrigin={t}
1410
+ nowMs={nowMs}
1411
+ pxPerMs={pxPerMs}
1412
+ />
1413
+ </AiTimeline>
1414
+ ```
1415
+
621
1416
  ---
622
1417
 
623
1418
  ### AiToolCall
@@ -697,6 +1492,25 @@ Compact token usage display bar. Shows input/output token counts, total, optiona
697
1492
 
698
1493
  `text-sf-inactive`, `text-sf-subtle`
699
1494
 
1495
+ **Examples:**
1496
+
1497
+ ```tsx
1498
+ <div className="w-full max-w-md rounded-lg border border-sf-line">
1499
+ <AiUsageBar
1500
+ inputTokens={12480}
1501
+ outputTokens={3256}
1502
+ cost={0.04}
1503
+ modelId="claude-sonnet-4"
1504
+ />
1505
+ </div>
1506
+ ```
1507
+
1508
+ ```tsx
1509
+ <div className="w-full max-w-sm rounded-lg border border-sf-line">
1510
+ <AiUsageBar inputTokens={850} outputTokens={124} />
1511
+ </div>
1512
+ ```
1513
+
700
1514
  ---
701
1515
 
702
1516
  ### Badge
@@ -741,6 +1555,116 @@ Small status label for categorizing or highlighting content. Supports icons, loa
741
1555
 
742
1556
  `bg-sf-brand`, `bg-sf-contrast`, `bg-sf-danger`, `bg-sf-fill`, `bg-sf-info`, `bg-sf-subtle`, `bg-sf-success`, `bg-sf-warning`, `border-sf-brand`, `border-sf-fill`, `text-sf-default`, `text-sf-inverse`, `text-sf-link`, `text-sf-strong`, `text-sf-success`, `text-sf-warning`
743
1557
 
1558
+ **Examples:**
1559
+
1560
+ ```tsx
1561
+ <div className="flex flex-wrap items-center gap-2">
1562
+ <Badge variant="primary">Primary</Badge>
1563
+ <Badge variant="secondary">Secondary</Badge>
1564
+ <Badge variant="destructive">Destructive</Badge>
1565
+ <Badge variant="outline">Outline</Badge>
1566
+ <Badge variant="beta">Beta</Badge>
1567
+ <Badge variant="success">Success</Badge>
1568
+ <Badge variant="warning">Warning</Badge>
1569
+ <Badge variant="info">Info</Badge>
1570
+ <Badge variant="ghost">Ghost</Badge>
1571
+ </div>
1572
+ ```
1573
+
1574
+ ```tsx
1575
+ <Badge variant="primary">Primary</Badge>
1576
+ ```
1577
+
1578
+ ```tsx
1579
+ <p className="flex items-center gap-2">
1580
+ Workers
1581
+ <Badge variant="beta">Beta</Badge>
1582
+ </p>
1583
+ ```
1584
+
1585
+ ```tsx
1586
+ <div className="flex flex-wrap items-center gap-2">
1587
+ <Badge variant="success" icon={CheckCircleIcon}>
1588
+ Verified
1589
+ </Badge>
1590
+ <Badge variant="secondary" icon={LightningIcon}>
1591
+ Boosted
1592
+ </Badge>
1593
+ <Badge variant="outline" icon={TagIcon} iconPosition="right">
1594
+ Tagged
1595
+ </Badge>
1596
+ </div>
1597
+ ```
1598
+
1599
+ ```tsx
1600
+ <div className="flex flex-wrap items-center gap-2">
1601
+ {tags.map((tag) => (
1602
+ <Badge
1603
+ key={tag}
1604
+ variant="secondary"
1605
+ onDismiss={() => setTags((t) => t.filter((v) => v !== tag))}
1606
+ >
1607
+ {tag}
1608
+ </Badge>
1609
+ ))}
1610
+ {tags.length === 0 && (
1611
+ <span className="text-sm text-sf-subtle">All tags removed</span>
1612
+ )}
1613
+ </div>
1614
+ ```
1615
+
1616
+ ```tsx
1617
+ <div className="flex flex-wrap items-center gap-2">
1618
+ <Badge variant="secondary" loading>
1619
+ Syncing
1620
+ </Badge>
1621
+ <Badge variant="info" loading>
1622
+ Deploying
1623
+ </Badge>
1624
+ </div>
1625
+ ```
1626
+
1627
+ ```tsx
1628
+ <div className="flex flex-wrap items-center gap-2">
1629
+ <Badge variant="outline" dot="green">
1630
+ Online
1631
+ </Badge>
1632
+ <Badge variant="outline" dot="red">
1633
+ Offline
1634
+ </Badge>
1635
+ <Badge variant="outline" dot="yellow">
1636
+ Degraded
1637
+ </Badge>
1638
+ <Badge variant="outline" dot="blue">
1639
+ Deploying
1640
+ </Badge>
1641
+ </div>
1642
+ ```
1643
+
1644
+ ```tsx
1645
+ <div className="flex flex-wrap items-center gap-2">
1646
+ <Badge variant="secondary" onClick={handleBadgeClick}>
1647
+ Clickable
1648
+ </Badge>
1649
+ <Badge variant="info" href="https://example.com">
1650
+ Link badge
1651
+ </Badge>
1652
+ </div>
1653
+ ```
1654
+
1655
+ ```tsx
1656
+ <TooltipProvider>
1657
+ <div className="flex flex-wrap items-center gap-2">
1658
+ <Badge variant="success" tooltip="Deployed 2 hours ago" dot="green">
1659
+ Production
1660
+ </Badge>
1661
+ <Badge variant="outline" tooltip="3 of 5 tasks complete">
1662
+ 3/5
1663
+ </Badge>
1664
+ </div>
1665
+ </TooltipProvider>
1666
+ ```
1667
+
744
1668
  ---
745
1669
 
746
1670
  ### Banner
@@ -771,6 +1695,38 @@ Full-width message bar for informational, warning, or error notices.
771
1695
 
772
1696
  `bg-sf-danger`, `bg-sf-danger-tint`, `bg-sf-info`, `bg-sf-info-tint`, `bg-sf-warning`, `bg-sf-warning-tint`, `border-sf-danger`, `border-sf-info`, `border-sf-warning`, `text-sf-danger`, `text-sf-link`, `text-sf-warning`
773
1697
 
1698
+ **Examples:**
1699
+
1700
+ ```tsx
1701
+ <div className="space-y-3">
1702
+ <Banner>This is an informational banner.</Banner>
1703
+ <Banner variant="alert">This is an alert banner.</Banner>
1704
+ <Banner variant="error">This is an error banner.</Banner>
1705
+ </div>
1706
+ ```
1707
+
1708
+ ```tsx
1709
+ <Banner>This is an informational banner.</Banner>
1710
+ ```
1711
+
1712
+ ```tsx
1713
+ <Banner variant="alert">Your session will expire soon.</Banner>
1714
+ ```
1715
+
1716
+ ```tsx
1717
+ <Banner icon={<WarningCircleIcon />} variant="alert">
1718
+ Review your billing information.
1719
+ </Banner>
1720
+ ```
1721
+
1722
+ ```tsx
1723
+ <Banner icon={<InfoIcon />}>
1724
+ <Text DANGEROUS_className="text-inherit">
1725
+ This banner supports <strong>custom content</strong> with Text.
1726
+ </Text>
1727
+ </Banner>
1728
+ ```
1729
+
774
1730
  ---
775
1731
 
776
1732
  ### Breadcrumbs
@@ -830,6 +1786,47 @@ Props:
830
1786
 
831
1787
  - `text`: string (required)
832
1788
 
1789
+ **Examples:**
1790
+
1791
+ ```tsx
1792
+ <Breadcrumbs>
1793
+ <Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
1794
+ <Breadcrumbs.Separator />
1795
+ <Breadcrumbs.Link href="#">Docs</Breadcrumbs.Link>
1796
+ <Breadcrumbs.Separator />
1797
+ <Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
1798
+ </Breadcrumbs>
1799
+ ```
1800
+
1801
+ ```tsx
1802
+ <Breadcrumbs>
1803
+ <Breadcrumbs.Link href="#" icon={<HouseIcon size={16} />}>
1804
+ Home
1805
+ </Breadcrumbs.Link>
1806
+ <Breadcrumbs.Separator />
1807
+ <Breadcrumbs.Link href="#">Projects</Breadcrumbs.Link>
1808
+ <Breadcrumbs.Separator />
1809
+ <Breadcrumbs.Current>Current Project</Breadcrumbs.Current>
1810
+ </Breadcrumbs>
1811
+ ```
1812
+
1813
+ ```tsx
1814
+ <Breadcrumbs>
1815
+ <Breadcrumbs.Current icon={<HouseIcon size={16} />}>
1816
+ Worker Analytics
1817
+ </Breadcrumbs.Current>
1818
+ </Breadcrumbs>
1819
+ ```
1820
+
1821
+ ```tsx
1822
+ <Breadcrumbs>
1823
+ <Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
1824
+ <Breadcrumbs.Separator />
1825
+ <Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
1826
+ <Breadcrumbs.Clipboard text="#" />
1827
+ </Breadcrumbs>
1828
+ ```
1829
+
833
1830
  ---
834
1831
 
835
1832
  ### Button
@@ -897,6 +1894,59 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
897
1894
 
898
1895
  `bg-sf-base`, `bg-sf-brand`, `bg-sf-brand-hover`, `bg-sf-control`, `bg-sf-danger`, `bg-sf-tint`, `ring-sf-line`, `ring-sf-ring`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`
899
1896
 
1897
+ **Examples:**
1898
+
1899
+ ```tsx
1900
+ <div className="flex flex-wrap items-center gap-2">
1901
+ <Button variant="secondary">Button</Button>
1902
+ <Button variant="secondary" shape="square" icon={PlusIcon} aria-label="Add" />
1903
+ </div>
1904
+ ```
1905
+
1906
+ ```tsx
1907
+ <Button variant="primary">Primary</Button>
1908
+ ```
1909
+
1910
+ ```tsx
1911
+ <div className="flex flex-wrap items-center gap-3">
1912
+ <Button size="xs" variant="secondary">
1913
+ Extra Small
1914
+ </Button>
1915
+ <Button size="sm" variant="secondary">
1916
+ Small
1917
+ </Button>
1918
+ <Button size="base" variant="secondary">
1919
+ Base
1920
+ </Button>
1921
+ <Button size="lg" variant="secondary">
1922
+ Large
1923
+ </Button>
1924
+ </div>
1925
+ ```
1926
+
1927
+ ```tsx
1928
+ <Button variant="secondary" icon={PlusIcon}>
1929
+ Create Worker
1930
+ </Button>
1931
+ ```
1932
+
1933
+ ```tsx
1934
+ <div className="flex flex-wrap items-center gap-3">
1935
+ <Button
1936
+ variant="secondary"
1937
+ shape="square"
1938
+ icon={PlusIcon}
1939
+ aria-label="Add item"
1940
+ />
1941
+ <Button
1942
+ variant="secondary"
1943
+ shape="circle"
1944
+ icon={PlusIcon}
1945
+ aria-label="Add item"
1946
+ />
1947
+ </div>
1948
+ ```
1949
+
900
1950
  ---
901
1951
 
902
1952
  ### Checkbox
@@ -985,6 +2035,66 @@ Props:
985
2035
  - `controlFirst`: boolean
986
2036
  - `className`: string
987
2037
 
2038
+ **Examples:**
2039
+
2040
+ ```tsx
2041
+ <Checkbox
2042
+ label="Accept terms and conditions"
2043
+ checked={checked}
2044
+ onCheckedChange={setChecked}
2045
+ />
2046
+ ```
2047
+
2048
+ ```tsx
2049
+ <Checkbox
2050
+ label="Select all"
2051
+ indeterminate={indeterminate}
2052
+ onCheckedChange={setIndeterminate}
2053
+ />
2054
+ ```
2055
+
2056
+ ```tsx
2057
+ <Checkbox
2058
+ label="Remember me"
2059
+ controlFirst={false}
2060
+ checked={checked}
2061
+ onCheckedChange={setChecked}
2062
+ />
2063
+ ```
2064
+
2065
+ ```tsx
2066
+ <Checkbox label="Disabled option" disabled />
2067
+ ```
2068
+
2069
+ ```tsx
2070
+ <Checkbox label="Invalid option" variant="error" />
2071
+ ```
2072
+
2073
+ ```tsx
2074
+ <Checkbox.Group
2075
+ legend="Email preferences"
2076
+ description="Choose how you'd like to receive updates"
2077
+ value={preferences}
2078
+ onValueChange={setPreferences}
2079
+ >
2080
+ <Checkbox.Item value="email" label="Email notifications" />
2081
+ <Checkbox.Item value="sms" label="SMS notifications" />
2082
+ <Checkbox.Item value="push" label="Push notifications" />
2083
+ </Checkbox.Group>
2084
+ ```
2085
+
2086
+ ```tsx
2087
+ <Checkbox.Group
2088
+ legend="Required preferences"
2089
+ error="Please select at least one notification method"
2090
+ value={[]}
2091
+ onValueChange={() => {}}
2092
+ >
2093
+ <Checkbox.Item value="email" label="Email" variant="error" />
2094
+ <Checkbox.Item value="sms" label="SMS" variant="error" />
2095
+ </Checkbox.Group>
2096
+ ```
2097
+
988
2098
  ---
989
2099
 
990
2100
  ### ClipboardText
@@ -1062,6 +2172,19 @@ Read-only text field with a one-click copy-to-clipboard button.
1062
2172
  - borderRadius: 8
1063
2173
  - fontSize: 14
1064
2174
 
2175
+ **Examples:**
2176
+
2177
+ ```tsx
2178
+ <ClipboardText text="0c239dd2" />
2179
+ ```
2180
+
2181
+ ```tsx
2182
+ <ClipboardText
2183
+ text="npx sf add button"
2184
+ tooltip={{ copiedText: "Copied!", side: "top", text: "Copy" }}
2185
+ />
2186
+ ```
2187
+
1065
2188
  ---
1066
2189
 
1067
2190
  ### Code
@@ -1108,6 +2231,26 @@ Props:
1108
2231
  - `code`: string (required)
1109
2232
  - `lang`: CodeLang
1110
2233
 
2234
+ **Examples:**
2235
+
2236
+ ```tsx
2237
+ <CodeBlock
2238
+ lang="tsx"
2239
+ code={`const greeting = "Hello, World!";
2240
+ console.log(greeting);`}
2241
+ />
2242
+ ```
2243
+
2244
+ ```tsx
2245
+ <Code
2246
+ lang="bash"
2247
+ code="export API_KEY={{apiKey}}"
2248
+ values={{
2249
+ apiKey: { highlight: true, value: "sk_live_123" },
2250
+ }}
2251
+ />
2252
+ ```
2253
+
1111
2254
  ---
1112
2255
 
1113
2256
  ### Collapsible
@@ -1136,6 +2279,30 @@ Collapsible component for showing/hiding content. Features: - Animated chevron i
1136
2279
 
1137
2280
  `border-sf-fill`, `text-sf-link`
1138
2281
 
2282
+ **Examples:**
2283
+
2284
+ ```tsx
2285
+ <div className="w-full">
2286
+ <Collapsible label="What is SF?" open={isOpen} onOpenChange={setIsOpen}>
2287
+ A minimal, composable component library for building modern interfaces.
2288
+ </Collapsible>
2289
+ </div>
2290
+ ```
2291
+
2292
+ ```tsx
2293
+ <div className="w-full space-y-2">
2294
+ <Collapsible label="What is SF?" open={open1} onOpenChange={setOpen1}>
2295
+ A minimal, composable component library for building modern interfaces.
2296
+ </Collapsible>
2297
+ <Collapsible label="How do I use it?" open={open2} onOpenChange={setOpen2}>
2298
+ Install the components and import them into your project.
2299
+ </Collapsible>
2300
+ <Collapsible label="Is it open source?" open={open3} onOpenChange={setOpen3}>
2301
+ Check the repository for license information.
2302
+ </Collapsible>
2303
+ </div>
2304
+ ```
2305
+
1139
2306
  ---
1140
2307
 
1141
2308
  ### Combobox
@@ -1258,6 +2425,161 @@ Usage:
1258
2425
  </Combobox.Collection>
1259
2426
  ```
1260
2427
 
2428
+ **Examples:**
2429
+
2430
+ ```tsx
2431
+ <Combobox
2432
+ value={value}
2433
+ onValueChange={(v) => setValue(v as string | null)}
2434
+ items={fruits}
2435
+ >
2436
+ <Combobox.TriggerInput placeholder="Please select" />
2437
+ <Combobox.Content>
2438
+ <Combobox.Empty />
2439
+ <Combobox.List>
2440
+ {(item: string) => (
2441
+ <Combobox.Item key={item} value={item}>
2442
+ {item}
2443
+ </Combobox.Item>
2444
+ )}
2445
+ </Combobox.List>
2446
+ </Combobox.Content>
2447
+ </Combobox>
2448
+ ```
2449
+
2450
+ ```tsx
2451
+ <Combobox
2452
+ value={value}
2453
+ onValueChange={(v) => setValue(v as Language)}
2454
+ items={languages}
2455
+ >
2456
+ <Combobox.TriggerValue className="w-[200px]" />
2457
+ <Combobox.Content>
2458
+ <Combobox.Input placeholder="Search languages" />
2459
+ <Combobox.Empty />
2460
+ <Combobox.List>
2461
+ {(item: Language) => (
2462
+ <Combobox.Item key={item.value} value={item}>
2463
+ {item.emoji} {item.label}
2464
+ </Combobox.Item>
2465
+ )}
2466
+ </Combobox.List>
2467
+ </Combobox.Content>
2468
+ </Combobox>
2469
+ ```
2470
+
2471
+ ```tsx
2472
+ <Combobox
2473
+ value={value}
2474
+ onValueChange={(v) => setValue(v as ServerLocation | null)}
2475
+ items={servers}
2476
+ >
2477
+ <Combobox.TriggerInput className="w-[200px]" placeholder="Select server" />
2478
+ <Combobox.Content>
2479
+ <Combobox.Empty />
2480
+ <Combobox.List>
2481
+ {(group: ServerLocationGroup) => (
2482
+ <Combobox.Group key={group.value} items={group.items}>
2483
+ <Combobox.GroupLabel>{group.value}</Combobox.GroupLabel>
2484
+ <Combobox.Collection>
2485
+ {(item: ServerLocation) => (
2486
+ <Combobox.Item key={item.value} value={item}>
2487
+ {item.label}
2488
+ </Combobox.Item>
2489
+ )}
2490
+ </Combobox.Collection>
2491
+ </Combobox.Group>
2492
+ )}
2493
+ </Combobox.List>
2494
+ </Combobox.Content>
2495
+ </Combobox>
2496
+ ```
2497
+
2498
+ ```tsx
2499
+ <div className="flex gap-2">
2500
+ <Combobox
2501
+ value={value}
2502
+ onValueChange={setValue}
2503
+ items={bots}
2504
+ isItemEqualToValue={(bot: BotItem, selected: BotItem) =>
2505
+ bot.value === selected.value
2506
+ }
2507
+ multiple
2508
+ >
2509
+ <Combobox.TriggerMultipleWithInput
2510
+ className="w-[400px]"
2511
+ placeholder="Select bots"
2512
+ renderItem={(selected: BotItem) => (
2513
+ <Combobox.Chip key={selected.value}>{selected.label}</Combobox.Chip>
2514
+ )}
2515
+ inputSide="right"
2516
+ />
2517
+ <Combobox.Content className="max-h-[200px] min-w-auto overflow-y-auto">
2518
+ <Combobox.Empty />
2519
+ <Combobox.List>
2520
+ {(item: BotItem) => (
2521
+ <Combobox.Item key={item.value} value={item}>
2522
+ <div className="flex gap-2">
2523
+ <Text>{item.label}</Text>
2524
+ <Text variant="secondary">{item.author}</Text>
2525
+ </div>
2526
+ </Combobox.Item>
2527
+ )}
2528
+ </Combobox.List>
2529
+ </Combobox.Content>
2530
+ </Combobox>
2531
+ <Button variant="primary">Submit</Button>
2532
+ </div>
2533
+ ```
2534
+
2535
+ ```tsx
2536
+ <div className="w-80">
2537
+ <Combobox
2538
+ items={databases}
2539
+ value={value}
2540
+ onValueChange={setValue}
2541
+ label="Database"
2542
+ description="Select your preferred database"
2543
+ >
2544
+ <Combobox.TriggerInput placeholder="Select database" />
2545
+ <Combobox.Content>
2546
+ <Combobox.Empty />
2547
+ <Combobox.List>
2548
+ {(item: DatabaseItem) => (
2549
+ <Combobox.Item key={item.value} value={item}>
2550
+ {item.label}
2551
+ </Combobox.Item>
2552
+ )}
2553
+ </Combobox.List>
2554
+ </Combobox.Content>
2555
+ </Combobox>
2556
+ </div>
2557
+ ```
2558
+
2559
+ ```tsx
2560
+ <div className="w-80">
2561
+ <Combobox
2562
+ items={databases}
2563
+ value={value}
2564
+ onValueChange={setValue}
2565
+ label="Database"
2566
+ error={{ match: true, message: "Please select a database" }}
2567
+ >
2568
+ <Combobox.TriggerInput placeholder="Select database" />
2569
+ <Combobox.Content>
2570
+ <Combobox.Empty />
2571
+ <Combobox.List>
2572
+ {(item: DatabaseItem) => (
2573
+ <Combobox.Item key={item.value} value={item}>
2574
+ {item.label}
2575
+ </Combobox.Item>
2576
+ )}
2577
+ </Combobox.List>
2578
+ </Combobox.Content>
2579
+ </Combobox>
2580
+ </div>
2581
+ ```
2582
+
1261
2583
  ---
1262
2584
 
1263
2585
  ### CommandPalette
@@ -1281,6 +2603,216 @@ CommandPalette — accessible command palette / spotlight search overlay. Compou
1281
2603
 
1282
2604
  `bg-sf-elevated`, `bg-sf-overlay`, `bg-sf-warning`, `ring-sf-line`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
1283
2605
 
2606
+ **Examples:**
2607
+
2608
+ ```tsx
2609
+ <div className="flex flex-col items-start gap-4">
2610
+ <Button onClick={() => setOpen(true)}>Open Command Palette</Button>
2611
+ {selectedItem && (
2612
+ <p className="text-sm text-sf-subtle">
2613
+ Last selected: <span className="text-sf-default">{selectedItem}</span>
2614
+ </p>
2615
+ )}
2616
+
2617
+ <CommandPalette.Root
2618
+ open={open}
2619
+ onOpenChange={setOpen}
2620
+ items={sampleGroups}
2621
+ value={search}
2622
+ onValueChange={setSearch}
2623
+ itemToStringValue={(group) => group.label}
2624
+ onSelect={(item, { newTab }) => {
2625
+ console.log("Selected:", item.title, newTab ? "(new tab)" : "");
2626
+ handleSelect(item);
2627
+ }}
2628
+ getSelectableItems={getSelectableItems}
2629
+ >
2630
+ <CommandPalette.Input placeholder="Type a command or search..." />
2631
+ <CommandPalette.List>
2632
+ <CommandPalette.Results>
2633
+ {(group: CommandGroup) => (
2634
+ <CommandPalette.Group key={group.id}>
2635
+ <CommandPalette.GroupLabel>{group.label}</CommandPalette.GroupLabel>
2636
+ <CommandPalette.Items>
2637
+ {(item: CommandItem) => (
2638
+ <CommandPalette.Item
2639
+ key={item.id}
2640
+ value={item}
2641
+ onClick={() => handleSelect(item)}
2642
+ >
2643
+ <span className="flex items-center gap-3">
2644
+ {item.icon && (
2645
+ <span className="text-sf-subtle">{item.icon}</span>
2646
+ )}
2647
+ <span>{item.title}</span>
2648
+ </span>
2649
+ </CommandPalette.Item>
2650
+ )}
2651
+ </CommandPalette.Items>
2652
+ </CommandPalette.Group>
2653
+ )}
2654
+ </CommandPalette.Results>
2655
+ <CommandPalette.Empty>No commands found</CommandPalette.Empty>
2656
+ </CommandPalette.List>
2657
+ <CommandPalette.Footer>
2658
+ <span className="flex items-center gap-2">
2659
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2660
+ ↑↓
2661
+ </kbd>
2662
+ <span>Navigate</span>
2663
+ </span>
2664
+ <span className="flex items-center gap-2">
2665
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2666
+
2667
+ </kbd>
2668
+ <span>Select</span>
2669
+ </span>
2670
+ </CommandPalette.Footer>
2671
+ </CommandPalette.Root>
2672
+ </div>
2673
+ ```
2674
+
2675
+ ```tsx
2676
+ <div>
2677
+ <Button onClick={() => setOpen(true)}>Open Simple Palette</Button>
2678
+
2679
+ <CommandPalette.Root
2680
+ open={open}
2681
+ onOpenChange={setOpen}
2682
+ items={simpleItems}
2683
+ value={search}
2684
+ onValueChange={setSearch}
2685
+ itemToStringValue={(item) => item.title}
2686
+ onSelect={(item) => {
2687
+ console.log("Selected:", item.title);
2688
+ setOpen(false);
2689
+ }}
2690
+ getSelectableItems={(items) => items}
2691
+ >
2692
+ <CommandPalette.Input placeholder="Search actions..." />
2693
+ <CommandPalette.List>
2694
+ <CommandPalette.Results>
2695
+ {(item: SimpleItem) => (
2696
+ <CommandPalette.Item
2697
+ key={item.id}
2698
+ value={item}
2699
+ onClick={() => {
2700
+ console.log("Clicked:", item.title);
2701
+ setOpen(false);
2702
+ }}
2703
+ >
2704
+ {item.title}
2705
+ </CommandPalette.Item>
2706
+ )}
2707
+ </CommandPalette.Results>
2708
+ <CommandPalette.Empty>No actions found</CommandPalette.Empty>
2709
+ </CommandPalette.List>
2710
+ </CommandPalette.Root>
2711
+ </div>
2712
+ ```
2713
+
2714
+ ```tsx
2715
+ <div>
2716
+ <Button onClick={handleOpen}>Open with Loading</Button>
2717
+
2718
+ <CommandPalette.Root
2719
+ open={open}
2720
+ onOpenChange={setOpen}
2721
+ items={loading ? [] : sampleGroups}
2722
+ value={search}
2723
+ onValueChange={setSearch}
2724
+ itemToStringValue={(group) => group.label}
2725
+ getSelectableItems={getSelectableItems}
2726
+ >
2727
+ <CommandPalette.Input placeholder="Search..." />
2728
+ <CommandPalette.List>
2729
+ {loading ? (
2730
+ <CommandPalette.Loading />
2731
+ ) : (
2732
+ <>
2733
+ <CommandPalette.Results>
2734
+ {(group: CommandGroup) => (
2735
+ <CommandPalette.Group key={group.id}>
2736
+ <CommandPalette.GroupLabel>
2737
+ {group.label}
2738
+ </CommandPalette.GroupLabel>
2739
+ <CommandPalette.Items>
2740
+ {(item: CommandItem) => (
2741
+ <CommandPalette.Item
2742
+ key={item.id}
2743
+ value={item}
2744
+ onClick={() => setOpen(false)}
2745
+ >
2746
+ <span className="flex items-center gap-3">
2747
+ {item.icon && (
2748
+ <span className="text-sf-subtle">{item.icon}</span>
2749
+ )}
2750
+ <span>{item.title}</span>
2751
+ </span>
2752
+ </CommandPalette.Item>
2753
+ )}
2754
+ </CommandPalette.Items>
2755
+ </CommandPalette.Group>
2756
+ )}
2757
+ </CommandPalette.Results>
2758
+ <CommandPalette.Empty>No results found</CommandPalette.Empty>
2759
+ </>
2760
+ )}
2761
+ </CommandPalette.List>
2762
+ </CommandPalette.Root>
2763
+ </div>
2764
+ ```
2765
+
2766
+ ```tsx
2767
+ <div>
2768
+ <Button onClick={() => setOpen(true)}>Open with ResultItem</Button>
2769
+
2770
+ <CommandPalette.Root
2771
+ open={open}
2772
+ onOpenChange={setOpen}
2773
+ items={searchResults}
2774
+ value={search}
2775
+ onValueChange={setSearch}
2776
+ itemToStringValue={(item) => item.title}
2777
+ getSelectableItems={(items) => items}
2778
+ >
2779
+ <CommandPalette.Input placeholder="Search documentation..." />
2780
+ <CommandPalette.List>
2781
+ <CommandPalette.Results>
2782
+ {(item: SearchResult) => (
2783
+ <CommandPalette.ResultItem
2784
+ key={item.id}
2785
+ value={item}
2786
+ title={item.title}
2787
+ breadcrumbs={item.breadcrumbs}
2788
+ icon={item.icon}
2789
+ onClick={() => {
2790
+ console.log("Navigate to:", item.title);
2791
+ setOpen(false);
2792
+ }}
2793
+ />
2794
+ )}
2795
+ </CommandPalette.Results>
2796
+ <CommandPalette.Empty>No pages found</CommandPalette.Empty>
2797
+ </CommandPalette.List>
2798
+ <CommandPalette.Footer>
2799
+ <span className="flex items-center gap-2">
2800
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2801
+ ↑↓
2802
+ </kbd>
2803
+ <span>Navigate</span>
2804
+ </span>
2805
+ <span className="flex items-center gap-2">
2806
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2807
+ ⌘↵
2808
+ </kbd>
2809
+ <span>Open in new tab</span>
2810
+ </span>
2811
+ </CommandPalette.Footer>
2812
+ </CommandPalette.Root>
2813
+ </div>
2814
+ ```
2815
+
1284
2816
  ---
1285
2817
 
1286
2818
  ### DataGrid
@@ -1331,6 +2863,137 @@ ColumnToggle sub-component
1331
2863
 
1332
2864
  Empty sub-component
1333
2865
 
2866
+ **Examples:**
2867
+
2868
+ ```tsx
2869
+ <LayerCard>
2870
+ <LayerCard.Primary className="p-0">
2871
+ <DataGrid data={sampleUsers} columns={columns} enableSorting>
2872
+ <DataGrid.Content />
2873
+ </DataGrid>
2874
+ </LayerCard.Primary>
2875
+ </LayerCard>
2876
+ ```
2877
+
2878
+ ```tsx
2879
+ <LayerCard>
2880
+ <LayerCard.Primary className="p-0">
2881
+ <DataGrid
2882
+ data={paginatedData}
2883
+ columns={columns.slice(0, 3)}
2884
+ pageSize={pageSize}
2885
+ pageIndex={pageIndex}
2886
+ onPaginationChange={({ pageIndex: newPage }) => setPageIndex(newPage)}
2887
+ totalCount={totalCount}
2888
+ manualPagination
2889
+ >
2890
+ <DataGrid.Content />
2891
+ <DataGrid.Pagination />
2892
+ </DataGrid>
2893
+ </LayerCard.Primary>
2894
+ </LayerCard>
2895
+ ```
2896
+
2897
+ ```tsx
2898
+ <LayerCard>
2899
+ <LayerCard.Primary className="p-0">
2900
+ <DataGrid
2901
+ data={sampleUsers.slice(0, 4)}
2902
+ columns={columns}
2903
+ enableRowSelection
2904
+ rowSelection={rowSelection}
2905
+ onRowSelectionChange={setRowSelection}
2906
+ >
2907
+ <DataGrid.Content />
2908
+ </DataGrid>
2909
+ <div className="border-t border-sf-line p-3 text-sm">
2910
+ <p className="text-sf-subtle">
2911
+ Selected: {Object.keys(rowSelection).length} rows
2912
+ </p>
2913
+ </div>
2914
+ </LayerCard.Primary>
2915
+ </LayerCard>
2916
+ ```
2917
+
2918
+ ```tsx
2919
+ <LayerCard>
2920
+ <LayerCard.Primary className="p-0">
2921
+ <DataGrid
2922
+ data={sampleUsers.slice(0, 4)}
2923
+ columns={columns}
2924
+ columnVisibility={columnVisibility}
2925
+ onColumnVisibilityChange={setColumnVisibility}
2926
+ >
2927
+ <DataGrid.Toolbar className="p-3">
2928
+ <DataGrid.ColumnToggle />
2929
+ </DataGrid.Toolbar>
2930
+ <DataGrid.Content />
2931
+ </DataGrid>
2932
+ </LayerCard.Primary>
2933
+ </LayerCard>
2934
+ ```
2935
+
2936
+ ```tsx
2937
+ <LayerCard>
2938
+ <LayerCard.Primary className="p-0">
2939
+ <DataGrid data={sampleUsers} columns={columns} enableSorting>
2940
+ <DataGrid.Toolbar className="flex items-center justify-between p-3">
2941
+ <span className="text-sm font-medium">Users</span>
2942
+ <DataGrid.ColumnToggle />
2943
+ </DataGrid.Toolbar>
2944
+ <DataGrid.Content />
2945
+ </DataGrid>
2946
+ </LayerCard.Primary>
2947
+ </LayerCard>
2948
+ ```
2949
+
2950
+ ```tsx
2951
+ <LayerCard>
2952
+ <LayerCard.Primary className="p-0">
2953
+ <DataGrid
2954
+ data={[]}
2955
+ columns={columns.slice(0, 3)}
2956
+ emptyState={
2957
+ <div className="flex flex-col items-center justify-center py-12 text-center">
2958
+ <p className="text-sf-strong font-medium">No users found</p>
2959
+ <p className="text-sf-subtle mt-1 text-sm">
2960
+ Try adjusting your filters or add new users
2961
+ </p>
2962
+ </div>
2963
+ }
2964
+ >
2965
+ <DataGrid.Content />
2966
+ </DataGrid>
2967
+ </LayerCard.Primary>
2968
+ </LayerCard>
2969
+ ```
2970
+
2971
+ ```tsx
2972
+ <LayerCard>
2973
+ <LayerCard.Primary className="p-0">
2974
+ <DataGrid data={[]} columns={columns.slice(0, 3)} loading loadingRows={3}>
2975
+ <DataGrid.Content />
2976
+ </DataGrid>
2977
+ </LayerCard.Primary>
2978
+ </LayerCard>
2979
+ ```
2980
+
2981
+ ```tsx
2982
+ <LayerCard>
2983
+ <LayerCard.Primary className="p-0">
2984
+ <DataGrid
2985
+ data={sampleUsers}
2986
+ columns={resizableColumns}
2987
+ enableSorting
2988
+ enableColumnResizing
2989
+ columnResizeMode="onEnd"
2990
+ >
2991
+ <DataGrid.Content />
2992
+ </DataGrid>
2993
+ </LayerCard.Primary>
2994
+ </LayerCard>
2995
+ ```
2996
+
1334
2997
  ---
1335
2998
 
1336
2999
  ### DatePicker
@@ -1354,6 +3017,154 @@ DatePicker — a date selection calendar. Built on [react-day-picker](https://da
1354
3017
 
1355
3018
  `bg-sf-base`
1356
3019
 
3020
+ **Examples:**
3021
+
3022
+ ```tsx
3023
+ <div className="flex flex-col gap-4">
3024
+ <DatePicker
3025
+ mode="single"
3026
+ selected={date}
3027
+ onChange={(d) => {
3028
+ if (d) {
3029
+ setDate(d);
3030
+ }
3031
+ }}
3032
+ />
3033
+ <p className="text-sm text-sf-subtle">
3034
+ Selected: {date ? date.toLocaleDateString() : "None"}
3035
+ </p>
3036
+ </div>
3037
+ ```
3038
+
3039
+ ```tsx
3040
+ <div className="flex flex-col gap-4">
3041
+ <DatePicker mode="multiple" selected={dates} onChange={setDates} max={5} />
3042
+ <p className="text-sm text-sf-subtle">
3043
+ Selected: {dates?.length ?? 0} date(s)
3044
+ </p>
3045
+ </div>
3046
+ ```
3047
+
3048
+ ```tsx
3049
+ <div className="flex flex-col gap-4">
3050
+ <DatePicker
3051
+ mode="range"
3052
+ selected={range}
3053
+ onChange={setRange}
3054
+ numberOfMonths={2}
3055
+ />
3056
+ <p className="text-sm text-sf-subtle">
3057
+ Range:{" "}
3058
+ {range?.from
3059
+ ? `${range.from.toLocaleDateString()} - ${range.to?.toLocaleDateString() ?? "..."}`
3060
+ : "None"}
3061
+ </p>
3062
+ </div>
3063
+ ```
3064
+
3065
+ ```tsx
3066
+ <div className="flex flex-col gap-4">
3067
+ <DatePicker
3068
+ mode="range"
3069
+ selected={range}
3070
+ onChange={setRange}
3071
+ min={3}
3072
+ max={7}
3073
+ footer={<span className="text-xs text-sf-subtle">Select 3-7 nights</span>}
3074
+ />
3075
+ </div>
3076
+ ```
3077
+
3078
+ ```tsx
3079
+ <Popover>
3080
+ <Popover.Trigger asChild>
3081
+ <Button variant="outline" icon={CalendarDotsIcon}>
3082
+ {date ? date.toLocaleDateString() : "Pick a date"}
3083
+ </Button>
3084
+ </Popover.Trigger>
3085
+ <Popover.Content className="p-3">
3086
+ <DatePicker mode="single" selected={date} onChange={setDate} />
3087
+ </Popover.Content>
3088
+ </Popover>
3089
+ ```
3090
+
3091
+ ```tsx
3092
+ <Popover>
3093
+ <Popover.Trigger asChild>
3094
+ <Button variant="outline" icon={CalendarDotsIcon}>
3095
+ {formatRange()}
3096
+ </Button>
3097
+ </Popover.Trigger>
3098
+ <Popover.Content className="p-3">
3099
+ <DatePicker
3100
+ mode="range"
3101
+ selected={range}
3102
+ onChange={setRange}
3103
+ numberOfMonths={2}
3104
+ />
3105
+ </Popover.Content>
3106
+ </Popover>
3107
+ ```
3108
+
3109
+ ```tsx
3110
+ <Popover>
3111
+ <Popover.Trigger asChild>
3112
+ <Button variant="outline" icon={CalendarDotsIcon}>
3113
+ {formatRange()}
3114
+ </Button>
3115
+ </Popover.Trigger>
3116
+ <Popover.Content className="p-0">
3117
+ <div className="flex">
3118
+ <div className="flex flex-col gap-1 border-r border-sf-line p-2 text-sm">
3119
+ {presets.map((preset) => {
3120
+ const isActive = isPresetActive(preset);
3121
+ return (
3122
+ <button
3123
+ key={preset.label}
3124
+ type="button"
3125
+ onClick={() => handlePresetClick(preset)}
3126
+ className={`rounded-md px-3 py-1.5 text-left whitespace-nowrap ${
3127
+ isActive
3128
+ ? "bg-sf-bg-inverse text-sf-text-inverse"
3129
+ : "text-sf-strong hover:bg-sf-control"
3130
+ }`}
3131
+ >
3132
+ {preset.label}
3133
+ </button>
3134
+ );
3135
+ })}
3136
+ </div>
3137
+ <div className="p-3">
3138
+ <DatePicker
3139
+ mode="range"
3140
+ selected={range}
3141
+ onChange={setRange}
3142
+ month={month}
3143
+ onMonthChange={setMonth}
3144
+ numberOfMonths={2}
3145
+ />
3146
+ </div>
3147
+ </div>
3148
+ </Popover.Content>
3149
+ </Popover>
3150
+ ```
3151
+
3152
+ ```tsx
3153
+ <DatePicker
3154
+ mode="multiple"
3155
+ selected={dates}
3156
+ onChange={setDates}
3157
+ max={maxDays}
3158
+ disabled={unavailableDates}
3159
+ fixedWeeks
3160
+ footer={
3161
+ <p className="text-xs text-sf-subtle pt-2 w-full">
3162
+ {selectedCount}/{maxDays} days selected. Grayed dates are unavailable.
3163
+ </p>
3164
+ }
3165
+ />
3166
+ ```
3167
+
1357
3168
  ---
1358
3169
 
1359
3170
  ### DateRangePicker
@@ -1478,6 +3289,228 @@ Description sub-component
1478
3289
 
1479
3290
  Close sub-component
1480
3291
 
3292
+ **Examples:**
3293
+
3294
+ ```tsx
3295
+ <Dialog.Root>
3296
+ <Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />
3297
+ <Dialog className="p-8">
3298
+ <div className="mb-4 flex items-start justify-between gap-4">
3299
+ <Dialog.Title className="text-2xl font-semibold">
3300
+ Modal Title
3301
+ </Dialog.Title>
3302
+ <Dialog.Close
3303
+ aria-label="Close"
3304
+ render={(props) => (
3305
+ <Button
3306
+ {...props}
3307
+ variant="secondary"
3308
+ shape="square"
3309
+ icon={<XIcon />}
3310
+ aria-label="Close"
3311
+ />
3312
+ )}
3313
+ />
3314
+ </div>
3315
+ <Dialog.Description className="text-sf-subtle">
3316
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
3317
+ tempor incididunt ut labore et dolore magna aliqua.
3318
+ </Dialog.Description>
3319
+ </Dialog>
3320
+ </Dialog.Root>
3321
+ ```
3322
+
3323
+ ```tsx
3324
+ <Dialog.Root>
3325
+ <Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />
3326
+ <Dialog className="p-8">
3327
+ <div className="mb-4 flex items-start justify-between gap-4">
3328
+ <Dialog.Title className="text-2xl font-semibold">
3329
+ Modal Title
3330
+ </Dialog.Title>
3331
+ <Dialog.Close
3332
+ aria-label="Close"
3333
+ render={(props) => (
3334
+ <Button
3335
+ {...props}
3336
+ variant="secondary"
3337
+ shape="square"
3338
+ icon={<XIcon />}
3339
+ aria-label="Close"
3340
+ />
3341
+ )}
3342
+ />
3343
+ </div>
3344
+ <Dialog.Description className="text-sf-subtle">
3345
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
3346
+ tempor incididunt ut labore et dolore magna aliqua.
3347
+ </Dialog.Description>
3348
+ <div className="mt-8 flex justify-end gap-2">
3349
+ <Dialog.Close
3350
+ render={(props) => (
3351
+ <Button variant="secondary" {...props}>
3352
+ Cancel
3353
+ </Button>
3354
+ )}
3355
+ />
3356
+ <Dialog.Close
3357
+ render={(props) => (
3358
+ <Button variant="destructive" {...props}>
3359
+ Delete
3360
+ </Button>
3361
+ )}
3362
+ />
3363
+ </div>
3364
+ </Dialog>
3365
+ </Dialog.Root>
3366
+ ```
3367
+
3368
+ ```tsx
3369
+ <Dialog.Root disablePointerDismissal>
3370
+ <Dialog.Trigger
3371
+ render={(p) => (
3372
+ <Button {...p} variant="destructive">
3373
+ Delete Project
3374
+ </Button>
3375
+ )}
3376
+ />
3377
+ <Dialog className="p-8">
3378
+ <div className="mb-4 flex items-center gap-3">
3379
+ <div className="flex h-10 w-10 items-center justify-center rounded-full bg-sf-danger/20">
3380
+ <WarningIcon size={20} className="text-sf-danger" />
3381
+ </div>
3382
+ <Dialog.Title className="text-xl font-semibold">
3383
+ Delete Project?
3384
+ </Dialog.Title>
3385
+ </div>
3386
+ <Dialog.Description className="text-sf-subtle">
3387
+ This action cannot be undone. This will permanently delete the project and
3388
+ all associated data.
3389
+ </Dialog.Description>
3390
+ <div className="mt-8 flex justify-end gap-2">
3391
+ <Dialog.Close
3392
+ render={(props) => (
3393
+ <Button variant="secondary" {...props}>
3394
+ Cancel
3395
+ </Button>
3396
+ )}
3397
+ />
3398
+ <Dialog.Close
3399
+ render={(props) => (
3400
+ <Button variant="destructive" {...props}>
3401
+ Delete
3402
+ </Button>
3403
+ )}
3404
+ />
3405
+ </div>
3406
+ </Dialog>
3407
+ </Dialog.Root>
3408
+ ```
3409
+
3410
+ ```tsx
3411
+ <Dialog.Root>
3412
+ <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
3413
+ <Dialog className="p-8">
3414
+ <div className="mb-4 flex items-start justify-between gap-4">
3415
+ <Dialog.Title className="text-2xl font-semibold">
3416
+ Create Resource
3417
+ </Dialog.Title>
3418
+ <Dialog.Close
3419
+ aria-label="Close"
3420
+ render={(props) => (
3421
+ <Button
3422
+ {...props}
3423
+ variant="secondary"
3424
+ shape="square"
3425
+ icon={<XIcon />}
3426
+ aria-label="Close"
3427
+ />
3428
+ )}
3429
+ />
3430
+ </div>
3431
+ <Dialog.Description className="mb-4 text-sf-subtle">
3432
+ Select a region for your new resource.
3433
+ </Dialog.Description>
3434
+ <Select
3435
+ className="w-full"
3436
+ renderValue={(v) =>
3437
+ regions.find((r) => r.value === v)?.label ?? "Select region..."
3438
+ }
3439
+ >
3440
+ {regions.map((region) => (
3441
+ <Select.Option key={region.value} value={region.value}>
3442
+ {region.label}
3443
+ </Select.Option>
3444
+ ))}
3445
+ </Select>
3446
+ <div className="mt-8 flex justify-end gap-2">
3447
+ <Dialog.Close
3448
+ render={(props) => (
3449
+ <Button variant="secondary" {...props}>
3450
+ Cancel
3451
+ </Button>
3452
+ )}
3453
+ />
3454
+ <Button variant="primary">Create</Button>
3455
+ </div>
3456
+ </Dialog>
3457
+ </Dialog.Root>
3458
+ ```
3459
+
3460
+ ```tsx
3461
+ <Dialog.Root>
3462
+ <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
3463
+ <Dialog className="p-8">
3464
+ <div className="mb-4 flex items-start justify-between gap-4">
3465
+ <Dialog.Title className="text-2xl font-semibold">
3466
+ Create Resource
3467
+ </Dialog.Title>
3468
+ <Dialog.Close
3469
+ aria-label="Close"
3470
+ render={(props) => (
3471
+ <Button
3472
+ {...props}
3473
+ variant="secondary"
3474
+ shape="square"
3475
+ icon={<XIcon />}
3476
+ aria-label="Close"
3477
+ />
3478
+ )}
3479
+ />
3480
+ </div>
3481
+ <Dialog.Description className="mb-4 text-sf-subtle">
3482
+ Search and select a region for your new resource.
3483
+ </Dialog.Description>
3484
+ <Combobox value={value} onValueChange={setValue} items={regions}>
3485
+ <Combobox.TriggerInput
3486
+ className="w-full"
3487
+ placeholder="Search regions..."
3488
+ />
3489
+ <Combobox.Content>
3490
+ <Combobox.Empty>No regions found</Combobox.Empty>
3491
+ <Combobox.List>
3492
+ {(item: { value: string; label: string }) => (
3493
+ <Combobox.Item key={item.value} value={item}>
3494
+ {item.label}
3495
+ </Combobox.Item>
3496
+ )}
3497
+ </Combobox.List>
3498
+ </Combobox.Content>
3499
+ </Combobox>
3500
+ <div className="mt-8 flex justify-end gap-2">
3501
+ <Dialog.Close
3502
+ render={(props) => (
3503
+ <Button variant="secondary" {...props}>
3504
+ Cancel
3505
+ </Button>
3506
+ )}
3507
+ />
3508
+ <Button variant="primary">Create</Button>
3509
+ </div>
3510
+ </Dialog>
3511
+ </Dialog.Root>
3512
+ ```
3513
+
1481
3514
  ---
1482
3515
 
1483
3516
  ### DropdownMenu
@@ -1599,6 +3632,91 @@ Placeholder shown when a list, table, or page has no content to display.
1599
3632
 
1600
3633
  `bg-sf-control`, `bg-sf-overlay`, `border-sf-fill`, `border-sf-interact`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-success`
1601
3634
 
3635
+ **Examples:**
3636
+
3637
+ ```tsx
3638
+ <Empty
3639
+ icon={<PackageIcon size={48} />}
3640
+ title="No packages found"
3641
+ description="Get started by installing your first package."
3642
+ commandLine="npm install @signalflare-ai/ui"
3643
+ contents={
3644
+ <div className="flex items-center gap-2">
3645
+ <Button icon={<CodeIcon />}>See examples</Button>
3646
+ <Button icon={<GlobeIcon />} variant="primary">
3647
+ View documentation
3648
+ </Button>
3649
+ </div>
3650
+ }
3651
+ />
3652
+ ```
3653
+
3654
+ ```tsx
3655
+ <div className="flex flex-col gap-8">
3656
+ <div>
3657
+ <p className="mb-2 text-sm text-sf-subtle">Small</p>
3658
+ <Empty
3659
+ size="sm"
3660
+ icon={<DatabaseIcon size={32} className="text-sf-inactive" />}
3661
+ title="No data available"
3662
+ description="There is no data to display."
3663
+ />
3664
+ </div>
3665
+ <div>
3666
+ <p className="mb-2 text-sm text-sf-subtle">Base</p>
3667
+ <Empty
3668
+ size="base"
3669
+ icon={<DatabaseIcon size={48} className="text-sf-inactive" />}
3670
+ title="No data available"
3671
+ description="There is no data to display."
3672
+ />
3673
+ </div>
3674
+ <div>
3675
+ <p className="mb-2 text-sm text-sf-subtle">Large</p>
3676
+ <Empty
3677
+ size="lg"
3678
+ icon={<DatabaseIcon size={64} className="text-sf-inactive" />}
3679
+ title="No data available"
3680
+ description="There is no data to display."
3681
+ />
3682
+ </div>
3683
+ </div>
3684
+ ```
3685
+
3686
+ ```tsx
3687
+ <Empty
3688
+ icon={<FolderOpenIcon size={48} className="text-sf-inactive" />}
3689
+ title="No projects found"
3690
+ description="Get started by creating your first project using the command below."
3691
+ commandLine="npm create sf-project"
3692
+ />
3693
+ ```
3694
+
3695
+ ```tsx
3696
+ <Empty
3697
+ icon={<CloudSlashIcon size={48} className="text-sf-inactive" />}
3698
+ title="No connection"
3699
+ description="Unable to connect to the server. Please check your connection and try again."
3700
+ contents={
3701
+ <div className="flex gap-2">
3702
+ <Button variant="primary">Retry</Button>
3703
+ <Button variant="secondary">Go Back</Button>
3704
+ </div>
3705
+ }
3706
+ />
3707
+ ```
3708
+
3709
+ ```tsx
3710
+ <Empty title="Nothing here" />
3711
+ ```
3712
+
3713
+ ```tsx
3714
+ <Empty
3715
+ title="No results found"
3716
+ description="Try adjusting your search or filter to find what you're looking for."
3717
+ />
3718
+ ```
3719
+
1602
3720
  ---
1603
3721
 
1604
3722
  ### Field
@@ -1677,6 +3795,61 @@ Filters component for building and managing active filter conditions. Supports m
1677
3795
 
1678
3796
  `bg-sf-fill`, `bg-sf-line`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-line`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
1679
3797
 
3798
+ **Examples:**
3799
+
3800
+ ```tsx
3801
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3802
+ <Filters filters={filters} fields={filterFields} onChange={setFilters} />
3803
+ <div className="mt-4 rounded bg-sf-elevated p-3 font-mono text-xs">
3804
+ <p className="text-sf-subtle mb-1">Active filters:</p>
3805
+ <pre className="text-sf-strong overflow-x-auto">
3806
+ {JSON.stringify(filters, null, 2)}
3807
+ </pre>
3808
+ </div>
3809
+ </div>
3810
+ ```
3811
+
3812
+ ```tsx
3813
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3814
+ <Filters
3815
+ filters={filters}
3816
+ fields={filterFields.slice(0, 3)}
3817
+ onChange={setFilters}
3818
+ size="sm"
3819
+ />
3820
+ </div>
3821
+ ```
3822
+
3823
+ ```tsx
3824
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3825
+ <Filters
3826
+ filters={filters}
3827
+ fields={filterFields}
3828
+ onChange={setFilters}
3829
+ showSearchInput
3830
+ />
3831
+ <p className="text-sf-subtle mt-3 text-xs">
3832
+ Open the "Add Filter" menu to see grouped fields (General, User Details)
3833
+ </p>
3834
+ </div>
3835
+ ```
3836
+
3837
+ ```tsx
3838
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3839
+ <Filters
3840
+ filters={filters}
3841
+ fields={filterFields.slice(0, 3)}
3842
+ onChange={setFilters}
3843
+ enableShortcut
3844
+ shortcutKey="k"
3845
+ shortcutLabel="Cmd+K"
3846
+ />
3847
+ <p className="text-sf-subtle mt-3 text-xs">
3848
+ Press Cmd+K (or Ctrl+K) to quickly open the add filter menu
3849
+ </p>
3850
+ </div>
3851
+ ```
3852
+
1680
3853
  ---
1681
3854
 
1682
3855
  ### Grid
@@ -1720,6 +3893,229 @@ Responsive CSS grid layout container with preset column configurations.
1720
3893
 
1721
3894
  `border-sf-line`
1722
3895
 
3896
+ **Examples:**
3897
+
3898
+ ```tsx
3899
+ <Grid variant="2up" gap="base">
3900
+ <GridItem>
3901
+ <Tile>
3902
+ <div>Item 1</div>
3903
+ <div className="mt-1">First grid item</div>
3904
+ </Tile>
3905
+ </GridItem>
3906
+ <GridItem>
3907
+ <Tile>
3908
+ <div>Item 2</div>
3909
+ <div className="mt-1">Second grid item</div>
3910
+ </Tile>
3911
+ </GridItem>
3912
+ </Grid>
3913
+ ```
3914
+
3915
+ ```tsx
3916
+ <div className="flex flex-col gap-8">
3917
+ <div>
3918
+ <p className="mb-2 text-sf-subtle">variant="2up"</p>
3919
+ <Grid variant="2up" gap="sm">
3920
+ <GridItem>
3921
+ <Tile>
3922
+ <span className="block text-center">1</span>
3923
+ </Tile>
3924
+ </GridItem>
3925
+ <GridItem>
3926
+ <Tile>
3927
+ <span className="block text-center">2</span>
3928
+ </Tile>
3929
+ </GridItem>
3930
+ </Grid>
3931
+ </div>
3932
+
3933
+ <div>
3934
+ <p className="mb-2 text-sf-subtle">variant="3up"</p>
3935
+ <Grid variant="3up" gap="sm">
3936
+ <GridItem>
3937
+ <Tile>
3938
+ <span className="block text-center">1</span>
3939
+ </Tile>
3940
+ </GridItem>
3941
+ <GridItem>
3942
+ <Tile>
3943
+ <span className="block text-center">2</span>
3944
+ </Tile>
3945
+ </GridItem>
3946
+ <GridItem>
3947
+ <Tile>
3948
+ <span className="block text-center">3</span>
3949
+ </Tile>
3950
+ </GridItem>
3951
+ </Grid>
3952
+ </div>
3953
+
3954
+ <div>
3955
+ <p className="mb-2 text-sf-subtle">variant="4up"</p>
3956
+ <Grid variant="4up" gap="sm">
3957
+ <GridItem>
3958
+ <Tile>
3959
+ <span className="block text-center">1</span>
3960
+ </Tile>
3961
+ </GridItem>
3962
+ <GridItem>
3963
+ <Tile>
3964
+ <span className="block text-center">2</span>
3965
+ </Tile>
3966
+ </GridItem>
3967
+ <GridItem>
3968
+ <Tile>
3969
+ <span className="block text-center">3</span>
3970
+ </Tile>
3971
+ </GridItem>
3972
+ <GridItem>
3973
+ <Tile>
3974
+ <span className="block text-center">4</span>
3975
+ </Tile>
3976
+ </GridItem>
3977
+ </Grid>
3978
+ </div>
3979
+ </div>
3980
+ ```
3981
+
3982
+ ```tsx
3983
+ <div className="flex flex-col gap-8">
3984
+ <div>
3985
+ <p className="mb-2 text-sf-subtle">variant="2-1" (66% / 33%)</p>
3986
+ <Grid variant="2-1" gap="sm">
3987
+ <GridItem>
3988
+ <Tile>
3989
+ <div>Main Content</div>
3990
+ <div className="mt-1">Two-thirds width</div>
3991
+ </Tile>
3992
+ </GridItem>
3993
+ <GridItem>
3994
+ <Tile>
3995
+ <div>Sidebar</div>
3996
+ <div className="mt-1">One-third width</div>
3997
+ </Tile>
3998
+ </GridItem>
3999
+ </Grid>
4000
+ </div>
4001
+
4002
+ <div>
4003
+ <p className="mb-2 text-sf-subtle">variant="1-2" (33% / 66%)</p>
4004
+ <Grid variant="1-2" gap="sm">
4005
+ <GridItem>
4006
+ <Tile>
4007
+ <div>Sidebar</div>
4008
+ <div className="mt-1">One-third width</div>
4009
+ </Tile>
4010
+ </GridItem>
4011
+ <GridItem>
4012
+ <Tile>
4013
+ <div>Main Content</div>
4014
+ <div className="mt-1">Two-thirds width</div>
4015
+ </Tile>
4016
+ </GridItem>
4017
+ </Grid>
4018
+ </div>
4019
+ </div>
4020
+ ```
4021
+
4022
+ ```tsx
4023
+ <div className="flex flex-col gap-8">
4024
+ <div>
4025
+ <p className="mb-2 text-sf-subtle">gap="none"</p>
4026
+ <Grid variant="side-by-side" gap="none">
4027
+ <GridItem>
4028
+ <Tile>
4029
+ <span className="block text-center">1</span>
4030
+ </Tile>
4031
+ </GridItem>
4032
+ <GridItem>
4033
+ <Tile>
4034
+ <span className="block text-center">2</span>
4035
+ </Tile>
4036
+ </GridItem>
4037
+ </Grid>
4038
+ </div>
4039
+
4040
+ <div>
4041
+ <p className="mb-2 text-sf-subtle">gap="sm"</p>
4042
+ <Grid variant="side-by-side" gap="sm">
4043
+ <GridItem>
4044
+ <Tile>
4045
+ <span className="block text-center">1</span>
4046
+ </Tile>
4047
+ </GridItem>
4048
+ <GridItem>
4049
+ <Tile>
4050
+ <span className="block text-center">2</span>
4051
+ </Tile>
4052
+ </GridItem>
4053
+ </Grid>
4054
+ </div>
4055
+
4056
+ <div>
4057
+ <p className="mb-2 text-sf-subtle">gap="base" (default, responsive)</p>
4058
+ <Grid variant="side-by-side" gap="base">
4059
+ <GridItem>
4060
+ <Tile>
4061
+ <span className="block text-center">1</span>
4062
+ </Tile>
4063
+ </GridItem>
4064
+ <GridItem>
4065
+ <Tile>
4066
+ <span className="block text-center">2</span>
4067
+ </Tile>
4068
+ </GridItem>
4069
+ </Grid>
4070
+ </div>
4071
+
4072
+ <div>
4073
+ <p className="mb-2 text-sf-subtle">gap="lg"</p>
4074
+ <Grid variant="side-by-side" gap="lg">
4075
+ <GridItem>
4076
+ <Tile>
4077
+ <span className="block text-center">1</span>
4078
+ </Tile>
4079
+ </GridItem>
4080
+ <GridItem>
4081
+ <Tile>
4082
+ <span className="block text-center">2</span>
4083
+ </Tile>
4084
+ </GridItem>
4085
+ </Grid>
4086
+ </div>
4087
+ </div>
4088
+ ```
4089
+
4090
+ ```tsx
4091
+ <Grid variant="4up" gap="base" mobileDivider>
4092
+ <GridItem>
4093
+ <Tile>
4094
+ <div>Item 1</div>
4095
+ <div className="mt-1">Has divider on mobile</div>
4096
+ </Tile>
4097
+ </GridItem>
4098
+ <GridItem>
4099
+ <Tile>
4100
+ <div>Item 2</div>
4101
+ <div className="mt-1">Has divider on mobile</div>
4102
+ </Tile>
4103
+ </GridItem>
4104
+ <GridItem>
4105
+ <Tile>
4106
+ <div>Item 3</div>
4107
+ <div className="mt-1">Has divider on mobile</div>
4108
+ </Tile>
4109
+ </GridItem>
4110
+ <GridItem>
4111
+ <Tile>
4112
+ <div>Item 4</div>
4113
+ <div className="mt-1">Has divider on mobile</div>
4114
+ </Tile>
4115
+ </GridItem>
4116
+ </Grid>
4117
+ ```
4118
+
1723
4119
  ---
1724
4120
 
1725
4121
  ### Input
@@ -1765,6 +4161,87 @@ Input component
1765
4161
 
1766
4162
  - **Dimensions:** `[object Object]`
1767
4163
 
4164
+ **Examples:**
4165
+
4166
+ ```tsx
4167
+ <Input
4168
+ label="Email"
4169
+ placeholder="you@example.com"
4170
+ description="We'll never share your email"
4171
+ />
4172
+ ```
4173
+
4174
+ ```tsx
4175
+ <Input
4176
+ label="Email"
4177
+ placeholder="you@example.com"
4178
+ value="invalid-email"
4179
+ variant="error"
4180
+ error="Please enter a valid email address"
4181
+ />
4182
+ ```
4183
+
4184
+ ```tsx
4185
+ <Input
4186
+ label="Password"
4187
+ type="password"
4188
+ value="short"
4189
+ variant="error"
4190
+ error={{
4191
+ match: "tooShort",
4192
+ message: "Password must be at least 8 characters",
4193
+ }}
4194
+ minLength={8}
4195
+ />
4196
+ ```
4197
+
4198
+ ```tsx
4199
+ <div className="flex flex-col gap-4">
4200
+ <Input size="xs" label="Extra Small" placeholder="Extra small input" />
4201
+ <Input size="sm" label="Small" placeholder="Small input" />
4202
+ <Input label="Base" placeholder="Base input (default)" />
4203
+ <Input size="lg" label="Large" placeholder="Large input" />
4204
+ </div>
4205
+ ```
4206
+
4207
+ ```tsx
4208
+ <Input label="Disabled field" placeholder="Cannot edit" disabled />
4209
+ ```
4210
+
4211
+ ```tsx
4212
+ <div className="flex flex-col gap-4">
4213
+ <Input type="email" label="Email" placeholder="you@example.com" />
4214
+ <Input type="password" label="Password" placeholder="••••••••" />
4215
+ <Input type="number" label="Age" placeholder="18" />
4216
+ <Input type="tel" label="Phone" placeholder="+1 (555) 000-0000" />
4217
+ </div>
4218
+ ```
4219
+
4220
+ ```tsx
4221
+ <Input label="Phone Number" required={false} placeholder="+1 (555) 000-0000" />
4222
+ ```
4223
+
4224
+ ```tsx
4225
+ <Input
4226
+ label="API Key"
4227
+ labelTooltip="Find this in your dashboard under Settings > API Keys"
4228
+ placeholder="sk_live_..."
4229
+ />
4230
+ ```
4231
+
4232
+ ```tsx
4233
+ <Input
4234
+ label={
4235
+ <span>
4236
+ Email for <strong>billing</strong>
4237
+ </span>
4238
+ }
4239
+ required
4240
+ placeholder="billing@company.com"
4241
+ type="email"
4242
+ />
4243
+ ```
4244
+
1768
4245
  ---
1769
4246
 
1770
4247
  ### Label
@@ -1796,6 +4273,56 @@ Label component for form fields. Provides a standardized way to display labels w
1796
4273
 
1797
4274
  `text-sf-default`, `text-sf-strong`
1798
4275
 
4276
+ **Examples:**
4277
+
4278
+ ```tsx
4279
+ <div className="flex flex-col gap-4">
4280
+ <Label>Default Label</Label>
4281
+ <Label showOptional>Optional Label</Label>
4282
+ <Label tooltip="More information about this field">Label with Tooltip</Label>
4283
+ </div>
4284
+ ```
4285
+
4286
+ ```tsx
4287
+ <Input label="Phone Number" required={false} placeholder="+1 555-0000" />
4288
+ ```
4289
+
4290
+ ```tsx
4291
+ <Input
4292
+ label="API Key"
4293
+ labelTooltip="Find this in your dashboard settings under API > Keys"
4294
+ placeholder="sk_live_..."
4295
+ />
4296
+ ```
4297
+
4298
+ ```tsx
4299
+ <Checkbox
4300
+ label={
4301
+ <span>
4302
+ I agree to the <strong>Terms of Service</strong>
4303
+ </span>
4304
+ }
4305
+ />
4306
+ ```
4307
+
4308
+ ```tsx
4309
+ <div className="flex max-w-md flex-col gap-4">
4310
+ <Input label="Full Name" placeholder="John Doe" />
4311
+ <Input
4312
+ label="Email"
4313
+ labelTooltip="We'll send your receipt here"
4314
+ placeholder="john@example.com"
4315
+ type="email"
4316
+ />
4317
+ <Input label="Company" required={false} placeholder="Acme Inc." />
4318
+ <Select label="Country" hideLabel={false} placeholder="Select a country">
4319
+ <Select.Option value="us">United States</Select.Option>
4320
+ <Select.Option value="uk">United Kingdom</Select.Option>
4321
+ <Select.Option value="ca">Canada</Select.Option>
4322
+ </Select>
4323
+ </div>
4324
+ ```
4325
+
1799
4326
  ---
1800
4327
 
1801
4328
  ### LayerCard
@@ -1828,10 +4355,64 @@ This is a compound component. Use these sub-components:
1828
4355
 
1829
4356
  Primary sub-component
1830
4357
 
4358
+ Props:
4359
+
4360
+ - `className`: string
4361
+
1831
4362
  #### LayerCard.Secondary
1832
4363
 
1833
4364
  Secondary sub-component
1834
4365
 
4366
+ Props:
4367
+
4368
+ - `className`: string
4369
+
4370
+ **Examples:**
4371
+
4372
+ ```tsx
4373
+ <LayerCard>
4374
+ <LayerCard.Secondary className="flex items-center justify-between">
4375
+ <div>Next Steps</div>
4376
+ <Button
4377
+ variant="ghost"
4378
+ size="sm"
4379
+ shape="square"
4380
+ aria-label="Go to next steps"
4381
+ >
4382
+ <ArrowRightIcon size={16} />
4383
+ </Button>
4384
+ </LayerCard.Secondary>
4385
+
4386
+ <LayerCard.Primary>Get started with SF</LayerCard.Primary>
4387
+ </LayerCard>
4388
+ ```
4389
+
4390
+ ```tsx
4391
+ <LayerCard className="w-[250px]">
4392
+ <LayerCard.Secondary>Getting Started</LayerCard.Secondary>
4393
+ <LayerCard.Primary>
4394
+ <p className="text-sm text-sf-subtle">Quick start guide for new users</p>
4395
+ </LayerCard.Primary>
4396
+ </LayerCard>
4397
+ ```
4398
+
4399
+ ```tsx
4400
+ <div className="flex gap-4">
4401
+ <LayerCard className="w-[200px]">
4402
+ <LayerCard.Secondary>Components</LayerCard.Secondary>
4403
+ <LayerCard.Primary>
4404
+ <p className="text-sm">Browse all components</p>
4405
+ </LayerCard.Primary>
4406
+ </LayerCard>
4407
+ <LayerCard className="w-[200px]">
4408
+ <LayerCard.Secondary>Examples</LayerCard.Secondary>
4409
+ <LayerCard.Primary>
4410
+ <p className="text-sm">View code examples</p>
4411
+ </LayerCard.Primary>
4412
+ </LayerCard>
4413
+ </div>
4414
+ ```
4415
+
1835
4416
  ---
1836
4417
 
1837
4418
  ### Link
@@ -1882,6 +4463,69 @@ This is a compound component. Use these sub-components:
1882
4463
 
1883
4464
  ExternalIcon sub-component
1884
4465
 
4466
+ **Examples:**
4467
+
4468
+ ```tsx
4469
+ <div className="grid gap-x-6 gap-y-4 text-base md:grid-cols-3">
4470
+ <Link href="#">Default inline link</Link>
4471
+ <Link href="#" variant="current">
4472
+ Current color link
4473
+ </Link>
4474
+ <Link href="#" variant="plain">
4475
+ Plain inline link
4476
+ </Link>
4477
+ </div>
4478
+ ```
4479
+
4480
+ ```tsx
4481
+ <p className="mx-auto max-w-md text-base leading-relaxed text-sf-default">
4482
+ This is a paragraph with an <Link href="#">inline link</Link> that flows
4483
+ naturally with the surrounding text. Links maintain proper underline offset
4484
+ for readability.
4485
+ </p>
4486
+ ```
4487
+
4488
+ ```tsx
4489
+ <Link
4490
+ href="https://cloudflare.com"
4491
+ target="_blank"
4492
+ rel="noopener noreferrer"
4493
+ className="text-base"
4494
+ >
4495
+ Visit Cloudflare <Link.ExternalIcon />
4496
+ </Link>
4497
+ ```
4498
+
4499
+ ```tsx
4500
+ <p className="text-base text-sf-danger">
4501
+ This error message contains a{" "}
4502
+ <Link href="#" variant="current">
4503
+ link
4504
+ </Link>{" "}
4505
+ that inherits the red color from its parent.
4506
+ </p>
4507
+ ```
4508
+
4509
+ ```tsx
4510
+ <div className="flex flex-col gap-x-6 gap-y-4 text-base md:flex-row">
4511
+ <Link render={<CustomRouterLink href="/dashboard" />} variant="inline">
4512
+ Dashboard (via render)
4513
+ </Link>
4514
+ <Link
4515
+ render={
4516
+ <CustomRouterLink
4517
+ href="https://developers.cloudflare.com"
4518
+ target="_blank"
4519
+ rel="noopener noreferrer"
4520
+ />
4521
+ }
4522
+ variant="inline"
4523
+ >
4524
+ Cloudflare Docs <Link.ExternalIcon />
4525
+ </Link>
4526
+ </div>
4527
+ ```
4528
+
1885
4529
  ---
1886
4530
 
1887
4531
  ### Loader
@@ -1903,6 +4547,20 @@ Animated circular spinner for indicating loading states. Uses CSS keyframe anima
1903
4547
  - `"base"`: Default loader size
1904
4548
  - `"lg"`: Large loader for prominent loading states
1905
4549
 
4550
+ **Examples:**
4551
+
4552
+ ```tsx
4553
+ <div className="flex items-center gap-4">
4554
+ <Loader size="sm" />
4555
+ <Loader size="base" />
4556
+ <Loader size="lg" />
4557
+ </div>
4558
+ ```
4559
+
4560
+ ```tsx
4561
+ <Loader size={24} />
4562
+ ```
4563
+
1906
4564
  ---
1907
4565
 
1908
4566
  ### MenuBar
@@ -1932,6 +4590,29 @@ MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. E
1932
4590
 
1933
4591
  **Styling:**
1934
4592
 
4593
+ **Examples:**
4594
+
4595
+ ```tsx
4596
+ <MenuBar
4597
+ isActive="bold"
4598
+ optionIds
4599
+ options={[
4600
+ {
4601
+ icon: <TextBolderIcon />,
4602
+ id: "bold",
4603
+ onClick: () => {},
4604
+ tooltip: "Bold",
4605
+ },
4606
+ {
4607
+ icon: <TextItalicIcon />,
4608
+ id: "italic",
4609
+ onClick: () => {},
4610
+ tooltip: "Italic",
4611
+ },
4612
+ ]}
4613
+ />
4614
+ ```
4615
+
1935
4616
  ---
1936
4617
 
1937
4618
  ### Meter
@@ -1967,6 +4648,28 @@ Progress bar showing a measured value within a known range (e.g. quota usage).
1967
4648
 
1968
4649
  `bg-sf-fill`, `text-sf-default`, `text-sf-strong`
1969
4650
 
4651
+ **Examples:**
4652
+
4653
+ ```tsx
4654
+ <Meter label="Storage used" value={65} />
4655
+ ```
4656
+
4657
+ ```tsx
4658
+ <Meter label="API requests" value={75} customValue="750 / 1,000" />
4659
+ ```
4660
+
4661
+ ```tsx
4662
+ <Meter label="Progress" value={40} showValue={false} />
4663
+ ```
4664
+
4665
+ ```tsx
4666
+ <Meter
4667
+ label="Upload progress"
4668
+ value={80}
4669
+ indicatorClassName="from-green-500 via-green-500 to-green-500"
4670
+ />
4671
+ ```
4672
+
1970
4673
  ---
1971
4674
 
1972
4675
  ### Pagination
@@ -2001,6 +4704,32 @@ Page navigation controls with page count display.
2001
4704
 
2002
4705
  **Styling:**
2003
4706
 
4707
+ **Examples:**
4708
+
4709
+ ```tsx
4710
+ <Pagination page={page} setPage={setPage} perPage={10} totalCount={100} />
4711
+ ```
4712
+
4713
+ ```tsx
4714
+ <Pagination
4715
+ page={page}
4716
+ setPage={setPage}
4717
+ perPage={10}
4718
+ totalCount={100}
4719
+ controls="simple"
4720
+ />
4721
+ ```
4722
+
4723
+ ```tsx
4724
+ <Pagination
4725
+ text={({ perPage }) => `Page ${page} - showing ${perPage} per page`}
4726
+ page={page}
4727
+ setPage={setPage}
4728
+ perPage={25}
4729
+ totalCount={100}
4730
+ />
4731
+ ```
4732
+
2004
4733
  ---
2005
4734
 
2006
4735
  ### Popover
@@ -2033,10 +4762,22 @@ This is a compound component. Use these sub-components:
2033
4762
 
2034
4763
  Trigger sub-component
2035
4764
 
4765
+ Props:
4766
+
4767
+ - `asChild`: boolean
4768
+
2036
4769
  #### Popover.Content
2037
4770
 
2038
4771
  Content sub-component
2039
4772
 
4773
+ Props:
4774
+
4775
+ - `align`: PopoverAlign
4776
+ - `sideOffset`: number
4777
+ - `alignOffset`: number
4778
+ - `className`: string
4779
+ - `children`: ReactNode
4780
+
2040
4781
  #### Popover.Title
2041
4782
 
2042
4783
  Title sub-component
@@ -2049,6 +4790,150 @@ Description sub-component
2049
4790
 
2050
4791
  Close sub-component
2051
4792
 
4793
+ Props:
4794
+
4795
+ - `asChild`: boolean
4796
+
4797
+ **Examples:**
4798
+
4799
+ ```tsx
4800
+ <Popover>
4801
+ <Popover.Trigger asChild>
4802
+ <Button shape="square" icon={BellIcon} aria-label="Notifications" />
4803
+ </Popover.Trigger>
4804
+ <Popover.Content>
4805
+ <Popover.Title>Notifications</Popover.Title>
4806
+ <Popover.Description>You are all caught up. Good job!</Popover.Description>
4807
+ </Popover.Content>
4808
+ </Popover>
4809
+ ```
4810
+
4811
+ ```tsx
4812
+ <Popover>
4813
+ <Popover.Trigger asChild>
4814
+ <Button>Open Popover</Button>
4815
+ </Popover.Trigger>
4816
+ <Popover.Content>
4817
+ <Popover.Title>Popover Title</Popover.Title>
4818
+ <Popover.Description>
4819
+ This is a basic popover with a title and description.
4820
+ </Popover.Description>
4821
+ </Popover.Content>
4822
+ </Popover>
4823
+ ```
4824
+
4825
+ ```tsx
4826
+ <Popover>
4827
+ <Popover.Trigger asChild>
4828
+ <Button>Open Settings</Button>
4829
+ </Popover.Trigger>
4830
+ <Popover.Content>
4831
+ <Popover.Title>Settings</Popover.Title>
4832
+ <Popover.Description>Configure your preferences below.</Popover.Description>
4833
+ <div className="mt-3">
4834
+ <Popover.Close asChild>
4835
+ <Button variant="secondary" size="sm">
4836
+ Close
4837
+ </Button>
4838
+ </Popover.Close>
4839
+ </div>
4840
+ </Popover.Content>
4841
+ </Popover>
4842
+ ```
4843
+
4844
+ ```tsx
4845
+ <div className="flex flex-wrap gap-4">
4846
+ <Popover>
4847
+ <Popover.Trigger asChild>
4848
+ <Button variant="secondary">Bottom</Button>
4849
+ </Popover.Trigger>
4850
+ <Popover.Content side="bottom">
4851
+ <Popover.Title>Bottom</Popover.Title>
4852
+ <Popover.Description>Popover on bottom (default).</Popover.Description>
4853
+ </Popover.Content>
4854
+ </Popover>
4855
+
4856
+ <Popover>
4857
+ <Popover.Trigger asChild>
4858
+ <Button variant="secondary">Top</Button>
4859
+ </Popover.Trigger>
4860
+ <Popover.Content side="top">
4861
+ <Popover.Title>Top</Popover.Title>
4862
+ <Popover.Description>Popover on top.</Popover.Description>
4863
+ </Popover.Content>
4864
+ </Popover>
4865
+
4866
+ <Popover>
4867
+ <Popover.Trigger asChild>
4868
+ <Button variant="secondary">Left</Button>
4869
+ </Popover.Trigger>
4870
+ <Popover.Content side="left">
4871
+ <Popover.Title>Left</Popover.Title>
4872
+ <Popover.Description>Popover on left.</Popover.Description>
4873
+ </Popover.Content>
4874
+ </Popover>
4875
+
4876
+ <Popover>
4877
+ <Popover.Trigger asChild>
4878
+ <Button variant="secondary">Right</Button>
4879
+ </Popover.Trigger>
4880
+ <Popover.Content side="right">
4881
+ <Popover.Title>Right</Popover.Title>
4882
+ <Popover.Description>Popover on right.</Popover.Description>
4883
+ </Popover.Content>
4884
+ </Popover>
4885
+ </div>
4886
+ ```
4887
+
4888
+ ```tsx
4889
+ <Popover>
4890
+ <Popover.Trigger asChild>
4891
+ <Button>User Profile</Button>
4892
+ </Popover.Trigger>
4893
+ <Popover.Content className="w-64">
4894
+ <div className="flex items-center gap-3">
4895
+ <div className="size-10 rounded-full bg-sf-recessed" />
4896
+ <div>
4897
+ <Popover.Title>Jane Doe</Popover.Title>
4898
+ <p className="text-sm text-sf-subtle">jane@example.com</p>
4899
+ </div>
4900
+ </div>
4901
+ <div className="mt-3 flex gap-2 border-t border-sf-line pt-3">
4902
+ <Button variant="secondary" size="sm" className="flex-1">
4903
+ Profile
4904
+ </Button>
4905
+ <Popover.Close asChild>
4906
+ <Button variant="ghost" size="sm" className="flex-1">
4907
+ Sign Out
4908
+ </Button>
4909
+ </Popover.Close>
4910
+ </div>
4911
+ </Popover.Content>
4912
+ </Popover>
4913
+ ```
4914
+
4915
+ ```tsx
4916
+ <Popover>
4917
+ <Popover.Trigger openOnHover delay={200} asChild>
4918
+ <Button variant="secondary">Hover Me</Button>
4919
+ </Popover.Trigger>
4920
+ <Popover.Content>
4921
+ <Popover.Title>Hover Triggered</Popover.Title>
4922
+ <Popover.Description>
4923
+ This popover opens on hover with a 200ms delay. It can still contain
4924
+ interactive content like buttons and links.
4925
+ </Popover.Description>
4926
+ <div className="mt-3">
4927
+ <Popover.Close asChild>
4928
+ <Button variant="secondary" size="sm">
4929
+ Got it
4930
+ </Button>
4931
+ </Popover.Close>
4932
+ </div>
4933
+ </Popover.Content>
4934
+ </Popover>
4935
+ ```
4936
+
2052
4937
  ---
2053
4938
 
2054
4939
  ### PromptInput
@@ -2071,8 +4956,10 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
2071
4956
  Maximum file size in bytes.
2072
4957
  - `backLayer`: ReactNode
2073
4958
  Content rendered in the collapsible back layer (e.g. HITL approvals, task lists). When provided the prompt input is wrapped in a LayerCard shell with a header row containing a chevron toggle. Use `PromptInputBackLayer` to compose structured content for this slot.
2074
- - `backLayerTitle`: string
2075
- Title shown in the back layer header row. Defaults to `"Context"`.
4959
+ - `backLayerTitle`: ReactNode
4960
+ Header content shown in the back layer header row. Strings render as plain text; pass JSX to compose with icons/spinners/badges. Defaults to `"Context"`.
4961
+ - `backLayerStatus`: enum
4962
+ Optional status indicator rendered next to the title. `"running"` shows a small spinner; `"error"` shows an inline error icon. Use this instead of composing JSX into `backLayerTitle` for the common case of an agent doing work.
2076
4963
  - `backLayerOpen`: boolean
2077
4964
  Controls whether the back layer is visible. Pair with `onBackLayerOpenChange` for a controlled pattern.
2078
4965
  - `autoOpenBackLayerWhen`: boolean
@@ -2085,7 +4972,7 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
2085
4972
 
2086
4973
  **Colors (sf tokens used):**
2087
4974
 
2088
- `bg-sf-base`, `bg-sf-control`, `bg-sf-elevated`, `bg-sf-info-tint`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-info`, `ring-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-subtle`
4975
+ `bg-sf-base`, `bg-sf-control`, `bg-sf-elevated`, `bg-sf-info-tint`, `bg-sf-overlay`, `bg-sf-tint`, `border-sf-info`, `ring-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-inactive`, `text-sf-strong`, `text-sf-subtle`
2089
4976
 
2090
4977
  **Sub-Components:**
2091
4978
 
@@ -2095,6 +4982,10 @@ This is a compound component. Use these sub-components:
2095
4982
 
2096
4983
  BackLayer sub-component
2097
4984
 
4985
+ Props:
4986
+
4987
+ - `className`: string
4988
+
2098
4989
  #### PromptInput.Textarea
2099
4990
 
2100
4991
  Textarea sub-component
@@ -2127,10 +5018,18 @@ AddTagButton sub-component
2127
5018
 
2128
5019
  Tags sub-component
2129
5020
 
5021
+ Props:
5022
+
5023
+ - `children`: (tag: PromptInputTagData) => ReactNode (required)
5024
+
2130
5025
  #### PromptInput.Tag
2131
5026
 
2132
5027
  Tag sub-component
2133
5028
 
5029
+ Props:
5030
+
5031
+ - `data`: PromptInputTagData (required)
5032
+
2134
5033
  #### PromptInput.AttachButton
2135
5034
 
2136
5035
  AttachButton sub-component
@@ -2139,10 +5038,17 @@ AttachButton sub-component
2139
5038
 
2140
5039
  Attachments sub-component
2141
5040
 
5041
+ Props:
5042
+
5043
+ - `children`: (attachment: AttachmentFile) => ReactNode (required)
5044
+
2142
5045
  #### PromptInput.Attachment
2143
5046
 
2144
5047
  Attachment sub-component
2145
5048
 
5049
+ Props:
5050
+
5051
+ - `data`: AttachmentFile (required)
2146
5052
 
2147
5053
  ---
2148
5054
 
@@ -2183,6 +5089,77 @@ Radio — radio button group for single-select choices. Compound component: `Rad
2183
5089
 
2184
5090
  `bg-sf-base`, `bg-sf-contrast`, `border-sf-line`, `ring-sf-danger`, `ring-sf-interact`, `ring-sf-ring`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`
2185
5091
 
5092
+ **Examples:**
5093
+
5094
+ ```tsx
5095
+ <Radio.Group
5096
+ legend="Notification preference"
5097
+ value={value}
5098
+ onValueChange={setValue}
5099
+ >
5100
+ <Radio.Item label="Email" value="email" />
5101
+ <Radio.Item label="SMS" value="sms" />
5102
+ <Radio.Item label="Push notification" value="push" />
5103
+ </Radio.Group>
5104
+ ```
5105
+
5106
+ ```tsx
5107
+ <Radio.Group
5108
+ legend="Size"
5109
+ orientation="horizontal"
5110
+ value={value}
5111
+ onValueChange={setValue}
5112
+ >
5113
+ <Radio.Item label="Small" value="sm" />
5114
+ <Radio.Item label="Medium" value="md" />
5115
+ <Radio.Item label="Large" value="lg" />
5116
+ </Radio.Group>
5117
+ ```
5118
+
5119
+ ```tsx
5120
+ <Radio.Group
5121
+ legend="Shipping method"
5122
+ description="Choose how you'd like to receive your order"
5123
+ value={value}
5124
+ onValueChange={setValue}
5125
+ >
5126
+ <Radio.Item label="Standard (5-7 days)" value="standard" />
5127
+ <Radio.Item label="Express (2-3 days)" value="express" />
5128
+ <Radio.Item label="Overnight" value="overnight" />
5129
+ </Radio.Group>
5130
+ ```
5131
+
5132
+ ```tsx
5133
+ <Radio.Group
5134
+ legend="Payment method"
5135
+ error="Please select a payment method to continue"
5136
+ >
5137
+ <Radio.Item label="Credit Card" value="card" variant="error" />
5138
+ <Radio.Item label="PayPal" value="paypal" variant="error" />
5139
+ <Radio.Item label="Bank Transfer" value="bank" variant="error" />
5140
+ </Radio.Group>
5141
+ ```
5142
+
5143
+ ```tsx
5144
+ <div className="flex flex-col gap-6">
5145
+ <Radio.Group legend="Disabled group" disabled defaultValue="a">
5146
+ <Radio.Item label="Option A" value="a" />
5147
+ <Radio.Item label="Option B" value="b" />
5148
+ </Radio.Group>
5149
+ <Radio.Group legend="Individual disabled" defaultValue="available">
5150
+ <Radio.Item label="Available" value="available" />
5151
+ <Radio.Item label="Unavailable" value="unavailable" disabled />
5152
+ </Radio.Group>
5153
+ </div>
5154
+ ```
5155
+
5156
+ ```tsx
5157
+ <Radio.Group legend="Preferences" controlPosition="end" defaultValue="a">
5158
+ <Radio.Item label="Label before radio" value="a" />
5159
+ <Radio.Item label="Another option" value="b" />
5160
+ </Radio.Group>
5161
+ ```
5162
+
2186
5163
  ---
2187
5164
 
2188
5165
  ### Select
@@ -2240,6 +5217,105 @@ This is a compound component. Use these sub-components:
2240
5217
 
2241
5218
  Option sub-component
2242
5219
 
5220
+ **Examples:**
5221
+
5222
+ ```tsx
5223
+ <Select
5224
+ className="w-[200px]"
5225
+ value={value}
5226
+ onValueChange={(v) => setValue(v ?? "apple")}
5227
+ items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
5228
+ >
5229
+ <Select.Option value="apple">Apple</Select.Option>
5230
+ <Select.Option value="banana">Banana</Select.Option>
5231
+ <Select.Option value="cherry">Cherry</Select.Option>
5232
+ </Select>
5233
+ ```
5234
+
5235
+ ```tsx
5236
+ <Select
5237
+ className="w-[200px]"
5238
+ renderValue={(v) => (
5239
+ <span>
5240
+ {v.emoji} {v.label}
5241
+ </span>
5242
+ )}
5243
+ value={value}
5244
+ onValueChange={(v) => setValue(v as (typeof languages)[0])}
5245
+ >
5246
+ {languages.map((language) => (
5247
+ <Select.Option key={language.value} value={language}>
5248
+ {language.emoji} {language.label}
5249
+ </Select.Option>
5250
+ ))}
5251
+ </Select>
5252
+ ```
5253
+
5254
+ ```tsx
5255
+ <Select className="w-[200px]" loading />
5256
+ ```
5257
+
5258
+ ```tsx
5259
+ <Select
5260
+ className="w-[200px]"
5261
+ loading={loading}
5262
+ value={value}
5263
+ onValueChange={(v) => setValue(v as string | null)}
5264
+ placeholder="Please select"
5265
+ >
5266
+ {data?.map((item) => (
5267
+ <Select.Option key={item} value={item}>
5268
+ {item}
5269
+ </Select.Option>
5270
+ ))}
5271
+ </Select>
5272
+ ```
5273
+
5274
+ ```tsx
5275
+ <Select
5276
+ className="w-[250px]"
5277
+ multiple
5278
+ renderValue={(value) => {
5279
+ if (value.length > 3) {
5280
+ return (
5281
+ <span className="line-clamp-1">
5282
+ {value.slice(2).join(", ") + ` and ${value.length - 2} more`}
5283
+ </span>
5284
+ );
5285
+ }
5286
+ return <span>{value.join(", ")}</span>;
5287
+ }}
5288
+ value={value}
5289
+ onValueChange={(v) => setValue(v as string[])}
5290
+ >
5291
+ <Select.Option value="Name">Name</Select.Option>
5292
+ <Select.Option value="Location">Location</Select.Option>
5293
+ <Select.Option value="Size">Size</Select.Option>
5294
+ <Select.Option value="Read">Read</Select.Option>
5295
+ <Select.Option value="Write">Write</Select.Option>
5296
+ <Select.Option value="CreatedAt">Created At</Select.Option>
5297
+ </Select>
5298
+ ```
5299
+
5300
+ ```tsx
5301
+ <Select
5302
+ className="w-[200px]"
5303
+ onValueChange={(v) => setValue(v as (typeof authors)[0] | null)}
5304
+ value={value}
5305
+ isItemEqualToValue={(item, value) => item?.id === value?.id}
5306
+ renderValue={(author) => author?.name ?? "Please select author"}
5307
+ >
5308
+ {authors.map((author) => (
5309
+ <Select.Option key={author.id} value={author}>
5310
+ <div className="flex w-[300px] items-center justify-between gap-2">
5311
+ <Text>{author.name}</Text>
5312
+ <Text variant="secondary">{author.title}</Text>
5313
+ </div>
5314
+ </Select.Option>
5315
+ ))}
5316
+ </Select>
5317
+ ```
5318
+
2243
5319
  ---
2244
5320
 
2245
5321
  ### SensitiveInput
@@ -2295,6 +5371,76 @@ Password/secret input that masks its value by default and reveals on click. Incl
2295
5371
 
2296
5372
  `bg-sf-brand`, `bg-sf-control`, `outline-sf-ring`, `text-sf-default`, `text-sf-subtle`
2297
5373
 
5374
+ **Examples:**
5375
+
5376
+ ```tsx
5377
+ <div className="w-80">
5378
+ <SensitiveInput label="API Key" defaultValue="sk_live_abc123xyz789" />
5379
+ </div>
5380
+ ```
5381
+
5382
+ ```tsx
5383
+ <div className="flex flex-col gap-4">
5384
+ {sizes.map((size) => (
5385
+ <div key={size} className="flex items-center gap-2">
5386
+ <span className="w-12 text-sm text-sf-subtle">{size}</span>
5387
+ <SensitiveInput
5388
+ label={`${size} size`}
5389
+ size={size}
5390
+ defaultValue="secret-api-key-123"
5391
+ />
5392
+ </div>
5393
+ ))}
5394
+ </div>
5395
+ ```
5396
+
5397
+ ```tsx
5398
+ <div className="flex w-80 flex-col gap-4">
5399
+ <SensitiveInput
5400
+ label="Controlled Secret"
5401
+ value={value}
5402
+ onValueChange={setValue}
5403
+ />
5404
+ <div className="text-sm text-sf-subtle">
5405
+ Current value: <code className="text-sf-default">{value}</code>
5406
+ </div>
5407
+ <div className="flex gap-2">
5408
+ <Button
5409
+ onClick={() => setValue("new-secret-" + Date.now())}
5410
+ variant="primary"
5411
+ size="sm"
5412
+ >
5413
+ Change value
5414
+ </Button>
5415
+ <Button onClick={() => setValue("")} variant="secondary" size="sm">
5416
+ Clear
5417
+ </Button>
5418
+ </div>
5419
+ </div>
5420
+ ```
5421
+
5422
+ ```tsx
5423
+ <div className="flex w-80 flex-col gap-4">
5424
+ <SensitiveInput
5425
+ label="Error State"
5426
+ variant="error"
5427
+ defaultValue="invalid-key"
5428
+ error="This API key is not valid"
5429
+ />
5430
+ <SensitiveInput label="Disabled" defaultValue="cannot-edit" disabled />
5431
+ <SensitiveInput
5432
+ label="Read-only"
5433
+ defaultValue="view-only-secret-key"
5434
+ readOnly
5435
+ />
5436
+ <SensitiveInput
5437
+ label="With Description"
5438
+ defaultValue="my-secret-value"
5439
+ description="Keep this value secure and don't share it"
5440
+ />
5441
+ </div>
5442
+ ```
5443
+
2298
5444
  ---
2299
5445
 
2300
5446
  ### Sidebar
@@ -2457,6 +5603,283 @@ CollapsibleTrigger sub-component
2457
5603
 
2458
5604
  CollapsibleContent sub-component
2459
5605
 
5606
+ **Examples:**
5607
+
5608
+ ```tsx
5609
+ <DemoContainer>
5610
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5611
+ <Sidebar>
5612
+ <Sidebar.Content>
5613
+ <Sidebar.Group>
5614
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5615
+ <Sidebar.Menu>
5616
+ <Sidebar.MenuButton icon={HouseIcon} active>
5617
+ Home
5618
+ </Sidebar.MenuButton>
5619
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5620
+ Analytics
5621
+ </Sidebar.MenuButton>
5622
+ <Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
5623
+ </Sidebar.Menu>
5624
+ </Sidebar.Group>
5625
+
5626
+ <Sidebar.Group>
5627
+ <Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
5628
+ <Sidebar.Menu>
5629
+ <Sidebar.MenuItem>
5630
+ <Sidebar.Collapsible defaultOpen>
5631
+ <Sidebar.CollapsibleTrigger
5632
+ render={
5633
+ <Sidebar.MenuButton icon={CodeIcon}>
5634
+ Compute
5635
+ <Sidebar.MenuChevron />
5636
+ </Sidebar.MenuButton>
5637
+ }
5638
+ />
5639
+ <Sidebar.CollapsibleContent>
5640
+ <Sidebar.MenuSub>
5641
+ <Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
5642
+ <Sidebar.MenuSubButton>
5643
+ Durable Objects
5644
+ </Sidebar.MenuSubButton>
5645
+ </Sidebar.MenuSub>
5646
+ </Sidebar.CollapsibleContent>
5647
+ </Sidebar.Collapsible>
5648
+ </Sidebar.MenuItem>
5649
+ <Sidebar.MenuButton icon={DatabaseIcon}>Storage</Sidebar.MenuButton>
5650
+ </Sidebar.Menu>
5651
+ </Sidebar.Group>
5652
+ </Sidebar.Content>
5653
+ </Sidebar>
5654
+ <DemoMain />
5655
+ </Sidebar.Provider>
5656
+ </DemoContainer>
5657
+ ```
5658
+
5659
+ ```tsx
5660
+ <DemoContainer>
5661
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5662
+ <Sidebar>
5663
+ <Sidebar.Content>
5664
+ <Sidebar.Group collapsible defaultOpen>
5665
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5666
+ <Sidebar.GroupContent>
5667
+ <Sidebar.Menu>
5668
+ <Sidebar.MenuButton icon={HouseIcon} active>
5669
+ Home
5670
+ </Sidebar.MenuButton>
5671
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5672
+ Analytics
5673
+ </Sidebar.MenuButton>
5674
+ <Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
5675
+ </Sidebar.Menu>
5676
+ </Sidebar.GroupContent>
5677
+ </Sidebar.Group>
5678
+
5679
+ <Sidebar.Group collapsible defaultOpen={false}>
5680
+ <Sidebar.GroupLabel>Settings</Sidebar.GroupLabel>
5681
+ <Sidebar.GroupContent>
5682
+ <Sidebar.Menu>
5683
+ <Sidebar.MenuButton icon={ShieldCheckIcon}>
5684
+ Security
5685
+ </Sidebar.MenuButton>
5686
+ <Sidebar.MenuButton icon={LockIcon}>
5687
+ Access Control
5688
+ </Sidebar.MenuButton>
5689
+ </Sidebar.Menu>
5690
+ </Sidebar.GroupContent>
5691
+ </Sidebar.Group>
5692
+ </Sidebar.Content>
5693
+ </Sidebar>
5694
+ <DemoMain />
5695
+ </Sidebar.Provider>
5696
+ </DemoContainer>
5697
+ ```
5698
+
5699
+ ```tsx
5700
+ <DemoContainer>
5701
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5702
+ <Sidebar>
5703
+ <Sidebar.Header>
5704
+ <BrandLogo />
5705
+ </Sidebar.Header>
5706
+ <Sidebar.Content>
5707
+ <Sidebar.Group>
5708
+ <Sidebar.Menu>
5709
+ <Sidebar.MenuButton icon={HouseIcon} tooltip="Home" active>
5710
+ Home
5711
+ </Sidebar.MenuButton>
5712
+ <Sidebar.MenuButton icon={ChartBarIcon} tooltip="Analytics">
5713
+ Analytics
5714
+ </Sidebar.MenuButton>
5715
+ <Sidebar.MenuButton icon={CodeIcon} tooltip="Compute">
5716
+ Compute
5717
+ </Sidebar.MenuButton>
5718
+ <Sidebar.MenuButton icon={DatabaseIcon} tooltip="Storage">
5719
+ Storage
5720
+ </Sidebar.MenuButton>
5721
+ </Sidebar.Menu>
5722
+ </Sidebar.Group>
5723
+ </Sidebar.Content>
5724
+ <Sidebar.Footer>
5725
+ <Sidebar.Trigger />
5726
+ </Sidebar.Footer>
5727
+ </Sidebar>
5728
+ <DemoMain>
5729
+ <ToggleButton />
5730
+ <p className="text-sm">
5731
+ Click the button or the sidebar trigger to toggle
5732
+ </p>
5733
+ </DemoMain>
5734
+ </Sidebar.Provider>
5735
+ </DemoContainer>
5736
+ ```
5737
+
5738
+ ```tsx
5739
+ <DemoContainer>
5740
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5741
+ <Sidebar>
5742
+ <Sidebar.Header>
5743
+ <BrandLogo />
5744
+ </Sidebar.Header>
5745
+
5746
+ <Sidebar.Content>
5747
+ <div className="px-1 pb-2">
5748
+ <Sidebar.Input placeholder="Quick search..." shortcut="⌘K" />
5749
+ </div>
5750
+
5751
+ <Sidebar.Group>
5752
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5753
+ <Sidebar.Menu>
5754
+ <Sidebar.MenuButton icon={HouseIcon} active>
5755
+ Home
5756
+ </Sidebar.MenuButton>
5757
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5758
+ Analytics
5759
+ </Sidebar.MenuButton>
5760
+ <Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
5761
+ </Sidebar.Menu>
5762
+ </Sidebar.Group>
5763
+
5764
+ <Sidebar.Separator />
5765
+
5766
+ <Sidebar.Group>
5767
+ <Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
5768
+ <Sidebar.Menu>
5769
+ <Sidebar.MenuItem>
5770
+ <Sidebar.Collapsible defaultOpen>
5771
+ <Sidebar.CollapsibleTrigger
5772
+ render={
5773
+ <Sidebar.MenuButton icon={CodeIcon}>
5774
+ Compute
5775
+ <Sidebar.MenuChevron />
5776
+ </Sidebar.MenuButton>
5777
+ }
5778
+ />
5779
+ <Sidebar.CollapsibleContent>
5780
+ <Sidebar.MenuSub>
5781
+ <Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
5782
+ <Sidebar.MenuSubButton>
5783
+ Durable Objects
5784
+ </Sidebar.MenuSubButton>
5785
+ <Sidebar.MenuSubButton>
5786
+ Containers
5787
+ <Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
5788
+ </Sidebar.MenuSubButton>
5789
+ </Sidebar.MenuSub>
5790
+ </Sidebar.CollapsibleContent>
5791
+ </Sidebar.Collapsible>
5792
+ </Sidebar.MenuItem>
5793
+ <Sidebar.MenuButton icon={DatabaseIcon}>Storage</Sidebar.MenuButton>
5794
+ </Sidebar.Menu>
5795
+ </Sidebar.Group>
5796
+
5797
+ <Sidebar.Group>
5798
+ <Sidebar.GroupLabel>Security</Sidebar.GroupLabel>
5799
+ <Sidebar.Menu>
5800
+ <Sidebar.MenuButton icon={ShieldCheckIcon}>
5801
+ Firewall
5802
+ </Sidebar.MenuButton>
5803
+ <Sidebar.MenuButton icon={LockIcon}>
5804
+ Access
5805
+ <Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
5806
+ </Sidebar.MenuButton>
5807
+ <Sidebar.MenuButton icon={BellIcon}>
5808
+ Notifications
5809
+ </Sidebar.MenuButton>
5810
+ </Sidebar.Menu>
5811
+ </Sidebar.Group>
5812
+ </Sidebar.Content>
5813
+
5814
+ <Sidebar.Footer>
5815
+ <Sidebar.MenuButton icon={GearIcon}>Settings</Sidebar.MenuButton>
5816
+ </Sidebar.Footer>
5817
+ </Sidebar>
5818
+ <DemoMain />
5819
+ </Sidebar.Provider>
5820
+ </DemoContainer>
5821
+ ```
5822
+
5823
+ ```tsx
5824
+ <DemoContainer>
5825
+ <Sidebar.Provider
5826
+ defaultOpen
5827
+ resizable
5828
+ defaultWidth={240}
5829
+ minWidth={180}
5830
+ maxWidth={400}
5831
+ className="min-h-0! h-full"
5832
+ >
5833
+ <Sidebar>
5834
+ <Sidebar.Header>
5835
+ <BrandLogo />
5836
+ </Sidebar.Header>
5837
+ <Sidebar.Content>
5838
+ <Sidebar.Group>
5839
+ <Sidebar.Menu>
5840
+ <Sidebar.MenuButton icon={HouseIcon} active>
5841
+ Home
5842
+ </Sidebar.MenuButton>
5843
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5844
+ Analytics
5845
+ </Sidebar.MenuButton>
5846
+ <Sidebar.MenuButton icon={GlobeIcon}>Domains</Sidebar.MenuButton>
5847
+ </Sidebar.Menu>
5848
+ </Sidebar.Group>
5849
+ </Sidebar.Content>
5850
+ <Sidebar.ResizeHandle />
5851
+ </Sidebar>
5852
+ <DemoMain>
5853
+ <p className="text-sm">Drag the sidebar edge to resize</p>
5854
+ </DemoMain>
5855
+ </Sidebar.Provider>
5856
+ </DemoContainer>
5857
+ ```
5858
+
5859
+ ```tsx
5860
+ <DemoContainer>
5861
+ <Sidebar.Provider defaultOpen side="right" className="min-h-0! h-full">
5862
+ <DemoMain>
5863
+ <p className="text-sm">Sidebar on the right</p>
5864
+ </DemoMain>
5865
+ <Sidebar>
5866
+ <Sidebar.Content>
5867
+ <Sidebar.Group>
5868
+ <Sidebar.GroupLabel>Details</Sidebar.GroupLabel>
5869
+ <Sidebar.Menu>
5870
+ <Sidebar.MenuButton icon={GearIcon} active>
5871
+ Properties
5872
+ </Sidebar.MenuButton>
5873
+ <Sidebar.MenuButton icon={ChartBarIcon}>Metrics</Sidebar.MenuButton>
5874
+ <Sidebar.MenuButton icon={BellIcon}>Alerts</Sidebar.MenuButton>
5875
+ </Sidebar.Menu>
5876
+ </Sidebar.Group>
5877
+ </Sidebar.Content>
5878
+ </Sidebar>
5879
+ </Sidebar.Provider>
5880
+ </DemoContainer>
5881
+ ```
5882
+
2460
5883
  ---
2461
5884
 
2462
5885
  ### SignalFlareAILogo
@@ -2732,6 +6155,127 @@ SignalFlare AI logo component.
2732
6155
 
2733
6156
  `bg-sf-base`, `ring-sf-line`, `text-sf-default`
2734
6157
 
6158
+ **Examples:**
6159
+
6160
+ ```tsx
6161
+ <SignalFlareAILogo className="w-72" />
6162
+ ```
6163
+
6164
+ ```tsx
6165
+ <SignalFlareAILogo variant="glyph" className="w-16" />
6166
+ ```
6167
+
6168
+ ```tsx
6169
+ <div className="flex flex-wrap items-center gap-8">
6170
+ <SignalFlareAILogo className="w-32" color="brand" />
6171
+ <SignalFlareAILogo className="w-32" color="mono" />
6172
+ <div className="rounded-lg bg-white p-4">
6173
+ <SignalFlareAILogo className="w-32" color="black" />
6174
+ </div>
6175
+ <div className="rounded-lg bg-black p-4">
6176
+ <SignalFlareAILogo className="w-32" color="white" />
6177
+ </div>
6178
+ </div>
6179
+ ```
6180
+
6181
+ ```tsx
6182
+ <div className="flex flex-wrap items-center gap-8">
6183
+ <SignalFlareAILogo variant="glyph" className="w-10" color="brand" />
6184
+ <SignalFlareAILogo variant="glyph" className="w-10" color="mono" />
6185
+ <div className="rounded-lg bg-white p-4">
6186
+ <SignalFlareAILogo variant="glyph" className="w-10" color="black" />
6187
+ </div>
6188
+ <div className="rounded-lg bg-black p-4">
6189
+ <SignalFlareAILogo variant="glyph" className="w-10" color="white" />
6190
+ </div>
6191
+ </div>
6192
+ ```
6193
+
6194
+ ```tsx
6195
+ <div className="flex flex-wrap items-end gap-6">
6196
+ <SignalFlareAILogo className="w-24" />
6197
+ <SignalFlareAILogo className="w-36" />
6198
+ <SignalFlareAILogo className="w-52" />
6199
+ </div>
6200
+ ```
6201
+
6202
+ ```tsx
6203
+ <div className="flex items-center gap-4">
6204
+ <DropdownMenu>
6205
+ <DropdownMenu.Trigger>
6206
+ <button
6207
+ type="button"
6208
+ className="flex items-center gap-2 rounded-lg bg-[#4188ff] px-4 py-3 text-white transition-opacity hover:opacity-80"
6209
+ >
6210
+ <SignalFlareAILogo variant="glyph" color="white" className="w-6" />
6211
+ <span className="font-medium">Logo</span>
6212
+ </button>
6213
+ </DropdownMenu.Trigger>
6214
+ <DropdownMenu.Content>
6215
+ <DropdownMenu.Item
6216
+ icon={MapPinIcon}
6217
+ onSelect={() =>
6218
+ copyToClipboard(
6219
+ generateSignalFlareAILogoSvg({ variant: "glyph" }),
6220
+ "glyph"
6221
+ )
6222
+ }
6223
+ >
6224
+ {copied === "glyph" ? "Copied!" : "Copy icon as SVG"}
6225
+ </DropdownMenu.Item>
6226
+ <DropdownMenu.Item
6227
+ icon={CodeIcon}
6228
+ onSelect={() =>
6229
+ copyToClipboard(
6230
+ generateSignalFlareAILogoSvg({ variant: "full" }),
6231
+ "full"
6232
+ )
6233
+ }
6234
+ >
6235
+ {copied === "full" ? "Copied!" : "Copy full logo as SVG"}
6236
+ </DropdownMenu.Item>
6237
+ <DropdownMenu.Separator />
6238
+ <DropdownMenu.Item
6239
+ icon={ArrowSquareOutIcon}
6240
+ onSelect={() =>
6241
+ window.open("https://signalflare.ai", "_blank", "noopener")
6242
+ }
6243
+ >
6244
+ Visit SignalFlare AI
6245
+ </DropdownMenu.Item>
6246
+ </DropdownMenu.Content>
6247
+ </DropdownMenu>
6248
+
6249
+ <span className="text-sm text-sf-subtle">
6250
+ Click to open the brand assets menu
6251
+ </span>
6252
+ </div>
6253
+ ```
6254
+
6255
+ ```tsx
6256
+ <PoweredBySignalFlareAI />
6257
+ ```
6258
+
6259
+ ```tsx
6260
+ <div className="flex flex-wrap items-center gap-4">
6261
+ <PoweredBySignalFlareAI color="brand" />
6262
+ <PoweredBySignalFlareAI color="mono" />
6263
+ <PoweredBySignalFlareAI color="black" />
6264
+ <div className="rounded-lg bg-black p-3">
6265
+ <PoweredBySignalFlareAI color="white" />
6266
+ </div>
6267
+ </div>
6268
+ ```
6269
+
6270
+ ```tsx
6271
+ <footer className="flex w-full items-center justify-between rounded-lg border border-sf-line bg-sf-elevated px-6 py-4">
6272
+ <span className="text-sm text-sf-subtle">
6273
+ &copy; 2026 Your Company. All rights reserved.
6274
+ </span>
6275
+ <PoweredBySignalFlareAI />
6276
+ </footer>
6277
+ ```
6278
+
2735
6279
  ---
2736
6280
 
2737
6281
  ### Sparkline
@@ -2751,11 +6295,26 @@ Sparkline — a tiny inline chart intended for embedding in cards, tables, or ro
2751
6295
  - `children`: ReactNode
2752
6296
  Child elements
2753
6297
 
6298
+ **Examples:**
6299
+
6300
+ ```tsx
6301
+ <Sparkline echarts={echarts} data={sample} isDarkMode={isDarkMode} />
6302
+ ```
6303
+
6304
+ ```tsx
6305
+ <Sparkline
6306
+ echarts={echarts}
6307
+ data={sample}
6308
+ variant="area"
6309
+ isDarkMode={isDarkMode}
6310
+ />
6311
+ ```
6312
+
2754
6313
  ---
2755
6314
 
2756
6315
  ### StatCard
2757
6316
 
2758
- StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline.
6317
+ StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline. Uses pretext-driven `Text` for consistent spacing and wrapping: - Labels use `wrap="balance"` for even multiline breaks - Values use `wrap="shrink"` so sparklines tuck tight against numbers - Hints use `wrap="natural"` (numeric content rarely wraps)
2759
6318
 
2760
6319
  **Type:** component
2761
6320
 
@@ -2786,6 +6345,24 @@ StatCard — compact KPI tile displaying a label, a primary value, and an option
2786
6345
 
2787
6346
  `bg-sf-elevated`, `bg-sf-fill`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
2788
6347
 
6348
+ **Examples:**
6349
+
6350
+ ```tsx
6351
+ <StatCard
6352
+ label="Active users"
6353
+ value="12,384"
6354
+ delta={{ value: 0.12, label: "vs last week" }}
6355
+ />
6356
+ ```
6357
+
6358
+ ```tsx
6359
+ <StatCard size="sm" label="MRR" value="$128,420" hint="30-day avg" />
6360
+ ```
6361
+
6362
+ ```tsx
6363
+ <StatCard label="Signups" value="—" loading />
6364
+ ```
6365
+
2789
6366
  ---
2790
6367
 
2791
6368
  ### Surface
@@ -2811,6 +6388,44 @@ Surface component
2811
6388
 
2812
6389
  `bg-sf-base`, `ring-sf-line`
2813
6390
 
6391
+ **Examples:**
6392
+
6393
+ ```tsx
6394
+ <Surface className="rounded-lg p-6">
6395
+ <Text size="lg" bold>
6396
+ Surface Component
6397
+ </Text>
6398
+ <div className="mt-2">
6399
+ <Text variant="secondary">
6400
+ A container with consistent elevation and border styling.
6401
+ </Text>
6402
+ </div>
6403
+ </Surface>
6404
+ ```
6405
+
6406
+ ```tsx
6407
+ <div className="flex flex-col gap-4">
6408
+ <Surface as="section" className="rounded-lg p-4">
6409
+ <Text bold>As section element</Text>
6410
+ </Surface>
6411
+ <Surface as="article" className="rounded-lg p-4">
6412
+ <Text bold>As article element</Text>
6413
+ </Surface>
6414
+ <Surface as="aside" className="rounded-lg p-4">
6415
+ <Text bold>As aside element</Text>
6416
+ </Surface>
6417
+ </div>
6418
+ ```
6419
+
6420
+ ```tsx
6421
+ <Surface className="rounded-lg p-6">
6422
+ <Text bold>Outer Surface</Text>
6423
+ <Surface className="mt-4 rounded-md bg-sf-elevated p-4">
6424
+ <Text variant="secondary">Nested Surface</Text>
6425
+ </Surface>
6426
+ </Surface>
6427
+ ```
6428
+
2814
6429
  ---
2815
6430
 
2816
6431
  ### Switch
@@ -2879,6 +6494,16 @@ Props:
2879
6494
  - `controlFirst`: boolean
2880
6495
  - `className`: string
2881
6496
 
6497
+ **Examples:**
6498
+
6499
+ ```tsx
6500
+ <Switch label="Switch" checked={checked} onCheckedChange={setChecked} />
6501
+ ```
6502
+
6503
+ ```tsx
6504
+ <Switch label="Disabled" checked={false} disabled />
6505
+ ```
6506
+
2882
6507
  ---
2883
6508
 
2884
6509
  ### Table
@@ -2948,6 +6573,234 @@ Footer sub-component
2948
6573
 
2949
6574
  ResizeHandle sub-component
2950
6575
 
6576
+ **Examples:**
6577
+
6578
+ ```tsx
6579
+ <LayerCard>
6580
+ <LayerCard.Primary className="p-0">
6581
+ <Table>
6582
+ <Table.Header>
6583
+ <Table.Row>
6584
+ <Table.Head>Subject</Table.Head>
6585
+ <Table.Head>From</Table.Head>
6586
+ <Table.Head>Date</Table.Head>
6587
+ </Table.Row>
6588
+ </Table.Header>
6589
+ <Table.Body>
6590
+ {emailData.slice(0, 3).map((row) => (
6591
+ <Table.Row key={row.id}>
6592
+ <Table.Cell>{row.subject}</Table.Cell>
6593
+ <Table.Cell>{row.from}</Table.Cell>
6594
+ <Table.Cell>{row.date}</Table.Cell>
6595
+ </Table.Row>
6596
+ ))}
6597
+ </Table.Body>
6598
+ </Table>
6599
+ </LayerCard.Primary>
6600
+ </LayerCard>
6601
+ ```
6602
+
6603
+ ```tsx
6604
+ <LayerCard>
6605
+ <LayerCard.Primary className="p-0">
6606
+ <Table>
6607
+ <Table.Header>
6608
+ <Table.Row>
6609
+ <Table.CheckHead
6610
+ checked={selectedIds.size === rows.length}
6611
+ indeterminate={
6612
+ selectedIds.size > 0 && selectedIds.size < rows.length
6613
+ }
6614
+ onValueChange={toggleAll}
6615
+ aria-label="Select all rows"
6616
+ />
6617
+ <Table.Head>Subject</Table.Head>
6618
+ <Table.Head>From</Table.Head>
6619
+ <Table.Head>Date</Table.Head>
6620
+ </Table.Row>
6621
+ </Table.Header>
6622
+ <Table.Body>
6623
+ {rows.map((row) => (
6624
+ <Table.Row key={row.id}>
6625
+ <Table.CheckCell
6626
+ checked={selectedIds.has(row.id)}
6627
+ onValueChange={() => toggleRow(row.id)}
6628
+ aria-label={`Select ${row.subject}`}
6629
+ />
6630
+ <Table.Cell>{row.subject}</Table.Cell>
6631
+ <Table.Cell>{row.from}</Table.Cell>
6632
+ <Table.Cell>{row.date}</Table.Cell>
6633
+ </Table.Row>
6634
+ ))}
6635
+ </Table.Body>
6636
+ </Table>
6637
+ </LayerCard.Primary>
6638
+ </LayerCard>
6639
+ ```
6640
+
6641
+ ```tsx
6642
+ <LayerCard>
6643
+ <LayerCard.Primary className="p-0">
6644
+ <Table>
6645
+ <Table.Header>
6646
+ <Table.Row>
6647
+ <Table.CheckHead
6648
+ checked={selectedIds.size === rows.length}
6649
+ indeterminate={
6650
+ selectedIds.size > 0 && selectedIds.size < rows.length
6651
+ }
6652
+ onValueChange={toggleAll}
6653
+ aria-label="Select all rows"
6654
+ />
6655
+ <Table.Head>Subject</Table.Head>
6656
+ <Table.Head>From</Table.Head>
6657
+ <Table.Head>Date</Table.Head>
6658
+ </Table.Row>
6659
+ </Table.Header>
6660
+ <Table.Body>
6661
+ {rows.map((row) => (
6662
+ <Table.Row
6663
+ key={row.id}
6664
+ variant={selectedIds.has(row.id) ? "selected" : "default"}
6665
+ >
6666
+ <Table.CheckCell
6667
+ checked={selectedIds.has(row.id)}
6668
+ onValueChange={() => toggleRow(row.id)}
6669
+ aria-label={`Select ${row.subject}`}
6670
+ />
6671
+ <Table.Cell>{row.subject}</Table.Cell>
6672
+ <Table.Cell>{row.from}</Table.Cell>
6673
+ <Table.Cell>{row.date}</Table.Cell>
6674
+ </Table.Row>
6675
+ ))}
6676
+ </Table.Body>
6677
+ </Table>
6678
+ </LayerCard.Primary>
6679
+ </LayerCard>
6680
+ ```
6681
+
6682
+ ```tsx
6683
+ <LayerCard>
6684
+ <LayerCard.Primary className="p-0">
6685
+ <Table layout="fixed">
6686
+ <colgroup>
6687
+ <col />
6688
+ <col className="w-[150px]" />
6689
+ <col className="w-[150px]" />
6690
+ </colgroup>
6691
+ <Table.Header>
6692
+ <Table.Row>
6693
+ <Table.Head>Subject</Table.Head>
6694
+ <Table.Head>From</Table.Head>
6695
+ <Table.Head>Date</Table.Head>
6696
+ </Table.Row>
6697
+ </Table.Header>
6698
+ <Table.Body>
6699
+ {emailData.map((row) => (
6700
+ <Table.Row key={row.id}>
6701
+ <Table.Cell>{row.subject}</Table.Cell>
6702
+ <Table.Cell>{row.from}</Table.Cell>
6703
+ <Table.Cell>{row.date}</Table.Cell>
6704
+ </Table.Row>
6705
+ ))}
6706
+ </Table.Body>
6707
+ </Table>
6708
+ </LayerCard.Primary>
6709
+ </LayerCard>
6710
+ ```
6711
+
6712
+ ```tsx
6713
+ <LayerCard>
6714
+ <LayerCard.Primary className="w-full overflow-x-auto p-0">
6715
+ <Table layout="fixed">
6716
+ <colgroup>
6717
+ <col />{" "}
6718
+ {/* Checkbox column - width handled by Table.CheckHead/CheckCell */}
6719
+ <col />
6720
+ <col style={{ width: "150px" }} />
6721
+ <col style={{ width: "120px" }} />
6722
+ <col style={{ width: "50px" }} />
6723
+ </colgroup>
6724
+ <Table.Header>
6725
+ <Table.Row>
6726
+ <Table.CheckHead
6727
+ checked={selectedIds.size === emailData.length}
6728
+ indeterminate={
6729
+ selectedIds.size > 0 && selectedIds.size < emailData.length
6730
+ }
6731
+ onValueChange={toggleAll}
6732
+ aria-label="Select all rows"
6733
+ />
6734
+ <Table.Head>Subject</Table.Head>
6735
+ <Table.Head>From</Table.Head>
6736
+ <Table.Head>Date</Table.Head>
6737
+ <Table.Head />
6738
+ </Table.Row>
6739
+ </Table.Header>
6740
+ <Table.Body>
6741
+ {emailData.map((row) => (
6742
+ <Table.Row
6743
+ key={row.id}
6744
+ variant={selectedIds.has(row.id) ? "selected" : "default"}
6745
+ >
6746
+ <Table.CheckCell
6747
+ checked={selectedIds.has(row.id)}
6748
+ onValueChange={() => toggleRow(row.id)}
6749
+ aria-label={`Select ${row.subject}`}
6750
+ />
6751
+ <Table.Cell>
6752
+ <div className="flex items-center gap-2">
6753
+ <EnvelopeSimpleIcon size={16} />
6754
+ <span className="truncate">{row.subject}</span>
6755
+ {row.tags && (
6756
+ <div className="ml-2 inline-flex gap-1">
6757
+ {row.tags.map((tag) => (
6758
+ <Badge key={tag}>{tag}</Badge>
6759
+ ))}
6760
+ </div>
6761
+ )}
6762
+ </div>
6763
+ </Table.Cell>
6764
+ <Table.Cell>
6765
+ <span className="truncate">{row.from}</span>
6766
+ </Table.Cell>
6767
+ <Table.Cell>
6768
+ <span className="truncate">{row.date}</span>
6769
+ </Table.Cell>
6770
+ <Table.Cell className="text-right">
6771
+ <DropdownMenu>
6772
+ <DropdownMenu.Trigger
6773
+ render={
6774
+ <Button
6775
+ variant="ghost"
6776
+ size="sm"
6777
+ shape="square"
6778
+ aria-label="More options"
6779
+ >
6780
+ <DotsThreeIcon weight="bold" size={16} />
6781
+ </Button>
6782
+ }
6783
+ />
6784
+ <DropdownMenu.Content>
6785
+ <DropdownMenu.Item icon={EyeIcon}>View</DropdownMenu.Item>
6786
+ <DropdownMenu.Item icon={PencilSimpleIcon}>
6787
+ Edit
6788
+ </DropdownMenu.Item>
6789
+ <DropdownMenu.Separator />
6790
+ <DropdownMenu.Item icon={TrashIcon} variant="danger">
6791
+ Delete
6792
+ </DropdownMenu.Item>
6793
+ </DropdownMenu.Content>
6794
+ </DropdownMenu>
6795
+ </Table.Cell>
6796
+ </Table.Row>
6797
+ ))}
6798
+ </Table.Body>
6799
+ </Table>
6800
+ </LayerCard.Primary>
6801
+ </LayerCard>
6802
+ ```
6803
+
2951
6804
  ---
2952
6805
 
2953
6806
  ### Tabs
@@ -2990,6 +6843,114 @@ Tab navigation component with segmented, underline, or pill style. Built on Base
2990
6843
 
2991
6844
  **Styling:**
2992
6845
 
6846
+ **Examples:**
6847
+
6848
+ ```tsx
6849
+ <div className="flex flex-col gap-6">
6850
+ <div>
6851
+ <p className="mb-2 text-sm text-sf-subtle">Segmented (default)</p>
6852
+ <Tabs
6853
+ variant="segmented"
6854
+ tabs={[
6855
+ { label: "Tab 1", value: "tab1" },
6856
+ { label: "Tab 2", value: "tab2" },
6857
+ { label: "Tab 3", value: "tab3" },
6858
+ ]}
6859
+ selectedValue="tab1"
6860
+ />
6861
+ </div>
6862
+ <div>
6863
+ <p className="mb-2 text-sm text-sf-subtle">Underline</p>
6864
+ <Tabs
6865
+ variant="underline"
6866
+ tabs={[
6867
+ { label: "Tab 1", value: "tab1" },
6868
+ { label: "Tab 2", value: "tab2" },
6869
+ { label: "Tab 3", value: "tab3" },
6870
+ ]}
6871
+ selectedValue="tab1"
6872
+ />
6873
+ </div>
6874
+ <div>
6875
+ <p className="mb-2 text-sm text-sf-subtle">Pill</p>
6876
+ <Tabs
6877
+ variant="pill"
6878
+ tabs={[
6879
+ { label: "Tab 1", value: "tab1" },
6880
+ { label: "Tab 2", value: "tab2" },
6881
+ { label: "Tab 3", value: "tab3" },
6882
+ ]}
6883
+ selectedValue="tab1"
6884
+ />
6885
+ </div>
6886
+ </div>
6887
+ ```
6888
+
6889
+ ```tsx
6890
+ <Tabs
6891
+ variant="segmented"
6892
+ tabs={[
6893
+ { label: "Tab 1", value: "tab1" },
6894
+ { label: "Tab 2", value: "tab2" },
6895
+ { label: "Tab 3", value: "tab3" },
6896
+ ]}
6897
+ selectedValue="tab1"
6898
+ />
6899
+ ```
6900
+
6901
+ ```tsx
6902
+ <div className="space-y-4">
6903
+ <Tabs
6904
+ tabs={[
6905
+ { label: "Tab 1", value: "tab1" },
6906
+ { label: "Tab 2", value: "tab2" },
6907
+ { label: "Tab 3", value: "tab3" },
6908
+ ]}
6909
+ value={activeTab}
6910
+ onValueChange={setActiveTab}
6911
+ />
6912
+ <p className="text-sm text-sf-subtle">
6913
+ Active tab: <code className="text-sm">{activeTab}</code>
6914
+ </p>
6915
+ </div>
6916
+ ```
6917
+
6918
+ ```tsx
6919
+ <Tabs
6920
+ tabs={[
6921
+ { label: "Overview", value: "overview" },
6922
+ { label: "Analytics", value: "analytics" },
6923
+ { label: "Reports", value: "reports" },
6924
+ { label: "Notifications", value: "notifications" },
6925
+ { label: "Settings", value: "settings" },
6926
+ { label: "Billing", value: "billing" },
6927
+ ]}
6928
+ selectedValue="overview"
6929
+ />
6930
+ ```
6931
+
6932
+ ```tsx
6933
+ <Tabs
6934
+ tabs={[
6935
+ {
6936
+ label: "Regular Tab",
6937
+ value: "tab1",
6938
+ },
6939
+ {
6940
+ label: "Link Tab",
6941
+ render: (props) => <a {...props} href="#tab2" />,
6942
+ value: "tab2",
6943
+ },
6944
+ {
6945
+ label: "Another Link",
6946
+ render: (props) => <a {...props} href="#tab3" />,
6947
+ value: "tab3",
6948
+ },
6949
+ ]}
6950
+ selectedValue="tab1"
6951
+ />
6952
+ ```
6953
+
2993
6954
  ---
2994
6955
 
2995
6956
  ### Text
@@ -3025,6 +6986,14 @@ Text component
3025
6986
  The HTML element type to render as (e.g. `"span"`, `"p"`, `"h1"`). Auto-selected based on variant if omitted.
3026
6987
  - `children`: ReactNode
3027
6988
  Text content.
6989
+ - `wrap`: MeasuredTextMode | boolean
6990
+ Text layout strategy using pretext-driven measurement.
6991
+ - `"natural"` — No measurement, normal browser wrapping (default for body).
6992
+ - `"balance"` — Even wrapping, smallest maxWidth without adding lines (default for headings).
6993
+ - `"shrink"` — Hug widest natural line (maxWidth = line width). Good for chat bubbles.
6994
+ - `"reserve"` — Reserve height based on line count. Good for streaming text.
6995
+ - `reserveLines`: number
6996
+ For `wrap="reserve"`: reserve this many lines of height. If omitted, measures current content to determine line count.
3028
6997
 
3029
6998
  **Colors (sf tokens used):**
3030
6999
 
@@ -3032,6 +7001,71 @@ Text component
3032
7001
 
3033
7002
  **Styling:**
3034
7003
 
7004
+ **Examples:**
7005
+
7006
+ ```tsx
7007
+ <div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
7008
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7009
+ <Text variant="heading1">Heading 1</Text>
7010
+ <p className="font-mono text-xs text-sf-subtle">text-3xl (30px)</p>
7011
+ </div>
7012
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7013
+ <Text variant="heading2">Heading 2</Text>
7014
+ <p className="font-mono text-xs text-sf-subtle">text-2xl (24px)</p>
7015
+ </div>
7016
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7017
+ <Text variant="heading3">Heading 3</Text>
7018
+ <p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
7019
+ </div>
7020
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7021
+ <Text>Body</Text>
7022
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7023
+ </div>
7024
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7025
+ <Text bold>Body bold</Text>
7026
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7027
+ </div>
7028
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7029
+ <Text size="lg">Body lg</Text>
7030
+ <p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
7031
+ </div>
7032
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7033
+ <Text size="sm">Body sm</Text>
7034
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7035
+ </div>
7036
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7037
+ <Text size="xs">Body xs</Text>
7038
+ <p className="font-mono text-xs text-sf-subtle">text-xs (12px)</p>
7039
+ </div>
7040
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7041
+ <Text variant="secondary">Body secondary</Text>
7042
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7043
+ </div>
7044
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7045
+ <Text variant="mono">Monospace</Text>
7046
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7047
+ </div>
7048
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7049
+ <Text variant="mono" size="lg">
7050
+ Monospace lg
7051
+ </Text>
7052
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7053
+ </div>
7054
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7055
+ <Text variant="mono-secondary">Monospace secondary</Text>
7056
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7057
+ </div>
7058
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7059
+ <Text variant="success">Success</Text>
7060
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7061
+ </div>
7062
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7063
+ <Text variant="error">Error</Text>
7064
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7065
+ </div>
7066
+ </div>
7067
+ ```
7068
+
3035
7069
  ---
3036
7070
 
3037
7071
  ### TextRoll
@@ -3149,6 +7183,33 @@ Accessible popup that shows additional information on hover/focus. Wrap your app
3149
7183
 
3150
7184
  `bg-sf-elevated`, `fill-sf-elevated`, `fill-sf-tip-shadow`, `fill-sf-tip-stroke`, `outline-sf-fill`, `text-sf-default`
3151
7185
 
7186
+ **Examples:**
7187
+
7188
+ ```tsx
7189
+ <TooltipProvider>
7190
+ <Tooltip content="Add new item">
7191
+ <Button shape="square" icon={PlusIcon} aria-label="Add new item" />
7192
+ </Tooltip>
7193
+ </TooltipProvider>
7194
+ ```
7195
+
7196
+ ```tsx
7197
+ <TooltipProvider>
7198
+ <div className="flex gap-2">
7199
+ <Tooltip content="Add">
7200
+ <Button shape="square" icon={PlusIcon} aria-label="Add" />
7201
+ </Tooltip>
7202
+ <Tooltip content="Change language">
7203
+ <Button
7204
+ shape="square"
7205
+ icon={TranslateIcon}
7206
+ aria-label="Change language"
7207
+ />
7208
+ </Tooltip>
7209
+ </div>
7210
+ </TooltipProvider>
7211
+ ```
7212
+
3152
7213
  ---
3153
7214
 
3154
7215
  ### InputArea