@signalflare-ai/ui 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/CHANGELOG.md +37 -4
  2. package/README.md +1 -1
  3. package/ai/component-registry.json +1047 -183
  4. package/ai/component-registry.md +4241 -50
  5. package/ai/schemas.ts +99 -502
  6. package/dist/.build-complete +1 -1
  7. package/dist/ai/schemas.d.ts +76 -58
  8. package/dist/ai/schemas.d.ts.map +1 -1
  9. package/dist/{ai-actions-DSVeQn4e.js → ai-actions-BdUZI3Gk.js} +3 -3
  10. package/dist/{ai-actions-DSVeQn4e.js.map → ai-actions-BdUZI3Gk.js.map} +1 -1
  11. package/dist/{ai-agent-card-BXHwhWAU.js → ai-agent-card-BR2NIYhi.js} +1 -1
  12. package/dist/{ai-agent-card-BXHwhWAU.js.map → ai-agent-card-BR2NIYhi.js.map} +1 -1
  13. package/dist/{ai-approval-aa0qvjFN.js → ai-approval-Ba7mrKba.js} +2 -2
  14. package/dist/{ai-approval-aa0qvjFN.js.map → ai-approval-Ba7mrKba.js.map} +1 -1
  15. package/dist/{ai-code-block-BgtIxtZZ.js → ai-code-block-CZtoL73R.js} +3 -3
  16. package/dist/{ai-code-block-BgtIxtZZ.js.map → ai-code-block-CZtoL73R.js.map} +1 -1
  17. package/dist/ai-conversation-Cc7WlaBg.js +242 -0
  18. package/dist/ai-conversation-Cc7WlaBg.js.map +1 -0
  19. package/dist/{ai-info-banner-uFxHHwBA.js → ai-info-banner-C7EWPBj7.js} +7 -3
  20. package/dist/ai-info-banner-C7EWPBj7.js.map +1 -0
  21. package/dist/{ai-message-BjnFznXy.js → ai-message-Bp7L68U_.js} +27 -8
  22. package/dist/ai-message-Bp7L68U_.js.map +1 -0
  23. package/dist/{ai-mission-header-08__gULL.js → ai-mission-header-TiCJfTNt.js} +1 -1
  24. package/dist/{ai-mission-header-08__gULL.js.map → ai-mission-header-TiCJfTNt.js.map} +1 -1
  25. package/dist/{ai-part-group-DBtgTgAn.js → ai-part-group-DNb9I446.js} +3 -3
  26. package/dist/{ai-part-group-DBtgTgAn.js.map → ai-part-group-DNb9I446.js.map} +1 -1
  27. package/dist/{ai-prompt-input-Dy1LfxPk.js → ai-prompt-input-BVvov_KF.js} +467 -25
  28. package/dist/ai-prompt-input-BVvov_KF.js.map +1 -0
  29. package/dist/{ai-question-CHHoDJMg.js → ai-question-GPPMk7YM.js} +2 -2
  30. package/dist/{ai-question-CHHoDJMg.js.map → ai-question-GPPMk7YM.js.map} +1 -1
  31. package/dist/{ai-reasoning-CnL6ZSr5.js → ai-reasoning-_feFjk56.js} +2 -2
  32. package/dist/{ai-reasoning-CnL6ZSr5.js.map → ai-reasoning-_feFjk56.js.map} +1 -1
  33. package/dist/{ai-response-BEUg3xvd.js → ai-response-CvjV3WhV.js} +8 -3
  34. package/dist/ai-response-CvjV3WhV.js.map +1 -0
  35. package/dist/{ai-shimmer-By5_L05p.js → ai-shimmer-j6lKIrjj.js} +1 -1
  36. package/dist/{ai-shimmer-By5_L05p.js.map → ai-shimmer-j6lKIrjj.js.map} +1 -1
  37. package/dist/{ai-status-badge-BGYGWYF6.js → ai-status-badge-CSU_QOdz.js} +1 -1
  38. package/dist/{ai-status-badge-BGYGWYF6.js.map → ai-status-badge-CSU_QOdz.js.map} +1 -1
  39. package/dist/{ai-streaming-text-CMfoThV0.js → ai-streaming-text-IWW1BhvZ.js} +44 -16
  40. package/dist/ai-streaming-text-IWW1BhvZ.js.map +1 -0
  41. package/dist/{ai-subagent-DcPRqkAA.js → ai-subagent-JA4iIMW3.js} +13 -5
  42. package/dist/ai-subagent-JA4iIMW3.js.map +1 -0
  43. package/dist/{ai-suggestion-MgeCg5Ar.js → ai-suggestion-BdO6MBuH.js} +2 -2
  44. package/dist/{ai-suggestion-MgeCg5Ar.js.map → ai-suggestion-BdO6MBuH.js.map} +1 -1
  45. package/dist/{ai-task-list-Da9zIm00.js → ai-task-list-DYw4R1FA.js} +12 -5
  46. package/dist/ai-task-list-DYw4R1FA.js.map +1 -0
  47. package/dist/{ai-timeline-Cwu045IR.js → ai-timeline-C42tOUT8.js} +1 -1
  48. package/dist/{ai-timeline-Cwu045IR.js.map → ai-timeline-C42tOUT8.js.map} +1 -1
  49. package/dist/{ai-tool-Cn1O4xjP.js → ai-tool-03jOTwUI.js} +23 -10
  50. package/dist/ai-tool-03jOTwUI.js.map +1 -0
  51. package/dist/{ai-usage-bar-DjS12DMp.js → ai-usage-bar-BRf5LC_b.js} +1 -1
  52. package/dist/{ai-usage-bar-DjS12DMp.js.map → ai-usage-bar-BRf5LC_b.js.map} +1 -1
  53. package/dist/{badge-D_eaA6wv.js → badge-BheXjMc8.js} +2 -2
  54. package/dist/{badge-D_eaA6wv.js.map → badge-BheXjMc8.js.map} +1 -1
  55. package/dist/{banner-B_6oBrsu.js → banner-CcsjunJg.js} +7 -2
  56. package/dist/banner-CcsjunJg.js.map +1 -0
  57. package/dist/{breadcrumbs-BlmeYfgq.js → breadcrumbs-CouSyy3H.js} +3 -3
  58. package/dist/{breadcrumbs-BlmeYfgq.js.map → breadcrumbs-CouSyy3H.js.map} +1 -1
  59. package/dist/{button-De0267YU.js → button-CO6-qPax.js} +1 -1
  60. package/dist/{button-De0267YU.js.map → button-CO6-qPax.js.map} +1 -1
  61. package/dist/catalog.js +1 -1
  62. package/dist/{chart-BK3sVPnD.js → chart-Dg0qUeSc.js} +2 -2
  63. package/dist/{chart-BK3sVPnD.js.map → chart-Dg0qUeSc.js.map} +1 -1
  64. package/dist/{checkbox-DYhUmZNw.js → checkbox-D7p4QKsC.js} +2 -2
  65. package/dist/{checkbox-DYhUmZNw.js.map → checkbox-D7p4QKsC.js.map} +1 -1
  66. package/dist/{clipboard-text-ssybngLw.js → clipboard-text-kLaMogs3.js} +3 -3
  67. package/dist/{clipboard-text-ssybngLw.js.map → clipboard-text-kLaMogs3.js.map} +1 -1
  68. package/dist/{code-Cx-QSoOT.js → code-BN8InC0G.js} +2 -2
  69. package/dist/{code-Cx-QSoOT.js.map → code-BN8InC0G.js.map} +1 -1
  70. package/dist/{collapsible-DWsXeXmS.js → collapsible-D_ueZ0jz.js} +1 -1
  71. package/dist/{collapsible-DWsXeXmS.js.map → collapsible-D_ueZ0jz.js.map} +1 -1
  72. package/dist/{combobox-C0iW6a0r.js → combobox-B7TOK0U2.js} +3 -3
  73. package/dist/{combobox-C0iW6a0r.js.map → combobox-B7TOK0U2.js.map} +1 -1
  74. package/dist/{command-palette-DGzioeki.js → command-palette-CuNUyJca.js} +2 -2
  75. package/dist/{command-palette-DGzioeki.js.map → command-palette-CuNUyJca.js.map} +1 -1
  76. package/dist/components/ai-actions.js +1 -1
  77. package/dist/components/ai-agent-card.js +1 -1
  78. package/dist/components/ai-approval.js +1 -1
  79. package/dist/components/ai-code-block.js +1 -1
  80. package/dist/components/ai-conversation.js +2 -2
  81. package/dist/components/ai-info-banner.js +1 -1
  82. package/dist/components/ai-message.js +1 -1
  83. package/dist/components/ai-mission-header.js +1 -1
  84. package/dist/components/ai-part-group.js +1 -1
  85. package/dist/components/ai-prompt-input.js +2 -2
  86. package/dist/components/ai-question.js +1 -1
  87. package/dist/components/ai-reasoning.js +1 -1
  88. package/dist/components/ai-response.js +1 -1
  89. package/dist/components/ai-shimmer.js +1 -1
  90. package/dist/components/ai-status-badge.js +1 -1
  91. package/dist/components/ai-streaming-text.js +2 -2
  92. package/dist/components/ai-subagent.js +1 -1
  93. package/dist/components/ai-suggestion.js +1 -1
  94. package/dist/components/ai-task-list.js +1 -1
  95. package/dist/components/ai-timeline.js +1 -1
  96. package/dist/components/ai-tool.js +1 -1
  97. package/dist/components/ai-usage-bar.js +1 -1
  98. package/dist/components/badge.js +1 -1
  99. package/dist/components/banner.js +1 -1
  100. package/dist/components/breadcrumbs.js +1 -1
  101. package/dist/components/button.js +1 -1
  102. package/dist/components/chart.js +2 -2
  103. package/dist/components/checkbox.js +1 -1
  104. package/dist/components/clipboard-text.js +1 -1
  105. package/dist/components/code.js +1 -1
  106. package/dist/components/collapsible.js +1 -1
  107. package/dist/components/combobox.js +1 -1
  108. package/dist/components/command-palette.js +1 -1
  109. package/dist/components/data-grid.js +1 -1
  110. package/dist/components/date-picker.js +1 -1
  111. package/dist/components/date-range-picker.js +1 -1
  112. package/dist/components/dialog.js +1 -1
  113. package/dist/components/dropdown.js +1 -1
  114. package/dist/components/empty.js +1 -1
  115. package/dist/components/field.js +1 -1
  116. package/dist/components/filters.js +1 -1
  117. package/dist/components/flow.js +1 -1
  118. package/dist/components/grid.js +1 -1
  119. package/dist/components/input.js +2 -2
  120. package/dist/components/label.js +1 -1
  121. package/dist/components/layer-card.js +1 -1
  122. package/dist/components/loader.js +1 -1
  123. package/dist/components/menubar.js +1 -1
  124. package/dist/components/meter.js +1 -1
  125. package/dist/components/pagination.js +1 -1
  126. package/dist/components/popover.js +1 -1
  127. package/dist/components/radio.js +1 -1
  128. package/dist/components/select.js +1 -1
  129. package/dist/components/sensitive-input.js +1 -1
  130. package/dist/components/sidebar.js +1 -1
  131. package/dist/components/signalflare-ai-logo.js +1 -1
  132. package/dist/components/sparkline.js +1 -1
  133. package/dist/components/stat-card.js +1 -1
  134. package/dist/components/surface.js +1 -1
  135. package/dist/components/switch.js +1 -1
  136. package/dist/components/table.js +1 -1
  137. package/dist/components/tabs.js +1 -1
  138. package/dist/components/text-roll.js +1 -1
  139. package/dist/components/text.js +1 -1
  140. package/dist/components/theme-toggle.js +1 -1
  141. package/dist/components/toast.js +1 -1
  142. package/dist/components/tooltip.js +1 -1
  143. package/dist/components/use-agent-harness.js +1 -1
  144. package/dist/{data-grid-CG76N_hK.js → data-grid-DGHmU0w3.js} +8 -8
  145. package/dist/{data-grid-CG76N_hK.js.map → data-grid-DGHmU0w3.js.map} +1 -1
  146. package/dist/{date-picker-Dqg9L4xu.js → date-picker--ox89RBy.js} +1 -1
  147. package/dist/{date-picker-Dqg9L4xu.js.map → date-picker--ox89RBy.js.map} +1 -1
  148. package/dist/{date-range-picker-D75LLINc.js → date-range-picker-DVa7QBqE.js} +1 -1
  149. package/dist/{date-range-picker-D75LLINc.js.map → date-range-picker-DVa7QBqE.js.map} +1 -1
  150. package/dist/{dialog-CyHEQXEY.js → dialog-Bv1oSFOd.js} +2 -2
  151. package/dist/{dialog-CyHEQXEY.js.map → dialog-Bv1oSFOd.js.map} +1 -1
  152. package/dist/{dist-1-gcEL2L.js → dist-B6iWiWwp.js} +25 -25
  153. package/dist/{dist-1-gcEL2L.js.map → dist-B6iWiWwp.js.map} +1 -1
  154. package/dist/{dropdown-qnEYRFXZ.js → dropdown-B_nrGXjV.js} +2 -2
  155. package/dist/{dropdown-qnEYRFXZ.js.map → dropdown-B_nrGXjV.js.map} +1 -1
  156. package/dist/{echart-DURZEyai.js → echart-CdOUaT-r.js} +1 -1
  157. package/dist/{echart-DURZEyai.js.map → echart-CdOUaT-r.js.map} +1 -1
  158. package/dist/{empty-D2TypIId.js → empty-DZnN0zKX.js} +11 -6
  159. package/dist/empty-DZnN0zKX.js.map +1 -0
  160. package/dist/{field-Y_UK1_Cg.js → field-B_yVof52.js} +2 -2
  161. package/dist/{field-Y_UK1_Cg.js.map → field-B_yVof52.js.map} +1 -1
  162. package/dist/{filters-Bw_U6ZTx.js → filters-cpJCY21R.js} +7 -7
  163. package/dist/{filters-Bw_U6ZTx.js.map → filters-cpJCY21R.js.map} +1 -1
  164. package/dist/{flow-BRsYUCJa.js → flow-B4v198ot.js} +1 -1
  165. package/dist/{flow-BRsYUCJa.js.map → flow-B4v198ot.js.map} +1 -1
  166. package/dist/genui.js +1 -1
  167. package/dist/{grid-qUAN9hFx.js → grid-CEd64Lnh.js} +1 -1
  168. package/dist/{grid-qUAN9hFx.js.map → grid-CEd64Lnh.js.map} +1 -1
  169. package/dist/{highlight-to-react-ClEfL81q.js → highlight-to-react-D0Yav4jk.js} +1 -1
  170. package/dist/{highlight-to-react-ClEfL81q.js.map → highlight-to-react-D0Yav4jk.js.map} +1 -1
  171. package/dist/index.js +69 -69
  172. package/dist/{input-DXYUjGgD.js → input-B2bbijRh.js} +2 -2
  173. package/dist/{input-DXYUjGgD.js.map → input-B2bbijRh.js.map} +1 -1
  174. package/dist/{input-DddtBN-g.js → input-ClB_E4Lb.js} +4 -4
  175. package/dist/{input-DddtBN-g.js.map → input-ClB_E4Lb.js.map} +1 -1
  176. package/dist/{label-QtJxtJ4u.js → label-DUv_urO1.js} +2 -2
  177. package/dist/{label-QtJxtJ4u.js.map → label-DUv_urO1.js.map} +1 -1
  178. package/dist/{layer-card-BME0eljh.js → layer-card-BK7eYfwn.js} +1 -1
  179. package/dist/{layer-card-BME0eljh.js.map → layer-card-BK7eYfwn.js.map} +1 -1
  180. package/dist/layout-DJHMMap2.js +6103 -0
  181. package/dist/layout-DJHMMap2.js.map +1 -0
  182. package/dist/measured-text-BI3dTJmH.js +290 -0
  183. package/dist/measured-text-BI3dTJmH.js.map +1 -0
  184. package/dist/{menubar-C8NzAjfd.js → menubar-Cxf3xeAt.js} +2 -2
  185. package/dist/{menubar-C8NzAjfd.js.map → menubar-Cxf3xeAt.js.map} +1 -1
  186. package/dist/{meter-CpmTenEr.js → meter-BFFe9l5b.js} +1 -1
  187. package/dist/{meter-CpmTenEr.js.map → meter-BFFe9l5b.js.map} +1 -1
  188. package/dist/{pagination-BVqdlONY.js → pagination-yS372Tr4.js} +2 -2
  189. package/dist/{pagination-BVqdlONY.js.map → pagination-yS372Tr4.js.map} +1 -1
  190. package/dist/{popover-BRQZ2b6z.js → popover-SRoJaCZr.js} +1 -1
  191. package/dist/{popover-BRQZ2b6z.js.map → popover-SRoJaCZr.js.map} +1 -1
  192. package/dist/{radio-BNSwOt3B.js → radio-BcwhwYNB.js} +1 -1
  193. package/dist/{radio-BNSwOt3B.js.map → radio-BcwhwYNB.js.map} +1 -1
  194. package/dist/{select-1w2aebGQ.js → select-DMhdoHMa.js} +4 -4
  195. package/dist/{select-1w2aebGQ.js.map → select-DMhdoHMa.js.map} +1 -1
  196. package/dist/{sensitive-input-82Cez3vj.js → sensitive-input-CJUpIRal.js} +3 -3
  197. package/dist/{sensitive-input-82Cez3vj.js.map → sensitive-input-CJUpIRal.js.map} +1 -1
  198. package/dist/{sidebar-CAsCmSpM.js → sidebar-D4zrlYpn.js} +2 -2
  199. package/dist/{sidebar-CAsCmSpM.js.map → sidebar-D4zrlYpn.js.map} +1 -1
  200. package/dist/{signalflare-ai-logo-DDhxMJD6.js → signalflare-ai-logo-Bipogceq.js} +1 -1
  201. package/dist/{signalflare-ai-logo-DDhxMJD6.js.map → signalflare-ai-logo-Bipogceq.js.map} +1 -1
  202. package/dist/{skeleton-line-Do3UmGk9.js → skeleton-line-CH1-h6e2.js} +1 -1
  203. package/dist/{skeleton-line-Do3UmGk9.js.map → skeleton-line-CH1-h6e2.js.map} +1 -1
  204. package/dist/{sparkline-DdbeM4Ai.js → sparkline-DHmgj1d0.js} +2 -2
  205. package/dist/{sparkline-DdbeM4Ai.js.map → sparkline-DHmgj1d0.js.map} +1 -1
  206. package/dist/src/blocks/agent-harness/agent-harness.d.ts.map +1 -1
  207. package/dist/src/blocks/agent-harness/agent-harness.tsx +29 -5
  208. package/dist/src/components/ai-conversation/ai-conversation.d.ts +69 -37
  209. package/dist/src/components/ai-conversation/ai-conversation.d.ts.map +1 -1
  210. package/dist/src/components/ai-conversation/index.d.ts +2 -1
  211. package/dist/src/components/ai-conversation/index.d.ts.map +1 -1
  212. package/dist/src/components/ai-conversation/measurement-constants.d.ts +30 -0
  213. package/dist/src/components/ai-conversation/measurement-constants.d.ts.map +1 -0
  214. package/dist/src/components/ai-info-banner/ai-info-banner.d.ts.map +1 -1
  215. package/dist/src/components/ai-message/ai-message.d.ts +3 -0
  216. package/dist/src/components/ai-message/ai-message.d.ts.map +1 -1
  217. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts +58 -4
  218. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
  219. package/dist/src/components/ai-prompt-input/controller.d.ts +10 -2
  220. package/dist/src/components/ai-prompt-input/controller.d.ts.map +1 -1
  221. package/dist/src/components/ai-prompt-input/index.d.ts +2 -2
  222. package/dist/src/components/ai-prompt-input/index.d.ts.map +1 -1
  223. package/dist/src/components/ai-prompt-input/types.d.ts +16 -0
  224. package/dist/src/components/ai-prompt-input/types.d.ts.map +1 -1
  225. package/dist/src/components/ai-response/ai-response.d.ts +12 -1
  226. package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
  227. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts +27 -0
  228. package/dist/src/components/ai-streaming-text/ai-streaming-text.d.ts.map +1 -1
  229. package/dist/src/components/ai-streaming-text/index.d.ts +1 -1
  230. package/dist/src/components/ai-streaming-text/index.d.ts.map +1 -1
  231. package/dist/src/components/ai-subagent/ai-subagent.d.ts.map +1 -1
  232. package/dist/src/components/ai-task-list/ai-task-list.d.ts.map +1 -1
  233. package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
  234. package/dist/src/components/banner/banner.d.ts.map +1 -1
  235. package/dist/src/components/empty/empty.d.ts.map +1 -1
  236. package/dist/src/components/stat-card/stat-card.d.ts +5 -0
  237. package/dist/src/components/stat-card/stat-card.d.ts.map +1 -1
  238. package/dist/src/components/text/text.d.ts +35 -1
  239. package/dist/src/components/text/text.d.ts.map +1 -1
  240. package/dist/src/components/tooltip/tooltip.d.ts.map +1 -1
  241. package/dist/src/index.d.ts +3 -3
  242. package/dist/src/index.d.ts.map +1 -1
  243. package/dist/src/utils/index.d.ts +2 -0
  244. package/dist/src/utils/index.d.ts.map +1 -1
  245. package/dist/src/utils/measured-text.d.ts +40 -0
  246. package/dist/src/utils/measured-text.d.ts.map +1 -0
  247. package/dist/src/utils/use-measured-text.d.ts +59 -0
  248. package/dist/src/utils/use-measured-text.d.ts.map +1 -0
  249. package/dist/{stat-card-CEZscNh8.js → stat-card-Ew-ofzEm.js} +28 -10
  250. package/dist/stat-card-Ew-ofzEm.js.map +1 -0
  251. package/dist/styles/sf-binding.css +9 -1
  252. package/dist/styles/sf-standalone.css +2 -2
  253. package/dist/styles/shadcn.css +1 -1
  254. package/dist/styles/theme-fedramp.css +12 -3
  255. package/dist/styles/theme-minimal.css +104 -26
  256. package/dist/styles/theme-sf.css +138 -39
  257. package/dist/styles/theme-vesper.css +91 -0
  258. package/dist/{surface-BduI7Ehl.js → surface-DGwRlC0o.js} +1 -1
  259. package/dist/{surface-BduI7Ehl.js.map → surface-DGwRlC0o.js.map} +1 -1
  260. package/dist/{switch-CzZBRBL7.js → switch-BxAMfHdt.js} +2 -2
  261. package/dist/{switch-CzZBRBL7.js.map → switch-BxAMfHdt.js.map} +1 -1
  262. package/dist/{table-Rv4JMy0B.js → table-BBeAtYVZ.js} +2 -2
  263. package/dist/{table-Rv4JMy0B.js.map → table-BBeAtYVZ.js.map} +1 -1
  264. package/dist/{tabs-1cHrYoel.js → tabs-CeHu7Scn.js} +1 -1
  265. package/dist/{tabs-1cHrYoel.js.map → tabs-CeHu7Scn.js.map} +1 -1
  266. package/dist/{text-KJmGkwnf.js → text-Cqryz7rk.js} +27 -5
  267. package/dist/text-Cqryz7rk.js.map +1 -0
  268. package/dist/{text-roll-BZ3I1umc.js → text-roll-Ch52hcQj.js} +1 -1
  269. package/dist/{text-roll-BZ3I1umc.js.map → text-roll-Ch52hcQj.js.map} +1 -1
  270. package/dist/{theme-toggle-Bhu681D7.js → theme-toggle-LDfIKEqx.js} +3 -3
  271. package/dist/{theme-toggle-Bhu681D7.js.map → theme-toggle-LDfIKEqx.js.map} +1 -1
  272. package/dist/{toast-Nw28a5Cx.js → toast-CaFQNYng.js} +2 -2
  273. package/dist/{toast-Nw28a5Cx.js.map → toast-CaFQNYng.js.map} +1 -1
  274. package/dist/{tooltip-Cb7QW-7H.js → tooltip-g9lFsvcT.js} +8 -2
  275. package/dist/tooltip-g9lFsvcT.js.map +1 -0
  276. package/dist/{use-agent-harness-BMyF8pTq.js → use-agent-harness-BTcNJdw4.js} +1 -1
  277. package/dist/{use-agent-harness-BMyF8pTq.js.map → use-agent-harness-BTcNJdw4.js.map} +1 -1
  278. package/dist/utils.js +2 -1
  279. package/package.json +2 -1
  280. package/scripts/component-registry/index.ts +2 -2
  281. package/scripts/css-build.ts +1 -1
  282. package/scripts/theme-generator/config.ts +27 -141
  283. package/scripts/theme-generator/generate-css.ts +0 -1
  284. package/scripts/theme-generator/index.ts +0 -1
  285. package/dist/ai-conversation-CArP7C8K.js +0 -184
  286. package/dist/ai-conversation-CArP7C8K.js.map +0 -1
  287. package/dist/ai-info-banner-uFxHHwBA.js.map +0 -1
  288. package/dist/ai-message-BjnFznXy.js.map +0 -1
  289. package/dist/ai-prompt-input-Dy1LfxPk.js.map +0 -1
  290. package/dist/ai-response-BEUg3xvd.js.map +0 -1
  291. package/dist/ai-streaming-text-CMfoThV0.js.map +0 -1
  292. package/dist/ai-subagent-DcPRqkAA.js.map +0 -1
  293. package/dist/ai-task-list-Da9zIm00.js.map +0 -1
  294. package/dist/ai-tool-Cn1O4xjP.js.map +0 -1
  295. package/dist/banner-B_6oBrsu.js.map +0 -1
  296. package/dist/empty-D2TypIId.js.map +0 -1
  297. package/dist/stat-card-CEZscNh8.js.map +0 -1
  298. package/dist/styles/theme-blue-tint.css +0 -98
  299. package/dist/text-KJmGkwnf.js.map +0 -1
  300. package/dist/tooltip-Cb7QW-7H.js.map +0 -1
@@ -26,11 +26,31 @@ 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
+
48
+
29
49
  ---
30
50
 
