@keboola/design 13.1.3 → 14.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 (347) hide show
  1. package/AGENTS.md +68 -6
  2. package/CHANGELOG.md +196 -0
  3. package/COMPONENT-API.md +60 -50
  4. package/dist/{AIKit-BVCWP9Ks.js → AIKit-BRSZ3nY7.js} +2227 -313
  5. package/dist/AIKit-BRSZ3nY7.js.map +1 -0
  6. package/dist/{Alert-UI-CIs-1.js → Alert-CZ0dDsuk.js} +7 -7
  7. package/dist/{Alert-UI-CIs-1.js.map → Alert-CZ0dDsuk.js.map} +1 -1
  8. package/dist/{AlertModal-mbSnuuka.js → AlertModal-BDle9ZVQ.js} +6 -6
  9. package/dist/AlertModal-BDle9ZVQ.js.map +1 -0
  10. package/dist/{AppShell-WSQabK8r.js → AppShell-B03fj1j7.js} +2 -2
  11. package/dist/{AppShell-WSQabK8r.js.map → AppShell-B03fj1j7.js.map} +1 -1
  12. package/dist/{AutoSaveTextarea-C5iIr2Ts.js → AutoSaveTextarea-jiqNeeE4.js} +3 -3
  13. package/dist/{AutoSaveTextarea-C5iIr2Ts.js.map → AutoSaveTextarea-jiqNeeE4.js.map} +1 -1
  14. package/dist/{Badge-Dz0cj6rj.js → Badge-Ba3epgcI.js} +2 -2
  15. package/dist/{Badge-Dz0cj6rj.js.map → Badge-Ba3epgcI.js.map} +1 -1
  16. package/dist/{BrandEditor-P8OZX2hi.js → BrandEditor-CN2HJ_12.js} +155 -17
  17. package/dist/BrandEditor-CN2HJ_12.js.map +1 -0
  18. package/dist/{BrandLogo-CKpVSZb6.js → BrandLogo-BfITD0im.js} +2 -2
  19. package/dist/{BrandLogo-CKpVSZb6.js.map → BrandLogo-BfITD0im.js.map} +1 -1
  20. package/dist/{Breadcrumb-BUoAZyhO.js → Breadcrumb-BnIlsoIH.js} +62 -20
  21. package/dist/Breadcrumb-BnIlsoIH.js.map +1 -0
  22. package/dist/{Button-B21oVcPU.js → Button-D2JqBAq7.js} +199 -7
  23. package/dist/Button-D2JqBAq7.js.map +1 -0
  24. package/dist/{Calendar-DFtmZzbF.js → Calendar-BnKi1kPu.js} +4 -4
  25. package/dist/{Calendar-DFtmZzbF.js.map → Calendar-BnKi1kPu.js.map} +1 -1
  26. package/dist/{Card-BQmBWHXl.js → Card-Bpc_ZlL4.js} +3 -3
  27. package/dist/Card-Bpc_ZlL4.js.map +1 -0
  28. package/dist/{Checkbox-8yIIgY7g.js → Checkbox-uFE8XLT_.js} +6 -6
  29. package/dist/Checkbox-uFE8XLT_.js.map +1 -0
  30. package/dist/{Clipboard-_xf6hMDD.js → Clipboard-D-9XOqy4.js} +3 -3
  31. package/dist/{Clipboard-_xf6hMDD.js.map → Clipboard-D-9XOqy4.js.map} +1 -1
  32. package/dist/{ClipboardButton-srUgWgwH.js → ClipboardButton-DxvZG_H0.js} +4 -4
  33. package/dist/{ClipboardButton-srUgWgwH.js.map → ClipboardButton-DxvZG_H0.js.map} +1 -1
  34. package/dist/{CodeEditor-Df7VVx08.js → CodeEditor-BfRSCKEs.js} +6 -6
  35. package/dist/{CodeEditor-Df7VVx08.js.map → CodeEditor-BfRSCKEs.js.map} +1 -1
  36. package/dist/{Collapsible-BQXWEOBC.js → Collapsible-DD4xTL75.js} +2 -2
  37. package/dist/{Collapsible-BQXWEOBC.js.map → Collapsible-DD4xTL75.js.map} +1 -1
  38. package/dist/{ColorInput-B3gBZ8Ya.js → ColorInput-CDKH8q_f.js} +5 -5
  39. package/dist/{ColorInput-B3gBZ8Ya.js.map → ColorInput-CDKH8q_f.js.map} +1 -1
  40. package/dist/{ColorModeSwitch-D8Cki137.js → ColorModeSwitch-DR6J2U6M.js} +4 -4
  41. package/dist/{ColorModeSwitch-D8Cki137.js.map → ColorModeSwitch-DR6J2U6M.js.map} +1 -1
  42. package/dist/{Combobox-BNhW0TDB.js → Combobox-CEesMe2M.js} +246 -44
  43. package/dist/Combobox-CEesMe2M.js.map +1 -0
  44. package/dist/{Command-BQPiZCNz.js → Command-T3MLRaen.js} +10 -6
  45. package/dist/Command-T3MLRaen.js.map +1 -0
  46. package/dist/{CopyField-Ba7h8MqZ.js → CopyField-CNbCHw9a.js} +4 -4
  47. package/dist/{CopyField-Ba7h8MqZ.js.map → CopyField-CNbCHw9a.js.map} +1 -1
  48. package/dist/{DateInput-D0nWUasV.js → DateInput-ClK1lCxz.js} +5 -5
  49. package/dist/{DateInput-D0nWUasV.js.map → DateInput-ClK1lCxz.js.map} +1 -1
  50. package/dist/{DatePicker-CtSa9b3V.js → DatePicker-CgHAu9KX.js} +3 -3
  51. package/dist/{DatePicker-CtSa9b3V.js.map → DatePicker-CgHAu9KX.js.map} +1 -1
  52. package/dist/{DateRangeInput-i6wE45-V.js → DateRangeInput-DtlAffS1.js} +5 -5
  53. package/dist/{DateRangeInput-i6wE45-V.js.map → DateRangeInput-DtlAffS1.js.map} +1 -1
  54. package/dist/{DateRangePicker-BAnuz6vO.js → DateRangePicker-CXpXPMoh.js} +8 -8
  55. package/dist/{DateRangePicker-BAnuz6vO.js.map → DateRangePicker-CXpXPMoh.js.map} +1 -1
  56. package/dist/{DiffView-ppTIzh2h.js → DiffView-Dy4z-n-1.js} +3 -3
  57. package/dist/{DiffView-ppTIzh2h.js.map → DiffView-Dy4z-n-1.js.map} +1 -1
  58. package/dist/{DropdownMenu-BJGLjpVc.js → DropdownMenu-B1gGvZoh.js} +9 -9
  59. package/dist/DropdownMenu-B1gGvZoh.js.map +1 -0
  60. package/dist/{FieldBox-D7DYtX_m.js → FieldBox-BrxLkY9C.js} +8 -6
  61. package/dist/FieldBox-BrxLkY9C.js.map +1 -0
  62. package/dist/{FieldItem-BHViBJS3.js → FieldItem-CYvJyjiI.js} +4 -4
  63. package/dist/{FieldItem-BHViBJS3.js.map → FieldItem-CYvJyjiI.js.map} +1 -1
  64. package/dist/{FileUpload-Ch2hrIWq.js → FileUpload-D6vPG3WB.js} +9 -9
  65. package/dist/FileUpload-D6vPG3WB.js.map +1 -0
  66. package/dist/{Form-VkzfVPyT.js → Form-CD55zJiy.js} +10 -10
  67. package/dist/{Form-VkzfVPyT.js.map → Form-CD55zJiy.js.map} +1 -1
  68. package/dist/{FormGroup-CmCppxOn.js → FormGroup-DiYFdEhH.js} +4 -4
  69. package/dist/{FormGroup-CmCppxOn.js.map → FormGroup-DiYFdEhH.js.map} +1 -1
  70. package/dist/{FullScreenModal-Cwnm8WdM.js → FullScreenModal-CUuAakh3.js} +20 -6
  71. package/dist/{FullScreenModal-Cwnm8WdM.js.map → FullScreenModal-CUuAakh3.js.map} +1 -1
  72. package/dist/HoverCard-BBdPYqEf.js +31 -0
  73. package/dist/HoverCard-BBdPYqEf.js.map +1 -0
  74. package/dist/InlineEdit-D5RdunZo.js +370 -0
  75. package/dist/InlineEdit-D5RdunZo.js.map +1 -0
  76. package/dist/{InputGroup-CrlMRz4X.js → InputGroup-Dm014ruw.js} +4 -4
  77. package/dist/{InputGroup-CrlMRz4X.js.map → InputGroup-Dm014ruw.js.map} +1 -1
  78. package/dist/{Kbd-J4n1J6i4.js → Kbd-3YM7NQO4.js} +3 -3
  79. package/dist/{Kbd-J4n1J6i4.js.map → Kbd-3YM7NQO4.js.map} +1 -1
  80. package/dist/MermaidDiagram-CeiOkI60.js +199 -0
  81. package/dist/MermaidDiagram-CeiOkI60.js.map +1 -0
  82. package/dist/{Modal-BkSuS9Yz.js → Modal-DMZRswk4.js} +8 -7
  83. package/dist/Modal-DMZRswk4.js.map +1 -0
  84. package/dist/{ModalTitle-BxopkIoQ.js → ModalTitle-CTECVgL8.js} +3 -3
  85. package/dist/ModalTitle-CTECVgL8.js.map +1 -0
  86. package/dist/{MultiActionButtonGroup-AWLj1Tg7.js → MultiActionButtonGroup-CEv_txvz.js} +5 -5
  87. package/dist/{MultiActionButtonGroup-AWLj1Tg7.js.map → MultiActionButtonGroup-CEv_txvz.js.map} +1 -1
  88. package/dist/{Navbar-B_DNpv5s.js → Navbar-CtVYcRFn.js} +18 -14
  89. package/dist/Navbar-CtVYcRFn.js.map +1 -0
  90. package/dist/{OtpInput-I8B8Vjdl.js → OtpInput-CY8yCaJk.js} +4 -4
  91. package/dist/{OtpInput-I8B8Vjdl.js.map → OtpInput-CY8yCaJk.js.map} +1 -1
  92. package/dist/{PageHeader-CgfyXpf1.js → PageHeader-CL1A6jFM.js} +21 -14
  93. package/dist/PageHeader-CL1A6jFM.js.map +1 -0
  94. package/dist/{PageLayout-DiAAILuS.js → PageLayout-C9aXTpqV.js} +2 -2
  95. package/dist/{PageLayout-DiAAILuS.js.map → PageLayout-C9aXTpqV.js.map} +1 -1
  96. package/dist/{PageToolbar-C06RKIif.js → PageToolbar-B_e7HGva.js} +6 -6
  97. package/dist/{PageToolbar-C06RKIif.js.map → PageToolbar-B_e7HGva.js.map} +1 -1
  98. package/dist/{Pagination-DH3f6LN0.js → Pagination-DDp6PRqf.js} +5 -5
  99. package/dist/Pagination-DDp6PRqf.js.map +1 -0
  100. package/dist/{Popconfirm-Dhzn7sy6.js → Popconfirm-BgV6a0sl.js} +5 -5
  101. package/dist/{Popconfirm-Dhzn7sy6.js.map → Popconfirm-BgV6a0sl.js.map} +1 -1
  102. package/dist/{Popover-CEk915I1.js → Popover-BU7nGOv-.js} +3 -3
  103. package/dist/Popover-BU7nGOv-.js.map +1 -0
  104. package/dist/{RadioGroup-CYEp8Wnx.js → RadioGroup-C8EC3fqO.js} +6 -6
  105. package/dist/{RadioGroup-CYEp8Wnx.js.map → RadioGroup-C8EC3fqO.js.map} +1 -1
  106. package/dist/{Resizable-D3vYToZH.js → Resizable-D8zs0kcq.js} +2 -2
  107. package/dist/{Resizable-D3vYToZH.js.map → Resizable-D8zs0kcq.js.map} +1 -1
  108. package/dist/{Search-DmkQo716.js → Search-aaUMI4ix.js} +4 -4
  109. package/dist/{Search-DmkQo716.js.map → Search-aaUMI4ix.js.map} +1 -1
  110. package/dist/{SearchInput-D3qMkHaW.js → SearchInput-Dxi2GK4n.js} +4 -4
  111. package/dist/{SearchInput-D3qMkHaW.js.map → SearchInput-Dxi2GK4n.js.map} +1 -1
  112. package/dist/{SectionNav-I2p2uXTd.js → SectionNav-BnHOMLtE.js} +11 -11
  113. package/dist/{SectionNav-I2p2uXTd.js.map → SectionNav-BnHOMLtE.js.map} +1 -1
  114. package/dist/{Select-B4uK0QVm.js → Select-CjQgU_6K.js} +6 -6
  115. package/dist/Select-CjQgU_6K.js.map +1 -0
  116. package/dist/{Sheet-D0fAE14T.js → Sheet-utw4_rUa.js} +9 -9
  117. package/dist/Sheet-utw4_rUa.js.map +1 -0
  118. package/dist/{Sidebar-D9ytIs8V.js → Sidebar-BAmux2Uj.js} +21 -18
  119. package/dist/Sidebar-BAmux2Uj.js.map +1 -0
  120. package/dist/{Slider-B0ou9r0B.js → Slider-DbzzSDRV.js} +5 -5
  121. package/dist/{Slider-B0ou9r0B.js.map → Slider-DbzzSDRV.js.map} +1 -1
  122. package/dist/{Stepper-BLkLhfnd.js → Stepper-BBPembeK.js} +3 -3
  123. package/dist/{Stepper-BLkLhfnd.js.map → Stepper-BBPembeK.js.map} +1 -1
  124. package/dist/{Switch-DZvNePOm.js → Switch-Dw4tvQls.js} +3 -3
  125. package/dist/Switch-Dw4tvQls.js.map +1 -0
  126. package/dist/{Table-BaVT5Tkn.js → Table-CilEvpMq.js} +65 -6
  127. package/dist/Table-CilEvpMq.js.map +1 -0
  128. package/dist/{Tabs-CTDmye1N.js → Tabs-C0uvkPHc.js} +5 -5
  129. package/dist/Tabs-C0uvkPHc.js.map +1 -0
  130. package/dist/{TextInput-BWYXbfs4.js → TextInput-K2DSDs5O.js} +5 -5
  131. package/dist/{TextInput-BWYXbfs4.js.map → TextInput-K2DSDs5O.js.map} +1 -1
  132. package/dist/{ThemeProvider-VF38VfUa.js → ThemeProvider-C8yaKlM1.js} +22 -5
  133. package/dist/ThemeProvider-C8yaKlM1.js.map +1 -0
  134. package/dist/{TimePicker-CDGYrRxi.js → TimePicker-DyyV3nw8.js} +2 -2
  135. package/dist/{TimePicker-CDGYrRxi.js.map → TimePicker-DyyV3nw8.js.map} +1 -1
  136. package/dist/{Timeline-B-I6sb0M.js → Timeline-DUXgByUE.js} +3 -3
  137. package/dist/{Timeline-B-I6sb0M.js.map → Timeline-DUXgByUE.js.map} +1 -1
  138. package/dist/{Toast-NrOdDDru.js → Toast-BGnUL4jV.js} +2 -2
  139. package/dist/{Toast-NrOdDDru.js.map → Toast-BGnUL4jV.js.map} +1 -1
  140. package/dist/ToggleAllTooltip-Dlmq-yqS.js +37 -0
  141. package/dist/ToggleAllTooltip-Dlmq-yqS.js.map +1 -0
  142. package/dist/{ToggleGroup-Cy_10Mvu.js → ToggleGroup-BOz1yyz6.js} +3 -3
  143. package/dist/ToggleGroup-BOz1yyz6.js.map +1 -0
  144. package/dist/{Workbench-DmZzpkj7.js → Workbench-CxgNCs3I.js} +4 -4
  145. package/dist/{Workbench-DmZzpkj7.js.map → Workbench-CxgNCs3I.js.map} +1 -1
  146. package/dist/{ZoomableSvg-C65nta_r.js → ZoomableSvg-Dh1OstPN.js} +87 -83
  147. package/dist/ZoomableSvg-Dh1OstPN.js.map +1 -0
  148. package/dist/charts.js +1 -1
  149. package/dist/classNames-DcGnTh2N.js +21 -0
  150. package/dist/classNames-DcGnTh2N.js.map +1 -0
  151. package/dist/editors.js +6 -6
  152. package/dist/flint.js +10 -45
  153. package/dist/flint.js.map +1 -1
  154. package/dist/highlightCode-D354tCXO.js +81 -0
  155. package/dist/highlightCode-D354tCXO.js.map +1 -0
  156. package/dist/{icons-wcA70iQx.js → icons-ZIeZXXS7.js} +37 -4
  157. package/dist/icons-ZIeZXXS7.js.map +1 -0
  158. package/dist/icons.d.ts +2 -2
  159. package/dist/icons.js +2 -2
  160. package/dist/{index-B7k-09i1.d.ts → index-D-itZ3VP.d.ts} +14 -3
  161. package/dist/index.d.ts +942 -424
  162. package/dist/index.js +72 -70
  163. package/dist/internal/blocks/AIKit.js +2 -2
  164. package/dist/internal/blocks/AppShell.js +1 -1
  165. package/dist/internal/blocks/AuthLayout.js +2 -2
  166. package/dist/internal/blocks/AutoSaveTextarea.js +1 -1
  167. package/dist/internal/blocks/BrandEditor.js +1 -1
  168. package/dist/internal/blocks/ChartPanel.js +2 -2
  169. package/dist/internal/blocks/ChipEditor.js +4 -4
  170. package/dist/internal/blocks/ClipboardButton.js +1 -1
  171. package/dist/internal/blocks/ColorInput.js +1 -1
  172. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  173. package/dist/internal/blocks/Command.js +1 -1
  174. package/dist/internal/blocks/CopyField.js +1 -1
  175. package/dist/internal/blocks/DashboardHero.js +2 -2
  176. package/dist/internal/blocks/DashboardHero.js.map +1 -1
  177. package/dist/internal/blocks/DateInput.js +1 -1
  178. package/dist/internal/blocks/DateRangeInput.js +1 -1
  179. package/dist/internal/blocks/DiagramShared/DiagramSkeleton.js.map +1 -1
  180. package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
  181. package/dist/internal/blocks/ExportMenu.js +4 -4
  182. package/dist/internal/blocks/FacebookButton.js +66 -0
  183. package/dist/internal/blocks/FacebookButton.js.map +1 -0
  184. package/dist/internal/blocks/Form/connectors/ComboboxField.js +2 -2
  185. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  186. package/dist/internal/blocks/Form.js +1 -1
  187. package/dist/internal/blocks/FormGroup.js +1 -1
  188. package/dist/internal/blocks/GoogleButton.js +2 -2
  189. package/dist/internal/blocks/InlineEdit.js +2 -0
  190. package/dist/internal/blocks/MicrosoftButton.js +2 -2
  191. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  192. package/dist/internal/blocks/MultiCombobox.js +204 -68
  193. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  194. package/dist/internal/blocks/NumberInput.js +1 -1
  195. package/dist/internal/blocks/OtpInput.js +1 -1
  196. package/dist/internal/blocks/PageHeader.js +1 -1
  197. package/dist/internal/blocks/PageLayout.js +1 -1
  198. package/dist/internal/blocks/PageToolbar.js +1 -1
  199. package/dist/internal/blocks/PasswordInput.js +3 -3
  200. package/dist/internal/blocks/SearchInput.js +1 -1
  201. package/dist/internal/blocks/SearchInputWithNavigation.js +5 -5
  202. package/dist/internal/blocks/SectionNav.js +1 -1
  203. package/dist/internal/blocks/SplitButton.js +6 -5
  204. package/dist/internal/blocks/SplitButton.js.map +1 -1
  205. package/dist/internal/blocks/StatCard.js +2 -2
  206. package/dist/internal/blocks/TextInput.js +1 -1
  207. package/dist/internal/blocks/Textarea.js +1 -1
  208. package/dist/internal/blocks/TimeInput.js +4 -4
  209. package/dist/internal/components/Alert.js +1 -1
  210. package/dist/internal/components/AlertModal.js +1 -1
  211. package/dist/internal/components/Avatar.js +2 -2
  212. package/dist/internal/components/Badge.js +1 -1
  213. package/dist/internal/components/BrandLogo.js +1 -1
  214. package/dist/internal/components/Breadcrumb.js +1 -1
  215. package/dist/internal/components/Button.js +1 -1
  216. package/dist/internal/components/ButtonGroup.js +1 -1
  217. package/dist/internal/components/Calendar.js +1 -1
  218. package/dist/internal/components/Card.js +1 -1
  219. package/dist/internal/components/Checkbox.js +1 -1
  220. package/dist/internal/components/Clipboard.js +1 -1
  221. package/dist/internal/components/Collapsible.js +1 -1
  222. package/dist/internal/components/CollapsiblePanel.js +5 -5
  223. package/dist/internal/components/CollapsiblePanel.js.map +1 -1
  224. package/dist/internal/components/Combobox.js +1 -1
  225. package/dist/internal/components/DatePicker.js +1 -1
  226. package/dist/internal/components/DateRangePicker.js +1 -1
  227. package/dist/internal/components/DiffView.js +1 -1
  228. package/dist/internal/components/DotsLoader.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/Label.js +2 -2
  236. package/dist/internal/components/Label.js.map +1 -1
  237. package/dist/internal/components/Link.js +1 -1
  238. package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +2 -2
  239. package/dist/internal/components/Modal.js +1 -1
  240. package/dist/internal/components/Navbar.js +1 -1
  241. package/dist/internal/components/Pagination.js +1 -1
  242. package/dist/internal/components/PanelWithDetails.js +3 -3
  243. package/dist/internal/components/Popconfirm.js +1 -1
  244. package/dist/internal/components/Popover.js +1 -1
  245. package/dist/internal/components/Progress.js +1 -1
  246. package/dist/internal/components/RadioGroup.js +1 -1
  247. package/dist/internal/components/Resizable.js +1 -1
  248. package/dist/internal/components/ScrollArea.js +1 -1
  249. package/dist/internal/components/Search.js +1 -1
  250. package/dist/internal/components/Select.js +1 -1
  251. package/dist/internal/components/Separator.js +1 -1
  252. package/dist/internal/components/Sheet.js +1 -1
  253. package/dist/internal/components/Sidebar.js +1 -1
  254. package/dist/internal/components/Skeleton/Skeleton.js +2 -2
  255. package/dist/internal/components/Skeleton/Skeleton.js.map +1 -1
  256. package/dist/internal/components/Skeleton/SkeletonList.js +1 -1
  257. package/dist/internal/components/Slider.js +1 -1
  258. package/dist/internal/components/SpotlightBackdrop.js +1 -1
  259. package/dist/internal/components/Stepper.js +1 -1
  260. package/dist/internal/components/Switch.js +1 -1
  261. package/dist/internal/components/Table.js +1 -1
  262. package/dist/internal/components/Tabs.js +1 -1
  263. package/dist/internal/components/ThemeProvider.js +1 -1
  264. package/dist/internal/components/TimePicker.js +1 -1
  265. package/dist/internal/components/Timeline.js +1 -1
  266. package/dist/internal/components/Toast.js +2 -2
  267. package/dist/internal/components/Toggle.js +5 -5
  268. package/dist/internal/components/Toggle.js.map +1 -1
  269. package/dist/internal/components/ToggleGroup.js +1 -1
  270. package/dist/internal/components/Tooltip.js +1 -1
  271. package/dist/internal/components/Truncated.js +2 -2
  272. package/dist/internal/components/Workbench.js +1 -1
  273. package/dist/internal/components/ZoomableSvg.js +1 -1
  274. package/dist/internal/utils.js +2 -2
  275. package/dist/markdown-editor.js +14 -14
  276. package/dist/markdown-editor.js.map +1 -1
  277. package/dist/mermaid.d.ts +1 -2
  278. package/dist/mermaid.js +1 -1
  279. package/dist/rjsf.js +101 -14
  280. package/dist/rjsf.js.map +1 -1
  281. package/dist/{styles-DBGXH5-_.js → styles-BDA5rQz3.js} +6 -6
  282. package/dist/styles-BDA5rQz3.js.map +1 -0
  283. package/dist/{styles-gzcjOyKv.js → styles-YQdM7G8c.js} +3 -3
  284. package/dist/{styles-gzcjOyKv.js.map → styles-YQdM7G8c.js.map} +1 -1
  285. package/dist/styles.css +1 -1
  286. package/dist/svgCache-Dhmbe-7i.js +26 -0
  287. package/dist/svgCache-Dhmbe-7i.js.map +1 -0
  288. package/dist/svgTransforms-Hnvev3Vs.js +38 -0
  289. package/dist/svgTransforms-Hnvev3Vs.js.map +1 -0
  290. package/dist/testing.js +1 -1
  291. package/dist/{themeTokens-7DEab0kp.js → themeTokens-l2Fsfcs7.js} +3 -12
  292. package/dist/themeTokens-l2Fsfcs7.js.map +1 -0
  293. package/dist/{toast-CyXEdaCZ.js → toast-D6Z6MOB5.js} +5 -5
  294. package/dist/toast-D6Z6MOB5.js.map +1 -0
  295. package/dist/{utils-Bd28bWgm.js → utils-LQ4jJA-9.js} +21 -5
  296. package/dist/utils-LQ4jJA-9.js.map +1 -0
  297. package/dist/vega.js +1 -1
  298. package/dist/vegaTheme-BrmVoPEz.js +49 -0
  299. package/dist/vegaTheme-BrmVoPEz.js.map +1 -0
  300. package/dist/{vegaTheme-VQMWTlBw.js → vegaTokens-Ce07C0DH.js} +36 -44
  301. package/dist/vegaTokens-Ce07C0DH.js.map +1 -0
  302. package/package.json +4 -4
  303. package/src/styles.css +183 -4
  304. package/src/theme.css +47 -3
  305. package/dist/AIKit-BVCWP9Ks.js.map +0 -1
  306. package/dist/AlertModal-mbSnuuka.js.map +0 -1
  307. package/dist/BrandEditor-P8OZX2hi.js.map +0 -1
  308. package/dist/Breadcrumb-BUoAZyhO.js.map +0 -1
  309. package/dist/Button-B21oVcPU.js.map +0 -1
  310. package/dist/Card-BQmBWHXl.js.map +0 -1
  311. package/dist/Checkbox-8yIIgY7g.js.map +0 -1
  312. package/dist/Combobox-BNhW0TDB.js.map +0 -1
  313. package/dist/Command-BQPiZCNz.js.map +0 -1
  314. package/dist/DiagramSource-C5_d8Gdj.js +0 -11
  315. package/dist/DiagramSource-C5_d8Gdj.js.map +0 -1
  316. package/dist/DropdownMenu-BJGLjpVc.js.map +0 -1
  317. package/dist/FieldBox-D7DYtX_m.js.map +0 -1
  318. package/dist/FileUpload-Ch2hrIWq.js.map +0 -1
  319. package/dist/HoverCard-B8OKu9XZ.js +0 -31
  320. package/dist/HoverCard-B8OKu9XZ.js.map +0 -1
  321. package/dist/MermaidDiagram-B30x2yV7.js +0 -302
  322. package/dist/MermaidDiagram-B30x2yV7.js.map +0 -1
  323. package/dist/Modal-BkSuS9Yz.js.map +0 -1
  324. package/dist/ModalTitle-BxopkIoQ.js.map +0 -1
  325. package/dist/Navbar-B_DNpv5s.js.map +0 -1
  326. package/dist/PageHeader-CgfyXpf1.js.map +0 -1
  327. package/dist/Pagination-DH3f6LN0.js.map +0 -1
  328. package/dist/Popover-CEk915I1.js.map +0 -1
  329. package/dist/Select-B4uK0QVm.js.map +0 -1
  330. package/dist/Sheet-D0fAE14T.js.map +0 -1
  331. package/dist/Sidebar-D9ytIs8V.js.map +0 -1
  332. package/dist/Switch-DZvNePOm.js.map +0 -1
  333. package/dist/Table-BaVT5Tkn.js.map +0 -1
  334. package/dist/Tabs-CTDmye1N.js.map +0 -1
  335. package/dist/ThemeProvider-VF38VfUa.js.map +0 -1
  336. package/dist/ToggleGroup-Cy_10Mvu.js.map +0 -1
  337. package/dist/ZoomableSvg-C65nta_r.js.map +0 -1
  338. package/dist/classNames-BzrkDnOD.js +0 -9
  339. package/dist/classNames-BzrkDnOD.js.map +0 -1
  340. package/dist/icons-wcA70iQx.js.map +0 -1
  341. package/dist/styles-DBGXH5-_.js.map +0 -1
  342. package/dist/svgTransforms-Dw2hRA-i.js +0 -51
  343. package/dist/svgTransforms-Dw2hRA-i.js.map +0 -1
  344. package/dist/themeTokens-7DEab0kp.js.map +0 -1
  345. package/dist/toast-CyXEdaCZ.js.map +0 -1
  346. package/dist/utils-Bd28bWgm.js.map +0 -1
  347. package/dist/vegaTheme-VQMWTlBw.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { cn } from "./classNames-BzrkDnOD.js";
