@keboola/design 11.6.1 → 12.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 (365) hide show
  1. package/AGENTS.md +50 -9
  2. package/CHANGELOG.md +241 -0
  3. package/COMPONENT-API.md +337 -288
  4. package/README.md +12 -2
  5. package/dist/{AIKit-CQxVwyAk.js → AIKit-BD4r7ff-.js} +807 -199
  6. package/dist/AIKit-BD4r7ff-.js.map +1 -0
  7. package/dist/{Alert-C4Y9IwMI.js → Alert-UI-CIs-1.js} +16 -16
  8. package/dist/Alert-UI-CIs-1.js.map +1 -0
  9. package/dist/{AlertModal-BGJdaRRj.js → AlertModal-Th2khjPi.js} +5 -5
  10. package/dist/AlertModal-Th2khjPi.js.map +1 -0
  11. package/dist/{AppShell-DRgJxpXW.js → AppShell-WSQabK8r.js} +15 -52
  12. package/dist/AppShell-WSQabK8r.js.map +1 -0
  13. package/dist/{AutoSaveTextarea-BeuWuszr.js → AutoSaveTextarea-C5iIr2Ts.js} +2 -2
  14. package/dist/{AutoSaveTextarea-BeuWuszr.js.map → AutoSaveTextarea-C5iIr2Ts.js.map} +1 -1
  15. package/dist/{Badge-o5jURtpB.js → Badge-DIjhwPvh.js} +4 -9
  16. package/dist/Badge-DIjhwPvh.js.map +1 -0
  17. package/dist/{BrandEditor-CS9P4r2p.js → BrandEditor-BU23Vl8V.js} +7 -7
  18. package/dist/{BrandEditor-CS9P4r2p.js.map → BrandEditor-BU23Vl8V.js.map} +1 -1
  19. package/dist/{BrandLogo-CoKBk4MI.js → BrandLogo-CKpVSZb6.js} +4 -4
  20. package/dist/BrandLogo-CKpVSZb6.js.map +1 -0
  21. package/dist/{Breadcrumb-D1id7YXd.js → Breadcrumb-p9HtMLCc.js} +8 -14
  22. package/dist/Breadcrumb-p9HtMLCc.js.map +1 -0
  23. package/dist/{Button-DsRrU5F1.js → Button-Ca4Q3VJU.js} +31 -13
  24. package/dist/Button-Ca4Q3VJU.js.map +1 -0
  25. package/dist/{Calendar-cG5NIJ4O.js → Calendar-DFtmZzbF.js} +99 -99
  26. package/dist/Calendar-DFtmZzbF.js.map +1 -0
  27. package/dist/{Card-Dyo7055Q.js → Card-Cr9MBNHu.js} +4 -4
  28. package/dist/Card-Cr9MBNHu.js.map +1 -0
  29. package/dist/{Checkbox-Bqr6zXcW.js → Checkbox-8yIIgY7g.js} +4 -4
  30. package/dist/Checkbox-8yIIgY7g.js.map +1 -0
  31. package/dist/{Clipboard-C2YBRfD8.js → Clipboard-_xf6hMDD.js} +2 -2
  32. package/dist/{Clipboard-C2YBRfD8.js.map → Clipboard-_xf6hMDD.js.map} +1 -1
  33. package/dist/{ClipboardButton-CrljClL1.js → ClipboardButton-DHa1trtI.js} +4 -4
  34. package/dist/{ClipboardButton-CrljClL1.js.map → ClipboardButton-DHa1trtI.js.map} +1 -1
  35. package/dist/{CodeEditor-C9AS8Ch0.js → CodeEditor-BSo-oLFG.js} +55 -165
  36. package/dist/CodeEditor-BSo-oLFG.js.map +1 -0
  37. package/dist/{ColorInput-Dg87lKcR.js → ColorInput-DSMqrs2-.js} +12 -27
  38. package/dist/ColorInput-DSMqrs2-.js.map +1 -0
  39. package/dist/{ColorModeSwitch-CsWLiTBX.js → ColorModeSwitch-D7EuWyJz.js} +7 -17
  40. package/dist/ColorModeSwitch-D7EuWyJz.js.map +1 -0
  41. package/dist/Combobox-CxRAYOBt.js +1069 -0
  42. package/dist/Combobox-CxRAYOBt.js.map +1 -0
  43. package/dist/{Command-CqxoI_De.js → Command-BU_cVurn.js} +4 -4
  44. package/dist/{Command-CqxoI_De.js.map → Command-BU_cVurn.js.map} +1 -1
  45. package/dist/{CopyField-Rx9HPTbJ.js → CopyField-6_c-NdLO.js} +17 -53
  46. package/dist/{CopyField-Rx9HPTbJ.js.map → CopyField-6_c-NdLO.js.map} +1 -1
  47. package/dist/{DateInput-DpifECUQ.js → DateInput-DyEErfJf.js} +6 -6
  48. package/dist/{DateInput-DpifECUQ.js.map → DateInput-DyEErfJf.js.map} +1 -1
  49. package/dist/{DatePicker-nA8YdE84.js → DatePicker-CtSa9b3V.js} +3 -3
  50. package/dist/{DatePicker-nA8YdE84.js.map → DatePicker-CtSa9b3V.js.map} +1 -1
  51. package/dist/{DateRangeInput-9MIw7P6L.js → DateRangeInput-Dg7-VUd9.js} +10 -14
  52. package/dist/DateRangeInput-Dg7-VUd9.js.map +1 -0
  53. package/dist/{DateRangePicker-DjSUFjh4.js → DateRangePicker-BoPnh4aH.js} +9 -13
  54. package/dist/DateRangePicker-BoPnh4aH.js.map +1 -0
  55. package/dist/DiffView-ppTIzh2h.js.map +1 -1
  56. package/dist/{DropdownMenu-CASr-jgl.js → DropdownMenu-gRM-A8qU.js} +11 -6
  57. package/dist/DropdownMenu-gRM-A8qU.js.map +1 -0
  58. package/dist/{FieldItem-DtPTzNef.js → FieldItem-2wMXQ0Qw.js} +12 -25
  59. package/dist/FieldItem-2wMXQ0Qw.js.map +1 -0
  60. package/dist/{FieldItem-vhIJW4pj.d.ts → FieldItem-CPN1xjN5.d.ts} +11 -25
  61. package/dist/{FileUpload-DYQCTGjU.js → FileUpload-C83tXuE2.js} +11 -16
  62. package/dist/{FileUpload-DYQCTGjU.js.map → FileUpload-C83tXuE2.js.map} +1 -1
  63. package/dist/{Form-DAaatlBk.js → Form-95rVLfX8.js} +15 -23
  64. package/dist/{Form-DAaatlBk.js.map → Form-95rVLfX8.js.map} +1 -1
  65. package/dist/{FormGroup-Bl8JmnzJ.js → FormGroup-CmNiAtU6.js} +11 -17
  66. package/dist/FormGroup-CmNiAtU6.js.map +1 -0
  67. package/dist/{FullScreenModal-CN9nAs72.js → FullScreenModal-CD7mYeTz.js} +15 -29
  68. package/dist/FullScreenModal-CD7mYeTz.js.map +1 -0
  69. package/dist/{HoverCard-B9ZMJxjn.js → HoverCard-B8OKu9XZ.js} +2 -2
  70. package/dist/{HoverCard-B9ZMJxjn.js.map → HoverCard-B8OKu9XZ.js.map} +1 -1
  71. package/dist/{InputGroup-DcZRlVnN.js → InputGroup-B4QOPxHl.js} +12 -13
  72. package/dist/InputGroup-B4QOPxHl.js.map +1 -0
  73. package/dist/{Kbd-D1Azcc4g.js → Kbd-J4n1J6i4.js} +23 -13
  74. package/dist/Kbd-J4n1J6i4.js.map +1 -0
  75. package/dist/{MarkedText-DNGEUVWc.js → MarkedText-DlmlJO0u.js} +2 -2
  76. package/dist/{MarkedText-DNGEUVWc.js.map → MarkedText-DlmlJO0u.js.map} +1 -1
  77. package/dist/{MermaidDiagram-CujFxVzk.js → MermaidDiagram-BQvz6bhv.js} +16 -34
  78. package/dist/MermaidDiagram-BQvz6bhv.js.map +1 -0
  79. package/dist/{Modal-Coj-H02o.js → Modal-Driyqs_N.js} +17 -34
  80. package/dist/Modal-Driyqs_N.js.map +1 -0
  81. package/dist/{ModalTitle-C76ke2eo.js → ModalTitle-BxopkIoQ.js} +3 -3
  82. package/dist/ModalTitle-BxopkIoQ.js.map +1 -0
  83. package/dist/{MultiActionButtonGroup-CNNoBQbv.js → MultiActionButtonGroup-BPnmzBtw.js} +3 -3
  84. package/dist/{MultiActionButtonGroup-CNNoBQbv.js.map → MultiActionButtonGroup-BPnmzBtw.js.map} +1 -1
  85. package/dist/{Navbar-Liy1TPI7.js → Navbar-B_DNpv5s.js} +9 -13
  86. package/dist/{Navbar-Liy1TPI7.js.map → Navbar-B_DNpv5s.js.map} +1 -1
  87. package/dist/{OtpInput-CbbymqYs.js → OtpInput-I8B8Vjdl.js} +2 -2
  88. package/dist/{OtpInput-CbbymqYs.js.map → OtpInput-I8B8Vjdl.js.map} +1 -1
  89. package/dist/{PageHeader-Q3IpCnQd.js → PageHeader-CgfyXpf1.js} +13 -26
  90. package/dist/PageHeader-CgfyXpf1.js.map +1 -0
  91. package/dist/{PageLayout-DSVM-ASz.js → PageLayout-DiAAILuS.js} +12 -20
  92. package/dist/PageLayout-DiAAILuS.js.map +1 -0
  93. package/dist/{PageToolbar-BKVJiDAL.js → PageToolbar-DOAtAnfL.js} +12 -42
  94. package/dist/PageToolbar-DOAtAnfL.js.map +1 -0
  95. package/dist/{Pagination-C_b7Xhey.js → Pagination-LaSg-5cl.js} +3 -3
  96. package/dist/{Pagination-C_b7Xhey.js.map → Pagination-LaSg-5cl.js.map} +1 -1
  97. package/dist/{Popconfirm-5pBzT_HQ.js → Popconfirm-SLz0zodk.js} +3 -3
  98. package/dist/{Popconfirm-5pBzT_HQ.js.map → Popconfirm-SLz0zodk.js.map} +1 -1
  99. package/dist/{Popover-BEbQrC_P.js → Popover-CEk915I1.js} +4 -3
  100. package/dist/Popover-CEk915I1.js.map +1 -0
  101. package/dist/{RadioGroup-CUBsuP7r.js → RadioGroup-CBPRLRN0.js} +4 -4
  102. package/dist/{RadioGroup-CUBsuP7r.js.map → RadioGroup-CBPRLRN0.js.map} +1 -1
  103. package/dist/{Search-DVpJuzr9.js → Search-DmkQo716.js} +3 -3
  104. package/dist/{Search-DVpJuzr9.js.map → Search-DmkQo716.js.map} +1 -1
  105. package/dist/{SearchInput-Q85p8Ews.js → SearchInput-CEfQDNl3.js} +8 -13
  106. package/dist/SearchInput-CEfQDNl3.js.map +1 -0
  107. package/dist/{SectionNav-mpmSM3OC.js → SectionNav-B_qf0AXi.js} +10 -42
  108. package/dist/SectionNav-B_qf0AXi.js.map +1 -0
  109. package/dist/{Select-DV3Hak_l.js → Select-ByRvkZ3D.js} +8 -11
  110. package/dist/{Select-DV3Hak_l.js.map → Select-ByRvkZ3D.js.map} +1 -1
  111. package/dist/{Sheet-Chf0kX1E.js → Sheet-C-yXk5Da.js} +5 -9
  112. package/dist/Sheet-C-yXk5Da.js.map +1 -0
  113. package/dist/{Sidebar-CTWsHZhF.js → Sidebar-Ds0E6PbR.js} +181 -33
  114. package/dist/Sidebar-Ds0E6PbR.js.map +1 -0
  115. package/dist/{Slider-Bv0B6lI0.js → Slider-DWdu9NuM.js} +3 -3
  116. package/dist/{Slider-Bv0B6lI0.js.map → Slider-DWdu9NuM.js.map} +1 -1
  117. package/dist/{Stepper-C8sm9ZFM.js → Stepper-BLkLhfnd.js} +6 -9
  118. package/dist/{Stepper-C8sm9ZFM.js.map → Stepper-BLkLhfnd.js.map} +1 -1
  119. package/dist/{Switch-B0WdGSjz.js → Switch-DZvNePOm.js} +2 -2
  120. package/dist/{Switch-B0WdGSjz.js.map → Switch-DZvNePOm.js.map} +1 -1
  121. package/dist/{Table-CvYuTuNU.js → Table-BaVT5Tkn.js} +6 -11
  122. package/dist/{Table-CvYuTuNU.js.map → Table-BaVT5Tkn.js.map} +1 -1
  123. package/dist/{Tabs-eB974xJf.js → Tabs-Dt9oLYHC.js} +3 -3
  124. package/dist/{Tabs-eB974xJf.js.map → Tabs-Dt9oLYHC.js.map} +1 -1
  125. package/dist/{TextInput-DiEMxVF6.js → TextInput-CDG2XpBl.js} +12 -15
  126. package/dist/TextInput-CDG2XpBl.js.map +1 -0
  127. package/dist/{ThemeProvider-BI6JWBdJ.js → ThemeProvider-DXsxFg1U.js} +13 -31
  128. package/dist/ThemeProvider-DXsxFg1U.js.map +1 -0
  129. package/dist/{TimePicker-BGeqc-Ed.js → TimePicker-CDGYrRxi.js} +2 -2
  130. package/dist/{TimePicker-BGeqc-Ed.js.map → TimePicker-CDGYrRxi.js.map} +1 -1
  131. package/dist/{Timeline-BG5Xogxh.js → Timeline-B-I6sb0M.js} +2 -2
  132. package/dist/{Timeline-BG5Xogxh.js.map → Timeline-B-I6sb0M.js.map} +1 -1
  133. package/dist/{Toast-Dr6Uw7ao.js → Toast-PfQf3vj-.js} +2 -2
  134. package/dist/{Toast-Dr6Uw7ao.js.map → Toast-PfQf3vj-.js.map} +1 -1
  135. package/dist/{Workbench-UR2FBC7I.js → Workbench-DmZzpkj7.js} +2 -2
  136. package/dist/{Workbench-UR2FBC7I.js.map → Workbench-DmZzpkj7.js.map} +1 -1
  137. package/dist/{ZoomableSvg-U_VH3QRO.js → ZoomableSvg-BzXVfgnI.js} +5 -19
  138. package/dist/ZoomableSvg-BzXVfgnI.js.map +1 -0
  139. package/dist/charts.d.ts +21 -52
  140. package/dist/charts.js +13 -39
  141. package/dist/charts.js.map +1 -1
  142. package/dist/{context-D7X470dy.js → context-U293r3v-.js} +5 -9
  143. package/dist/context-U293r3v-.js.map +1 -0
  144. package/dist/editors.d.ts +27 -124
  145. package/dist/editors.js +29 -71
  146. package/dist/editors.js.map +1 -1
  147. package/dist/{findLiteralMatches-BGBw8Vbl.js → findLiteralMatches-DgGLzyG0.js} +8 -20
  148. package/dist/findLiteralMatches-DgGLzyG0.js.map +1 -0
  149. package/dist/flint.d.ts +3 -6
  150. package/dist/flint.js +31 -80
  151. package/dist/flint.js.map +1 -1
  152. package/dist/{icons-Cek151jC.js → icons-wcA70iQx.js} +105 -2
  153. package/dist/icons-wcA70iQx.js.map +1 -0
  154. package/dist/icons.d.ts +2 -2
  155. package/dist/icons.js +2 -2
  156. package/dist/{index-m-kQEWiY.d.ts → index-B7k-09i1.d.ts} +14 -2
  157. package/dist/index.d.ts +1461 -1809
  158. package/dist/index.js +70 -67
  159. package/dist/internal/blocks/AIKit.js +2 -2
  160. package/dist/internal/blocks/AppShell.js +1 -1
  161. package/dist/internal/blocks/AuthLayout.js +7 -27
  162. package/dist/internal/blocks/AuthLayout.js.map +1 -1
  163. package/dist/internal/blocks/AutoSaveTextarea.js +1 -1
  164. package/dist/internal/blocks/BrandEditor.js +1 -1
  165. package/dist/internal/blocks/ChartPanel.js +4 -8
  166. package/dist/internal/blocks/ChartPanel.js.map +1 -1
  167. package/dist/internal/blocks/ChipEditor.js +129 -0
  168. package/dist/internal/blocks/ChipEditor.js.map +1 -0
  169. package/dist/internal/blocks/ClipboardButton.js +1 -1
  170. package/dist/internal/blocks/ColorInput.js +1 -1
  171. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  172. package/dist/internal/blocks/Command.js +1 -1
  173. package/dist/internal/blocks/CopyField.js +1 -1
  174. package/dist/internal/blocks/DashboardHero.js +4 -7
  175. package/dist/internal/blocks/DashboardHero.js.map +1 -1
  176. package/dist/internal/blocks/DateInput.js +1 -1
  177. package/dist/internal/blocks/DateRangeInput.js +1 -1
  178. package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
  179. package/dist/internal/blocks/EmptyState.js +5 -9
  180. package/dist/internal/blocks/EmptyState.js.map +1 -1
  181. package/dist/internal/blocks/ErrorState.js +5 -9
  182. package/dist/internal/blocks/ErrorState.js.map +1 -1
  183. package/dist/internal/blocks/ExportMenu.js +6 -10
  184. package/dist/internal/blocks/ExportMenu.js.map +1 -1
  185. package/dist/internal/blocks/Form/connectors/ComboboxField.js +40 -0
  186. package/dist/internal/blocks/Form/connectors/ComboboxField.js.map +1 -0
  187. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +5 -22
  188. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js.map +1 -1
  189. package/dist/internal/blocks/Form.js +1 -1
  190. package/dist/internal/blocks/FormGroup.js +1 -1
  191. package/dist/internal/blocks/GoogleButton.js +1 -1
  192. package/dist/internal/blocks/MicrosoftButton.js +1 -1
  193. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  194. package/dist/internal/blocks/MultiCombobox.js +162 -165
  195. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  196. package/dist/internal/blocks/NumberInput.js +1 -1
  197. package/dist/internal/blocks/OtpInput.js +1 -1
  198. package/dist/internal/blocks/PageHeader.js +1 -1
  199. package/dist/internal/blocks/PageLayout.js +1 -1
  200. package/dist/internal/blocks/PageToolbar.js +1 -1
  201. package/dist/internal/blocks/PasswordInput.js +4 -4
  202. package/dist/internal/blocks/PasswordInput.js.map +1 -1
  203. package/dist/internal/blocks/SearchInput.js +1 -1
  204. package/dist/internal/blocks/SearchInputWithNavigation.js +4 -4
  205. package/dist/internal/blocks/SectionNav.js +1 -1
  206. package/dist/internal/blocks/SplitButton.js +3 -3
  207. package/dist/internal/blocks/StatCard.js +4 -8
  208. package/dist/internal/blocks/StatCard.js.map +1 -1
  209. package/dist/internal/blocks/TextInput.js +1 -1
  210. package/dist/internal/blocks/Textarea.js +2 -2
  211. package/dist/internal/blocks/TimeInput.js +5 -5
  212. package/dist/internal/blocks/TimeInput.js.map +1 -1
  213. package/dist/internal/components/Alert.js +1 -1
  214. package/dist/internal/components/AlertModal.js +1 -1
  215. package/dist/internal/components/Avatar.js +1 -1
  216. package/dist/internal/components/Badge.js +1 -1
  217. package/dist/internal/components/BrandLogo.js +1 -1
  218. package/dist/internal/components/Breadcrumb.js +1 -1
  219. package/dist/internal/components/Button.js +1 -1
  220. package/dist/internal/components/ButtonGroup.js.map +1 -1
  221. package/dist/internal/components/Calendar.js +1 -1
  222. package/dist/internal/components/Card.js +1 -1
  223. package/dist/internal/components/Checkbox.js +1 -1
  224. package/dist/internal/components/Clipboard.js +1 -1
  225. package/dist/internal/components/CollapsiblePanel.js +2 -2
  226. package/dist/internal/components/Combobox.js +2 -2
  227. package/dist/internal/components/DatePicker.js +1 -1
  228. package/dist/internal/components/DateRangePicker.js +1 -1
  229. package/dist/internal/components/DropdownMenu.js +1 -1
  230. package/dist/internal/components/FileUpload.js +1 -1
  231. package/dist/internal/components/FullScreenModal.js +1 -1
  232. package/dist/internal/components/HoverCard.js +1 -1
  233. package/dist/internal/components/InputGroup.js +1 -1
  234. package/dist/internal/components/Kbd.js +1 -1
  235. package/dist/internal/components/MarkedText.js +1 -1
  236. package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +1 -1
  237. package/dist/internal/components/Modal.js +1 -1
  238. package/dist/internal/components/Navbar.js +1 -1
  239. package/dist/internal/components/Pagination.js +1 -1
  240. package/dist/internal/components/PanelWithDetails.js +1 -1
  241. package/dist/internal/components/Popconfirm.js +1 -1
  242. package/dist/internal/components/Popover.js +1 -1
  243. package/dist/internal/components/RadioGroup.js +1 -1
  244. package/dist/internal/components/Search.js +1 -1
  245. package/dist/internal/components/Select.js +1 -1
  246. package/dist/internal/components/Separator.js.map +1 -1
  247. package/dist/internal/components/Sheet.js +1 -1
  248. package/dist/internal/components/Sidebar.js +1 -1
  249. package/dist/internal/components/Skeleton/Skeleton.js +5 -9
  250. package/dist/internal/components/Skeleton/Skeleton.js.map +1 -1
  251. package/dist/internal/components/Slider.js +1 -1
  252. package/dist/internal/components/SpotlightBackdrop.js +3 -8
  253. package/dist/internal/components/SpotlightBackdrop.js.map +1 -1
  254. package/dist/internal/components/StatusDot.js +60 -0
  255. package/dist/internal/components/StatusDot.js.map +1 -0
  256. package/dist/internal/components/Stepper.js +1 -1
  257. package/dist/internal/components/Switch.js +1 -1
  258. package/dist/internal/components/Table.js +1 -1
  259. package/dist/internal/components/Tabs.js +1 -1
  260. package/dist/internal/components/ThemeProvider.js +3 -3
  261. package/dist/internal/components/TimePicker.js +1 -1
  262. package/dist/internal/components/Timeline.js +1 -1
  263. package/dist/internal/components/Toast.js +2 -2
  264. package/dist/internal/components/Tooltip.js +2 -2
  265. package/dist/internal/components/Truncated.js +4 -8
  266. package/dist/internal/components/Truncated.js.map +1 -1
  267. package/dist/internal/components/Workbench.js +1 -1
  268. package/dist/internal/components/ZoomableSvg.js +1 -1
  269. package/dist/internal/hooks/useScrollbarPosition.js +1 -1
  270. package/dist/internal/hooks/useStableCallback.js +4 -13
  271. package/dist/internal/hooks/useStableCallback.js.map +1 -1
  272. package/dist/internal/utils/mergeRefs.js +27 -9
  273. package/dist/internal/utils/mergeRefs.js.map +1 -1
  274. package/dist/internal/utils.js +3 -3
  275. package/dist/markdown-editor.d.ts +15 -37
  276. package/dist/markdown-editor.js +17 -23
  277. package/dist/markdown-editor.js.map +1 -1
  278. package/dist/mermaid.d.ts +4 -6
  279. package/dist/mermaid.js +1 -1
  280. package/dist/rjsf.d.ts +9 -19
  281. package/dist/rjsf.js +44 -84
  282. package/dist/rjsf.js.map +1 -1
  283. package/dist/{styles-BAFscjSV.js → styles-gzcjOyKv.js} +6 -6
  284. package/dist/styles-gzcjOyKv.js.map +1 -0
  285. package/dist/styles.css +1 -1
  286. package/dist/svgTransforms-Dw2hRA-i.js +51 -0
  287. package/dist/svgTransforms-Dw2hRA-i.js.map +1 -0
  288. package/dist/testing.d.ts +3 -10
  289. package/dist/testing.js +5 -12
  290. package/dist/testing.js.map +1 -1
  291. package/dist/themeTokens-7DEab0kp.js +31 -0
  292. package/dist/themeTokens-7DEab0kp.js.map +1 -0
  293. package/dist/{toast-DIC0iNRf.js → toast-CyXEdaCZ.js} +3 -3
  294. package/dist/toast-CyXEdaCZ.js.map +1 -0
  295. package/dist/{themeScopeContext-D7fSyb06.js → useColorSchemeState-Cw4MCXUs.js} +14 -14
  296. package/dist/useColorSchemeState-Cw4MCXUs.js.map +1 -0
  297. package/dist/{useControllableState-M6494mCT.js → useControllableState-CUYXMsfz.js} +3 -7
  298. package/dist/useControllableState-CUYXMsfz.js.map +1 -0
  299. package/dist/useElement-D-RjrGa4.js +21 -0
  300. package/dist/useElement-D-RjrGa4.js.map +1 -0
  301. package/dist/useThemeAttributes-B199Regy.js +67 -0
  302. package/dist/useThemeAttributes-B199Regy.js.map +1 -0
  303. package/dist/{utils-DnkrFYqY.js → utils-Bd28bWgm.js} +53 -20
  304. package/dist/utils-Bd28bWgm.js.map +1 -0
  305. package/dist/vega.d.ts +8 -30
  306. package/dist/vega.js +5 -13
  307. package/dist/vega.js.map +1 -1
  308. package/dist/{vegaTheme-CSvFEMBl.js → vegaTheme-VQMWTlBw.js} +7 -21
  309. package/dist/vegaTheme-VQMWTlBw.js.map +1 -0
  310. package/package.json +11 -9
  311. package/src/styles.css +120 -14
  312. package/src/theme.css +126 -6
  313. package/dist/AIKit-CQxVwyAk.js.map +0 -1
  314. package/dist/Alert-C4Y9IwMI.js.map +0 -1
  315. package/dist/AlertModal-BGJdaRRj.js.map +0 -1
  316. package/dist/AppShell-DRgJxpXW.js.map +0 -1
  317. package/dist/Badge-o5jURtpB.js.map +0 -1
  318. package/dist/BrandLogo-CoKBk4MI.js.map +0 -1
  319. package/dist/Breadcrumb-D1id7YXd.js.map +0 -1
  320. package/dist/Button-DsRrU5F1.js.map +0 -1
  321. package/dist/Calendar-cG5NIJ4O.js.map +0 -1
  322. package/dist/Card-Dyo7055Q.js.map +0 -1
  323. package/dist/Checkbox-Bqr6zXcW.js.map +0 -1
  324. package/dist/CodeEditor-C9AS8Ch0.js.map +0 -1
  325. package/dist/ColorInput-Dg87lKcR.js.map +0 -1
  326. package/dist/ColorModeSwitch-CsWLiTBX.js.map +0 -1
  327. package/dist/Combobox-BfanUAqY.js +0 -619
  328. package/dist/Combobox-BfanUAqY.js.map +0 -1
  329. package/dist/DateRangeInput-9MIw7P6L.js.map +0 -1
  330. package/dist/DateRangePicker-DjSUFjh4.js.map +0 -1
  331. package/dist/DropdownMenu-CASr-jgl.js.map +0 -1
  332. package/dist/FieldItem-DtPTzNef.js.map +0 -1
  333. package/dist/FormGroup-Bl8JmnzJ.js.map +0 -1
  334. package/dist/FullScreenModal-CN9nAs72.js.map +0 -1
  335. package/dist/InputGroup-DcZRlVnN.js.map +0 -1
  336. package/dist/Kbd-D1Azcc4g.js.map +0 -1
  337. package/dist/MermaidDiagram-CujFxVzk.js.map +0 -1
  338. package/dist/Modal-Coj-H02o.js.map +0 -1
  339. package/dist/ModalTitle-C76ke2eo.js.map +0 -1
  340. package/dist/PageHeader-Q3IpCnQd.js.map +0 -1
  341. package/dist/PageLayout-DSVM-ASz.js.map +0 -1
  342. package/dist/PageToolbar-BKVJiDAL.js.map +0 -1
  343. package/dist/Popover-BEbQrC_P.js.map +0 -1
  344. package/dist/SearchInput-Q85p8Ews.js.map +0 -1
  345. package/dist/SectionNav-mpmSM3OC.js.map +0 -1
  346. package/dist/Sheet-Chf0kX1E.js.map +0 -1
  347. package/dist/Sidebar-CTWsHZhF.js.map +0 -1
  348. package/dist/TextInput-DiEMxVF6.js.map +0 -1
  349. package/dist/ThemeProvider-BI6JWBdJ.js.map +0 -1
  350. package/dist/ZoomableSvg-U_VH3QRO.js.map +0 -1
  351. package/dist/context-D7X470dy.js.map +0 -1
  352. package/dist/findLiteralMatches-BGBw8Vbl.js.map +0 -1
  353. package/dist/icons-Cek151jC.js.map +0 -1
  354. package/dist/styles-BAFscjSV.js.map +0 -1
  355. package/dist/svgTransforms-CJAYPk7o.js +0 -81
  356. package/dist/svgTransforms-CJAYPk7o.js.map +0 -1
  357. package/dist/themeScopeContext-D7fSyb06.js.map +0 -1
  358. package/dist/themeTokens-qP1-55O7.js +0 -119
  359. package/dist/themeTokens-qP1-55O7.js.map +0 -1
  360. package/dist/toast-DIC0iNRf.js.map +0 -1
  361. package/dist/useControllableState-M6494mCT.js.map +0 -1
  362. package/dist/useElement-DkF6esWL.js +0 -15
  363. package/dist/useElement-DkF6esWL.js.map +0 -1
  364. package/dist/utils-DnkrFYqY.js.map +0 -1
  365. package/dist/vegaTheme-CSvFEMBl.js.map +0 -1