31
51
  ### AiAgentCard
32
52
 
33
- `AiAgentCard` — compact card showing one agent's status in a commander dashboard. Displays: agent icon, name, status indicator, current task, model, duration, and tool call count. Clickable for selection.
53
+ `AiAgentCard` — compact card showing one agent's status in a commander dashboard. Displays: agent icon, name, status indicator, current task, model, duration, and tool call count. Clickable for selection.
34
54
 
35
55
  **Type:** component
36
56
 
@@ -75,11 +95,111 @@ Container for a row of AI message action buttons.
75
95
 
76
96
  `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
97
 
98
+ **Examples:**
99
+
100
+ ```tsx
101
+ <div className="flex flex-wrap gap-3">
102
+ <AiAgentCard
103
+ name="Explore"
104
+ agentType="explore"
105
+ status="running"
106
+ modelId="claude-haiku-3.5"
107
+ currentTask="Scanning auth files for deprecated patterns..."
108
+ duration={4200}
109
+ toolCallCount={3}
110
+ />
111
+ <AiAgentCard
112
+ name="Execute"
113
+ agentType="execute"
114
+ status="running"
115
+ modelId="claude-sonnet-4"
116
+ currentTask="Rewriting jwt.ts using jose library..."
117
+ duration={8700}
118
+ toolCallCount={1}
119
+ />
120
+ </div>
121
+ ```
122
+
123
+ ```tsx
124
+ <div className="flex flex-wrap gap-3">
125
+ <AiAgentCard
126
+ name="Explore"
127
+ agentType="explore"
128
+ status="idle"
129
+ modelId="claude-haiku-3.5"
130
+ />
131
+ <AiAgentCard
132
+ name="Plan"
133
+ agentType="plan"
134
+ status="running"
135
+ modelId="claude-sonnet-4"
136
+ currentTask="Drafting migration steps..."
137
+ duration={2100}
138
+ toolCallCount={0}
139
+ />
140
+ <AiAgentCard
141
+ name="Execute"
142
+ agentType="execute"
143
+ status="completed"
144
+ modelId="claude-sonnet-4"
145
+ currentTask="Rewrote 4 files successfully."
146
+ duration={12_400}
147
+ toolCallCount={7}
148
+ />
149
+ <AiAgentCard
150
+ name="Test"
151
+ agentType="test"
152
+ status="error"
153
+ modelId="claude-haiku-3.5"
154
+ currentTask="3 tests failed: auth.spec.ts"
155
+ duration={3200}
156
+ toolCallCount={2}
157
+ />
158
+ </div>
159
+ ```
160
+
161
+ ```tsx
162
+ <div className="flex flex-wrap gap-3">
163
+ <AiAgentCard
164
+ name="Explore"
165
+ agentType="explore"
166
+ status="completed"
167
+ modelId="claude-haiku-3.5"
168
+ duration={4200}
169
+ toolCallCount={5}
170
+ />
171
+ <AiAgentCard
172
+ name="Execute"
173
+ agentType="execute"
174
+ status="running"
175
+ modelId="claude-sonnet-4"
176
+ currentTask="Patching consumers..."
177
+ duration={6100}
178
+ toolCallCount={3}
179
+ selected
180
+ />
181
+ </div>
182
+ ```
183
+
184
+ ```tsx
185
+ <div className="flex flex-wrap gap-2">
186
+ {[
187
+ { name: "Explore", agentType: "explore", status: "completed" as const },
188
+ { name: "Plan", agentType: "plan", status: "completed" as const },
189
+ { name: "Execute", agentType: "execute", status: "running" as const },
190
+ { name: "Review", agentType: "review", status: "idle" as const },
191
+ ].map((agent) => (
192
+ <AiAgentCard key={agent.name} size="sm" {...agent} />
193
+ ))}
194
+ </div>
195
+ ```
196
+
197
+
78
198
  ---
79
199
 
80
200
  ### AiApproval
81
201
 
82
- Approval card for tool calls and plan submissions. Maps to harness events: `tool_approval_required`, `plan_approval_required`, `plan_approved`.
202
+ Approval card for tool calls and plan submissions. Maps to harness events: `tool_approval_required`, `plan_approval_required`, `plan_approved`.
83
203
 
84
204
  **Type:** component
85
205
 
@@ -119,6 +239,43 @@ Approval card for tool calls and plan submissions. Maps to harness events: `tool
119
239
 
120
240
  `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
241
 
242
+ **Examples:**
243
+
244
+ ```tsx
245
+ <div className="w-full max-w-md">
246
+ <AiApproval
247
+ kind="tool"
248
+ status={status}
249
+ title="Execute shell command"
250
+ description="rm -rf /tmp/cache"
251
+ onApprove={() => setStatus("approved")}
252
+ onReject={() => setStatus("rejected")}
253
+ />
254
+ </div>
255
+ ```
256
+
257
+ ```tsx
258
+ <div className="w-full max-w-md">
259
+ <AiApproval
260
+ kind="plan"
261
+ status={status}
262
+ title="Deployment plan"
263
+ description="The agent proposes the following steps:"
264
+ items={[
265
+ { id: "1", label: "Run test suite", description: "All 142 tests" },
266
+ { id: "2", label: "Build production bundle" },
267
+ { id: "3", label: "Deploy to staging", description: "us-east-1" },
268
+ { id: "4", label: "Run smoke tests" },
269
+ { id: "5", label: "Promote to production" },
270
+ ]}
271
+ showFeedback
272
+ onApprove={() => setStatus("approved")}
273
+ onReject={() => setStatus("rejected")}
274
+ />
275
+ </div>
276
+ ```
277
+
278
+
122
279
  ---
123
280
 
124
281
  ### AiCodeBlock
@@ -149,6 +306,21 @@ Displays a code block with monospace formatting and an optional copy button. Doe
149
306
 
150
307
  `bg-sf-recessed`, `border-sf-line`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`
151
308
 
309
+ **Examples:**
310
+
311
+ ```tsx
312
+ <AiCodeBlock code={CODE} language="tsx">
313
+ <AiCodeBlockCopyButton />
314
+ </AiCodeBlock>
315
+ ```
316
+
317
+ ```tsx
318
+ <AiCodeBlock code="npm install @signalflare-ai/ui">
319
+ <AiCodeBlockCopyButton />
320
+ </AiCodeBlock>
321
+ ```
322
+
323
+
152
324
  ---
153
325
 
154
326
  ### AiConversation
@@ -169,11 +341,30 @@ Outer scroll container for a conversation. Sticks to the bottom as new messages
169
341
  - `lang`: string
170
342
  - `title`: string
171
343
 
344
+ **Examples:**
345
+
346
+ ```tsx
347
+ <div className="h-80 w-full overflow-hidden rounded-lg border border-sf-line">
348
+ <AiConversation>
349
+ <AiConversationContent>
350
+ {MESSAGES.map((m) => (
351
+ <AiMessage key={m.id} from={m.from}>
352
+ <AiMessageContent>
353
+ <AiResponse>{m.text}</AiResponse>
354
+ </AiMessageContent>
355
+ </AiMessage>
356
+ ))}
357
+ </AiConversationContent>
358
+ </AiConversation>
359
+ </div>
360
+ ```
361
+
362
+
172
363
  ---
173
364
 
174
365
  ### AiInfoBanner
175
366
 
176
- Inline conversation banner for system notices. Renders as a compact, horizontally centered divider-like notice rather than a chat bubble. Maps to harness events: `error`, `info`, `mode_changed`, `model_changed`.
367
+ Inline conversation banner for system notices. Renders as a compact, horizontally centered divider-like notice rather than a chat bubble. Maps to harness events: `error`, `info`, `mode_changed`, `model_changed`.
177
368
 
178
369
  **Type:** component
179
370
 
@@ -199,6 +390,21 @@ Inline conversation banner for system notices. Renders as a compact, horizontall
199
390
 
200
391
  `border-sf-danger`, `border-sf-info`, `border-sf-line`, `text-sf-danger`, `text-sf-info`, `text-sf-subtle`
201
392
 
393
+ **Examples:**
394
+
395
+ ```tsx
396
+ <div className="flex w-full flex-col gap-3">
397
+ <AiInfoBanner level="info">
398
+ Follow-up message queued — will send after current response completes
399
+ </AiInfoBanner>
400
+ <AiInfoBanner level="change">Switched to claude-opus-4-6</AiInfoBanner>
401
+ <AiInfoBanner level="error">
402
+ Connection lost. Retrying in 3s…
403
+ </AiInfoBanner>
404
+ </div>
405
+ ```
406
+
407
+
202
408
  ---
203
409
 
204
410
  ### AiMessage
@@ -227,11 +433,43 @@ Root message container. Sets layout, group class, and role context.
227
433
 
228
434
  `bg-sf-control`, `bg-sf-overlay`, `bg-sf-tint`, `text-sf-default`, `text-sf-subtle`
229
435
 
436
+ **Examples:**
437
+
438
+ ```tsx
439
+ <div className="flex w-full flex-col gap-2 p-4">
440
+ <AiMessage from="user">
441
+ <AiMessageContent>What is the capital of France?</AiMessageContent>
442
+ </AiMessage>
443
+ <AiMessage from="assistant">
444
+ <AiMessageContent>
445
+ <AiResponse>{"The capital of France is **Paris**."}</AiResponse>
446
+ </AiMessageContent>
447
+ <AiMessageToolbar>
448
+ <AiMessageActions>
449
+ <AiMessageAction tooltip="Copy">
450
+ <CopyIcon className="size-4" />
451
+ </AiMessageAction>
452
+ <AiMessageAction tooltip="Retry">
453
+ <ArrowCounterClockwiseIcon className="size-4" />
454
+ </AiMessageAction>
455
+ </AiMessageActions>
456
+ </AiMessageToolbar>
457
+ </AiMessage>
458
+ </div>
459
+ ```
460
+
461
+ ```tsx
462
+ <AiMessage from="user">
463
+ <AiMessageContent>Can you summarise this document?</AiMessageContent>
464
+ </AiMessage>
465
+ ```
466
+
467
+
230
468
  ---
231
469
 
232
470
  ### AiMissionHeader
233
471
 
234
- `AiMissionHeader` — top bar for the Commander dashboard. Shows: mission title, progress bar (from task list), agent count, live elapsed time, token usage, and an abort button while running.
472
+ `AiMissionHeader` — top bar for the Commander dashboard. Shows: mission title, progress bar (from task list), agent count, live elapsed time, token usage, and an abort button while running.
235
473
 
236
474
  **Type:** component
237
475
 
@@ -269,11 +507,122 @@ Root message container. Sets layout, group class, and role context.
269
507
 
270
508
  `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
509
 
510
+ **Examples:**
511
+
512
+ ```tsx
513
+ <AiMissionHeader
514
+ title="Refactor auth module"
515
+ taskList={{
516
+ title: "Refactor auth module",
517
+ tasks: [
518
+ {
519
+ id: "t1",
520
+ content: "Explore authentication codebase",
521
+ status: "completed",
522
+ priority: "high",
523
+ },
524
+ {
525
+ id: "t2",
526
+ content: "Identify deprecated patterns",
527
+ status: "completed",
528
+ priority: "high",
529
+ },
530
+ {
531
+ id: "t3",
532
+ content: "Write updated auth helpers",
533
+ status: "in_progress",
534
+ priority: "medium",
535
+ },
536
+ {
537
+ id: "t4",
538
+ content: "Update all consumers",
539
+ status: "pending",
540
+ priority: "medium",
541
+ },
542
+ {
543
+ id: "t5",
544
+ content: "Update tests",
545
+ status: "pending",
546
+ priority: "low",
547
+ },
548
+ ],
549
+ }}
550
+ usage={{
551
+ inputTokens: 12_480,
552
+ outputTokens: 3256,
553
+ totalTokens: 15_736,
554
+ cost: 0.04,
555
+ }}
556
+ activeAgentCount={2}
557
+ totalAgentCount={4}
558
+ startedAt={startedAt}
559
+ isRunning
560
+ />
561
+ ```
562
+
563
+ ```tsx
564
+ <AiMissionHeader
565
+ title="Deploy to production"
566
+ taskList={{
567
+ tasks: [
568
+ {
569
+ id: "t1",
570
+ content: "Run tests",
571
+ status: "completed",
572
+ priority: "high",
573
+ },
574
+ {
575
+ id: "t2",
576
+ content: "Build artifacts",
577
+ status: "completed",
578
+ priority: "high",
579
+ },
580
+ {
581
+ id: "t3",
582
+ content: "Deploy to staging",
583
+ status: "completed",
584
+ priority: "medium",
585
+ },
586
+ {
587
+ id: "t4",
588
+ content: "Smoke test",
589
+ status: "completed",
590
+ priority: "medium",
591
+ },
592
+ {
593
+ id: "t5",
594
+ content: "Deploy to production",
595
+ status: "completed",
596
+ priority: "high",
597
+ },
598
+ ],
599
+ }}
600
+ usage={{ totalTokens: 28_400, cost: 0.12 }}
601
+ activeAgentCount={0}
602
+ totalAgentCount={3}
603
+ startedAt={startedAt}
604
+ endedAt={endedAt}
605
+ isRunning={false}
606
+ />
607
+ ```
608
+
609
+ ```tsx
610
+ <AiMissionHeader
611
+ title="Analyze codebase"
612
+ activeAgentCount={1}
613
+ totalAgentCount={2}
614
+ startedAt={startedAt}
615
+ isRunning
616
+ variant="compact"
617
+ />
618
+ ```
619
+
620
+
272
621
  ---
273
622
 
274
623
  ### AiPartGroup
275
624
 
276
- Groups streaming ephemeral activity (tool calls + reasoning) into a single rolling window during streaming, then collapses to a frozen summary line once the parent message completes. Behavior: - **Streaming:** shows the most recent `max` (default 3) ephemeral children. Pinned rows (errors / user-expanded) sit above the live window. - **Completed:** writes a snapshot keyed by `groupKey`, unmounts ephemeral children entirely, and renders a static `▸ {title} · N steps` line. - **Re-mount after completion:** always renders the cached snapshot — no animations, no `useEffect` re-runs, no tool re-execution risk.
625
+ Groups streaming ephemeral activity (tool calls + reasoning) into a single rolling window during streaming, then collapses to a frozen summary line once the parent message completes. Behavior: - **Streaming:** shows the most recent `max` (default 3) ephemeral children. Pinned rows (errors / user-expanded) sit above the live window. - **Completed:** writes a snapshot keyed by `groupKey`, unmounts ephemeral children entirely, and renders a static `▸ {title} · N steps` line. - **Re-mount after completion:** always renders the cached snapshot — no animations, no `useEffect` re-runs, no tool re-execution risk.
277
626
 
278
627
  **Type:** component
279
628
 
@@ -298,11 +647,59 @@ Groups streaming ephemeral activity (tool calls + reasoning) into a single rolli
298
647
 
299
648
  `bg-sf-tint`, `border-sf-line`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
300
649
 
650
+ **Examples:**
651
+
652
+ ```tsx
653
+ <div className="flex flex-col gap-3">
654
+ <div className="flex items-center justify-between gap-3">
655
+ <Text variant="secondary" size="sm">
656
+ Rolling window of 3 rows while streaming. Collapses to a single frozen
657
+ line when complete.
658
+ </Text>
659
+ <Button
660
+ onClick={() => setRunId((n) => n + 1)}
661
+ size="sm"
662
+ variant="ghost"
663
+ >
664
+ Run again
665
+ </Button>
666
+ </div>
667
+ <div className="min-h-[6rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3">
668
+ <AiPartGroup
669
+ complete={complete}
670
+ groupKey={`activity-demo-${runId}`}
671
+ max={3}
672
+ title="Investigating failing auth tests"
673
+ >
674
+ {steps.map((s) =>
675
+ s.kind === "tool" ? (
676
+ <AiToolCall
677
+ duration={s.duration}
678
+ key={s.part.toolCallId}
679
+ part={s.part}
680
+ variant="ephemeral"
681
+ />
682
+ ) : (
683
+ <AiReasoning
684
+ duration={s.duration}
685
+ isStreaming={s.isStreaming}
686
+ key={s.id}
687
+ part={{ text: s.text }}
688
+ variant="ephemeral"
689
+ />
690
+ )
691
+ )}
692
+ </AiPartGroup>
693
+ </div>
694
+ </div>
695
+ ```
696
+
697
+
301
698
  ---
302
699
 
303
700
  ### AiQuestion
304
701
 
305
- Agent question card. Renders when the agent uses the `ask_user` built-in tool and needs a response before continuing. Maps to harness event: `ask_question`.
702
+ Agent question card. Renders when the agent uses the `ask_user` built-in tool and needs a response before continuing. Maps to harness event: `ask_question`.
306
703
 
307
704
  **Type:** component
308
705
 
@@ -338,6 +735,56 @@ Agent question card. Renders when the agent uses the `ask_user` built-in tool an
338
735
 
339
736
  `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
737
 
738
+ **Examples:**
739
+
740
+ ```tsx
741
+ <div className="w-full max-w-md">
742
+ <AiQuestion
743
+ questionId="q-demo-1"
744
+ question="How should I handle the failing tests?"
745
+ header="Decision needed"
746
+ status={status}
747
+ answeredWith={answer}
748
+ options={[
749
+ {
750
+ label: "Fix them",
751
+ description: "Update the test expectations to match new behavior",
752
+ },
753
+ {
754
+ label: "Skip them",
755
+ description: "Mark as skipped for now and create a ticket",
756
+ },
757
+ {
758
+ label: "Delete them",
759
+ description: "Remove outdated tests entirely",
760
+ },
761
+ ]}
762
+ allowCustom
763
+ onAnswer={(_id, ans) => {
764
+ setAnswer(ans);
765
+ setStatus("answered");
766
+ }}
767
+ />
768
+ </div>
769
+ ```
770
+
771
+ ```tsx
772
+ <div className="w-full max-w-md">
773
+ <AiQuestion
774
+ questionId="q-demo-2"
775
+ question="What should the commit message be for these changes?"
776
+ status={status}
777
+ answeredWith={answer}
778
+ allowCustom
779
+ onAnswer={(_id, ans) => {
780
+ setAnswer(ans);
781
+ setStatus("answered");
782
+ }}
783
+ />
784
+ </div>
785
+ ```
786
+
787
+
341
788
  ---
342
789
 
343
790
  ### AiReasoning
@@ -387,11 +834,83 @@ Collapsible reasoning block. Supports three display variants: - `"default"` —
387
834
 
388
835
  `bg-sf-tint`, `border-sf-line`, `text-sf-subtle`, `text-sf-success`
389
836
 
837
+ **Examples:**
838
+
839
+ ```tsx
840
+ <AiReasoning
841
+ part={{ text: SAMPLE_REASONING }}
842
+ isStreaming={false}
843
+ duration={3}
844
+ defaultExpanded
845
+ />
846
+ ```
847
+
848
+ ```tsx
849
+ <AiReasoning
850
+ part={{ text: "Analysing context and forming a response..." }}
851
+ isStreaming
852
+ />
853
+ ```
854
+
855
+ ```tsx
856
+ <AiReasoning
857
+ variant="inline"
858
+ part={{ text: SAMPLE_REASONING }}
859
+ isStreaming={false}
860
+ />
861
+ ```
862
+
863
+ ```tsx
864
+ <div className="flex flex-col gap-3">
865
+ <div className="flex items-center justify-between gap-3">
866
+ <Text variant="secondary" size="sm">
867
+ Reasoning row evaporates 800ms after streaming ends.
868
+ </Text>
869
+ <Button
870
+ onClick={() => setRunId((n) => n + 1)}
871
+ size="sm"
872
+ variant="ghost"
873
+ >
874
+ Think again
875
+ </Button>
876
+ </div>
877
+ <div
878
+ className={
879
+ "min-h-[3.5rem] rounded-md border border-sf-line/40 bg-sf-base/40 p-3"
880
+ }
881
+ >
882
+ <AiReasoning
883
+ // `key` ensures each replay re-mounts to reset the dismiss state.
884
+ key={runId}
885
+ variant="ephemeral"
886
+ part={{
887
+ text: "**Reviewing diff** — checking for breaking changes in the migration.",
888
+ }}
889
+ isStreaming={isStreaming}
890
+ />
891
+ </div>
892
+ </div>
893
+ ```
894
+
895
+ ```tsx
896
+ <AiReasoningGroup
897
+ parts={[
898
+ { text: "**Step 1** — Understood the user intent and context." },
899
+ { text: "**Step 2** — Reviewed relevant data and constraints." },
900
+ { text: "**Step 3** — Formulated the final response structure." },
901
+ ]}
902
+ isStreaming={false}
903
+ totalDuration={7}
904
+ defaultExpanded
905
+ />
906
+ ```
907
+
908
+
390
909
  ---
391
910
 
392
911
  ### AiResponse
393
912
 
394
- Renders AI-generated markdown using Streamdown. Supports streaming animation, syntax-highlighted code, tables, and more. Pass `isAnimating={true}` while streaming and `false` once complete to get character-by-character reveal animation.
913
+ Renders AI-generated markdown using Streamdown. Supports streaming animation, syntax-highlighted code, tables, and more. Pass `isAnimating={true}` while streaming and `false` once complete to get character-by-character reveal animation.
395
914
 
396
915
  **Type:** component
397
916
 
@@ -410,6 +929,17 @@ Renders AI-generated markdown using Streamdown. Supports streaming animation, sy
410
929
 
411
930
  `text-sf-default`
412
931
 
932
+ **Examples:**
933
+
934
+ ```tsx
935
+ <AiResponse>{MARKDOWN_LIKE}</AiResponse>
936
+ ```
937
+
938
+ ```tsx
939
+ <AiResponse isAnimating={isAnimating}>{text}</AiResponse>
940
+ ```
941
+
942
+
413
943
  ---
414
944
 
415
945
  ### AiShimmer
@@ -435,6 +965,27 @@ AiShimmer component
435
965
  - `spread`: number
436
966
  Shimmer width multiplier relative to text length.
437
967
 
968
+ **Examples:**
969
+
970
+ ```tsx
971
+ <AiShimmer>Thinking...</AiShimmer>
972
+ ```
973
+
974
+ ```tsx
975
+ <p className="text-sf-default text-sm">
976
+ The AI is{" "}
977
+ <AiShimmer as="span" duration={1.5}>
978
+ generating a response
979
+ </AiShimmer>
980
+ .
981
+ </p>
982
+ ```
983
+
984
+ ```tsx
985
+ <AiShimmer duration={4}>Analysing your request...</AiShimmer>
986
+ ```
987
+
988
+
438
989
  ---
439
990
 
440
991
  ### AiStatusBadge
@@ -470,6 +1021,50 @@ Compact pill-shaped badge showing an icon, label, and a status indicator. Used b
470
1021
 