1
+ import { cn } from "./classNames-DcGnTh2N.js";
2
2
  import { cva } from "class-variance-authority";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
@@ -20,7 +20,7 @@ const rootVariants = cva([
20
20
  large: ["tw:h-10"]
21
21
  } }
22
22
  });
23
- const itemClasses = cn("tailwindcss-preflight", "tw:inline-flex", "tw:items-center", "tw:justify-center", "tw:gap-2", "tw:shrink-0", "tw:whitespace-nowrap", "tw:h-full", "tw:rounded-md", "tw:px-2", "tw:py-1", "tw:bg-transparent", "tw:text-muted-foreground", "tw:text-sm", "tw:font-medium", "tw:transition-colors", "tw:disabled:cursor-not-allowed", "tw:disabled:opacity-50", "tw:!outline-hidden", "tw:focus-visible:ring-2", "tw:focus-visible:ring-ring/50", "tw:not-disabled:[&[data-state=off]]:hover:bg-background/60", "tw:not-disabled:[&[data-state=off]]:hover:text-foreground", "tw:data-[state=on]:bg-background", "tw:data-[state=on]:text-foreground", "tw:data-[state=on]:shadow-[0_1px_2px_rgba(0,0,0,0.05),0_1px_1px_rgba(0,0,0,0.1)]", "tw:[[data-theme=dark]_&]:data-[state=on]:bg-secondary", "tw:[[data-theme=dark]_&]:data-[state=on]:shadow-none", "tw:[&_svg]:shrink-0", "tw:[&_svg]:pointer-events-none", "tw:[&_svg:not([class*='tw:size-'])]:size-4");
23
+ const itemClasses = cn("tailwindcss-preflight", "tw:inline-flex", "tw:items-center", "tw:justify-center", "tw:gap-2", "tw:shrink-0", "tw:whitespace-nowrap", "tw:h-full", "tw:rounded-md", "tw:px-2", "tw:py-1", "tw:bg-transparent", "tw:text-muted-foreground", "tw:text-sm", "tw:font-medium", "tw:transition-colors", "tw:disabled:cursor-not-allowed", "tw:disabled:opacity-disabled", "tw:!outline-hidden", "tw:focus-visible:ring-2", "tw:focus-visible:ring-ring/50", "tw:not-disabled:[&[data-state=off]]:hover:bg-background/60", "tw:not-disabled:[&[data-state=off]]:hover:text-foreground", "tw:data-[state=on]:bg-background", "tw:data-[state=on]:text-foreground", "tw:data-[state=on]:shadow-[0_1px_2px_rgba(0,0,0,0.05),0_1px_1px_rgba(0,0,0,0.1)]", "tw:[[data-theme=dark]_&]:data-[state=on]:bg-secondary", "tw:[[data-theme=dark]_&]:data-[state=on]:shadow-none", "tw:[&_svg]:shrink-0", "tw:[&_svg]:pointer-events-none", "tw:[&_svg:not([class*='tw:size-'])]:size-4");
24
24
  /**
25
25
  * Segmented row of mutually-exclusive (or multi-select) options. Built on `@radix-ui/react-toggle-group`.
26
26
  * For `type="single"`, `onValueChange` receives `""` when the user deselects the active item.
@@ -44,4 +44,4 @@ Item });
44
44
  //#endregion
45
45
  export { ToggleGroup };
46
46
 
47
- //# sourceMappingURL=ToggleGroup-Cy_10Mvu.js.map
47
+ //# sourceMappingURL=ToggleGroup-BOz1yyz6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleGroup-BOz1yyz6.js","names":[],"sources":["../src/components/ToggleGroup/ToggleGroup.tsx"],"sourcesContent":["import type { ComponentProps } from 'react';\nimport * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '../../utils';\n\nconst rootVariants = cva(\n [\n 'tailwindcss-preflight',\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:shrink-0',\n 'tw:bg-muted',\n 'tw:rounded-lg',\n 'tw:p-[3px]',\n 'tw:gap-0',\n ],\n {\n defaultVariants: { size: 'medium' },\n variants: {\n size: {\n small: ['tw:h-8'],\n medium: ['tw:h-9'],\n large: ['tw:h-10'],\n },\n },\n },\n);\n\nconst itemClasses = cn(\n 'tailwindcss-preflight',\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-2',\n 'tw:shrink-0',\n 'tw:whitespace-nowrap',\n\n 'tw:h-full',\n 'tw:rounded-md',\n 'tw:px-2',\n 'tw:py-1',\n\n 'tw:bg-transparent',\n // Off-state copy is muted so the pressed segment reads as pressed from the label\n // alone — the fill alone is a near-invisible step on either scheme's track.\n 'tw:text-muted-foreground',\n 'tw:text-sm',\n 'tw:font-medium',\n\n 'tw:transition-colors',\n\n 'tw:disabled:cursor-not-allowed',\n 'tw:disabled:opacity-disabled',\n\n 'tw:!outline-hidden',\n 'tw:focus-visible:ring-2',\n 'tw:focus-visible:ring-ring/50',\n\n // hover on non-pressed\n 'tw:not-disabled:[&[data-state=off]]:hover:bg-background/60',\n 'tw:not-disabled:[&[data-state=off]]:hover:text-foreground',\n\n // pressed\n 'tw:data-[state=on]:bg-background',\n 'tw:data-[state=on]:text-foreground',\n 'tw:data-[state=on]:shadow-[0_1px_2px_rgba(0,0,0,0.05),0_1px_1px_rgba(0,0,0,0.1)]',\n\n // Dark scheme inverts the lift: `background` is darker than the `muted` track, so the\n // pressed segment reads as a hole and the black drop shadow renders nothing on it.\n // `secondary` is the step above the track.\n 'tw:[[data-theme=dark]_&]:data-[state=on]:bg-secondary',\n 'tw:[[data-theme=dark]_&]:data-[state=on]:shadow-none',\n\n 'tw:[&_svg]:shrink-0',\n 'tw:[&_svg]:pointer-events-none',\n \"tw:[&_svg:not([class*='tw:size-'])]:size-4\",\n);\n\ntype RootProps = ComponentProps<typeof ToggleGroupPrimitive.Root> &\n VariantProps<typeof rootVariants>;\n\n/**\n * Segmented row of mutually-exclusive (or multi-select) options. Built on `@radix-ui/react-toggle-group`.\n * For `type=\"single\"`, `onValueChange` receives `\"\"` when the user deselects the active item.\n */\nconst Root = ({ ref, className, size = 'medium', ...props }: RootProps) => (\n <ToggleGroupPrimitive.Root\n ref={ref}\n {...props}\n className={cn(rootVariants({ size, className }))}\n />\n);\n\ntype ItemProps = ComponentProps<typeof ToggleGroupPrimitive.Item>;\n\nconst Item = ({ ref, className, ...props }: ItemProps) => (\n <ToggleGroupPrimitive.Item ref={ref} {...props} className={cn(itemClasses, className)} />\n);\n\nexport const ToggleGroup = Object.assign(Root, {\n /** Individual segment inside a `ToggleGroup`. `value` is required and must be unique within the group. */\n Item,\n});\n"],"mappings":";;;;;AAMA,MAAM,eAAe,IACnB;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,GACA;CACE,iBAAiB,EAAE,MAAM,SAAS;CAClC,UAAU,EACR,MAAM;EACJ,OAAO,CAAC,QAAQ;EAChB,QAAQ,CAAC,QAAQ;EACjB,OAAO,CAAC,SAAS;CACnB,EACF;AACF,CACF;AAEA,MAAM,cAAc,GAClB,yBACA,kBACA,mBACA,qBACA,YACA,eACA,wBAEA,aACA,iBACA,WACA,WAEA,qBAGA,4BACA,cACA,kBAEA,wBAEA,kCACA,gCAEA,sBACA,2BACA,iCAGA,8DACA,6DAGA,oCACA,sCACA,oFAKA,yDACA,wDAEA,uBACA,kCACA,4CACF;;;;;AASA,MAAM,QAAQ,EAAE,KAAK,WAAW,OAAO,UAAU,GAAG,YAClD,oBAAC,qBAAqB,MAAtB;CACO;CACL,GAAI;CACJ,WAAW,GAAG,aAAa;EAAE;EAAM;CAAU,CAAC,CAAC;AAChD,CAAA;AAKH,MAAM,QAAQ,EAAE,KAAK,WAAW,GAAG,YACjC,oBAAC,qBAAqB,MAAtB;CAAgC;CAAK,GAAI;CAAO,WAAW,GAAG,aAAa,SAAS;AAAI,CAAA;AAG1F,MAAa,cAAc,OAAO,OAAO,MAAM;;AAE7C,KACF,CAAC"}
@@ -1,8 +1,8 @@
1
- import { cn } from "./classNames-BzrkDnOD.js";
1
+ import { cn } from "./classNames-DcGnTh2N.js";
2
2
  import { useControllableState } from "./useControllableState-CUYXMsfz.js";