@@ -1,23 +1,23 @@
1
1
  import { cn } from "./classNames-BzrkDnOD.js";
2
- import { Tooltip, TooltipProvider } from "./utils-DnkrFYqY.js";
3
- import { AlertCircle, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CirclePause, CircleX, Loader2, Maximize2, Minimize2, Play, Send, Sparkles, ThumbsDown, ThumbsUp, TriangleAlert, X, XCircle } from "./icons-Cek151jC.js";
4
- import { Button } from "./Button-DsRrU5F1.js";
2
+ import { Tooltip, TooltipProvider } from "./utils-Bd28bWgm.js";
3
+ import { AlertCircle, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Ban, BarChart3, Bell, Bug, Calendar, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Circle, CircleAlert, CircleCheck, CircleHelp, CirclePause, CirclePlay, CirclePlus, CircleStop, CircleX, Clock, Cog, Copy, Database, Download, Ellipsis, ExternalLink, Eye, File, FilePen, FileText, Flag, Folder, Gauge, GitBranch, GitMerge, GitPullRequest, Globe, Hand, History, Hourglass, Info, Key, Layers, LineChart, Link, List, ListChecks, Loader2, Lock, Mail, Maximize2, Minimize2, Minus, Pencil, Play, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Save, Search, Send, Settings, Sparkles, Star, Table, ThumbsDown, ThumbsUp, Trash2, TriangleAlert, Upload, User, Users, WandSparkles, Warehouse, Workflow, X, XCircle, Zap } from "./icons-wcA70iQx.js";
4
+ import { Button } from "./Button-Ca4Q3VJU.js";
5
5
  import { ButtonGroup } from "./internal/components/ButtonGroup.js";