471
1022
  `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
472
1023
 
1024
+ **Examples:**
1025
+
1026
+ ```tsx
1027
+ <AiStatusBadge
1028
+ icon={MagnifyingGlassIcon}
1029
+ label="web_search"
1030
+ status="idle"
1031
+ />
1032
+ ```
1033
+
1034
+ ```tsx
1035
+ <div className="flex flex-wrap gap-2">
1036
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="idle" />
1037
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="running" />
1038
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="success" />
1039
+ <AiStatusBadge icon={GlobeIcon} label="search_web" status="error" />
1040
+ </div>
1041
+ ```
1042
+
1043
+ ```tsx
1044
+ <div className="flex flex-wrap gap-2">
1045
+ <AiStatusBadge
1046
+ icon={DatabaseIcon}
1047
+ label="query_db"
1048
+ info="3/5"
1049
+ status="running"
1050
+ />
1051
+ <AiStatusBadge
1052
+ icon={BrainIcon}
1053
+ label="analyse"
1054
+ info="done"
1055
+ status="success"
1056
+ />
1057
+ </div>
1058
+ ```
1059
+
1060
+ ```tsx
1061
+ <div className="flex flex-wrap gap-2">
1062
+ <AiStatusBadge label="processing" status="running" />
1063
+ <AiStatusBadge label="complete" status="success" />
1064
+ </div>
1065
+ ```
1066
+
1067
+
473
1068
  ---
474
1069
 
475
1070
  ### AiStreamingText
@@ -489,11 +1084,23 @@ AiStreamingText component
489
1084
  - `children`: ReactNode
490
1085
  Child elements
491
1086
 
1087
+ **Examples:**
1088
+
1089
+ ```tsx
1090
+ <p className="max-w-sm text-sf-default text-sm">
1091
+ {displayed}
1092
+ {streaming && (
1093
+ <span className="ml-0.5 inline-block h-4 w-0.5 animate-pulse bg-sf-brand" />
1094
+ )}
1095
+ </p>
1096
+ ```
1097
+
1098
+
492
1099
  ---
493
1100
 
494
1101
  ### AiSubagent
495
1102
 
496
- Collapsible wrapper for nested subagent activity. Shows the subagent name, status, model, and duration in a header, with all subagent output (text, tool calls, etc.) in a collapsible body. Maps to harness events: `subagent_start`, `subagent_text_delta`, `subagent_tool_start`, `subagent_tool_end`, `subagent_end`, `subagent_model_changed`.
1103
+ Collapsible wrapper for nested subagent activity. Shows the subagent name, status, model, and duration in a header, with all subagent output (text, tool calls, etc.) in a collapsible body. Maps to harness events: `subagent_start`, `subagent_text_delta`, `subagent_tool_start`, `subagent_tool_end`, `subagent_end`, `subagent_model_changed`.
497
1104
 
498
1105
  **Type:** component
499
1106
 
@@ -529,7 +1136,93 @@ Collapsible wrapper for nested subagent activity. Shows the subagent name, statu
529
1136
 
530
1137
  **Colors (sf tokens used):**
531
1138
 
532
- `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-default`, `text-sf-subtle`, `text-sf-success`
1139
+ `bg-sf-tint`, `text-sf-brand`, `text-sf-danger`, `text-sf-subtle`, `text-sf-success`
1140
+
1141
+ **Examples:**
1142
+
1143
+ ```tsx
1144
+ <div className="w-full max-w-lg">
1145
+ <AiSubagent
1146
+ name="Explore"
1147
+ agentType="explore"
1148
+ status="running"
1149
+ modelId="claude-haiku-3.5"
1150
+ defaultExpanded
1151
+ >
1152
+ <div className="flex flex-col gap-1.5 text-sm text-sf-subtle">
1153
+ <p>Searching codebase for authentication patterns...</p>
1154
+ <div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
1155
+ <span className="text-sf-brand">Glob</span>
1156
+ <span className="text-sf-subtle">src/**/*auth*</span>
1157
+ </div>
1158
+ <div className="flex items-center gap-2 border-l-2 border-sf-fill py-1 pl-2 text-xs">
1159
+ <span className="text-sf-brand">Read</span>
1160
+ <span className="text-sf-subtle">src/middleware/auth.ts</span>
1161
+ </div>
1162
+ </div>
1163
+ </AiSubagent>
1164
+ </div>
1165
+ ```
1166
+
1167
+ ```tsx
1168
+ <div className="w-full max-w-lg">
1169
+ <AiSubagent
1170
+ name="Execute"
1171
+ agentType="execute"
1172
+ status="completed"
1173
+ modelId="claude-sonnet-4"
1174
+ duration={12400}
1175
+ defaultExpanded={false}
1176
+ >
1177
+ <div className="text-sm text-sf-subtle">
1178
+ <p>Refactored 3 files, added 2 new tests. All tests passing.</p>
1179
+ </div>
1180
+ </AiSubagent>
1181
+ </div>
1182
+ ```
1183
+
1184
+ ```tsx
1185
+ <div className="w-full max-w-lg">
1186
+ <AiSubagent
1187
+ name="Plan"
1188
+ agentType="plan"
1189
+ status="completed"
1190
+ modelId="claude-sonnet-4"
1191
+ duration={28000}
1192
+ defaultExpanded
1193
+ >
1194
+ <div className="flex flex-col gap-2">
1195
+ <p className="text-sm text-sf-subtle">
1196
+ Breaking down the migration into subtasks...
1197
+ </p>
1198
+ <AiSubagent
1199
+ name="Explore"
1200
+ agentType="explore"
1201
+ status="completed"
1202
+ modelId="claude-haiku-3.5"
1203
+ duration={4200}
1204
+ defaultExpanded={false}
1205
+ >
1206
+ <p className="text-sm text-sf-subtle">
1207
+ Found 12 files using deprecated API.
1208
+ </p>
1209
+ </AiSubagent>
1210
+ <AiSubagent
1211
+ name="Execute"
1212
+ agentType="execute"
1213
+ status="running"
1214
+ modelId="claude-sonnet-4"
1215
+ defaultExpanded
1216
+ >
1217
+ <p className="text-sm text-sf-subtle">
1218
+ Updating import paths in batch 1/3...
1219
+ </p>
1220
+ </AiSubagent>
1221
+ </div>
1222
+ </AiSubagent>
1223
+ </div>
1224
+ ```
1225
+
533
1226
 
534
1227
  ---
535
1228
 
@@ -555,7 +1248,7 @@ Horizontally scrollable container for suggestion pills. Position it relative to
555
1248
 
556
1249
  ### AiTaskList
557
1250
 
558
- Task progress list. Renders structured tasks from the harness `task_write` tool. Typically rendered inside the `PromptInputBackLayer` or inline in conversation. Maps to harness event: `task_updated`.
1251
+ Task progress list. Renders structured tasks from the harness `task_write` tool. Typically rendered inside the `PromptInputBackLayer` or inline in conversation. Maps to harness event: `task_updated`.
559
1252
 
560
1253
  **Type:** component
561
1254
 
@@ -582,11 +1275,20 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
582
1275
 
583
1276
  `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
1277
 
1278
+ **Examples:**
1279
+
1280
+ ```tsx
1281
+ <div className="w-full max-w-sm">
1282
+ <AiTaskList title="Agent tasks" tasks={tasks} />
1283
+ </div>
1284
+ ```
1285
+
1286
+
585
1287
  ---
586
1288
 
587
1289
  ### AiTimeline
588
1290
 
589
- `AiTimeline` — horizontal swim-lane timeline for commander-level orchestration. Displays multiple `AiTimelineLane` children on a shared time axis. Supports live updating (a "now" marker follows the live edge), panning, and zoom via `pixelsPerSecond`.
1291
+ `AiTimeline` — horizontal swim-lane timeline for commander-level orchestration. Displays multiple `AiTimelineLane` children on a shared time axis. Supports live updating (a "now" marker follows the live edge), panning, and zoom via `pixelsPerSecond`.
590
1292
 
591
1293
  **Type:** component
592
1294
 
@@ -618,6 +1320,106 @@ Task progress list. Renders structured tasks from the harness `task_write` tool.
618
1320
 
619
1321
  `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
1322
 
1323
+ **Examples:**
1324
+
1325
+ ```tsx
1326
+ <AiTimeline
1327
+ timeOrigin={T0}
1328
+ pixelsPerSecond={25}
1329
+ showNowMarker
1330
+ nowMs={nowMs}
1331
+ >
1332
+ <AiTimelineLane
1333
+ label="Main"
1334
+ agentType="main"
1335
+ status="running"
1336
+ modelId="claude-sonnet-4"
1337
+ blocks={mainBlocks}
1338
+ timeOrigin={T0}
1339
+ nowMs={nowMs}
1340
+ pxPerMs={pxPerMs}
1341
+ />
1342
+ <AiTimelineLane
1343
+ label="Explore"
1344
+ agentType="explore"
1345
+ status="completed"
1346
+ modelId="claude-haiku-3.5"
1347
+ blocks={exploreBlocks}
1348
+ timeOrigin={T0}
1349
+ nowMs={nowMs}
1350
+ pxPerMs={pxPerMs}
1351
+ />
1352
+ <AiTimelineLane
1353
+ label="Plan"
1354
+ agentType="plan"
1355
+ status="completed"
1356
+ modelId="claude-sonnet-4"
1357
+ blocks={planBlocks}
1358
+ timeOrigin={T0}
1359
+ nowMs={nowMs}
1360
+ pxPerMs={pxPerMs}
1361
+ />
1362
+ <AiTimelineLane
1363
+ label="Execute"
1364
+ agentType="execute"
1365
+ status="running"
1366
+ modelId="claude-sonnet-4"
1367
+ blocks={executeBlocks}
1368
+ timeOrigin={T0}
1369
+ nowMs={nowMs}
1370
+ pxPerMs={pxPerMs}
1371
+ />
1372
+ </AiTimeline>
1373
+ ```
1374
+
1375
+ ```tsx
1376
+ <AiTimeline
1377
+ timeOrigin={T0}
1378
+ pixelsPerSecond={25}
1379
+ showNowMarker
1380
+ nowMs={nowMs}
1381
+ >
1382
+ <AiTimelineLane
1383
+ label="Explore"
1384
+ agentType="explore"
1385
+ status="completed"
1386
+ blocks={exploreBlocks}
1387
+ timeOrigin={T0}
1388
+ nowMs={nowMs}
1389
+ pxPerMs={pxPerMs}
1390
+ density="compact"
1391
+ />
1392
+ <AiTimelineLane
1393
+ label="Execute"
1394
+ agentType="execute"
1395
+ status="running"
1396
+ blocks={executeBlocks}
1397
+ timeOrigin={T0}
1398
+ nowMs={nowMs}
1399
+ pxPerMs={pxPerMs}
1400
+ density="compact"
1401
+ />
1402
+ </AiTimeline>
1403
+ ```
1404
+
1405
+ ```tsx
1406
+ <AiTimeline
1407
+ timeOrigin={t}
1408
+ pixelsPerSecond={30}
1409
+ showNowMarker={false}
1410
+ nowMs={nowMs}
1411
+ >
1412
+ <AiTimelineLane
1413
+ label="Agent"
1414
+ blocks={allTypeBlocks}
1415
+ timeOrigin={t}
1416
+ nowMs={nowMs}
1417
+ pxPerMs={pxPerMs}
1418
+ />
1419
+ </AiTimeline>
1420
+ ```
1421
+
1422
+
621
1423
  ---
622
1424
 
623
1425
  ### AiToolCall
@@ -665,7 +1467,7 @@ Renders a single tool call. Supports three display variants: - `"default"` — e
665
1467
 
666
1468
  ### AiUsageBar
667
1469
 
668
- Compact token usage display bar. Shows input/output token counts, total, optional cost, and model identifier. Maps to harness event: `usage_update`.
1470
+ Compact token usage display bar. Shows input/output token counts, total, optional cost, and model identifier. Maps to harness event: `usage_update`.
669
1471
 
670
1472
  **Type:** component
671
1473
 
@@ -697,6 +1499,26 @@ Compact token usage display bar. Shows input/output token counts, total, optiona
697
1499
 
698
1500
  `text-sf-inactive`, `text-sf-subtle`
699
1501
 
1502
+ **Examples:**
1503
+
1504
+ ```tsx
1505
+ <div className="w-full max-w-md rounded-lg border border-sf-line">
1506
+ <AiUsageBar
1507
+ inputTokens={12480}
1508
+ outputTokens={3256}
1509
+ cost={0.04}
1510
+ modelId="claude-sonnet-4"
1511
+ />
1512
+ </div>
1513
+ ```
1514
+
1515
+ ```tsx
1516
+ <div className="w-full max-w-sm rounded-lg border border-sf-line">
1517
+ <AiUsageBar inputTokens={850} outputTokens={124} />
1518
+ </div>
1519
+ ```
1520
+
1521
+
700
1522
  ---
701
1523
 
702
1524
  ### Badge
@@ -741,6 +1563,117 @@ Small status label for categorizing or highlighting content. Supports icons, loa
741
1563
 
742
1564
  `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
1565
 
1566
+ **Examples:**
1567
+
1568
+ ```tsx
1569
+ <div className="flex flex-wrap items-center gap-2">
1570
+ <Badge variant="primary">Primary</Badge>
1571
+ <Badge variant="secondary">Secondary</Badge>
1572
+ <Badge variant="destructive">Destructive</Badge>
1573
+ <Badge variant="outline">Outline</Badge>
1574
+ <Badge variant="beta">Beta</Badge>
1575
+ <Badge variant="success">Success</Badge>
1576
+ <Badge variant="warning">Warning</Badge>
1577
+ <Badge variant="info">Info</Badge>
1578
+ <Badge variant="ghost">Ghost</Badge>
1579
+ </div>
1580
+ ```
1581
+
1582
+ ```tsx
1583
+ <Badge variant="primary">Primary</Badge>
1584
+ ```
1585
+
1586
+ ```tsx
1587
+ <p className="flex items-center gap-2">
1588
+ Workers
1589
+ <Badge variant="beta">Beta</Badge>
1590
+ </p>
1591
+ ```
1592
+
1593
+ ```tsx
1594
+ <div className="flex flex-wrap items-center gap-2">
1595
+ <Badge variant="success" icon={CheckCircleIcon}>
1596
+ Verified
1597
+ </Badge>
1598
+ <Badge variant="secondary" icon={LightningIcon}>
1599
+ Boosted
1600
+ </Badge>
1601
+ <Badge variant="outline" icon={TagIcon} iconPosition="right">
1602
+ Tagged
1603
+ </Badge>
1604
+ </div>
1605
+ ```
1606
+
1607
+ ```tsx
1608
+ <div className="flex flex-wrap items-center gap-2">
1609
+ {tags.map((tag) => (
1610
+ <Badge
1611
+ key={tag}
1612
+ variant="secondary"
1613
+ onDismiss={() => setTags((t) => t.filter((v) => v !== tag))}
1614
+ >
1615
+ {tag}
1616
+ </Badge>
1617
+ ))}
1618
+ {tags.length === 0 && (
1619
+ <span className="text-sm text-sf-subtle">All tags removed</span>
1620
+ )}
1621
+ </div>
1622
+ ```
1623
+
1624
+ ```tsx
1625
+ <div className="flex flex-wrap items-center gap-2">
1626
+ <Badge variant="secondary" loading>
1627
+ Syncing
1628
+ </Badge>
1629
+ <Badge variant="info" loading>
1630
+ Deploying
1631
+ </Badge>
1632
+ </div>
1633
+ ```
1634
+
1635
+ ```tsx
1636
+ <div className="flex flex-wrap items-center gap-2">
1637
+ <Badge variant="outline" dot="green">
1638
+ Online
1639
+ </Badge>
1640
+ <Badge variant="outline" dot="red">
1641
+ Offline
1642
+ </Badge>
1643
+ <Badge variant="outline" dot="yellow">
1644
+ Degraded
1645
+ </Badge>
1646
+ <Badge variant="outline" dot="blue">
1647
+ Deploying
1648
+ </Badge>
1649
+ </div>
1650
+ ```
1651
+
1652
+ ```tsx
1653
+ <div className="flex flex-wrap items-center gap-2">
1654
+ <Badge variant="secondary" onClick={handleBadgeClick}>
1655
+ Clickable
1656
+ </Badge>
1657
+ <Badge variant="info" href="https://example.com">
1658
+ Link badge
1659
+ </Badge>
1660
+ </div>
1661
+ ```
1662
+
1663
+ ```tsx
1664
+ <TooltipProvider>
1665
+ <div className="flex flex-wrap items-center gap-2">
1666
+ <Badge variant="success" tooltip="Deployed 2 hours ago" dot="green">
1667
+ Production
1668
+ </Badge>
1669
+ <Badge variant="outline" tooltip="3 of 5 tasks complete">
1670
+ 3/5
1671
+ </Badge>
1672
+ </div>
1673
+ </TooltipProvider>
1674
+ ```
1675
+
1676
+
744
1677
  ---
745
1678
 
746
1679
  ### Banner
@@ -771,6 +1704,39 @@ Full-width message bar for informational, warning, or error notices.
771
1704
 
772
1705
  `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
1706
 
1707
+ **Examples:**
1708
+
1709
+ ```tsx
1710
+ <div className="space-y-3">
1711
+ <Banner>This is an informational banner.</Banner>
1712
+ <Banner variant="alert">This is an alert banner.</Banner>
1713
+ <Banner variant="error">This is an error banner.</Banner>
1714
+ </div>
1715
+ ```
1716
+
1717
+ ```tsx
1718
+ <Banner>This is an informational banner.</Banner>
1719
+ ```
1720
+
1721
+ ```tsx
1722
+ <Banner variant="alert">Your session will expire soon.</Banner>
1723
+ ```
1724
+
1725
+ ```tsx
1726
+ <Banner icon={<WarningCircleIcon />} variant="alert">
1727
+ Review your billing information.
1728
+ </Banner>
1729
+ ```
1730
+
1731
+ ```tsx
1732
+ <Banner icon={<InfoIcon />}>
1733
+ <Text DANGEROUS_className="text-inherit">
1734
+ This banner supports <strong>custom content</strong> with Text.
1735
+ </Text>
1736
+ </Banner>
1737
+ ```
1738
+
1739
+
774
1740
  ---
775
1741
 
776
1742
  ### Breadcrumbs
@@ -805,7 +1771,6 @@ This is a compound component. Use these sub-components:
805
1771
  Link sub-component
806
1772
 
807
1773
  Props:
808
-
809
1774
  - `href`: string (required)
810
1775
  - `icon`: React.ReactNode
811
1776
 
@@ -814,7 +1779,6 @@ Props:
814
1779
  Current sub-component
815
1780
 
816
1781
  Props:
817
-
818
1782
  - `loading`: boolean
819
1783
  - `icon`: React.ReactNode
820
1784
 
@@ -827,9 +1791,51 @@ Separator sub-component
827
1791
  Clipboard sub-component
828
1792
 
829
1793
  Props:
830
-
831
1794
  - `text`: string (required)
832
1795
 
1796
+
1797
+ **Examples:**
1798
+
1799
+ ```tsx
1800
+ <Breadcrumbs>
1801
+ <Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
1802
+ <Breadcrumbs.Separator />
1803
+ <Breadcrumbs.Link href="#">Docs</Breadcrumbs.Link>
1804
+ <Breadcrumbs.Separator />
1805
+ <Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
1806
+ </Breadcrumbs>
1807
+ ```
1808
+
1809
+ ```tsx
1810
+ <Breadcrumbs>
1811
+ <Breadcrumbs.Link href="#" icon={<HouseIcon size={16} />}>
1812
+ Home
1813
+ </Breadcrumbs.Link>
1814
+ <Breadcrumbs.Separator />
1815
+ <Breadcrumbs.Link href="#">Projects</Breadcrumbs.Link>
1816
+ <Breadcrumbs.Separator />
1817
+ <Breadcrumbs.Current>Current Project</Breadcrumbs.Current>
1818
+ </Breadcrumbs>
1819
+ ```
1820
+
1821
+ ```tsx
1822
+ <Breadcrumbs>
1823
+ <Breadcrumbs.Current icon={<HouseIcon size={16} />}>
1824
+ Worker Analytics
1825
+ </Breadcrumbs.Current>
1826
+ </Breadcrumbs>
1827
+ ```
1828
+
1829
+ ```tsx
1830
+ <Breadcrumbs>
1831
+ <Breadcrumbs.Link href="#">Home</Breadcrumbs.Link>
1832
+ <Breadcrumbs.Separator />
1833
+ <Breadcrumbs.Current>Breadcrumbs</Breadcrumbs.Current>
1834
+ <Breadcrumbs.Clipboard text="#" />
1835
+ </Breadcrumbs>
1836
+ ```
1837
+
1838
+
833
1839
  ---
834
1840
 
835
1841
  ### Button
@@ -878,7 +1884,6 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
878
1884
  - `not-disabled`: `not-disabled:hover:border-secondary! not-disabled:hover:bg-sf-control`
879
1885
  - `disabled`: `disabled:bg-sf-control/50 disabled:!text-sf-danger/70`
880
1886
  - `data-state`: `data-[state=open]:bg-sf-control`
881
-
882
1887
  - `children`: ReactNode
883
1888
  - `className`: string
884
1889
  - `icon`: ReactNode
@@ -897,6 +1902,65 @@ Primary action trigger. Supports multiple variants, sizes, shapes, icons, and lo
897
1902
 
898
1903
  `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
1904
 
1905
+ **Examples:**
1906
+
1907
+ ```tsx
1908
+ <div className="flex flex-wrap items-center gap-2">
1909
+ <Button variant="secondary">Button</Button>
1910
+ <Button
1911
+ variant="secondary"
1912
+ shape="square"
1913
+ icon={PlusIcon}
1914
+ aria-label="Add"
1915
+ />
1916
+ </div>
1917
+ ```
1918
+
1919
+ ```tsx
1920
+ <Button variant="primary">Primary</Button>
1921
+ ```
1922
+
1923
+ ```tsx
1924
+ <div className="flex flex-wrap items-center gap-3">
1925
+ <Button size="xs" variant="secondary">
1926
+ Extra Small
1927
+ </Button>
1928
+ <Button size="sm" variant="secondary">
1929
+ Small
1930
+ </Button>
1931
+ <Button size="base" variant="secondary">
1932
+ Base
1933
+ </Button>
1934
+ <Button size="lg" variant="secondary">
1935
+ Large
1936
+ </Button>
1937
+ </div>
1938
+ ```
1939
+
1940
+ ```tsx
1941
+ <Button variant="secondary" icon={PlusIcon}>
1942
+ Create Worker
1943
+ </Button>
1944
+ ```
1945
+
1946
+ ```tsx
1947
+ <div className="flex flex-wrap items-center gap-3">
1948
+ <Button
1949
+ variant="secondary"
1950
+ shape="square"
1951
+ icon={PlusIcon}
1952
+ aria-label="Add item"
1953
+ />
1954
+ <Button
1955
+ variant="secondary"
1956
+ shape="circle"
1957
+ icon={PlusIcon}
1958
+ aria-label="Add item"
1959
+ />
1960
+ </div>
1961
+ ```
1962
+
1963
+
900
1964
  ---
901
1965
 
902
1966
  ### Checkbox
@@ -919,7 +1983,6 @@ Checkbox component
919
1983
  - `"default"`:
920
1984
  - `focus`: `[&:focus-within>span]:ring-sf-ring`
921
1985
  - `hover`: `[&:hover>span]:ring-sf-ring`
922
-
923
1986
  - `label`: ReactNode
924
1987
  Label content for the checkbox (enables built-in Field wrapper) - can be a string or any React node
925
1988
  - `labelTooltip`: ReactNode
@@ -974,7 +2037,6 @@ Item sub-component
974
2037
  Group sub-component
975
2038
 
976
2039
  Props:
977
-
978
2040
  - `legend`: string (required)
979
2041
  - `children`: ReactNode (required)
980
2042
  - `error`: string
@@ -985,11 +2047,73 @@ Props:
985
2047
  - `controlFirst`: boolean
986
2048
  - `className`: string
987
2049
 
988
- ---
989
-
990
- ### ClipboardText
991
2050
 
992
- Read-only text field with a one-click copy-to-clipboard button.
2051
+ **Examples:**
2052
+
2053
+ ```tsx
2054
+ <Checkbox
2055
+ label="Accept terms and conditions"
2056
+ checked={checked}
2057
+ onCheckedChange={setChecked}
2058
+ />
2059
+ ```
2060
+
2061
+ ```tsx
2062
+ <Checkbox
2063
+ label="Select all"
2064
+ indeterminate={indeterminate}
2065
+ onCheckedChange={setIndeterminate}
2066
+ />
2067
+ ```
2068
+
2069
+ ```tsx
2070
+ <Checkbox
2071
+ label="Remember me"
2072
+ controlFirst={false}
2073
+ checked={checked}
2074
+ onCheckedChange={setChecked}
2075
+ />
2076
+ ```
2077
+
2078
+ ```tsx
2079
+ <Checkbox label="Disabled option" disabled />
2080
+ ```
2081
+
2082
+ ```tsx
2083
+ <Checkbox label="Invalid option" variant="error" />
2084
+ ```
2085
+
2086
+ ```tsx
2087
+ <Checkbox.Group
2088
+ legend="Email preferences"
2089
+ description="Choose how you'd like to receive updates"
2090
+ value={preferences}
2091
+ onValueChange={setPreferences}
2092
+ >
2093
+ <Checkbox.Item value="email" label="Email notifications" />
2094
+ <Checkbox.Item value="sms" label="SMS notifications" />
2095
+ <Checkbox.Item value="push" label="Push notifications" />
2096
+ </Checkbox.Group>
2097
+ ```
2098
+
2099
+ ```tsx
2100
+ <Checkbox.Group
2101
+ legend="Required preferences"
2102
+ error="Please select at least one notification method"
2103
+ value={[]}
2104
+ onValueChange={() => {}}
2105
+ >
2106
+ <Checkbox.Item value="email" label="Email" variant="error" />
2107
+ <Checkbox.Item value="sms" label="SMS" variant="error" />
2108
+ </Checkbox.Group>
2109
+ ```
2110
+
2111
+
2112
+ ---
2113
+
2114
+ ### ClipboardText
2115
+
2116
+ Read-only text field with a one-click copy-to-clipboard button.
993
2117
 
994
2118
  **Type:** component
995
2119
 
@@ -1062,6 +2186,20 @@ Read-only text field with a one-click copy-to-clipboard button.
1062
2186
  - borderRadius: 8
1063
2187
  - fontSize: 14
1064
2188
 
2189
+ **Examples:**
2190
+
2191
+ ```tsx
2192
+ <ClipboardText text="0c239dd2" />
2193
+ ```
2194
+
2195
+ ```tsx
2196
+ <ClipboardText
2197
+ text="npx sf add button"
2198
+ tooltip={{ copiedText: "Copied!", side: "top", text: "Copy" }}
2199
+ />
2200
+ ```
2201
+
2202
+
1065
2203
  ---
1066
2204
 
1067
2205
  ### Code
@@ -1095,6 +2233,7 @@ Code component
1095
2233
 
1096
2234
  **Styling:**
1097
2235
 
2236
+
1098
2237
  **Sub-Components:**
1099
2238
 
1100
2239
  This is a compound component. Use these sub-components:
@@ -1104,15 +2243,36 @@ This is a compound component. Use these sub-components:
1104
2243
  Block sub-component
1105
2244
 
1106
2245
  Props:
1107
-
1108
2246
  - `code`: string (required)
1109
2247
  - `lang`: CodeLang
1110
2248
 
2249
+
2250
+ **Examples:**
2251
+
2252
+ ```tsx
2253
+ <CodeBlock
2254
+ lang="tsx"
2255
+ code={`const greeting = "Hello, World!";
2256
+ console.log(greeting);`}
2257
+ />
2258
+ ```
2259
+
2260
+ ```tsx
2261
+ <Code
2262
+ lang="bash"
2263
+ code="export API_KEY={{apiKey}}"
2264
+ values={{
2265
+ apiKey: { highlight: true, value: "sk_live_123" },
2266
+ }}
2267
+ />
2268
+ ```
2269
+
2270
+
1111
2271
  ---
1112
2272
 
1113
2273
  ### Collapsible
1114
2274
 
1115
- Collapsible component for showing/hiding content. Features: - Animated chevron indicator (rotates 180° when open) - Accessible with aria-expanded and aria-controls - Content panel with left border accent
2275
+ Collapsible component for showing/hiding content. Features: - Animated chevron indicator (rotates 180° when open) - Accessible with aria-expanded and aria-controls - Content panel with left border accent
1116
2276
 
1117
2277
  **Type:** component
1118
2278
 
@@ -1136,11 +2296,44 @@ Collapsible component for showing/hiding content. Features: - Animated chevron i
1136
2296
 
1137
2297
  `border-sf-fill`, `text-sf-link`
1138
2298
 
