@signalflare-ai/ui 0.5.0 → 1.0.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 (316) hide show
  1. package/CHANGELOG.md +117 -1
  2. package/ai/USAGE.md +64 -0
  3. package/ai/component-registry.json +492 -618
  4. package/ai/component-registry.md +167 -85
  5. package/ai/schemas.ts +545 -102
  6. package/bin/sf.js +2 -3
  7. package/dist/.build-complete +1 -1
  8. package/dist/ai/schemas.d.ts +1659 -5532
  9. package/dist/ai/schemas.d.ts.map +1 -1
  10. package/dist/{ai-actions-DG1dhDMP.js → ai-actions-DSVeQn4e.js} +1 -1
  11. package/dist/{ai-actions-DG1dhDMP.js.map → ai-actions-DSVeQn4e.js.map} +1 -1
  12. package/dist/{ai-agent-card-BbtL4NII.js → ai-agent-card-BXHwhWAU.js} +1 -1
  13. package/dist/{ai-agent-card-BbtL4NII.js.map → ai-agent-card-BXHwhWAU.js.map} +1 -1
  14. package/dist/{ai-approval-Mb7-BY6i.js → ai-approval-aa0qvjFN.js} +1 -1
  15. package/dist/{ai-approval-Mb7-BY6i.js.map → ai-approval-aa0qvjFN.js.map} +1 -1
  16. package/dist/{ai-code-block-BI_z0UVR.js → ai-code-block-BgtIxtZZ.js} +1 -1
  17. package/dist/{ai-code-block-BI_z0UVR.js.map → ai-code-block-BgtIxtZZ.js.map} +1 -1
  18. package/dist/{ai-conversation-DYtExcrw.js → ai-conversation-CArP7C8K.js} +1 -1
  19. package/dist/{ai-conversation-DYtExcrw.js.map → ai-conversation-CArP7C8K.js.map} +1 -1
  20. package/dist/{ai-info-banner-BpzauUAY.js → ai-info-banner-uFxHHwBA.js} +1 -1
  21. package/dist/{ai-info-banner-BpzauUAY.js.map → ai-info-banner-uFxHHwBA.js.map} +1 -1
  22. package/dist/{ai-message-CV8SBoHM.js → ai-message-BjnFznXy.js} +1 -1
  23. package/dist/{ai-message-CV8SBoHM.js.map → ai-message-BjnFznXy.js.map} +1 -1
  24. package/dist/{ai-mission-header-ByYkJ6YP.js → ai-mission-header-08__gULL.js} +1 -1
  25. package/dist/{ai-mission-header-ByYkJ6YP.js.map → ai-mission-header-08__gULL.js.map} +1 -1
  26. package/dist/ai-part-group-DBtgTgAn.js +277 -0
  27. package/dist/ai-part-group-DBtgTgAn.js.map +1 -0
  28. package/dist/ai-prompt-input-Dy1LfxPk.js +1541 -0
  29. package/dist/ai-prompt-input-Dy1LfxPk.js.map +1 -0
  30. package/dist/{ai-question-Dp1g9k2o.js → ai-question-CHHoDJMg.js} +1 -1
  31. package/dist/{ai-question-Dp1g9k2o.js.map → ai-question-CHHoDJMg.js.map} +1 -1
  32. package/dist/{ai-reasoning-UAmNx_LD.js → ai-reasoning-CnL6ZSr5.js} +84 -5
  33. package/dist/ai-reasoning-CnL6ZSr5.js.map +1 -0
  34. package/dist/{ai-response-BWoVsNQG.js → ai-response-BEUg3xvd.js} +13 -16
  35. package/dist/ai-response-BEUg3xvd.js.map +1 -0
  36. package/dist/{ai-shimmer-BpOmfonu.js → ai-shimmer-By5_L05p.js} +1 -1
  37. package/dist/{ai-shimmer-BpOmfonu.js.map → ai-shimmer-By5_L05p.js.map} +1 -1
  38. package/dist/{ai-status-badge-WhbKVeqn.js → ai-status-badge-BGYGWYF6.js} +1 -1
  39. package/dist/{ai-status-badge-WhbKVeqn.js.map → ai-status-badge-BGYGWYF6.js.map} +1 -1
  40. package/dist/{ai-streaming-text-ClL7FwvD.js → ai-streaming-text-CMfoThV0.js} +1 -1
  41. package/dist/{ai-streaming-text-ClL7FwvD.js.map → ai-streaming-text-CMfoThV0.js.map} +1 -1
  42. package/dist/{ai-subagent-BruGN1UE.js → ai-subagent-DcPRqkAA.js} +1 -1
  43. package/dist/{ai-subagent-BruGN1UE.js.map → ai-subagent-DcPRqkAA.js.map} +1 -1
  44. package/dist/{ai-suggestion-CNsCZj5P.js → ai-suggestion-MgeCg5Ar.js} +1 -1
  45. package/dist/{ai-suggestion-CNsCZj5P.js.map → ai-suggestion-MgeCg5Ar.js.map} +1 -1
  46. package/dist/{ai-task-list-B9CpMDYN.js → ai-task-list-Da9zIm00.js} +9 -12
  47. package/dist/ai-task-list-Da9zIm00.js.map +1 -0
  48. package/dist/{ai-timeline-Bb5ntsr3.js → ai-timeline-Cwu045IR.js} +1 -1
  49. package/dist/ai-timeline-Cwu045IR.js.map +1 -0
  50. package/dist/{ai-tool-BGH8nQ_D.js → ai-tool-Cn1O4xjP.js} +168 -11
  51. package/dist/ai-tool-Cn1O4xjP.js.map +1 -0
  52. package/dist/{ai-usage-bar-BI-p-JBk.js → ai-usage-bar-DjS12DMp.js} +1 -1
  53. package/dist/{ai-usage-bar-BI-p-JBk.js.map → ai-usage-bar-DjS12DMp.js.map} +1 -1
  54. package/dist/catalog.js +3 -3
  55. package/dist/catalog.js.map +1 -1
  56. package/dist/{chart-Bes4MN3C.js → chart-BK3sVPnD.js} +442 -248
  57. package/dist/chart-BK3sVPnD.js.map +1 -0
  58. package/dist/{checkbox-CPX7lBaU.js → checkbox-DYhUmZNw.js} +4 -4
  59. package/dist/checkbox-DYhUmZNw.js.map +1 -0
  60. package/dist/{clipboard-text-92YeCybc.js → clipboard-text-ssybngLw.js} +2 -2
  61. package/dist/{clipboard-text-92YeCybc.js.map → clipboard-text-ssybngLw.js.map} +1 -1
  62. package/dist/{code-DE1Yy1Cu.js → code-Cx-QSoOT.js} +2 -2
  63. package/dist/{code-DE1Yy1Cu.js.map → code-Cx-QSoOT.js.map} +1 -1
  64. package/dist/{combobox-B0bLdsX8.js → combobox-C0iW6a0r.js} +2 -2
  65. package/dist/{combobox-B0bLdsX8.js.map → combobox-C0iW6a0r.js.map} +1 -1
  66. package/dist/command-line/cli.js +22 -27
  67. package/dist/{command-palette-CBTY8EiF.js → command-palette-DGzioeki.js} +2 -2
  68. package/dist/command-palette-DGzioeki.js.map +1 -0
  69. package/dist/components/ai-actions.js +1 -1
  70. package/dist/components/ai-agent-card.js +1 -1
  71. package/dist/components/ai-approval.js +1 -1
  72. package/dist/components/ai-code-block.js +1 -1
  73. package/dist/components/ai-conversation.js +1 -1
  74. package/dist/components/ai-info-banner.js +1 -1
  75. package/dist/components/ai-message.js +1 -1
  76. package/dist/components/ai-mission-header.js +1 -1
  77. package/dist/components/ai-part-group.js +3 -0
  78. package/dist/components/ai-prompt-input.js +2 -2
  79. package/dist/components/ai-question.js +1 -1
  80. package/dist/components/ai-reasoning.js +1 -1
  81. package/dist/components/ai-response.js +1 -1
  82. package/dist/components/ai-shimmer.js +1 -1
  83. package/dist/components/ai-status-badge.js +1 -1
  84. package/dist/components/ai-streaming-text.js +1 -1
  85. package/dist/components/ai-subagent.js +1 -1
  86. package/dist/components/ai-suggestion.js +1 -1
  87. package/dist/components/ai-task-list.js +1 -1
  88. package/dist/components/ai-timeline.js +1 -1
  89. package/dist/components/ai-tool.js +1 -1
  90. package/dist/components/ai-usage-bar.js +1 -1
  91. package/dist/components/chart.js +3 -2
  92. package/dist/components/checkbox.js +1 -1
  93. package/dist/components/clipboard-text.js +1 -1
  94. package/dist/components/code.js +1 -1
  95. package/dist/components/combobox.js +1 -1
  96. package/dist/components/command-palette.js +1 -1
  97. package/dist/components/data-grid.js +1 -1
  98. package/dist/components/date-picker.js +1 -1
  99. package/dist/components/dropdown.js +1 -1
  100. package/dist/components/filters.js +1 -1
  101. package/dist/components/input.js +2 -2
  102. package/dist/components/link.js +2 -2
  103. package/dist/components/link.js.map +1 -1
  104. package/dist/components/pagination.js +1 -1
  105. package/dist/components/radio.js +1 -1
  106. package/dist/components/select.js +1 -1
  107. package/dist/components/sensitive-input.js +1 -1
  108. package/dist/components/sidebar.js +1 -1
  109. package/dist/components/sparkline.js +3 -0
  110. package/dist/components/stat-card.js +3 -0
  111. package/dist/components/table.js +1 -1
  112. package/dist/components/text-roll.js +3 -0
  113. package/dist/components/theme-toggle.js +1 -1
  114. package/dist/components/use-agent-harness.js +1 -1
  115. package/dist/{data-grid-UJ9ja5cu.js → data-grid-CG76N_hK.js} +6 -6
  116. package/dist/data-grid-CG76N_hK.js.map +1 -0
  117. package/dist/{date-picker-ebekkC3R.js → date-picker-Dqg9L4xu.js} +2 -2
  118. package/dist/{date-picker-ebekkC3R.js.map → date-picker-Dqg9L4xu.js.map} +1 -1
  119. package/dist/{dist-BNlyONdD.js → dist-1-gcEL2L.js} +224 -135
  120. package/dist/dist-1-gcEL2L.js.map +1 -0
  121. package/dist/{dropdown-J5T4pHaR.js → dropdown-qnEYRFXZ.js} +2 -2
  122. package/dist/{dropdown-J5T4pHaR.js.map → dropdown-qnEYRFXZ.js.map} +1 -1
  123. package/dist/echart-DURZEyai.js +314 -0
  124. package/dist/echart-DURZEyai.js.map +1 -0
  125. package/dist/{filters-BdBogf7D.js → filters-Bw_U6ZTx.js} +5 -5
  126. package/dist/filters-Bw_U6ZTx.js.map +1 -0
  127. package/dist/flow-BRsYUCJa.js.map +1 -1
  128. package/dist/genui.js +2 -2
  129. package/dist/genui.js.map +1 -1
  130. package/dist/index.js +45 -42
  131. package/dist/index.js.map +1 -1
  132. package/dist/{input-BxQAnXki.js → input-DXYUjGgD.js} +2 -2
  133. package/dist/{input-BxQAnXki.js.map → input-DXYUjGgD.js.map} +1 -1
  134. package/dist/{input-Cn25I4o5.js → input-DddtBN-g.js} +2 -2
  135. package/dist/{input-Cn25I4o5.js.map → input-DddtBN-g.js.map} +1 -1
  136. package/dist/layer-card-BME0eljh.js.map +1 -1
  137. package/dist/{pagination-C_YqCy8l.js → pagination-BVqdlONY.js} +2 -2
  138. package/dist/{pagination-C_YqCy8l.js.map → pagination-BVqdlONY.js.map} +1 -1
  139. package/dist/primitives/otp-field.js +2 -0
  140. package/dist/primitives.js +1 -0
  141. package/dist/{radio-B7zg1wUI.js → radio-BNSwOt3B.js} +3 -3
  142. package/dist/radio-BNSwOt3B.js.map +1 -0
  143. package/dist/{select-9p721G00.js → select-1w2aebGQ.js} +2 -2
  144. package/dist/select-1w2aebGQ.js.map +1 -0
  145. package/dist/{sensitive-input-D5je2NLl.js → sensitive-input-82Cez3vj.js} +2 -2
  146. package/dist/{sensitive-input-D5je2NLl.js.map → sensitive-input-82Cez3vj.js.map} +1 -1
  147. package/dist/{sidebar-DOwBrq57.js → sidebar-CAsCmSpM.js} +3 -3
  148. package/dist/sidebar-CAsCmSpM.js.map +1 -0
  149. package/dist/sparkline-DdbeM4Ai.js +108 -0
  150. package/dist/sparkline-DdbeM4Ai.js.map +1 -0
  151. package/dist/src/blocks/agent-harness/agent-harness.d.ts +30 -9
  152. package/dist/src/blocks/agent-harness/agent-harness.d.ts.map +1 -1
  153. package/dist/src/blocks/agent-harness/agent-harness.stories.tsx +114 -0
  154. package/dist/src/blocks/agent-harness/agent-harness.tsx +144 -63
  155. package/dist/src/blocks/commander/commander.stories.tsx +31 -0
  156. package/dist/src/blocks/dashboard-grid/dashboard-grid.d.ts +48 -0
  157. package/dist/src/blocks/dashboard-grid/dashboard-grid.d.ts.map +1 -0
  158. package/dist/src/blocks/dashboard-grid/dashboard-grid.stories.tsx +19 -0
  159. package/dist/src/blocks/dashboard-grid/dashboard-grid.tsx +110 -0
  160. package/dist/src/blocks/dashboard-grid/index.d.ts +2 -0
  161. package/dist/src/blocks/dashboard-grid/index.d.ts.map +1 -0
  162. package/dist/src/blocks/delete-resource/delete-resource.stories.tsx +31 -0
  163. package/dist/src/blocks/map-block/map-block.stories.tsx +41 -0
  164. package/dist/src/blocks/metrics-overview/index.d.ts +2 -0
  165. package/dist/src/blocks/metrics-overview/index.d.ts.map +1 -0
  166. package/dist/src/blocks/metrics-overview/metrics-overview.d.ts +67 -0
  167. package/dist/src/blocks/metrics-overview/metrics-overview.d.ts.map +1 -0
  168. package/dist/src/blocks/metrics-overview/metrics-overview.stories.tsx +26 -0
  169. package/dist/src/blocks/metrics-overview/metrics-overview.tsx +139 -0
  170. package/dist/src/blocks/page-header/page-header.stories.tsx +56 -0
  171. package/dist/src/blocks/resource-list/resource-list.stories.tsx +31 -0
  172. package/dist/src/catalog/catalog.d.ts +1 -1
  173. package/dist/src/catalog/index.d.ts +1 -1
  174. package/dist/src/catalog/types.d.ts +1 -1
  175. package/dist/src/command-line/build-cli.d.ts +1 -1
  176. package/dist/src/command-line/cli.d.ts +1 -1
  177. package/dist/src/command-line/commands/add.d.ts +1 -1
  178. package/dist/src/command-line/commands/add.d.ts.map +1 -1
  179. package/dist/src/command-line/commands/ai.d.ts.map +1 -1
  180. package/dist/src/command-line/commands/blocks.d.ts +1 -1
  181. package/dist/src/command-line/commands/blocks.d.ts.map +1 -1
  182. package/dist/src/command-line/commands/doc.d.ts +1 -1
  183. package/dist/src/command-line/commands/doc.d.ts.map +1 -1
  184. package/dist/src/command-line/commands/ls.d.ts +1 -1
  185. package/dist/src/command-line/commands/ls.d.ts.map +1 -1
  186. package/dist/src/command-line/commands/migrate.d.ts +3 -3
  187. package/dist/src/command-line/commands/migrate.d.ts.map +1 -1
  188. package/dist/src/command-line/utils/config.d.ts +1 -1
  189. package/dist/src/command-line/utils/transformer.d.ts +1 -1
  190. package/dist/src/components/ai-part-group/ai-part-group.d.ts +134 -0
  191. package/dist/src/components/ai-part-group/ai-part-group.d.ts.map +1 -0
  192. package/dist/src/components/ai-part-group/index.d.ts +2 -0
  193. package/dist/src/components/ai-part-group/index.d.ts.map +1 -0
  194. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts +196 -7
  195. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
  196. package/dist/src/components/ai-prompt-input/controller.d.ts +41 -0
  197. package/dist/src/components/ai-prompt-input/controller.d.ts.map +1 -0
  198. package/dist/src/components/ai-prompt-input/index.d.ts +3 -1
  199. package/dist/src/components/ai-prompt-input/index.d.ts.map +1 -1
  200. package/dist/src/components/ai-prompt-input/types.d.ts +86 -0
  201. package/dist/src/components/ai-prompt-input/types.d.ts.map +1 -0
  202. package/dist/src/components/ai-reasoning/ai-reasoning.d.ts +17 -1
  203. package/dist/src/components/ai-reasoning/ai-reasoning.d.ts.map +1 -1
  204. package/dist/src/components/ai-response/ai-response.d.ts +1 -2
  205. package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
  206. package/dist/src/components/ai-task-list/ai-task-list.d.ts.map +1 -1
  207. package/dist/src/components/ai-tool/ai-tool.d.ts +17 -1
  208. package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
  209. package/dist/src/components/chart/area-chart.d.ts +69 -0
  210. package/dist/src/components/chart/area-chart.d.ts.map +1 -0
  211. package/dist/src/components/chart/bar-chart.d.ts +60 -0
  212. package/dist/src/components/chart/bar-chart.d.ts.map +1 -0
  213. package/dist/src/components/chart/color.d.ts +56 -0
  214. package/dist/src/components/chart/color.d.ts.map +1 -1
  215. package/dist/src/components/chart/echart.d.ts.map +1 -1
  216. package/dist/src/components/chart/index.d.ts +5 -0
  217. package/dist/src/components/chart/index.d.ts.map +1 -1
  218. package/dist/src/components/chart/pie-chart.d.ts +64 -0
  219. package/dist/src/components/chart/pie-chart.d.ts.map +1 -0
  220. package/dist/src/components/chart/scatter-chart.d.ts +57 -0
  221. package/dist/src/components/chart/scatter-chart.d.ts.map +1 -0
  222. package/dist/src/components/chart/stacked-bar-chart.d.ts +59 -0
  223. package/dist/src/components/chart/stacked-bar-chart.d.ts.map +1 -0
  224. package/dist/src/components/chart/timeseries-chart.d.ts.map +1 -1
  225. package/dist/src/components/code/code.d.ts +1 -1
  226. package/dist/src/components/command-palette/command-palette.d.ts +1 -1
  227. package/dist/src/components/data-grid/data-grid.d.ts.map +1 -1
  228. package/dist/src/components/data-grid/index.d.ts +1 -1
  229. package/dist/src/components/data-grid/index.d.ts.map +1 -1
  230. package/dist/src/components/data-grid/types.d.ts.map +1 -1
  231. package/dist/src/components/date-picker/date-picker.d.ts +2 -2
  232. package/dist/src/components/filters/filters.d.ts.map +1 -1
  233. package/dist/src/components/filters/helpers.d.ts.map +1 -1
  234. package/dist/src/components/filters/types.d.ts.map +1 -1
  235. package/dist/src/components/layer-card/layer-card.d.ts +1 -1
  236. package/dist/src/components/link/link.d.ts +2 -2
  237. package/dist/src/components/radio/radio.d.ts +1 -1
  238. package/dist/src/components/select/select.d.ts +1 -1
  239. package/dist/src/components/sidebar/sidebar.d.ts +2 -2
  240. package/dist/src/components/sparkline/index.d.ts +2 -0
  241. package/dist/src/components/sparkline/index.d.ts.map +1 -0
  242. package/dist/src/components/sparkline/sparkline.d.ts +52 -0
  243. package/dist/src/components/sparkline/sparkline.d.ts.map +1 -0
  244. package/dist/src/components/stat-card/index.d.ts +2 -0
  245. package/dist/src/components/{ai-loader → stat-card}/index.d.ts.map +1 -1
  246. package/dist/src/components/stat-card/stat-card.d.ts +80 -0
  247. package/dist/src/components/stat-card/stat-card.d.ts.map +1 -0
  248. package/dist/src/components/text-roll/index.d.ts +2 -0
  249. package/dist/src/components/text-roll/index.d.ts.map +1 -0
  250. package/dist/src/components/text-roll/text-roll.d.ts +49 -0
  251. package/dist/src/components/text-roll/text-roll.d.ts.map +1 -0
  252. package/dist/src/components/toast/toast.d.ts.map +1 -1
  253. package/dist/src/components/use-agent-harness/use-agent-harness.d.ts +2 -2
  254. package/dist/src/genui/genui.d.ts.map +1 -1
  255. package/dist/src/index.d.ts +5 -2
  256. package/dist/src/index.d.ts.map +1 -1
  257. package/dist/src/primitives/index.d.ts +1 -0
  258. package/dist/src/primitives/index.d.ts.map +1 -1
  259. package/dist/src/primitives/otp-field.d.ts +13 -0
  260. package/dist/src/primitives/otp-field.d.ts.map +1 -0
  261. package/dist/src/registry/index.d.ts +1 -1
  262. package/dist/src/registry/types.d.ts +1 -1
  263. package/dist/stat-card-CEZscNh8.js +103 -0
  264. package/dist/stat-card-CEZscNh8.js.map +1 -0
  265. package/dist/styles/sf-binding.css +20 -62
  266. package/dist/styles/sf-standalone.css +2 -2
  267. package/dist/styles/shadcn.css +120 -0
  268. package/dist/styles/theme-blue-tint.css +98 -0
  269. package/dist/styles/theme-fedramp.css +3 -12
  270. package/dist/styles/theme-minimal.css +26 -104
  271. package/dist/styles/theme-sf.css +96 -114
  272. package/dist/{table-CIMx0Oq0.js → table-Rv4JMy0B.js} +2 -2
  273. package/dist/{table-CIMx0Oq0.js.map → table-Rv4JMy0B.js.map} +1 -1
  274. package/dist/text-roll-BZ3I1umc.js +79 -0
  275. package/dist/text-roll-BZ3I1umc.js.map +1 -0
  276. package/dist/{theme-toggle-Dpgnoj_Q.js → theme-toggle-Bhu681D7.js} +1 -1
  277. package/dist/{theme-toggle-Dpgnoj_Q.js.map → theme-toggle-Bhu681D7.js.map} +1 -1
  278. package/dist/{use-agent-harness-DZzcn96L.js → use-agent-harness-BMyF8pTq.js} +5 -5
  279. package/dist/use-agent-harness-BMyF8pTq.js.map +1 -0
  280. package/package.json +48 -19
  281. package/scripts/component-registry/discovery.ts +2 -2
  282. package/scripts/component-registry/index.ts +1 -1
  283. package/scripts/component-registry/props-filter.ts +1 -1
  284. package/scripts/component-registry/utils.ts +5 -5
  285. package/scripts/component-registry/variant-parser.ts +124 -19
  286. package/scripts/convert-demos-to-stories.ts +253 -0
  287. package/scripts/css-build.ts +4 -3
  288. package/scripts/generate-primitives.ts +11 -3
  289. package/scripts/theme-generator/config.ts +339 -71
  290. package/scripts/theme-generator/generate-css.ts +17 -3
  291. package/scripts/theme-generator/index.ts +3 -3
  292. package/scripts/theme-generator/migrate.ts +1 -1
  293. package/dist/ai-loader-Cr3eQkNS.js +0 -134
  294. package/dist/ai-loader-Cr3eQkNS.js.map +0 -1
  295. package/dist/ai-prompt-input-Bo1YuJly.js +0 -769
  296. package/dist/ai-prompt-input-Bo1YuJly.js.map +0 -1
  297. package/dist/ai-reasoning-UAmNx_LD.js.map +0 -1
  298. package/dist/ai-response-BWoVsNQG.js.map +0 -1
  299. package/dist/ai-task-list-B9CpMDYN.js.map +0 -1
  300. package/dist/ai-timeline-Bb5ntsr3.js.map +0 -1
  301. package/dist/ai-tool-BGH8nQ_D.js.map +0 -1
  302. package/dist/chart-Bes4MN3C.js.map +0 -1
  303. package/dist/checkbox-CPX7lBaU.js.map +0 -1
  304. package/dist/command-palette-CBTY8EiF.js.map +0 -1
  305. package/dist/components/ai-loader.js +0 -3
  306. package/dist/data-grid-UJ9ja5cu.js.map +0 -1
  307. package/dist/dist-BNlyONdD.js.map +0 -1
  308. package/dist/filters-BdBogf7D.js.map +0 -1
  309. package/dist/radio-B7zg1wUI.js.map +0 -1
  310. package/dist/select-9p721G00.js.map +0 -1
  311. package/dist/sidebar-DOwBrq57.js.map +0 -1
  312. package/dist/src/components/ai-loader/ai-loader.d.ts +0 -44
  313. package/dist/src/components/ai-loader/ai-loader.d.ts.map +0 -1
  314. package/dist/src/components/ai-loader/index.d.ts +0 -2
  315. package/dist/styles/theme-navigator.css +0 -137
  316. package/dist/use-agent-harness-DZzcn96L.js.map +0 -1