3
- import { Collapsible } from "./Collapsible-BQXWEOBC.js";
4
- import { Slot } from "@radix-ui/react-slot";
3
+ import { Collapsible } from "./Collapsible-DD4xTL75.js";
5
4
  import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
5
+ import { Slot } from "@radix-ui/react-slot";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/components/Workbench/constants.ts
8
8
  const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;
@@ -292,4 +292,4 @@ Workbench.FullScreenTrigger = WorkbenchFullScreenTrigger;
292
292
  //#endregion
293
293
  export { DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM, DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX, Workbench, useWorkbench };
294
294
 
295
- //# sourceMappingURL=Workbench-DmZzpkj7.js.map
295
+ //# sourceMappingURL=Workbench-CxgNCs3I.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Workbench-DmZzpkj7.js","names":[],"sources":["../src/components/Workbench/constants.ts","../src/components/Workbench/context.ts","../src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx","../src/components/Workbench/WorkbenchFullScreenTrigger.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx","../src/components/Workbench/Workbench.tsx"],"sourcesContent":["export const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;\n\nexport const MIN_WORKBENCH_BAR_HEIGHT_IN_REM = 1;\n\nexport const DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX = 320;\n\nexport const MIN_WORKBENCH_PANEL_HEIGHT_IN_PX = 120;\n\nexport const WORKBENCH_PANEL_RESIZE_STEP_IN_PX = 24;\n\nexport const WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO = 0.8;\n","import { createContext, use } from 'react';\nimport type { Dispatch, SetStateAction } from 'react';\n\n/**\n * Full screen is a mode of the open panel, not a flag beside it — as two booleans the fourth\n * combination (collapsed *and* full screen) is expressible but meaningless.\n */\nexport type WorkbenchState = 'collapsed' | 'expanded' | 'full-screen';\n\ntype WorkbenchActions = {\n expand: () => void;\n collapse: () => void;\n toggleExpanded: () => void;\n enterFullScreen: () => void;\n exitFullScreen: () => void;\n toggleFullScreen: () => void;\n};\n\ntype WorkbenchContextValue = WorkbenchActions & {\n state: WorkbenchState;\n setState: Dispatch<SetStateAction<WorkbenchState>>;\n panelHeight: number;\n setPanelHeight: Dispatch<SetStateAction<number>>;\n isResizing: boolean;\n setIsResizing: (isResizing: boolean) => void;\n};\n\nexport const createWorkbenchActions = (\n setState: Dispatch<SetStateAction<WorkbenchState>>,\n): WorkbenchActions => ({\n // Opening an already-open panel leaves full screen alone.\n expand: () => setState((state) => (state === 'collapsed' ? 'expanded' : state)),\n collapse: () => setState('collapsed'),\n toggleExpanded: () => setState((state) => (state === 'collapsed' ? 'expanded' : 'collapsed')),\n\n enterFullScreen: () => setState('full-screen'),\n // Exiting returns to the open panel, never to a closed one — this is a restore, not a collapse.\n exitFullScreen: () => setState((state) => (state === 'full-screen' ? 'expanded' : state)),\n toggleFullScreen: () =>\n setState((state) => (state === 'full-screen' ? 'expanded' : 'full-screen')),\n});\n\nexport const WorkbenchContext = createContext<WorkbenchContextValue | null>(null);\n\n/**\n * The parts sit at arbitrary depth under `<Workbench>` — a trigger lives inside the panel header,\n * three levels down — so the state travels by context rather than props.\n */\nexport const useWorkbench = (): WorkbenchContextValue => {\n const context = use(WorkbenchContext);\n\n if (context === null) {\n throw new Error('Workbench compound components must be rendered inside <Workbench>.');\n }\n\n return context;\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarEnd = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-end\"\n className={cn(\n // grid placement\n 'tw:col-start-3',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-end',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarMiddle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-middle\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarStart = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-start\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\nimport { WorkbenchBarEnd } from './WorkbenchBarEnd';\nimport { WorkbenchBarMiddle } from './WorkbenchBarMiddle';\nimport { WorkbenchBarStart } from './WorkbenchBarStart';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBar = ({ className, children, ...props }: Props) => (\n <div\n // Marked so a floating surface (kbc-ui's Kai widget) can measure the dock; the root's rect is the bar alone.\n data-workbench-slot=\"bar\"\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[auto_1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:h-(--workbench-bar-height)',\n 'tw:shrink-0',\n 'tw:pointer-events-auto',\n\n // surface\n 'tw:border-t',\n 'tw:border-sidebar-border',\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n\nWorkbenchBar.Start = WorkbenchBarStart;\nWorkbenchBar.Middle = WorkbenchBarMiddle;\nWorkbenchBar.End = WorkbenchBarEnd;\n","import type { ComponentProps, MouseEvent } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useWorkbench } from './context';\n\ntype Props = ComponentProps<'button'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }: Props) => {\n const { state, toggleFullScreen } = useWorkbench();\n const isFullScreen = state === 'full-screen';\n const Comp = asChild ? Slot : 'button';\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented) {\n toggleFullScreen();\n }\n };\n\n return (\n <Comp\n {...(asChild ? {} : { type: 'button' as const })}\n {...props}\n data-slot=\"workbench-full-screen-trigger\"\n data-state={isFullScreen ? 'on' : 'off'}\n onClick={handleClick}\n />\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { KeyboardEvent, PointerEvent, RefObject } from 'react';\n\nimport { cn } from '../../../utils';\nimport {\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO,\n WORKBENCH_PANEL_RESIZE_STEP_IN_PX,\n} from '../constants';\nimport { useWorkbench } from '../context';\n\ntype Props = {\n panelRef: RefObject<HTMLDivElement | null>;\n};\n\nconst getMaxHeight = (panel: HTMLDivElement) => {\n const hostTop = panel.offsetParent?.getBoundingClientRect().top ?? 0;\n\n return Math.max(panel.getBoundingClientRect().bottom - hostTop, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n};\n\nconst clampHeight = (height: number, panel: HTMLDivElement) =>\n Math.min(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX), getMaxHeight(panel));\n\nexport const WorkbenchPanelResizeHandle = ({ panelRef }: Props) => {\n const {\n state,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n enterFullScreen,\n exitFullScreen,\n } = useWorkbench();\n const grabOffsetRef = useRef(0);\n const previousStateRef = useRef(state);\n const isFullScreenRequestedRef = useRef(state === 'full-screen');\n const enteredFullScreenByDragRef = useRef(false);\n const exitedFullScreenByDragRef = useRef(false);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const { body } = document;\n const { cursor, userSelect } = body.style;\n\n body.style.cursor = 'ns-resize';\n body.style.userSelect = 'none';\n\n return () => {\n body.style.cursor = cursor;\n body.style.userSelect = userSelect;\n };\n }, [isResizing]);\n\n useEffect(() => {\n const previous = previousStateRef.current;\n const panel = panelRef.current;\n\n previousStateRef.current = state;\n isFullScreenRequestedRef.current = state === 'full-screen';\n\n if (previous !== 'full-screen' || state !== 'expanded' || !panel) return;\n\n const draggedIntoFullScreen = enteredFullScreenByDragRef.current;\n const draggedOutOfFullScreen = exitedFullScreenByDragRef.current;\n\n enteredFullScreenByDragRef.current = false;\n exitedFullScreenByDragRef.current = false;\n\n if (!draggedIntoFullScreen || draggedOutOfFullScreen) return;\n\n setPanelHeight(\n clampHeight(getMaxHeight(panel) * WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO, panel),\n );\n }, [state, panelRef, setPanelHeight]);\n\n const applyHeight = (height: number, panel: HTMLDivElement) => {\n const isFullScreen = isFullScreenRequestedRef.current;\n\n if (height >= getMaxHeight(panel)) {\n if (!isFullScreen) {\n isFullScreenRequestedRef.current = true;\n enteredFullScreenByDragRef.current = true;\n enterFullScreen();\n }\n\n return;\n }\n\n if (isFullScreen) {\n isFullScreenRequestedRef.current = false;\n exitedFullScreenByDragRef.current = true;\n exitFullScreen();\n }\n\n setPanelHeight(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX));\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (event.button !== 0 || !panel) return;\n\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n grabOffsetRef.current = panel.getBoundingClientRect().top - event.clientY;\n setIsResizing(true);\n };\n\n const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n\n const top = event.clientY + grabOffsetRef.current;\n\n applyHeight(panel.getBoundingClientRect().bottom - top, panel);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel) return;\n\n const step = event.shiftKey\n ? WORKBENCH_PANEL_RESIZE_STEP_IN_PX * 4\n : WORKBENCH_PANEL_RESIZE_STEP_IN_PX;\n const delta = event.key === 'ArrowUp' ? step : event.key === 'ArrowDown' ? -step : 0;\n\n if (delta === 0) return;\n\n event.preventDefault();\n applyHeight(\n (isFullScreenRequestedRef.current ? getMaxHeight(panel) : panelHeight) + delta,\n panel,\n );\n };\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label=\"Resize panel\"\n aria-valuenow={Math.round(panelHeight)}\n aria-valuemin={MIN_WORKBENCH_PANEL_HEIGHT_IN_PX}\n tabIndex={0}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onLostPointerCapture={() => setIsResizing(false)}\n onKeyDown={handleKeyDown}\n className={cn(\n // group\n 'tw:group/workbench-resize',\n\n // positioning — the panel is the positioned ancestor\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:top-0',\n 'tw:z-10',\n\n // sizing\n 'tw:h-2',\n\n // layout — the whole strip grabs, only the pill shows\n 'tw:flex',\n 'tw:justify-center',\n\n // affordance\n 'tw:cursor-ns-resize',\n 'tw:touch-none',\n\n // focus\n 'tw:outline-none',\n )}\n >\n <span\n className={cn(\n // layout — hangs below the strip so the pill sits clear of the top edge, and\n // grabs there too since the events bubble to the strip\n 'tw:flex',\n 'tw:h-3',\n 'tw:w-16',\n 'tw:items-end',\n 'tw:justify-center',\n )}\n >\n <span\n className={cn(\n // sizing\n 'tw:h-1.5',\n 'tw:w-16',\n\n // surface\n 'tw:rounded-full',\n 'tw:bg-input',\n 'tw:transition-colors',\n 'tw:group-hover/workbench-resize:bg-muted-foreground',\n 'tw:group-focus-visible/workbench-resize:bg-muted-foreground',\n 'tw:group-data-[workbench-resizing=true]/workbench:bg-muted-foreground',\n )}\n />\n </span>\n </div>\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { ComponentProps, CSSProperties } from 'react';\n\nimport { cn } from '../../../utils';\nimport { Collapsible } from '../../Collapsible';\n\nimport { WorkbenchPanelResizeHandle } from './WorkbenchPanelResizeHandle';\n\ntype Props = ComponentProps<'div'>;\n\nconst clearRadixMeasurementTransitionBlock = (panel: HTMLDivElement | null) => {\n if (panel) panel.style.transitionDuration = '';\n};\n\nexport const WorkbenchPanel = ({ className, children, ...props }: Props) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => clearRadixMeasurementTransitionBlock(panelRef.current), []);\n\n return (\n <Collapsible.Content\n ref={panelRef}\n // See `WorkbenchBar` — the other half of the dock's measurable area.\n data-workbench-slot=\"panel\"\n style={{ '--workbench-panel-shadow': '0 -8px 24px -6px rgb(0 0 0 / 0.08)' } as CSSProperties}\n className={cn(\n // positioning — against the host, which must be a positioned element\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:bottom-(--workbench-bar-height)',\n 'tw:pointer-events-auto',\n\n // height — the drag-controlled var, capped at the space above the bar so the panel\n // never covers it, whatever height was dragged or restored\n 'tw:h-(--workbench-panel-height)',\n 'tw:max-h-[calc(100%-var(--workbench-bar-height))]',\n 'tw:group-data-[workbench-state=full-screen]/workbench:h-[calc(100%-var(--workbench-bar-height))]',\n\n // height transition\n 'tw:transition-[height]',\n 'tw:duration-200',\n 'tw:ease-out',\n 'tw:group-data-[workbench-resizing=true]/workbench:transition-none',\n\n // surface\n 'tw:border-x',\n 'tw:border-t',\n 'tw:border-border',\n\n // clipping\n 'tw:overflow-hidden',\n\n // raised edge\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:rounded-t-2xl',\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:shadow-(--workbench-panel-shadow)',\n )}\n >\n <WorkbenchPanelResizeHandle panelRef={panelRef} />\n\n <div\n className={cn(\n // layout\n 'tw:flex',\n 'tw:flex-col',\n 'tw:h-full',\n\n // surface\n 'tw:bg-background',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </Collapsible.Content>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchPanelActions = ({ className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n\n return (\n <Comp\n {...props}\n data-slot=\"workbench-panel-actions\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelContent = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:min-h-0',\n 'tw:flex-1',\n 'tw:overflow-auto',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelHeader = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:shrink-0',\n\n // surface\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n 'tw:py-2',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelTitle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-panel-title\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n\n // typography\n 'tw:text-sm',\n 'tw:font-semibold',\n 'tw:text-foreground',\n\n className,\n )}\n />\n);\n","import { useMemo, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport {\n DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n MIN_WORKBENCH_BAR_HEIGHT_IN_REM,\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n} from './constants';\nimport type { WorkbenchState } from './context';\nimport { createWorkbenchActions, WorkbenchContext } from './context';\nimport {\n WorkbenchBar,\n WorkbenchBarEnd,\n WorkbenchBarMiddle,\n WorkbenchBarStart,\n} from './WorkbenchBar';\nimport { WorkbenchFullScreenTrigger } from './WorkbenchFullScreenTrigger';\nimport {\n WorkbenchPanel,\n WorkbenchPanelActions,\n WorkbenchPanelContent,\n WorkbenchPanelHeader,\n WorkbenchPanelTitle,\n} from './WorkbenchPanel';\n\ntype Props = {\n className?: string;\n children: ReactNode;\n state?: WorkbenchState;\n defaultState?: WorkbenchState;\n onStateChange?: (state: WorkbenchState) => void;\n barHeight?: number;\n panelHeight?: number;\n defaultPanelHeight?: number;\n onPanelHeightChange?: (panelHeight: number) => void;\n};\n\nexport const Workbench = ({\n className,\n children,\n state: stateProp,\n defaultState = 'collapsed',\n onStateChange,\n barHeight = DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n panelHeight: panelHeightProp,\n defaultPanelHeight = DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n onPanelHeightChange,\n}: Props) => {\n const [state, setState] = useControllableState<WorkbenchState>({\n prop: stateProp,\n defaultProp: defaultState,\n onChange: onStateChange,\n });\n const [panelHeight, setPanelHeight] = useControllableState<number>({\n prop: panelHeightProp,\n defaultProp: defaultPanelHeight,\n onChange: onPanelHeightChange,\n });\n const [isResizing, setIsResizing] = useState(false);\n\n const actions = useMemo(() => createWorkbenchActions(setState), [setState]);\n const value = useMemo(\n () => ({\n state,\n setState,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n ...actions,\n }),\n [state, setState, panelHeight, setPanelHeight, isResizing, actions],\n );\n\n const clampedBarHeight = Math.max(barHeight, MIN_WORKBENCH_BAR_HEIGHT_IN_REM);\n const clampedPanelHeight = Math.max(panelHeight, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n\n return (\n <WorkbenchContext value={value}>\n <Collapsible\n open={state !== 'collapsed'}\n onOpenChange={(open) => setState(open ? 'expanded' : 'collapsed')}\n data-workbench-state={state}\n data-workbench-resizing={isResizing ? 'true' : undefined}\n style={\n {\n '--workbench-bar-height': `${clampedBarHeight}rem`,\n '--workbench-panel-height': `${clampedPanelHeight}px`,\n } as CSSProperties\n }\n className={cn(\n // reset\n 'tailwindcss-preflight',\n\n // group\n 'tw:group/workbench',\n\n // positioning — above the chrome layer (`z-50`) *and* above a `Sidebar` in\n // `expand-on-hover`, which takes `z-51` to float over content; the dock outranks both.\n // Overlays (Modal / Sheet / Popover / Tooltip) live at 1051+, so they still win.\n 'tw:z-[52]',\n\n // layout\n 'tw:shrink-0',\n\n className,\n )}\n >\n {children}\n </Collapsible>\n </WorkbenchContext>\n );\n};\n\nWorkbench.Bar = WorkbenchBar;\nWorkbench.BarStart = WorkbenchBarStart;\nWorkbench.BarMiddle = WorkbenchBarMiddle;\nWorkbench.BarEnd = WorkbenchBarEnd;\n\nWorkbench.Panel = WorkbenchPanel;\nWorkbench.PanelHeader = WorkbenchPanelHeader;\nWorkbench.PanelTitle = WorkbenchPanelTitle;\nWorkbench.PanelActions = WorkbenchPanelActions;\nWorkbench.PanelContent = WorkbenchPanelContent;\n\nWorkbench.Trigger = Collapsible.Trigger;\nWorkbench.FullScreenTrigger = WorkbenchFullScreenTrigger;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Workbench-CxgNCs3I.js","names":[],"sources":["../src/components/Workbench/constants.ts","../src/components/Workbench/context.ts","../src/components/Workbench/WorkbenchBar/WorkbenchBarEnd.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarMiddle.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBarStart.tsx","../src/components/Workbench/WorkbenchBar/WorkbenchBar.tsx","../src/components/Workbench/WorkbenchFullScreenTrigger.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelResizeHandle.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanel.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelActions.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelContent.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelHeader.tsx","../src/components/Workbench/WorkbenchPanel/WorkbenchPanelTitle.tsx","../src/components/Workbench/Workbench.tsx"],"sourcesContent":["export const DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM = 2.75;\n\nexport const MIN_WORKBENCH_BAR_HEIGHT_IN_REM = 1;\n\nexport const DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX = 320;\n\nexport const MIN_WORKBENCH_PANEL_HEIGHT_IN_PX = 120;\n\nexport const WORKBENCH_PANEL_RESIZE_STEP_IN_PX = 24;\n\nexport const WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO = 0.8;\n","import { createContext, use } from 'react';\nimport type { Dispatch, SetStateAction } from 'react';\n\n/**\n * Full screen is a mode of the open panel, not a flag beside it — as two booleans the fourth\n * combination (collapsed *and* full screen) is expressible but meaningless.\n */\nexport type WorkbenchState = 'collapsed' | 'expanded' | 'full-screen';\n\ntype WorkbenchActions = {\n expand: () => void;\n collapse: () => void;\n toggleExpanded: () => void;\n enterFullScreen: () => void;\n exitFullScreen: () => void;\n toggleFullScreen: () => void;\n};\n\ntype WorkbenchContextValue = WorkbenchActions & {\n state: WorkbenchState;\n setState: Dispatch<SetStateAction<WorkbenchState>>;\n panelHeight: number;\n setPanelHeight: Dispatch<SetStateAction<number>>;\n isResizing: boolean;\n setIsResizing: (isResizing: boolean) => void;\n};\n\nexport const createWorkbenchActions = (\n setState: Dispatch<SetStateAction<WorkbenchState>>,\n): WorkbenchActions => ({\n // Opening an already-open panel leaves full screen alone.\n expand: () => setState((state) => (state === 'collapsed' ? 'expanded' : state)),\n collapse: () => setState('collapsed'),\n toggleExpanded: () => setState((state) => (state === 'collapsed' ? 'expanded' : 'collapsed')),\n\n enterFullScreen: () => setState('full-screen'),\n // Exiting returns to the open panel, never to a closed one — this is a restore, not a collapse.\n exitFullScreen: () => setState((state) => (state === 'full-screen' ? 'expanded' : state)),\n toggleFullScreen: () =>\n setState((state) => (state === 'full-screen' ? 'expanded' : 'full-screen')),\n});\n\nexport const WorkbenchContext = createContext<WorkbenchContextValue | null>(null);\n\n/**\n * The parts sit at arbitrary depth under `<Workbench>` — a trigger lives inside the panel header,\n * three levels down — so the state travels by context rather than props.\n */\nexport const useWorkbench = (): WorkbenchContextValue => {\n const context = use(WorkbenchContext);\n\n if (context === null) {\n throw new Error('Workbench compound components must be rendered inside <Workbench>.');\n }\n\n return context;\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarEnd = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-end\"\n className={cn(\n // grid placement\n 'tw:col-start-3',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-end',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarMiddle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-middle\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBarStart = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-bar-start\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\nimport { WorkbenchBarEnd } from './WorkbenchBarEnd';\nimport { WorkbenchBarMiddle } from './WorkbenchBarMiddle';\nimport { WorkbenchBarStart } from './WorkbenchBarStart';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchBar = ({ className, children, ...props }: Props) => (\n <div\n // Marked so a floating surface (kbc-ui's Kai widget) can measure the dock; the root's rect is the bar alone.\n data-workbench-slot=\"bar\"\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[auto_1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:h-(--workbench-bar-height)',\n 'tw:shrink-0',\n 'tw:pointer-events-auto',\n\n // surface\n 'tw:border-t',\n 'tw:border-sidebar-border',\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n\nWorkbenchBar.Start = WorkbenchBarStart;\nWorkbenchBar.Middle = WorkbenchBarMiddle;\nWorkbenchBar.End = WorkbenchBarEnd;\n","import type { ComponentProps, MouseEvent } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useWorkbench } from './context';\n\ntype Props = ComponentProps<'button'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchFullScreenTrigger = ({ asChild = false, onClick, ...props }: Props) => {\n const { state, toggleFullScreen } = useWorkbench();\n const isFullScreen = state === 'full-screen';\n const Comp = asChild ? Slot : 'button';\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented) {\n toggleFullScreen();\n }\n };\n\n return (\n <Comp\n {...(asChild ? {} : { type: 'button' as const })}\n {...props}\n data-slot=\"workbench-full-screen-trigger\"\n data-state={isFullScreen ? 'on' : 'off'}\n onClick={handleClick}\n />\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { KeyboardEvent, PointerEvent, RefObject } from 'react';\n\nimport { cn } from '../../../utils';\nimport {\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO,\n WORKBENCH_PANEL_RESIZE_STEP_IN_PX,\n} from '../constants';\nimport { useWorkbench } from '../context';\n\ntype Props = {\n panelRef: RefObject<HTMLDivElement | null>;\n};\n\nconst getMaxHeight = (panel: HTMLDivElement) => {\n const hostTop = panel.offsetParent?.getBoundingClientRect().top ?? 0;\n\n return Math.max(panel.getBoundingClientRect().bottom - hostTop, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n};\n\nconst clampHeight = (height: number, panel: HTMLDivElement) =>\n Math.min(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX), getMaxHeight(panel));\n\nexport const WorkbenchPanelResizeHandle = ({ panelRef }: Props) => {\n const {\n state,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n enterFullScreen,\n exitFullScreen,\n } = useWorkbench();\n const grabOffsetRef = useRef(0);\n const previousStateRef = useRef(state);\n const isFullScreenRequestedRef = useRef(state === 'full-screen');\n const enteredFullScreenByDragRef = useRef(false);\n const exitedFullScreenByDragRef = useRef(false);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const { body } = document;\n const { cursor, userSelect } = body.style;\n\n body.style.cursor = 'ns-resize';\n body.style.userSelect = 'none';\n\n return () => {\n body.style.cursor = cursor;\n body.style.userSelect = userSelect;\n };\n }, [isResizing]);\n\n useEffect(() => {\n const previous = previousStateRef.current;\n const panel = panelRef.current;\n\n previousStateRef.current = state;\n isFullScreenRequestedRef.current = state === 'full-screen';\n\n if (previous !== 'full-screen' || state !== 'expanded' || !panel) return;\n\n const draggedIntoFullScreen = enteredFullScreenByDragRef.current;\n const draggedOutOfFullScreen = exitedFullScreenByDragRef.current;\n\n enteredFullScreenByDragRef.current = false;\n exitedFullScreenByDragRef.current = false;\n\n if (!draggedIntoFullScreen || draggedOutOfFullScreen) return;\n\n setPanelHeight(\n clampHeight(getMaxHeight(panel) * WORKBENCH_PANEL_FULL_SCREEN_EXIT_RATIO, panel),\n );\n }, [state, panelRef, setPanelHeight]);\n\n const applyHeight = (height: number, panel: HTMLDivElement) => {\n const isFullScreen = isFullScreenRequestedRef.current;\n\n if (height >= getMaxHeight(panel)) {\n if (!isFullScreen) {\n isFullScreenRequestedRef.current = true;\n enteredFullScreenByDragRef.current = true;\n enterFullScreen();\n }\n\n return;\n }\n\n if (isFullScreen) {\n isFullScreenRequestedRef.current = false;\n exitedFullScreenByDragRef.current = true;\n exitFullScreen();\n }\n\n setPanelHeight(Math.max(height, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX));\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (event.button !== 0 || !panel) return;\n\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n grabOffsetRef.current = panel.getBoundingClientRect().top - event.clientY;\n setIsResizing(true);\n };\n\n const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel || !event.currentTarget.hasPointerCapture(event.pointerId)) return;\n\n const top = event.clientY + grabOffsetRef.current;\n\n applyHeight(panel.getBoundingClientRect().bottom - top, panel);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const panel = panelRef.current;\n\n if (!panel) return;\n\n const step = event.shiftKey\n ? WORKBENCH_PANEL_RESIZE_STEP_IN_PX * 4\n : WORKBENCH_PANEL_RESIZE_STEP_IN_PX;\n const delta = event.key === 'ArrowUp' ? step : event.key === 'ArrowDown' ? -step : 0;\n\n if (delta === 0) return;\n\n event.preventDefault();\n applyHeight(\n (isFullScreenRequestedRef.current ? getMaxHeight(panel) : panelHeight) + delta,\n panel,\n );\n };\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label=\"Resize panel\"\n aria-valuenow={Math.round(panelHeight)}\n aria-valuemin={MIN_WORKBENCH_PANEL_HEIGHT_IN_PX}\n tabIndex={0}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onLostPointerCapture={() => setIsResizing(false)}\n onKeyDown={handleKeyDown}\n className={cn(\n // group\n 'tw:group/workbench-resize',\n\n // positioning — the panel is the positioned ancestor\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:top-0',\n 'tw:z-10',\n\n // sizing\n 'tw:h-2',\n\n // layout — the whole strip grabs, only the pill shows\n 'tw:flex',\n 'tw:justify-center',\n\n // affordance\n 'tw:cursor-ns-resize',\n 'tw:touch-none',\n\n // focus\n 'tw:outline-none',\n )}\n >\n <span\n className={cn(\n // layout — hangs below the strip so the pill sits clear of the top edge, and\n // grabs there too since the events bubble to the strip\n 'tw:flex',\n 'tw:h-3',\n 'tw:w-16',\n 'tw:items-end',\n 'tw:justify-center',\n )}\n >\n <span\n className={cn(\n // sizing\n 'tw:h-1.5',\n 'tw:w-16',\n\n // surface\n 'tw:rounded-full',\n 'tw:bg-input',\n 'tw:transition-colors',\n 'tw:group-hover/workbench-resize:bg-muted-foreground',\n 'tw:group-focus-visible/workbench-resize:bg-muted-foreground',\n 'tw:group-data-[workbench-resizing=true]/workbench:bg-muted-foreground',\n )}\n />\n </span>\n </div>\n );\n};\n","import { useEffect, useRef } from 'react';\nimport type { ComponentProps, CSSProperties } from 'react';\n\nimport { cn } from '../../../utils';\nimport { Collapsible } from '../../Collapsible';\n\nimport { WorkbenchPanelResizeHandle } from './WorkbenchPanelResizeHandle';\n\ntype Props = ComponentProps<'div'>;\n\nconst clearRadixMeasurementTransitionBlock = (panel: HTMLDivElement | null) => {\n if (panel) panel.style.transitionDuration = '';\n};\n\nexport const WorkbenchPanel = ({ className, children, ...props }: Props) => {\n const panelRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => clearRadixMeasurementTransitionBlock(panelRef.current), []);\n\n return (\n <Collapsible.Content\n ref={panelRef}\n // See `WorkbenchBar` — the other half of the dock's measurable area.\n data-workbench-slot=\"panel\"\n style={{ '--workbench-panel-shadow': '0 -8px 24px -6px rgb(0 0 0 / 0.08)' } as CSSProperties}\n className={cn(\n // positioning — against the host, which must be a positioned element\n 'tw:absolute',\n 'tw:inset-x-0',\n 'tw:bottom-(--workbench-bar-height)',\n 'tw:pointer-events-auto',\n\n // height — the drag-controlled var, capped at the space above the bar so the panel\n // never covers it, whatever height was dragged or restored\n 'tw:h-(--workbench-panel-height)',\n 'tw:max-h-[calc(100%-var(--workbench-bar-height))]',\n 'tw:group-data-[workbench-state=full-screen]/workbench:h-[calc(100%-var(--workbench-bar-height))]',\n\n // height transition\n 'tw:transition-[height]',\n 'tw:duration-200',\n 'tw:ease-out',\n 'tw:group-data-[workbench-resizing=true]/workbench:transition-none',\n\n // surface\n 'tw:border-x',\n 'tw:border-t',\n 'tw:border-border',\n\n // clipping\n 'tw:overflow-hidden',\n\n // raised edge\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:rounded-t-2xl',\n 'tw:group-not-data-[workbench-state=full-screen]/workbench:shadow-(--workbench-panel-shadow)',\n )}\n >\n <WorkbenchPanelResizeHandle panelRef={panelRef} />\n\n <div\n className={cn(\n // layout\n 'tw:flex',\n 'tw:flex-col',\n 'tw:h-full',\n\n // surface\n 'tw:bg-background',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n </Collapsible.Content>\n );\n};\n","import type { ComponentProps } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'> & {\n asChild?: boolean;\n};\n\nexport const WorkbenchPanelActions = ({ className, asChild = false, ...props }: Props) => {\n const Comp = asChild ? Slot : 'div';\n\n return (\n <Comp\n {...props}\n data-slot=\"workbench-panel-actions\"\n className={cn(\n // grid placement\n 'tw:col-start-2',\n 'tw:row-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n 'tw:gap-2',\n\n className,\n )}\n />\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelContent = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:min-h-0',\n 'tw:flex-1',\n 'tw:overflow-auto',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelHeader = ({ className, children, ...props }: Props) => (\n <div\n className={cn(\n // layout\n 'tw:grid',\n 'tw:grid-cols-[1fr_auto]',\n 'tw:items-center',\n 'tw:gap-x-2',\n\n // sizing\n 'tw:shrink-0',\n\n // surface\n 'tw:bg-sidebar',\n\n // spacing\n 'tw:px-3',\n 'tw:py-2',\n\n // typography\n 'tw:text-xs',\n\n className,\n )}\n {...props}\n >\n {children}\n </div>\n);\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../../utils';\n\ntype Props = ComponentProps<'div'>;\n\nexport const WorkbenchPanelTitle = ({ className, ...props }: Props) => (\n <div\n {...props}\n data-slot=\"workbench-panel-title\"\n className={cn(\n // grid placement\n 'tw:col-start-1',\n\n // layout\n 'tw:flex',\n 'tw:items-center',\n\n // typography\n 'tw:text-sm',\n 'tw:font-semibold',\n 'tw:text-foreground',\n\n className,\n )}\n />\n);\n","import { useMemo, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\nimport { useControllableState } from '../../hooks/useControllableState';\nimport { cn } from '../../utils';\nimport { Collapsible } from '../Collapsible';\n\nimport {\n DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n MIN_WORKBENCH_BAR_HEIGHT_IN_REM,\n MIN_WORKBENCH_PANEL_HEIGHT_IN_PX,\n} from './constants';\nimport type { WorkbenchState } from './context';\nimport { createWorkbenchActions, WorkbenchContext } from './context';\nimport {\n WorkbenchBar,\n WorkbenchBarEnd,\n WorkbenchBarMiddle,\n WorkbenchBarStart,\n} from './WorkbenchBar';\nimport { WorkbenchFullScreenTrigger } from './WorkbenchFullScreenTrigger';\nimport {\n WorkbenchPanel,\n WorkbenchPanelActions,\n WorkbenchPanelContent,\n WorkbenchPanelHeader,\n WorkbenchPanelTitle,\n} from './WorkbenchPanel';\n\ntype Props = {\n className?: string;\n children: ReactNode;\n state?: WorkbenchState;\n defaultState?: WorkbenchState;\n onStateChange?: (state: WorkbenchState) => void;\n barHeight?: number;\n panelHeight?: number;\n defaultPanelHeight?: number;\n onPanelHeightChange?: (panelHeight: number) => void;\n};\n\nexport const Workbench = ({\n className,\n children,\n state: stateProp,\n defaultState = 'collapsed',\n onStateChange,\n barHeight = DEFAULT_WORKBENCH_BAR_HEIGHT_IN_REM,\n panelHeight: panelHeightProp,\n defaultPanelHeight = DEFAULT_WORKBENCH_PANEL_HEIGHT_IN_PX,\n onPanelHeightChange,\n}: Props) => {\n const [state, setState] = useControllableState<WorkbenchState>({\n prop: stateProp,\n defaultProp: defaultState,\n onChange: onStateChange,\n });\n const [panelHeight, setPanelHeight] = useControllableState<number>({\n prop: panelHeightProp,\n defaultProp: defaultPanelHeight,\n onChange: onPanelHeightChange,\n });\n const [isResizing, setIsResizing] = useState(false);\n\n const actions = useMemo(() => createWorkbenchActions(setState), [setState]);\n const value = useMemo(\n () => ({\n state,\n setState,\n panelHeight,\n setPanelHeight,\n isResizing,\n setIsResizing,\n ...actions,\n }),\n [state, setState, panelHeight, setPanelHeight, isResizing, actions],\n );\n\n const clampedBarHeight = Math.max(barHeight, MIN_WORKBENCH_BAR_HEIGHT_IN_REM);\n const clampedPanelHeight = Math.max(panelHeight, MIN_WORKBENCH_PANEL_HEIGHT_IN_PX);\n\n return (\n <WorkbenchContext value={value}>\n <Collapsible\n open={state !== 'collapsed'}\n onOpenChange={(open) => setState(open ? 'expanded' : 'collapsed')}\n data-workbench-state={state}\n data-workbench-resizing={isResizing ? 'true' : undefined}\n style={\n {\n '--workbench-bar-height': `${clampedBarHeight}rem`,\n '--workbench-panel-height': `${clampedPanelHeight}px`,\n } as CSSProperties\n }\n className={cn(\n // reset\n 'tailwindcss-preflight',\n\n // group\n 'tw:group/workbench',\n\n // positioning — above the chrome layer (`z-50`) *and* above a `Sidebar` in\n // `expand-on-hover`, which takes `z-51` to float over content; the dock outranks both.\n // Overlays (Modal / Sheet / Popover / Tooltip) live at 1051+, so they still win.\n 'tw:z-[52]',\n\n // layout\n 'tw:shrink-0',\n\n className,\n )}\n >\n {children}\n </Collapsible>\n </WorkbenchContext>\n );\n};\n\nWorkbench.Bar = WorkbenchBar;\nWorkbench.BarStart = WorkbenchBarStart;\nWorkbench.BarMiddle = WorkbenchBarMiddle;\nWorkbench.BarEnd = WorkbenchBarEnd;\n\nWorkbench.Panel = WorkbenchPanel;\nWorkbench.PanelHeader = WorkbenchPanelHeader;\nWorkbench.PanelTitle = WorkbenchPanelTitle;\nWorkbench.PanelActions = WorkbenchPanelActions;\nWorkbench.PanelContent = WorkbenchPanelContent;\n\nWorkbench.Trigger = Collapsible.Trigger;\nWorkbench.FullScreenTrigger = WorkbenchFullScreenTrigger;\n"],"mappings":"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"}
@@ -1,24 +1,102 @@
1
- import { cn } from "./classNames-BzrkDnOD.js";
2
- import { Tooltip } from "./utils-Bd28bWgm.js";
3
- import { Maximize2, Minimize2 } from "./icons-wcA70iQx.js";
4
- import { Button } from "./Button-B21oVcPU.js";
5
- import { ClipboardButton } from "./ClipboardButton-srUgWgwH.js";
1
+ import { cn } from "./classNames-DcGnTh2N.js";
2
+ import { Tooltip } from "./utils-LQ4jJA-9.js";
3
+ import { Maximize2, Minimize2 } from "./icons-ZIeZXXS7.js";
4
+ import { Button } from "./Button-D2JqBAq7.js";
5
+ import { ClipboardButton } from "./ClipboardButton-DxvZG_H0.js";
6
6
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { createPortal } from "react-dom";
9
9
  import DOMPurify from "dompurify";