2299
+ **Examples:**
2300
+
2301
+ ```tsx
2302
+ <div className="w-full">
2303
+ <Collapsible label="What is SF?" open={isOpen} onOpenChange={setIsOpen}>
2304
+ A minimal, composable component library for building modern interfaces.
2305
+ </Collapsible>
2306
+ </div>
2307
+ ```
2308
+
2309
+ ```tsx
2310
+ <div className="w-full space-y-2">
2311
+ <Collapsible label="What is SF?" open={open1} onOpenChange={setOpen1}>
2312
+ A minimal, composable component library for building modern interfaces.
2313
+ </Collapsible>
2314
+ <Collapsible
2315
+ label="How do I use it?"
2316
+ open={open2}
2317
+ onOpenChange={setOpen2}
2318
+ >
2319
+ Install the components and import them into your project.
2320
+ </Collapsible>
2321
+ <Collapsible
2322
+ label="Is it open source?"
2323
+ open={open3}
2324
+ onOpenChange={setOpen3}
2325
+ >
2326
+ Check the repository for license information.
2327
+ </Collapsible>
2328
+ </div>
2329
+ ```
2330
+
2331
+
1139
2332
  ---
1140
2333
 
1141
2334
  ### Combobox
1142
2335
 
1143
- Combobox — autocomplete input with filterable dropdown list. Compound component: `Combobox` (Root), `.TriggerInput`, `.TriggerValue`, `.TriggerMultipleWithInput`, `.Content`, `.Item`, `.Chip`, `.Input`, `.Empty`, `.GroupLabel`, `.Group`, `.List`, `.Collection`.
2336
+ Combobox — autocomplete input with filterable dropdown list. Compound component: `Combobox` (Root), `.TriggerInput`, `.TriggerValue`, `.TriggerMultipleWithInput`, `.Content`, `.Item`, `.Chip`, `.Input`, `.Empty`, `.GroupLabel`, `.Group`, `.List`, `.Collection`.
1144
2337
 
1145
2338
  **Type:** component
1146
2339
 
@@ -1191,7 +2384,6 @@ This is a compound component. Use these sub-components:
1191
2384
  Content sub-component
1192
2385
 
1193
2386
  Props:
1194
-
1195
2387
  - `className`: string
1196
2388
  - `align`: ComboboxBase.Positioner.Props["align"]
1197
2389
  - `alignOffset`: ComboboxBase.Positioner.Props["alignOffset"]
@@ -1243,11 +2435,9 @@ List sub-component
1243
2435
  Renders filtered list items. Use when you need more control over item rendering.
1244
2436
 
1245
2437
  Props:
1246
-
1247
2438
  - `children`: (item: T, index: number) => ReactNode (required) - Function that receives each filtered item and returns a node
1248
2439
 
1249
2440
  Usage:
1250
-
1251
2441
  ```tsx
1252
2442
  <Combobox.Collection>
1253
2443
  {(item, index) => (
@@ -1258,11 +2448,171 @@ Usage:
1258
2448
  </Combobox.Collection>
1259
2449
  ```
1260
2450
 
2451
+
2452
+ **Examples:**
2453
+
2454
+ ```tsx
2455
+ <Combobox
2456
+ value={value}
2457
+ onValueChange={(v) => setValue(v as string | null)}
2458
+ items={fruits}
2459
+ >
2460
+ <Combobox.TriggerInput placeholder="Please select" />
2461
+ <Combobox.Content>
2462
+ <Combobox.Empty />
2463
+ <Combobox.List>
2464
+ {(item: string) => (
2465
+ <Combobox.Item key={item} value={item}>
2466
+ {item}
2467
+ </Combobox.Item>
2468
+ )}
2469
+ </Combobox.List>
2470
+ </Combobox.Content>
2471
+ </Combobox>
2472
+ ```
2473
+
2474
+ ```tsx
2475
+ <Combobox
2476
+ value={value}
2477
+ onValueChange={(v) => setValue(v as Language)}
2478
+ items={languages}
2479
+ >
2480
+ <Combobox.TriggerValue className="w-[200px]" />
2481
+ <Combobox.Content>
2482
+ <Combobox.Input placeholder="Search languages" />
2483
+ <Combobox.Empty />
2484
+ <Combobox.List>
2485
+ {(item: Language) => (
2486
+ <Combobox.Item key={item.value} value={item}>
2487
+ {item.emoji} {item.label}
2488
+ </Combobox.Item>
2489
+ )}
2490
+ </Combobox.List>
2491
+ </Combobox.Content>
2492
+ </Combobox>
2493
+ ```
2494
+
2495
+ ```tsx
2496
+ <Combobox
2497
+ value={value}
2498
+ onValueChange={(v) => setValue(v as ServerLocation | null)}
2499
+ items={servers}
2500
+ >
2501
+ <Combobox.TriggerInput
2502
+ className="w-[200px]"
2503
+ placeholder="Select server"
2504
+ />
2505
+ <Combobox.Content>
2506
+ <Combobox.Empty />
2507
+ <Combobox.List>
2508
+ {(group: ServerLocationGroup) => (
2509
+ <Combobox.Group key={group.value} items={group.items}>
2510
+ <Combobox.GroupLabel>{group.value}</Combobox.GroupLabel>
2511
+ <Combobox.Collection>
2512
+ {(item: ServerLocation) => (
2513
+ <Combobox.Item key={item.value} value={item}>
2514
+ {item.label}
2515
+ </Combobox.Item>
2516
+ )}
2517
+ </Combobox.Collection>
2518
+ </Combobox.Group>
2519
+ )}
2520
+ </Combobox.List>
2521
+ </Combobox.Content>
2522
+ </Combobox>
2523
+ ```
2524
+
2525
+ ```tsx
2526
+ <div className="flex gap-2">
2527
+ <Combobox
2528
+ value={value}
2529
+ onValueChange={setValue}
2530
+ items={bots}
2531
+ isItemEqualToValue={(bot: BotItem, selected: BotItem) =>
2532
+ bot.value === selected.value
2533
+ }
2534
+ multiple
2535
+ >
2536
+ <Combobox.TriggerMultipleWithInput
2537
+ className="w-[400px]"
2538
+ placeholder="Select bots"
2539
+ renderItem={(selected: BotItem) => (
2540
+ <Combobox.Chip key={selected.value}>{selected.label}</Combobox.Chip>
2541
+ )}
2542
+ inputSide="right"
2543
+ />
2544
+ <Combobox.Content className="max-h-[200px] min-w-auto overflow-y-auto">
2545
+ <Combobox.Empty />
2546
+ <Combobox.List>
2547
+ {(item: BotItem) => (
2548
+ <Combobox.Item key={item.value} value={item}>
2549
+ <div className="flex gap-2">
2550
+ <Text>{item.label}</Text>
2551
+ <Text variant="secondary">{item.author}</Text>
2552
+ </div>
2553
+ </Combobox.Item>
2554
+ )}
2555
+ </Combobox.List>
2556
+ </Combobox.Content>
2557
+ </Combobox>
2558
+ <Button variant="primary">Submit</Button>
2559
+ </div>
2560
+ ```
2561
+
2562
+ ```tsx
2563
+ <div className="w-80">
2564
+ <Combobox
2565
+ items={databases}
2566
+ value={value}
2567
+ onValueChange={setValue}
2568
+ label="Database"
2569
+ description="Select your preferred database"
2570
+ >
2571
+ <Combobox.TriggerInput placeholder="Select database" />
2572
+ <Combobox.Content>
2573
+ <Combobox.Empty />
2574
+ <Combobox.List>
2575
+ {(item: DatabaseItem) => (
2576
+ <Combobox.Item key={item.value} value={item}>
2577
+ {item.label}
2578
+ </Combobox.Item>
2579
+ )}
2580
+ </Combobox.List>
2581
+ </Combobox.Content>
2582
+ </Combobox>
2583
+ </div>
2584
+ ```
2585
+
2586
+ ```tsx
2587
+ <div className="w-80">
2588
+ <Combobox
2589
+ items={databases}
2590
+ value={value}
2591
+ onValueChange={setValue}
2592
+ label="Database"
2593
+ error={{ match: true, message: "Please select a database" }}
2594
+ >
2595
+ <Combobox.TriggerInput placeholder="Select database" />
2596
+ <Combobox.Content>
2597
+ <Combobox.Empty />
2598
+ <Combobox.List>
2599
+ {(item: DatabaseItem) => (
2600
+ <Combobox.Item key={item.value} value={item}>
2601
+ {item.label}
2602
+ </Combobox.Item>
2603
+ )}
2604
+ </Combobox.List>
2605
+ </Combobox.Content>
2606
+ </Combobox>
2607
+ </div>
2608
+ ```
2609
+
2610
+
1261
2611
  ---
1262
2612
 
1263
2613
  ### CommandPalette
1264
2614
 
1265
- CommandPalette — accessible command palette / spotlight search overlay. Compound component: `CommandPalette.Root` (or `.Dialog` + `.Panel`), `.Input`, `.List`, `.Results`, `.Items`, `.Group`, `.GroupLabel`, `.Item`, `.ResultItem`, `.HighlightedText`, `.Empty`, `.Loading`, `.Footer`. Built on `@base-ui/react/autocomplete` + `@base-ui/react/dialog`.
2615
+ CommandPalette — accessible command palette / spotlight search overlay. Compound component: `CommandPalette.Root` (or `.Dialog` + `.Panel`), `.Input`, `.List`, `.Results`, `.Items`, `.Group`, `.GroupLabel`, `.Item`, `.ResultItem`, `.HighlightedText`, `.Empty`, `.Loading`, `.Footer`. Built on `@base-ui/react/autocomplete` + `@base-ui/react/dialog`.
1266
2616
 
1267
2617
  **Type:** component
1268
2618
 
@@ -1281,6 +2631,221 @@ CommandPalette — accessible command palette / spotlight search overlay. Compou
1281
2631
 
1282
2632
  `bg-sf-elevated`, `bg-sf-overlay`, `bg-sf-warning`, `ring-sf-line`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`
1283
2633
 
2634
+ **Examples:**
2635
+
2636
+ ```tsx
2637
+ <div className="flex flex-col items-start gap-4">
2638
+ <Button onClick={() => setOpen(true)}>Open Command Palette</Button>
2639
+ {selectedItem && (
2640
+ <p className="text-sm text-sf-subtle">
2641
+ Last selected: <span className="text-sf-default">{selectedItem}</span>
2642
+ </p>
2643
+ )}
2644
+
2645
+ <CommandPalette.Root
2646
+ open={open}
2647
+ onOpenChange={setOpen}
2648
+ items={sampleGroups}
2649
+ value={search}
2650
+ onValueChange={setSearch}
2651
+ itemToStringValue={(group) => group.label}
2652
+ onSelect={(item, { newTab }) => {
2653
+ console.log("Selected:", item.title, newTab ? "(new tab)" : "");
2654
+ handleSelect(item);
2655
+ }}
2656
+ getSelectableItems={getSelectableItems}
2657
+ >
2658
+ <CommandPalette.Input placeholder="Type a command or search..." />
2659
+ <CommandPalette.List>
2660
+ <CommandPalette.Results>
2661
+ {(group: CommandGroup) => (
2662
+ <CommandPalette.Group key={group.id}>
2663
+ <CommandPalette.GroupLabel>
2664
+ {group.label}
2665
+ </CommandPalette.GroupLabel>
2666
+ <CommandPalette.Items>
2667
+ {(item: CommandItem) => (
2668
+ <CommandPalette.Item
2669
+ key={item.id}
2670
+ value={item}
2671
+ onClick={() => handleSelect(item)}
2672
+ >
2673
+ <span className="flex items-center gap-3">
2674
+ {item.icon && (
2675
+ <span className="text-sf-subtle">{item.icon}</span>
2676
+ )}
2677
+ <span>{item.title}</span>
2678
+ </span>
2679
+ </CommandPalette.Item>
2680
+ )}
2681
+ </CommandPalette.Items>
2682
+ </CommandPalette.Group>
2683
+ )}
2684
+ </CommandPalette.Results>
2685
+ <CommandPalette.Empty>No commands found</CommandPalette.Empty>
2686
+ </CommandPalette.List>
2687
+ <CommandPalette.Footer>
2688
+ <span className="flex items-center gap-2">
2689
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2690
+ ↑↓
2691
+ </kbd>
2692
+ <span>Navigate</span>
2693
+ </span>
2694
+ <span className="flex items-center gap-2">
2695
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2696
+
2697
+ </kbd>
2698
+ <span>Select</span>
2699
+ </span>
2700
+ </CommandPalette.Footer>
2701
+ </CommandPalette.Root>
2702
+ </div>
2703
+ ```
2704
+
2705
+ ```tsx
2706
+ <div>
2707
+ <Button onClick={() => setOpen(true)}>Open Simple Palette</Button>
2708
+
2709
+ <CommandPalette.Root
2710
+ open={open}
2711
+ onOpenChange={setOpen}
2712
+ items={simpleItems}
2713
+ value={search}
2714
+ onValueChange={setSearch}
2715
+ itemToStringValue={(item) => item.title}
2716
+ onSelect={(item) => {
2717
+ console.log("Selected:", item.title);
2718
+ setOpen(false);
2719
+ }}
2720
+ getSelectableItems={(items) => items}
2721
+ >
2722
+ <CommandPalette.Input placeholder="Search actions..." />
2723
+ <CommandPalette.List>
2724
+ <CommandPalette.Results>
2725
+ {(item: SimpleItem) => (
2726
+ <CommandPalette.Item
2727
+ key={item.id}
2728
+ value={item}
2729
+ onClick={() => {
2730
+ console.log("Clicked:", item.title);
2731
+ setOpen(false);
2732
+ }}
2733
+ >
2734
+ {item.title}
2735
+ </CommandPalette.Item>
2736
+ )}
2737
+ </CommandPalette.Results>
2738
+ <CommandPalette.Empty>No actions found</CommandPalette.Empty>
2739
+ </CommandPalette.List>
2740
+ </CommandPalette.Root>
2741
+ </div>
2742
+ ```
2743
+
2744
+ ```tsx
2745
+ <div>
2746
+ <Button onClick={handleOpen}>Open with Loading</Button>
2747
+
2748
+ <CommandPalette.Root
2749
+ open={open}
2750
+ onOpenChange={setOpen}
2751
+ items={loading ? [] : sampleGroups}
2752
+ value={search}
2753
+ onValueChange={setSearch}
2754
+ itemToStringValue={(group) => group.label}
2755
+ getSelectableItems={getSelectableItems}
2756
+ >
2757
+ <CommandPalette.Input placeholder="Search..." />
2758
+ <CommandPalette.List>
2759
+ {loading ? (
2760
+ <CommandPalette.Loading />
2761
+ ) : (
2762
+ <>
2763
+ <CommandPalette.Results>
2764
+ {(group: CommandGroup) => (
2765
+ <CommandPalette.Group key={group.id}>
2766
+ <CommandPalette.GroupLabel>
2767
+ {group.label}
2768
+ </CommandPalette.GroupLabel>
2769
+ <CommandPalette.Items>
2770
+ {(item: CommandItem) => (
2771
+ <CommandPalette.Item
2772
+ key={item.id}
2773
+ value={item}
2774
+ onClick={() => setOpen(false)}
2775
+ >
2776
+ <span className="flex items-center gap-3">
2777
+ {item.icon && (
2778
+ <span className="text-sf-subtle">
2779
+ {item.icon}
2780
+ </span>
2781
+ )}
2782
+ <span>{item.title}</span>
2783
+ </span>
2784
+ </CommandPalette.Item>
2785
+ )}
2786
+ </CommandPalette.Items>
2787
+ </CommandPalette.Group>
2788
+ )}
2789
+ </CommandPalette.Results>
2790
+ <CommandPalette.Empty>No results found</CommandPalette.Empty>
2791
+ </>
2792
+ )}
2793
+ </CommandPalette.List>
2794
+ </CommandPalette.Root>
2795
+ </div>
2796
+ ```
2797
+
2798
+ ```tsx
2799
+ <div>
2800
+ <Button onClick={() => setOpen(true)}>Open with ResultItem</Button>
2801
+
2802
+ <CommandPalette.Root
2803
+ open={open}
2804
+ onOpenChange={setOpen}
2805
+ items={searchResults}
2806
+ value={search}
2807
+ onValueChange={setSearch}
2808
+ itemToStringValue={(item) => item.title}
2809
+ getSelectableItems={(items) => items}
2810
+ >
2811
+ <CommandPalette.Input placeholder="Search documentation..." />
2812
+ <CommandPalette.List>
2813
+ <CommandPalette.Results>
2814
+ {(item: SearchResult) => (
2815
+ <CommandPalette.ResultItem
2816
+ key={item.id}
2817
+ value={item}
2818
+ title={item.title}
2819
+ breadcrumbs={item.breadcrumbs}
2820
+ icon={item.icon}
2821
+ onClick={() => {
2822
+ console.log("Navigate to:", item.title);
2823
+ setOpen(false);
2824
+ }}
2825
+ />
2826
+ )}
2827
+ </CommandPalette.Results>
2828
+ <CommandPalette.Empty>No pages found</CommandPalette.Empty>
2829
+ </CommandPalette.List>
2830
+ <CommandPalette.Footer>
2831
+ <span className="flex items-center gap-2">
2832
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2833
+ ↑↓
2834
+ </kbd>
2835
+ <span>Navigate</span>
2836
+ </span>
2837
+ <span className="flex items-center gap-2">
2838
+ <kbd className="rounded border border-sf-line bg-sf-base px-1.5 py-0.5 text-[10px]">
2839
+ ⌘↵
2840
+ </kbd>
2841
+ <span>Open in new tab</span>
2842
+ </span>
2843
+ </CommandPalette.Footer>
2844
+ </CommandPalette.Root>
2845
+ </div>
2846
+ ```
2847
+
2848
+
1284
2849
  ---
1285
2850
 
1286
2851
  ### DataGrid
@@ -1331,11 +2896,149 @@ ColumnToggle sub-component
1331
2896
 
1332
2897
  Empty sub-component
1333
2898
 
2899
+
2900
+ **Examples:**
2901
+
2902
+ ```tsx
2903
+ <LayerCard>
2904
+ <LayerCard.Primary className="p-0">
2905
+ <DataGrid data={sampleUsers} columns={columns} enableSorting>
2906
+ <DataGrid.Content />
2907
+ </DataGrid>
2908
+ </LayerCard.Primary>
2909
+ </LayerCard>
2910
+ ```
2911
+
2912
+ ```tsx
2913
+ <LayerCard>
2914
+ <LayerCard.Primary className="p-0">
2915
+ <DataGrid
2916
+ data={paginatedData}
2917
+ columns={columns.slice(0, 3)}
2918
+ pageSize={pageSize}
2919
+ pageIndex={pageIndex}
2920
+ onPaginationChange={({ pageIndex: newPage }) => setPageIndex(newPage)}
2921
+ totalCount={totalCount}
2922
+ manualPagination
2923
+ >
2924
+ <DataGrid.Content />
2925
+ <DataGrid.Pagination />
2926
+ </DataGrid>
2927
+ </LayerCard.Primary>
2928
+ </LayerCard>
2929
+ ```
2930
+
2931
+ ```tsx
2932
+ <LayerCard>
2933
+ <LayerCard.Primary className="p-0">
2934
+ <DataGrid
2935
+ data={sampleUsers.slice(0, 4)}
2936
+ columns={columns}
2937
+ enableRowSelection
2938
+ rowSelection={rowSelection}
2939
+ onRowSelectionChange={setRowSelection}
2940
+ >
2941
+ <DataGrid.Content />
2942
+ </DataGrid>
2943
+ <div className="border-t border-sf-line p-3 text-sm">
2944
+ <p className="text-sf-subtle">
2945
+ Selected: {Object.keys(rowSelection).length} rows
2946
+ </p>
2947
+ </div>
2948
+ </LayerCard.Primary>
2949
+ </LayerCard>
2950
+ ```
2951
+
2952
+ ```tsx
2953
+ <LayerCard>
2954
+ <LayerCard.Primary className="p-0">
2955
+ <DataGrid
2956
+ data={sampleUsers.slice(0, 4)}
2957
+ columns={columns}
2958
+ columnVisibility={columnVisibility}
2959
+ onColumnVisibilityChange={setColumnVisibility}
2960
+ >
2961
+ <DataGrid.Toolbar className="p-3">
2962
+ <DataGrid.ColumnToggle />
2963
+ </DataGrid.Toolbar>
2964
+ <DataGrid.Content />
2965
+ </DataGrid>
2966
+ </LayerCard.Primary>
2967
+ </LayerCard>
2968
+ ```
2969
+
2970
+ ```tsx
2971
+ <LayerCard>
2972
+ <LayerCard.Primary className="p-0">
2973
+ <DataGrid data={sampleUsers} columns={columns} enableSorting>
2974
+ <DataGrid.Toolbar className="flex items-center justify-between p-3">
2975
+ <span className="text-sm font-medium">Users</span>
2976
+ <DataGrid.ColumnToggle />
2977
+ </DataGrid.Toolbar>
2978
+ <DataGrid.Content />
2979
+ </DataGrid>
2980
+ </LayerCard.Primary>
2981
+ </LayerCard>
2982
+ ```
2983
+
2984
+ ```tsx
2985
+ <LayerCard>
2986
+ <LayerCard.Primary className="p-0">
2987
+ <DataGrid
2988
+ data={[]}
2989
+ columns={columns.slice(0, 3)}
2990
+ emptyState={
2991
+ <div className="flex flex-col items-center justify-center py-12 text-center">
2992
+ <p className="text-sf-strong font-medium">No users found</p>
2993
+ <p className="text-sf-subtle mt-1 text-sm">
2994
+ Try adjusting your filters or add new users
2995
+ </p>
2996
+ </div>
2997
+ }
2998
+ >
2999
+ <DataGrid.Content />
3000
+ </DataGrid>
3001
+ </LayerCard.Primary>
3002
+ </LayerCard>
3003
+ ```
3004
+
3005
+ ```tsx
3006
+ <LayerCard>
3007
+ <LayerCard.Primary className="p-0">
3008
+ <DataGrid
3009
+ data={[]}
3010
+ columns={columns.slice(0, 3)}
3011
+ loading
3012
+ loadingRows={3}
3013
+ >
3014
+ <DataGrid.Content />
3015
+ </DataGrid>
3016
+ </LayerCard.Primary>
3017
+ </LayerCard>
3018
+ ```
3019
+
3020
+ ```tsx
3021
+ <LayerCard>
3022
+ <LayerCard.Primary className="p-0">
3023
+ <DataGrid
3024
+ data={sampleUsers}
3025
+ columns={resizableColumns}
3026
+ enableSorting
3027
+ enableColumnResizing
3028
+ columnResizeMode="onEnd"
3029
+ >
3030
+ <DataGrid.Content />
3031
+ </DataGrid>
3032
+ </LayerCard.Primary>
3033
+ </LayerCard>
3034
+ ```
3035
+
3036
+
1334
3037
  ---
1335
3038
 
1336
3039
  ### DatePicker
1337
3040
 
1338
- DatePicker — a date selection calendar. Built on [react-day-picker](https://daypicker.dev) with SignalFlare styling. Supports three selection modes: single, multiple, and range.
3041
+ DatePicker — a date selection calendar. Built on [react-day-picker](https://daypicker.dev) with SignalFlare styling. Supports three selection modes: single, multiple, and range.
1339
3042
 
1340
3043
  **Type:** component
1341
3044
 
@@ -1354,11 +3057,167 @@ DatePicker — a date selection calendar. Built on [react-day-picker](https://da
1354
3057
 
1355
3058
  `bg-sf-base`
1356
3059
 
3060
+ **Examples:**
3061
+
3062
+ ```tsx
3063
+ <div className="flex flex-col gap-4">
3064
+ <DatePicker
3065
+ mode="single"
3066
+ selected={date}
3067
+ onChange={(d) => {
3068
+ if (d) {
3069
+ setDate(d);
3070
+ }
3071
+ }}
3072
+ />
3073
+ <p className="text-sm text-sf-subtle">
3074
+ Selected: {date ? date.toLocaleDateString() : "None"}
3075
+ </p>
3076
+ </div>
3077
+ ```
3078
+
3079
+ ```tsx
3080
+ <div className="flex flex-col gap-4">
3081
+ <DatePicker
3082
+ mode="multiple"
3083
+ selected={dates}
3084
+ onChange={setDates}
3085
+ max={5}
3086
+ />
3087
+ <p className="text-sm text-sf-subtle">
3088
+ Selected: {dates?.length ?? 0} date(s)
3089
+ </p>
3090
+ </div>
3091
+ ```
3092
+
3093
+ ```tsx
3094
+ <div className="flex flex-col gap-4">
3095
+ <DatePicker
3096
+ mode="range"
3097
+ selected={range}
3098
+ onChange={setRange}
3099
+ numberOfMonths={2}
3100
+ />
3101
+ <p className="text-sm text-sf-subtle">
3102
+ Range:{" "}
3103
+ {range?.from
3104
+ ? `${range.from.toLocaleDateString()} - ${range.to?.toLocaleDateString() ?? "..."}`
3105
+ : "None"}
3106
+ </p>
3107
+ </div>
3108
+ ```
3109
+
3110
+ ```tsx
3111
+ <div className="flex flex-col gap-4">
3112
+ <DatePicker
3113
+ mode="range"
3114
+ selected={range}
3115
+ onChange={setRange}
3116
+ min={3}
3117
+ max={7}
3118
+ footer={
3119
+ <span className="text-xs text-sf-subtle">Select 3-7 nights</span>
3120
+ }
3121
+ />
3122
+ </div>
3123
+ ```
3124
+
3125
+ ```tsx
3126
+ <Popover>
3127
+ <Popover.Trigger asChild>
3128
+ <Button variant="outline" icon={CalendarDotsIcon}>
3129
+ {date ? date.toLocaleDateString() : "Pick a date"}
3130
+ </Button>
3131
+ </Popover.Trigger>
3132
+ <Popover.Content className="p-3">
3133
+ <DatePicker mode="single" selected={date} onChange={setDate} />
3134
+ </Popover.Content>
3135
+ </Popover>
3136
+ ```
3137
+
3138
+ ```tsx
3139
+ <Popover>
3140
+ <Popover.Trigger asChild>
3141
+ <Button variant="outline" icon={CalendarDotsIcon}>
3142
+ {formatRange()}
3143
+ </Button>
3144
+ </Popover.Trigger>
3145
+ <Popover.Content className="p-3">
3146
+ <DatePicker
3147
+ mode="range"
3148
+ selected={range}
3149
+ onChange={setRange}
3150
+ numberOfMonths={2}
3151
+ />
3152
+ </Popover.Content>
3153
+ </Popover>
3154
+ ```
3155
+
3156
+ ```tsx
3157
+ <Popover>
3158
+ <Popover.Trigger asChild>
3159
+ <Button variant="outline" icon={CalendarDotsIcon}>
3160
+ {formatRange()}
3161
+ </Button>
3162
+ </Popover.Trigger>
3163
+ <Popover.Content className="p-0">
3164
+ <div className="flex">
3165
+ <div className="flex flex-col gap-1 border-r border-sf-line p-2 text-sm">
3166
+ {presets.map((preset) => {
3167
+ const isActive = isPresetActive(preset);
3168
+ return (
3169
+ <button
3170
+ key={preset.label}
3171
+ type="button"
3172
+ onClick={() => handlePresetClick(preset)}
3173
+ className={`rounded-md px-3 py-1.5 text-left whitespace-nowrap ${
3174
+ isActive
3175
+ ? "bg-sf-bg-inverse text-sf-text-inverse"
3176
+ : "text-sf-strong hover:bg-sf-control"
3177
+ }`}
3178
+ >
3179
+ {preset.label}
3180
+ </button>
3181
+ );
3182
+ })}
3183
+ </div>
3184
+ <div className="p-3">
3185
+ <DatePicker
3186
+ mode="range"
3187
+ selected={range}
3188
+ onChange={setRange}
3189
+ month={month}
3190
+ onMonthChange={setMonth}
3191
+ numberOfMonths={2}
3192
+ />
3193
+ </div>
3194
+ </div>
3195
+ </Popover.Content>
3196
+ </Popover>
3197
+ ```
3198
+
3199
+ ```tsx
3200
+ <DatePicker
3201
+ mode="multiple"
3202
+ selected={dates}
3203
+ onChange={setDates}
3204
+ max={maxDays}
3205
+ disabled={unavailableDates}
3206
+ fixedWeeks
3207
+ footer={
3208
+ <p className="text-xs text-sf-subtle pt-2 w-full">
3209
+ {selectedCount}/{maxDays} days selected. Grayed dates are unavailable.
3210
+ </p>
3211
+ }
3212
+ />
3213
+ ```
3214
+
3215
+
1357
3216
  ---
1358
3217
 
1359
3218
  ### DateRangePicker
1360
3219
 
1361
- DateRangePicker — dual-calendar date range selector. Renders two side-by-side month calendars with click-to-select start/end dates, hover preview of the range, a timezone footer, and a reset button.
3220
+ DateRangePicker — dual-calendar date range selector. Renders two side-by-side month calendars with click-to-select start/end dates, hover preview of the range, a timezone footer, and a reset button.
1362
3221
 
1363
3222
  **Type:** component
1364
3223
 
@@ -1478,11 +3337,235 @@ Description sub-component
1478
3337
 
1479
3338
  Close sub-component
1480
3339
 
3340
+
3341
+ **Examples:**
3342
+
3343
+ ```tsx
3344
+ <Dialog.Root>
3345
+ <Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />
3346
+ <Dialog className="p-8">
3347
+ <div className="mb-4 flex items-start justify-between gap-4">
3348
+ <Dialog.Title className="text-2xl font-semibold">
3349
+ Modal Title
3350
+ </Dialog.Title>
3351
+ <Dialog.Close
3352
+ aria-label="Close"
3353
+ render={(props) => (
3354
+ <Button
3355
+ {...props}
3356
+ variant="secondary"
3357
+ shape="square"
3358
+ icon={<XIcon />}
3359
+ aria-label="Close"
3360
+ />
3361
+ )}
3362
+ />
3363
+ </div>
3364
+ <Dialog.Description className="text-sf-subtle">
3365
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
3366
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
3367
+ </Dialog.Description>
3368
+ </Dialog>
3369
+ </Dialog.Root>
3370
+ ```
3371
+
3372
+ ```tsx
3373
+ <Dialog.Root>
3374
+ <Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />
3375
+ <Dialog className="p-8">
3376
+ <div className="mb-4 flex items-start justify-between gap-4">
3377
+ <Dialog.Title className="text-2xl font-semibold">
3378
+ Modal Title
3379
+ </Dialog.Title>
3380
+ <Dialog.Close
3381
+ aria-label="Close"
3382
+ render={(props) => (
3383
+ <Button
3384
+ {...props}
3385
+ variant="secondary"
3386
+ shape="square"
3387
+ icon={<XIcon />}
3388
+ aria-label="Close"
3389
+ />
3390
+ )}
3391
+ />
3392
+ </div>
3393
+ <Dialog.Description className="text-sf-subtle">
3394
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
3395
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
3396
+ </Dialog.Description>
3397
+ <div className="mt-8 flex justify-end gap-2">
3398
+ <Dialog.Close
3399
+ render={(props) => (
3400
+ <Button variant="secondary" {...props}>
3401
+ Cancel
3402
+ </Button>
3403
+ )}
3404
+ />
3405
+ <Dialog.Close
3406
+ render={(props) => (
3407
+ <Button variant="destructive" {...props}>
3408
+ Delete
3409
+ </Button>
3410
+ )}
3411
+ />
3412
+ </div>
3413
+ </Dialog>
3414
+ </Dialog.Root>
3415
+ ```
3416
+
3417
+ ```tsx
3418
+ <Dialog.Root disablePointerDismissal>
3419
+ <Dialog.Trigger
3420
+ render={(p) => (
3421
+ <Button {...p} variant="destructive">
3422
+ Delete Project
3423
+ </Button>
3424
+ )}
3425
+ />
3426
+ <Dialog className="p-8">
3427
+ <div className="mb-4 flex items-center gap-3">
3428
+ <div className="flex h-10 w-10 items-center justify-center rounded-full bg-sf-danger/20">
3429
+ <WarningIcon size={20} className="text-sf-danger" />
3430
+ </div>
3431
+ <Dialog.Title className="text-xl font-semibold">
3432
+ Delete Project?
3433
+ </Dialog.Title>
3434
+ </div>
3435
+ <Dialog.Description className="text-sf-subtle">
3436
+ This action cannot be undone. This will permanently delete the project
3437
+ and all associated data.
3438
+ </Dialog.Description>
3439
+ <div className="mt-8 flex justify-end gap-2">
3440
+ <Dialog.Close
3441
+ render={(props) => (
3442
+ <Button variant="secondary" {...props}>
3443
+ Cancel
3444
+ </Button>
3445
+ )}
3446
+ />
3447
+ <Dialog.Close
3448
+ render={(props) => (
3449
+ <Button variant="destructive" {...props}>
3450
+ Delete
3451
+ </Button>
3452
+ )}
3453
+ />
3454
+ </div>
3455
+ </Dialog>
3456
+ </Dialog.Root>
3457
+ ```
3458
+
3459
+ ```tsx
3460
+ <Dialog.Root>
3461
+ <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
3462
+ <Dialog className="p-8">
3463
+ <div className="mb-4 flex items-start justify-between gap-4">
3464
+ <Dialog.Title className="text-2xl font-semibold">
3465
+ Create Resource
3466
+ </Dialog.Title>
3467
+ <Dialog.Close
3468
+ aria-label="Close"
3469
+ render={(props) => (
3470
+ <Button
3471
+ {...props}
3472
+ variant="secondary"
3473
+ shape="square"
3474
+ icon={<XIcon />}
3475
+ aria-label="Close"
3476
+ />
3477
+ )}
3478
+ />
3479
+ </div>
3480
+ <Dialog.Description className="mb-4 text-sf-subtle">
3481
+ Select a region for your new resource.
3482
+ </Dialog.Description>
3483
+ <Select
3484
+ className="w-full"
3485
+ renderValue={(v) =>
3486
+ regions.find((r) => r.value === v)?.label ?? "Select region..."
3487
+ }
3488
+ >
3489
+ {regions.map((region) => (
3490
+ <Select.Option key={region.value} value={region.value}>
3491
+ {region.label}
3492
+ </Select.Option>
3493
+ ))}
3494
+ </Select>
3495
+ <div className="mt-8 flex justify-end gap-2">
3496
+ <Dialog.Close
3497
+ render={(props) => (
3498
+ <Button variant="secondary" {...props}>
3499
+ Cancel
3500
+ </Button>
3501
+ )}
3502
+ />
3503
+ <Button variant="primary">Create</Button>
3504
+ </div>
3505
+ </Dialog>
3506
+ </Dialog.Root>
3507
+ ```
3508
+
3509
+ ```tsx
3510
+ <Dialog.Root>
3511
+ <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
3512
+ <Dialog className="p-8">
3513
+ <div className="mb-4 flex items-start justify-between gap-4">
3514
+ <Dialog.Title className="text-2xl font-semibold">
3515
+ Create Resource
3516
+ </Dialog.Title>
3517
+ <Dialog.Close
3518
+ aria-label="Close"
3519
+ render={(props) => (
3520
+ <Button
3521
+ {...props}
3522
+ variant="secondary"
3523
+ shape="square"
3524
+ icon={<XIcon />}
3525
+ aria-label="Close"
3526
+ />
3527
+ )}
3528
+ />
3529
+ </div>
3530
+ <Dialog.Description className="mb-4 text-sf-subtle">
3531
+ Search and select a region for your new resource.
3532
+ </Dialog.Description>
3533
+ <Combobox value={value} onValueChange={setValue} items={regions}>
3534
+ <Combobox.TriggerInput
3535
+ className="w-full"
3536
+ placeholder="Search regions..."
3537
+ />
3538
+ <Combobox.Content>
3539
+ <Combobox.Empty>No regions found</Combobox.Empty>
3540
+ <Combobox.List>
3541
+ {(item: { value: string; label: string }) => (
3542
+ <Combobox.Item key={item.value} value={item}>
3543
+ {item.label}
3544
+ </Combobox.Item>
3545
+ )}
3546
+ </Combobox.List>
3547
+ </Combobox.Content>
3548
+ </Combobox>
3549
+ <div className="mt-8 flex justify-end gap-2">
3550
+ <Dialog.Close
3551
+ render={(props) => (
3552
+ <Button variant="secondary" {...props}>
3553
+ Cancel
3554
+ </Button>
3555
+ )}
3556
+ />
3557
+ <Button variant="primary">Create</Button>
3558
+ </div>
3559
+ </Dialog>
3560
+ </Dialog.Root>
3561
+ ```
3562
+
3563
+
1481
3564
  ---
1482
3565
 
1483
3566
  ### DropdownMenu
1484
3567
 
1485
- DropdownMenu — accessible dropdown menu anchored to a trigger. Compound component: `DropdownMenu` (Root), `.Trigger`, `.Content`, `.Item`, `.CheckboxItem`, `.RadioGroup`, `.RadioItem`, `.RadioItemIndicator`, `.Sub`, `.SubTrigger`, `.SubContent`, `.Label`, `.Separator`, `.Shortcut`, `.Group`. Built on `@base-ui/react/menu`.
3568
+ DropdownMenu — accessible dropdown menu anchored to a trigger. Compound component: `DropdownMenu` (Root), `.Trigger`, `.Content`, `.Item`, `.CheckboxItem`, `.RadioGroup`, `.RadioItem`, `.RadioItemIndicator`, `.Sub`, `.SubTrigger`, `.SubContent`, `.Label`, `.Separator`, `.Shortcut`, `.Group`. Built on `@base-ui/react/menu`.
1486
3569
 
1487
3570
  **Type:** component
1488
3571
 
@@ -1564,6 +3647,7 @@ Shortcut sub-component
1564
3647
 
1565
3648
  Group sub-component (wraps DropdownMenuPrimitive)
1566
3649
 
3650
+
1567
3651
  ---
1568
3652
 
1569
3653
  ### Empty
@@ -1599,6 +3683,92 @@ Placeholder shown when a list, table, or page has no content to display.
1599
3683
 
1600
3684
  `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