@@ -0,0 +1,1541 @@
1
+ "use client";
2
+ import { t as cn } from "./cn-YROP2_ox.js";
3
+ import { t as Tooltip } from "./tooltip-Cb7QW-7H.js";
4
+ import { t as Button } from "./button-De0267YU.js";
5
+ import { t as InputGroup } from "./input-DddtBN-g.js";
6
+ import { Fragment, createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { ArrowUpIcon, ArrowsClockwiseIcon, CaretDownIcon, CheckIcon, FileIcon, FileTextIcon, ImageIcon, MicrophoneIcon, PaperclipIcon, PlusIcon, SpinnerGapIcon, SquareIcon, XIcon } from "@phosphor-icons/react";
9
+ import { Menu } from "@base-ui/react/menu";
10
+ import { Select } from "@base-ui/react/select";
11
+ import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector";
12
+ //#region ../../node_modules/.bun/@tanstack+store@0.11.0/node_modules/@tanstack/store/dist/alien.js
13
+ var ReactiveFlags = /* @__PURE__ */ function(ReactiveFlags) {
14
+ ReactiveFlags[ReactiveFlags["None"] = 0] = "None";
15
+ ReactiveFlags[ReactiveFlags["Mutable"] = 1] = "Mutable";
16
+ ReactiveFlags[ReactiveFlags["Watching"] = 2] = "Watching";
17
+ ReactiveFlags[ReactiveFlags["RecursedCheck"] = 4] = "RecursedCheck";
18
+ ReactiveFlags[ReactiveFlags["Recursed"] = 8] = "Recursed";
19
+ ReactiveFlags[ReactiveFlags["Dirty"] = 16] = "Dirty";
20
+ ReactiveFlags[ReactiveFlags["Pending"] = 32] = "Pending";
21
+ return ReactiveFlags;
22
+ }({});
23
+ /* @__NO_SIDE_EFFECTS__ */
24
+ function createReactiveSystem({ update, notify, unwatched }) {
25
+ return {
26
+ link,
27
+ unlink,
28
+ propagate,
29
+ checkDirty,
30
+ shallowPropagate
31
+ };
32
+ function link(dep, sub, version) {
33
+ const prevDep = sub.depsTail;
34
+ if (prevDep !== void 0 && prevDep.dep === dep) return;
35
+ const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps;
36
+ if (nextDep !== void 0 && nextDep.dep === dep) {
37
+ nextDep.version = version;
38
+ sub.depsTail = nextDep;
39
+ return;
40
+ }
41
+ const prevSub = dep.subsTail;
42
+ if (prevSub !== void 0 && prevSub.version === version && prevSub.sub === sub) return;
43
+ const newLink = sub.depsTail = dep.subsTail = {
44
+ version,
45
+ dep,
46
+ sub,
47
+ prevDep,
48
+ nextDep,
49
+ prevSub,
50
+ nextSub: void 0
51
+ };
52
+ if (nextDep !== void 0) nextDep.prevDep = newLink;
53
+ if (prevDep !== void 0) prevDep.nextDep = newLink;
54
+ else sub.deps = newLink;
55
+ if (prevSub !== void 0) prevSub.nextSub = newLink;
56
+ else dep.subs = newLink;
57
+ }
58
+ function unlink(link, sub = link.sub) {
59
+ const dep = link.dep;
60
+ const prevDep = link.prevDep;
61
+ const nextDep = link.nextDep;
62
+ const nextSub = link.nextSub;
63
+ const prevSub = link.prevSub;
64
+ if (nextDep !== void 0) nextDep.prevDep = prevDep;
65
+ else sub.depsTail = prevDep;
66
+ if (prevDep !== void 0) prevDep.nextDep = nextDep;
67
+ else sub.deps = nextDep;
68
+ if (nextSub !== void 0) nextSub.prevSub = prevSub;
69
+ else dep.subsTail = prevSub;
70
+ if (prevSub !== void 0) prevSub.nextSub = nextSub;
71
+ else if ((dep.subs = nextSub) === void 0) unwatched(dep);
72
+ return nextDep;
73
+ }
74
+ function propagate(link) {
75
+ let next = link.nextSub;
76
+ let stack;
77
+ top: do {
78
+ const sub = link.sub;
79
+ let flags = sub.flags;
80
+ if (!(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed | ReactiveFlags.Dirty | ReactiveFlags.Pending))) sub.flags = flags | ReactiveFlags.Pending;
81
+ else if (!(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed))) flags = ReactiveFlags.None;
82
+ else if (!(flags & ReactiveFlags.RecursedCheck)) sub.flags = flags & ~ReactiveFlags.Recursed | ReactiveFlags.Pending;
83
+ else if (!(flags & (ReactiveFlags.Dirty | ReactiveFlags.Pending)) && isValidLink(link, sub)) {
84
+ sub.flags = flags | (ReactiveFlags.Recursed | ReactiveFlags.Pending);
85
+ flags &= ReactiveFlags.Mutable;
86
+ } else flags = ReactiveFlags.None;
87
+ if (flags & ReactiveFlags.Watching) notify(sub);
88
+ if (flags & ReactiveFlags.Mutable) {
89
+ const subSubs = sub.subs;
90
+ if (subSubs !== void 0) {
91
+ const nextSub = (link = subSubs).nextSub;
92
+ if (nextSub !== void 0) {
93
+ stack = {
94
+ value: next,
95
+ prev: stack
96
+ };
97
+ next = nextSub;
98
+ }
99
+ continue;
100
+ }
101
+ }
102
+ if ((link = next) !== void 0) {
103
+ next = link.nextSub;
104
+ continue;
105
+ }
106
+ while (stack !== void 0) {
107
+ link = stack.value;
108
+ stack = stack.prev;
109
+ if (link !== void 0) {
110
+ next = link.nextSub;
111
+ continue top;
112
+ }
113
+ }
114
+ break;
115
+ } while (true);
116
+ }
117
+ function checkDirty(link, sub) {
118
+ let stack;
119
+ let checkDepth = 0;
120
+ let dirty = false;
121
+ top: do {
122
+ const dep = link.dep;
123
+ const flags = dep.flags;
124
+ if (sub.flags & ReactiveFlags.Dirty) dirty = true;
125
+ else if ((flags & (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) === (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) {
126
+ if (update(dep)) {
127
+ const subs = dep.subs;
128
+ if (subs.nextSub !== void 0) shallowPropagate(subs);
129
+ dirty = true;
130
+ }
131
+ } else if ((flags & (ReactiveFlags.Mutable | ReactiveFlags.Pending)) === (ReactiveFlags.Mutable | ReactiveFlags.Pending)) {
132
+ if (link.nextSub !== void 0 || link.prevSub !== void 0) stack = {
133
+ value: link,
134
+ prev: stack
135
+ };
136
+ link = dep.deps;
137
+ sub = dep;
138
+ ++checkDepth;
139
+ continue;
140
+ }
141
+ if (!dirty) {
142
+ const nextDep = link.nextDep;
143
+ if (nextDep !== void 0) {
144
+ link = nextDep;
145
+ continue;
146
+ }
147
+ }
148
+ while (checkDepth--) {
149
+ const firstSub = sub.subs;
150
+ const hasMultipleSubs = firstSub.nextSub !== void 0;
151
+ if (hasMultipleSubs) {
152
+ link = stack.value;
153
+ stack = stack.prev;
154
+ } else link = firstSub;
155
+ if (dirty) {
156
+ if (update(sub)) {
157
+ if (hasMultipleSubs) shallowPropagate(firstSub);
158
+ sub = link.sub;
159
+ continue;
160
+ }
161
+ dirty = false;
162
+ } else sub.flags &= ~ReactiveFlags.Pending;
163
+ sub = link.sub;
164
+ const nextDep = link.nextDep;
165
+ if (nextDep !== void 0) {
166
+ link = nextDep;
167
+ continue top;
168
+ }
169
+ }
170
+ return dirty;
171
+ } while (true);
172
+ }
173
+ function shallowPropagate(link) {
174
+ do {
175
+ const sub = link.sub;
176
+ const flags = sub.flags;
177
+ if ((flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) === ReactiveFlags.Pending) {
178
+ sub.flags = flags | ReactiveFlags.Dirty;
179
+ if ((flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) === ReactiveFlags.Watching) notify(sub);
180
+ }
181
+ } while ((link = link.nextSub) !== void 0);
182
+ }
183
+ function isValidLink(checkLink, sub) {
184
+ let link = sub.depsTail;
185
+ while (link !== void 0) {
186
+ if (link === checkLink) return true;
187
+ link = link.prevDep;
188
+ }
189
+ return false;
190
+ }
191
+ }
192
+ //#endregion
193
+ //#region ../../node_modules/.bun/@tanstack+store@0.11.0/node_modules/@tanstack/store/dist/atom.js
194
+ function toObserver(nextHandler, errorHandler, completionHandler) {
195
+ const isObserver = typeof nextHandler === "object";
196
+ const self = isObserver ? nextHandler : void 0;
197
+ return {
198
+ next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
199
+ error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
200
+ complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self)
201
+ };
202
+ }
203
+ var queuedEffects = [];
204
+ var cycle = 0;
205
+ var { link, unlink, propagate, checkDirty, shallowPropagate } = /* @__PURE__ */ createReactiveSystem({
206
+ update(atom) {
207
+ return atom._update();
208
+ },
209
+ notify(effect) {
210
+ queuedEffects[queuedEffectsLength++] = effect;
211
+ effect.flags &= ~ReactiveFlags.Watching;
212
+ },
213
+ unwatched(atom) {
214
+ if (atom.depsTail !== void 0) {
215
+ atom.depsTail = void 0;
216
+ atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
217
+ purgeDeps(atom);
218
+ }
219
+ }
220
+ });
221
+ var notifyIndex = 0;
222
+ var queuedEffectsLength = 0;
223
+ var activeSub;
224
+ var batchDepth = 0;
225
+ function purgeDeps(sub) {
226
+ const depsTail = sub.depsTail;
227
+ let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
228
+ while (dep !== void 0) dep = unlink(dep, sub);
229
+ }
230
+ function flush() {
231
+ if (batchDepth > 0) return;
232
+ while (notifyIndex < queuedEffectsLength) {
233
+ const effect = queuedEffects[notifyIndex];
234
+ queuedEffects[notifyIndex++] = void 0;
235
+ effect.notify();
236
+ }
237
+ notifyIndex = 0;
238
+ queuedEffectsLength = 0;
239
+ }
240
+ function createAtom(valueOrFn, options) {
241
+ const isComputed = typeof valueOrFn === "function";
242
+ const getter = valueOrFn;
243
+ const atom = {
244
+ _snapshot: isComputed ? void 0 : valueOrFn,
245
+ subs: void 0,
246
+ subsTail: void 0,
247
+ deps: void 0,
248
+ depsTail: void 0,
249
+ flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable,
250
+ get() {
251
+ if (activeSub !== void 0) link(atom, activeSub, cycle);
252
+ return atom._snapshot;
253
+ },
254
+ subscribe(observerOrFn) {
255
+ const obs = toObserver(observerOrFn);
256
+ const observed = { current: false };
257
+ const e = effect(() => {
258
+ atom.get();
259
+ if (!observed.current) observed.current = true;
260
+ else obs.next?.(atom._snapshot);
261
+ });
262
+ return { unsubscribe: () => {
263
+ e.stop();
264
+ } };
265
+ },
266
+ _update(getValue) {
267
+ const prevSub = activeSub;
268
+ const compare = options?.compare ?? Object.is;
269
+ if (isComputed) {
270
+ activeSub = atom;
271
+ ++cycle;
272
+ atom.depsTail = void 0;
273
+ } else if (getValue === void 0) return false;
274
+ if (isComputed) atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck;
275
+ try {
276
+ const oldValue = atom._snapshot;
277
+ const newValue = typeof getValue === "function" ? getValue(oldValue) : getValue === void 0 && isComputed ? getter(oldValue) : getValue;
278
+ if (oldValue === void 0 || !compare(oldValue, newValue)) {
279
+ atom._snapshot = newValue;
280
+ return true;
281
+ }
282
+ return false;
283
+ } finally {
284
+ activeSub = prevSub;
285
+ if (isComputed) atom.flags &= ~ReactiveFlags.RecursedCheck;
286
+ purgeDeps(atom);
287
+ }
288
+ }
289
+ };
290
+ if (isComputed) {
291
+ atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
292
+ atom.get = function() {
293
+ const flags = atom.flags;
294
+ if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(atom.deps, atom)) {
295
+ if (atom._update()) {
296
+ const subs = atom.subs;
297
+ if (subs !== void 0) shallowPropagate(subs);
298
+ }
299
+ } else if (flags & ReactiveFlags.Pending) atom.flags = flags & ~ReactiveFlags.Pending;
300
+ if (activeSub !== void 0) link(atom, activeSub, cycle);
301
+ return atom._snapshot;
302
+ };
303
+ } else atom.set = function(valueOrFn) {
304
+ if (atom._update(valueOrFn)) {
305
+ const subs = atom.subs;
306
+ if (subs !== void 0) {
307
+ propagate(subs);
308
+ shallowPropagate(subs);
309
+ flush();
310
+ }
311
+ }
312
+ };
313
+ return atom;
314
+ }
315
+ function effect(fn) {
316
+ const run = () => {
317
+ const prevSub = activeSub;
318
+ activeSub = effectObj;
319
+ ++cycle;
320
+ effectObj.depsTail = void 0;
321
+ effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck;
322
+ try {
323
+ return fn();
324
+ } finally {
325
+ activeSub = prevSub;
326
+ effectObj.flags &= ~ReactiveFlags.RecursedCheck;
327
+ purgeDeps(effectObj);
328
+ }
329
+ };
330
+ const effectObj = {
331
+ deps: void 0,
332
+ depsTail: void 0,
333
+ subs: void 0,
334
+ subsTail: void 0,
335
+ flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,
336
+ notify() {
337
+ const flags = this.flags;
338
+ if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(this.deps, this)) run();
339
+ else this.flags = ReactiveFlags.Watching;
340
+ },
341
+ stop() {
342
+ this.flags = ReactiveFlags.None;
343
+ this.depsTail = void 0;
344
+ purgeDeps(this);
345
+ }
346
+ };
347
+ run();
348
+ return effectObj;
349
+ }
350
+ //#endregion
351
+ //#region ../../node_modules/.bun/@tanstack+store@0.11.0/node_modules/@tanstack/store/dist/store.js
352
+ var Store = class {
353
+ constructor(valueOrFn, actionsFactory) {
354
+ this.atom = createAtom(valueOrFn);
355
+ this.get = this.get.bind(this);
356
+ this.setState = this.setState.bind(this);
357
+ this.subscribe = this.subscribe.bind(this);
358
+ if (actionsFactory) this.actions = actionsFactory(this);
359
+ }
360
+ setState(updater) {
361
+ this.atom.set(updater);
362
+ }
363
+ get state() {
364
+ return this.atom.get();
365
+ }
366
+ get() {
367
+ return this.state;
368
+ }
369
+ subscribe(observerOrFn) {
370
+ return this.atom.subscribe(toObserver(observerOrFn));
371
+ }
372
+ };
373
+ //#endregion
374
+ //#region ../../node_modules/.bun/@tanstack+react-store@0.11.0+21ccd8898788a04d/node_modules/@tanstack/react-store/dist/useSelector.js
375
+ function defaultCompare(a, b) {
376
+ return a === b;
377
+ }
378
+ /**
379
+ * Selects a slice of state from an atom or store and subscribes the component
380
+ * to that selection.
381
+ *
382
+ * This is the primary React read hook for TanStack Store. It works with any
383
+ * source that exposes `get()` and `subscribe()`, including atoms, readonly
384
+ * atoms, stores, and readonly stores.
385
+ *
386
+ * Omit the selector to subscribe to the whole value.
387
+ *
388
+ * @example
389
+ * ```tsx
390
+ * const count = useSelector(counterStore, (state) => state.count)
391
+ * ```
392
+ *
393
+ * @example
394
+ * ```tsx
395
+ * const value = useSelector(countAtom)
396
+ * ```
397
+ */
398
+ function useSelector(source, selector = (s) => s, options) {
399
+ const compare = options?.compare ?? defaultCompare;
400
+ const subscribe = useCallback((handleStoreChange) => {
401
+ const { unsubscribe } = source.subscribe(handleStoreChange);
402
+ return unsubscribe;
403
+ }, [source]);
404
+ const getSnapshot = useCallback(() => source.get(), [source]);
405
+ return useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, selector, compare);
406
+ }
407
+ //#endregion
408
+ //#region ../../node_modules/.bun/@tanstack+react-store@0.11.0+21ccd8898788a04d/node_modules/@tanstack/react-store/dist/useStore.js
409
+ /**
410
+ * Deprecated alias for {@link useSelector}.
411
+ *
412
+ * @example
413
+ * ```tsx
414
+ * const count = useStore(counterStore, (state) => state.count)
415
+ * ```
416
+ *
417
+ * @deprecated Use `useSelector` instead.
418
+ */
419
+ var useStore = (source, selector = (s) => s, compare) => useSelector(source, selector, { compare });
420
+ //#endregion
421
+ //#region src/components/ai-prompt-input/controller.ts
422
+ /**
423
+ * PromptInputController — the single source of truth for a prompt input tree.
424
+ *
425
+ * Built on @tanstack/store for per-slice subscriptions (sub-components
426
+ * re-render only when the fields they read change). The controller exposes
427
+ * two stores:
428
+ *
429
+ * - `request` : outbound state (text, files, mode, model, …extensions). The
430
+ * user edits these; `submit()` ships them to `onSubmit`.
431
+ * - `display` : inbound state (sendStatus, tasks, pendingQuestion, pendingPlan,
432
+ * usage). The harness writes these in; sub-components read them.
433
+ *
434
+ * Consumers never touch the stores directly. They use:
435
+ *
436
+ * const mode = useRequestField('mode'); // read
437
+ * const setMode = useSetRequestField('mode'); // write
438
+ * const status = useDisplayField('sendStatus'); // read
439
+ *
440
+ * Or, for advanced use, subscribe to the whole store with
441
+ * `useStore(controller.request)`.
442
+ */
443
+ var DEFAULT_REQUEST = {
444
+ text: "",
445
+ files: []
446
+ };
447
+ var DEFAULT_DISPLAY = { sendStatus: "idle" };
448
+ function createPromptInputRequestController(options = {}) {
449
+ const request = new Store({
450
+ ...DEFAULT_REQUEST,
451
+ ...options.initialRequest
452
+ });
453
+ const display = new Store({
454
+ ...DEFAULT_DISPLAY,
455
+ ...options.initialDisplay
456
+ });
457
+ return {
458
+ request,
459
+ display,
460
+ setRequestField(key, value) {
461
+ request.setState((prev) => ({
462
+ ...prev,
463
+ [key]: value
464
+ }));
465
+ },
466
+ setDisplayField(key, value) {
467
+ display.setState((prev) => ({
468
+ ...prev,
469
+ [key]: value
470
+ }));
471
+ },
472
+ addAttachments(files) {
473
+ request.setState((prev) => ({
474
+ ...prev,
475
+ files: [...prev.files, ...files]
476
+ }));
477
+ },
478
+ removeAttachment(id) {
479
+ request.setState((prev) => {
480
+ const removed = prev.files.find((f) => f.id === id);
481
+ if (removed?.url.startsWith("blob:")) URL.revokeObjectURL(removed.url);
482
+ return {
483
+ ...prev,
484
+ files: prev.files.filter((f) => f.id !== id)
485
+ };
486
+ });
487
+ },
488
+ clearAttachments() {
489
+ request.setState((prev) => {
490
+ for (const f of prev.files) if (f.url.startsWith("blob:")) URL.revokeObjectURL(f.url);
491
+ return {
492
+ ...prev,
493
+ files: []
494
+ };
495
+ });
496
+ },
497
+ resetRequest() {
498
+ request.setState((prev) => {
499
+ for (const f of prev.files) if (f.url.startsWith("blob:")) URL.revokeObjectURL(f.url);
500
+ return {
501
+ ...prev,
502
+ text: "",
503
+ files: []
504
+ };
505
+ });
506
+ },
507
+ snapshot() {
508
+ return request.state;
509
+ }
510
+ };
511
+ }
512
+ var PromptInputRequestControllerContext = createContext(null);
513
+ var PromptInputRequestControllerProvider = PromptInputRequestControllerContext.Provider;
514
+ function usePromptInputRequestController() {
515
+ const ctx = useContext(PromptInputRequestControllerContext);
516
+ if (!ctx) throw new Error("usePromptInputRequestController must be used inside <PromptInput> or <PromptInputRequestProvider>");
517
+ return ctx;
518
+ }
519
+ /** Optional variant — returns null if no controller is in context. */
520
+ function useOptionalPromptInputRequestController() {
521
+ return useContext(PromptInputRequestControllerContext);
522
+ }
523
+ /**
524
+ * Subscribe to one field of the request context. Component re-renders only
525
+ * when that field changes.
526
+ */
527
+ function useRequestField(key) {
528
+ return useStore(usePromptInputRequestController().request, (state) => state[key]);
529
+ }
530
+ /** Returns a stable setter for one field of the request context. */
531
+ function useSetRequestField(key) {
532
+ const ctrl = usePromptInputRequestController();
533
+ return useMemo(() => (value) => {
534
+ ctrl.setRequestField(key, value);
535
+ }, [ctrl, key]);
536
+ }
537
+ /**
538
+ * Subscribe to one field of the display context. Component re-renders only
539
+ * when that field changes.
540
+ */
541
+ function useDisplayField(key) {
542
+ return useStore(usePromptInputRequestController().display, (state) => state[key]);
543
+ }
544
+ //#endregion
545
+ //#region src/components/ai-prompt-input/ai-prompt-input.tsx
546
+ var FALLBACK_REQUEST_STORE = new Store({});
547
+ var SF_AI_PROMPT_INPUT_VARIANTS = { status: {
548
+ idle: {
549
+ classes: "",
550
+ description: "Ready to accept input"
551
+ },
552
+ submitted: {
553
+ classes: "",
554
+ description: "Waiting for response (shows spinner)"
555
+ },
556
+ streaming: {
557
+ classes: "",
558
+ description: "Streaming response (shows stop)"
559
+ },
560
+ error: {
561
+ classes: "",
562
+ description: "Error state (shows X)"
563
+ }
564
+ } };
565
+ var SF_AI_PROMPT_INPUT_DEFAULT_VARIANTS = { status: "idle" };
566
+ var PromptInputContext = createContext(null);
567
+ var ProviderAttachmentsContext = createContext(null);
568
+ var usePromptInputController = () => {
569
+ const ctx = useContext(PromptInputContext);
570
+ if (!ctx) throw new Error("Wrap your component inside <PromptInputProvider> to use usePromptInputController().");
571
+ return ctx;
572
+ };
573
+ var useOptionalPromptInputController = () => useContext(PromptInputContext);
574
+ var useProviderAttachments = () => {
575
+ const ctx = useContext(ProviderAttachmentsContext);
576
+ if (!ctx) throw new Error("Wrap your component inside <PromptInputProvider> to use useProviderAttachments().");
577
+ return ctx;
578
+ };
579
+ var useOptionalProviderAttachments = () => useContext(ProviderAttachmentsContext);
580
+ /**
581
+ * Optional global provider that lifts PromptInput state outside of PromptInput.
582
+ * If you don't use it, PromptInput stays fully self-managed.
583
+ *
584
+ * @example
585
+ * ```tsx
586
+ * <PromptInputProvider>
587
+ * <PromptInput onSubmit={handleSubmit}>...</PromptInput>
588
+ * </PromptInputProvider>
589
+ * ```
590
+ */
591
+ function PromptInputProvider({ initialInput = "", children }) {
592
+ const [textInput, setTextInput] = useState(initialInput);
593
+ const clearInput = useCallback(() => setTextInput(""), []);
594
+ const [attachmentItems, setAttachmentItems] = useState([]);
595
+ const fileInputRef = useRef(null);
596
+ const openRef = useRef(() => {});
597
+ const add = useCallback((files) => {
598
+ const incoming = Array.from(files);
599
+ if (incoming.length === 0) return;
600
+ setAttachmentItems((prev) => prev.concat(incoming.map((file) => ({
601
+ id: `${Date.now()}-${Math.random()}`,
602
+ url: URL.createObjectURL(file),
603
+ mediaType: file.type,
604
+ filename: file.name
605
+ }))));
606
+ }, []);
607
+ const remove = useCallback((id) => {
608
+ setAttachmentItems((prev) => {
609
+ const found = prev.find((f) => f.id === id);
610
+ if (found?.url) URL.revokeObjectURL(found.url);
611
+ return prev.filter((f) => f.id !== id);
612
+ });
613
+ }, []);
614
+ const clear = useCallback(() => {
615
+ setAttachmentItems((prev) => {
616
+ for (const f of prev) if (f.url) URL.revokeObjectURL(f.url);
617
+ return [];
618
+ });
619
+ }, []);
620
+ const openFileDialog = useCallback(() => {
621
+ openRef.current?.();
622
+ }, []);
623
+ const attachments = useMemo(() => ({
624
+ files: attachmentItems,
625
+ add,
626
+ remove,
627
+ clear,
628
+ openFileDialog,
629
+ fileInputRef
630
+ }), [
631
+ attachmentItems,
632
+ add,
633
+ remove,
634
+ clear,
635
+ openFileDialog
636
+ ]);
637
+ const __registerFileInput = useCallback((ref, open) => {
638
+ fileInputRef.current = ref.current;
639
+ openRef.current = open;
640
+ }, []);
641
+ const controller = useMemo(() => ({
642
+ textInput: {
643
+ value: textInput,
644
+ setInput: setTextInput,
645
+ clear: clearInput
646
+ },
647
+ attachments,
648
+ __registerFileInput
649
+ }), [
650
+ textInput,
651
+ clearInput,
652
+ attachments,
653
+ __registerFileInput
654
+ ]);
655
+ return /* @__PURE__ */ jsx(PromptInputContext.Provider, {
656
+ value: controller,
657
+ children: /* @__PURE__ */ jsx(ProviderAttachmentsContext.Provider, {
658
+ value: attachments,
659
+ children
660
+ })
661
+ });
662
+ }
663
+ var LocalAttachmentsContext = createContext(null);
664
+ var usePromptInputAttachments = () => {
665
+ const provider = useOptionalProviderAttachments();
666
+ const local = useContext(LocalAttachmentsContext);
667
+ const context = provider ?? local;
668
+ if (!context) throw new Error("usePromptInputAttachments must be used within a PromptInput or PromptInputProvider");
669
+ return context;
670
+ };
671
+ /** Convert a blob URL to a base64 data URL for serialization. */
672
+ async function convertBlobToDataUrl(url) {
673
+ const blob = await (await fetch(url)).blob();
674
+ return new Promise((resolve, reject) => {
675
+ const reader = new FileReader();
676
+ reader.addEventListener("loadend", () => resolve(reader.result));
677
+ reader.addEventListener("error", () => reject(/* @__PURE__ */ new Error("FileReader error")));
678
+ reader.readAsDataURL(blob);
679
+ });
680
+ }
681
+ function makeAttachmentId() {
682
+ return `${Date.now()}-${Math.random()}`;
683
+ }
684
+ /**
685
+ * Prompt input form. Can be self-managed or controlled via `PromptInputProvider`.
686
+ *
687
+ * @example
688
+ * ```tsx
689
+ * <PromptInput onSubmit={({ text, files }) => send(text, files)}>
690
+ * <PromptInputAttachments>{(f) => <PromptInputAttachment data={f} />}</PromptInputAttachments>
691
+ * <PromptInputTextarea placeholder="Ask anything…" />
692
+ * <PromptInputToolbar>
693
+ * <PromptInputTools>
694
+ * <PromptInputAttachButton />
695
+ * </PromptInputTools>
696
+ * <PromptInputSubmit />
697
+ * </PromptInputToolbar>
698
+ * </PromptInput>
699
+ * ```
700
+ */
701
+ var PromptInput = ({ className, accept, multiple, globalDrop, maxFiles, maxFileSize, onError, onSubmit, children, backLayer, backLayerTitle = "Context", backLayerOpen, onBackLayerOpenChange, autoOpenBackLayerWhen, ...props }) => {
702
+ const hasBackLayer = backLayer !== void 0;
703
+ const controller = useOptionalPromptInputController();
704
+ const usingProvider = !!controller;
705
+ const inputRef = useRef(null);
706
+ const anchorRef = useRef(null);
707
+ const formRef = useRef(null);
708
+ useEffect(() => {
709
+ const root = anchorRef.current?.closest("form");
710
+ if (root instanceof HTMLFormElement) formRef.current = root;
711
+ }, []);
712
+ useEffect(() => {
713
+ if (autoOpenBackLayerWhen) onBackLayerOpenChange?.(true);
714
+ }, [autoOpenBackLayerWhen, onBackLayerOpenChange]);
715
+ const [items, setItems] = useState([]);
716
+ const files = usingProvider ? controller.attachments.files : items;
717
+ const openFileDialogLocal = useCallback(() => {
718
+ inputRef.current?.click();
719
+ }, []);
720
+ const matchesAccept = useCallback((f) => {
721
+ if (!accept || accept.trim() === "") return true;
722
+ if (accept.includes("image/*")) return f.type.startsWith("image/");
723
+ return true;
724
+ }, [accept]);
725
+ const addLocal = useCallback((fileList) => {
726
+ const incoming = Array.from(fileList);
727
+ const accepted = incoming.filter((f) => matchesAccept(f));
728
+ if (incoming.length && accepted.length === 0) {
729
+ onError?.({
730
+ code: "accept",
731
+ message: "No files match the accepted types."
732
+ });
733
+ return;
734
+ }
735
+ const withinSize = (f) => maxFileSize ? f.size <= maxFileSize : true;
736
+ const sized = accepted.filter(withinSize);
737
+ if (accepted.length > 0 && sized.length === 0) {
738
+ onError?.({
739
+ code: "max_file_size",
740
+ message: "All files exceed the maximum size."
741
+ });
742
+ return;
743
+ }
744
+ setItems((prev) => {
745
+ const capacity = typeof maxFiles === "number" ? Math.max(0, maxFiles - prev.length) : void 0;
746
+ const capped = typeof capacity === "number" ? sized.slice(0, capacity) : sized;
747
+ if (typeof capacity === "number" && sized.length > capacity) onError?.({
748
+ code: "max_files",
749
+ message: "Too many files. Some were not added."
750
+ });
751
+ const next = capped.map((file) => ({
752
+ id: makeAttachmentId(),
753
+ url: URL.createObjectURL(file),
754
+ mediaType: file.type,
755
+ filename: file.name
756
+ }));
757
+ return prev.concat(next);
758
+ });
759
+ }, [
760
+ matchesAccept,
761
+ maxFiles,
762
+ maxFileSize,
763
+ onError
764
+ ]);
765
+ const add = usingProvider ? (f) => controller.attachments.add(f) : addLocal;
766
+ const remove = usingProvider ? (id) => controller.attachments.remove(id) : (id) => setItems((prev) => {
767
+ const found = prev.find((f) => f.id === id);
768
+ if (found?.url) URL.revokeObjectURL(found.url);
769
+ return prev.filter((f) => f.id !== id);
770
+ });
771
+ const clear = usingProvider ? () => controller.attachments.clear() : () => setItems((prev) => {
772
+ for (const f of prev) if (f.url) URL.revokeObjectURL(f.url);
773
+ return [];
774
+ });
775
+ const openFileDialog = usingProvider ? () => controller.attachments.openFileDialog() : openFileDialogLocal;
776
+ useEffect(() => {
777
+ if (!usingProvider) return;
778
+ controller.__registerFileInput(inputRef, () => inputRef.current?.click());
779
+ }, [usingProvider, controller]);
780
+ useEffect(() => {
781
+ const form = formRef.current;
782
+ if (!form) return;
783
+ const onDragOver = (e) => {
784
+ if (e.dataTransfer?.types?.includes("Files")) e.preventDefault();
785
+ };
786
+ const onDrop = (e) => {
787
+ if (e.dataTransfer?.types?.includes("Files")) e.preventDefault();
788
+ if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) add(e.dataTransfer.files);
789
+ };
790
+ form.addEventListener("dragover", onDragOver);
791
+ form.addEventListener("drop", onDrop);
792
+ return () => {
793
+ form.removeEventListener("dragover", onDragOver);
794
+ form.removeEventListener("drop", onDrop);
795
+ };
796
+ }, [add]);
797
+ useEffect(() => {
798
+ if (!globalDrop) return;
799
+ const onDragOver = (e) => {
800
+ if (e.dataTransfer?.types?.includes("Files")) e.preventDefault();
801
+ };
802
+ const onDrop = (e) => {
803
+ if (e.dataTransfer?.types?.includes("Files")) e.preventDefault();
804
+ if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) add(e.dataTransfer.files);
805
+ };
806
+ document.addEventListener("dragover", onDragOver);
807
+ document.addEventListener("drop", onDrop);
808
+ return () => {
809
+ document.removeEventListener("dragover", onDragOver);
810
+ document.removeEventListener("drop", onDrop);
811
+ };
812
+ }, [add, globalDrop]);
813
+ useEffect(() => {
814
+ return () => {
815
+ if (!usingProvider) {
816
+ for (const f of files) if (f.url) URL.revokeObjectURL(f.url);
817
+ }
818
+ };
819
+ }, [usingProvider, files]);
820
+ const handleFileInputChange = (event) => {
821
+ if (event.currentTarget.files) add(event.currentTarget.files);
822
+ };
823
+ const ctx = useMemo(() => ({
824
+ files,
825
+ add,
826
+ remove,
827
+ clear,
828
+ openFileDialog,
829
+ fileInputRef: inputRef
830
+ }), [
831
+ files,
832
+ add,
833
+ remove,
834
+ clear,
835
+ openFileDialog
836
+ ]);
837
+ const handleSubmit = (event) => {
838
+ event.preventDefault();
839
+ const form = event.currentTarget;
840
+ const text = usingProvider ? controller.textInput.value : new FormData(form).get("message") || "";
841
+ if (!usingProvider) form.reset();
842
+ const doSubmit = async () => {
843
+ const convertedFiles = await Promise.all(files.map(async (item) => {
844
+ if (item.url.startsWith("blob:")) return {
845
+ ...item,
846
+ url: await convertBlobToDataUrl(item.url)
847
+ };
848
+ return item;
849
+ }));
850
+ try {
851
+ await onSubmit({
852
+ text,
853
+ files: convertedFiles
854
+ }, event);
855
+ clear();
856
+ if (usingProvider) controller.textInput.clear();
857
+ } catch {}
858
+ };
859
+ doSubmit().catch(() => {});
860
+ };
861
+ const isBackLayerOpen = backLayerOpen ?? false;
862
+ const inputShell = hasBackLayer ? /* @__PURE__ */ jsxs("div", {
863
+ className: "flex w-full flex-col rounded-xl bg-sf-elevated ring ring-sf-line/50",
864
+ children: [
865
+ /* @__PURE__ */ jsxs("button", {
866
+ "aria-expanded": isBackLayerOpen,
867
+ "aria-label": isBackLayerOpen ? "Collapse context" : "Expand context",
868
+ className: "flex w-full items-center justify-between gap-2 px-3 py-2 text-left",
869
+ onClick: () => onBackLayerOpenChange?.(!isBackLayerOpen),
870
+ type: "button",
871
+ children: [/* @__PURE__ */ jsx("span", {
872
+ className: "text-sm font-medium text-sf-subtle uppercase tracking-wide select-none",
873
+ children: backLayerTitle
874
+ }), /* @__PURE__ */ jsx(CaretDownIcon, { className: cn("size-3.5 text-sf-subtle transition-transform duration-200", isBackLayerOpen && "rotate-180") })]
875
+ }),
876
+ /* @__PURE__ */ jsx(PromptInputBackLayerPanel, {
877
+ open: isBackLayerOpen,
878
+ children: backLayer
879
+ }),
880
+ /* @__PURE__ */ jsx("div", {
881
+ className: "flex flex-col overflow-hidden rounded-xl bg-sf-base ring ring-sf-line/50 focus-within:ring-sf-ring",
882
+ children
883
+ })
884
+ ]
885
+ }) : /* @__PURE__ */ jsx(InputGroup, { children });
886
+ const inner = /* @__PURE__ */ jsxs(Fragment$1, { children: [
887
+ /* @__PURE__ */ jsx("span", {
888
+ "aria-hidden": "true",
889
+ className: "hidden",
890
+ ref: anchorRef
891
+ }),
892
+ /* @__PURE__ */ jsx("input", {
893
+ accept,
894
+ "aria-label": "Upload files",
895
+ className: "hidden",
896
+ multiple,
897
+ onChange: handleFileInputChange,
898
+ ref: inputRef,
899
+ type: "file"
900
+ }),
901
+ /* @__PURE__ */ jsx("form", {
902
+ className: cn("w-full", className),
903
+ onSubmit: handleSubmit,
904
+ ...props,
905
+ children: inputShell
906
+ })
907
+ ] });
908
+ return usingProvider ? inner : /* @__PURE__ */ jsx(LocalAttachmentsContext.Provider, {
909
+ value: ctx,
910
+ children: inner
911
+ });
912
+ };
913
+ var PromptInputBody = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
914
+ className: cn("contents", className),
915
+ ...props
916
+ });
917
+ function PromptInputBackLayerPanel({ open, children }) {
918
+ const isOpen = open ?? false;
919
+ return /* @__PURE__ */ jsx("div", {
920
+ "aria-hidden": !isOpen,
921
+ className: "grid",
922
+ style: {
923
+ gridTemplateRows: isOpen ? "1fr" : "0fr",
924
+ opacity: isOpen ? 1 : 0,
925
+ transition: "grid-template-rows 200ms ease-out, opacity 200ms ease-out"
926
+ },
927
+ children: /* @__PURE__ */ jsx("div", {
928
+ className: "min-h-0 overflow-hidden",
929
+ children
930
+ })
931
+ });
932
+ }
933
+ /**
934
+ * Container for back-layer content (HITL approvals, task lists, agent status,
935
+ * etc.). Pass instances of this as the `backLayer` prop on `PromptInput`.
936
+ *
937
+ * @example
938
+ * ```tsx
939
+ * <PromptInput
940
+ * onSubmit={handleSubmit}
941
+ * backLayer={<PromptInputBackLayer>...</PromptInputBackLayer>}
942
+ * backLayerOpen={open}
943
+ * onBackLayerOpenChange={setOpen}
944
+ * >
945
+ * <PromptInputTextarea />
946
+ * <PromptInputToolbar>
947
+ * <PromptInputTools />
948
+ * <PromptInputSubmit />
949
+ * </PromptInputToolbar>
950
+ * </PromptInput>
951
+ * ```
952
+ */
953
+ function PromptInputBackLayer({ children, className }) {
954
+ return /* @__PURE__ */ jsx("div", {
955
+ className: cn("flex flex-col gap-2 px-3 py-2.5 text-sm text-sf-default", className),
956
+ children
957
+ });
958
+ }
959
+ var handleTextareaKeyDown = (e) => {
960
+ if (e.key === "Enter") {
961
+ if (e.nativeEvent.isComposing) return;
962
+ if (e.shiftKey) return;
963
+ e.preventDefault();
964
+ e.currentTarget.form?.requestSubmit();
965
+ }
966
+ };
967
+ /**
968
+ * Auto-resizing textarea for the prompt. Submits on Enter (Shift+Enter for newline).
969
+ * Pastes files into attachments.
970
+ */
971
+ var PromptInputTextarea = ({ onChange, className, placeholder = "What would you like to know?", ...props }) => {
972
+ const controller = useOptionalPromptInputController();
973
+ const attachments = usePromptInputAttachments();
974
+ const handlePaste = (event) => {
975
+ const items = event.clipboardData?.items;
976
+ if (!items) return;
977
+ const pastedFiles = [];
978
+ for (const item of items) if (item.kind === "file") {
979
+ const file = item.getAsFile();
980
+ if (file) pastedFiles.push(file);
981
+ }
982
+ if (pastedFiles.length > 0) {
983
+ event.preventDefault();
984
+ attachments.add(pastedFiles);
985
+ }
986
+ };
987
+ const controlledProps = controller ? {
988
+ value: controller.textInput.value,
989
+ onChange: (e) => {
990
+ controller.textInput.setInput(e.currentTarget.value);
991
+ onChange?.(e);
992
+ }
993
+ } : { onChange };
994
+ return /* @__PURE__ */ jsx("textarea", {
995
+ className: cn("field-sizing-content max-h-48 min-h-16 w-full resize-none border-0 bg-transparent px-3 py-2 text-sm text-sf-default outline-none placeholder:text-sf-inactive", className),
996
+ name: "message",
997
+ onKeyDown: handleTextareaKeyDown,
998
+ onPaste: handlePaste,
999
+ placeholder,
1000
+ rows: 1,
1001
+ ...props,
1002
+ ...controlledProps
1003
+ });
1004
+ };
1005
+ var PromptInputToolbar = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
1006
+ className: cn("flex min-w-0 items-center justify-between gap-1 px-2 py-1.5", className),
1007
+ ...props
1008
+ });
1009
+ var PromptInputTools = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
1010
+ className: cn("flex min-w-0 items-center gap-1", className),
1011
+ ...props
1012
+ });
1013
+ var PromptInputButton = ({ variant = "ghost", size = "sm", className, ...props }) => /* @__PURE__ */ jsx(Button, {
1014
+ className: cn("text-sf-subtle hover:text-sf-default", className),
1015
+ size,
1016
+ type: "button",
1017
+ variant,
1018
+ ...props
1019
+ });
1020
+ /**
1021
+ * Submit button. Icon changes based on `status`:
1022
+ * - `idle` → send arrow
1023
+ * - `submitted` → spinner
1024
+ * - `streaming` → stop square
1025
+ * - `error` → X
1026
+ */
1027
+ var PromptInputSubmit = ({ className, variant = "primary", size = "sm", status = "idle", children, ...props }) => {
1028
+ let Icon;
1029
+ if (status === "submitted") Icon = /* @__PURE__ */ jsx(SpinnerGapIcon, { className: "size-4 animate-spin" });
1030
+ else if (status === "streaming") Icon = /* @__PURE__ */ jsx(SquareIcon, { className: "size-4" });
1031
+ else if (status === "error") Icon = /* @__PURE__ */ jsx(XIcon, { className: "size-4" });
1032
+ else Icon = /* @__PURE__ */ jsx(ArrowUpIcon, { className: "size-4" });
1033
+ return /* @__PURE__ */ jsx(Button, {
1034
+ "aria-label": "Submit",
1035
+ className: cn(className),
1036
+ size,
1037
+ type: "submit",
1038
+ variant,
1039
+ ...props,
1040
+ children: children ?? Icon
1041
+ });
1042
+ };
1043
+ var DropdownMenu = Menu;
1044
+ var PromptInputActionMenu = (props) => /* @__PURE__ */ jsx(DropdownMenu.Root, { ...props });
1045
+ var PromptInputActionMenuTrigger = ({ className, children, "aria-label": ariaLabel = "More actions", ...props }) => /* @__PURE__ */ jsx(DropdownMenu.Trigger, { render: /* @__PURE__ */ jsx(Button, {
1046
+ "aria-label": ariaLabel,
1047
+ className: cn("text-sf-subtle hover:text-sf-default", className),
1048
+ size: "sm",
1049
+ type: "button",
1050
+ variant: "ghost",
1051
+ ...props,
1052
+ children: children ?? /* @__PURE__ */ jsx(PlusIcon, { className: "size-4" })
1053
+ }) });
1054
+ var PromptInputActionMenuContent = ({ className, children, ...props }) => /* @__PURE__ */ jsx(DropdownMenu.Positioner, {
1055
+ className: "z-50",
1056
+ side: "top",
1057
+ align: "start",
1058
+ ...props,
1059
+ children: /* @__PURE__ */ jsx(DropdownMenu.Popup, {
1060
+ className: cn("min-w-[160px] rounded-lg bg-sf-elevated p-1 shadow-md", "data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 transition-opacity duration-100", className),
1061
+ children
1062
+ })
1063
+ });
1064
+ var PromptInputActionMenuItem = ({ className, ...props }) => /* @__PURE__ */ jsx(DropdownMenu.Item, {
1065
+ className: cn("flex cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm text-sf-default outline-none", "data-highlighted:bg-sf-tint", className),
1066
+ ...props
1067
+ });
1068
+ var PromptInputActionAddAttachments = ({ label = "Add photos or files", ...props }) => {
1069
+ const attachments = usePromptInputAttachments();
1070
+ const handleSelect = useCallback(() => {
1071
+ attachments.openFileDialog();
1072
+ }, [attachments]);
1073
+ return /* @__PURE__ */ jsxs(PromptInputActionMenuItem, {
1074
+ ...props,
1075
+ onSelect: handleSelect,
1076
+ children: [/* @__PURE__ */ jsx(ImageIcon, { className: "size-4" }), label]
1077
+ });
1078
+ };
1079
+ var PromptInputModeSelector = ({ options, value: valueProp, onChange: onChangeProp, "aria-label": ariaLabel = "Select mode", className }) => {
1080
+ const controller = useOptionalPromptInputRequestController();
1081
+ const ctxMode = useStore(controller?.request ?? FALLBACK_REQUEST_STORE, (s) => s.mode);
1082
+ if (options.length === 0) return null;
1083
+ const isControlled = valueProp !== void 0 || onChangeProp !== void 0;
1084
+ const value = isControlled ? valueProp : ctxMode;
1085
+ const handleSelect = (next) => {
1086
+ if (onChangeProp) {
1087
+ onChangeProp(next);
1088
+ return;
1089
+ }
1090
+ if (!isControlled && controller) controller.setRequestField("mode", next);
1091
+ };
1092
+ return /* @__PURE__ */ jsx("div", {
1093
+ className: cn("flex items-center gap-0.5 rounded-md bg-sf-tint p-0.5", className),
1094
+ role: "group",
1095
+ "aria-label": ariaLabel,
1096
+ children: options.map((opt) => {
1097
+ const isSelected = opt.value === value;
1098
+ return /* @__PURE__ */ jsxs("button", {
1099
+ "aria-pressed": isSelected,
1100
+ disabled: opt.disabled,
1101
+ className: cn("flex cursor-pointer items-center gap-1 rounded-[4px] px-2 py-0.5 text-[11px] font-medium transition-colors", "disabled:cursor-not-allowed disabled:opacity-50", isSelected ? "bg-sf-elevated text-sf-default shadow-sm" : "text-sf-subtle hover:text-sf-default"),
1102
+ onClick: () => handleSelect(opt.value),
1103
+ title: opt.description,
1104
+ type: "button",
1105
+ children: [opt.icon, opt.label]
1106
+ }, opt.value);
1107
+ })
1108
+ });
1109
+ };
1110
+ /**
1111
+ * Compact Select primitive sized for the PromptInput toolbar.
1112
+ *
1113
+ * - 24px-tall trigger with `text-[11px]` label and truncating value
1114
+ * - Matching compact popup with the same text scale
1115
+ *
1116
+ * Build toolbar-specific selectors (mode, model, voice, tone, ...) by
1117
+ * wrapping this and wiring `value`/`onChange` to your state source.
1118
+ */
1119
+ var PromptInputCompactSelect = ({ options, value, onChange, placeholder = "Select", "aria-label": ariaLabel = "Select", maxWidth = 160, className }) => {
1120
+ if (options.length === 0) return null;
1121
+ const selected = options.find((o) => o.value === value);
1122
+ const triggerMaxWidth = typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth;
1123
+ return /* @__PURE__ */ jsxs(Select.Root, {
1124
+ value: value ?? "",
1125
+ onValueChange: (v) => {
1126
+ if (typeof v === "string") onChange?.(v);
1127
+ },
1128
+ children: [/* @__PURE__ */ jsxs(Select.Trigger, {
1129
+ "aria-label": ariaLabel,
1130
+ style: { maxWidth: triggerMaxWidth },
1131
+ className: cn("flex h-6 min-w-0 shrink cursor-pointer items-center gap-1 rounded-[4px] px-2 text-[11px] leading-none font-medium text-sf-subtle transition-colors", "hover:text-sf-default focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-sf-ring", className),
1132
+ children: [/* @__PURE__ */ jsx(Select.Value, {
1133
+ className: "min-w-0 truncate",
1134
+ children: selected ? selected.label ?? selected.value : placeholder
1135
+ }), /* @__PURE__ */ jsx(Select.Icon, {
1136
+ className: "flex shrink-0 items-center",
1137
+ children: /* @__PURE__ */ jsx(CaretDownIcon, { className: "size-3" })
1138
+ })]
1139
+ }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
1140
+ sideOffset: 6,
1141
+ children: /* @__PURE__ */ jsx(Select.Popup, {
1142
+ className: cn("overflow-hidden rounded-lg bg-sf-control p-1 text-[11px] text-sf-default shadow-lg ring ring-sf-line", "min-w-[calc(var(--anchor-width)+3px)]"),
1143
+ children: options.map((opt) => /* @__PURE__ */ jsxs(Select.Item, {
1144
+ value: opt.value,
1145
+ disabled: opt.disabled,
1146
+ className: cn("flex cursor-pointer items-center justify-between gap-2 rounded px-2 py-1 text-[11px] leading-tight outline-none", "data-[highlighted]:bg-sf-tint data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"),
1147
+ children: [/* @__PURE__ */ jsx(Select.ItemText, { children: opt.label ?? opt.value }), /* @__PURE__ */ jsx(Select.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3" }) })]
1148
+ }, opt.value))
1149
+ })
1150
+ }) })]
1151
+ });
1152
+ };
1153
+ function getModelLabel(option) {
1154
+ if (option.label) return option.label;
1155
+ return option.value.split("/").pop() ?? option.value;
1156
+ }
1157
+ /**
1158
+ * Compact model selector for the PromptInput toolbar.
1159
+ *
1160
+ * - Controlled: pass `value` + `onChange`.
1161
+ * - Controller-bound: omit both and wrap in `PromptInputRequestControllerProvider`
1162
+ * — the selector reads/writes `requestContext.model` automatically.
1163
+ */
1164
+ var PromptInputModelSelect = ({ options, value: valueProp, onChange: onChangeProp, "aria-label": ariaLabel = "Select model", className }) => {
1165
+ const controller = useOptionalPromptInputRequestController();
1166
+ const ctxModel = useStore(controller?.request ?? FALLBACK_REQUEST_STORE, (s) => s.model);
1167
+ const isControlled = valueProp !== void 0 || onChangeProp !== void 0;
1168
+ const value = isControlled ? valueProp : ctxModel;
1169
+ const handleChange = (next) => {
1170
+ if (onChangeProp) {
1171
+ onChangeProp(next);
1172
+ return;
1173
+ }
1174
+ if (!isControlled && controller) controller.setRequestField("model", next);
1175
+ };
1176
+ return /* @__PURE__ */ jsx(PromptInputCompactSelect, {
1177
+ options: options.map((o) => ({
1178
+ value: o.value,
1179
+ label: getModelLabel(o),
1180
+ disabled: o.disabled
1181
+ })),
1182
+ value,
1183
+ onChange: handleChange,
1184
+ placeholder: "Select model",
1185
+ "aria-label": ariaLabel,
1186
+ className
1187
+ });
1188
+ };
1189
+ /**
1190
+ * Compact mode selector for the PromptInput toolbar — matches
1191
+ * `PromptInputModelSelect` visually. For a segmented button-group look
1192
+ * (multi-mode headers, empty states), use `PromptInputModeSelector` instead.
1193
+ *
1194
+ * - Controlled: pass `value` + `onChange`.
1195
+ * - Controller-bound: omit both and wrap in `PromptInputRequestControllerProvider`
1196
+ * — the selector reads/writes `requestContext.mode` automatically.
1197
+ */
1198
+ var PromptInputModeSelect = ({ options, value: valueProp, onChange: onChangeProp, "aria-label": ariaLabel = "Select mode", className }) => {
1199
+ const controller = useOptionalPromptInputRequestController();
1200
+ const ctxMode = useStore(controller?.request ?? FALLBACK_REQUEST_STORE, (s) => s.mode);
1201
+ const isControlled = valueProp !== void 0 || onChangeProp !== void 0;
1202
+ const value = isControlled ? valueProp : ctxMode;
1203
+ const handleChange = (next) => {
1204
+ if (onChangeProp) {
1205
+ onChangeProp(next);
1206
+ return;
1207
+ }
1208
+ if (!isControlled && controller) controller.setRequestField("mode", next);
1209
+ };
1210
+ return /* @__PURE__ */ jsx(PromptInputCompactSelect, {
1211
+ options: options.map((o) => ({
1212
+ value: o.value,
1213
+ label: o.label ?? o.value,
1214
+ disabled: o.disabled
1215
+ })),
1216
+ value,
1217
+ onChange: handleChange,
1218
+ placeholder: "Select mode",
1219
+ "aria-label": ariaLabel,
1220
+ className
1221
+ });
1222
+ };
1223
+ /**
1224
+ * Single compact button that cycles through `options` on click.
1225
+ *
1226
+ * - Click / Enter / Space → next option (wraps at end)
1227
+ * - Shift+Click / Shift+Enter → previous option
1228
+ * - Skips `disabled` options
1229
+ *
1230
+ * Useful for binary or 2–3 option toggles where a dropdown feels heavy.
1231
+ */
1232
+ var PromptInputCompactCycle = ({ options, value, onChange, "aria-label": ariaLabel = "Cycle option", showIcon = true, maxWidth = 160, className }) => {
1233
+ const enabledOptions = options.filter((o) => !o.disabled);
1234
+ if (enabledOptions.length === 0) return null;
1235
+ const currentIndex = options.findIndex((o) => o.value === value);
1236
+ const current = currentIndex !== -1 ? options[currentIndex] : enabledOptions[0];
1237
+ const advance = (direction) => {
1238
+ const start = currentIndex !== -1 ? currentIndex : -direction;
1239
+ const len = options.length;
1240
+ for (let step = 1; step <= len; step++) {
1241
+ const candidate = options[(start + direction * step + len * len) % len];
1242
+ if (candidate && !candidate.disabled) {
1243
+ onChange?.(candidate.value);
1244
+ return;
1245
+ }
1246
+ }
1247
+ };
1248
+ const triggerMaxWidth = typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth;
1249
+ return /* @__PURE__ */ jsxs("button", {
1250
+ type: "button",
1251
+ "aria-label": ariaLabel,
1252
+ title: `${current?.label ?? current?.value ?? ""} — click to cycle`,
1253
+ style: { maxWidth: triggerMaxWidth },
1254
+ onClick: (e) => advance(e.shiftKey ? -1 : 1),
1255
+ onKeyDown: (e) => {
1256
+ if (e.key === "Enter" || e.key === " ") {
1257
+ e.preventDefault();
1258
+ advance(e.shiftKey ? -1 : 1);
1259
+ }
1260
+ },
1261
+ className: cn("flex h-6 min-w-0 shrink cursor-pointer items-center gap-1 rounded-[4px] px-2 text-[11px] leading-none font-medium text-sf-subtle transition-colors", "hover:text-sf-default focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-sf-ring", className),
1262
+ children: [/* @__PURE__ */ jsx("span", {
1263
+ className: "min-w-0 truncate",
1264
+ children: current?.label ?? current?.value ?? ""
1265
+ }), showIcon && /* @__PURE__ */ jsx(ArrowsClockwiseIcon, { className: "size-3 shrink-0 opacity-70" })]
1266
+ });
1267
+ };
1268
+ /**
1269
+ * Click-to-cycle mode picker. Single compact button that advances through
1270
+ * `options` on each click. Best for 2–3 modes.
1271
+ *
1272
+ * - Controlled: pass `value` + `onChange`.
1273
+ * - Controller-bound: omit both and wrap in `PromptInputRequestControllerProvider`
1274
+ * — reads/writes `requestContext.mode` automatically.
1275
+ */
1276
+ var PromptInputModeCycle = ({ options, value: valueProp, onChange: onChangeProp, "aria-label": ariaLabel = "Cycle mode", showIcon = true, className }) => {
1277
+ const controller = useOptionalPromptInputRequestController();
1278
+ const ctxMode = useStore(controller?.request ?? FALLBACK_REQUEST_STORE, (s) => s.mode);
1279
+ const isControlled = valueProp !== void 0 || onChangeProp !== void 0;
1280
+ const value = isControlled ? valueProp : ctxMode;
1281
+ const handleChange = (next) => {
1282
+ if (onChangeProp) {
1283
+ onChangeProp(next);
1284
+ return;
1285
+ }
1286
+ if (!isControlled && controller) controller.setRequestField("mode", next);
1287
+ };
1288
+ return /* @__PURE__ */ jsx(PromptInputCompactCycle, {
1289
+ options: options.map((o) => ({
1290
+ value: o.value,
1291
+ label: o.label ?? o.value,
1292
+ disabled: o.disabled
1293
+ })),
1294
+ value,
1295
+ onChange: handleChange,
1296
+ "aria-label": ariaLabel,
1297
+ showIcon,
1298
+ className
1299
+ });
1300
+ };
1301
+ /**
1302
+ * Click-to-cycle model picker. Single compact button that advances through
1303
+ * `options` on each click. Best for 2–3 models.
1304
+ *
1305
+ * - Controlled: pass `value` + `onChange`.
1306
+ * - Controller-bound: omit both and wrap in `PromptInputRequestControllerProvider`
1307
+ * — reads/writes `requestContext.model` automatically.
1308
+ */
1309
+ var PromptInputModelCycle = ({ options, value: valueProp, onChange: onChangeProp, "aria-label": ariaLabel = "Cycle model", showIcon = true, className }) => {
1310
+ const controller = useOptionalPromptInputRequestController();
1311
+ const ctxModel = useStore(controller?.request ?? FALLBACK_REQUEST_STORE, (s) => s.model);
1312
+ const isControlled = valueProp !== void 0 || onChangeProp !== void 0;
1313
+ const value = isControlled ? valueProp : ctxModel;
1314
+ const handleChange = (next) => {
1315
+ if (onChangeProp) {
1316
+ onChangeProp(next);
1317
+ return;
1318
+ }
1319
+ if (!isControlled && controller) controller.setRequestField("model", next);
1320
+ };
1321
+ return /* @__PURE__ */ jsx(PromptInputCompactCycle, {
1322
+ options: options.map((o) => ({
1323
+ value: o.value,
1324
+ label: getModelLabel(o),
1325
+ disabled: o.disabled
1326
+ })),
1327
+ value,
1328
+ onChange: handleChange,
1329
+ "aria-label": ariaLabel,
1330
+ showIcon,
1331
+ className
1332
+ });
1333
+ };
1334
+ var IMAGE_EXTS = new Set([
1335
+ "jpg",
1336
+ "jpeg",
1337
+ "png",
1338
+ "gif",
1339
+ "webp",
1340
+ "svg"
1341
+ ]);
1342
+ function getFileIcon(filename) {
1343
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
1344
+ if (IMAGE_EXTS.has(ext)) return /* @__PURE__ */ jsx(ImageIcon, { className: "size-3.5" });
1345
+ if ([
1346
+ "pdf",
1347
+ "doc",
1348
+ "docx",
1349
+ "txt",
1350
+ "md"
1351
+ ].includes(ext)) return /* @__PURE__ */ jsx(FileTextIcon, { className: "size-3.5" });
1352
+ return /* @__PURE__ */ jsx(FileIcon, { className: "size-3.5" });
1353
+ }
1354
+ /**
1355
+ * Single attachment chip for images or files. Includes a remove button.
1356
+ */
1357
+ function PromptInputAttachment({ data, className, ...props }) {
1358
+ const attachments = usePromptInputAttachments();
1359
+ const isImage = data.mediaType?.startsWith("image/") && data.url;
1360
+ const handleRemove = useCallback(() => {
1361
+ attachments.remove(data.id);
1362
+ }, [attachments, data.id]);
1363
+ if (isImage) return /* @__PURE__ */ jsxs("div", {
1364
+ className: cn("group relative size-14 overflow-hidden rounded-md", className),
1365
+ ...props,
1366
+ children: [/* @__PURE__ */ jsx("img", {
1367
+ alt: data.filename || "attachment",
1368
+ className: "size-full object-cover",
1369
+ src: data.url
1370
+ }), /* @__PURE__ */ jsx(Button, {
1371
+ "aria-label": "Remove attachment",
1372
+ className: "absolute top-1 right-1 size-5 rounded-full bg-sf-overlay/80 p-0 opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100",
1373
+ onClick: handleRemove,
1374
+ size: "sm",
1375
+ type: "button",
1376
+ variant: "ghost",
1377
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-3" })
1378
+ })]
1379
+ });
1380
+ const ext = data.filename.split(".").pop()?.toUpperCase() ?? "FILE";
1381
+ const name = data.filename.replace(/\.[^/.]+$/, "");
1382
+ return /* @__PURE__ */ jsxs("div", {
1383
+ className: cn("group relative inline-flex h-8 items-center gap-2 rounded-md bg-sf-tint/50 px-2 text-sm", className),
1384
+ ...props,
1385
+ children: [
1386
+ /* @__PURE__ */ jsx("div", {
1387
+ className: "flex size-5 shrink-0 items-center justify-center text-sf-subtle",
1388
+ children: getFileIcon(data.filename)
1389
+ }),
1390
+ /* @__PURE__ */ jsx(Tooltip, {
1391
+ content: data.filename,
1392
+ children: /* @__PURE__ */ jsx("span", {
1393
+ className: "max-w-[160px] truncate font-medium text-sf-default",
1394
+ children: name || "File"
1395
+ })
1396
+ }),
1397
+ /* @__PURE__ */ jsx("span", {
1398
+ className: "rounded bg-sf-tint px-1 py-0.5 font-semibold text-sf-subtle text-[10px] uppercase",
1399
+ children: ext
1400
+ }),
1401
+ /* @__PURE__ */ jsx(Button, {
1402
+ "aria-label": "Remove attachment",
1403
+ className: "ml-0.5 size-4 shrink-0 rounded-full p-0 opacity-0 transition-opacity group-hover:opacity-100",
1404
+ onClick: handleRemove,
1405
+ size: "sm",
1406
+ type: "button",
1407
+ variant: "ghost",
1408
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-3" })
1409
+ })
1410
+ ]
1411
+ });
1412
+ }
1413
+ /**
1414
+ * Renders all attachments using a render prop. Hidden when no files.
1415
+ * Animates height as files are added/removed.
1416
+ */
1417
+ function PromptInputAttachments({ className, children, ...props }) {
1418
+ const attachments = usePromptInputAttachments();
1419
+ const [height, setHeight] = useState(0);
1420
+ const contentRef = useRef(null);
1421
+ useLayoutEffect(() => {
1422
+ const el = contentRef.current;
1423
+ if (!el) return;
1424
+ const ro = new ResizeObserver(() => {
1425
+ setHeight(el.getBoundingClientRect().height);
1426
+ });
1427
+ ro.observe(el);
1428
+ setHeight(el.getBoundingClientRect().height);
1429
+ return () => ro.disconnect();
1430
+ }, []);
1431
+ useLayoutEffect(() => {
1432
+ const el = contentRef.current;
1433
+ if (el) setHeight(el.getBoundingClientRect().height);
1434
+ }, [attachments.files.length]);
1435
+ if (attachments.files.length === 0) return null;
1436
+ return /* @__PURE__ */ jsx("div", {
1437
+ "aria-live": "polite",
1438
+ className: cn("overflow-hidden px-2 transition-[height] duration-200 ease-out", className),
1439
+ style: { height: attachments.files.length ? height : 0 },
1440
+ ...props,
1441
+ children: /* @__PURE__ */ jsx("div", {
1442
+ className: "flex flex-wrap gap-2 py-1",
1443
+ ref: contentRef,
1444
+ children: attachments.files.map((file) => /* @__PURE__ */ jsx(Fragment, { children: children(file) }, file.id))
1445
+ })
1446
+ });
1447
+ }
1448
+ /**
1449
+ * Voice input button. Uses the Web Speech API (Chrome/Edge). Hidden on unsupported browsers.
1450
+ * Pulses while listening.
1451
+ */
1452
+ var PromptInputSpeechButton = ({ className, textareaRef, onTranscriptionChange, "aria-label": ariaLabel = "Voice input", ...props }) => {
1453
+ const [isListening, setIsListening] = useState(false);
1454
+ const [recognition, setRecognition] = useState(null);
1455
+ const recognitionRef = useRef(null);
1456
+ useEffect(() => {
1457
+ if (typeof window === "undefined") return;
1458
+ const SR = window.SpeechRecognition ?? window.webkitSpeechRecognition;
1459
+ if (!SR) return;
1460
+ const sr = new SR();
1461
+ sr.continuous = true;
1462
+ sr.interimResults = true;
1463
+ sr.lang = "en-US";
1464
+ const handleStart = () => setIsListening(true);
1465
+ const handleEnd = () => setIsListening(false);
1466
+ const handleResult = (event) => {
1467
+ const e = event;
1468
+ let final = "";
1469
+ for (const result of Array.from({ length: e.results.length }, (_, i) => e.results[i])) if (result?.isFinal && result[0]?.transcript) final += result[0].transcript;
1470
+ if (final && textareaRef?.current) {
1471
+ const ta = textareaRef.current;
1472
+ const next = ta.value + (ta.value ? " " : "") + final;
1473
+ ta.value = next;
1474
+ ta.dispatchEvent(new Event("input", { bubbles: true }));
1475
+ onTranscriptionChange?.(next);
1476
+ }
1477
+ };
1478
+ const handleError = (_event) => setIsListening(false);
1479
+ sr.addEventListener("start", handleStart);
1480
+ sr.addEventListener("end", handleEnd);
1481
+ sr.addEventListener("result", handleResult);
1482
+ sr.addEventListener("error", handleError);
1483
+ recognitionRef.current = sr;
1484
+ setRecognition(sr);
1485
+ return () => {
1486
+ sr.removeEventListener("start", handleStart);
1487
+ sr.removeEventListener("end", handleEnd);
1488
+ sr.removeEventListener("result", handleResult);
1489
+ sr.removeEventListener("error", handleError);
1490
+ recognitionRef.current?.stop();
1491
+ };
1492
+ }, [textareaRef, onTranscriptionChange]);
1493
+ const handleToggleListening = useCallback(() => {
1494
+ if (!recognition) return;
1495
+ const sr = recognition;
1496
+ if (isListening) sr.stop();
1497
+ else sr.start();
1498
+ }, [recognition, isListening]);
1499
+ const button = /* @__PURE__ */ jsx(Button, {
1500
+ "aria-label": ariaLabel,
1501
+ className: cn("text-sf-subtle hover:text-sf-default transition-all", isListening && "animate-pulse text-sf-brand", className),
1502
+ disabled: !recognition,
1503
+ onClick: handleToggleListening,
1504
+ size: "sm",
1505
+ type: "button",
1506
+ variant: "ghost",
1507
+ ...props,
1508
+ children: /* @__PURE__ */ jsx(MicrophoneIcon, { className: "size-4" })
1509
+ });
1510
+ if (!recognition) return null;
1511
+ return /* @__PURE__ */ jsx(Tooltip, {
1512
+ content: isListening ? "Stop listening" : "Voice input",
1513
+ children: button
1514
+ });
1515
+ };
1516
+ /**
1517
+ * Convenience button that opens the file dialog directly (no dropdown needed).
1518
+ */
1519
+ var PromptInputAttachButton = ({ "aria-label": ariaLabel = "Attach file", className, ...props }) => {
1520
+ const attachments = usePromptInputAttachments();
1521
+ const handleClick = useCallback(() => {
1522
+ attachments.openFileDialog();
1523
+ }, [attachments]);
1524
+ return /* @__PURE__ */ jsx(Tooltip, {
1525
+ content: ariaLabel,
1526
+ children: /* @__PURE__ */ jsx(Button, {
1527
+ "aria-label": ariaLabel,
1528
+ className: cn("text-sf-subtle hover:text-sf-default", className),
1529
+ onClick: handleClick,
1530
+ size: "sm",
1531
+ type: "button",
1532
+ variant: "ghost",
1533
+ ...props,
1534
+ children: /* @__PURE__ */ jsx(PaperclipIcon, { className: "size-4" })
1535
+ })
1536
+ });
1537
+ };
1538
+ //#endregion
1539
+ export { useProviderAttachments as A, PromptInputTextarea as C, SF_AI_PROMPT_INPUT_VARIANTS as D, SF_AI_PROMPT_INPUT_DEFAULT_VARIANTS as E, usePromptInputRequestController as F, useRequestField as I, useSetRequestField as L, createPromptInputRequestController as M, useDisplayField as N, usePromptInputAttachments as O, useOptionalPromptInputRequestController as P, PromptInputSubmit as S, PromptInputTools as T, PromptInputModeSelector as _, PromptInputActionMenuItem as a, PromptInputProvider as b, PromptInputAttachment as c, PromptInputBody as d, PromptInputButton as f, PromptInputModeSelect as g, PromptInputModeCycle as h, PromptInputActionMenuContent as i, PromptInputRequestControllerProvider as j, usePromptInputController as k, PromptInputAttachments as l, PromptInputCompactSelect as m, PromptInputActionAddAttachments as n, PromptInputActionMenuTrigger as o, PromptInputCompactCycle as p, PromptInputActionMenu as r, PromptInputAttachButton as s, PromptInput as t, PromptInputBackLayer as u, PromptInputModelCycle as v, PromptInputToolbar as w, PromptInputSpeechButton as x, PromptInputModelSelect as y };
1540
+
1541
+ //# sourceMappingURL=ai-prompt-input-Dy1LfxPk.js.map