10
+ //#region src/components/ZoomableSvg/exportSvg.ts
11
+ const PNG_SCALE = 2;
12
+ const ROOT_SVG_TAG = /^<svg\b[^>]*>/i;
13
+ const HAS_DEFAULT_NAMESPACE = /\bxmlns\s*=/i;
14
+ const withSvgNamespace = (svg) => {
15
+ const trimmed = svg.trim();
16
+ const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];
17
+ if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;
18
+ return trimmed.replace(/^<svg\b/i, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
19
+ };
20
+ const toSvgFileContent = (svg) => `<?xml version="1.0" encoding="UTF-8"?>\n${withSvgNamespace(svg).trim()}\n`;
21
+ const NUMBER = String.raw`\d+(?:\.\d+)?|\.\d+`;
22
+ const PIXEL_LENGTH = new RegExp(String.raw`^\s*(?:${NUMBER})(?:px)?\s*$`, "i");
23
+ const parsePixelLength = (value) => {
24
+ if (!PIXEL_LENGTH.test(value ?? "")) return null;
25
+ const parsed = Number.parseFloat(value ?? "");
26
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
27
+ };
28
+ const parseSvgSize = (svg) => {
29
+ const element = new DOMParser().parseFromString(withSvgNamespace(svg), "image/svg+xml").documentElement;
30
+ const viewBox = element.getAttribute("viewBox")?.split(/[\s,]+/).map(Number);
31
+ if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {
32
+ const [, , width, height] = viewBox;
33
+ if (width !== void 0 && height !== void 0 && width > 0 && height > 0) return {
34
+ width,
35
+ height
36
+ };
37
+ }
38
+ const width = parsePixelLength(element.getAttribute("width"));
39
+ const height = parsePixelLength(element.getAttribute("height"));
40
+ return width !== null && height !== null ? {
41
+ width,
42
+ height
43
+ } : null;
44
+ };
45
+ const CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\s+(?:${NUMBER})\s+(?:${NUMBER})$`);
46
+ const toCanvasColor = (token) => {
47
+ const trimmed = token.trim();
48
+ if (!trimmed) return "white";
49
+ return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;
50
+ };
51
+ const resolveBackground = () => toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--color-background"));
52
+ /**
53
+ * Rasterize SVG markup to a PNG blob at 2x for legible text.
54
+ *
55
+ * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG
56
+ * is treated as a foreign resource, so a blob URL would taint the canvas and
57
+ * make toBlob throw a SecurityError. A background is painted first because a
58
+ * transparent PNG reads as unusable when pasted into a slide deck.
59
+ */
60
+ const svgToPngBlob = async (svg, background) => {
61
+ const size = parseSvgSize(svg);
62
+ if (!size) throw new Error("Cannot determine diagram dimensions.");
63
+ const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;
64
+ const image = new Image();
65
+ image.decoding = "sync";
66
+ await new Promise((resolve, reject) => {
67
+ image.onload = () => resolve();
68
+ image.onerror = () => reject(/* @__PURE__ */ new Error("Failed to load the diagram for export."));
69
+ image.src = encoded;
70
+ });
71
+ const canvas = document.createElement("canvas");
72
+ canvas.width = Math.round(size.width * PNG_SCALE);
73
+ canvas.height = Math.round(size.height * PNG_SCALE);
74
+ const context = canvas.getContext("2d");
75
+ if (!context) throw new Error("Canvas is unavailable in this browser.");
76
+ context.fillStyle = background ?? resolveBackground();
77
+ context.fillRect(0, 0, canvas.width, canvas.height);
78
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
79
+ return new Promise((resolve, reject) => {
80
+ canvas.toBlob((blob) => blob ? resolve(blob) : reject(/* @__PURE__ */ new Error("Failed to encode the PNG.")), "image/png");
81
+ });
82
+ };
83
+ //#endregion
10
84
  //#region src/components/ZoomableSvg/ZoomableSvg.tsx
11
85
  const MIN_SCALE = .5;
12
86
  const MAX_SCALE = 3;
13
87
  const ZOOM_STEP = .1;
14
- const ZoomableSvg = ({ html, copyText, className, allowForeignObject, renderActions }) => {
88
+ const ZoomableSvg = ({ html, copyText, className, allowForeignObject, allowUse, renderActions }) => {
15
89
  const safeHtml = useMemo(() => DOMPurify.sanitize(html, {
16
90
  USE_PROFILES: {
17
91
  svg: true,
18
92
  svgFilters: true
19
93
  },
20
- ...allowForeignObject ? { ADD_TAGS: ["foreignObject"] } : {}
21
- }), [html, allowForeignObject]);
94
+ ADD_TAGS: [...allowForeignObject ? ["foreignObject"] : [], ...allowUse ? ["use"] : []]
95
+ }), [
96
+ html,
97
+ allowForeignObject,
98
+ allowUse
99
+ ]);
22
100
  const containerRef = useRef(null);
23
101
  const [scale, setScale] = useState(1);
24
102
  const [translate, setTranslate] = useState({
@@ -155,80 +233,6 @@ const ZoomableSvg = ({ html, copyText, className, allowForeignObject, renderActi
155
233
  });
156
234
  };
157
235
  //#endregion
158
- //#region src/components/ZoomableSvg/exportSvg.ts
159
- const PNG_SCALE = 2;
160
- const ROOT_SVG_TAG = /^<svg\b[^>]*>/i;
161
- const HAS_DEFAULT_NAMESPACE = /\bxmlns\s*=/i;
162
- const withSvgNamespace = (svg) => {
163
- const trimmed = svg.trim();
164
- const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];
165
- if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;
166
- return trimmed.replace(/^<svg\b/i, "<svg xmlns=\"http://www.w3.org/2000/svg\"");
167
- };
168
- const toSvgFileContent = (svg) => `<?xml version="1.0" encoding="UTF-8"?>\n${withSvgNamespace(svg).trim()}\n`;
169
- const NUMBER = String.raw`\d+(?:\.\d+)?|\.\d+`;
170
- const PIXEL_LENGTH = new RegExp(String.raw`^\s*(?:${NUMBER})(?:px)?\s*$`, "i");
171
- const parsePixelLength = (value) => {
172
- if (!PIXEL_LENGTH.test(value ?? "")) return null;
173
- const parsed = Number.parseFloat(value ?? "");
174
- return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
175
- };
176
- const parseSvgSize = (svg) => {
177
- const element = new DOMParser().parseFromString(withSvgNamespace(svg), "image/svg+xml").documentElement;
178
- const viewBox = element.getAttribute("viewBox")?.split(/[\s,]+/).map(Number);
179
- if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {
180
- const [, , width, height] = viewBox;
181
- if (width !== void 0 && height !== void 0 && width > 0 && height > 0) return {
182
- width,
183
- height
184
- };
185
- }
186
- const width = parsePixelLength(element.getAttribute("width"));
187
- const height = parsePixelLength(element.getAttribute("height"));
188
- return width !== null && height !== null ? {
189
- width,
190
- height
191
- } : null;
192
- };
193
- const CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\s+(?:${NUMBER})\s+(?:${NUMBER})$`);
194
- const toCanvasColor = (token) => {
195
- const trimmed = token.trim();
196
- if (!trimmed) return "white";
197
- return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;
198
- };
199
- const resolveBackground = () => toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue("--color-background"));
200
- /**
201
- * Rasterize SVG markup to a PNG blob at 2x for legible text.
202
- *
203
- * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG
204
- * is treated as a foreign resource, so a blob URL would taint the canvas and
205
- * make toBlob throw a SecurityError. A background is painted first because a
206
- * transparent PNG reads as unusable when pasted into a slide deck.
207
- */
208
- const svgToPngBlob = async (svg, background) => {
209
- const size = parseSvgSize(svg);
210
- if (!size) throw new Error("Cannot determine diagram dimensions.");
211
- const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;
212
- const image = new Image();
213
- image.decoding = "sync";
214
- await new Promise((resolve, reject) => {
215
- image.onload = () => resolve();
216
- image.onerror = () => reject(/* @__PURE__ */ new Error("Failed to load the diagram for export."));
217
- image.src = encoded;
218
- });
219
- const canvas = document.createElement("canvas");
220
- canvas.width = Math.round(size.width * PNG_SCALE);
221
- canvas.height = Math.round(size.height * PNG_SCALE);
222
- const context = canvas.getContext("2d");
223
- if (!context) throw new Error("Canvas is unavailable in this browser.");
224
- context.fillStyle = background ?? resolveBackground();
225
- context.fillRect(0, 0, canvas.width, canvas.height);
226
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
227
- return new Promise((resolve, reject) => {
228
- canvas.toBlob((blob) => blob ? resolve(blob) : reject(/* @__PURE__ */ new Error("Failed to encode the PNG.")), "image/png");
229
- });
230
- };
231
- //#endregion
232
236
  export { ZoomableSvg, svgToPngBlob, toSvgFileContent };