3685
 
3686
+ **Examples:**
3687
+
3688
+ ```tsx
3689
+ <Empty
3690
+ icon={<PackageIcon size={48} />}
3691
+ title="No packages found"
3692
+ description="Get started by installing your first package."
3693
+ commandLine="npm install @signalflare-ai/ui"
3694
+ contents={
3695
+ <div className="flex items-center gap-2">
3696
+ <Button icon={<CodeIcon />}>See examples</Button>
3697
+ <Button icon={<GlobeIcon />} variant="primary">
3698
+ View documentation
3699
+ </Button>
3700
+ </div>
3701
+ }
3702
+ />
3703
+ ```
3704
+
3705
+ ```tsx
3706
+ <div className="flex flex-col gap-8">
3707
+ <div>
3708
+ <p className="mb-2 text-sm text-sf-subtle">Small</p>
3709
+ <Empty
3710
+ size="sm"
3711
+ icon={<DatabaseIcon size={32} className="text-sf-inactive" />}
3712
+ title="No data available"
3713
+ description="There is no data to display."
3714
+ />
3715
+ </div>
3716
+ <div>
3717
+ <p className="mb-2 text-sm text-sf-subtle">Base</p>
3718
+ <Empty
3719
+ size="base"
3720
+ icon={<DatabaseIcon size={48} className="text-sf-inactive" />}
3721
+ title="No data available"
3722
+ description="There is no data to display."
3723
+ />
3724
+ </div>
3725
+ <div>
3726
+ <p className="mb-2 text-sm text-sf-subtle">Large</p>
3727
+ <Empty
3728
+ size="lg"
3729
+ icon={<DatabaseIcon size={64} className="text-sf-inactive" />}
3730
+ title="No data available"
3731
+ description="There is no data to display."
3732
+ />
3733
+ </div>
3734
+ </div>
3735
+ ```
3736
+
3737
+ ```tsx
3738
+ <Empty
3739
+ icon={<FolderOpenIcon size={48} className="text-sf-inactive" />}
3740
+ title="No projects found"
3741
+ description="Get started by creating your first project using the command below."
3742
+ commandLine="npm create sf-project"
3743
+ />
3744
+ ```
3745
+
3746
+ ```tsx
3747
+ <Empty
3748
+ icon={<CloudSlashIcon size={48} className="text-sf-inactive" />}
3749
+ title="No connection"
3750
+ description="Unable to connect to the server. Please check your connection and try again."
3751
+ contents={
3752
+ <div className="flex gap-2">
3753
+ <Button variant="primary">Retry</Button>
3754
+ <Button variant="secondary">Go Back</Button>
3755
+ </div>
3756
+ }
3757
+ />
3758
+ ```
3759
+
3760
+ ```tsx
3761
+ <Empty title="Nothing here" />
3762
+ ```
3763
+
3764
+ ```tsx
3765
+ <Empty
3766
+ title="No results found"
3767
+ description="Try adjusting your search or filter to find what you're looking for."
3768
+ />
3769
+ ```
3770
+
3771
+
1602
3772
  ---
1603
3773
 
1604
3774
  ### Field
@@ -1636,7 +3806,7 @@ Form field wrapper that provides a label, optional description, and error displa
1636
3806
 
1637
3807
  ### Filters
1638
3808
 
1639
- Filters component for building and managing active filter conditions. Supports multiple filter types (text, select, multiselect, custom), operators, and an "Add Filter" popover interface. Designed to work standalone or with DataGrid for advanced data filtering.
3809
+ Filters component for building and managing active filter conditions. Supports multiple filter types (text, select, multiselect, custom), operators, and an "Add Filter" popover interface. Designed to work standalone or with DataGrid for advanced data filtering.
1640
3810
 
1641
3811
  **Type:** component
1642
3812
 
@@ -1677,6 +3847,62 @@ Filters component for building and managing active filter conditions. Supports m
1677
3847
 