6
- import { ClipboardButton } from "./ClipboardButton-CrljClL1.js";
7
- import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-CN9nAs72.js";
6
+ import { ClipboardButton } from "./ClipboardButton-DHa1trtI.js";
7
+ import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-CD7mYeTz.js";
8
8
  import { Truncated } from "./internal/components/Truncated.js";
9
- import { HoverCard } from "./HoverCard-B9ZMJxjn.js";
10
- import { Command } from "./Command-CqxoI_De.js";
11
- import { TextInput } from "./TextInput-DiEMxVF6.js";
12
- import { Checkbox } from "./Checkbox-Bqr6zXcW.js";
13
- import { Badge } from "./Badge-o5jURtpB.js";
9
+ import { HoverCard } from "./HoverCard-B8OKu9XZ.js";
10
+ import { Command } from "./Command-BU_cVurn.js";
11
+ import { TextInput } from "./TextInput-CDG2XpBl.js";
12
+ import { Checkbox } from "./Checkbox-8yIIgY7g.js";
13
+ import { Badge } from "./Badge-DIjhwPvh.js";
14
14
  import { Textarea } from "./internal/blocks/Textarea.js";
15
- import { Table } from "./Table-CvYuTuNU.js";
15
+ import { Table as Table$1 } from "./Table-BaVT5Tkn.js";
16
16
  import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
17
17
  import { DiagramSource } from "./DiagramSource-C5_d8Gdj.js";
18
18
  import { Progress } from "./internal/components/Progress.js";
19
19
  import { Slot } from "@radix-ui/react-slot";