233
237
 
234
- //# sourceMappingURL=ZoomableSvg-C65nta_r.js.map
238
+ //# sourceMappingURL=ZoomableSvg-Dh1OstPN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ZoomableSvg-Dh1OstPN.js","names":[],"sources":["../src/components/ZoomableSvg/exportSvg.ts","../src/components/ZoomableSvg/ZoomableSvg.tsx"],"sourcesContent":["const PNG_SCALE = 2;\n\n// The root `<svg …>` tag, so the namespace check looks only at its attributes.\n// A plain `includes('xmlns=')` would also match a nested element or body text,\n// and would miss `xmlns = \"…\"` — adding a second declaration, which parsers\n// reject outright with \"Attribute xmlns redefined\".\nconst ROOT_SVG_TAG = /^<svg\\b[^>]*>/i;\nconst HAS_DEFAULT_NAMESPACE = /\\bxmlns\\s*=/i;\n\n// A standalone SVG file needs the namespace declaration; inline diagram output may\n// omit it because an inline <svg> inherits it from the host document.\n// Trim before matching: the anchored `^<svg` misses markup that arrives with a\n// leading newline or indentation, which would emit a standalone file with no\n// namespace — unopenable in an image viewer.\nconst withSvgNamespace = (svg: string) => {\n const trimmed = svg.trim();\n const rootTag = trimmed.match(ROOT_SVG_TAG)?.[0];\n\n if (!rootTag || HAS_DEFAULT_NAMESPACE.test(rootTag)) return trimmed;\n\n return trimmed.replace(/^<svg\\b/i, '<svg xmlns=\"http://www.w3.org/2000/svg\"');\n};\n\nexport const toSvgFileContent = (svg: string) =>\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${withSvgNamespace(svg).trim()}\\n`;\n\n// A single decimal number: `12`, `12.5`, `.5`. Deliberately stricter than\n// `[\\d.]+`, which also matches `1.2.3` — and `parseFloat` truncates that to\n// `1.2` rather than rejecting it, so a malformed value would pass as a plausible\n// one.\nconst NUMBER = String.raw`\\d+(?:\\.\\d+)?|\\.\\d+`;\n\n// `parseFloat` happily reads a relative length as a number — `\"100%\"` becomes\n// `100`, `\"2em\"` becomes `2` — and `makeResponsive` sets `width=\"100%\"` on every\n// diagram root, so an SVG with no usable viewBox would rasterize 100px wide with\n// no error. Accept only a unitless number or an explicit `px`.\nconst PIXEL_LENGTH = new RegExp(String.raw`^\\s*(?:${NUMBER})(?:px)?\\s*$`, 'i');\n\nconst parsePixelLength = (value: string | null): number | null => {\n if (!PIXEL_LENGTH.test(value ?? '')) return null;\n\n const parsed = Number.parseFloat(value ?? '');\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n};\n\nexport const parseSvgSize = (svg: string) => {\n const doc = new DOMParser().parseFromString(withSvgNamespace(svg), 'image/svg+xml');\n const element = doc.documentElement;\n\n const viewBox = element\n .getAttribute('viewBox')\n ?.split(/[\\s,]+/)\n .map(Number);\n // `> 0`, not truthiness: a negative extent is accepted by a truthy check, and\n // negative canvas dimensions silently fall back to the 300x150 default — an\n // export at the wrong size with no error. Falling through to width/height is\n // the better answer, since those are usually still valid.\n if (viewBox?.length === 4 && viewBox.every((value) => Number.isFinite(value))) {\n const [, , width, height] = viewBox;\n if (width !== undefined && height !== undefined && width > 0 && height > 0) {\n return { width, height };\n }\n }\n\n const width = parsePixelLength(element.getAttribute('width'));\n const height = parsePixelLength(element.getAttribute('height'));\n\n return width !== null && height !== null ? { width, height } : null;\n};\n\n// Resolve the themed page background so the exported PNG follows the active\n// brand and color scheme instead of a frozen literal. Falls back to `white`\n// (a CSS keyword, not a brand-locked hex) when the token is unset.\n//\n// The token holds Tailwind's bare channel triplet (\"249 250 251\") so utilities\n// can add an alpha. Canvas `fillStyle` rejects that form *silently* and keeps\n// its previous value (black), so wrap it back into rgb() before use.\nconst CHANNEL_TRIPLET = new RegExp(String.raw`^(?:${NUMBER})\\s+(?:${NUMBER})\\s+(?:${NUMBER})$`);\n\nexport const toCanvasColor = (token: string) => {\n const trimmed = token.trim();\n if (!trimmed) return 'white';\n\n // Only wrap a well-formed triplet. A malformed one (`1.2.3 4 5`) would produce\n // an invalid `rgb()` that `fillStyle` rejects silently, painting the PNG on\n // whatever colour was set before — passing it through unwrapped at least lets\n // a genuine CSS color value work.\n return CHANNEL_TRIPLET.test(trimmed) ? `rgb(${trimmed})` : trimmed;\n};\n\nconst resolveBackground = () =>\n toCanvasColor(getComputedStyle(document.documentElement).getPropertyValue('--color-background'));\n\n/**\n * Rasterize SVG markup to a PNG blob at 2x for legible text.\n *\n * The SVG is loaded as a data URL rather than a blob URL: an <img> loading SVG\n * is treated as a foreign resource, so a blob URL would taint the canvas and\n * make toBlob throw a SecurityError. A background is painted first because a\n * transparent PNG reads as unusable when pasted into a slide deck.\n */\nexport const svgToPngBlob = async (svg: string, background?: string): Promise<Blob> => {\n const size = parseSvgSize(svg);\n if (!size) throw new Error('Cannot determine diagram dimensions.');\n\n const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(toSvgFileContent(svg))}`;\n\n const image = new Image();\n image.decoding = 'sync';\n await new Promise<void>((resolve, reject) => {\n image.onload = () => resolve();\n image.onerror = () => reject(new Error('Failed to load the diagram for export.'));\n image.src = encoded;\n });\n\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(size.width * PNG_SCALE);\n canvas.height = Math.round(size.height * PNG_SCALE);\n\n const context = canvas.getContext('2d');\n if (!context) throw new Error('Canvas is unavailable in this browser.');\n\n context.fillStyle = background ?? resolveBackground();\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error('Failed to encode the PNG.'))),\n 'image/png',\n );\n });\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport DOMPurify from 'dompurify';\n\nimport { ClipboardButton } from '../../blocks/ClipboardButton';\nimport { Maximize2, Minimize2 } from '../../icons';\nimport { cn } from '../../utils';\nimport { Button } from '../Button';\nimport { Tooltip } from '../Tooltip';\n\nconst MIN_SCALE = 0.5;\nconst MAX_SCALE = 3;\nconst ZOOM_STEP = 0.1;\n\ntype Props = {\n /** Raw SVG markup; DOMPurify-sanitized (SVG profile), so user/LLM content is safe. */\n html: string;\n copyText?: string;\n className?: string;\n /** Keep `<foreignObject>` through sanitization; its HTML children are still stripped.\n * Enable only when each one is pre-flattened to bare text. */\n allowForeignObject?: boolean;\n /** Keep `<use>` through sanitization. Enable only when every `href` is already a `#` reference. */\n allowUse?: boolean;\n /** Extra toolbar controls (e.g. `ExportMenu`) between copy and fullscreen; receives the\n * sanitized SVG. Injected so this lazy chunk carries no export dependencies. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const ZoomableSvg = ({\n html,\n copyText,\n className,\n allowForeignObject,\n allowUse,\n renderActions,\n}: Props) => {\n const safeHtml = useMemo(\n () =>\n DOMPurify.sanitize(html, {\n USE_PROFILES: { svg: true, svgFilters: true },\n ADD_TAGS: [...(allowForeignObject ? ['foreignObject'] : []), ...(allowUse ? ['use'] : [])],\n }),\n [html, allowForeignObject, allowUse],\n );\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [scale, setScale] = useState(1);\n const [translate, setTranslate] = useState({ x: 0, y: 0 });\n const [isFullscreen, setIsFullscreen] = useState(false);\n\n useEffect(() => {\n if (!isFullscreen) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n setIsFullscreen(false);\n }\n };\n document.addEventListener('keydown', onKeyDown, { capture: true });\n return () => document.removeEventListener('keydown', onKeyDown, { capture: true });\n }, [isFullscreen]);\n\n const dragRef = useRef<{\n startX: number;\n startY: number;\n startTx: number;\n startTy: number;\n } | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;\n setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));\n };\n\n el.addEventListener('wheel', onWheel, { passive: false });\n return () => el.removeEventListener('wheel', onWheel);\n // Re-bind when toggling fullscreen: the portal/inline switch remounts the\n // container element, so the listener must attach to the new node.\n }, [isFullscreen]);\n\n const didDragRef = useRef(false);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n didDragRef.current = false;\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startTx: translate.x,\n startTy: translate.y,\n };\n },\n [translate],\n );\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!dragRef.current) return;\n didDragRef.current = true;\n setTranslate({\n x: dragRef.current.startTx + e.clientX - dragRef.current.startX,\n y: dragRef.current.startTy + e.clientY - dragRef.current.startY,\n });\n }, []);\n\n const handleMouseUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const handleReset = useCallback(() => {\n setScale(1);\n setTranslate({ x: 0, y: 0 });\n }, []);\n\n const isZoomed = Math.abs(scale - 1) > 0.001 || translate.x !== 0 || translate.y !== 0;\n\n const handleClick = useCallback((e: React.MouseEvent) => {\n if (didDragRef.current) {\n e.stopPropagation();\n }\n }, []);\n\n const stopPropagation = useCallback((e: React.SyntheticEvent) => {\n e.stopPropagation();\n }, []);\n\n const diagramContent = (\n <div\n role=\"presentation\"\n className={cn('tw:group/zoom tw:relative', isFullscreen && 'tw:h-full')}\n onClick={handleClick}\n >\n <div\n role=\"presentation\"\n ref={containerRef}\n className={cn(\n 'tw:overflow-hidden tw:cursor-grab tw:active:cursor-grabbing tw:p-3',\n isFullscreen && 'tw:h-full',\n )}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n >\n <div\n className={cn(\n 'tw:flex tw:justify-center tw:origin-center',\n isFullscreen && 'tw:h-full tw:[&>svg]:h-full',\n )}\n style={{ transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` }}\n dangerouslySetInnerHTML={{ __html: safeHtml }}\n />\n </div>\n <div\n role=\"presentation\"\n // `focus-within` too: the opacity-0 toolbar is still in the tab order.\n className=\"tw:absolute tw:right-1 tw:top-1 tw:flex tw:gap-1 tw:opacity-0 tw:transition-opacity tw:focus-within:opacity-100 tw:group-hover/zoom:opacity-100\"\n onClick={stopPropagation}\n >\n {isZoomed && (\n <Tooltip tooltip=\"Reset zoom\" placement=\"top\" triggerAsChild>\n <Button size=\"small\" variant=\"outline\" onClick={handleReset}>\n Reset\n </Button>\n </Tooltip>\n )}\n {copyText && (\n <ClipboardButton text={copyText} tooltip=\"Copy code\" size=\"icon-sm\" variant=\"outline\" />\n )}\n {renderActions?.(safeHtml)}\n <Tooltip\n tooltip={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n placement=\"top\"\n triggerAsChild\n >\n <Button\n size=\"icon-sm\"\n variant=\"outline\"\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}\n onClick={() => setIsFullscreen((f) => !f)}\n >\n {isFullscreen ? (\n <Minimize2 className=\"tw:size-4\" />\n ) : (\n <Maximize2 className=\"tw:size-4\" />\n )}\n </Button>\n </Tooltip>\n </div>\n </div>\n );\n\n if (isFullscreen) {\n return createPortal(\n <div\n role=\"presentation\"\n data-testid=\"zoomable-svg-fullscreen\"\n // z-1051 (Modal band): must stay below floating panels (z-1055) or toolbar menus hide.\n // Tooltip (z-1060) and SpotlightBackdrop (z-1056) sit above it by design.\n className=\"tw:fixed tw:inset-0 tw:z-[1051] tw:bg-muted tw:p-4 tailwindcss-preflight\"\n onClick={stopPropagation}\n >\n {diagramContent}\n </div>,\n document.body,\n );\n }\n\n return (\n <div\n className={cn(\n 'tw:overflow-hidden tw:rounded-md tw:border tw:border-border tw:bg-muted',\n className,\n )}\n >\n {diagramContent}\n </div>\n );\n};\n"],"mappings":"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"}
package/dist/charts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { cn } from "./classNames-BzrkDnOD.js";
1
+ import { cn } from "./classNames-DcGnTh2N.js";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Area, AreaChart as AreaChart$1, Bar, BarChart as BarChart$1, CartesianGrid, Cell, Legend, Line, LineChart as LineChart$1, Pie, PieChart as PieChart$1, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
4
4
  //#region src/blocks/Charts/ChartContainer.tsx