1678
3848
  `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
3849
 
3850
+ **Examples:**
3851
+
3852
+ ```tsx
3853
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3854
+ <Filters filters={filters} fields={filterFields} onChange={setFilters} />
3855
+ <div className="mt-4 rounded bg-sf-elevated p-3 font-mono text-xs">
3856
+ <p className="text-sf-subtle mb-1">Active filters:</p>
3857
+ <pre className="text-sf-strong overflow-x-auto">
3858
+ {JSON.stringify(filters, null, 2)}
3859
+ </pre>
3860
+ </div>
3861
+ </div>
3862
+ ```
3863
+
3864
+ ```tsx
3865
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3866
+ <Filters
3867
+ filters={filters}
3868
+ fields={filterFields.slice(0, 3)}
3869
+ onChange={setFilters}
3870
+ size="sm"
3871
+ />
3872
+ </div>
3873
+ ```
3874
+
3875
+ ```tsx
3876
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3877
+ <Filters
3878
+ filters={filters}
3879
+ fields={filterFields}
3880
+ onChange={setFilters}
3881
+ showSearchInput
3882
+ />
3883
+ <p className="text-sf-subtle mt-3 text-xs">
3884
+ Open the "Add Filter" menu to see grouped fields (General, User Details)
3885
+ </p>
3886
+ </div>
3887
+ ```
3888
+
3889
+ ```tsx
3890
+ <div className="w-full rounded-lg border border-sf-line bg-sf-base p-4">
3891
+ <Filters
3892
+ filters={filters}
3893
+ fields={filterFields.slice(0, 3)}
3894
+ onChange={setFilters}
3895
+ enableShortcut
3896
+ shortcutKey="k"
3897
+ shortcutLabel="Cmd+K"
3898
+ />
3899
+ <p className="text-sf-subtle mt-3 text-xs">
3900
+ Press Cmd+K (or Ctrl+K) to quickly open the add filter menu
3901
+ </p>
3902
+ </div>
3903
+ ```
3904
+
3905
+
1680
3906
  ---
1681
3907
 
1682
3908
  ### Grid
@@ -1720,6 +3946,230 @@ Responsive CSS grid layout container with preset column configurations.
1720
3946
 
1721
3947
  `border-sf-line`
1722
3948
 
3949
+ **Examples:**
3950
+
3951
+ ```tsx
3952
+ <Grid variant="2up" gap="base">
3953
+ <GridItem>
3954
+ <Tile>
3955
+ <div>Item 1</div>
3956
+ <div className="mt-1">First grid item</div>
3957
+ </Tile>
3958
+ </GridItem>
3959
+ <GridItem>
3960
+ <Tile>
3961
+ <div>Item 2</div>
3962
+ <div className="mt-1">Second grid item</div>
3963
+ </Tile>
3964
+ </GridItem>
3965
+ </Grid>
3966
+ ```
3967
+
3968
+ ```tsx
3969
+ <div className="flex flex-col gap-8">
3970
+ <div>
3971
+ <p className="mb-2 text-sf-subtle">variant="2up"</p>
3972
+ <Grid variant="2up" gap="sm">
3973
+ <GridItem>
3974
+ <Tile>
3975
+ <span className="block text-center">1</span>
3976
+ </Tile>
3977
+ </GridItem>
3978
+ <GridItem>
3979
+ <Tile>
3980
+ <span className="block text-center">2</span>
3981
+ </Tile>
3982
+ </GridItem>
3983
+ </Grid>
3984
+ </div>
3985
+
3986
+ <div>
3987
+ <p className="mb-2 text-sf-subtle">variant="3up"</p>
3988
+ <Grid variant="3up" gap="sm">
3989
+ <GridItem>
3990
+ <Tile>
3991
+ <span className="block text-center">1</span>
3992
+ </Tile>
3993
+ </GridItem>
3994
+ <GridItem>
3995
+ <Tile>
3996
+ <span className="block text-center">2</span>
3997
+ </Tile>
3998
+ </GridItem>
3999
+ <GridItem>
4000
+ <Tile>
4001
+ <span className="block text-center">3</span>
4002
+ </Tile>
4003
+ </GridItem>
4004
+ </Grid>
4005
+ </div>
4006
+
4007
+ <div>
4008
+ <p className="mb-2 text-sf-subtle">variant="4up"</p>
4009
+ <Grid variant="4up" gap="sm">
4010
+ <GridItem>
4011
+ <Tile>
4012
+ <span className="block text-center">1</span>
4013
+ </Tile>
4014
+ </GridItem>
4015
+ <GridItem>
4016
+ <Tile>
4017
+ <span className="block text-center">2</span>
4018
+ </Tile>
4019
+ </GridItem>
4020
+ <GridItem>
4021
+ <Tile>
4022
+ <span className="block text-center">3</span>
4023
+ </Tile>
4024
+ </GridItem>
4025
+ <GridItem>
4026
+ <Tile>
4027
+ <span className="block text-center">4</span>
4028
+ </Tile>
4029
+ </GridItem>
4030
+ </Grid>
4031
+ </div>
4032
+ </div>
4033
+ ```
4034
+
4035
+ ```tsx
4036
+ <div className="flex flex-col gap-8">
4037
+ <div>
4038
+ <p className="mb-2 text-sf-subtle">variant="2-1" (66% / 33%)</p>
4039
+ <Grid variant="2-1" gap="sm">
4040
+ <GridItem>
4041
+ <Tile>
4042
+ <div>Main Content</div>
4043
+ <div className="mt-1">Two-thirds width</div>
4044
+ </Tile>
4045
+ </GridItem>
4046
+ <GridItem>
4047
+ <Tile>
4048
+ <div>Sidebar</div>
4049
+ <div className="mt-1">One-third width</div>
4050
+ </Tile>
4051
+ </GridItem>
4052
+ </Grid>
4053
+ </div>
4054
+
4055
+ <div>
4056
+ <p className="mb-2 text-sf-subtle">variant="1-2" (33% / 66%)</p>
4057
+ <Grid variant="1-2" gap="sm">
4058
+ <GridItem>
4059
+ <Tile>
4060
+ <div>Sidebar</div>
4061
+ <div className="mt-1">One-third width</div>
4062
+ </Tile>
4063
+ </GridItem>
4064
+ <GridItem>
4065
+ <Tile>
4066
+ <div>Main Content</div>
4067
+ <div className="mt-1">Two-thirds width</div>
4068
+ </Tile>
4069
+ </GridItem>
4070
+ </Grid>
4071
+ </div>
4072
+ </div>
4073
+ ```
4074
+
4075
+ ```tsx
4076
+ <div className="flex flex-col gap-8">
4077
+ <div>
4078
+ <p className="mb-2 text-sf-subtle">gap="none"</p>
4079
+ <Grid variant="side-by-side" gap="none">
4080
+ <GridItem>
4081
+ <Tile>
4082
+ <span className="block text-center">1</span>
4083
+ </Tile>
4084
+ </GridItem>
4085
+ <GridItem>
4086
+ <Tile>
4087
+ <span className="block text-center">2</span>
4088
+ </Tile>
4089
+ </GridItem>
4090
+ </Grid>
4091
+ </div>
4092
+
4093
+ <div>
4094
+ <p className="mb-2 text-sf-subtle">gap="sm"</p>
4095
+ <Grid variant="side-by-side" gap="sm">
4096
+ <GridItem>
4097
+ <Tile>
4098
+ <span className="block text-center">1</span>
4099
+ </Tile>
4100
+ </GridItem>
4101
+ <GridItem>
4102
+ <Tile>
4103
+ <span className="block text-center">2</span>
4104
+ </Tile>
4105
+ </GridItem>
4106
+ </Grid>
4107
+ </div>
4108
+
4109
+ <div>
4110
+ <p className="mb-2 text-sf-subtle">gap="base" (default, responsive)</p>
4111
+ <Grid variant="side-by-side" gap="base">
4112
+ <GridItem>
4113
+ <Tile>
4114
+ <span className="block text-center">1</span>
4115
+ </Tile>
4116
+ </GridItem>
4117
+ <GridItem>
4118
+ <Tile>
4119
+ <span className="block text-center">2</span>
4120
+ </Tile>
4121
+ </GridItem>
4122
+ </Grid>
4123
+ </div>
4124
+
4125
+ <div>
4126
+ <p className="mb-2 text-sf-subtle">gap="lg"</p>
4127
+ <Grid variant="side-by-side" gap="lg">
4128
+ <GridItem>
4129
+ <Tile>
4130
+ <span className="block text-center">1</span>
4131
+ </Tile>
4132
+ </GridItem>
4133
+ <GridItem>
4134
+ <Tile>
4135
+ <span className="block text-center">2</span>
4136
+ </Tile>
4137
+ </GridItem>
4138
+ </Grid>
4139
+ </div>
4140
+ </div>
4141
+ ```
4142
+
4143
+ ```tsx
4144
+ <Grid variant="4up" gap="base" mobileDivider>
4145
+ <GridItem>
4146
+ <Tile>
4147
+ <div>Item 1</div>
4148
+ <div className="mt-1">Has divider on mobile</div>
4149
+ </Tile>
4150
+ </GridItem>
4151
+ <GridItem>
4152
+ <Tile>
4153
+ <div>Item 2</div>
4154
+ <div className="mt-1">Has divider on mobile</div>
4155
+ </Tile>
4156
+ </GridItem>
4157
+ <GridItem>
4158
+ <Tile>
4159
+ <div>Item 3</div>
4160
+ <div className="mt-1">Has divider on mobile</div>
4161
+ </Tile>
4162
+ </GridItem>
4163
+ <GridItem>
4164
+ <Tile>
4165
+ <div>Item 4</div>
4166
+ <div className="mt-1">Has divider on mobile</div>
4167
+ </Tile>
4168
+ </GridItem>
4169
+ </Grid>
4170
+ ```
4171
+
4172
+
1723
4173
  ---
1724
4174
 
1725
4175
  ### Input
@@ -1765,11 +4215,97 @@ Input component
1765
4215
 
1766
4216
  - **Dimensions:** `[object Object]`
1767
4217
 
4218
+ **Examples:**
4219
+
4220
+ ```tsx
4221
+ <Input
4222
+ label="Email"
4223
+ placeholder="you@example.com"
4224
+ description="We'll never share your email"
4225
+ />
4226
+ ```
4227
+
4228
+ ```tsx
4229
+ <Input
4230
+ label="Email"
4231
+ placeholder="you@example.com"
4232
+ value="invalid-email"
4233
+ variant="error"
4234
+ error="Please enter a valid email address"
4235
+ />
4236
+ ```
4237
+
4238
+ ```tsx
4239
+ <Input
4240
+ label="Password"
4241
+ type="password"
4242
+ value="short"
4243
+ variant="error"
4244
+ error={{
4245
+ match: "tooShort",
4246
+ message: "Password must be at least 8 characters",
4247
+ }}
4248
+ minLength={8}
4249
+ />
4250
+ ```
4251
+
4252
+ ```tsx
4253
+ <div className="flex flex-col gap-4">
4254
+ <Input size="xs" label="Extra Small" placeholder="Extra small input" />
4255
+ <Input size="sm" label="Small" placeholder="Small input" />
4256
+ <Input label="Base" placeholder="Base input (default)" />
4257
+ <Input size="lg" label="Large" placeholder="Large input" />
4258
+ </div>
4259
+ ```
4260
+
4261
+ ```tsx
4262
+ <Input label="Disabled field" placeholder="Cannot edit" disabled />
4263
+ ```
4264
+
4265
+ ```tsx
4266
+ <div className="flex flex-col gap-4">
4267
+ <Input type="email" label="Email" placeholder="you@example.com" />
4268
+ <Input type="password" label="Password" placeholder="••••••••" />
4269
+ <Input type="number" label="Age" placeholder="18" />
4270
+ <Input type="tel" label="Phone" placeholder="+1 (555) 000-0000" />
4271
+ </div>
4272
+ ```
4273
+
4274
+ ```tsx
4275
+ <Input
4276
+ label="Phone Number"
4277
+ required={false}
4278
+ placeholder="+1 (555) 000-0000"
4279
+ />
4280
+ ```
4281
+
4282
+ ```tsx
4283
+ <Input
4284
+ label="API Key"
4285
+ labelTooltip="Find this in your dashboard under Settings > API Keys"
4286
+ placeholder="sk_live_..."
4287
+ />
4288
+ ```
4289
+
4290
+ ```tsx
4291
+ <Input
4292
+ label={
4293
+ <span>
4294
+ Email for <strong>billing</strong>
4295
+ </span>
4296
+ }
4297
+ required
4298
+ placeholder="billing@company.com"
4299
+ type="email"
4300
+ />
4301
+ ```
4302
+
4303
+
1768
4304
  ---
1769
4305
 
1770
4306
  ### Label
1771
4307
 
1772
- Label component for form fields. Provides a standardized way to display labels with optional indicators: - Optional indicator: gray "(optional)" text when `showOptional={true}` - Tooltip: info icon with hover tooltip for additional context
4308
+ Label component for form fields. Provides a standardized way to display labels with optional indicators: - Optional indicator: gray "(optional)" text when `showOptional={true}` - Tooltip: info icon with hover tooltip for additional context
1773
4309
 
1774
4310
  **Type:** component
1775
4311
 
@@ -1796,6 +4332,59 @@ Label component for form fields. Provides a standardized way to display labels w
1796
4332
 
1797
4333
  `text-sf-default`, `text-sf-strong`
1798
4334
 
4335
+ **Examples:**
4336
+
4337
+ ```tsx
4338
+ <div className="flex flex-col gap-4">
4339
+ <Label>Default Label</Label>
4340
+ <Label showOptional>Optional Label</Label>
4341
+ <Label tooltip="More information about this field">
4342
+ Label with Tooltip
4343
+ </Label>
4344
+ </div>
4345
+ ```
4346
+
4347
+ ```tsx
4348
+ <Input label="Phone Number" required={false} placeholder="+1 555-0000" />
4349
+ ```
4350
+
4351
+ ```tsx
4352
+ <Input
4353
+ label="API Key"
4354
+ labelTooltip="Find this in your dashboard settings under API > Keys"
4355
+ placeholder="sk_live_..."
4356
+ />
4357
+ ```
4358
+
4359
+ ```tsx
4360
+ <Checkbox
4361
+ label={
4362
+ <span>
4363
+ I agree to the <strong>Terms of Service</strong>
4364
+ </span>
4365
+ }
4366
+ />
4367
+ ```
4368
+
4369
+ ```tsx
4370
+ <div className="flex max-w-md flex-col gap-4">
4371
+ <Input label="Full Name" placeholder="John Doe" />
4372
+ <Input
4373
+ label="Email"
4374
+ labelTooltip="We'll send your receipt here"
4375
+ placeholder="john@example.com"
4376
+ type="email"
4377
+ />
4378
+ <Input label="Company" required={false} placeholder="Acme Inc." />
4379
+ <Select label="Country" hideLabel={false} placeholder="Select a country">
4380
+ <Select.Option value="us">United States</Select.Option>
4381
+ <Select.Option value="uk">United Kingdom</Select.Option>
4382
+ <Select.Option value="ca">Canada</Select.Option>
4383
+ </Select>
4384
+ </div>
4385
+ ```
4386
+
4387
+
1799
4388
  ---
1800
4389
 
1801
4390
  ### LayerCard
@@ -1820,6 +4409,7 @@ LayerCard component
1820
4409
 
1821
4410
  **Styling:**
1822
4411
 
4412
+
1823
4413
  **Sub-Components:**
1824
4414
 
1825
4415
  This is a compound component. Use these sub-components:
@@ -1832,6 +4422,56 @@ Primary sub-component
1832
4422
 
1833
4423
  Secondary sub-component
1834
4424
 
4425
+
4426
+ **Examples:**
4427
+
4428
+ ```tsx
4429
+ <LayerCard>
4430
+ <LayerCard.Secondary className="flex items-center justify-between">
4431
+ <div>Next Steps</div>
4432
+ <Button
4433
+ variant="ghost"
4434
+ size="sm"
4435
+ shape="square"
4436
+ aria-label="Go to next steps"
4437
+ >
4438
+ <ArrowRightIcon size={16} />
4439
+ </Button>
4440
+ </LayerCard.Secondary>
4441
+
4442
+ <LayerCard.Primary>Get started with SF</LayerCard.Primary>
4443
+ </LayerCard>
4444
+ ```
4445
+
4446
+ ```tsx
4447
+ <LayerCard className="w-[250px]">
4448
+ <LayerCard.Secondary>Getting Started</LayerCard.Secondary>
4449
+ <LayerCard.Primary>
4450
+ <p className="text-sm text-sf-subtle">
4451
+ Quick start guide for new users
4452
+ </p>
4453
+ </LayerCard.Primary>
4454
+ </LayerCard>
4455
+ ```
4456
+
4457
+ ```tsx
4458
+ <div className="flex gap-4">
4459
+ <LayerCard className="w-[200px]">
4460
+ <LayerCard.Secondary>Components</LayerCard.Secondary>
4461
+ <LayerCard.Primary>
4462
+ <p className="text-sm">Browse all components</p>
4463
+ </LayerCard.Primary>
4464
+ </LayerCard>
4465
+ <LayerCard className="w-[200px]">
4466
+ <LayerCard.Secondary>Examples</LayerCard.Secondary>
4467
+ <LayerCard.Primary>
4468
+ <p className="text-sm">View code examples</p>
4469
+ </LayerCard.Primary>
4470
+ </LayerCard>
4471
+ </div>
4472
+ ```
4473
+
4474
+
1835
4475
  ---
1836
4476
 
1837
4477
  ### Link
@@ -1854,7 +4494,6 @@ Link component
1854
4494
  **State Classes:**
1855
4495
  - `"plain"`:
1856
4496
  - `hover`: `hover:text-primary/70`
1857
-
1858
4497
  - `to`: string
1859
4498
  - `children`: ReactNode
1860
4499
  - `className`: string
@@ -1882,6 +4521,71 @@ This is a compound component. Use these sub-components:
1882
4521
 
1883
4522
  ExternalIcon sub-component
1884
4523
 
4524
+
4525
+ **Examples:**
4526
+
4527
+ ```tsx
4528
+ <div className="grid gap-x-6 gap-y-4 text-base md:grid-cols-3">
4529
+ <Link href="#">Default inline link</Link>
4530
+ <Link href="#" variant="current">
4531
+ Current color link
4532
+ </Link>
4533
+ <Link href="#" variant="plain">
4534
+ Plain inline link
4535
+ </Link>
4536
+ </div>
4537
+ ```
4538
+
4539
+ ```tsx
4540
+ <p className="mx-auto max-w-md text-base leading-relaxed text-sf-default">
4541
+ This is a paragraph with an <Link href="#">inline link</Link> that flows
4542
+ naturally with the surrounding text. Links maintain proper underline
4543
+ offset for readability.
4544
+ </p>
4545
+ ```
4546
+
4547
+ ```tsx
4548
+ <Link
4549
+ href="https://cloudflare.com"
4550
+ target="_blank"
4551
+ rel="noopener noreferrer"
4552
+ className="text-base"
4553
+ >
4554
+ Visit Cloudflare <Link.ExternalIcon />
4555
+ </Link>
4556
+ ```
4557
+
4558
+ ```tsx
4559
+ <p className="text-base text-sf-danger">
4560
+ This error message contains a{" "}
4561
+ <Link href="#" variant="current">
4562
+ link
4563
+ </Link>{" "}
4564
+ that inherits the red color from its parent.
4565
+ </p>
4566
+ ```
4567
+
4568
+ ```tsx
4569
+ <div className="flex flex-col gap-x-6 gap-y-4 text-base md:flex-row">
4570
+ <Link render={<CustomRouterLink href="/dashboard" />} variant="inline">
4571
+ Dashboard (via render)
4572
+ </Link>
4573
+ <Link
4574
+ render={
4575
+ <CustomRouterLink
4576
+ href="https://developers.cloudflare.com"
4577
+ target="_blank"
4578
+ rel="noopener noreferrer"
4579
+ />
4580
+ }
4581
+ variant="inline"
4582
+ >
4583
+ Cloudflare Docs <Link.ExternalIcon />
4584
+ </Link>
4585
+ </div>
4586
+ ```
4587
+
4588
+
1885
4589
  ---
1886
4590
 
1887
4591
  ### Loader
@@ -1903,11 +4607,26 @@ Animated circular spinner for indicating loading states. Uses CSS keyframe anima
1903
4607
  - `"base"`: Default loader size
1904
4608
  - `"lg"`: Large loader for prominent loading states
1905
4609
 
4610
+ **Examples:**
4611
+
4612
+ ```tsx
4613
+ <div className="flex items-center gap-4">
4614
+ <Loader size="sm" />
4615
+ <Loader size="base" />
4616
+ <Loader size="lg" />
4617
+ </div>
4618
+ ```
4619
+
4620
+ ```tsx
4621
+ <Loader size={24} />
4622
+ ```
4623
+
4624
+
1906
4625
  ---
1907
4626
 
1908
4627
  ### MenuBar
1909
4628
 
1910
- MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. Each option renders as a `<button>` with a Tooltip. The active option is visually highlighted with an elevated background.
4629
+ MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. Each option renders as a `<button>` with a Tooltip. The active option is visually highlighted with an elevated background.
1911
4630
 
1912
4631
  **Type:** component
1913
4632
 
@@ -1932,6 +4651,31 @@ MenuBar — horizontal icon-button toolbar with keyboard arrow-key navigation. E
1932
4651
 
1933
4652
  **Styling:**
1934
4653
 
4654
+
4655
+ **Examples:**
4656
+
4657
+ ```tsx
4658
+ <MenuBar
4659
+ isActive="bold"
4660
+ optionIds
4661
+ options={[
4662
+ {
4663
+ icon: <TextBolderIcon />,
4664
+ id: "bold",
4665
+ onClick: () => {},
4666
+ tooltip: "Bold",
4667
+ },
4668
+ {
4669
+ icon: <TextItalicIcon />,
4670
+ id: "italic",
4671
+ onClick: () => {},
4672
+ tooltip: "Italic",
4673
+ },
4674
+ ]}
4675
+ />
4676
+ ```
4677
+
4678
+
1935
4679
  ---
1936
4680
 
1937
4681
  ### Meter
@@ -1967,6 +4711,29 @@ Progress bar showing a measured value within a known range (e.g. quota usage).
1967
4711
 
1968
4712
  `bg-sf-fill`, `text-sf-default`, `text-sf-strong`
1969
4713
 
4714
+ **Examples:**
4715
+
4716
+ ```tsx
4717
+ <Meter label="Storage used" value={65} />
4718
+ ```
4719
+
4720
+ ```tsx
4721
+ <Meter label="API requests" value={75} customValue="750 / 1,000" />
4722
+ ```
4723
+
4724
+ ```tsx
4725
+ <Meter label="Progress" value={40} showValue={false} />
4726
+ ```
4727
+
4728
+ ```tsx
4729
+ <Meter
4730
+ label="Upload progress"
4731
+ value={80}
4732
+ indicatorClassName="from-green-500 via-green-500 to-green-500"
4733
+ />
4734
+ ```
4735
+
4736
+
1970
4737
  ---
1971
4738
 
1972
4739
  ### Pagination
@@ -1999,7 +4766,35 @@ Page navigation controls with page count display.
1999
4766
 
2000
4767
  `text-sf-strong`
2001
4768
 
2002
- **Styling:**
4769
+ **Styling:**
4770
+
4771
+
4772
+ **Examples:**
4773
+
4774
+ ```tsx
4775
+ <Pagination page={page} setPage={setPage} perPage={10} totalCount={100} />
4776
+ ```
4777
+
4778
+ ```tsx
4779
+ <Pagination
4780
+ page={page}
4781
+ setPage={setPage}
4782
+ perPage={10}
4783
+ totalCount={100}
4784
+ controls="simple"
4785
+ />
4786
+ ```
4787
+
4788
+ ```tsx
4789
+ <Pagination
4790
+ text={({ perPage }) => `Page ${page} - showing ${perPage} per page`}
4791
+ page={page}
4792
+ setPage={setPage}
4793
+ perPage={25}
4794
+ totalCount={100}
4795
+ />
4796
+ ```
4797
+
2003
4798
 
2004
4799
  ---
2005
4800
 
@@ -2049,6 +4844,154 @@ Description sub-component
2049
4844
 
2050
4845
  Close sub-component
2051
4846
 
4847
+
4848
+ **Examples:**
4849
+
4850
+ ```tsx
4851
+ <Popover>
4852
+ <Popover.Trigger asChild>
4853
+ <Button shape="square" icon={BellIcon} aria-label="Notifications" />
4854
+ </Popover.Trigger>
4855
+ <Popover.Content>
4856
+ <Popover.Title>Notifications</Popover.Title>
4857
+ <Popover.Description>
4858
+ You are all caught up. Good job!
4859
+ </Popover.Description>
4860
+ </Popover.Content>
4861
+ </Popover>
4862
+ ```
4863
+
4864
+ ```tsx
4865
+ <Popover>
4866
+ <Popover.Trigger asChild>
4867
+ <Button>Open Popover</Button>
4868
+ </Popover.Trigger>
4869
+ <Popover.Content>
4870
+ <Popover.Title>Popover Title</Popover.Title>
4871
+ <Popover.Description>
4872
+ This is a basic popover with a title and description.
4873
+ </Popover.Description>
4874
+ </Popover.Content>
4875
+ </Popover>
4876
+ ```
4877
+
4878
+ ```tsx
4879
+ <Popover>
4880
+ <Popover.Trigger asChild>
4881
+ <Button>Open Settings</Button>
4882
+ </Popover.Trigger>
4883
+ <Popover.Content>
4884
+ <Popover.Title>Settings</Popover.Title>
4885
+ <Popover.Description>
4886
+ Configure your preferences below.
4887
+ </Popover.Description>
4888
+ <div className="mt-3">
4889
+ <Popover.Close asChild>
4890
+ <Button variant="secondary" size="sm">
4891
+ Close
4892
+ </Button>
4893
+ </Popover.Close>
4894
+ </div>
4895
+ </Popover.Content>
4896
+ </Popover>
4897
+ ```
4898
+
4899
+ ```tsx
4900
+ <div className="flex flex-wrap gap-4">
4901
+ <Popover>
4902
+ <Popover.Trigger asChild>
4903
+ <Button variant="secondary">Bottom</Button>
4904
+ </Popover.Trigger>
4905
+ <Popover.Content side="bottom">
4906
+ <Popover.Title>Bottom</Popover.Title>
4907
+ <Popover.Description>
4908
+ Popover on bottom (default).
4909
+ </Popover.Description>
4910
+ </Popover.Content>
4911
+ </Popover>
4912
+
4913
+ <Popover>
4914
+ <Popover.Trigger asChild>
4915
+ <Button variant="secondary">Top</Button>
4916
+ </Popover.Trigger>
4917
+ <Popover.Content side="top">
4918
+ <Popover.Title>Top</Popover.Title>
4919
+ <Popover.Description>Popover on top.</Popover.Description>
4920
+ </Popover.Content>
4921
+ </Popover>
4922
+
4923
+ <Popover>
4924
+ <Popover.Trigger asChild>
4925
+ <Button variant="secondary">Left</Button>
4926
+ </Popover.Trigger>
4927
+ <Popover.Content side="left">
4928
+ <Popover.Title>Left</Popover.Title>
4929
+ <Popover.Description>Popover on left.</Popover.Description>
4930
+ </Popover.Content>
4931
+ </Popover>
4932
+
4933
+ <Popover>
4934
+ <Popover.Trigger asChild>
4935
+ <Button variant="secondary">Right</Button>
4936
+ </Popover.Trigger>
4937
+ <Popover.Content side="right">
4938
+ <Popover.Title>Right</Popover.Title>
4939
+ <Popover.Description>Popover on right.</Popover.Description>
4940
+ </Popover.Content>
4941
+ </Popover>
4942
+ </div>
4943
+ ```
4944
+
4945
+ ```tsx
4946
+ <Popover>
4947
+ <Popover.Trigger asChild>
4948
+ <Button>User Profile</Button>
4949
+ </Popover.Trigger>
4950
+ <Popover.Content className="w-64">
4951
+ <div className="flex items-center gap-3">
4952
+ <div className="size-10 rounded-full bg-sf-recessed" />
4953
+ <div>
4954
+ <Popover.Title>Jane Doe</Popover.Title>
4955
+ <p className="text-sm text-sf-subtle">jane@example.com</p>
4956
+ </div>
4957
+ </div>
4958
+ <div className="mt-3 flex gap-2 border-t border-sf-line pt-3">
4959
+ <Button variant="secondary" size="sm" className="flex-1">
4960
+ Profile
4961
+ </Button>
4962
+ <Popover.Close asChild>
4963
+ <Button variant="ghost" size="sm" className="flex-1">
4964
+ Sign Out
4965
+ </Button>
4966
+ </Popover.Close>
4967
+ </div>
4968
+ </Popover.Content>
4969
+ </Popover>
4970
+ ```
4971
+
4972
+ ```tsx
4973
+ <Popover>
4974
+ <Popover.Trigger openOnHover delay={200} asChild>
4975
+ <Button variant="secondary">Hover Me</Button>
4976
+ </Popover.Trigger>
4977
+ <Popover.Content>
4978
+ <Popover.Title>Hover Triggered</Popover.Title>
4979
+ <Popover.Description>
4980
+ This popover opens on hover with a 200ms delay. It can still contain
4981
+ interactive content like buttons and links.
4982
+ </Popover.Description>
4983
+ <div className="mt-3">
4984
+ <Popover.Close asChild>
4985
+ <Button variant="secondary" size="sm">
4986
+ Got it
4987
+ </Button>
4988
+ </Popover.Close>
4989
+ </div>
4990
+ </Popover.Content>
4991
+ </Popover>
4992
+ ```
4993
+
4994
+
2052
4995
  ---
2053
4996
 
2054
4997
  ### PromptInput
@@ -2071,8 +5014,10 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
2071
5014
  Maximum file size in bytes.
2072
5015
  - `backLayer`: ReactNode
2073
5016
  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"`.
5017
+ - `backLayerTitle`: ReactNode
5018
+ 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"`.
5019
+ - `backLayerStatus`: enum
5020
+ 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
5021
  - `backLayerOpen`: boolean
2077
5022
  Controls whether the back layer is visible. Pair with `onBackLayerOpenChange` for a controlled pattern.
2078
5023
  - `autoOpenBackLayerWhen`: boolean
@@ -2085,13 +5030,70 @@ Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
2085
5030
 
2086
5031
  **Colors (sf tokens used):**
2087
5032
 
2088
- `bg-sf-base`, `bg-sf-control`, `bg-sf-elevated`, `bg-sf-overlay`, `bg-sf-tint`, `ring-sf-line`, `ring-sf-ring`, `text-sf-brand`, `text-sf-default`, `text-sf-inactive`, `text-sf-subtle`
5033
+ `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`
5034
+
5035
+ **Sub-Components:**
5036
+
5037
+ This is a compound component. Use these sub-components:
5038
+
5039
+ #### PromptInput.BackLayer
5040
+
5041
+ BackLayer sub-component
5042
+
5043
+ #### PromptInput.Textarea
5044
+
5045
+ Textarea sub-component
5046
+
5047
+ #### PromptInput.Editor
5048
+
5049
+ Editor sub-component
5050
+
5051
+ #### PromptInput.Toolbar
5052
+
5053
+ Toolbar sub-component
5054
+
5055
+ #### PromptInput.Tools
5056
+
5057
+ Tools sub-component
5058
+
5059
+ #### PromptInput.Submit
5060
+
5061
+ Submit sub-component
5062
+
5063
+ #### PromptInput.ModeSelector
5064
+
5065
+ ModeSelector sub-component
5066
+
5067
+ #### PromptInput.AddTagButton
5068
+
5069
+ AddTagButton sub-component
5070
+
5071
+ #### PromptInput.Tags
5072
+
5073
+ Tags sub-component
5074
+
5075
+ #### PromptInput.Tag
5076
+
5077
+ Tag sub-component
5078
+
5079
+ #### PromptInput.AttachButton
5080
+
5081
+ AttachButton sub-component
5082
+
5083
+ #### PromptInput.Attachments
5084
+
5085
+ Attachments sub-component
5086
+
5087
+ #### PromptInput.Attachment
5088
+
5089
+ Attachment sub-component
5090
+
2089
5091
 
2090
5092
  ---
2091
5093
 
2092
5094
  ### Radio
2093
5095
 
2094
- Radio — radio button group for single-select choices. Compound component: `Radio.Group` (with built-in Fieldset) and `Radio.Item`. Built on `@base-ui/react/radio-group` + `@base-ui/react/radio`.
5096
+ Radio — radio button group for single-select choices. Compound component: `Radio.Group` (with built-in Fieldset) and `Radio.Item`. Built on `@base-ui/react/radio-group` + `@base-ui/react/radio`.
2095
5097
 
2096
5098
  **Type:** component
2097
5099
 