20
- import { isValidElement, useCallback, useEffect, useId, useRef, useState } from "react";
20
+ import { createContext, isValidElement, use, useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
21
21
  import { cva } from "class-variance-authority";
22
22
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
23
23
  import TextareaAutosize from "react-textarea-autosize";
@@ -26,50 +26,85 @@ import remarkGfm from "remark-gfm";
26
26
  //#region src/blocks/AIKit/AnswerActions.tsx
27
27
  const VOTE_BUTTONS = [{
28
28
  vote: "up",
29
- label: "Good answer",
30
29
  icon: /* @__PURE__ */ jsx(ThumbsUp, { className: "tw:size-4" })
31
30
  }, {
32
31
  vote: "down",
33
- label: "Bad answer",
34
32
  icon: /* @__PURE__ */ jsx(ThumbsDown, { className: "tw:size-4" })
35
33
  }];
34
+ const DEFAULT_LABELS = {
35
+ up: "Good answer",
36
+ down: "Bad answer"
37
+ };
38
+ /** Roomier for a panel; compact for a dense transcript. */
39
+ const SIZES = {
40
+ small: {
41
+ button: "icon-xs",
42
+ gap: "extra-small"
43
+ },
44
+ medium: {
45
+ button: "icon-sm",
46
+ gap: "little-small"
47
+ }
48
+ };
36
49
  /**
37
- * What a reader can do with a finished answer: take it away, and say whether it was any good.
50
+ * Copy and thumbs up/down for a finished answer.
38
51
  *
39
- * - **Always rendered, never hover-only.** A reveal-on-hover row does not exist for anyone
40
- * reaching it without a pointer. The buttons are quiet (`invisible`) rather than hidden.
41
- * - Copy sits first: it is the one action with no round trip.
42
- * - **A vote can be changed but not withdrawn.** `aria-pressed` says which one is recorded, and
43
- * both buttons stay focusable so a reader can switch. Pressing the pressed one re-sends the
44
- * same vote.
45
- * - The recorded vote and the write are the caller's: the two chats vote against different
46
- * endpoints, and only the caller knows whether a turn is finished enough to rate.
52
+ * - Always rendered, never hover-only, so it is reachable without a pointer.
53
+ * - A vote can be changed but not withdrawn; pressing the pressed one re-sends it.
54
+ * - The caller owns the recorded vote and the write.
47
55
  */
48
- const AnswerActions = ({ copyText, vote, onVote }) => {
56
+ const AnswerActions = ({ copyText, vote, onVote, onCopy, actions, labels = DEFAULT_LABELS, confirmation, size = "small", layout = "inline" }) => {
57
+ const { button, gap } = SIZES[size];
58
+ const votes = VOTE_BUTTONS.map(({ vote: candidate, icon }) => {
59
+ const isRecorded = vote === candidate;
60
+ const label = labels[candidate];
61
+ return /* @__PURE__ */ jsx(Tooltip, {
62
+ tooltip: label,
63
+ placement: "top",
64
+ triggerAsChild: true,
65
+ children: /* @__PURE__ */ jsx(Button, {
66
+ size: button,
67
+ variant: "invisible",
68
+ className: cn(isRecorded && candidate === "up" && "tw:bg-success/10 tw:text-success tw:hover:not-disabled:bg-success/20 tw:hover:not-disabled:text-success", isRecorded && candidate === "down" && "tw:bg-destructive/10 tw:text-destructive tw:hover:not-disabled:bg-destructive/20 tw:hover:not-disabled:text-destructive"),
69
+ "aria-label": label,
70
+ "aria-pressed": isRecorded,
71
+ onClick: () => onVote(candidate),
72
+ children: icon
73
+ })
74
+ }, candidate);
75
+ });
76
+ const copy = copyText ? /* @__PURE__ */ jsx(ClipboardButton, {
77
+ text: copyText,
78
+ tooltip: "Copy answer",
79
+ size: button,
80
+ variant: "invisible",
81
+ onClick: onCopy
82
+ }) : null;
83
+ const said = confirmation ? /* @__PURE__ */ jsx("span", {
84
+ "aria-live": "polite",
85
+ className: "tw:ml-1 tw:text-xs tw:font-medium tw:text-foreground tw:empty:hidden tw:animate-in tw:fade-in tw:slide-in-from-left-1 tw:duration-300",
86
+ children: vote ? confirmation[vote] : ""
87
+ }) : null;
88
+ if (layout === "split") return /* @__PURE__ */ jsxs("div", {
89
+ className: "tw:flex tw:w-full tw:items-center tw:justify-between tw:gap-2",
90
+ children: [/* @__PURE__ */ jsxs(ButtonGroup, {
91
+ space: gap,
92
+ "aria-label": "Answer actions",
93
+ children: [votes, said]
94
+ }), /* @__PURE__ */ jsxs(ButtonGroup, {
95
+ space: gap,
96
+ children: [actions, copy]
97
+ })]
98
+ });
49
99
  return /* @__PURE__ */ jsxs(ButtonGroup, {
50
- space: "extra-small",
100
+ space: gap,
51
101
  "aria-label": "Answer actions",
52
- children: [copyText ? /* @__PURE__ */ jsx(ClipboardButton, {
53
- text: copyText,
54
- tooltip: "Copy answer",
55
- size: "icon-xs",
56
- variant: "invisible"
57
- }) : null, VOTE_BUTTONS.map(({ vote: candidate, label, icon }) => {
58
- const isRecorded = vote === candidate;
59
- return /* @__PURE__ */ jsx(Tooltip, {
60
- tooltip: label,
61
- placement: "top",
62
- triggerAsChild: true,
63
- children: /* @__PURE__ */ jsx(Button, {
64
- size: "icon-xs",
65
- variant: isRecorded ? "secondary" : "invisible",
66
- "aria-label": label,
67
- "aria-pressed": isRecorded,
68
- onClick: () => onVote(candidate),
69
- children: icon
70
- })
71
- }, candidate);
72
- })]
102
+ children: [
103
+ copy,
104
+ votes,
105
+ actions,
106
+ said
107
+ ]
73
108
  });
74
109
  };
75
110
  //#endregion
@@ -98,6 +133,12 @@ const variantClasses = {
98
133
  dismissed: "tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground"
99
134
  };
100
135
  const iconClasses = "tw:size-3.5 tw:shrink-0 tw:basis-3.5 tw:opacity-70";
136
+ const variantStatus = {
137
+ success: "finished",
138
+ error: "failed",
139
+ processing: "running",
140
+ dismissed: "not run"
141
+ };
101
142
  const renderVariantIcon$1 = (variant) => {
102
143
  if (variant === "processing") return /* @__PURE__ */ jsx(Loader2, { className: cn(iconClasses, "tw:animate-spin") });
103
144
  if (variant === "error" || variant === "dismissed") return /* @__PURE__ */ jsx(XCircle, { className: iconClasses });
@@ -108,13 +149,21 @@ const CollapsibleStepHeader = ({ isExpanded, onToggle, label, variant = "success
108
149
  type: "button",
109
150
  "aria-expanded": isExpanded,
110
151
  onClick: onToggle,
152
+ "data-variant": variant,
111
153
  className: cn("tw:flex tw:w-fit tw:items-center tw:gap-1.5 tw:text-left tw:text-xs tw:font-medium tw:transition-colors tw:focus-visible:outline tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:disabled:opacity-40", variantClasses[variant]),
112
154
  children: [renderVariantIcon$1(variant), /* @__PURE__ */ jsxs("span", {
113
155
  className: "tw:min-w-0",
114
- children: [label, /* @__PURE__ */ jsxs("span", {
115
- className: "tw:whitespace-nowrap",
116
- children: ["⁠", /* @__PURE__ */ jsx(ChevronDown, { className: cn("tw:ml-1.5 tw:inline-block tw:size-3.5 tw:align-middle tw:transition-transform", isExpanded && "tw:rotate-180") })]
117
- })]
156
+ children: [
157
+ label,
158
+ /* @__PURE__ */ jsx("span", {
159
+ className: "tw:sr-only",
160
+ children: ` (${variantStatus[variant]})`
161
+ }),
162
+ /* @__PURE__ */ jsxs("span", {
163
+ className: "tw:whitespace-nowrap",
164
+ children: ["⁠", /* @__PURE__ */ jsx(ChevronDown, { className: cn("tw:ml-1.5 tw:inline-block tw:size-3.5 tw:align-middle tw:transition-transform", isExpanded && "tw:rotate-180") })]
165
+ })
166
+ ]
118
167
  })]
119
168
  });
120
169
  };
@@ -189,20 +238,236 @@ const AnswerSummary = ({ items, variant = "success", noAnswerLabel = "No answer"
189
238
  });
190
239
  };
191
240
  //#endregion
241
+ //#region src/blocks/AIKit/ChatInlineIcon.tsx
242
+ /**
243
+ * The Lucide component each `icon:<name>` token draws.
244
+ *
245
+ * - Names are FontAwesome-solid ones, published as `CHAT_INLINE_ICON_NAMES`.
246
+ * - The `satisfies` is the drift guard: a name the prompt teaches and this map lacks fails to compile.
247
+ * - Read through `Object.hasOwn`: `icon:constructor` would otherwise hit `Object.prototype`.
248
+ */
249
+ const ICON_REGISTRY = {
250
+ "alert-circle": AlertCircle,
251
+ "arrow-down": ArrowDown,
252
+ "arrow-left": ArrowLeft,
253
+ "arrow-right": ArrowRight,
254
+ "arrow-rotate-back": RotateCcw,
255
+ "arrow-rotate-left": RotateCcw,
256
+ "arrow-rotate-right": RotateCw,
257
+ "arrow-up": ArrowUp,
258
+ "arrow-up-right-from-square": ExternalLink,
259
+ "arrows-rotate": RefreshCw,
260
+ analytics: BarChart3,
261
+ ban: Ban,
262
+ bell: Bell,
263
+ bug: Bug,
264
+ calendar: Calendar,
265
+ changes: FilePen,
266
+ "chart-line": LineChart,
267
+ check: Check,
268
+ "check-circle": CircleCheck,
269
+ "chevron-down": ChevronDown,
270
+ "chevron-left": ChevronLeft,
271
+ "chevron-right": ChevronRight,
272
+ "chevron-up": ChevronUp,
273
+ circle: Circle,
274
+ "circle-check": CircleCheck,
275
+ "circle-exclamation": CircleAlert,
276
+ "circle-info": Info,
277
+ "circle-pause": CirclePause,
278
+ "circle-play": CirclePlay,
279
+ "circle-plus": CirclePlus,
280
+ "circle-question": CircleHelp,
281
+ "circle-stop": CircleStop,
282
+ "circle-xmark": CircleX,
283
+ clock: Clock,
284
+ "clock-rotate-left": History,
285
+ "code-branch": GitBranch,
286
+ "code-merge": GitMerge,
287
+ "code-pull-request": GitPullRequest,
288
+ cog: Cog,
289
+ configuration: Settings,
290
+ copy: Copy,
291
+ database: Database,
292
+ "diagram-project": Workflow,
293
+ download: Download,
294
+ ellipsis: Ellipsis,
295
+ envelope: Mail,
296
+ "exclamation-circle": CircleAlert,
297
+ "exclamation-triangle": TriangleAlert,
298
+ eye: Eye,
299
+ file: File,
300
+ "file-lines": FileText,
301
+ flag: Flag,
302
+ folder: Folder,
303
+ gauge: Gauge,
304
+ gear: Settings,
305
+ globe: Globe,
306
+ hand: Hand,
307
+ "hourglass-half": Hourglass,
308
+ "info-circle": Info,
309
+ key: Key,
310
+ "layer-group": Layers,
311
+ link: Link,
312
+ "list-check": ListChecks,
313
+ "list-ul": List,
314
+ lock: Lock,
315
+ "magnifying-glass": Search,
316
+ minus: Minus,
317
+ "paper-plane-top": Send,
318
+ pen: Pencil,
319
+ play: Play,
320
+ plus: Plus,
321
+ refresh: RefreshCw,
322
+ rocket: Rocket,
323
+ save: Save,
324
+ "save-changes": Save,
325
+ search: Search,
326
+ spinner: Loader2,
327
+ sparkles: Sparkles,
328
+ star: Star,
329
+ stop: CircleStop,
330
+ table: Table,
331
+ "thumbs-down": ThumbsDown,
332
+ "thumbs-up": ThumbsUp,
333
+ transformation: WandSparkles,
334
+ trash: Trash2,
335
+ "triangle-exclamation": TriangleAlert,
336
+ upload: Upload,
337
+ user: User,
338
+ "user-group": Users,
339
+ warning: TriangleAlert,
340
+ warehouse: Warehouse,
341
+ xmark: X,
342
+ zap: Zap
343
+ };
344
+ /**
345
+ * Extra classes a single name needs.
346
+ *
347
+ * - `spinner` spins (per `MAINTAINING.md`): a still `Loader2` reads as a broken ring.
348
+ * - Read through `Object.hasOwn`, like the registry.
349
+ */
350
+ const ICON_CLASSES = { spinner: "tw:animate-spin" };
351
+ /**
352
+ * A whole `icon:<name>` token and nothing else.
353
+ *
354
+ * - Must match the name shape `remarkIconSyntax` (`@keboola/kai-chat`) accepts.
355
+ * - Anchored, so inline code like `` `icon: database` `` or `` `icon:` `` stays code.
356
+ */
357
+ const TOKEN = /^icon:([a-z][a-z0-9-]*)$/;
358
+ /** Built once: an answer is re-parsed per streamed chunk, so `isArriving` runs per code node. */
359
+ const ICON_NAMES = Object.keys(ICON_REGISTRY);
360
+ /** Whether a name is a strict prefix of a registry name: `tabl` → `true`, `table-name` → `false`. */
361
+ const isArriving = (name) => ICON_NAMES.some((key) => key.length > name.length && key.startsWith(name));
362
+ /**
363
+ * The icon name in a code node's text, if the text is a token — drawn, or still arriving.
364
+ *
365
+ * - An unknown name → `undefined`, so the call site's `<code>` fall-through keeps the text.
366
+ * - A prefix of a known name is a token still streaming; `<ChatInlineIcon />` draws it blank.
367
+ * - A name that is both (`save`, of `save-changes`) is drawn now.
368
+ */
369
+ const getChatInlineIconName = (text) => {
370
+ const name = TOKEN.exec(text)?.[1];
371
+ if (name === void 0) return void 0;
372
+ return Object.hasOwn(ICON_REGISTRY, name) || isArriving(name) ? name : void 0;
373
+ };
374
+ /**
375
+ * One inline `icon:<name>` token, drawn at the size of the text it leads.
376
+ *
377
+ * - An unknown name (a token still arriving) renders nothing.
378
+ * - `mr` widens the single source space, which reads as cramped beside a glyph.
379
+ * - The heavier stroke holds its own beside a bold heading.
380
+ * - `aria-hidden`: the token's text is removed, so the glyph has no label to announce.
381
+ */
382
+ const ChatInlineIcon = ({ name }) => {
383
+ const Icon = Object.hasOwn(ICON_REGISTRY, name) ? ICON_REGISTRY[name] : void 0;
384
+ if (Icon === void 0) return null;
385
+ return /* @__PURE__ */ jsx(Icon, {
386
+ "aria-hidden": true,
387
+ className: cn("tw:mr-[0.15em] tw:inline-block tw:size-[1em] tw:shrink-0 tw:align-[-0.125em] tw:text-muted-foreground", Object.hasOwn(ICON_CLASSES, name) ? ICON_CLASSES[name] : void 0),
388
+ strokeWidth: 2.25
389
+ });
390
+ };
391
+ //#endregion
392
+ //#region src/blocks/AIKit/FileDownloadChip.tsx
393
+ /**
394
+ * A file the agent wrote, offered inside its own answer.
395
+ *
396
+ * - The whole chip is the control: a small icon beside a truncating filename is hard to hit.
397
+ * - Presentation only — the host fetches and saves, through its own auth.
398
+ */
399
+ const FileDownloadChip = ({ fileName, filePath, size, isPending = false, onDownload, className }) => /* @__PURE__ */ jsxs(Button, {
400
+ variant: "secondary",
401
+ size: "small",
402
+ isLoading: isPending,
403
+ "aria-disabled": isPending,
404
+ "aria-label": `Download ${filePath ?? fileName}`,
405
+ title: filePath,
406
+ onClick: () => {
407
+ if (!isPending) onDownload();
408
+ },
409
+ className: cn("tw:max-w-full tw:justify-start tw:gap-2 tw:font-normal", className),
410
+ children: [
411
+ !isPending && /* @__PURE__ */ jsx(FileText, { className: "tw:size-4 tw:shrink-0 tw:text-muted-foreground" }),
412
+ /* @__PURE__ */ jsx("span", {
413
+ className: "tw:truncate",
414
+ children: fileName
415
+ }),
416
+ size !== void 0 && /* @__PURE__ */ jsx("span", {
417
+ className: "tw:shrink-0 tw:text-xs tw:text-muted-foreground",
418
+ children: size
419
+ }),
420
+ !isPending && /* @__PURE__ */ jsx(Download, { className: "tw:size-4 tw:shrink-0" })
421
+ ]
422
+ });
423
+ //#endregion
424
+ //#region src/blocks/AIKit/InlineStepGroup.tsx
425
+ /** The surface colour, as the custom property the step icons mask against. */
426
+ const surfaceStyle = (surface) => ({ "--inline-step-surface": surface });
427
+ /**
428
+ * A collapsible run of agent steps behind one summary line; rows arrive as children.
429
+ *
430
+ * - Connector sits at the icon centre line (`pl-5` + half a `size-5` box), drawn once so it
431
+ * survives icon-less rows.
432
+ * - Animates `grid-template-rows`; children stay mounted while closed.
433
+ * - `role="group"`, not a `region` landmark: dozens per transcript would drown real landmarks.
434
+ */
435
+ const InlineStepGroup = ({ label, variant = "success", isExpanded, onToggle, surface = "rgb(var(--background))", "aria-label": ariaLabel, "data-testid": testId, className, children }) => /* @__PURE__ */ jsxs("section", {
436
+ role: "group",
437
+ className: cn("tw:flex tw:flex-col", className),
438
+ "aria-label": ariaLabel,
439
+ "data-testid": testId,
440
+ children: [/* @__PURE__ */ jsx(CollapsibleStepHeader, {
441
+ isExpanded,
442
+ onToggle,
443
+ label,
444
+ variant
445
+ }), /* @__PURE__ */ jsx("div", {
446
+ className: cn("tw:grid tw:transition-[grid-template-rows] tw:duration-200 tw:ease-out tw:motion-reduce:transition-none", isExpanded ? "tw:grid-rows-[1fr]" : "tw:grid-rows-[0fr]"),
447
+ children: /* @__PURE__ */ jsx("div", {
448
+ className: "tw:min-h-0 tw:overflow-hidden",
449
+ inert: !isExpanded,
450
+ "aria-hidden": isExpanded ? void 0 : true,
451
+ children: /* @__PURE__ */ jsxs("div", {
452
+ style: surfaceStyle(surface),
453
+ className: "tw:relative tw:flex tw:flex-col tw:gap-4 tw:pt-4 tw:pl-5",
454
+ children: [/* @__PURE__ */ jsx("span", {
455
+ "aria-hidden": "true",
456
+ className: "tw:pointer-events-none tw:absolute tw:top-4 tw:bottom-0 tw:left-[30px] tw:w-px tw:bg-border"
457
+ }), children]
458
+ })
459
+ })
460
+ })]
461
+ });
462
+ //#endregion
192
463
  //#region src/blocks/AIKit/DiagramBlock.tsx
193
464
  /**
194
465
  * One diagram block: a skeleton while its chunk loads, the fence source plus a retry if it fails.
195
466
  *
196
- * - `load` runs once per mount and once per press of the retry button. The loader drops its own
197
- * rejected promise, so every attempt is a fresh fetch.
198
- * - Recovery is a gesture, not a timer: nothing on the page can tell when a chunk became
199
- * reachable again, and a tab left open across a deploy points at a URL that is gone for good —
200
- * a background loop would retry that one forever.
201
- * - The failure is already logged by the loader, which knows the chunk's name.
202
- * - A new `load` resets the block: every fence renders this same component type, so a block that
203
- * switches dialect would otherwise keep drawing through the dialect it had before.
204
- * - Both the renderer and the loader are functions held in state, so they go in through the
205
- * setter form — React runs a bare function as a lazy initializer or an updater instead.
467
+ * - Each attempt is a fresh fetch; the loader drops its rejected promise and logs the failure.
468
+ * - Retry is manual: a chunk gone after a deploy never returns, so a timer would loop forever.
469
+ * - A new `load` resets the block, or a dialect switch keeps the previous renderer.
470
+ * - Functions in state go through the setter form, or React calls them.
206
471
  */
207
472
  const DiagramBlock = ({ load, code }) => {
208
473
  const [Diagram, setDiagram] = useState(null);
@@ -241,16 +506,12 @@ const DiagramBlock = ({ load, code }) => {
241
506
  //#endregion
242
507
  //#region src/blocks/AIKit/diagramChunk.ts
243
508
  /**
244
- * An on-demand diagram chunk — shared between mounts, and retryable.
509
+ * An on-demand diagram chunk, shared between mounts and retryable.
245
510
  *
246
- * - `lazy()` is deliberately not used here: it memoizes the settled import for the life of the
247
- * page, so one failed fetch (a dev server restarting, a stale tab after a deploy, a flaky
248
- * network) leaves every diagram in that tab rendering raw source until a full reload.
249
- * - A resolved import is kept, so the chunk is fetched once however many blocks mount.
250
- * - A failed one is cleared, so the next mount imports again. Same contract as
251
- * `getFlintRuntime()` one level down, inside `FlintChart`.
252
- * - The failure is logged here, where the chunk's name is known, so the swap to plain source is
253
- * never silent and a retry that fails again says so.
511
+ * - Not `lazy()`: it memoizes a failed import, stranding every diagram until a reload.
512
+ * - A resolved import is kept; a failed one is cleared so the next mount retries.
513
+ * - Same contract as `getFlintRuntime()` in `FlintChart`.
514
+ * - Failures are logged here, where the chunk's name is known.
254
515
  */
255
516
  const diagramChunk = (name, load) => {
256
517
  let pending = null;
@@ -267,7 +528,10 @@ const diagramChunk = (name, load) => {
267
528
  //#region src/blocks/AIKit/Markdown.tsx
268
529
  const loadMermaid = diagramChunk("MermaidDiagram", () => import("@keboola/design/mermaid").then((module) => module.MermaidDiagram));
269
530
  const loadFlint = diagramChunk("FlintChart", () => import("@keboola/design/flint").then((module) => module.FlintChart));
270
- const proseClass = "tw:prose tw:prose-sm tw:max-w-none tw:break-words tw:[&_pre]:bg-muted tw:[&_pre]:text-foreground tw:[&_:not(pre)>code]:bg-muted tw:[&_:not(pre)>code]:text-foreground tw:[&_:not(pre)>code]:rounded tw:[&_:not(pre)>code]:px-1 tw:[&_:not(pre)>code]:py-0.5 tw:[&_:not(pre)>code]:before:content-none tw:[&_:not(pre)>code]:after:content-none";
531
+ const PROSE_CLASS = {
532
+ answer: "tw:prose tw:prose-answer tw:prose-code-chip tw:break-words",
533
+ chrome: "tw:prose tw:prose-sm tw:prose-code-chip tw:break-words"
534
+ };
271
535
  const getText = (node) => {
272
536
  if (typeof node === "string") return node;
273
537
  if (typeof node === "number") return String(node);
@@ -282,25 +546,14 @@ const getLanguage = (element) => {
282
546
  if (typeof props.className !== "string") return void 0;
283
547
  return props.className.match(/language-(\S+)/)?.[1];
284
548
  };
285
- /**
286
- * The plugins this renderer always runs.
287
- *
288
- * - GFM is part of its contract: tables route through the design `Table`, and autolinks and
289
- * task lists are what an assistant answer is written in.
290
- * - A caller's own plugins are appended to these, never substituted for them.
291
- */
549
+ /** Always run; a caller's plugins are appended, never substituted. */
292
550
  const baseRemarkPlugins = [remarkGfm];
293
551
  /**
294
552
  * Fence language → the on-demand chunk that draws it.
295
553
  *
296
- * - Both dialects are the agent's, not this package's: kai-agent's prompt tells the model to
297
- * write ```mermaid for structure and ```flint for quantitative data, so a chat that renders
298
- * one and not the other drops output the agent was instructed to produce.
299
- * - `flint-chart` is an alias — it is the fence tag flint's own docs use, so a model emits it
300
- * unprompted often enough to matter. `markdownComponents.tsx` in kbc-ui carries the same pair.
301
- * - Read through `Object.hasOwn`, never by plain index: a fence tagged ```constructor or
302
- * ```valueOf otherwise answers with an `Object.prototype` member, which is truthy, and calling
303
- * it as a loader throws — taking the whole message subtree down with it.
554
+ * - Dialects come from kai-agent's prompt; keep in sync with kbc-ui `markdownComponents.tsx`.
555
+ * - `flint-chart`: alias models emit unprompted.
556
+ * - Read via `Object.hasOwn`: ```constructor would otherwise hit `Object.prototype` and throw.
304
557
  */
305
558
  const DIAGRAM_CHUNKS = {
306
559
  mermaid: loadMermaid,
@@ -310,14 +563,32 @@ const DIAGRAM_CHUNKS = {
310
563
  /**
311
564
  * The fence languages this renderer draws instead of printing.
312
565
  *
313
- * - For a caller that streams: a diagram mounts a lazily loaded chunk, so an answer arriving a
314
- * token at a time has to keep a fence that is still open an ordinary code block, or every
315
- * keystroke fetches the chunk. Sharing the list is what keeps that hold-back from missing a
316
- * dialect this map has and the caller does not.
317
- * - Frozen, because it is that shared contract: a consumer that pushed onto it would change how
318
- * every other app in the same bundle holds a fence back.
566
+ * - Streaming callers hold an open fence back as plain code, or every keystroke fetches the chunk.
567
+ * - Frozen: it is shared across every app in the bundle.
319
568
  */
320
569
  const DIAGRAM_LANGUAGES = Object.freeze(Object.keys(DIAGRAM_CHUNKS));
570
+ /**
571
+ * Whether the `code` being rendered sits inside a fenced block.
572
+ *
573
+ * - Set by `pre`: a fence without info string has no `language-…` class, like inline code.
574
+ */
575
+ const CodeBlockContext = createContext(false);
576
+ /**
577
+ * The `code` renderer: an inline `icon:<name>` token becomes the icon it names.
578
+ *
579
+ * - Fenced blocks never swap.
580
+ * - Unknown names stay code; a name still streaming renders nothing.
581
+ */
582
+ const MarkdownCode = ({ children, className, ...props }) => {
583
+ const { node: _node, ...rest } = props;
584
+ const name = use(CodeBlockContext) ? void 0 : getChatInlineIconName(getText(children));
585
+ if (name !== void 0) return /* @__PURE__ */ jsx(ChatInlineIcon, { name });
586
+ return /* @__PURE__ */ jsx("code", {
587
+ className,
588
+ ...rest,
589
+ children
590
+ });
591
+ };
321
592
  const baseComponents = {
322
593
  pre({ children, ...props }) {
323
594
  const child = Array.isArray(children) ? children[0] : children;
@@ -344,10 +615,14 @@ const baseComponents = {
344
615
  })
345
616
  }), /* @__PURE__ */ jsx("pre", {
346
617
  ...rest,
347
- children
618
+ children: /* @__PURE__ */ jsx(CodeBlockContext, {
619
+ value: true,
620
+ children
621
+ })
348
622
  })]
349
623
  });
350
624
  },
625
+ code: MarkdownCode,
351
626
  a({ children, href, ...props }) {
352
627
  const { node: _node, ...rest } = props;
353
628
  const isExternal = !!href && /^https?:\/\//.test(href);
@@ -365,7 +640,7 @@ const baseComponents = {
365
640
  const { node: _node, ...rest } = props;
366
641
  return /* @__PURE__ */ jsx("div", {
367
642
  className: "tw:not-prose tw:my-4",
368
- children: /* @__PURE__ */ jsx(Table, {
643
+ children: /* @__PURE__ */ jsx(Table$1, {
369
644
  bordered: true,
370
645
  className: cn("tw:!mb-0", className),
371
646
  ...rest
@@ -374,74 +649,80 @@ const baseComponents = {
374
649
  },
375
650
  thead(props) {
376
651
  const { node: _node, ...rest } = props;
377
- return /* @__PURE__ */ jsx(Table.Header, { ...rest });
652
+ return /* @__PURE__ */ jsx(Table$1.Header, { ...rest });
378
653
  },
379
654
  tbody(props) {
380
655
  const { node: _node, ...rest } = props;
381
- return /* @__PURE__ */ jsx(Table.Body, { ...rest });
656
+ return /* @__PURE__ */ jsx(Table$1.Body, { ...rest });
382
657
  },
383
658
  tr(props) {
384
659
  const { node: _node, ...rest } = props;
385
- return /* @__PURE__ */ jsx(Table.Row, { ...rest });
660
+ return /* @__PURE__ */ jsx(Table$1.Row, { ...rest });
386
661
  },
387
662
  th(props) {
388
663
  const { node: _node, ...rest } = props;
389
- return /* @__PURE__ */ jsx(Table.Head, { ...rest });
664
+ return /* @__PURE__ */ jsx(Table$1.Head, { ...rest });
390
665
  },
391
666
  td(props) {
392
667
  const { node: _node, ...rest } = props;
393
- return /* @__PURE__ */ jsx(Table.Cell, { ...rest });
668
+ return /* @__PURE__ */ jsx(Table$1.Cell, { ...rest });
394
669
  }
395
670
  };
396
671
  /**
397
- * Read-only GFM Markdown renderer with design-token typography. Pair with
398
- * `MessageBubble` to render an assistant message body. Code blocks expose a
399
- * copy button, so mount a `TooltipProvider` once at the app root.
672
+ * The prose surface an answer is drawn on.
673
+ *
674
+ * - Wrap all `Block`s of one answer in one `Root`, so `:first-child`/`:last-child` span the reply.
675
+ * - `data-prose` is `MessageBubble`'s colour hook; Tailwind can't target `tw:prose` directly.
676
+ * - Spacing overrides need `!`: `tw:prose-answer` rules are `(0,2,1)`, above `[&_p]:mb-1`.
400
677
  */
401
- const Markdown = ({ children, className, remarkPlugins, components: componentOverrides }) => {
402
- return /* @__PURE__ */ jsx("div", {
403
- "data-prose": true,
404
- className: cn(proseClass, className),
405
- children: /* @__PURE__ */ jsx(ReactMarkdown, {
406
- remarkPlugins: remarkPlugins === void 0 ? baseRemarkPlugins : [...baseRemarkPlugins, ...remarkPlugins],
407
- components: componentOverrides === void 0 ? baseComponents : {
408
- ...baseComponents,
409
- ...componentOverrides
410
- },
411
- children
412
- })
413
- });
414
- };
678
+ const MarkdownRoot = ({ children, className, rhythm = "answer" }) => /* @__PURE__ */ jsx("div", {
679
+ "data-prose": true,
680
+ className: cn(PROSE_CLASS[rhythm], className),
681
+ children
682
+ });
683
+ /** One parsed piece of an answer, with no surface of its own; memoise at the call site. */
684
+ const MarkdownBlock = ({ children, remarkPlugins, components: componentOverrides }) => /* @__PURE__ */ jsx(ReactMarkdown, {
685
+ remarkPlugins: remarkPlugins === void 0 ? baseRemarkPlugins : [...baseRemarkPlugins, ...remarkPlugins],
686
+ components: componentOverrides === void 0 ? baseComponents : {
687
+ ...baseComponents,
688
+ ...componentOverrides
689
+ },
690
+ children
691
+ });
692
+ /**
693
+ * Read-only GFM Markdown renderer with design-token typography.
694
+ *
695
+ * - Needs a `TooltipProvider` at the app root (code copy button).
696
+ * - Pass `rhythm="chrome"` for content a model did not write.
697
+ */
698
+ const Markdown = ({ className, rhythm, ...blockProps }) => /* @__PURE__ */ jsx(MarkdownRoot, {
699
+ className,
700
+ rhythm,
701
+ children: /* @__PURE__ */ jsx(MarkdownBlock, { ...blockProps })
702
+ });
703
+ Markdown.Root = MarkdownRoot;
704
+ Markdown.Block = MarkdownBlock;
415
705
  //#endregion
416
706
  //#region src/blocks/AIKit/MarkdownTable.tsx
417
707
  /** How much wider than its column a table has to be before the column is the wrong surface. */
418
708
  const EXPAND_RATIO = 1.5;
419
709
  /**
420
- * The token the host paints the table on, which is the colour the fade has to end in.
710
+ * The fade's end colour — must match the host's surface, or it draws a strip over the data.
421
711
  *
422
- * - A gradient hides the cut-off cells by ending in the surface behind them. End it in any other
423
- * token and it draws a contrasting strip over the data instead of hiding it.
424
- * - Full class strings, not a composed `tw:from-${token}`: Tailwind reads literals.
712
+ * - Full class strings: Tailwind reads literals.
425
713
  */
426
714
  const FADE_SURFACE = {
427
715
  card: "tw:from-card",
428
716
  background: "tw:from-background"
429
717
  };
430
718
  /**
431
- * A table in an answer, with the fact that it is cut off on the right said out loud.
719
+ * A table in an answer that shows when it is cut off on the right.
432
720
  *
433
- * - `overflow-x: auto` scrolls silently, so nothing on screen says there is more to the right.
434
- * - The controls sit in a rail above the grid, never over the header row or the last row — the
435
- * data a reader reaches for them to get at. The rail holds its height, so revealing hover
436
- * controls or crossing the ratio cannot shift the table under the pointer.
437
- * - The fade marks the cut edge only while content remains, so it never reads as a border.
438
- * - A painted gradient rather than the `tw:scroll-fade-x` mask, which needs scroll-driven
439
- * animations: the build floor is `baseline-widely-available` (Safari 16, Firefox 104), and there
440
- * the utility either fades both edges of a table that fits or, behind the `supports-` guard
441
- * `PageLayout` uses, says nothing at all — which is the state this component exists to end. The
442
- * mask also has to sit on the scrolling element, and that is `Table`'s own container, not ours.
443
- * - Past `EXPAND_RATIO` the fade is joined by `onExpand`'s action, drawn without waiting for a
444
- * hover: it reports that content is cut off, which the reader needs before going looking.
721
+ * - Controls sit in a fixed-height rail above the grid, so they never cover rows or shift them.
722
+ * - The fade shows only while content remains to the right.
723
+ * - A painted gradient, not `tw:scroll-fade-x`: that needs scroll-driven animations, which the
724
+ * `baseline-widely-available` build floor lacks, and must sit on `Table`'s own container.
725
+ * - Past `EXPAND_RATIO` the expand action shows without hover.
445
726
  */
446
727
  const MarkdownTable = ({ children, actions, onExpand, surface = "card", className }) => {
447
728
  const frameRef = useRef(null);
@@ -551,7 +832,7 @@ const contentClasses = cva([
551
832
  "tw:py-2",
552
833
  "tw:rounded-xl",
553
834
  "tw:overflow-hidden",
554
- "tw:break-anywhere"
835
+ "tw:wrap-anywhere"
555
836
  ]
556
837
  } },
557
838
  defaultVariants: { variant: "assistant" }
@@ -896,6 +1177,58 @@ const PlanRewritingIndicator = ({ label = "Rewriting the plan..." }) => /* @__PU
896
1177
  })]
897
1178
  });
898
1179
  //#endregion
1180
+ //#region src/blocks/AIKit/constants.ts
1181
+ /**
1182
+ * Names the container query `PromptInput`'s `inline` row reads to fold into the stacked layout.
1183
+ *
1184
+ * It has to sit on an **ancestor**: a container query matches descendants only, so the field that
1185
+ * would read it cannot name it, and its own wrapper is the width the fold changes. A host that
1186
+ * never names it keeps the one-line row at every width.
1187
+ */
1188
+ const PROMPT_INPUT_CONTAINER = "tw:@container/composer";
1189
+ //#endregion
1190
+ //#region src/blocks/AIKit/AnimatedHeight.tsx
1191
+ /**
1192
+ * A box whose height eases to whatever its content measures.
1193
+ *
1194
+ * - Content is measured with a `ResizeObserver`; without one (jsdom) the box is plain `auto`.
1195
+ * - The first measurement lands without a transition, so mounting with content does not grow in.
1196
+ * - Overflow is clipped only while the height moves, so focus rings are not cut off at rest.
1197
+ * - `prefers-reduced-motion` drops the transition.
1198
+ */
1199
+ const AnimatedHeight = ({ children, className }) => {
1200
+ const contentRef = useRef(null);
1201
+ const heightRef = useRef(void 0);
1202
+ const [height, setHeight] = useState();
1203
+ const [isAnimating, setIsAnimating] = useState(false);
1204
+ useLayoutEffect(() => {
1205
+ const node = contentRef.current;
1206
+ if (!node || typeof ResizeObserver === "undefined") return;
1207
+ const observer = new ResizeObserver(() => {
1208
+ const next = node.offsetHeight;
1209
+ const prev = heightRef.current;
1210
+ if (prev !== void 0 && prev !== next && hasMotion()) setIsAnimating(true);
1211
+ heightRef.current = next;
1212
+ setHeight(next);
1213
+ });
1214
+ observer.observe(node);
1215
+ return () => observer.disconnect();
1216
+ }, []);
1217
+ const handleTransitionEnd = (event) => {
1218
+ if (event.target !== event.currentTarget || event.propertyName !== "height") return;
1219
+ setIsAnimating(false);
1220
+ };
1221
+ return /* @__PURE__ */ jsx("div", {
1222
+ style: { height },
1223
+ onTransitionEnd: handleTransitionEnd,
1224
+ className: cn("tw:transition-[height] tw:duration-200 tw:ease-out tw:motion-reduce:transition-none", isAnimating && "tw:overflow-hidden", className),
1225
+ children: /* @__PURE__ */ jsx("div", {
1226
+ ref: contentRef,
1227
+ children
1228
+ })
1229
+ });
1230
+ };
1231
+ //#endregion
899
1232
  //#region src/blocks/AIKit/PromptInputAction.tsx
900
1233
  const PromptInputAction = ({ ref, onMouseDown, ...rest }) => {
901
1234
  const handleOnMouseDown = (event) => {
@@ -910,39 +1243,152 @@ const PromptInputAction = ({ ref, onMouseDown, ...rest }) => {
910
1243
  };
911
1244
  //#endregion
912
1245
  //#region src/blocks/AIKit/PromptInputCommands.tsx
913
- const PromptInputCommands = ({ items, open, onSelect, filterValue, children }) => {
914
- const filtered = filterValue ? items.filter((item) => item.label.toLowerCase().includes(filterValue.toLowerCase()) || item.value.toLowerCase().includes(filterValue.toLowerCase())) : items;
1246
+ /** What the menu needs above or below the composer before it will open on that side. */
1247
+ const MENU_HEIGHT = 440;
1248
+ /** As tall as the list ever gets, however much room there is. */
1249
+ const MENU_MAX_HEIGHT = 416;
1250
+ /** Space kept from the measured edge; `POPUP_CHROME` is the popup's own border and padding. */
1251
+ const MENU_GUTTER = 16;
1252
+ const POPUP_CHROME = 10;
1253
+ /**
1254
+ * The rows a typed filter leaves.
1255
+ *
1256
+ * - An empty filter keeps everything.
1257
+ * - A row matches on its label or its value.
1258
+ * - Matching nothing falls back to the action rows.
1259
+ */
1260
+ const matchesFilter = (items, filterValue) => {
1261
+ if (!filterValue) return items;
1262
+ const query = filterValue.toLowerCase();
1263
+ const matched = items.filter((item) => item.label.toLowerCase().includes(query) || item.value.toLowerCase().includes(query));
1264
+ return matched.length > 0 ? matched : items.filter((item) => item.onSelect !== void 0);
1265
+ };
1266
+ /**
1267
+ * The band the menu has to stay inside: the window, narrowed by every ancestor that clips.
1268
+ *
1269
+ * - The chat sidebar's panel clips well below the window's top edge.
1270
+ */
1271
+ const CLIPS = /* @__PURE__ */ new Set([
1272
+ "hidden",
1273
+ "auto",
1274
+ "scroll",
1275
+ "clip",
1276
+ "overlay"
1277
+ ]);
1278
+ const clipBand = (node) => {
1279
+ let top = 0;
1280
+ let bottom = window.innerHeight;
1281
+ let parent = node.parentElement;
1282
+ while (parent) {
1283
+ const { overflowY, overflowX } = window.getComputedStyle(parent);
1284
+ if (CLIPS.has(overflowY) || CLIPS.has(overflowX)) {
1285
+ const box = parent.getBoundingClientRect();
1286
+ top = Math.max(top, box.top);
1287
+ bottom = Math.min(bottom, box.bottom);
1288
+ }
1289
+ parent = parent.parentElement;
1290
+ }
1291
+ return {
1292
+ top,
1293
+ bottom
1294
+ };
1295
+ };
1296
+ const PromptInputCommands = ({ items, open, onSelect, filterValue, emptyText = "No commands found", panel, groupAction, groupHeading, children }) => {
1297
+ const filtered = matchesFilter(items, filterValue);
1298
+ const [highlighted, setHighlighted] = useState();
1299
+ const [wasOpen, setWasOpen] = useState(open);
1300
+ if (open !== wasOpen) {
1301
+ setWasOpen(open);
1302
+ if (open) setHighlighted(void 0);
1303
+ }
1304
+ /**
1305
+ * Which side the menu opens on.
1306
+ *
1307
+ * - Above by default; below when there is not room above and more room below.
1308
+ * - Re-measured while open: the composer and the transcript above it move.
1309
+ */
1310
+ const rootRef = useRef(null);
1311
+ const [below, setBelow] = useState(false);
1312
+ const [maxHeight, setMaxHeight] = useState(MENU_MAX_HEIGHT);
1313
+ const measure = useCallback(() => {
1314
+ const node = rootRef.current;
1315
+ const box = node?.getBoundingClientRect();
1316
+ if (!node || !box) return;
1317
+ const band = clipBand(node);
1318
+ const above = box.top - band.top;
1319
+ const under = band.bottom - box.bottom;
1320
+ const openBelow = above < MENU_HEIGHT && under > above;
1321
+ setBelow(openBelow);
1322
+ setMaxHeight(Math.max(0, Math.min(MENU_MAX_HEIGHT, (openBelow ? under : above) - MENU_GUTTER - POPUP_CHROME)));
1323
+ }, []);
1324
+ const attachRoot = useCallback((node) => {
1325
+ rootRef.current = node;
1326
+ if (node) measure();
1327
+ }, [measure]);
1328
+ useEffect(() => {
1329
+ if (!open) return;
1330
+ const node = rootRef.current;
1331
+ const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
1332
+ if (node) observer?.observe(node);
1333
+ window.addEventListener("resize", measure);
1334
+ window.addEventListener("scroll", measure, true);
1335
+ return () => {
1336
+ observer?.disconnect();
1337
+ window.removeEventListener("resize", measure);
1338
+ window.removeEventListener("scroll", measure, true);
1339
+ };
1340
+ }, [open, measure]);
1341
+ const highlightedValue = filtered.some((item) => item.value === highlighted) ? highlighted : filtered[0]?.value;
915
1342
  const groups = filtered.reduce((acc, item) => {
916
1343
  const group = acc[item.group] ?? [];
917
1344
  group.push(item);
918
1345
  acc[item.group] = group;
919
1346
  return acc;
920
1347
  }, {});
1348
+ const menuStyle = { "--prompt-menu-max-h": `${maxHeight}px` };
921
1349
  return /* @__PURE__ */ jsxs(Command, {
1350
+ ref: attachRoot,
922
1351
  loop: true,
923
1352
  className: "tw:relative",
924
1353
  shouldFilter: false,
1354
+ value: highlightedValue ?? "",
1355
+ onValueChange: setHighlighted,
925
1356
  children: [open && /* @__PURE__ */ jsx("div", {
926
- className: cn("tw:absolute tw:bottom-full tw:left-0 tw:right-0 tw:z-50 tw:mb-1", "tw:rounded-md tw:border tw:border-border tw:bg-popover tw:text-popover-foreground tw:shadow-lg"),
927
- children: filtered.length === 0 ? /* @__PURE__ */ jsx("div", {
928
- className: "tw:px-4 tw:py-3 tw:text-center tw:text-sm tw:text-muted-foreground",
929
- children: "No commands found"
1357
+ className: cn("tw:absolute tw:left-0 tw:z-50 tw:w-full tw:max-w-lg", below ? "tw:top-full tw:mt-1" : "tw:bottom-full tw:mb-1", "tw:rounded-[14px] tw:border tw:border-border tw:bg-popover tw:text-popover-foreground tw:shadow-lg", "tw:p-1"),
1358
+ style: menuStyle,
1359
+ children: panel ? /* @__PURE__ */ jsx("div", {
1360
+ className: "tw:p-3",
1361
+ children: panel
1362
+ }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", {
1363
+ className: "tw:py-3 tw:pl-4 tw:text-center tw:text-sm tw:text-muted-foreground",
1364
+ children: emptyText
930
1365
  }) : /* @__PURE__ */ jsx(Command.List, {
931
- viewPortClassName: "tw:max-h-80",
932
- children: Object.entries(groups).map(([groupName, groupItems]) => /* @__PURE__ */ jsx(Command.Group, {
933
- heading: groupName,
934
- children: groupItems.map((item) => /* @__PURE__ */ jsx(Command.Item, {
1366
+ className: "tw:group-data-[variant=argo]/command:px-1 tw:group-data-[variant=argo]/command:pb-1",
1367
+ viewPortClassName: "tw:max-h-[var(--prompt-menu-max-h)] tw:[&>div]:!block",
1368
+ children: Object.entries(groups).map(([groupName, groupItems], index) => /* @__PURE__ */ jsx(Command.Group, {
1369
+ heading: groupName ? /* @__PURE__ */ jsxs("span", {
1370
+ className: "tw:flex tw:items-center tw:justify-between tw:gap-2",
1371
+ children: [/* @__PURE__ */ jsx("span", {
1372
+ className: "tw:min-w-0 tw:truncate",
1373
+ children: groupHeading?.(groupName) ?? groupName
1374
+ }), groupAction?.(groupName)]
1375
+ }) : void 0,
1376
+ className: cn("tw:[&_[cmdk-group-heading]]:normal-case", "tw:[&_[cmdk-group-heading]]:tracking-normal", "tw:[&_[cmdk-group-heading]]:border-b-0", "tw:[&_[cmdk-group-heading]]:!py-0", "tw:[&_[cmdk-group-heading]]:mt-2", "tw:[&_[cmdk-group-heading]]:mb-1", "tw:[&_[cmdk-group-heading]]:pl-2", "tw:[&_[cmdk-group-heading]]:text-xs", index > 0 && "tw:mt-3"),
1377
+ children: groupItems.map((item) => /* @__PURE__ */ jsxs(Command.Item, {
935
1378
  value: item.value,
936
- icon: item.icon,
937
- onSelect: () => onSelect(item.value),
938
- children: /* @__PURE__ */ jsxs("div", {
1379
+ className: "tw:w-full tw:min-w-0 tw:rounded-md",
1380
+ onSelect: () => onSelect(item),
1381
+ children: [item.icon, /* @__PURE__ */ jsxs("div", {
939
1382
  className: "tw:flex tw:min-w-0 tw:flex-1 tw:flex-col",
940
- children: [/* @__PURE__ */ jsx("span", { children: item.label }), item.description && /* @__PURE__ */ jsx(Truncated, {
1383
+ children: [item.content ?? /* @__PURE__ */ jsx("span", {
1384
+ className: "tw:truncate",
1385
+ children: item.label
1386
+ }), item.description && /* @__PURE__ */ jsx(Truncated, {
941
1387
  text: item.description,
942
1388
  twoLines: true,
943
1389
  className: "tw:text-xs tw:text-muted-foreground"
944
1390
  })]
945
- })
1391
+ })]
946
1392
  }, item.value))
947
1393
  }, groupName))
948
1394
  })
@@ -950,6 +1396,27 @@ const PromptInputCommands = ({ items, open, onSelect, filterValue, children }) =
950
1396
  });
951
1397
  };
952
1398
  //#endregion
1399
+ //#region src/blocks/AIKit/PromptInputMenuTrigger.tsx
1400
+ /**
1401
+ * The composer's "add to message" button.
1402
+ *
1403
+ * - One glyph for both states: a plus rotated 45° reads as a close cross, so nothing swaps.
1404
+ * - `aria-expanded` mirrors `open`; the accessible name changes with it.
1405
+ * - Wrapped in `PromptInputAction` so a click does not hand focus to the textarea.
1406
+ */
1407
+ const PromptInputMenuTrigger = ({ open = false, large = false, className, ref, ...props }) => /* @__PURE__ */ jsx(PromptInputAction, { children: /* @__PURE__ */ jsx(Button, {
1408
+ ref,
1409
+ type: "button",
1410
+ size: large ? "icon" : "icon-sm",
1411
+ variant: "invisible",
1412
+ "aria-expanded": open,
1413
+ "aria-label": open ? "Close menu" : "Add to message",
1414
+ "data-testid": "prompt-input-menu-trigger",
1415
+ className: cn("tw:rounded-full", "tw:hover:not-disabled:bg-muted tw:hover:not-disabled:text-foreground tw:hover:not-disabled:border-transparent", "tw:aria-expanded:bg-muted", className),
1416
+ ...props,
1417
+ children: /* @__PURE__ */ jsx(Plus, { className: cn(large ? "tw:size-5" : "tw:size-4", "tw:transition-transform tw:duration-300 tw:ease-out tw:motion-reduce:transition-none", open && "tw:rotate-135") })
1418
+ }) });
1419
+ //#endregion
953
1420
  //#region src/blocks/AIKit/PromptInputSubmit.tsx
954
1421
  const ARIA_LABEL_BY_STATUS = {
955
1422
  ready: "Send message",
@@ -996,6 +1463,42 @@ const CMDK_HIJACKED_KEYS = /* @__PURE__ */ new Set([
996
1463
  "Enter"
997
1464
  ]);
998
1465
  const isCmdkNavigation = (event) => event.key !== "Enter" || !(event.metaKey || event.ctrlKey || event.altKey);
1466
+ /**
1467
+ * The `@token` the caret sits at the end of, if any.
1468
+ *
1469
+ * - `@` has to open a word: it must start the value or follow whitespace.
1470
+ * - The token holds no whitespace or second `@` and runs past the caret, so a mid-word pick takes the word.
1471
+ * - `start` indexes the `@` itself, so replacing `[start, end)` removes the token.
1472
+ */
1473
+ const findMentionToken = (value, caret) => {
1474
+ const before = value.slice(0, caret);
1475
+ const match = /(?:^|\s)@([^\s@]*)$/.exec(before);
1476
+ if (!match) return null;
1477
+ const typed = match[1] ?? "";
1478
+ const tail = /^[^\s@]*/.exec(value.slice(caret))?.[0] ?? "";
1479
+ return {
1480
+ start: caret - typed.length - 1,
1481
+ end: caret + tail.length,
1482
+ query: typed + tail
1483
+ };
1484
+ };
1485
+ /**
1486
+ * The `/token` a message leads with, while the caret is still on it.
1487
+ *
1488
+ * - Only the first token: the Agent SDK expands a skill only at the start of a message.
1489
+ * - Text may follow it.
1490
+ * - The caret past the token closes the menu.
1491
+ */
1492
+ const findSlashToken = (value, caret) => {
1493
+ const match = /^\/(\S*)/.exec(value);
1494
+ if (!match) return null;
1495
+ const end = match[0].length;
1496
+ if (caret > end) return null;
1497
+ return {
1498
+ end,
1499
+ query: match[1] ?? ""
1500
+ };
1501
+ };
999
1502
  const promptInputVariants = cva([
1000
1503
  "tailwindcss-preflight",
1001
1504
  "tw:relative",
@@ -1024,11 +1527,7 @@ const promptInputVariants = cva([
1024
1527
  "tw:pt-3",
1025
1528
  "tw:pb-2"
1026
1529
  ],
1027
- inline: [
1028
- "tw:flex-row",
1029
- "tw:py-3",
1030
- "tw:items-center"
1031
- ]
1530
+ inline: ["tw:flex-col", "tw:py-3"]
1032
1531
  } }
1033
1532
  });
1034
1533
  const wrapperVariants = cva(null, {
@@ -1038,7 +1537,7 @@ const wrapperVariants = cva(null, {
1038
1537
  inline: ""
1039
1538
  } }
1040
1539
  });
1041
- const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, autoFocus, textareaRef: publishedRef, ...textareaProps }) => {
1540
+ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, attachments, className, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, commandsGroupAction, panel, mentions, onMentionSelect, mentionsEmptyText = "Nothing to attach", mentionsGroupHeading, mentionsMultiple = false, autoFocus, textareaRef: publishedRef, ...textareaProps }) => {
1042
1541
  const defaultMinRows = variant === "inline" ? 1 : 2;
1043
1542
  const isDisabled = (disabled || disableSubmit || !value.trim()) && status !== "streaming" && status !== "interrupted";
1044
1543
  const textareaId = useId();
@@ -1048,15 +1547,29 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
1048
1547
  if (publishedRef) publishedRef.current = node;
1049
1548
  }, [publishedRef]);
1050
1549
  const [dismissedValue, setDismissedValue] = useState(null);
1550
+ const [caret, setCaret] = useState(0);
1551
+ const [caretValue, setCaretValue] = useState(value);
1552
+ const moveCaret = (next, forValue) => {
1553
+ setCaret(next);
1554
+ setCaretValue(forValue);
1555
+ };
1556
+ if (value !== caretValue) moveCaret(value.length, value);
1051
1557
  const autoFocusRef = useRef(autoFocus);
1052
1558
  useEffect(() => {
1053
1559
  if (autoFocusRef.current) textareaRef.current?.focus({ preventScroll: true });
1054
1560
  }, []);
1055
1561
  if (dismissedValue !== null && value !== dismissedValue) setDismissedValue(null);
1056
1562
  const hasCommands = !!commands && commands.length > 0;
1057
- const valueLooksLikeSlashCommand = value.startsWith("/") && !/\s/.test(value);
1058
- const commandsOpen = hasCommands && valueLooksLikeSlashCommand && value !== dismissedValue;
1059
- const slashFilter = commandsOpen ? value.slice(1) : "";
1563
+ const panelOpen = panel !== void 0;
1564
+ const hasMentions = mentions !== void 0;
1565
+ const hasMenus = hasCommands || hasMentions;
1566
+ const slashToken = hasCommands && !panelOpen && value !== dismissedValue ? findSlashToken(value, Math.min(caret, value.length)) : null;
1567
+ const commandsOpen = slashToken !== null;
1568
+ const mentionToken = hasMentions && !commandsOpen && !panelOpen && value !== dismissedValue ? findMentionToken(value, Math.min(caret, value.length)) : null;
1569
+ const mentionsOpen = mentionToken !== null;
1570
+ const menuOpen = commandsOpen || mentionsOpen || panelOpen;
1571
+ const menuItems = commandsOpen ? commands ?? [] : mentions ?? [];
1572
+ const menuFilter = commandsOpen ? slashToken.query : mentionToken?.query ?? "";
1060
1573
  const handleSubmit = () => {
1061
1574
  if (isDisabled) return;
1062
1575
  if (status === "streaming") onAbort?.();
@@ -1068,21 +1581,71 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
1068
1581
  handleSubmit();
1069
1582
  };
1070
1583
  const handleOnChange = (event) => {
1584
+ moveCaret(event.target.selectionStart ?? event.target.value.length, event.target.value);
1071
1585
  onValueChange?.(event.target.value);
1072
1586
  };
1073
- const handleCommandSelect = (commandValue) => {
1074
- onValueChange?.(commandValue + " ");
1587
+ const handleOnSelect = (event) => {
1588
+ moveCaret(event.currentTarget.selectionStart ?? 0, event.currentTarget.value);
1589
+ };
1590
+ const handleMenuSelect = (item) => {
1591
+ if (item.onSelect) {
1592
+ const start = mentionToken?.start ?? 0;
1593
+ const end = mentionToken?.end ?? slashToken?.end;
1594
+ if (end !== void 0) {
1595
+ const next = value.slice(0, start) + value.slice(end);
1596
+ onValueChange?.(next);
1597
+ moveCaret(start, next);
1598
+ }
1599
+ item.onSelect();
1600
+ textareaRef.current?.focus();
1601
+ return;
1602
+ }
1603
+ if (mentionToken) {
1604
+ const keep = mentionsMultiple ? "@" : "";
1605
+ const next = value.slice(0, mentionToken.start) + keep + value.slice(mentionToken.end);
1606
+ const nextCaret = mentionToken.start + keep.length;
1607
+ onValueChange?.(next);
1608
+ moveCaret(nextCaret, next);
1609
+ requestAnimationFrame(() => {
1610
+ textareaRef.current?.setSelectionRange(nextCaret, nextCaret);
1611
+ });
1612
+ onMentionSelect?.(item);
1613
+ } else {
1614
+ const rest = slashToken ? value.slice(slashToken.end).replace(/^\s+/, "") : "";
1615
+ const head = `${item.value} `;
1616
+ onValueChange?.(head + rest);
1617
+ moveCaret(head.length, head + rest);
1618
+ requestAnimationFrame(() => {
1619
+ textareaRef.current?.setSelectionRange(head.length, head.length);
1620
+ });
1621
+ }
1075
1622
  textareaRef.current?.focus();
1076
1623
  };
1624
+ const dismissMenu = () => {
1625
+ if (value.trim() === "/" || value.trim() === "@") {
1626
+ onValueChange?.("");
1627
+ return;
1628
+ }
1629
+ if (mentionToken && mentionToken.query === "") {
1630
+ const next = (value.slice(0, mentionToken.start) + value.slice(mentionToken.end)).replace(/\s+$/, "");
1631
+ onValueChange?.(next);
1632
+ moveCaret(next.length, next);
1633
+ return;
1634
+ }
1635
+ setDismissedValue(value);
1636
+ };
1077
1637
  const handleOnKeyDown = (event) => {
1078
- if (commandsOpen) {
1638
+ if (menuOpen) {
1079
1639
  if (event.key === "Escape") {
1080
1640
  event.preventDefault();
1081
- setDismissedValue(value);
1641
+ if (panel) panel.onClose();
1642
+ else dismissMenu();
1082
1643
  return;
1083
1644
  }
1084
- if (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "Enter") return;
1085
- } else if (hasCommands && CMDK_HIJACKED_KEYS.has(event.key) && isCmdkNavigation(event)) event.stopPropagation();
1645
+ if (panelOpen) return;
1646
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") return;
1647
+ if (event.key === "Enter" && matchesFilter(menuItems, menuFilter).length > 0) return;
1648
+ } else if (hasMenus && CMDK_HIJACKED_KEYS.has(event.key) && isCmdkNavigation(event)) event.stopPropagation();
1086
1649
  if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey && !event.metaKey) {
1087
1650
  event.preventDefault();
1088
1651
  if (status !== "streaming") handleSubmit();
@@ -1100,48 +1663,69 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
1100
1663
  "data-status": status,
1101
1664
  onMouseDown: handleOnMouseDown,
1102
1665
  onSubmit: handleOnSubmit,
1103
- className: cn(promptInputVariants({ variant }), disabled && "tw:bg-none tw:border-border tw:shadow-[inset_0_100vw_rgb(var(--muted))] tw:cursor-default"),
1666
+ className: cn(promptInputVariants({ variant }), disabled && "tw:bg-none tw:border-border tw:shadow-[inset_0_100vw_rgb(var(--muted))] tw:cursor-default", className),
1104
1667
  children: [
1105
- prefix && /* @__PURE__ */ jsx("div", {
1106
- className: "tw:flex tw:items-center",
1107
- children: prefix
1668
+ /* @__PURE__ */ jsx(AnimatedHeight, {
1669
+ className: "tw:-mb-2",
1670
+ children: attachments && /* @__PURE__ */ jsx("div", {
1671
+ className: "tw:flex tw:flex-col tw:gap-2 tw:pb-4",
1672
+ children: attachments
1673
+ })
1108
1674
  }),
1109
1675
  /* @__PURE__ */ jsx("label", {
1110
1676
  htmlFor: textareaId,
1111
1677
  className: "tw:sr-only",
1112
1678
  children: "Prompt Input"
1113
1679
  }),
1114
- /* @__PURE__ */ jsx(TextareaAutosize, {
1115
- ...textareaProps,
1116
- disabled,
1117
- minRows: minRows ?? defaultMinRows,
1118
- maxRows,
1119
- id: textareaId,
1120
- ref: setTextareaNode,
1121
- value,
1122
- onChange: handleOnChange,
1123
- onKeyDown: handleOnKeyDown,
1124
- className: cn("tw:resize-none", "tw:outline-hidden", "tw:w-full", "tw:px-2", "tw:bg-transparent", disabled ? "tw:text-muted-foreground" : "tw:text-foreground", "tw:text-sm", "tw:font-sans", "tw:transition-[width]", "tw:delay-75", "tw:ease-linear", "tw:overflow-auto")
1125
- }),
1126
1680
  /* @__PURE__ */ jsxs("div", {
1127
- className: cn("tw:flex tw:items-center tw:gap-4", variant === "inline" ? "tw:items-end" : "tw:items-center"),
1128
- children: [suffix, /* @__PURE__ */ jsx(PromptInputSubmit, {
1129
- disabled: isDisabled,
1130
- status
1131
- })]
1681
+ className: cn("tw:flex tw:min-w-0 tw:gap-2", variant === "inline" ? "tw:flex-row tw:items-center tw:@max-[480px]/composer:flex-wrap" : "tw:flex-col"),
1682
+ children: [
1683
+ prefix && /* @__PURE__ */ jsx("div", {
1684
+ className: "tw:flex tw:shrink-0 tw:items-center",
1685
+ children: prefix
1686
+ }),
1687
+ /* @__PURE__ */ jsx("div", {
1688
+ className: cn("tw:flex tw:min-w-0 tw:items-center", variant === "inline" ? "tw:grow tw:@max-[480px]/composer:order-first tw:@max-[480px]/composer:basis-full" : "tw:flex-1"),
1689
+ children: /* @__PURE__ */ jsx(TextareaAutosize, {
1690
+ ...textareaProps,
1691
+ disabled,
1692
+ minRows: minRows ?? defaultMinRows,
1693
+ maxRows,
1694
+ id: textareaId,
1695
+ ref: setTextareaNode,
1696
+ value,
1697
+ onChange: handleOnChange,
1698
+ onSelect: handleOnSelect,
1699
+ onKeyDown: handleOnKeyDown,
1700
+ className: cn("tw:resize-none", "tw:outline-hidden", "tw:min-w-32 tw:flex-1", variant === "inline" ? "tw:@max-[480px]/composer:pl-2" : "tw:pl-2 tw:pr-0", "tw:bg-transparent", disabled ? "tw:text-muted-foreground" : "tw:text-foreground", "tw:text-sm", "tw:font-sans", "tw:transition-[width]", "tw:delay-75", "tw:ease-linear", "tw:overflow-auto")
1701
+ })
1702
+ }),
1703
+ /* @__PURE__ */ jsxs("div", {
1704
+ className: cn("tw:flex tw:items-center tw:gap-1", "tw:[&>*:last-child]:ml-1", "tw:shrink-0", variant === "inline" && "tw:pr-2.5 tw:@max-[480px]/composer:grow tw:@max-[480px]/composer:pr-0"),
1705
+ children: [suffix, /* @__PURE__ */ jsx(PromptInputSubmit, {
1706
+ disabled: isDisabled,
1707
+ status
1708
+ })]
1709
+ })
1710
+ ]
1132
1711
  })
1133
1712
  ]
1134
1713
  })
1135
1714
  });
1136
- return /* @__PURE__ */ jsx(TooltipProvider, { children: hasCommands ? /* @__PURE__ */ jsx(PromptInputCommands, {
1137
- items: commands ?? [],
1138
- open: commandsOpen,
1139
- onSelect: handleCommandSelect,
1140
- filterValue: slashFilter,
1715
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: hasMenus ? /* @__PURE__ */ jsx(PromptInputCommands, {
1716
+ items: menuItems,
1717
+ open: menuOpen,
1718
+ onSelect: handleMenuSelect,
1719
+ filterValue: menuFilter,
1720
+ emptyText: mentionsOpen ? mentionsEmptyText : "No commands found",
1721
+ panel: panel?.content,
1722
+ groupAction: commandsOpen ? commandsGroupAction : void 0,
1723
+ groupHeading: mentionsOpen ? mentionsGroupHeading : void 0,
1141
1724
  children: formEl
1142
1725
  }) : formEl });
1143
1726
  };
1144
1727
  PromptInput.Action = PromptInputAction;
1728
+ PromptInput.MenuTrigger = PromptInputMenuTrigger;
1145
1729
  //#endregion
1146
1730
  //#region src/blocks/AIKit/Question.tsx
1147
1731
  const handleKeyDown = (callback) => (e) => {
@@ -1154,6 +1738,10 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
1154
1738
  const [isCustomExpanded, setIsCustomExpanded] = useState(false);
1155
1739
  const isCustomSelected = isCustomExpanded || customAnswer.length > 0;
1156
1740
  const hasSteps = currentStep != null && totalSteps != null;
1741
+ const showStepControls = hasSteps && totalSteps > 1;
1742
+ const showSkipButton = showSkip && onSkip != null;
1743
+ const showSubmitButton = multiSelect || isCustomSelected;
1744
+ const showFooter = showStepControls || showSkipButton || showSubmitButton;
1157
1745
  const progressValue = hasSteps ? currentStep / totalSteps * 100 : 0;
1158
1746
  const isFirstStep = currentStep === 1;
1159
1747
  const isLastStep = hasSteps && currentStep === totalSteps;
@@ -1280,14 +1868,14 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
1280
1868
  }),
1281
1869
  /* @__PURE__ */ jsxs("div", {
1282
1870
  className: "tw:flex tw:flex-col",
1283
- children: [hasSteps && /* @__PURE__ */ jsx(Progress, {
1871
+ children: [showStepControls && /* @__PURE__ */ jsx(Progress, {
1284
1872
  size: "sm",
1285
1873
  value: progressValue,
1286
1874
  className: "tw:rounded-none"
1287
- }), /* @__PURE__ */ jsxs("div", {
1288
- className: cn("tw:flex tw:items-center tw:justify-end tw:gap-4 tw:px-4 tw:py-3", !hasSteps && "tw:border-0 tw:border-t tw:border-solid tw:border-border"),
1875
+ }), showFooter && /* @__PURE__ */ jsxs("div", {
1876
+ className: cn("tw:flex tw:items-center tw:justify-end tw:gap-4 tw:px-4 tw:py-3", !showStepControls && "tw:border-0 tw:border-t tw:border-solid tw:border-border"),
1289
1877
  children: [
1290
- hasSteps && /* @__PURE__ */ jsxs("div", {
1878
+ showStepControls && /* @__PURE__ */ jsxs("div", {
1291
1879
  className: "tw:flex tw:items-center tw:gap-2",
1292
1880
  children: [
1293
1881
  /* @__PURE__ */ jsx("button", {
@@ -1316,14 +1904,14 @@ const Question = ({ question, header, options, multiSelect = true, selectedOptio
1316
1904
  })
1317
1905
  ]
1318
1906
  }),
1319
- showSkip && onSkip && /* @__PURE__ */ jsx(Button, {
1907
+ showSkipButton && /* @__PURE__ */ jsx(Button, {
1320
1908
  variant: "outline",
1321
1909
  size: "small",
1322
1910
  onClick: onSkip,
1323
1911
  "data-testid": "question-skip-button",
1324
1912
  children: "Skip"
1325
1913
  }),
1326
- (multiSelect || isCustomSelected) && (submitTooltip ? /* @__PURE__ */ jsx(Tooltip, {
1914
+ showSubmitButton && (submitTooltip ? /* @__PURE__ */ jsx(Tooltip, {
1327
1915
  tooltip: submitTooltip,
1328
1916
  placement: "top",
1329
1917
  triggerAsChild: true,
@@ -1656,6 +2244,25 @@ const formatPercentage = (value) => {
1656
2244
  return `${value < 100 ? Math.min(rounded, 99) : rounded}%`;
1657
2245
  };
1658
2246
  //#endregion
2247
+ //#region src/blocks/AIKit/UsageBar.tsx
2248
+ /**
2249
+ * One budget, as a labelled row over a bar.
2250
+ *
2251
+ * - `value` is clamped by `clampPercentage` — `Progress`'s indicator is unclamped.
2252
+ */
2253
+ const UsageBar = ({ value, label, variant, className, ...props }) => /* @__PURE__ */ jsxs("span", {
2254
+ ...props,
2255
+ className: cn("tw:flex tw:flex-col tw:gap-1.5 tw:text-xs tw:text-muted-foreground", className),
2256
+ children: [/* @__PURE__ */ jsxs("span", {
2257
+ className: "tw:flex tw:items-baseline tw:justify-between tw:gap-2",
2258
+ children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", { children: `${formatPercentage(Math.max(0, 100 - value))} left` })]
2259
+ }), /* @__PURE__ */ jsx(Progress, {
2260
+ size: "sm",
2261
+ variant,
2262
+ value: clampPercentage(value)
2263
+ })]
2264
+ });
2265
+ //#endregion
1659
2266
  //#region src/blocks/AIKit/UsageStatsRing.tsx
1660
2267
  const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }) => {
1661
2268
  const radius = Math.max(0, (size - strokeWidth) / 2 - 1);
@@ -1698,9 +2305,10 @@ const UsageStats = ({ value, alert = false, children, className, ariaLabel, alig
1698
2305
  onOpenChange,
1699
2306
  children: [/* @__PURE__ */ jsx(HoverCard.Trigger, {
1700
2307
  asChild: true,
1701
- children: /* @__PURE__ */ jsxs("span", {
2308
+ children: /* @__PURE__ */ jsxs("button", {
2309
+ type: "button",
1702
2310
  "aria-label": ariaLabel ?? defaultLabel,
1703
- className: cn("tw:relative tw:inline-flex tw:size-8 tw:items-center tw:justify-center", className),
2311
+ className: cn("tw:relative tw:inline-flex tw:size-8 tw:shrink-0 tw:items-center tw:justify-center", "tw:cursor-pointer tw:rounded-full tw:border-0 tw:bg-transparent tw:p-0", "tw:transition-colors tw:hover:bg-muted", "tw:focus-visible:outline-hidden tw:focus-visible:ring-2 tw:focus-visible:ring-ring/50", className),
1704
2312
  children: [/* @__PURE__ */ jsx(UsageStatsRing, { value }), hasAlert && /* @__PURE__ */ jsx(AlertCircle, {
1705
2313
  "data-testid": "usage-stats-alert",
1706
2314
  className: cn("tw:absolute tw:-right-0.5 tw:-top-0.5 tw:size-3", isWarning ? "tw:text-warning-500" : "tw:text-error-500")
@@ -1715,6 +2323,6 @@ const UsageStats = ({ value, alert = false, children, className, ariaLabel, alig
1715
2323
  });
1716
2324
  };
1717
2325
  //#endregion
1718
- export { AnswerActions, AnswerSummary, CollapsibleStepHeader, DIAGRAM_LANGUAGES, InlineStepDetail, InlineStepLabel, Markdown, MarkdownTable, MessageBubble, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageStats, UsageStatsRing, clampPercentage, formatPercentage };
2326
+ export { AnswerActions, AnswerSummary, ChatInlineIcon, CollapsibleStepHeader, DIAGRAM_LANGUAGES, FileDownloadChip, InlineStepDetail, InlineStepGroup, InlineStepLabel, Markdown, MarkdownTable, MessageBubble, PROMPT_INPUT_CONTAINER, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageBar, UsageStats, UsageStatsRing, clampPercentage, findMentionToken, findSlashToken, formatPercentage, getChatInlineIconName };
1719
2327
 
1720
- //# sourceMappingURL=AIKit-CQxVwyAk.js.map
2328
+ //# sourceMappingURL=AIKit-BD4r7ff-.js.map