@@ -0,0 +1,21 @@
1
+ import { clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+ //#region src/utils/classNames.ts
4
+ const twMerge = extendTailwindMerge({
5
+ prefix: "tw",
6
+ extend: {
7
+ theme: { radius: [
8
+ "card",
9
+ "popover",
10
+ "modal",
11
+ "sheet",
12
+ "toast"
13
+ ] },
14
+ classGroups: { opacity: [{ opacity: ["disabled"] }] }
15
+ }
16
+ });
17
+ const cn = (...classes) => twMerge(clsx(...classes));
18
+ //#endregion
19
+ export { cn };
20
+
21
+ //# sourceMappingURL=classNames-DcGnTh2N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classNames-DcGnTh2N.js","names":[],"sources":["../src/utils/classNames.ts"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n// tailwind-merge v3 (Tailwind v4): the prefix drops the trailing separator —\n// `tw:` → `tw` (the `:` separator is implied).\n// `extend` registers the package's own scale names, so a caller's `className` replaces them.\nconst twMerge = extendTailwindMerge({\n prefix: 'tw',\n extend: {\n theme: { radius: ['card', 'popover', 'modal', 'sheet', 'toast'] },\n classGroups: { opacity: [{ opacity: ['disabled'] }] },\n },\n});\n\nexport const cn = (...classes: ClassValue[]) => twMerge(clsx(...classes));\n"],"mappings":";;;AAMA,MAAM,UAAU,oBAAoB;CAClC,QAAQ;CACR,QAAQ;EACN,OAAO,EAAE,QAAQ;GAAC;GAAQ;GAAW;GAAS;GAAS;EAAO,EAAE;EAChE,aAAa,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,EAAE;CACtD;AACF,CAAC;AAED,MAAa,MAAM,GAAG,YAA0B,QAAQ,KAAK,GAAG,OAAO,CAAC"}
package/dist/editors.js CHANGED
@@ -1,11 +1,11 @@
1
- import { cn } from "./classNames-BzrkDnOD.js";
2
- import { ChevronsLeft, ChevronsRight, X } from "./icons-wcA70iQx.js";
3
- import { Button } from "./Button-B21oVcPU.js";
1
+ import { cn } from "./classNames-DcGnTh2N.js";
2
+ import { ChevronsLeft, ChevronsRight, X } from "./icons-ZIeZXXS7.js";
3
+ import { Button } from "./Button-D2JqBAq7.js";
4
4
  import { useStableCallback } from "./internal/hooks/useStableCallback.js";
5
- import { FieldItem, useFieldContext } from "./FieldItem-BHViBJS3.js";
5
+ import { FieldItem, useFieldContext } from "./FieldItem-CYvJyjiI.js";
6
6
  import { CHANGE_CLASS } from "./internal/components/MergeEditor/constants.js";
7
- import { resolveToken } from "./themeTokens-7DEab0kp.js";
8
- import { CodeEditor, LANGUAGE_MODES, buildBaseThemeStyles, buildBasicSetup, buildCanvasChrome, buildChromeStyles, buildCustomTheme, buildDiffWash, isLanguageMode, searchExtension, updateSearch, useThemedExtension, useTooltipsExtension, useVariableCompletion } from "./CodeEditor-Df7VVx08.js";
7
+ import { resolveToken } from "./themeTokens-l2Fsfcs7.js";
8
+ import { CodeEditor, LANGUAGE_MODES, buildBaseThemeStyles, buildBasicSetup, buildCanvasChrome, buildChromeStyles, buildCustomTheme, buildDiffWash, isLanguageMode, searchExtension, updateSearch, useThemedExtension, useTooltipsExtension, useVariableCompletion } from "./CodeEditor-BfRSCKEs.js";
9
9
  import { useCallback, useEffect, useMemo, useRef } from "react";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { Decoration, EditorView, GutterMarker, ViewPlugin, gutter, gutterLineClass } from "@codemirror/view";
package/dist/flint.js CHANGED
@@ -1,40 +1,14 @@
1
- import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
2
- import { DiagramSource } from "./DiagramSource-C5_d8Gdj.js";
3
1
  import { useThemeAttributes } from "./useThemeAttributes-B199Regy.js";
4
- import { ZoomableSvg } from "./ZoomableSvg-C65nta_r.js";
5
- import { SERIES_TOKENS, createVegaColorResolver, vegaRgb, vegaTheme } from "./vegaTheme-VQMWTlBw.js";
6
- import { makeResponsive } from "./svgTransforms-Dw2hRA-i.js";
2
+ import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
3
+ import { DiagramSource, makeResponsive } from "./svgTransforms-Hnvev3Vs.js";
4
+ import { ZoomableSvg } from "./ZoomableSvg-Dh1OstPN.js";
5
+ import { SERIES_TOKENS, createVegaColorResolver, tierTwoColour } from "./vegaTokens-Ce07C0DH.js";
6
+ import { vegaTheme } from "./vegaTheme-BrmVoPEz.js";
7
+ import { createSvgCache, diagramCacheKey } from "./svgCache-Dhmbe-7i.js";
7
8
  import { useEffect, useState } from "react";
8
9
  import { jsx } from "react/jsx-runtime";
9
10
  //#region src/blocks/FlintChart/flintTheme.ts
10
11
  /**
11
- * How the second palette tier (series 6-10) is derived from the core hues.
12
- *
13
- * - Each hue moves *away* from its surface: darker on light, lighter on dark.
14
- * Darkening on dark would drop contrast from ~6.7:1 to ~3.7:1.
15
- * - `amount` is the fraction of the distance travelled toward `towards`.
16
- */
17
- const TIER_TWO_SHIFT = {
18
- light: {
19
- towards: 0,
20
- amount: .38
21
- },
22
- dark: {
23
- towards: 255,
24
- amount: .35
25
- }
26
- };
27
- /**
28
- * Move an `rgb()` string's channels a fraction of the way toward `towards`
29
- * (0 = black, 255 = white). Returns the input unchanged if it is not that shape.
30
- */
31
- const shiftChannels = (colour, towards, amount) => {
32
- const channels = colour.match(/\d+/g);
33
- if (!channels || channels.length < 3) return colour;
34
- const shifted = channels.slice(0, 3).map((c) => Math.round(Number(c) + (towards - Number(c)) * amount));
35
- return vegaRgb(shifted.join(" "));
36
- };
37
- /**
38
12
  * Put the design system's `--chart-1..5` palette on a Flint input.
39
13
  *
40
14
  * - Flint resolves series colours during assembly, so they ride `theme_spec`, not `vegaTheme`.
@@ -63,7 +37,7 @@ const withFlintSeriesPalette = (input, scheme, from) => {
63
37
  },
64
38
  series: {
65
39
  categorical,
66
- categoricalExtended: [...categorical, ...categorical.map((colour) => shiftChannels(colour, TIER_TWO_SHIFT[scheme].towards, TIER_TWO_SHIFT[scheme].amount))],
40
+ categoricalExtended: [...categorical, ...categorical.map((colour) => tierTwoColour(colour, scheme))],
67
41
  overflow: token("muted-foreground"),
68
42
  sequential: {
69
43
  stops: [token("accent"), token("chart-1")],
@@ -201,20 +175,11 @@ const getFlintRuntime = () => {
201
175
  };
202
176
  const RENDER_DEBOUNCE_MS = 300;
203
177
  const MAX_SOURCE_CHARS = 2e5;
204
- const MAX_CACHED_CHARTS = 24;
205
- const svgCache = /* @__PURE__ */ new Map();
206
- const cacheSvg = (key, svg) => {
207
- if (!svgCache.has(key) && svgCache.size >= MAX_CACHED_CHARTS) {
208
- const oldest = svgCache.keys().next();
209
- if (!oldest.done) svgCache.delete(oldest.value);
210
- }
211
- svgCache.set(key, svg);
212
- };
213
- const chartCacheKey = (code, themeKey) => `${themeKey}\n${code}`;
178
+ const svgCache = createSvgCache();
214
179
  const prevThemeKeyOf = (key) => key.slice(0, key.indexOf("\n"));
215
180
  const FlintChart = ({ code, renderActions }) => {
216
181
  const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();
217
- const cacheKey = chartCacheKey(code, themeKey);
182
+ const cacheKey = diagramCacheKey(code, themeKey);
218
183
  const [svg, setSvg] = useState(() => svgCache.get(cacheKey) ?? null);
219
184
  const [renderFailed, setRenderFailed] = useState(false);
220
185
  const [prevKey, setPrevKey] = useState(cacheKey);
@@ -254,7 +219,7 @@ const FlintChart = ({ code, renderActions }) => {
254
219
  if (cancelled) return;
255
220
  const svgOutput = makeResponsive(await renderFlintSvg(runtime, withFlintSeriesPalette(input, scheme, scope), vegaTheme(scheme, scope)));
256
221
  if (cancelled) return;
257
- cacheSvg(cacheKey, svgOutput);
222
+ svgCache.set(cacheKey, svgOutput);
258
223
  setSvg(svgOutput);
259
224
  setRenderFailed(false);
260
225
  }).catch((err) => {