@@ -2126,6 +5128,78 @@ Radio — radio button group for single-select choices. Compound component: `Rad
2126
5128
 
2127
5129
  `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`
2128
5130
 
5131
+ **Examples:**
5132
+
5133
+ ```tsx
5134
+ <Radio.Group
5135
+ legend="Notification preference"
5136
+ value={value}
5137
+ onValueChange={setValue}
5138
+ >
5139
+ <Radio.Item label="Email" value="email" />
5140
+ <Radio.Item label="SMS" value="sms" />
5141
+ <Radio.Item label="Push notification" value="push" />
5142
+ </Radio.Group>
5143
+ ```
5144
+
5145
+ ```tsx
5146
+ <Radio.Group
5147
+ legend="Size"
5148
+ orientation="horizontal"
5149
+ value={value}
5150
+ onValueChange={setValue}
5151
+ >
5152
+ <Radio.Item label="Small" value="sm" />
5153
+ <Radio.Item label="Medium" value="md" />
5154
+ <Radio.Item label="Large" value="lg" />
5155
+ </Radio.Group>
5156
+ ```
5157
+
5158
+ ```tsx
5159
+ <Radio.Group
5160
+ legend="Shipping method"
5161
+ description="Choose how you'd like to receive your order"
5162
+ value={value}
5163
+ onValueChange={setValue}
5164
+ >
5165
+ <Radio.Item label="Standard (5-7 days)" value="standard" />
5166
+ <Radio.Item label="Express (2-3 days)" value="express" />
5167
+ <Radio.Item label="Overnight" value="overnight" />
5168
+ </Radio.Group>
5169
+ ```
5170
+
5171
+ ```tsx
5172
+ <Radio.Group
5173
+ legend="Payment method"
5174
+ error="Please select a payment method to continue"
5175
+ >
5176
+ <Radio.Item label="Credit Card" value="card" variant="error" />
5177
+ <Radio.Item label="PayPal" value="paypal" variant="error" />
5178
+ <Radio.Item label="Bank Transfer" value="bank" variant="error" />
5179
+ </Radio.Group>
5180
+ ```
5181
+
5182
+ ```tsx
5183
+ <div className="flex flex-col gap-6">
5184
+ <Radio.Group legend="Disabled group" disabled defaultValue="a">
5185
+ <Radio.Item label="Option A" value="a" />
5186
+ <Radio.Item label="Option B" value="b" />
5187
+ </Radio.Group>
5188
+ <Radio.Group legend="Individual disabled" defaultValue="available">
5189
+ <Radio.Item label="Available" value="available" />
5190
+ <Radio.Item label="Unavailable" value="unavailable" disabled />
5191
+ </Radio.Group>
5192
+ </div>
5193
+ ```
5194
+
5195
+ ```tsx
5196
+ <Radio.Group legend="Preferences" controlPosition="end" defaultValue="a">
5197
+ <Radio.Item label="Label before radio" value="a" />
5198
+ <Radio.Item label="Another option" value="b" />
5199
+ </Radio.Group>
5200
+ ```
5201
+
5202
+
2129
5203
  ---
2130
5204
 
2131
5205
  ### Select
@@ -2175,6 +5249,7 @@ Select component
2175
5249
 
2176
5250
  **Styling:**
2177
5251
 
5252
+
2178
5253
  **Sub-Components:**
2179
5254
 
2180
5255
  This is a compound component. Use these sub-components:
@@ -2183,6 +5258,107 @@ This is a compound component. Use these sub-components:
2183
5258
 
2184
5259
  Option sub-component
2185
5260
 
5261
+
5262
+ **Examples:**
5263
+
5264
+ ```tsx
5265
+ <Select
5266
+ className="w-[200px]"
5267
+ value={value}
5268
+ onValueChange={(v) => setValue(v ?? "apple")}
5269
+ items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
5270
+ >
5271
+ <Select.Option value="apple">Apple</Select.Option>
5272
+ <Select.Option value="banana">Banana</Select.Option>
5273
+ <Select.Option value="cherry">Cherry</Select.Option>
5274
+ </Select>
5275
+ ```
5276
+
5277
+ ```tsx
5278
+ <Select
5279
+ className="w-[200px]"
5280
+ renderValue={(v) => (
5281
+ <span>
5282
+ {v.emoji} {v.label}
5283
+ </span>
5284
+ )}
5285
+ value={value}
5286
+ onValueChange={(v) => setValue(v as (typeof languages)[0])}
5287
+ >
5288
+ {languages.map((language) => (
5289
+ <Select.Option key={language.value} value={language}>
5290
+ {language.emoji} {language.label}
5291
+ </Select.Option>
5292
+ ))}
5293
+ </Select>
5294
+ ```
5295
+
5296
+ ```tsx
5297
+ <Select className="w-[200px]" loading />
5298
+ ```
5299
+
5300
+ ```tsx
5301
+ <Select
5302
+ className="w-[200px]"
5303
+ loading={loading}
5304
+ value={value}
5305
+ onValueChange={(v) => setValue(v as string | null)}
5306
+ placeholder="Please select"
5307
+ >
5308
+ {data?.map((item) => (
5309
+ <Select.Option key={item} value={item}>
5310
+ {item}
5311
+ </Select.Option>
5312
+ ))}
5313
+ </Select>
5314
+ ```
5315
+
5316
+ ```tsx
5317
+ <Select
5318
+ className="w-[250px]"
5319
+ multiple
5320
+ renderValue={(value) => {
5321
+ if (value.length > 3) {
5322
+ return (
5323
+ <span className="line-clamp-1">
5324
+ {value.slice(2).join(", ") + ` and ${value.length - 2} more`}
5325
+ </span>
5326
+ );
5327
+ }
5328
+ return <span>{value.join(", ")}</span>;
5329
+ }}
5330
+ value={value}
5331
+ onValueChange={(v) => setValue(v as string[])}
5332
+ >
5333
+ <Select.Option value="Name">Name</Select.Option>
5334
+ <Select.Option value="Location">Location</Select.Option>
5335
+ <Select.Option value="Size">Size</Select.Option>
5336
+ <Select.Option value="Read">Read</Select.Option>
5337
+ <Select.Option value="Write">Write</Select.Option>
5338
+ <Select.Option value="CreatedAt">Created At</Select.Option>
5339
+ </Select>
5340
+ ```
5341
+
5342
+ ```tsx
5343
+ <Select
5344
+ className="w-[200px]"
5345
+ onValueChange={(v) => setValue(v as (typeof authors)[0] | null)}
5346
+ value={value}
5347
+ isItemEqualToValue={(item, value) => item?.id === value?.id}
5348
+ renderValue={(author) => author?.name ?? "Please select author"}
5349
+ >
5350
+ {authors.map((author) => (
5351
+ <Select.Option key={author.id} value={author}>
5352
+ <div className="flex w-[300px] items-center justify-between gap-2">
5353
+ <Text>{author.name}</Text>
5354
+ <Text variant="secondary">{author.title}</Text>
5355
+ </div>
5356
+ </Select.Option>
5357
+ ))}
5358
+ </Select>
5359
+ ```
5360
+
5361
+
2186
5362
  ---
2187
5363
 
2188
5364
  ### SensitiveInput
@@ -2238,11 +5414,82 @@ Password/secret input that masks its value by default and reveals on click. Incl
2238
5414
 
2239
5415
  `bg-sf-brand`, `bg-sf-control`, `outline-sf-ring`, `text-sf-default`, `text-sf-subtle`
2240
5416
 
5417
+ **Examples:**
5418
+
5419
+ ```tsx
5420
+ <div className="w-80">
5421
+ <SensitiveInput label="API Key" defaultValue="sk_live_abc123xyz789" />
5422
+ </div>
5423
+ ```
5424
+
5425
+ ```tsx
5426
+ <div className="flex flex-col gap-4">
5427
+ {sizes.map((size) => (
5428
+ <div key={size} className="flex items-center gap-2">
5429
+ <span className="w-12 text-sm text-sf-subtle">{size}</span>
5430
+ <SensitiveInput
5431
+ label={`${size} size`}
5432
+ size={size}
5433
+ defaultValue="secret-api-key-123"
5434
+ />
5435
+ </div>
5436
+ ))}
5437
+ </div>
5438
+ ```
5439
+
5440
+ ```tsx
5441
+ <div className="flex w-80 flex-col gap-4">
5442
+ <SensitiveInput
5443
+ label="Controlled Secret"
5444
+ value={value}
5445
+ onValueChange={setValue}
5446
+ />
5447
+ <div className="text-sm text-sf-subtle">
5448
+ Current value: <code className="text-sf-default">{value}</code>
5449
+ </div>
5450
+ <div className="flex gap-2">
5451
+ <Button
5452
+ onClick={() => setValue("new-secret-" + Date.now())}
5453
+ variant="primary"
5454
+ size="sm"
5455
+ >
5456
+ Change value
5457
+ </Button>
5458
+ <Button onClick={() => setValue("")} variant="secondary" size="sm">
5459
+ Clear
5460
+ </Button>
5461
+ </div>
5462
+ </div>
5463
+ ```
5464
+
5465
+ ```tsx
5466
+ <div className="flex w-80 flex-col gap-4">
5467
+ <SensitiveInput
5468
+ label="Error State"
5469
+ variant="error"
5470
+ defaultValue="invalid-key"
5471
+ error="This API key is not valid"
5472
+ />
5473
+ <SensitiveInput label="Disabled" defaultValue="cannot-edit" disabled />
5474
+ <SensitiveInput
5475
+ label="Read-only"
5476
+ defaultValue="view-only-secret-key"
5477
+ readOnly
5478
+ />
5479
+ <SensitiveInput
5480
+ label="With Description"
5481
+ defaultValue="my-secret-value"
5482
+ description="Keep this value secure and don't share it"
5483
+ />
5484
+ </div>
5485
+ ```
5486
+
5487
+
2241
5488
  ---
2242
5489
 
2243
5490
  ### Sidebar
2244
5491
 
2245
- Sidebar — responsive navigation panel with expand/collapse support. Compound component: `Sidebar` (root `<aside>`), `.Provider`, `.Header`, `.Content`, `.Footer`, `.Group`, `.GroupLabel`, `.GroupContent`, `.Menu`, `.MenuItem`, `.MenuButton`, `.MenuAction`, `.MenuBadge`, `.MenuSub`, `.MenuSubItem`, `.MenuSubButton`, `.Separator`, `.Input`, `.Trigger`, `.Rail`, `.MenuChevron`, `.Collapsible`, `.CollapsibleTrigger`, `.CollapsibleContent`. Built on `@base-ui/react/collapsible` + `@base-ui/react/dialog`.
5492
+ Sidebar — responsive navigation panel with expand/collapse support. Compound component: `Sidebar` (root `<aside>`), `.Provider`, `.Header`, `.Content`, `.Footer`, `.Group`, `.GroupLabel`, `.GroupContent`, `.Menu`, `.MenuItem`, `.MenuButton`, `.MenuAction`, `.MenuBadge`, `.MenuSub`, `.MenuSubItem`, `.MenuSubButton`, `.Separator`, `.Input`, `.Trigger`, `.Rail`, `.MenuChevron`, `.Collapsible`, `.CollapsibleTrigger`, `.CollapsibleContent`. Built on `@base-ui/react/collapsible` + `@base-ui/react/dialog`.
2246
5493
 
2247
5494
  **Type:** component
2248
5495
 
@@ -2286,6 +5533,7 @@ Sidebar — responsive navigation panel with expand/collapse support. Compound c
2286
5533
 
2287
5534
  **Styling:**
2288
5535
 
5536
+
2289
5537
  **Sub-Components:**
2290
5538
 
2291
5539
  This is a compound component. Use these sub-components:
@@ -2295,7 +5543,6 @@ This is a compound component. Use these sub-components:
2295
5543
  Provider sub-component
2296
5544
 
2297
5545
  Props:
2298
-
2299
5546
  - `defaultOpen`: boolean
2300
5547
  - `open`: boolean
2301
5548
  - `variant`: SidebarVariant
@@ -2400,6 +5647,299 @@ CollapsibleTrigger sub-component
2400
5647
 
2401
5648
  CollapsibleContent sub-component
2402
5649
 
5650
+
5651
+ **Examples:**
5652
+
5653
+ ```tsx
5654
+ <DemoContainer>
5655
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5656
+ <Sidebar>
5657
+ <Sidebar.Content>
5658
+ <Sidebar.Group>
5659
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5660
+ <Sidebar.Menu>
5661
+ <Sidebar.MenuButton icon={HouseIcon} active>
5662
+ Home
5663
+ </Sidebar.MenuButton>
5664
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5665
+ Analytics
5666
+ </Sidebar.MenuButton>
5667
+ <Sidebar.MenuButton icon={GlobeIcon}>
5668
+ Domains
5669
+ </Sidebar.MenuButton>
5670
+ </Sidebar.Menu>
5671
+ </Sidebar.Group>
5672
+
5673
+ <Sidebar.Group>
5674
+ <Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
5675
+ <Sidebar.Menu>
5676
+ <Sidebar.MenuItem>
5677
+ <Sidebar.Collapsible defaultOpen>
5678
+ <Sidebar.CollapsibleTrigger
5679
+ render={
5680
+ <Sidebar.MenuButton icon={CodeIcon}>
5681
+ Compute
5682
+ <Sidebar.MenuChevron />
5683
+ </Sidebar.MenuButton>
5684
+ }
5685
+ />
5686
+ <Sidebar.CollapsibleContent>
5687
+ <Sidebar.MenuSub>
5688
+ <Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
5689
+ <Sidebar.MenuSubButton>
5690
+ Durable Objects
5691
+ </Sidebar.MenuSubButton>
5692
+ </Sidebar.MenuSub>
5693
+ </Sidebar.CollapsibleContent>
5694
+ </Sidebar.Collapsible>
5695
+ </Sidebar.MenuItem>
5696
+ <Sidebar.MenuButton icon={DatabaseIcon}>
5697
+ Storage
5698
+ </Sidebar.MenuButton>
5699
+ </Sidebar.Menu>
5700
+ </Sidebar.Group>
5701
+ </Sidebar.Content>
5702
+ </Sidebar>
5703
+ <DemoMain />
5704
+ </Sidebar.Provider>
5705
+ </DemoContainer>
5706
+ ```
5707
+
5708
+ ```tsx
5709
+ <DemoContainer>
5710
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5711
+ <Sidebar>
5712
+ <Sidebar.Content>
5713
+ <Sidebar.Group collapsible defaultOpen>
5714
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5715
+ <Sidebar.GroupContent>
5716
+ <Sidebar.Menu>
5717
+ <Sidebar.MenuButton icon={HouseIcon} active>
5718
+ Home
5719
+ </Sidebar.MenuButton>
5720
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5721
+ Analytics
5722
+ </Sidebar.MenuButton>
5723
+ <Sidebar.MenuButton icon={GlobeIcon}>
5724
+ Domains
5725
+ </Sidebar.MenuButton>
5726
+ </Sidebar.Menu>
5727
+ </Sidebar.GroupContent>
5728
+ </Sidebar.Group>
5729
+
5730
+ <Sidebar.Group collapsible defaultOpen={false}>
5731
+ <Sidebar.GroupLabel>Settings</Sidebar.GroupLabel>
5732
+ <Sidebar.GroupContent>
5733
+ <Sidebar.Menu>
5734
+ <Sidebar.MenuButton icon={ShieldCheckIcon}>
5735
+ Security
5736
+ </Sidebar.MenuButton>
5737
+ <Sidebar.MenuButton icon={LockIcon}>
5738
+ Access Control
5739
+ </Sidebar.MenuButton>
5740
+ </Sidebar.Menu>
5741
+ </Sidebar.GroupContent>
5742
+ </Sidebar.Group>
5743
+ </Sidebar.Content>
5744
+ </Sidebar>
5745
+ <DemoMain />
5746
+ </Sidebar.Provider>
5747
+ </DemoContainer>
5748
+ ```
5749
+
5750
+ ```tsx
5751
+ <DemoContainer>
5752
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5753
+ <Sidebar>
5754
+ <Sidebar.Header>
5755
+ <BrandLogo />
5756
+ </Sidebar.Header>
5757
+ <Sidebar.Content>
5758
+ <Sidebar.Group>
5759
+ <Sidebar.Menu>
5760
+ <Sidebar.MenuButton icon={HouseIcon} tooltip="Home" active>
5761
+ Home
5762
+ </Sidebar.MenuButton>
5763
+ <Sidebar.MenuButton icon={ChartBarIcon} tooltip="Analytics">
5764
+ Analytics
5765
+ </Sidebar.MenuButton>
5766
+ <Sidebar.MenuButton icon={CodeIcon} tooltip="Compute">
5767
+ Compute
5768
+ </Sidebar.MenuButton>
5769
+ <Sidebar.MenuButton icon={DatabaseIcon} tooltip="Storage">
5770
+ Storage
5771
+ </Sidebar.MenuButton>
5772
+ </Sidebar.Menu>
5773
+ </Sidebar.Group>
5774
+ </Sidebar.Content>
5775
+ <Sidebar.Footer>
5776
+ <Sidebar.Trigger />
5777
+ </Sidebar.Footer>
5778
+ </Sidebar>
5779
+ <DemoMain>
5780
+ <ToggleButton />
5781
+ <p className="text-sm">
5782
+ Click the button or the sidebar trigger to toggle
5783
+ </p>
5784
+ </DemoMain>
5785
+ </Sidebar.Provider>
5786
+ </DemoContainer>
5787
+ ```
5788
+
5789
+ ```tsx
5790
+ <DemoContainer>
5791
+ <Sidebar.Provider defaultOpen className="min-h-0! h-full">
5792
+ <Sidebar>
5793
+ <Sidebar.Header>
5794
+ <BrandLogo />
5795
+ </Sidebar.Header>
5796
+
5797
+ <Sidebar.Content>
5798
+ <div className="px-1 pb-2">
5799
+ <Sidebar.Input placeholder="Quick search..." shortcut="⌘K" />
5800
+ </div>
5801
+
5802
+ <Sidebar.Group>
5803
+ <Sidebar.GroupLabel>Overview</Sidebar.GroupLabel>
5804
+ <Sidebar.Menu>
5805
+ <Sidebar.MenuButton icon={HouseIcon} active>
5806
+ Home
5807
+ </Sidebar.MenuButton>
5808
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5809
+ Analytics
5810
+ </Sidebar.MenuButton>
5811
+ <Sidebar.MenuButton icon={GlobeIcon}>
5812
+ Domains
5813
+ </Sidebar.MenuButton>
5814
+ </Sidebar.Menu>
5815
+ </Sidebar.Group>
5816
+
5817
+ <Sidebar.Separator />
5818
+
5819
+ <Sidebar.Group>
5820
+ <Sidebar.GroupLabel>Build</Sidebar.GroupLabel>
5821
+ <Sidebar.Menu>
5822
+ <Sidebar.MenuItem>
5823
+ <Sidebar.Collapsible defaultOpen>
5824
+ <Sidebar.CollapsibleTrigger
5825
+ render={
5826
+ <Sidebar.MenuButton icon={CodeIcon}>
5827
+ Compute
5828
+ <Sidebar.MenuChevron />
5829
+ </Sidebar.MenuButton>
5830
+ }
5831
+ />
5832
+ <Sidebar.CollapsibleContent>
5833
+ <Sidebar.MenuSub>
5834
+ <Sidebar.MenuSubButton>Workers</Sidebar.MenuSubButton>
5835
+ <Sidebar.MenuSubButton>
5836
+ Durable Objects
5837
+ </Sidebar.MenuSubButton>
5838
+ <Sidebar.MenuSubButton>
5839
+ Containers
5840
+ <Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
5841
+ </Sidebar.MenuSubButton>
5842
+ </Sidebar.MenuSub>
5843
+ </Sidebar.CollapsibleContent>
5844
+ </Sidebar.Collapsible>
5845
+ </Sidebar.MenuItem>
5846
+ <Sidebar.MenuButton icon={DatabaseIcon}>
5847
+ Storage
5848
+ </Sidebar.MenuButton>
5849
+ </Sidebar.Menu>
5850
+ </Sidebar.Group>
5851
+
5852
+ <Sidebar.Group>
5853
+ <Sidebar.GroupLabel>Security</Sidebar.GroupLabel>
5854
+ <Sidebar.Menu>
5855
+ <Sidebar.MenuButton icon={ShieldCheckIcon}>
5856
+ Firewall
5857
+ </Sidebar.MenuButton>
5858
+ <Sidebar.MenuButton icon={LockIcon}>
5859
+ Access
5860
+ <Sidebar.MenuBadge>Beta</Sidebar.MenuBadge>
5861
+ </Sidebar.MenuButton>
5862
+ <Sidebar.MenuButton icon={BellIcon}>
5863
+ Notifications
5864
+ </Sidebar.MenuButton>
5865
+ </Sidebar.Menu>
5866
+ </Sidebar.Group>
5867
+ </Sidebar.Content>
5868
+
5869
+ <Sidebar.Footer>
5870
+ <Sidebar.MenuButton icon={GearIcon}>Settings</Sidebar.MenuButton>
5871
+ </Sidebar.Footer>
5872
+ </Sidebar>
5873
+ <DemoMain />
5874
+ </Sidebar.Provider>
5875
+ </DemoContainer>
5876
+ ```
5877
+
5878
+ ```tsx
5879
+ <DemoContainer>
5880
+ <Sidebar.Provider
5881
+ defaultOpen
5882
+ resizable
5883
+ defaultWidth={240}
5884
+ minWidth={180}
5885
+ maxWidth={400}
5886
+ className="min-h-0! h-full"
5887
+ >
5888
+ <Sidebar>
5889
+ <Sidebar.Header>
5890
+ <BrandLogo />
5891
+ </Sidebar.Header>
5892
+ <Sidebar.Content>
5893
+ <Sidebar.Group>
5894
+ <Sidebar.Menu>
5895
+ <Sidebar.MenuButton icon={HouseIcon} active>
5896
+ Home
5897
+ </Sidebar.MenuButton>
5898
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5899
+ Analytics
5900
+ </Sidebar.MenuButton>
5901
+ <Sidebar.MenuButton icon={GlobeIcon}>
5902
+ Domains
5903
+ </Sidebar.MenuButton>
5904
+ </Sidebar.Menu>
5905
+ </Sidebar.Group>
5906
+ </Sidebar.Content>
5907
+ <Sidebar.ResizeHandle />
5908
+ </Sidebar>
5909
+ <DemoMain>
5910
+ <p className="text-sm">Drag the sidebar edge to resize</p>
5911
+ </DemoMain>
5912
+ </Sidebar.Provider>
5913
+ </DemoContainer>
5914
+ ```
5915
+
5916
+ ```tsx
5917
+ <DemoContainer>
5918
+ <Sidebar.Provider defaultOpen side="right" className="min-h-0! h-full">
5919
+ <DemoMain>
5920
+ <p className="text-sm">Sidebar on the right</p>
5921
+ </DemoMain>
5922
+ <Sidebar>
5923
+ <Sidebar.Content>
5924
+ <Sidebar.Group>
5925
+ <Sidebar.GroupLabel>Details</Sidebar.GroupLabel>
5926
+ <Sidebar.Menu>
5927
+ <Sidebar.MenuButton icon={GearIcon} active>
5928
+ Properties
5929
+ </Sidebar.MenuButton>
5930
+ <Sidebar.MenuButton icon={ChartBarIcon}>
5931
+ Metrics
5932
+ </Sidebar.MenuButton>
5933
+ <Sidebar.MenuButton icon={BellIcon}>Alerts</Sidebar.MenuButton>
5934
+ </Sidebar.Menu>
5935
+ </Sidebar.Group>
5936
+ </Sidebar.Content>
5937
+ </Sidebar>
5938
+ </Sidebar.Provider>
5939
+ </DemoContainer>
5940
+ ```
5941
+
5942
+
2403
5943
  ---
2404
5944
 
2405
5945
  ### SignalFlareAILogo
@@ -2675,6 +6215,128 @@ SignalFlare AI logo component.
2675
6215
 
2676
6216
  `bg-sf-base`, `ring-sf-line`, `text-sf-default`
2677
6217
 
6218
+ **Examples:**
6219
+
6220
+ ```tsx
6221
+ <SignalFlareAILogo className="w-72" />
6222
+ ```
6223
+
6224
+ ```tsx
6225
+ <SignalFlareAILogo variant="glyph" className="w-16" />
6226
+ ```
6227
+
6228
+ ```tsx
6229
+ <div className="flex flex-wrap items-center gap-8">
6230
+ <SignalFlareAILogo className="w-32" color="brand" />
6231
+ <SignalFlareAILogo className="w-32" color="mono" />
6232
+ <div className="rounded-lg bg-white p-4">
6233
+ <SignalFlareAILogo className="w-32" color="black" />
6234
+ </div>
6235
+ <div className="rounded-lg bg-black p-4">
6236
+ <SignalFlareAILogo className="w-32" color="white" />
6237
+ </div>
6238
+ </div>
6239
+ ```
6240
+
6241
+ ```tsx
6242
+ <div className="flex flex-wrap items-center gap-8">
6243
+ <SignalFlareAILogo variant="glyph" className="w-10" color="brand" />
6244
+ <SignalFlareAILogo variant="glyph" className="w-10" color="mono" />
6245
+ <div className="rounded-lg bg-white p-4">
6246
+ <SignalFlareAILogo variant="glyph" className="w-10" color="black" />
6247
+ </div>
6248
+ <div className="rounded-lg bg-black p-4">
6249
+ <SignalFlareAILogo variant="glyph" className="w-10" color="white" />
6250
+ </div>
6251
+ </div>
6252
+ ```
6253
+
6254
+ ```tsx
6255
+ <div className="flex flex-wrap items-end gap-6">
6256
+ <SignalFlareAILogo className="w-24" />
6257
+ <SignalFlareAILogo className="w-36" />
6258
+ <SignalFlareAILogo className="w-52" />
6259
+ </div>
6260
+ ```
6261
+
6262
+ ```tsx
6263
+ <div className="flex items-center gap-4">
6264
+ <DropdownMenu>
6265
+ <DropdownMenu.Trigger>
6266
+ <button
6267
+ type="button"
6268
+ className="flex items-center gap-2 rounded-lg bg-[#4188ff] px-4 py-3 text-white transition-opacity hover:opacity-80"
6269
+ >
6270
+ <SignalFlareAILogo variant="glyph" color="white" className="w-6" />
6271
+ <span className="font-medium">Logo</span>
6272
+ </button>
6273
+ </DropdownMenu.Trigger>
6274
+ <DropdownMenu.Content>
6275
+ <DropdownMenu.Item
6276
+ icon={MapPinIcon}
6277
+ onSelect={() =>
6278
+ copyToClipboard(
6279
+ generateSignalFlareAILogoSvg({ variant: "glyph" }),
6280
+ "glyph"
6281
+ )
6282
+ }
6283
+ >
6284
+ {copied === "glyph" ? "Copied!" : "Copy icon as SVG"}
6285
+ </DropdownMenu.Item>
6286
+ <DropdownMenu.Item
6287
+ icon={CodeIcon}
6288
+ onSelect={() =>
6289
+ copyToClipboard(
6290
+ generateSignalFlareAILogoSvg({ variant: "full" }),
6291
+ "full"
6292
+ )
6293
+ }
6294
+ >
6295
+ {copied === "full" ? "Copied!" : "Copy full logo as SVG"}
6296
+ </DropdownMenu.Item>
6297
+ <DropdownMenu.Separator />
6298
+ <DropdownMenu.Item
6299
+ icon={ArrowSquareOutIcon}
6300
+ onSelect={() =>
6301
+ window.open("https://signalflare.ai", "_blank", "noopener")
6302
+ }
6303
+ >
6304
+ Visit SignalFlare AI
6305
+ </DropdownMenu.Item>
6306
+ </DropdownMenu.Content>
6307
+ </DropdownMenu>
6308
+
6309
+ <span className="text-sm text-sf-subtle">
6310
+ Click to open the brand assets menu
6311
+ </span>
6312
+ </div>
6313
+ ```
6314
+
6315
+ ```tsx
6316
+ <PoweredBySignalFlareAI />
6317
+ ```
6318
+
6319
+ ```tsx
6320
+ <div className="flex flex-wrap items-center gap-4">
6321
+ <PoweredBySignalFlareAI color="brand" />
6322
+ <PoweredBySignalFlareAI color="mono" />
6323
+ <PoweredBySignalFlareAI color="black" />
6324
+ <div className="rounded-lg bg-black p-3">
6325
+ <PoweredBySignalFlareAI color="white" />
6326
+ </div>
6327
+ </div>
6328
+ ```
6329
+
6330
+ ```tsx
6331
+ <footer className="flex w-full items-center justify-between rounded-lg border border-sf-line bg-sf-elevated px-6 py-4">
6332
+ <span className="text-sm text-sf-subtle">
6333
+ &copy; 2026 Your Company. All rights reserved.
6334
+ </span>
6335
+ <PoweredBySignalFlareAI />
6336
+ </footer>
6337
+ ```
6338
+
6339
+
2678
6340
  ---
2679
6341
 
2680
6342
  ### Sparkline
@@ -2694,11 +6356,27 @@ Sparkline — a tiny inline chart intended for embedding in cards, tables, or ro
2694
6356
  - `children`: ReactNode
2695
6357
  Child elements
2696
6358
 
6359
+ **Examples:**
6360
+
6361
+ ```tsx
6362
+ <Sparkline echarts={echarts} data={sample} isDarkMode={isDarkMode} />
6363
+ ```
6364
+
6365
+ ```tsx
6366
+ <Sparkline
6367
+ echarts={echarts}
6368
+ data={sample}
6369
+ variant="area"
6370
+ isDarkMode={isDarkMode}
6371
+ />
6372
+ ```
6373
+
6374
+
2697
6375
  ---
2698
6376
 
2699
6377
  ### StatCard
2700
6378
 
2701
- StatCard — compact KPI tile displaying a label, a primary value, and an optional delta + trend sparkline.
6379
+ 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)
2702
6380
 
2703
6381
  **Type:** component
2704
6382
 
@@ -2729,6 +6407,25 @@ StatCard — compact KPI tile displaying a label, a primary value, and an option
2729
6407
 
2730
6408
  `bg-sf-elevated`, `bg-sf-fill`, `text-sf-danger`, `text-sf-default`, `text-sf-strong`, `text-sf-subtle`, `text-sf-success`
2731
6409
 
6410
+ **Examples:**
6411
+
6412
+ ```tsx
6413
+ <StatCard
6414
+ label="Active users"
6415
+ value="12,384"
6416
+ delta={{ value: 0.12, label: "vs last week" }}
6417
+ />
6418
+ ```
6419
+
6420
+ ```tsx
6421
+ <StatCard size="sm" label="MRR" value="$128,420" hint="30-day avg" />
6422
+ ```
6423
+
6424
+ ```tsx
6425
+ <StatCard label="Signups" value="—" loading />
6426
+ ```
6427
+
6428
+
2732
6429
  ---
2733
6430
 
2734
6431
  ### Surface
@@ -2754,6 +6451,45 @@ Surface component
2754
6451
 
2755
6452
  `bg-sf-base`, `ring-sf-line`
2756
6453
 
6454
+ **Examples:**
6455
+
6456
+ ```tsx
6457
+ <Surface className="rounded-lg p-6">
6458
+ <Text size="lg" bold>
6459
+ Surface Component
6460
+ </Text>
6461
+ <div className="mt-2">
6462
+ <Text variant="secondary">
6463
+ A container with consistent elevation and border styling.
6464
+ </Text>
6465
+ </div>
6466
+ </Surface>
6467
+ ```
6468
+
6469
+ ```tsx
6470
+ <div className="flex flex-col gap-4">
6471
+ <Surface as="section" className="rounded-lg p-4">
6472
+ <Text bold>As section element</Text>
6473
+ </Surface>
6474
+ <Surface as="article" className="rounded-lg p-4">
6475
+ <Text bold>As article element</Text>
6476
+ </Surface>
6477
+ <Surface as="aside" className="rounded-lg p-4">
6478
+ <Text bold>As aside element</Text>
6479
+ </Surface>
6480
+ </div>
6481
+ ```
6482
+
6483
+ ```tsx
6484
+ <Surface className="rounded-lg p-6">
6485
+ <Text bold>Outer Surface</Text>
6486
+ <Surface className="mt-4 rounded-md bg-sf-elevated p-4">
6487
+ <Text variant="secondary">Nested Surface</Text>
6488
+ </Surface>
6489
+ </Surface>
6490
+ ```
6491
+
6492
+
2757
6493
  ---
2758
6494
 
2759
6495
  ### Switch
@@ -2813,7 +6549,6 @@ Item sub-component
2813
6549
  Group sub-component
2814
6550
 
2815
6551
  Props:
2816
-
2817
6552
  - `legend`: string (required)
2818
6553
  - `children`: ReactNode (required)
2819
6554
  - `error`: string
@@ -2822,11 +6557,23 @@ Props:
2822
6557
  - `controlFirst`: boolean
2823
6558
  - `className`: string
2824
6559
 
6560
+
6561
+ **Examples:**
6562
+
6563
+ ```tsx
6564
+ <Switch label="Switch" checked={checked} onCheckedChange={setChecked} />
6565
+ ```
6566
+
6567
+ ```tsx
6568
+ <Switch label="Disabled" checked={false} disabled />
6569
+ ```
6570
+
6571
+
2825
6572
  ---
2826
6573
 
2827
6574
  ### Table
2828
6575
 
2829
- Table — semantic HTML table with styled rows, cells, and selection support. Compound component: `Table` (Root), `.Header`, `.Head`, `.Body`, `.Row`, `.Cell`, `.Footer`, `.CheckCell`, `.CheckHead`, `.ResizeHandle`.
6576
+ Table — semantic HTML table with styled rows, cells, and selection support. Compound component: `Table` (Root), `.Header`, `.Head`, `.Body`, `.Row`, `.Cell`, `.Footer`, `.CheckCell`, `.CheckHead`, `.ResizeHandle`.
2830
6577
 
2831
6578
  **Type:** component
2832
6579
 
@@ -2891,6 +6638,236 @@ Footer sub-component
2891
6638
 
2892
6639
  ResizeHandle sub-component
2893
6640
 
6641
+
6642
+ **Examples:**
6643
+
6644
+ ```tsx
6645
+ <LayerCard>
6646
+ <LayerCard.Primary className="p-0">
6647
+ <Table>
6648
+ <Table.Header>
6649
+ <Table.Row>
6650
+ <Table.Head>Subject</Table.Head>
6651
+ <Table.Head>From</Table.Head>
6652
+ <Table.Head>Date</Table.Head>
6653
+ </Table.Row>
6654
+ </Table.Header>
6655
+ <Table.Body>
6656
+ {emailData.slice(0, 3).map((row) => (
6657
+ <Table.Row key={row.id}>
6658
+ <Table.Cell>{row.subject}</Table.Cell>
6659
+ <Table.Cell>{row.from}</Table.Cell>
6660
+ <Table.Cell>{row.date}</Table.Cell>
6661
+ </Table.Row>
6662
+ ))}
6663
+ </Table.Body>
6664
+ </Table>
6665
+ </LayerCard.Primary>
6666
+ </LayerCard>
6667
+ ```
6668
+
6669
+ ```tsx
6670
+ <LayerCard>
6671
+ <LayerCard.Primary className="p-0">
6672
+ <Table>
6673
+ <Table.Header>
6674
+ <Table.Row>
6675
+ <Table.CheckHead
6676
+ checked={selectedIds.size === rows.length}
6677
+ indeterminate={
6678
+ selectedIds.size > 0 && selectedIds.size < rows.length
6679
+ }
6680
+ onValueChange={toggleAll}
6681
+ aria-label="Select all rows"
6682
+ />
6683
+ <Table.Head>Subject</Table.Head>
6684
+ <Table.Head>From</Table.Head>
6685
+ <Table.Head>Date</Table.Head>
6686
+ </Table.Row>
6687
+ </Table.Header>
6688
+ <Table.Body>
6689
+ {rows.map((row) => (
6690
+ <Table.Row key={row.id}>
6691
+ <Table.CheckCell
6692
+ checked={selectedIds.has(row.id)}
6693
+ onValueChange={() => toggleRow(row.id)}
6694
+ aria-label={`Select ${row.subject}`}
6695
+ />
6696
+ <Table.Cell>{row.subject}</Table.Cell>
6697
+ <Table.Cell>{row.from}</Table.Cell>
6698
+ <Table.Cell>{row.date}</Table.Cell>
6699
+ </Table.Row>
6700
+ ))}
6701
+ </Table.Body>
6702
+ </Table>
6703
+ </LayerCard.Primary>
6704
+ </LayerCard>
6705
+ ```
6706
+
6707
+ ```tsx
6708
+ <LayerCard>
6709
+ <LayerCard.Primary className="p-0">
6710
+ <Table>
6711
+ <Table.Header>
6712
+ <Table.Row>
6713
+ <Table.CheckHead
6714
+ checked={selectedIds.size === rows.length}
6715
+ indeterminate={
6716
+ selectedIds.size > 0 && selectedIds.size < rows.length
6717
+ }
6718
+ onValueChange={toggleAll}
6719
+ aria-label="Select all rows"
6720
+ />
6721
+ <Table.Head>Subject</Table.Head>
6722
+ <Table.Head>From</Table.Head>
6723
+ <Table.Head>Date</Table.Head>
6724
+ </Table.Row>
6725
+ </Table.Header>
6726
+ <Table.Body>
6727
+ {rows.map((row) => (
6728
+ <Table.Row
6729
+ key={row.id}
6730
+ variant={selectedIds.has(row.id) ? "selected" : "default"}
6731
+ >
6732
+ <Table.CheckCell
6733
+ checked={selectedIds.has(row.id)}
6734
+ onValueChange={() => toggleRow(row.id)}
6735
+ aria-label={`Select ${row.subject}`}
6736
+ />
6737
+ <Table.Cell>{row.subject}</Table.Cell>
6738
+ <Table.Cell>{row.from}</Table.Cell>
6739
+ <Table.Cell>{row.date}</Table.Cell>
6740
+ </Table.Row>
6741
+ ))}
6742
+ </Table.Body>
6743
+ </Table>
6744
+ </LayerCard.Primary>
6745
+ </LayerCard>
6746
+ ```
6747
+
6748
+ ```tsx
6749
+ <LayerCard>
6750
+ <LayerCard.Primary className="p-0">
6751
+ <Table layout="fixed">
6752
+ <colgroup>
6753
+ <col />
6754
+ <col className="w-[150px]" />
6755
+ <col className="w-[150px]" />
6756
+ </colgroup>
6757
+ <Table.Header>
6758
+ <Table.Row>
6759
+ <Table.Head>Subject</Table.Head>
6760
+ <Table.Head>From</Table.Head>
6761
+ <Table.Head>Date</Table.Head>
6762
+ </Table.Row>
6763
+ </Table.Header>
6764
+ <Table.Body>
6765
+ {emailData.map((row) => (
6766
+ <Table.Row key={row.id}>
6767
+ <Table.Cell>{row.subject}</Table.Cell>
6768
+ <Table.Cell>{row.from}</Table.Cell>
6769
+ <Table.Cell>{row.date}</Table.Cell>
6770
+ </Table.Row>
6771
+ ))}
6772
+ </Table.Body>
6773
+ </Table>
6774
+ </LayerCard.Primary>
6775
+ </LayerCard>
6776
+ ```
6777
+
6778
+ ```tsx
6779
+ <LayerCard>
6780
+ <LayerCard.Primary className="w-full overflow-x-auto p-0">
6781
+ <Table layout="fixed">
6782
+ <colgroup>
6783
+ <col />{" "}
6784
+ {/* Checkbox column - width handled by Table.CheckHead/CheckCell */}
6785
+ <col />
6786
+ <col style={{ width: "150px" }} />
6787
+ <col style={{ width: "120px" }} />
6788
+ <col style={{ width: "50px" }} />
6789
+ </colgroup>
6790
+ <Table.Header>
6791
+ <Table.Row>
6792
+ <Table.CheckHead
6793
+ checked={selectedIds.size === emailData.length}
6794
+ indeterminate={
6795
+ selectedIds.size > 0 && selectedIds.size < emailData.length
6796
+ }
6797
+ onValueChange={toggleAll}
6798
+ aria-label="Select all rows"
6799
+ />
6800
+ <Table.Head>Subject</Table.Head>
6801
+ <Table.Head>From</Table.Head>
6802
+ <Table.Head>Date</Table.Head>
6803
+ <Table.Head />
6804
+ </Table.Row>
6805
+ </Table.Header>
6806
+ <Table.Body>
6807
+ {emailData.map((row) => (
6808
+ <Table.Row
6809
+ key={row.id}
6810
+ variant={selectedIds.has(row.id) ? "selected" : "default"}
6811
+ >
6812
+ <Table.CheckCell
6813
+ checked={selectedIds.has(row.id)}
6814
+ onValueChange={() => toggleRow(row.id)}
6815
+ aria-label={`Select ${row.subject}`}
6816
+ />
6817
+ <Table.Cell>
6818
+ <div className="flex items-center gap-2">
6819
+ <EnvelopeSimpleIcon size={16} />
6820
+ <span className="truncate">{row.subject}</span>
6821
+ {row.tags && (
6822
+ <div className="ml-2 inline-flex gap-1">
6823
+ {row.tags.map((tag) => (
6824
+ <Badge key={tag}>{tag}</Badge>
6825
+ ))}
6826
+ </div>
6827
+ )}
6828
+ </div>
6829
+ </Table.Cell>
6830
+ <Table.Cell>
6831
+ <span className="truncate">{row.from}</span>
6832
+ </Table.Cell>
6833
+ <Table.Cell>
6834
+ <span className="truncate">{row.date}</span>
6835
+ </Table.Cell>
6836
+ <Table.Cell className="text-right">
6837
+ <DropdownMenu>
6838
+ <DropdownMenu.Trigger
6839
+ render={
6840
+ <Button
6841
+ variant="ghost"
6842
+ size="sm"
6843
+ shape="square"
6844
+ aria-label="More options"
6845
+ >
6846
+ <DotsThreeIcon weight="bold" size={16} />
6847
+ </Button>
6848
+ }
6849
+ />
6850
+ <DropdownMenu.Content>
6851
+ <DropdownMenu.Item icon={EyeIcon}>View</DropdownMenu.Item>
6852
+ <DropdownMenu.Item icon={PencilSimpleIcon}>
6853
+ Edit
6854
+ </DropdownMenu.Item>
6855
+ <DropdownMenu.Separator />
6856
+ <DropdownMenu.Item icon={TrashIcon} variant="danger">
6857
+ Delete
6858
+ </DropdownMenu.Item>
6859
+ </DropdownMenu.Content>
6860
+ </DropdownMenu>
6861
+ </Table.Cell>
6862
+ </Table.Row>
6863
+ ))}
6864
+ </Table.Body>
6865
+ </Table>
6866
+ </LayerCard.Primary>
6867
+ </LayerCard>
6868
+ ```
6869
+
6870
+
2894
6871
  ---
2895
6872
 
2896
6873
  ### Tabs
@@ -2933,6 +6910,116 @@ Tab navigation component with segmented, underline, or pill style. Built on Base
2933
6910
 
2934
6911
  **Styling:**
2935
6912
 
6913
+
6914
+ **Examples:**
6915
+
6916
+ ```tsx
6917
+ <div className="flex flex-col gap-6">
6918
+ <div>
6919
+ <p className="mb-2 text-sm text-sf-subtle">Segmented (default)</p>
6920
+ <Tabs
6921
+ variant="segmented"
6922
+ tabs={[
6923
+ { label: "Tab 1", value: "tab1" },
6924
+ { label: "Tab 2", value: "tab2" },
6925
+ { label: "Tab 3", value: "tab3" },
6926
+ ]}
6927
+ selectedValue="tab1"
6928
+ />
6929
+ </div>
6930
+ <div>
6931
+ <p className="mb-2 text-sm text-sf-subtle">Underline</p>
6932
+ <Tabs
6933
+ variant="underline"
6934
+ tabs={[
6935
+ { label: "Tab 1", value: "tab1" },
6936
+ { label: "Tab 2", value: "tab2" },
6937
+ { label: "Tab 3", value: "tab3" },
6938
+ ]}
6939
+ selectedValue="tab1"
6940
+ />
6941
+ </div>
6942
+ <div>
6943
+ <p className="mb-2 text-sm text-sf-subtle">Pill</p>
6944
+ <Tabs
6945
+ variant="pill"
6946
+ tabs={[
6947
+ { label: "Tab 1", value: "tab1" },
6948
+ { label: "Tab 2", value: "tab2" },
6949
+ { label: "Tab 3", value: "tab3" },
6950
+ ]}
6951
+ selectedValue="tab1"
6952
+ />
6953
+ </div>
6954
+ </div>
6955
+ ```
6956
+
6957
+ ```tsx
6958
+ <Tabs
6959
+ variant="segmented"
6960
+ tabs={[
6961
+ { label: "Tab 1", value: "tab1" },
6962
+ { label: "Tab 2", value: "tab2" },
6963
+ { label: "Tab 3", value: "tab3" },
6964
+ ]}
6965
+ selectedValue="tab1"
6966
+ />
6967
+ ```
6968
+
6969
+ ```tsx
6970
+ <div className="space-y-4">
6971
+ <Tabs
6972
+ tabs={[
6973
+ { label: "Tab 1", value: "tab1" },
6974
+ { label: "Tab 2", value: "tab2" },
6975
+ { label: "Tab 3", value: "tab3" },
6976
+ ]}
6977
+ value={activeTab}
6978
+ onValueChange={setActiveTab}
6979
+ />
6980
+ <p className="text-sm text-sf-subtle">
6981
+ Active tab: <code className="text-sm">{activeTab}</code>
6982
+ </p>
6983
+ </div>
6984
+ ```
6985
+
6986
+ ```tsx
6987
+ <Tabs
6988
+ tabs={[
6989
+ { label: "Overview", value: "overview" },
6990
+ { label: "Analytics", value: "analytics" },
6991
+ { label: "Reports", value: "reports" },
6992
+ { label: "Notifications", value: "notifications" },
6993
+ { label: "Settings", value: "settings" },
6994
+ { label: "Billing", value: "billing" },
6995
+ ]}
6996
+ selectedValue="overview"
6997
+ />
6998
+ ```
6999
+
7000
+ ```tsx
7001
+ <Tabs
7002
+ tabs={[
7003
+ {
7004
+ label: "Regular Tab",
7005
+ value: "tab1",
7006
+ },
7007
+ {
7008
+ label: "Link Tab",
7009
+ render: (props) => <a {...props} href="#tab2" />,
7010
+ value: "tab2",
7011
+ },
7012
+ {
7013
+ label: "Another Link",
7014
+ render: (props) => <a {...props} href="#tab3" />,
7015
+ value: "tab3",
7016
+ },
7017
+ ]}
7018
+ selectedValue="tab1"
7019
+ />
7020
+ ```
7021
+
7022
+
2936
7023
  ---
2937
7024
 
2938
7025
  ### Text
@@ -2968,6 +7055,14 @@ Text component
2968
7055
  The HTML element type to render as (e.g. `"span"`, `"p"`, `"h1"`). Auto-selected based on variant if omitted.
2969
7056
  - `children`: ReactNode
2970
7057
  Text content.
7058
+ - `wrap`: MeasuredTextMode | boolean
7059
+ Text layout strategy using pretext-driven measurement.
7060
+ - `"natural"` — No measurement, normal browser wrapping (default for body).
7061
+ - `"balance"` — Even wrapping, smallest maxWidth without adding lines (default for headings).
7062
+ - `"shrink"` — Hug widest natural line (maxWidth = line width). Good for chat bubbles.
7063
+ - `"reserve"` — Reserve height based on line count. Good for streaming text.
7064
+ - `reserveLines`: number
7065
+ For `wrap="reserve"`: reserve this many lines of height. If omitted, measures current content to determine line count.
2971
7066
 
2972
7067
  **Colors (sf tokens used):**
2973
7068
 
@@ -2975,11 +7070,78 @@ Text component
2975
7070
 
2976
7071
  **Styling:**
2977
7072
 
7073
+
7074
+ **Examples:**
7075
+
7076
+ ```tsx
7077
+ <div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
7078
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7079
+ <Text variant="heading1">Heading 1</Text>
7080
+ <p className="font-mono text-xs text-sf-subtle">text-3xl (30px)</p>
7081
+ </div>
7082
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7083
+ <Text variant="heading2">Heading 2</Text>
7084
+ <p className="font-mono text-xs text-sf-subtle">text-2xl (24px)</p>
7085
+ </div>
7086
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7087
+ <Text variant="heading3">Heading 3</Text>
7088
+ <p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
7089
+ </div>
7090
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7091
+ <Text>Body</Text>
7092
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7093
+ </div>
7094
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7095
+ <Text bold>Body bold</Text>
7096
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7097
+ </div>
7098
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7099
+ <Text size="lg">Body lg</Text>
7100
+ <p className="font-mono text-xs text-sf-subtle">text-lg (16px)</p>
7101
+ </div>
7102
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7103
+ <Text size="sm">Body sm</Text>
7104
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7105
+ </div>
7106
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7107
+ <Text size="xs">Body xs</Text>
7108
+ <p className="font-mono text-xs text-sf-subtle">text-xs (12px)</p>
7109
+ </div>
7110
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7111
+ <Text variant="secondary">Body secondary</Text>
7112
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7113
+ </div>
7114
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7115
+ <Text variant="mono">Monospace</Text>
7116
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7117
+ </div>
7118
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7119
+ <Text variant="mono" size="lg">
7120
+ Monospace lg
7121
+ </Text>
7122
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7123
+ </div>
7124
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7125
+ <Text variant="mono-secondary">Monospace secondary</Text>
7126
+ <p className="font-mono text-xs text-sf-subtle">text-sm (13px)</p>
7127
+ </div>
7128
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7129
+ <Text variant="success">Success</Text>
7130
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7131
+ </div>
7132
+ <div className="flex flex-col justify-end gap-1 rounded-lg border border-sf-line bg-sf-base p-4">
7133
+ <Text variant="error">Error</Text>
7134
+ <p className="font-mono text-xs text-sf-subtle">text-base (14px)</p>
7135
+ </div>
7136
+ </div>
7137
+ ```
7138
+
7139
+
2978
7140
  ---
2979
7141
 
2980
7142
  ### TextRoll
2981
7143
 
2982
- Letter-by-letter roll animation. Each character flips on the X axis: the current letter rolls up and out, the new letter rolls in from below. Good for title changes (e.g. a streaming activity group swapping its current-step label) where the text content is short and the change should register visually. Wraps the string in an `aria-hidden` visual stack with a screen-reader-only copy of the full text so a11y tools always read the real content.
7144
+ Letter-by-letter roll animation. Each character flips on the X axis: the current letter rolls up and out, the new letter rolls in from below. Good for title changes (e.g. a streaming activity group swapping its current-step label) where the text content is short and the change should register visually. Wraps the string in an `aria-hidden` visual stack with a screen-reader-only copy of the full text so a11y tools always read the real content.
2983
7145
 
2984
7146
  **Type:** component
2985
7147
 
@@ -3008,7 +7170,7 @@ Letter-by-letter roll animation. Each character flips on the X axis: the current
3008
7170
 
3009
7171
  ### ThemeToggle
3010
7172
 
3011
- Theme toggle button. Cycles through light → dark → system (follows OS) modes. Reads from and writes to `localStorage` under the key `"theme"`. When set to `"system"` the key is removed so the OS preference takes over automatically. Applies the resolved mode to `document.documentElement.dataset.mode`.
7173
+ Theme toggle button. Cycles through light → dark → system (follows OS) modes. Reads from and writes to `localStorage` under the key `"theme"`. When set to `"system"` the key is removed so the OS preference takes over automatically. Applies the resolved mode to `document.documentElement.dataset.mode`.
3012
7174
 
3013
7175
  **Type:** component
3014
7176
 
@@ -3037,7 +7199,7 @@ Theme toggle button. Cycles through light → dark → system (follows OS) modes
3037
7199
 
3038
7200
  ### Toasty
3039
7201
 
3040
- Toasty — toast notification provider and viewport. Renders a `Toast.Provider` with a fixed-position viewport in the bottom-right corner. Toasts stack with smooth enter/exit animations, swipe-to-dismiss, and expand-on-hover. Built on `@base-ui/react/toast`.
7202
+ Toasty — toast notification provider and viewport. Renders a `Toast.Provider` with a fixed-position viewport in the bottom-right corner. Toasts stack with smooth enter/exit animations, swipe-to-dismiss, and expand-on-hover. Built on `@base-ui/react/toast`.
3041
7203
 
3042
7204
  **Type:** component
3043
7205
 
@@ -3062,6 +7224,7 @@ Toasty — toast notification provider and viewport. Renders a `Toast.Provider`
3062
7224
 
3063
7225
  **Styling:**
3064
7226
 
7227
+
3065
7228
  ---
3066
7229
 
3067
7230
  ### Tooltip
@@ -3092,6 +7255,34 @@ Accessible popup that shows additional information on hover/focus. Wrap your app
3092
7255
 
3093
7256
  `bg-sf-elevated`, `fill-sf-elevated`, `fill-sf-tip-shadow`, `fill-sf-tip-stroke`, `outline-sf-fill`, `text-sf-default`
3094
7257
 
7258
+ **Examples:**
7259
+
7260
+ ```tsx
7261
+ <TooltipProvider>
7262
+ <Tooltip content="Add new item">
7263
+ <Button shape="square" icon={PlusIcon} aria-label="Add new item" />
7264
+ </Tooltip>
7265
+ </TooltipProvider>
7266
+ ```
7267
+
7268
+ ```tsx
7269
+ <TooltipProvider>
7270
+ <div className="flex gap-2">
7271
+ <Tooltip content="Add">
7272
+ <Button shape="square" icon={PlusIcon} aria-label="Add" />
7273
+ </Tooltip>
7274
+ <Tooltip content="Change language">
7275
+ <Button
7276
+ shape="square"
7277
+ icon={TranslateIcon}
7278
+ aria-label="Change language"
7279
+ />
7280
+ </Tooltip>
7281
+ </div>
7282
+ </TooltipProvider>
7283
+ ```
7284
+
7285
+
3095
7286
  ---
3096
7287
 
3097
7288
  ### InputArea
@@ -3106,6 +7297,7 @@ Multi-line textarea input with Input variants and InputArea-specific dimensions
3106
7297
 
3107
7298
  **Props:**
3108
7299
 
7300
+
3109
7301
  **Styling:**
3110
7302
 
3111
7303
  - **Size Variants:**
@@ -3117,7 +7309,6 @@ Multi-line textarea input with Input variants and InputArea-specific dimensions
3117
7309
  ## Quick Reference
3118
7310
 
3119
7311
  **Components by Category:**
3120
-
3121
7312
  - **Other:** AiActions, AiAgentCard, AiApproval, AiCodeBlock, AiConversation, AiInfoBanner, AiMessage, AiMissionHeader, AiPartGroup, AiQuestion, AiReasoning, AiResponse, AiShimmer, AiStatusBadge, AiStreamingText, AiSubagent, AiSuggestions, AiTaskList, AiTimeline, AiToolCall, AiUsageBar, DataGrid, DatePicker, Filters, Label, Link, PromptInput, SensitiveInput, Sidebar, SignalFlareAILogo, Sparkline, StatCard, Table, TextRoll, ThemeToggle, AgentHarness, Commander, DashboardGrid, DeleteResource, Map, MetricsOverview
3122
7313
  - **Display:** Badge, Breadcrumbs, Code, Collapsible, Empty, LayerCard, Meter, Text
3123
7314
  - **Feedback:** Banner, Loader, Toasty