@keboola/design 15.1.0 → 16.1.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 (345) hide show
  1. package/AGENTS.md +6 -5
  2. package/CHANGELOG.md +85 -0
  3. package/COMPONENT-API.md +62 -61
  4. package/dist/{AIKit-BR6jfsdI.js → AIKit-Cf5plya2.js} +328 -210
  5. package/dist/AIKit-Cf5plya2.js.map +1 -0
  6. package/dist/{Alert-Chz6KZ7e.js → Alert-DziS8n1H.js} +12 -19
  7. package/dist/{Alert-Chz6KZ7e.js.map → Alert-DziS8n1H.js.map} +1 -1
  8. package/dist/{AlertModal-DMsn62JJ.js → AlertModal-De04fFoy.js} +14 -24
  9. package/dist/{AlertModal-DMsn62JJ.js.map → AlertModal-De04fFoy.js.map} +1 -1
  10. package/dist/{AppShell-C8V1KRr_.js → AppShell-BUa3U7-e.js} +6 -9
  11. package/dist/{AppShell-C8V1KRr_.js.map → AppShell-BUa3U7-e.js.map} +1 -1
  12. package/dist/{AutoSaveTextarea-BbMhC5Aq.js → AutoSaveTextarea-CXHOQSun.js} +4 -5
  13. package/dist/{AutoSaveTextarea-BbMhC5Aq.js.map → AutoSaveTextarea-CXHOQSun.js.map} +1 -1
  14. package/dist/{Badge-CqlOE5A2.js → Badge-CFRhducL.js} +9 -14
  15. package/dist/{Badge-CqlOE5A2.js.map → Badge-CFRhducL.js.map} +1 -1
  16. package/dist/{BrandEditor-D61pzWRq.js → BrandEditor-hiLBX7az.js} +16 -23
  17. package/dist/{BrandEditor-D61pzWRq.js.map → BrandEditor-hiLBX7az.js.map} +1 -1
  18. package/dist/{BrandLogo-DkESE19K.js → BrandLogo-Dn7hhp2c.js} +4 -5
  19. package/dist/{BrandLogo-DkESE19K.js.map → BrandLogo-Dn7hhp2c.js.map} +1 -1
  20. package/dist/{Breadcrumb-DbqvDnYl.js → Breadcrumb-uGFEIjFF.js} +17 -28
  21. package/dist/{Breadcrumb-DbqvDnYl.js.map → Breadcrumb-uGFEIjFF.js.map} +1 -1
  22. package/dist/{Button-BNkyYU8u.js → Button-DbvGzEDb.js} +24 -20
  23. package/dist/Button-DbvGzEDb.js.map +1 -0
  24. package/dist/{Calendar-BnKi1kPu.js → Calendar-lJBTETbk.js} +752 -905
  25. package/dist/Calendar-lJBTETbk.js.map +1 -0
  26. package/dist/{Card-DxjGiqH8.js → Card-VIPfOVW5.js} +8 -14
  27. package/dist/{Card-DxjGiqH8.js.map → Card-VIPfOVW5.js.map} +1 -1
  28. package/dist/{Checkbox-CHDDJyAA.js → Checkbox-B2jLlyaO.js} +6 -8
  29. package/dist/{Checkbox-CHDDJyAA.js.map → Checkbox-B2jLlyaO.js.map} +1 -1
  30. package/dist/{Clipboard-DlwVZS1P.js → Clipboard-fAkDdpEu.js} +4 -5
  31. package/dist/{Clipboard-DlwVZS1P.js.map → Clipboard-fAkDdpEu.js.map} +1 -1
  32. package/dist/{ClipboardButton-B1Hr_n_Z.js → ClipboardButton-71Ugbl8c.js} +6 -8
  33. package/dist/{ClipboardButton-B1Hr_n_Z.js.map → ClipboardButton-71Ugbl8c.js.map} +1 -1
  34. package/dist/{CodeEditor-DVSPdfdo.js → CodeEditor-D_b-ZCng.js} +19 -31
  35. package/dist/{CodeEditor-DVSPdfdo.js.map → CodeEditor-D_b-ZCng.js.map} +1 -1
  36. package/dist/{Collapsible-DD4xTL75.js → Collapsible-zsXk4Vpp.js} +5 -8
  37. package/dist/{Collapsible-DD4xTL75.js.map → Collapsible-zsXk4Vpp.js.map} +1 -1
  38. package/dist/{ColorInput-B_eZIu39.js → ColorInput-Cjr1jkvy.js} +9 -12
  39. package/dist/{ColorInput-B_eZIu39.js.map → ColorInput-Cjr1jkvy.js.map} +1 -1
  40. package/dist/{ColorModeSwitch-BlrH8jAi.js → ColorModeSwitch-CuPYnJ2V.js} +5 -6
  41. package/dist/{ColorModeSwitch-BlrH8jAi.js.map → ColorModeSwitch-CuPYnJ2V.js.map} +1 -1
  42. package/dist/{Combobox-BLqX-Tdh.js → Combobox-DYjvYgl3.js} +37 -66
  43. package/dist/{Combobox-BLqX-Tdh.js.map → Combobox-DYjvYgl3.js.map} +1 -1
  44. package/dist/{Command-DhXmqFLT.js → Command-BcTb6GsR.js} +14 -24
  45. package/dist/{Command-DhXmqFLT.js.map → Command-BcTb6GsR.js.map} +1 -1
  46. package/dist/{CopyField-D0Pg4Z0R.js → CopyField-CnwAvQz9.js} +16 -28
  47. package/dist/{CopyField-D0Pg4Z0R.js.map → CopyField-CnwAvQz9.js.map} +1 -1
  48. package/dist/{DateInput-duinbI9_.js → DateInput-DJNX7Vdx.js} +8 -10
  49. package/dist/{DateInput-duinbI9_.js.map → DateInput-DJNX7Vdx.js.map} +1 -1
  50. package/dist/{DatePicker-Cg_aG_N4.js → DatePicker-CI59gF3S.js} +4 -5
  51. package/dist/{DatePicker-Cg_aG_N4.js.map → DatePicker-CI59gF3S.js.map} +1 -1
  52. package/dist/{DateRangeInput-BYVHf9zo.js → DateRangeInput-B3g8cyS0.js} +8 -10
  53. package/dist/{DateRangeInput-BYVHf9zo.js.map → DateRangeInput-B3g8cyS0.js.map} +1 -1
  54. package/dist/{DateRangePicker-m47cSV1r.js → DateRangePicker-48yOB2qV.js} +9 -10
  55. package/dist/{DateRangePicker-m47cSV1r.js.map → DateRangePicker-48yOB2qV.js.map} +1 -1
  56. package/dist/{DiffView-Dy4z-n-1.js → DiffView-DITZdVbh.js} +7 -12
  57. package/dist/{DiffView-Dy4z-n-1.js.map → DiffView-DITZdVbh.js.map} +1 -1
  58. package/dist/{DropdownMenu-Bum99mVf.js → DropdownMenu-Ba9atqDa.js} +20 -36
  59. package/dist/{DropdownMenu-Bum99mVf.js.map → DropdownMenu-Ba9atqDa.js.map} +1 -1
  60. package/dist/{FieldBox-BrxLkY9C.js → FieldBox-DdSdJ3ZN.js} +6 -10
  61. package/dist/{FieldBox-BrxLkY9C.js.map → FieldBox-DdSdJ3ZN.js.map} +1 -1
  62. package/dist/{FieldItem-BHUqgSO1.js → FieldItem-D7eCMfMB.js} +6 -8
  63. package/dist/{FieldItem-BHUqgSO1.js.map → FieldItem-D7eCMfMB.js.map} +1 -1
  64. package/dist/{FieldItem-CPN1xjN5.d.ts → FieldItem-fqm3CNR8.d.ts} +7 -6
  65. package/dist/{FileUpload-BYFONpEl.js → FileUpload-DskvxhAr.js} +25 -45
  66. package/dist/{FileUpload-BYFONpEl.js.map → FileUpload-DskvxhAr.js.map} +1 -1
  67. package/dist/{Form-Dqbt_tIs.js → Form-BUNW7nlt.js} +24 -38
  68. package/dist/{Form-Dqbt_tIs.js.map → Form-BUNW7nlt.js.map} +1 -1
  69. package/dist/{FormGroup-V5kIgQRN.js → FormGroup-QJB21LKp.js} +12 -20
  70. package/dist/{FormGroup-V5kIgQRN.js.map → FormGroup-QJB21LKp.js.map} +1 -1
  71. package/dist/{FullScreenModal-DAvvlGOz.js → FullScreenModal-RzY5XxiG.js} +8 -12
  72. package/dist/{FullScreenModal-DAvvlGOz.js.map → FullScreenModal-RzY5XxiG.js.map} +1 -1
  73. package/dist/{HoverCard-Cf9iYyaW.js → HoverCard-OGWKRXJ7.js} +4 -6
  74. package/dist/{HoverCard-Cf9iYyaW.js.map → HoverCard-OGWKRXJ7.js.map} +1 -1
  75. package/dist/{InlineEdit-D4P0SvCB.js → InlineEdit-CXL0ZslO.js} +7 -8
  76. package/dist/{InlineEdit-D4P0SvCB.js.map → InlineEdit-CXL0ZslO.js.map} +1 -1
  77. package/dist/{InputGroup-CZv_7QlM.js → InputGroup-BWeanEo7.js} +9 -15
  78. package/dist/{InputGroup-CZv_7QlM.js.map → InputGroup-BWeanEo7.js.map} +1 -1
  79. package/dist/{Kbd-CflKthfu.js → Kbd-BprYCICe.js} +8 -13
  80. package/dist/{Kbd-CflKthfu.js.map → Kbd-BprYCICe.js.map} +1 -1
  81. package/dist/{MarkedText-DlmlJO0u.js → MarkedText-BrganZ_V.js} +4 -6
  82. package/dist/{MarkedText-DlmlJO0u.js.map → MarkedText-BrganZ_V.js.map} +1 -1
  83. package/dist/{MermaidDiagram-2-EuNu1i.js → MermaidDiagram-E3azndPk.js} +9 -11
  84. package/dist/{MermaidDiagram-2-EuNu1i.js.map → MermaidDiagram-E3azndPk.js.map} +1 -1
  85. package/dist/{Modal-DwuvuiUx.js → Modal-Cf_kPEBW.js} +13 -21
  86. package/dist/{Modal-DwuvuiUx.js.map → Modal-Cf_kPEBW.js.map} +1 -1
  87. package/dist/{ModalTitle-RGWwIMU6.js → ModalTitle-7vgpfc6B.js} +5 -8
  88. package/dist/{ModalTitle-RGWwIMU6.js.map → ModalTitle-7vgpfc6B.js.map} +1 -1
  89. package/dist/{MultiActionButtonGroup-Dzig87s1.js → MultiActionButtonGroup-8WQwL4UQ.js} +6 -8
  90. package/dist/{MultiActionButtonGroup-Dzig87s1.js.map → MultiActionButtonGroup-8WQwL4UQ.js.map} +1 -1
  91. package/dist/{Navbar-DHUS7XiU.js → Navbar-CRjxVboE.js} +13 -22
  92. package/dist/{Navbar-DHUS7XiU.js.map → Navbar-CRjxVboE.js.map} +1 -1
  93. package/dist/{OtpInput-CY8yCaJk.js → OtpInput-C5plPzGU.js} +7 -11
  94. package/dist/{OtpInput-CY8yCaJk.js.map → OtpInput-C5plPzGU.js.map} +1 -1
  95. package/dist/{PageHeader-CL1A6jFM.js → PageHeader-DosMyar2.js} +6 -10
  96. package/dist/{PageHeader-CL1A6jFM.js.map → PageHeader-DosMyar2.js.map} +1 -1
  97. package/dist/{PageLayout-C9aXTpqV.js → PageLayout-LcvJccOW.js} +5 -8
  98. package/dist/{PageLayout-C9aXTpqV.js.map → PageLayout-LcvJccOW.js.map} +1 -1
  99. package/dist/{PageToolbar-LKP6PiP_.js → PageToolbar-By2HznxO.js} +8 -10
  100. package/dist/{PageToolbar-LKP6PiP_.js.map → PageToolbar-By2HznxO.js.map} +1 -1
  101. package/dist/{Pagination-D27x5KmH.js → Pagination-DrXTrvfD.js} +11 -18
  102. package/dist/{Pagination-D27x5KmH.js.map → Pagination-DrXTrvfD.js.map} +1 -1
  103. package/dist/{Popconfirm-p72DiagN.js → Popconfirm-BJuDOHdv.js} +46 -25
  104. package/dist/Popconfirm-BJuDOHdv.js.map +1 -0
  105. package/dist/{Popover-DnBw5Uay.js → Popover-DhOPlWgF.js} +4 -6
  106. package/dist/{Popover-DnBw5Uay.js.map → Popover-DhOPlWgF.js.map} +1 -1
  107. package/dist/{RadioGroup-B0TwHjBb.js → RadioGroup-B9oC8P15.js} +12 -18
  108. package/dist/{RadioGroup-B0TwHjBb.js.map → RadioGroup-B9oC8P15.js.map} +1 -1
  109. package/dist/{Resizable-D8zs0kcq.js → Resizable-Co-L3qg7.js} +4 -6
  110. package/dist/{Resizable-D8zs0kcq.js.map → Resizable-Co-L3qg7.js.map} +1 -1
  111. package/dist/{Search-vyZwGKMU.js → Search-OgaNjqQM.js} +26 -21
  112. package/dist/Search-OgaNjqQM.js.map +1 -0
  113. package/dist/{SearchInput-DyYXyw3u.js → SearchInput-eLS-uvOn.js} +18 -29
  114. package/dist/SearchInput-eLS-uvOn.js.map +1 -0
  115. package/dist/{SectionNav-6hcIpZLO.js → SectionNav-L81iJBo3.js} +11 -14
  116. package/dist/{SectionNav-6hcIpZLO.js.map → SectionNav-L81iJBo3.js.map} +1 -1
  117. package/dist/{Select-C6zKeip5.js → Select-DRdkdzBp.js} +28 -25
  118. package/dist/{Select-C6zKeip5.js.map → Select-DRdkdzBp.js.map} +1 -1
  119. package/dist/{Sheet-DKG20J7W.js → Sheet-DVb4XoJ5.js} +12 -19
  120. package/dist/{Sheet-DKG20J7W.js.map → Sheet-DVb4XoJ5.js.map} +1 -1
  121. package/dist/{Sidebar-BlYqasnX.js → Sidebar-DYvodJWN.js} +43 -75
  122. package/dist/{Sidebar-BlYqasnX.js.map → Sidebar-DYvodJWN.js.map} +1 -1
  123. package/dist/{Slider-DrcsM8_G.js → Slider-B9IskDxf.js} +8 -12
  124. package/dist/{Slider-DrcsM8_G.js.map → Slider-B9IskDxf.js.map} +1 -1
  125. package/dist/{Stepper-CQrUPVFL.js → Stepper-D7VspVEt.js} +11 -19
  126. package/dist/{Stepper-CQrUPVFL.js.map → Stepper-D7VspVEt.js.map} +1 -1
  127. package/dist/{Switch-DccpSpzC.js → Switch-DONWW7ju.js} +4 -6
  128. package/dist/{Switch-DccpSpzC.js.map → Switch-DONWW7ju.js.map} +1 -1
  129. package/dist/{Table-CilEvpMq.js → Table-BwgBm3hJ.js} +12 -21
  130. package/dist/{Table-CilEvpMq.js.map → Table-BwgBm3hJ.js.map} +1 -1
  131. package/dist/{Tabs-Ck4uWf8U.js → Tabs-DmJB4l_N.js} +9 -14
  132. package/dist/{Tabs-Ck4uWf8U.js.map → Tabs-DmJB4l_N.js.map} +1 -1
  133. package/dist/{TextInput-CR0_USaY.js → TextInput--1CfZybC.js} +8 -10
  134. package/dist/TextInput--1CfZybC.js.map +1 -0
  135. package/dist/{ThemeProvider-BTK7AL-T.js → ThemeProvider-BCHllN7d.js} +8 -13
  136. package/dist/{ThemeProvider-BTK7AL-T.js.map → ThemeProvider-BCHllN7d.js.map} +1 -1
  137. package/dist/{TimePicker-lk3NGqeK.js → TimePicker-CCV3SOw5.js} +4 -6
  138. package/dist/{TimePicker-lk3NGqeK.js.map → TimePicker-CCV3SOw5.js.map} +1 -1
  139. package/dist/{Timeline-DUXgByUE.js → Timeline-EMOpTLAT.js} +8 -13
  140. package/dist/{Timeline-DUXgByUE.js.map → Timeline-EMOpTLAT.js.map} +1 -1
  141. package/dist/{Toast-937n7n8i.js → Toast-BOTINeTX.js} +4 -6
  142. package/dist/{Toast-937n7n8i.js.map → Toast-BOTINeTX.js.map} +1 -1
  143. package/dist/{ToggleAllTooltip-DEjbWFoj.js → ToggleAllTooltip-BFmA6TXf.js} +4 -6
  144. package/dist/{ToggleAllTooltip-DEjbWFoj.js.map → ToggleAllTooltip-BFmA6TXf.js.map} +1 -1
  145. package/dist/{ToggleGroup-BOz1yyz6.js → ToggleGroup-DsDS7k70.js} +3 -4
  146. package/dist/{ToggleGroup-BOz1yyz6.js.map → ToggleGroup-DsDS7k70.js.map} +1 -1
  147. package/dist/{Workbench-CxgNCs3I.js → Workbench-4s0xP6XU.js} +18 -32
  148. package/dist/{Workbench-CxgNCs3I.js.map → Workbench-4s0xP6XU.js.map} +1 -1
  149. package/dist/{ZoomableSvg-CxXKanUR.js → ZoomableSvg-BRPGgaWJ.js} +8 -10
  150. package/dist/{ZoomableSvg-CxXKanUR.js.map → ZoomableSvg-BRPGgaWJ.js.map} +1 -1
  151. package/dist/charts.d.ts +0 -16
  152. package/dist/charts.js +10 -19
  153. package/dist/charts.js.map +1 -1
  154. package/dist/{classNames-DcGnTh2N.js → classNames-DkX30VJU.js} +2 -3
  155. package/dist/{classNames-DcGnTh2N.js.map → classNames-DkX30VJU.js.map} +1 -1
  156. package/dist/editors.d.ts +2 -16
  157. package/dist/editors.js +16 -26
  158. package/dist/editors.js.map +1 -1
  159. package/dist/{findLiteralMatches-DgGLzyG0.js → findLiteralMatches-BaLZTPtx.js} +2 -3
  160. package/dist/{findLiteralMatches-DgGLzyG0.js.map → findLiteralMatches-BaLZTPtx.js.map} +1 -1
  161. package/dist/flint.d.ts +0 -2
  162. package/dist/flint.js +10 -14
  163. package/dist/flint.js.map +1 -1
  164. package/dist/{highlightCode-D354tCXO.js → highlightCode-2spZP7ZA.js} +2 -3
  165. package/dist/{highlightCode-D354tCXO.js.map → highlightCode-2spZP7ZA.js.map} +1 -1
  166. package/dist/{icons-ZIeZXXS7.js → icons-DDR9dFSr.js} +21 -40
  167. package/dist/{icons-ZIeZXXS7.js.map → icons-DDR9dFSr.js.map} +1 -1
  168. package/dist/icons.d.ts +1 -1
  169. package/dist/icons.js +1 -2
  170. package/dist/{index-D-itZ3VP.d.ts → index-BljYaTWL.d.ts} +1 -39
  171. package/dist/index.d.ts +418 -1296
  172. package/dist/index.js +75 -74
  173. package/dist/internal/blocks/AIKit.js +1 -2
  174. package/dist/internal/blocks/AppShell.js +1 -2
  175. package/dist/internal/blocks/AuthLayout.js +3 -4
  176. package/dist/internal/blocks/AutoSaveTextarea.js +1 -2
  177. package/dist/internal/blocks/BrandEditor.js +1 -2
  178. package/dist/internal/blocks/ChartPanel.js +3 -4
  179. package/dist/internal/blocks/ChipEditor.js +6 -7
  180. package/dist/internal/blocks/ClipboardButton.js +1 -2
  181. package/dist/internal/blocks/ColorInput.js +1 -2
  182. package/dist/internal/blocks/ColorModeSwitch.js +1 -2
  183. package/dist/internal/blocks/Command.js +1 -2
  184. package/dist/internal/blocks/CopyField.js +1 -2
  185. package/dist/internal/blocks/DashboardHero.js +2 -3
  186. package/dist/internal/blocks/DateInput.js +1 -2
  187. package/dist/internal/blocks/DateRangeInput.js +1 -2
  188. package/dist/internal/blocks/DiagramShared/DiagramSkeleton.js +1 -2
  189. package/dist/internal/blocks/EmptyConfigurationActionCard.js +2 -3
  190. package/dist/internal/blocks/EmptyState.js +1 -2
  191. package/dist/internal/blocks/ErrorState.js +1 -2
  192. package/dist/internal/blocks/ExportMenu.js +5 -6
  193. package/dist/internal/blocks/FacebookButton.js +3 -4
  194. package/dist/internal/blocks/Form/connectors/ComboboxField.js +3 -4
  195. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +2 -3
  196. package/dist/internal/blocks/Form.js +3 -2
  197. package/dist/internal/blocks/FormGroup.js +1 -2
  198. package/dist/internal/blocks/GoogleButton.js +3 -4
  199. package/dist/internal/blocks/InlineEdit.js +1 -2
  200. package/dist/internal/blocks/MicrosoftButton.js +3 -4
  201. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -2
  202. package/dist/internal/blocks/MultiCombobox.js +7 -8
  203. package/dist/internal/blocks/NumberInput.js +2 -3
  204. package/dist/internal/blocks/OtpInput.js +1 -2
  205. package/dist/internal/blocks/PageHeader.js +1 -2
  206. package/dist/internal/blocks/PageLayout.js +1 -2
  207. package/dist/internal/blocks/PageToolbar.js +1 -2
  208. package/dist/internal/blocks/PasswordInput.js +5 -6
  209. package/dist/internal/blocks/SearchInput.js +1 -2
  210. package/dist/internal/blocks/SearchInputWithNavigation.js +6 -7
  211. package/dist/internal/blocks/SectionNav.js +1 -2
  212. package/dist/internal/blocks/SplitButton.js +4 -5
  213. package/dist/internal/blocks/StatCard.js +4 -6
  214. package/dist/internal/blocks/StatCard.js.map +1 -1
  215. package/dist/internal/blocks/TextInput.js +1 -2
  216. package/dist/internal/blocks/Textarea.js +3 -4
  217. package/dist/internal/blocks/TimeInput.js +6 -7
  218. package/dist/internal/components/Alert.js +1 -2
  219. package/dist/internal/components/AlertModal.js +1 -2
  220. package/dist/internal/components/Avatar.js +3 -4
  221. package/dist/internal/components/Badge.js +1 -2
  222. package/dist/internal/components/BrandLogo.js +1 -2
  223. package/dist/internal/components/Breadcrumb.js +1 -2
  224. package/dist/internal/components/Button.js +1 -2
  225. package/dist/internal/components/ButtonGroup.js +2 -3
  226. package/dist/internal/components/Calendar.js +1 -2
  227. package/dist/internal/components/Card.js +1 -2
  228. package/dist/internal/components/Checkbox.js +1 -2
  229. package/dist/internal/components/Clipboard.js +1 -2
  230. package/dist/internal/components/Collapsible.js +1 -2
  231. package/dist/internal/components/CollapsiblePanel.js +5 -6
  232. package/dist/internal/components/Combobox.js +1 -2
  233. package/dist/internal/components/DatePicker.js +1 -2
  234. package/dist/internal/components/DateRangePicker.js +1 -2
  235. package/dist/internal/components/DiffView.js +1 -2
  236. package/dist/internal/components/DotsLoader.js +2 -3
  237. package/dist/internal/components/DropdownMenu.js +1 -2
  238. package/dist/internal/components/EmptySearchContent.js +1 -2
  239. package/dist/internal/components/FileUpload.js +1 -2
  240. package/dist/internal/components/FullScreenModal.js +1 -2
  241. package/dist/internal/components/HelpBlock.js +1 -2
  242. package/dist/internal/components/HoverCard.js +1 -2
  243. package/dist/internal/components/InputGroup.js +1 -2
  244. package/dist/internal/components/Kbd.js +1 -2
  245. package/dist/internal/components/Label.js +2 -3
  246. package/dist/internal/components/Link.js +2 -3
  247. package/dist/internal/components/MarkedText.js +1 -2
  248. package/dist/internal/components/MergeEditor/ConflictStatus/ConflictStatusIndicator.js +3 -4
  249. package/dist/internal/components/MergeEditor/PaneHeader.js +1 -2
  250. package/dist/internal/components/MergeEditor/constants.js +1 -2
  251. package/dist/internal/components/MergeEditor/useMergeDiff.js +1 -2
  252. package/dist/internal/components/Modal.js +1 -2
  253. package/dist/internal/components/Navbar.js +1 -2
  254. package/dist/internal/components/Pagination.js +1 -2
  255. package/dist/internal/components/PanelWithDetails.js +4 -5
  256. package/dist/internal/components/Popconfirm.js +1 -2
  257. package/dist/internal/components/Popover.js +1 -2
  258. package/dist/internal/components/Progress.js +2 -3
  259. package/dist/internal/components/RadioGroup.js +1 -2
  260. package/dist/internal/components/Resizable.js +1 -2
  261. package/dist/internal/components/ScrollArea.js +3 -5
  262. package/dist/internal/components/ScrollArea.js.map +1 -1
  263. package/dist/internal/components/Search.js +1 -2
  264. package/dist/internal/components/Select.js +1 -2
  265. package/dist/internal/components/Separator.js +2 -3
  266. package/dist/internal/components/Sheet.js +1 -2
  267. package/dist/internal/components/Sidebar.js +1 -2
  268. package/dist/internal/components/Skeleton/Skeleton.js +2 -3
  269. package/dist/internal/components/Skeleton/SkeletonList.js +2 -3
  270. package/dist/internal/components/Slider.js +1 -2
  271. package/dist/internal/components/SpotlightBackdrop.js +3 -5
  272. package/dist/internal/components/SpotlightBackdrop.js.map +1 -1
  273. package/dist/internal/components/Stepper.js +1 -2
  274. package/dist/internal/components/Switch.js +1 -2
  275. package/dist/internal/components/Table.js +1 -2
  276. package/dist/internal/components/Tabs.js +1 -2
  277. package/dist/internal/components/ThemeProvider.js +2 -2
  278. package/dist/internal/components/TimePicker.js +1 -2
  279. package/dist/internal/components/Timeline.js +1 -2
  280. package/dist/internal/components/Toast.js +2 -2
  281. package/dist/internal/components/Toggle.js +2 -3
  282. package/dist/internal/components/ToggleGroup.js +1 -2
  283. package/dist/internal/components/Tooltip.js +1 -2
  284. package/dist/internal/components/Truncated.js +3 -4
  285. package/dist/internal/components/Workbench.js +1 -2
  286. package/dist/internal/components/ZoomableSvg.js +1 -2
  287. package/dist/internal/hooks/useAltDigitHotkey.js +1 -2
  288. package/dist/internal/hooks/useAutosizeInput.js +1 -2
  289. package/dist/internal/hooks/useScrollbarPosition.js +2 -3
  290. package/dist/internal/hooks/useStableCallback.js +1 -2
  291. package/dist/internal/hooks/useTimeout.js +1 -2
  292. package/dist/internal/utils/accessibleName.js +1 -2
  293. package/dist/internal/utils/mergeRefs.js +1 -2
  294. package/dist/internal/utils.js +3 -3
  295. package/dist/markdown-editor.d.ts +0 -4
  296. package/dist/markdown-editor.js +30 -49
  297. package/dist/markdown-editor.js.map +1 -1
  298. package/dist/mermaid.d.ts +0 -2
  299. package/dist/mermaid.js +1 -2
  300. package/dist/rjsf.d.ts +0 -8
  301. package/dist/rjsf.js +47 -78
  302. package/dist/rjsf.js.map +1 -1
  303. package/dist/{rolldown-runtime-Bdc48AWt.js → rolldown-runtime-BrwM56v-.js} +2 -3
  304. package/dist/{styles-T8xwr0sR.js → styles-BXXXosW_.js} +2 -3
  305. package/dist/{styles-T8xwr0sR.js.map → styles-BXXXosW_.js.map} +1 -1
  306. package/dist/{styles-DxazJ8Mz.js → styles-nwtCRF7y.js} +2 -3
  307. package/dist/{styles-DxazJ8Mz.js.map → styles-nwtCRF7y.js.map} +1 -1
  308. package/dist/styles.css +1 -1
  309. package/dist/{svgCache-Dhmbe-7i.js → svgCache-BzvN_fgr.js} +2 -3
  310. package/dist/{svgCache-Dhmbe-7i.js.map → svgCache-BzvN_fgr.js.map} +1 -1
  311. package/dist/{svgTransforms-Hnvev3Vs.js → svgTransforms-BBxxO9T6.js} +4 -6
  312. package/dist/{svgTransforms-Hnvev3Vs.js.map → svgTransforms-BBxxO9T6.js.map} +1 -1
  313. package/dist/testing.d.ts +0 -2
  314. package/dist/testing.js +2 -3
  315. package/dist/{themeScopeContext-CEVXbYvZ.js → themeScopeContext-BZGPdyG8.js} +6 -11
  316. package/dist/{themeScopeContext-CEVXbYvZ.js.map → themeScopeContext-BZGPdyG8.js.map} +1 -1
  317. package/dist/{themeTokens-DCeb62ap.js → themeTokens-B60cQtAY.js} +4 -6
  318. package/dist/{themeTokens-DCeb62ap.js.map → themeTokens-B60cQtAY.js.map} +1 -1
  319. package/dist/{toast-Y3cTMBW8.js → toast-Dzj1EFOb.js} +10 -17
  320. package/dist/{toast-Y3cTMBW8.js.map → toast-Dzj1EFOb.js.map} +1 -1
  321. package/dist/{types-BPcAjMG0.d.ts → types-CsZuwfxc.d.ts} +1 -3
  322. package/dist/{useControllableState-CUYXMsfz.js → useControllableState-BCvUOC6G.js} +2 -3
  323. package/dist/{useControllableState-CUYXMsfz.js.map → useControllableState-BCvUOC6G.js.map} +1 -1
  324. package/dist/{useElement-D-RjrGa4.js → useElement-Dcoo9Jlr.js} +2 -3
  325. package/dist/{useElement-D-RjrGa4.js.map → useElement-Dcoo9Jlr.js.map} +1 -1
  326. package/dist/{useMergeDiff-CvowEXJ1.js → useMergeDiff-DFIATaTw.js} +3 -5
  327. package/dist/{useMergeDiff-CvowEXJ1.js.map → useMergeDiff-DFIATaTw.js.map} +1 -1
  328. package/dist/{utils-DwC9u0tM.js → utils-DjFceY3H.js} +18 -34
  329. package/dist/{utils-DwC9u0tM.js.map → utils-DjFceY3H.js.map} +1 -1
  330. package/dist/vega.d.ts +1 -5
  331. package/dist/vega.js +3 -4
  332. package/dist/{vegaTheme-ISwGXvof.js → vegaTheme-BcTNRmVS.js} +3 -4
  333. package/dist/{vegaTheme-ISwGXvof.js.map → vegaTheme-BcTNRmVS.js.map} +1 -1
  334. package/dist/{vegaTokens-DCkvpIVE.js → vegaTokens-DnCcy7JY.js} +3 -4
  335. package/dist/{vegaTokens-DCkvpIVE.js.map → vegaTokens-DnCcy7JY.js.map} +1 -1
  336. package/package.json +40 -40
  337. package/src/styles.css +70 -4
  338. package/src/theme.css +113 -11
  339. package/dist/AIKit-BR6jfsdI.js.map +0 -1
  340. package/dist/Button-BNkyYU8u.js.map +0 -1
  341. package/dist/Calendar-BnKi1kPu.js.map +0 -1
  342. package/dist/Popconfirm-p72DiagN.js.map +0 -1
  343. package/dist/Search-vyZwGKMU.js.map +0 -1
  344. package/dist/SearchInput-DyYXyw3u.js.map +0 -1
  345. package/dist/TextInput-CR0_USaY.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"editors.js","names":["keymap","EditorView","EMPTY_LINES","EMPTY_CLASSIFICATION"],"sources":["../src/components/CodeEditor/activeQueryHighlight.ts","../src/components/CodeEditor/highlighting.ts","../src/components/CodeEditor/SqlEditor.tsx","../src/components/MergeEditor/AcceptControls/AcceptButton.tsx","../src/components/MergeEditor/AcceptControls/AcceptControls.tsx","../src/components/MergeEditor/decorations.ts","../src/components/MergeEditor/MergePane.tsx","../src/components/MergeEditor/useScrollSync.ts","../src/components/MergeEditor/MergeEditor.tsx","../src/components/CodeEditor/CodeEditorField.tsx"],"sourcesContent":["import type { ChangeSet, Range } from '@codemirror/state';\nimport { Decoration, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nconst activeQueryFirstLine = Decoration.line({ class: 'cm-active-query cm-active-query-first' });\nconst activeQueryMiddleLine = Decoration.line({ class: 'cm-active-query' });\nconst activeQueryLastLine = Decoration.line({ class: 'cm-active-query cm-active-query-last' });\nconst activeQuerySingleLine = Decoration.line({\n class: 'cm-active-query cm-active-query-first cm-active-query-last',\n});\n\ntype QueryBoundary = { from: number; to: number };\n\n/** Whitespace-trimmed offsets of the query holding the cursor, or null. */\nexport const findActiveQueryRange = (\n doc: string,\n cursorPos: number,\n boundaries: QueryBoundary[],\n): { from: number; to: number } | null => {\n if (boundaries.length === 0) return null;\n\n let match: QueryBoundary | undefined = boundaries[boundaries.length - 1];\n for (const boundary of boundaries) {\n if (cursorPos <= boundary.to) {\n match = boundary;\n break;\n }\n }\n\n if (!match) return null;\n\n const queryText = doc.slice(match.from, match.to);\n const leadingWhitespace = queryText.length - queryText.trimStart().length;\n const trailingWhitespace = queryText.length - queryText.trimEnd().length;\n\n const trimmedStart = match.from + leadingWhitespace;\n const trimmedEnd = match.to - trailingWhitespace;\n\n if (trimmedStart >= trimmedEnd) return null;\n\n return { from: trimmedStart, to: trimmedEnd };\n};\n\n/**\n * Character-offset boundaries for the fragments a splitter reported for `doc`.\n *\n * - Bounded by `docLength`: an injected splitter is not trusted to re-join to `doc`.\n * - A fragment past the end is cut there, or dropped if it starts past it.\n * - Offsets past the document would throw in `Text.lineAt`.\n */\nexport const computeBoundaries = (queries: string[], docLength: number): QueryBoundary[] => {\n const boundaries: QueryBoundary[] = [];\n let offset = 0;\n for (const query of queries) {\n if (offset >= docLength) break;\n boundaries.push({ from: offset, to: Math.min(offset + query.length, docLength) });\n offset += query.length;\n }\n return boundaries;\n};\n\n/**\n * Synchronously map cached boundaries through a changeset.\n *\n * - Clamped to `[0, changes.length]` first: the re-parse is debounced, so boundaries can be\n * stale, and `ChangeSet.mapPos` throws a `RangeError` past the pre-change length.\n * - Degenerate boundaries are dropped.\n */\nexport const mapBoundariesThroughChanges = (\n boundaries: QueryBoundary[],\n changes: ChangeSet,\n): QueryBoundary[] => {\n const prevLen = changes.length;\n const mapped: QueryBoundary[] = [];\n for (const b of boundaries) {\n const from = changes.mapPos(Math.max(0, Math.min(b.from, prevLen)), -1);\n const to = changes.mapPos(Math.max(0, Math.min(b.to, prevLen)), 1);\n if (from < to) mapped.push({ from, to });\n }\n return mapped;\n};\n\nconst buildDecorations = (view: EditorView, range: { from: number; to: number }) => {\n const startLine = view.state.doc.lineAt(range.from).number;\n const endLine = view.state.doc.lineAt(range.to).number;\n\n const decorations: Range<Decoration>[] = [];\n for (let lineNum = startLine; lineNum <= endLine; lineNum++) {\n const lineStart = view.state.doc.line(lineNum).from;\n if (startLine === endLine) {\n decorations.push(activeQuerySingleLine.range(lineStart));\n } else if (lineNum === startLine) {\n decorations.push(activeQueryFirstLine.range(lineStart));\n } else if (lineNum === endLine) {\n decorations.push(activeQueryLastLine.range(lineStart));\n } else {\n decorations.push(activeQueryMiddleLine.range(lineStart));\n }\n }\n\n return Decoration.set(decorations);\n};\n\nexport const activeQueryHighlight = (splitQueries: (sql: string) => Promise<string[]>) => {\n return [\n ViewPlugin.fromClass(\n class {\n decorations = Decoration.none;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private seq = 0;\n private cachedDoc = '';\n private cachedBoundaries: QueryBoundary[] = [];\n private destroyed = false;\n\n constructor(view: EditorView) {\n this.scheduleDocParse(view);\n }\n\n update(update: ViewUpdate) {\n if (update.focusChanged && !update.view.hasFocus) {\n this.decorations = Decoration.none;\n return;\n }\n\n if (update.docChanged) {\n // Map the cache now so decorations don't wait for the re-parse.\n if (this.cachedBoundaries.length > 0) {\n this.cachedBoundaries = mapBoundariesThroughChanges(\n this.cachedBoundaries,\n update.changes,\n );\n this.cachedDoc = update.state.doc.toString();\n this.updateFromCache(update.view);\n }\n // Re-parse anyway: edits like a new `;` move the boundaries.\n this.scheduleDocParse(update.view);\n } else if (update.selectionSet || (update.focusChanged && update.view.hasFocus)) {\n this.updateFromCache(update.view);\n }\n }\n\n destroy() {\n this.destroyed = true;\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n }\n\n /** Sets `this.decorations` without dispatching; an async caller must dispatch. */\n private updateFromCache(view: EditorView) {\n if (!view.hasFocus) {\n this.decorations = Decoration.none;\n return;\n }\n\n const { main } = view.state.selection;\n\n if (main.from !== main.to) {\n this.decorations = Decoration.none;\n return;\n }\n\n const doc = view.state.doc.toString();\n if (doc !== this.cachedDoc) return;\n if (this.cachedBoundaries.length === 0) {\n this.decorations = Decoration.none;\n return;\n }\n\n const range = findActiveQueryRange(doc, main.head, this.cachedBoundaries);\n this.decorations = range ? buildDecorations(view, range) : Decoration.none;\n }\n\n private scheduleDocParse(view: EditorView) {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n\n this.debounceTimer = setTimeout(async () => {\n const seq = ++this.seq;\n const doc = view.state.doc.toString();\n\n if (!doc.trim()) {\n this.cachedDoc = doc;\n this.cachedBoundaries = [];\n if (this.decorations !== Decoration.none) {\n this.decorations = Decoration.none;\n if (!this.destroyed) view.dispatch();\n }\n return;\n }\n\n let queries: string[];\n try {\n queries = await splitQueries(doc);\n } catch {\n return;\n }\n\n // Discard stale results\n if (this.destroyed || seq !== this.seq) return;\n\n this.cachedDoc = doc;\n this.cachedBoundaries = computeBoundaries(queries, doc.length);\n\n this.updateFromCache(view);\n if (!this.destroyed) view.dispatch();\n }, 100);\n }\n },\n { decorations: (v) => v.decorations },\n ),\n EditorView.baseTheme({\n '.cm-active-query': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}`,\n marginRight: '8px',\n },\n '.cm-active-query-first': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 1px 0 0 ${colors.blue[300]}`,\n borderRadius: '4px 4px 0 0',\n },\n '.cm-active-query-last': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 -1px 0 0 ${colors.blue[300]}`,\n borderRadius: '0 0 4px 4px',\n },\n '.cm-active-query-first.cm-active-query-last': {\n boxShadow: `inset 0 0 0 1px ${colors.blue[300]}`,\n borderRadius: '4px',\n },\n }),\n ];\n};\n","import type { Extension } from '@codemirror/state';\nimport { RangeSet, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, EditorView, gutter, GutterMarker } from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { DARK_LINE_ALPHA } from './diffWash';\n\nexport type HighlightedLines = {\n from: number;\n to: number;\n error?: { from: number; to: number };\n processing?: { from: number; to: number };\n} | null;\n\n// Gutter markers for highlighting\nclass HighlightMarker extends GutterMarker {\n override toDOM() {\n const marker = document.createElement('div');\n marker.className = 'cm-highlight-marker';\n return marker;\n }\n}\n\nconst highlightMarker = new HighlightMarker();\n\n// Helper function to iterate over line range and apply a callback\nconst forEachLineInRange = <T>(\n doc: { lines: number; line: (n: number) => { from: number } },\n from: number,\n to: number,\n callback: (lineFrom: number) => T,\n): T[] => {\n const results: T[] = [];\n\n // Convert 0-based to 1-based for CodeMirror\n const fromLine = Math.max(1, from + 1);\n const toLine = Math.min(doc.lines, to + 1);\n\n for (let i = fromLine; i <= toLine; i++) {\n const line = doc.line(i);\n results.push(callback(line.from));\n }\n\n return results;\n};\n\n// State effect for setting highlighted lines\nconst setHighlightedLinesEffect = StateEffect.define<HighlightedLines>();\n\n// State field for storing highlighted lines info\nconst highlightedLinesField = StateField.define<HighlightedLines>({\n create() {\n return null;\n },\n update(value, transaction) {\n for (const effect of transaction.effects) {\n if (effect.is(setHighlightedLinesEffect)) {\n return effect.value;\n }\n }\n return value;\n },\n});\n\n// Gutter extension that displays highlight markers\nconst highlightGutter = gutter({\n class: 'cm-highlight-gutter',\n markers: (view): RangeSet<GutterMarker> => {\n const highlightInfo = view.state.field(highlightedLinesField, false);\n\n if (!highlightInfo) {\n return RangeSet.empty;\n }\n\n // Add blue markers for all running query lines\n const markers = forEachLineInRange(\n view.state.doc,\n highlightInfo.from,\n highlightInfo.to,\n (lineFrom) => highlightMarker.range(lineFrom),\n );\n\n return RangeSet.of(markers);\n },\n});\n\n// State field for error line background decorations\nconst errorLineDecorations = StateField.define({\n create() {\n return Decoration.none;\n },\n update(decorations, transaction) {\n decorations = decorations.map(transaction.changes);\n for (const effect of transaction.effects) {\n if (!effect.is(setHighlightedLinesEffect)) {\n continue;\n }\n\n if (!effect.value || !effect.value.error) {\n return Decoration.none;\n }\n\n // Add error line background decorations\n const decorationArray = forEachLineInRange(\n transaction.state.doc,\n effect.value.error.from,\n effect.value.error.to,\n (lineFrom) => Decoration.line({ class: 'cm-error-line' }).range(lineFrom),\n );\n\n return Decoration.set(decorationArray);\n }\n return decorations;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n// State field for processing line background decorations\nconst processingLineDecorations = StateField.define({\n create() {\n return Decoration.none;\n },\n update(decorations, transaction) {\n decorations = decorations.map(transaction.changes);\n for (const effect of transaction.effects) {\n if (!effect.is(setHighlightedLinesEffect)) {\n continue;\n }\n\n if (!effect.value || !effect.value.processing) {\n return Decoration.none;\n }\n\n const decorationArray = forEachLineInRange(\n transaction.state.doc,\n effect.value.processing.from,\n effect.value.processing.to,\n (lineFrom) => Decoration.line({ class: 'cm-processing-line' }).range(lineFrom),\n );\n\n return Decoration.set(decorationArray);\n }\n return decorations;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n/**\n * The run-state washes for the line a query occupies.\n *\n * - `&dark` keeps this a static base theme rather than a themed extension — see `search.ts` for\n * the mechanism and what sets the facet.\n * - Light paints an opaque pastel; dark tints the same `500` hue over the page, at the line alpha\n * the diff wash uses, so an opaque slab never sits under near-white text.\n * - `.cm-highlight-marker` needs no pair: `blue[500]` is 4.60:1 on the darkest surface it sits on.\n */\nconst highlightedLinesTheme = EditorView.baseTheme({\n '.cm-highlight-gutter': {\n width: '2px',\n marginRight: '2px',\n },\n '.cm-highlight-marker': {\n width: '2px',\n height: '100%',\n backgroundColor: colors.blue[500],\n },\n '.cm-error-line': {\n backgroundColor: `${colors.error[100]} !important`,\n },\n '.cm-processing-line': {\n backgroundColor: `${colors.blue[100]} !important`,\n },\n\n '&dark .cm-error-line': {\n backgroundColor: `${colors.error[500]}${DARK_LINE_ALPHA} !important`,\n },\n '&dark .cm-processing-line': {\n backgroundColor: `${colors.blue[500]}${DARK_LINE_ALPHA} !important`,\n },\n});\n\n// Install highlight lines extension\nexport function highlightingExtension(): Extension[] {\n return [\n highlightedLinesField,\n highlightGutter,\n errorLineDecorations,\n processingLineDecorations,\n highlightedLinesTheme,\n ];\n}\n\nexport function updateHighlighting(view: EditorView, lines?: HighlightedLines) {\n view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });\n}\n","import { useEffect, useMemo, useRef } from 'react';\nimport type { CompletionSource } from '@codemirror/autocomplete';\nimport { defaultKeymap } from '@codemirror/commands';\nimport type { SQLNamespace } from '@codemirror/lang-sql';\nimport type {\n EditorState,\n KeyBinding,\n ReactCodeMirrorRef,\n ViewUpdate,\n} from '@uiw/react-codemirror';\nimport CodeMirror, { EditorView, keymap } from '@uiw/react-codemirror';\n\nimport { installExtensions, type SqlDialectName } from '@keboola/codemirror-lang-sql';\n\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport { activeQueryHighlight } from './activeQueryHighlight';\nimport { buildCanvasChrome, buildChromeStyles } from './editorChrome';\nimport { buildBaseThemeStyles, buildBasicSetup, buildCustomTheme } from './helpers';\nimport type { HighlightedLines } from './highlighting';\nimport { highlightingExtension, updateHighlighting } from './highlighting';\nimport { searchExtension, updateSearch } from './search';\nimport { useThemedExtension } from './tokenTheme';\nimport { useTooltipsExtension } from './tooltips';\nimport { type EditorVariable, useVariableCompletion } from './variableCompletion';\n\n// Own keymaps: Escape ahead of `defaultKeymap`, a Tab/Enter-filtered completion keymap from\n// `@keboola/codemirror-lang-sql`, and prop-driven search instead of the panel.\nconst OWN_KEYMAPS = {\n defaultKeymap: false,\n completionKeymap: false,\n searchKeymap: false,\n} as const;\n\nconst CUSTOM_KEYMAP: KeyBinding[] = [\n {\n key: 'Escape',\n stopPropagation: true,\n run: (view: EditorView) => {\n view.contentDOM.blur();\n return true;\n },\n },\n];\n\nconst OWN_KEYMAP_EXTENSION = keymap.of([...defaultKeymap, ...CUSTOM_KEYMAP]);\n\n// Resolves live `--*` tokens, so the chrome re-skins with brand + dark mode.\nconst buildTheme = (scheme: ResolvedColorScheme) => ({\n ...buildBaseThemeStyles(scheme),\n ...buildChromeStyles(buildCanvasChrome()),\n});\n\ntype Props = {\n value: string;\n onChange?: (value: string) => void;\n onSelectionChange?: (text: string) => void;\n onCreateEditor?: (view: EditorView, state: EditorState) => void;\n onDestroyEditor?: () => void;\n onBlurEditor?: (view: EditorView) => void;\n onFocusEditor?: (view: EditorView) => void;\n readOnly: boolean;\n placeholder?: string;\n searchQuery?: string;\n searchMatchIndex?: number;\n queryParser?: (sql: string) => Promise<string[]>;\n autoFocus?: boolean;\n lineNumbers?: boolean;\n className?: string;\n /** Compared by identity: pass a stable object or the extension tree rebuilds every render. */\n schema?: SQLNamespace;\n /**\n * Added to schema/keyword/variable completions; unlike `CodeEditor`'s, replaces nothing.\n * Compared by identity: `useMemo` it or the extension tree rebuilds every render.\n */\n completionSource?: CompletionSource;\n variables?: EditorVariable[];\n defaultSchema?: string;\n defaultDatabase?: string;\n highlightLines?: HighlightedLines;\n dialect?: SqlDialectName;\n};\n\nexport const SqlEditor = ({\n value,\n onChange,\n onSelectionChange,\n onCreateEditor,\n onDestroyEditor,\n onBlurEditor,\n onFocusEditor,\n placeholder = '',\n searchQuery = '',\n searchMatchIndex,\n readOnly = false,\n queryParser,\n autoFocus = false,\n lineNumbers = true,\n className,\n schema,\n completionSource,\n variables,\n defaultDatabase,\n defaultSchema,\n highlightLines,\n dialect,\n}: Props) => {\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n\n // Stable identities: CodeMirror rebuilds its extension tree when a handler changes.\n const handleChange = useStableCallback((next: string) => onChange?.(next));\n const parseQueries = useStableCallback(async (sql: string) => (await queryParser?.(sql)) ?? []);\n const handleBlur = useStableCallback((view: EditorView) => onBlurEditor?.(view));\n const handleFocus = useStableCallback((view: EditorView) => onFocusEditor?.(view));\n\n const handleUpdate = useStableCallback((update: ViewUpdate) => {\n if (update.selectionSet) {\n const { main } = update.state.selection;\n\n onSelectionChange?.(update.state.sliceDoc(main.from, main.to));\n }\n });\n\n const variableCompletion = useVariableCompletion(variables);\n\n // Only a parser's presence reconfigures; swapping it does not.\n const withQueryParser = queryParser !== undefined;\n\n const tooltipLayer = useTooltipsExtension();\n\n // Shares `CodeEditor`'s cache entry — same `buildCustomTheme`.\n const customTheme = useThemedExtension('editor:syntax', buildCustomTheme);\n // `dark` sets `EditorView.darkTheme` — see `CodeEditor`'s base theme for what depends on it.\n const themeExtension = useThemedExtension('sql-editor:chrome', (scheme) =>\n EditorView.theme(buildTheme(scheme), { dark: scheme === 'dark' }),\n );\n\n const extensions = useMemo(() => {\n return [\n EditorView.lineWrapping,\n OWN_KEYMAP_EXTENSION,\n ...installExtensions({\n schema,\n defaultDatabase,\n defaultSchema,\n variableCompletion,\n completionSource,\n dialect,\n }),\n searchExtension(),\n highlightingExtension(),\n withQueryParser ? activeQueryHighlight(parseQueries) : [],\n tooltipLayer,\n themeExtension,\n EditorView.domEventHandlers({\n blur: (_, view) => handleBlur(view),\n focus: (_, view) => handleFocus(view),\n }),\n ];\n }, [\n withQueryParser,\n parseQueries,\n schema,\n completionSource,\n defaultDatabase,\n defaultSchema,\n variableCompletion,\n dialect,\n handleBlur,\n handleFocus,\n themeExtension,\n tooltipLayer,\n ]);\n\n const defaultSetup = useMemo(() => {\n return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };\n }, [readOnly, lineNumbers]);\n\n useEffect(() => {\n if (editorRef.current?.view) {\n updateHighlighting(editorRef.current.view, highlightLines);\n }\n }, [highlightLines]);\n\n useEffect(() => {\n if (editorRef.current?.view) {\n updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);\n }\n }, [searchQuery, searchMatchIndex]);\n\n // Fires once on unmount, with the latest handler.\n const handleDestroy = useStableCallback(() => onDestroyEditor?.());\n useEffect(() => handleDestroy, [handleDestroy]);\n\n const handleCreate = useStableCallback((view: EditorView, state: EditorState) => {\n onCreateEditor?.(view, state);\n\n if (highlightLines) {\n updateHighlighting(view, highlightLines);\n }\n\n if (searchQuery) {\n updateSearch(view, searchQuery, searchMatchIndex);\n }\n });\n\n return (\n <CodeMirror\n ref={editorRef}\n theme={customTheme}\n extensions={extensions}\n value={value}\n onChange={handleChange}\n onUpdate={handleUpdate}\n onCreateEditor={handleCreate}\n autoFocus={autoFocus}\n placeholder={placeholder}\n className={className}\n readOnly={readOnly}\n editable={!readOnly}\n basicSetup={defaultSetup}\n />\n );\n};\n","import { ChevronsLeft, ChevronsRight } from '../../../icons';\nimport { Button } from '../../Button';\n\ntype Props = {\n side: 'left' | 'right';\n onAccept: () => void;\n};\n\nexport const AcceptButton = ({ side, onAccept }: Props) => {\n const label = `Accept ${side === 'left' ? 'production' : 'branch'} version`;\n const Chevron = side === 'left' ? ChevronsRight : ChevronsLeft;\n return (\n <Button onClick={onAccept} variant=\"outline\" size=\"icon-sm\" title={label} aria-label={label}>\n <Chevron className=\"tw:size-5\" />\n </Button>\n );\n};\n","import type { RefCallback } from 'react';\n\nimport { X } from '../../../icons';\nimport { cn } from '../../../utils';\nimport { Button } from '../../Button';\nimport { LINE_HEIGHT_PX, type MergeConflict, PANE_HEADER_HEIGHT_PX } from '../constants';\n\nimport { AcceptButton } from './AcceptButton';\n\ntype Props = {\n conflicts: MergeConflict[];\n side: 'left' | 'right';\n onAccept: (conflict: MergeConflict) => void;\n onDismiss?: (conflict: MergeConflict) => void;\n contentRef?: RefCallback<HTMLDivElement>;\n};\n\n// Column of accept/dismiss buttons between panes.\n//\n// - 28px fits the icons without crossing into the `overflow-hidden` panes; 0 when no conflicts.\n// - Inner wrapper allows x-overflow so focus rings stay visible past the column edge.\n// - The parent scroll-syncs `contentRef` to align buttons with their chunk.\nexport const AcceptControls = ({ conflicts, side, onAccept, onDismiss, contentRef }: Props) => (\n <div\n className={cn(\n 'tw:z-10 tw:flex tw:shrink-0 tw:flex-col tw:items-center',\n conflicts.length > 0 ? 'tw:w-7' : 'tw:w-0',\n )}\n >\n {conflicts.length > 0 && (\n <>\n <div className=\"tw:shrink-0\" style={{ height: `${PANE_HEADER_HEIGHT_PX}px` }} />\n <div className=\"tw:relative tw:w-full tw:flex-1 tw:overflow-y-clip tw:overflow-x-visible\">\n <div ref={contentRef} className=\"tw:relative tw:size-full\">\n {conflicts.map((conflict) => {\n const topLine = side === 'left' ? conflict.oldStartLine : conflict.newStartLine;\n const topOffset = (topLine - 1) * LINE_HEIGHT_PX - 2;\n\n return (\n <div\n key={conflict.id}\n className=\"tw:absolute tw:inset-x-0 tw:flex tw:flex-col tw:items-center tw:gap-0.5\"\n style={{ top: `${topOffset}px` }}\n >\n <AcceptButton side={side} onAccept={() => onAccept(conflict)} />\n {onDismiss && (\n <Button\n onClick={() => onDismiss(conflict)}\n variant=\"outline\"\n size=\"icon-sm\"\n title=\"Dismiss\"\n aria-label={`Dismiss ${side === 'left' ? 'production' : 'branch'} change`}\n >\n <X className=\"tw:size-4\" />\n </Button>\n )}\n </div>\n );\n })}\n </div>\n </div>\n </>\n )}\n </div>\n);\n","import {\n type Extension,\n RangeSet,\n RangeSetBuilder,\n StateEffect,\n StateField,\n} from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n gutterLineClass,\n GutterMarker,\n} from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { buildDiffWash } from '../CodeEditor/diffWash';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport type { ChangeClassification } from './constants';\nimport { CHANGE_CLASS } from './constants';\n\ntype HighlightPayload = {\n lines: Set<number>;\n classification: Map<number, ChangeClassification>;\n};\n\nconst setHighlightedLines = StateEffect.define<HighlightPayload>();\n\nconst safeDecoration = Decoration.line({ class: 'cm-merge-safe-line' });\nconst conflictDecoration = Decoration.line({ class: 'cm-merge-conflict-line' });\n\nclass SafeGutterMarker extends GutterMarker {\n override elementClass = 'cm-merge-safe-gutter';\n}\n\nclass ConflictGutterMarker extends GutterMarker {\n override elementClass = 'cm-merge-conflict-gutter';\n}\n\nconst safeGutterMarker = new SafeGutterMarker();\nconst conflictGutterMarker = new ConflictGutterMarker();\n\ntype FieldValue = {\n decorations: DecorationSet;\n gutterMarkers: RangeSet<GutterMarker>;\n};\n\nexport const createDiffHighlightExtension = (): Extension =>\n StateField.define<FieldValue>({\n create: () => ({ decorations: Decoration.none, gutterMarkers: RangeSet.empty }),\n update(value, tr) {\n // Last effect wins\n let payload: HighlightPayload | null = null;\n for (const effect of tr.effects) {\n if (effect.is(setHighlightedLines)) {\n payload = effect.value;\n }\n }\n\n if (!payload) {\n return {\n decorations: value.decorations.map(tr.changes),\n gutterMarkers: value.gutterMarkers.map(tr.changes),\n };\n }\n\n const decoBuilder = new RangeSetBuilder<Decoration>();\n const gutterBuilder = new RangeSetBuilder<GutterMarker>();\n const doc = tr.state.doc;\n const { lines, classification } = payload;\n\n // RangeSetBuilder requires positions in order\n const sorted = [...lines].filter((l) => l >= 1 && l <= doc.lines).sort((a, b) => a - b);\n for (const i of sorted) {\n const cls = classification.get(i);\n if (!cls) continue;\n\n const isSafe = cls === CHANGE_CLASS.SAFE;\n const line = doc.line(i);\n decoBuilder.add(line.from, line.from, isSafe ? safeDecoration : conflictDecoration);\n gutterBuilder.add(line.from, line.from, isSafe ? safeGutterMarker : conflictGutterMarker);\n }\n\n return {\n decorations: decoBuilder.finish(),\n gutterMarkers: gutterBuilder.finish(),\n };\n },\n provide: (f) => [\n EditorView.decorations.from(f, (val) => val.decorations),\n gutterLineClass.from(f, (val: FieldValue) => val.gutterMarkers),\n ],\n });\n\n/**\n * The highlight palette, for `useThemedExtension`; separate from the StateField, which must stay stable across schemes.\n *\n * - `!important` overrides CodeMirror's active-line and selection backgrounds.\n * - SAFE (green): one side changed. CONFLICT (amber, not red — red reads as deletion): both did.\n * - Dark mode tints at low alpha; an opaque pastel would put light text on a light slab.\n */\nexport const buildDiffHighlightTheme = (scheme: ResolvedColorScheme): Extension => {\n const dark = scheme === 'dark';\n const { line, gutter } = buildDiffWash(scheme);\n\n // `muted-foreground` fails AA on the tinted gutter; hue-matched numbers reach ≥6:1\n const safeNumber = dark ? colors.green[300] : colors.green[900];\n const conflictNumber = dark ? colors.warning[300] : colors.warning[800];\n\n return EditorView.theme({\n '.cm-merge-safe-line': {\n backgroundColor: `${line(colors.green[500], colors.green[100])} !important`,\n boxShadow: `inset 3px 0 0 ${colors.green[500]}`,\n },\n '.cm-merge-conflict-line': {\n backgroundColor: `${line(colors.warning[500], colors.warning[100])} !important`,\n boxShadow: `inset 3px 0 0 ${colors.warning[500]}`,\n },\n '.cm-merge-safe-gutter': {\n backgroundColor: `${gutter(colors.green[500], colors.green[200])} !important`,\n color: safeNumber,\n },\n '.cm-merge-conflict-gutter': {\n backgroundColor: `${gutter(colors.warning[500], colors.warning[200])} !important`,\n color: conflictNumber,\n },\n });\n};\n\nexport const updateHighlightedLines = (\n view: EditorView,\n lines: Set<number>,\n classification: Map<number, ChangeClassification>,\n) => {\n view.dispatch({ effects: setHighlightedLines.of({ lines, classification }) });\n};\n","import { type ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { cn } from '../../utils';\nimport { resolveToken } from '../../utils/themeTokens';\nimport { buildBasicSetup } from '../CodeEditor/helpers';\nimport { useThemedExtension } from '../CodeEditor/tokenTheme';\n\nimport { type ChangeClassification, LINE_HEIGHT_PX } from './constants';\nimport {\n buildDiffHighlightTheme,\n createDiffHighlightExtension,\n updateHighlightedLines,\n} from './decorations';\n\nconst EMPTY_LINES: Set<number> = new Set();\nconst EMPTY_CLASSIFICATION: Map<number, ChangeClassification> = new Map();\n\ntype Props = {\n value: string;\n highlightedLines: Set<number>;\n lineClassification: Map<number, ChangeClassification>;\n readOnly?: boolean;\n onChange?: (value: string) => void;\n header?: ReactNode;\n headerClassName?: string;\n className?: string;\n onScrollDOMReady?: (el: HTMLElement | null) => void;\n /** Side deleted upstream: error-red chrome, the diff still visible. */\n deleted?: boolean;\n};\n\nexport const MergePane = ({\n value,\n highlightedLines,\n lineClassification,\n readOnly = false,\n onChange,\n header,\n headerClassName,\n className,\n onScrollDOMReady,\n deleted = false,\n}: Props) => {\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n const handleChange = useStableCallback((next: string) => onChange?.(next));\n\n // The deleted wash is a fixed error hue, not a token; dark mode uses a low-alpha tint\n // because an opaque light-red slab makes near-white text unreadable.\n const themeExtension = useThemedExtension(`merge-pane:${deleted}`, (scheme) => {\n const dark = scheme === 'dark';\n const deletedSurface = dark ? `${colors.error[500]}1f` : colors.error[100];\n const deletedGutter = dark ? `${colors.error[500]}3d` : colors.error[200];\n // Stock line-number grey fails contrast on the wash.\n const deletedGutterText = dark ? colors.error[300] : colors.error[700];\n\n return EditorView.theme({\n '&.cm-editor': {\n height: '100%',\n backgroundColor: deleted ? deletedSurface : resolveToken('background', '249 250 251'),\n // Token text colour so content stays readable when `--background` goes dark.\n color: resolveToken('foreground', '30 41 59'),\n outline: 'none',\n },\n '.cm-gutters': {\n backgroundColor: deleted ? deletedGutter : resolveToken('muted', '241 245 249'),\n color: deleted ? deletedGutterText : resolveToken('muted-foreground', '100 116 139'),\n },\n '*': { lineHeight: `${LINE_HEIGHT_PX}px` },\n '.cm-lineNumbers .cm-gutterElement': { padding: '0 0 0 25px' },\n });\n });\n\n // Separate from the theme: a fresh `StateField` on reconfigure would drop the highlights.\n const diffHighlightExtension = useMemo(() => createDiffHighlightExtension(), []);\n\n // Must rebuild on scheme change — see `buildDiffHighlightTheme`.\n const diffHighlightTheme = useThemedExtension('merge-diff-highlight', buildDiffHighlightTheme);\n\n const basicSetup = useMemo(\n () => ({ ...buildBasicSetup(readOnly), lineNumbers: true }),\n [readOnly],\n );\n\n const extensions = useMemo(\n (): Extension[] => [\n diffHighlightExtension,\n diffHighlightTheme,\n themeExtension,\n // Re-measure after doc changes so late-settling layouts don't leave trailing lines blank.\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n requestAnimationFrame(() => update.view.dispatch({}));\n }\n }),\n ],\n [diffHighlightExtension, diffHighlightTheme, themeExtension],\n );\n\n // A deleted side is a file-level conflict, so it shows no line markers.\n useEffect(() => {\n const view = editorRef.current?.view;\n if (!view) return;\n updateHighlightedLines(\n view,\n deleted ? EMPTY_LINES : highlightedLines,\n deleted ? EMPTY_CLASSIFICATION : lineClassification,\n );\n }, [highlightedLines, lineClassification, deleted]);\n\n const handleCreateEditor = useCallback(\n (view: EditorView) => {\n updateHighlightedLines(\n view,\n deleted ? EMPTY_LINES : highlightedLines,\n deleted ? EMPTY_CLASSIFICATION : lineClassification,\n );\n onScrollDOMReady?.(view.scrollDOM);\n },\n [highlightedLines, lineClassification, onScrollDOMReady, deleted],\n );\n\n useEffect(() => {\n return () => onScrollDOMReady?.(null);\n }, [onScrollDOMReady]);\n\n // Parent dimensions settle after CodeMirror mounts (fullscreen modal, alerts above).\n useEffect(() => {\n const view = editorRef.current?.view;\n const wrapper = view?.dom.parentElement;\n if (!view || !wrapper) return;\n\n const observer = new ResizeObserver(() => view.dispatch({}));\n observer.observe(wrapper);\n\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n className={cn(\n 'tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:overflow-hidden',\n className,\n deleted && 'tw:border-error-300 tw:[[data-theme=dark]_&]:border-error-500/50',\n )}\n >\n {header && (\n <div\n className={cn(\n 'tw:px-4 tw:py-3',\n // Same light/dark split as the editor wash, for the same near-white text.\n deleted\n ? 'tw:border-b tw:border-error-200 tw:bg-error-100 tw:[[data-theme=dark]_&]:border-error-500/30 tw:[[data-theme=dark]_&]:bg-error-500/15'\n : 'tw:bg-background',\n headerClassName,\n )}\n >\n {header}\n </div>\n )}\n <div className=\"tw:flex tw:h-0 tw:flex-1 tw:flex-col tw:[&_>div]:h-full\">\n <CodeMirror\n ref={editorRef}\n height=\"100%\"\n value={value}\n onChange={handleChange}\n extensions={extensions}\n readOnly={readOnly}\n onCreateEditor={handleCreateEditor}\n basicSetup={basicSetup}\n />\n </div>\n </div>\n );\n};\n","import { useCallback, useRef } from 'react';\n\nexport const useScrollSync = () => {\n const scrollersRef = useRef<(HTMLElement | null)[]>([]);\n const followersRef = useRef<Map<string, { paneIndex: number; el: HTMLElement }>>(new Map());\n const isSyncingRef = useRef(false);\n const scrollerCallbacksRef = useRef<Map<number, (el: HTMLElement | null) => void>>(new Map());\n const followerCallbacksRef = useRef<Map<string, (el: HTMLElement | null) => void>>(new Map());\n\n const updateFollowers = useCallback(() => {\n for (const [, { paneIndex, el }] of followersRef.current) {\n const scroller = scrollersRef.current[paneIndex];\n if (!scroller) continue;\n el.style.transform = `translateY(-${scroller.scrollTop}px)`;\n }\n }, []);\n\n const handleScroll = useCallback(\n (e: Event) => {\n if (isSyncingRef.current) return;\n isSyncingRef.current = true;\n\n // Px-aligned sync. All panes share LINE_HEIGHT_PX, so matching scrollTop is the same\n // as matching the line at the top of the viewport. Previous ratio-based sync drifted\n // badly when pane heights differed (e.g. 50 lines vs 500 — half-scrolling left snapped\n // right to its midpoint, not to the equivalent line). Clamp to each target's max so\n // the source can scroll past where shorter panes bottom out without errors.\n const sourceScrollTop = (e.target as HTMLElement).scrollTop;\n\n for (const scroller of scrollersRef.current) {\n if (!scroller || scroller === e.target) continue;\n const targetMax = Math.max(0, scroller.scrollHeight - scroller.clientHeight);\n scroller.scrollTop = Math.min(sourceScrollTop, targetMax);\n }\n\n updateFollowers();\n isSyncingRef.current = false;\n },\n [updateFollowers],\n );\n\n const registerScroller = useCallback(\n (index: number) => {\n const existing = scrollerCallbacksRef.current.get(index);\n if (existing) return existing;\n\n const callback = (el: HTMLElement | null) => {\n const prev = scrollersRef.current[index];\n if (prev === el) return;\n\n prev?.removeEventListener('scroll', handleScroll);\n scrollersRef.current[index] = el;\n el?.addEventListener('scroll', handleScroll, { passive: true });\n };\n\n scrollerCallbacksRef.current.set(index, callback);\n return callback;\n },\n [handleScroll],\n );\n\n const registerFollower = useCallback((paneIndex: number, key: string) => {\n const existing = followerCallbacksRef.current.get(key);\n if (existing) return existing;\n\n const callback = (el: HTMLElement | null) => {\n if (el) {\n followersRef.current.set(key, { paneIndex, el });\n } else {\n followersRef.current.delete(key);\n }\n };\n\n followerCallbacksRef.current.set(key, callback);\n return callback;\n }, []);\n\n return { registerScroller, registerFollower };\n};\n","import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { AcceptControls } from './AcceptControls/AcceptControls';\nimport type { ChangeClassification, MergeConflict } from './constants';\nimport { MergePane } from './MergePane';\nimport { useScrollSync } from './useScrollSync';\n\nconst EMPTY_LINES: Set<number> = new Set();\nconst EMPTY_CLASSIFICATION: Map<number, ChangeClassification> = new Map();\n\ntype Props = {\n mergeValue: string;\n handleMergeChange: (value: string) => void;\n leftText: string;\n rightText: string;\n leftConflicts: MergeConflict[];\n rightConflicts: MergeConflict[];\n leftHighlightedLines: Set<number>;\n rightHighlightedLines: Set<number>;\n leftClassification: Map<number, ChangeClassification>;\n rightClassification: Map<number, ChangeClassification>;\n mergeHighlightedLines: Set<number>;\n mergeClassification: Map<number, ChangeClassification>;\n acceptLeft: (conflict: MergeConflict) => void;\n acceptRight: (conflict: MergeConflict) => void;\n dismissLeft: (conflict: MergeConflict) => void;\n dismissRight: (conflict: MergeConflict) => void;\n leftHeader?: ReactNode;\n middleHeader?: ReactNode;\n middleHeaderClassName?: string;\n middleClassName?: string;\n rightHeader?: ReactNode;\n className?: string;\n /** Side deleted upstream: its pane turns error-red, its accept/dismiss controls are hidden. */\n leftDeleted?: boolean;\n rightDeleted?: boolean;\n};\n\nexport const MergeEditor = ({\n mergeValue,\n handleMergeChange,\n leftText,\n rightText,\n leftConflicts,\n rightConflicts,\n leftHighlightedLines,\n rightHighlightedLines,\n leftClassification,\n rightClassification,\n mergeHighlightedLines,\n mergeClassification,\n acceptLeft,\n acceptRight,\n dismissLeft,\n dismissRight,\n leftHeader,\n middleHeader,\n middleHeaderClassName,\n middleClassName,\n rightHeader,\n className,\n leftDeleted = false,\n rightDeleted = false,\n}: Props) => {\n const { registerScroller, registerFollower } = useScrollSync();\n\n // A deleted side makes it a keep-or-drop-the-file choice, so the middle pane shows no line markers.\n const anySideDeleted = leftDeleted || rightDeleted;\n\n return (\n <div\n className={cn(\n 'tw:flex tw:h-full tw:min-h-0 tw:overflow-hidden tw:bg-background tw:gap-3',\n className,\n )}\n >\n <MergePane\n value={leftText}\n highlightedLines={leftHighlightedLines}\n lineClassification={leftClassification}\n readOnly\n header={leftHeader}\n className=\"tw:rounded-r-lg tw:border tw:border-border\"\n onScrollDOMReady={registerScroller(0)}\n deleted={leftDeleted}\n />\n\n <AcceptControls\n conflicts={leftDeleted ? [] : leftConflicts}\n side=\"left\"\n onAccept={acceptLeft}\n onDismiss={dismissLeft}\n contentRef={registerFollower(0, 'left-controls')}\n />\n\n <MergePane\n value={mergeValue}\n highlightedLines={anySideDeleted ? EMPTY_LINES : mergeHighlightedLines}\n lineClassification={anySideDeleted ? EMPTY_CLASSIFICATION : mergeClassification}\n onChange={handleMergeChange}\n header={middleHeader}\n headerClassName={middleHeaderClassName}\n className={cn('tw:border tw:border-border tw:rounded-lg', middleClassName)}\n onScrollDOMReady={registerScroller(1)}\n />\n\n <AcceptControls\n conflicts={rightDeleted ? [] : rightConflicts}\n side=\"right\"\n onAccept={acceptRight}\n onDismiss={dismissRight}\n contentRef={registerFollower(2, 'right-controls')}\n />\n\n <MergePane\n value={rightText}\n highlightedLines={rightHighlightedLines}\n lineClassification={rightClassification}\n readOnly\n header={rightHeader}\n className=\"tw:rounded-l-lg tw:border tw:border-border\"\n onScrollDOMReady={registerScroller(2)}\n deleted={rightDeleted}\n />\n </div>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { FieldItem, type FieldItemProps } from '../../blocks/Form/connectors/FieldItem';\nimport { useFieldContext } from '../../blocks/Form/contexts';\n\nimport { CodeEditor } from './CodeEditor';\n\ntype Props = FieldItemProps &\n Omit<\n ComponentProps<typeof CodeEditor>,\n // Owned by the field / `FieldItem` — see the connector rules in AGENTS.md.\n | 'value'\n | 'onChange'\n | 'onBlur'\n | 'ariaLabel'\n | 'ariaLabelledBy'\n | 'ariaDescribedBy'\n | 'ariaInvalid'\n | 'ariaRequired'\n // Makes a viewer (no lint, no completions), not a disabled control; use `inputLocked` instead.\n | 'readOnly'\n | 'className'\n // Derived from `required`, so a call site cannot contradict its own validation.\n | 'allowBlankDocument'\n > & {\n /** Styles the editor box; `className` styles the field frame. */\n editorClassName?: string;\n };\n\n/**\n * Code / JSON editor field; state is the raw editor text, never a parsed value.\n *\n * - In `@keboola/design/editors`, not `useAppForm`: keeps CodeMirror (~170 kB) out of the main entry.\n * - Reads the field from context, so use it inside `<form.AppField>` like a connector.\n * - JSON is invalid mid-edit; parse in the schema or at submit.\n * - Labelled via `aria-labelledby`: CodeMirror's `div[role=\"textbox\"]` is not labelable.\n */\nexport const CodeEditorField = ({\n label,\n action,\n required,\n requiredMark,\n help,\n tooltip,\n className,\n 'aria-describedby': ariaDescribedBy,\n editorClassName,\n variant = 'field',\n ...editorProps\n}: Props) => {\n const field = useFieldContext<string>();\n\n return (\n <FieldItem\n label={label}\n action={action}\n required={required}\n requiredMark={requiredMark}\n labelling=\"aria-labelledby\"\n help={help}\n tooltip={tooltip}\n className={className}\n aria-describedby={ariaDescribedBy}\n >\n {(control) => (\n <CodeEditor\n {...editorProps}\n variant={variant}\n className={editorClassName}\n // Camel-cased: CodeEditor writes them onto CodeMirror's focused content node.\n ariaLabelledBy={control['aria-labelledby']}\n ariaDescribedBy={control['aria-describedby']}\n ariaInvalid={control['aria-invalid']}\n ariaRequired={control['aria-required']}\n // Empty is valid for an optional field, so hide the \"Unexpected end of input\" lint mark.\n allowBlankDocument={!required}\n value={field.state.value ?? ''}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n />\n )}\n </FieldItem>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"editors.js","names":["keymap","EditorView","EMPTY_LINES","EMPTY_CLASSIFICATION"],"sources":["../src/components/CodeEditor/activeQueryHighlight.ts","../src/components/CodeEditor/highlighting.ts","../src/components/CodeEditor/SqlEditor.tsx","../src/components/MergeEditor/AcceptControls/AcceptButton.tsx","../src/components/MergeEditor/AcceptControls/AcceptControls.tsx","../src/components/MergeEditor/decorations.ts","../src/components/MergeEditor/MergePane.tsx","../src/components/MergeEditor/useScrollSync.ts","../src/components/MergeEditor/MergeEditor.tsx","../src/components/CodeEditor/CodeEditorField.tsx"],"sourcesContent":["import type { ChangeSet, Range } from '@codemirror/state';\nimport { Decoration, EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nconst activeQueryFirstLine = Decoration.line({ class: 'cm-active-query cm-active-query-first' });\nconst activeQueryMiddleLine = Decoration.line({ class: 'cm-active-query' });\nconst activeQueryLastLine = Decoration.line({ class: 'cm-active-query cm-active-query-last' });\nconst activeQuerySingleLine = Decoration.line({\n class: 'cm-active-query cm-active-query-first cm-active-query-last',\n});\n\ntype QueryBoundary = { from: number; to: number };\n\n/** Whitespace-trimmed offsets of the query holding the cursor, or null. */\nexport const findActiveQueryRange = (\n doc: string,\n cursorPos: number,\n boundaries: QueryBoundary[],\n): { from: number; to: number } | null => {\n if (boundaries.length === 0) return null;\n\n let match: QueryBoundary | undefined = boundaries[boundaries.length - 1];\n for (const boundary of boundaries) {\n if (cursorPos <= boundary.to) {\n match = boundary;\n break;\n }\n }\n\n if (!match) return null;\n\n const queryText = doc.slice(match.from, match.to);\n const leadingWhitespace = queryText.length - queryText.trimStart().length;\n const trailingWhitespace = queryText.length - queryText.trimEnd().length;\n\n const trimmedStart = match.from + leadingWhitespace;\n const trimmedEnd = match.to - trailingWhitespace;\n\n if (trimmedStart >= trimmedEnd) return null;\n\n return { from: trimmedStart, to: trimmedEnd };\n};\n\n/**\n * Character-offset boundaries for the fragments a splitter reported for `doc`.\n *\n * - Bounded by `docLength`: an injected splitter is not trusted to re-join to `doc`.\n * - A fragment past the end is cut there, or dropped if it starts past it.\n * - Offsets past the document would throw in `Text.lineAt`.\n */\nexport const computeBoundaries = (queries: string[], docLength: number): QueryBoundary[] => {\n const boundaries: QueryBoundary[] = [];\n let offset = 0;\n for (const query of queries) {\n if (offset >= docLength) break;\n boundaries.push({ from: offset, to: Math.min(offset + query.length, docLength) });\n offset += query.length;\n }\n return boundaries;\n};\n\n/**\n * Synchronously map cached boundaries through a changeset.\n *\n * - Clamped to `[0, changes.length]` first: the re-parse is debounced, so boundaries can be\n * stale, and `ChangeSet.mapPos` throws a `RangeError` past the pre-change length.\n * - Degenerate boundaries are dropped.\n */\nexport const mapBoundariesThroughChanges = (\n boundaries: QueryBoundary[],\n changes: ChangeSet,\n): QueryBoundary[] => {\n const prevLen = changes.length;\n const mapped: QueryBoundary[] = [];\n for (const b of boundaries) {\n const from = changes.mapPos(Math.max(0, Math.min(b.from, prevLen)), -1);\n const to = changes.mapPos(Math.max(0, Math.min(b.to, prevLen)), 1);\n if (from < to) mapped.push({ from, to });\n }\n return mapped;\n};\n\nconst buildDecorations = (view: EditorView, range: { from: number; to: number }) => {\n const startLine = view.state.doc.lineAt(range.from).number;\n const endLine = view.state.doc.lineAt(range.to).number;\n\n const decorations: Range<Decoration>[] = [];\n for (let lineNum = startLine; lineNum <= endLine; lineNum++) {\n const lineStart = view.state.doc.line(lineNum).from;\n if (startLine === endLine) {\n decorations.push(activeQuerySingleLine.range(lineStart));\n } else if (lineNum === startLine) {\n decorations.push(activeQueryFirstLine.range(lineStart));\n } else if (lineNum === endLine) {\n decorations.push(activeQueryLastLine.range(lineStart));\n } else {\n decorations.push(activeQueryMiddleLine.range(lineStart));\n }\n }\n\n return Decoration.set(decorations);\n};\n\nexport const activeQueryHighlight = (splitQueries: (sql: string) => Promise<string[]>) => {\n return [\n ViewPlugin.fromClass(\n class {\n decorations = Decoration.none;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private seq = 0;\n private cachedDoc = '';\n private cachedBoundaries: QueryBoundary[] = [];\n private destroyed = false;\n\n constructor(view: EditorView) {\n this.scheduleDocParse(view);\n }\n\n update(update: ViewUpdate) {\n if (update.focusChanged && !update.view.hasFocus) {\n this.decorations = Decoration.none;\n return;\n }\n\n if (update.docChanged) {\n // Map the cache now so decorations don't wait for the re-parse.\n if (this.cachedBoundaries.length > 0) {\n this.cachedBoundaries = mapBoundariesThroughChanges(\n this.cachedBoundaries,\n update.changes,\n );\n this.cachedDoc = update.state.doc.toString();\n this.updateFromCache(update.view);\n }\n // Re-parse anyway: edits like a new `;` move the boundaries.\n this.scheduleDocParse(update.view);\n } else if (update.selectionSet || (update.focusChanged && update.view.hasFocus)) {\n this.updateFromCache(update.view);\n }\n }\n\n destroy() {\n this.destroyed = true;\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n }\n\n /** Sets `this.decorations` without dispatching; an async caller must dispatch. */\n private updateFromCache(view: EditorView) {\n if (!view.hasFocus) {\n this.decorations = Decoration.none;\n return;\n }\n\n const { main } = view.state.selection;\n\n if (main.from !== main.to) {\n this.decorations = Decoration.none;\n return;\n }\n\n const doc = view.state.doc.toString();\n if (doc !== this.cachedDoc) return;\n if (this.cachedBoundaries.length === 0) {\n this.decorations = Decoration.none;\n return;\n }\n\n const range = findActiveQueryRange(doc, main.head, this.cachedBoundaries);\n this.decorations = range ? buildDecorations(view, range) : Decoration.none;\n }\n\n private scheduleDocParse(view: EditorView) {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n\n this.debounceTimer = setTimeout(async () => {\n const seq = ++this.seq;\n const doc = view.state.doc.toString();\n\n if (!doc.trim()) {\n this.cachedDoc = doc;\n this.cachedBoundaries = [];\n if (this.decorations !== Decoration.none) {\n this.decorations = Decoration.none;\n if (!this.destroyed) view.dispatch();\n }\n return;\n }\n\n let queries: string[];\n try {\n queries = await splitQueries(doc);\n } catch {\n return;\n }\n\n // Discard stale results\n if (this.destroyed || seq !== this.seq) return;\n\n this.cachedDoc = doc;\n this.cachedBoundaries = computeBoundaries(queries, doc.length);\n\n this.updateFromCache(view);\n if (!this.destroyed) view.dispatch();\n }, 100);\n }\n },\n { decorations: (v) => v.decorations },\n ),\n EditorView.baseTheme({\n '.cm-active-query': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}`,\n marginRight: '8px',\n },\n '.cm-active-query-first': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 1px 0 0 ${colors.blue[300]}`,\n borderRadius: '4px 4px 0 0',\n },\n '.cm-active-query-last': {\n boxShadow: `inset -1px 0 0 0 ${colors.blue[300]}, inset 1px 0 0 0 ${colors.blue[300]}, inset 0 -1px 0 0 ${colors.blue[300]}`,\n borderRadius: '0 0 4px 4px',\n },\n '.cm-active-query-first.cm-active-query-last': {\n boxShadow: `inset 0 0 0 1px ${colors.blue[300]}`,\n borderRadius: '4px',\n },\n }),\n ];\n};\n","import type { Extension } from '@codemirror/state';\nimport { RangeSet, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, EditorView, gutter, GutterMarker } from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { DARK_LINE_ALPHA } from './diffWash';\n\nexport type HighlightedLines = {\n from: number;\n to: number;\n error?: { from: number; to: number };\n processing?: { from: number; to: number };\n} | null;\n\n// Gutter markers for highlighting\nclass HighlightMarker extends GutterMarker {\n override toDOM() {\n const marker = document.createElement('div');\n marker.className = 'cm-highlight-marker';\n return marker;\n }\n}\n\nconst highlightMarker = new HighlightMarker();\n\n// Helper function to iterate over line range and apply a callback\nconst forEachLineInRange = <T>(\n doc: { lines: number; line: (n: number) => { from: number } },\n from: number,\n to: number,\n callback: (lineFrom: number) => T,\n): T[] => {\n const results: T[] = [];\n\n // Convert 0-based to 1-based for CodeMirror\n const fromLine = Math.max(1, from + 1);\n const toLine = Math.min(doc.lines, to + 1);\n\n for (let i = fromLine; i <= toLine; i++) {\n const line = doc.line(i);\n results.push(callback(line.from));\n }\n\n return results;\n};\n\n// State effect for setting highlighted lines\nconst setHighlightedLinesEffect = StateEffect.define<HighlightedLines>();\n\n// State field for storing highlighted lines info\nconst highlightedLinesField = StateField.define<HighlightedLines>({\n create() {\n return null;\n },\n update(value, transaction) {\n for (const effect of transaction.effects) {\n if (effect.is(setHighlightedLinesEffect)) {\n return effect.value;\n }\n }\n return value;\n },\n});\n\n// Gutter extension that displays highlight markers\nconst highlightGutter = gutter({\n class: 'cm-highlight-gutter',\n markers: (view): RangeSet<GutterMarker> => {\n const highlightInfo = view.state.field(highlightedLinesField, false);\n\n if (!highlightInfo) {\n return RangeSet.empty;\n }\n\n // Add blue markers for all running query lines\n const markers = forEachLineInRange(\n view.state.doc,\n highlightInfo.from,\n highlightInfo.to,\n (lineFrom) => highlightMarker.range(lineFrom),\n );\n\n return RangeSet.of(markers);\n },\n});\n\n// State field for error line background decorations\nconst errorLineDecorations = StateField.define({\n create() {\n return Decoration.none;\n },\n update(decorations, transaction) {\n decorations = decorations.map(transaction.changes);\n for (const effect of transaction.effects) {\n if (!effect.is(setHighlightedLinesEffect)) {\n continue;\n }\n\n if (!effect.value || !effect.value.error) {\n return Decoration.none;\n }\n\n // Add error line background decorations\n const decorationArray = forEachLineInRange(\n transaction.state.doc,\n effect.value.error.from,\n effect.value.error.to,\n (lineFrom) => Decoration.line({ class: 'cm-error-line' }).range(lineFrom),\n );\n\n return Decoration.set(decorationArray);\n }\n return decorations;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n// State field for processing line background decorations\nconst processingLineDecorations = StateField.define({\n create() {\n return Decoration.none;\n },\n update(decorations, transaction) {\n decorations = decorations.map(transaction.changes);\n for (const effect of transaction.effects) {\n if (!effect.is(setHighlightedLinesEffect)) {\n continue;\n }\n\n if (!effect.value || !effect.value.processing) {\n return Decoration.none;\n }\n\n const decorationArray = forEachLineInRange(\n transaction.state.doc,\n effect.value.processing.from,\n effect.value.processing.to,\n (lineFrom) => Decoration.line({ class: 'cm-processing-line' }).range(lineFrom),\n );\n\n return Decoration.set(decorationArray);\n }\n return decorations;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n/**\n * The run-state washes for the line a query occupies.\n *\n * - `&dark` keeps this a static base theme rather than a themed extension — see `search.ts` for\n * the mechanism and what sets the facet.\n * - Light paints an opaque pastel; dark tints the same `500` hue over the page, at the line alpha\n * the diff wash uses, so an opaque slab never sits under near-white text.\n * - `.cm-highlight-marker` needs no pair: `blue[500]` is 4.60:1 on the darkest surface it sits on.\n */\nconst highlightedLinesTheme = EditorView.baseTheme({\n '.cm-highlight-gutter': {\n width: '2px',\n marginRight: '2px',\n },\n '.cm-highlight-marker': {\n width: '2px',\n height: '100%',\n backgroundColor: colors.blue[500],\n },\n '.cm-error-line': {\n backgroundColor: `${colors.error[100]} !important`,\n },\n '.cm-processing-line': {\n backgroundColor: `${colors.blue[100]} !important`,\n },\n\n '&dark .cm-error-line': {\n backgroundColor: `${colors.error[500]}${DARK_LINE_ALPHA} !important`,\n },\n '&dark .cm-processing-line': {\n backgroundColor: `${colors.blue[500]}${DARK_LINE_ALPHA} !important`,\n },\n});\n\n// Install highlight lines extension\nexport function highlightingExtension(): Extension[] {\n return [\n highlightedLinesField,\n highlightGutter,\n errorLineDecorations,\n processingLineDecorations,\n highlightedLinesTheme,\n ];\n}\n\nexport function updateHighlighting(view: EditorView, lines?: HighlightedLines) {\n view.dispatch({ effects: setHighlightedLinesEffect.of(lines ?? null) });\n}\n","import { useEffect, useMemo, useRef } from 'react';\nimport type { CompletionSource } from '@codemirror/autocomplete';\nimport { defaultKeymap } from '@codemirror/commands';\nimport type { SQLNamespace } from '@codemirror/lang-sql';\nimport type {\n EditorState,\n KeyBinding,\n ReactCodeMirrorRef,\n ViewUpdate,\n} from '@uiw/react-codemirror';\nimport CodeMirror, { EditorView, keymap } from '@uiw/react-codemirror';\n\nimport { installExtensions, type SqlDialectName } from '@keboola/codemirror-lang-sql';\n\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport { activeQueryHighlight } from './activeQueryHighlight';\nimport { buildCanvasChrome, buildChromeStyles } from './editorChrome';\nimport { buildBaseThemeStyles, buildBasicSetup, buildCustomTheme } from './helpers';\nimport type { HighlightedLines } from './highlighting';\nimport { highlightingExtension, updateHighlighting } from './highlighting';\nimport { searchExtension, updateSearch } from './search';\nimport { useThemedExtension } from './tokenTheme';\nimport { useTooltipsExtension } from './tooltips';\nimport { type EditorVariable, useVariableCompletion } from './variableCompletion';\n\n// Own keymaps: Escape ahead of `defaultKeymap`, a Tab/Enter-filtered completion keymap from\n// `@keboola/codemirror-lang-sql`, and prop-driven search instead of the panel.\nconst OWN_KEYMAPS = {\n defaultKeymap: false,\n completionKeymap: false,\n searchKeymap: false,\n} as const;\n\nconst CUSTOM_KEYMAP: KeyBinding[] = [\n {\n key: 'Escape',\n stopPropagation: true,\n run: (view: EditorView) => {\n view.contentDOM.blur();\n return true;\n },\n },\n];\n\nconst OWN_KEYMAP_EXTENSION = keymap.of([...defaultKeymap, ...CUSTOM_KEYMAP]);\n\n// Resolves live `--*` tokens, so the chrome re-skins with brand + dark mode.\nconst buildTheme = (scheme: ResolvedColorScheme) => ({\n ...buildBaseThemeStyles(scheme),\n ...buildChromeStyles(buildCanvasChrome()),\n});\n\ntype Props = {\n value: string;\n onChange?: (value: string) => void;\n onSelectionChange?: (text: string) => void;\n onCreateEditor?: (view: EditorView, state: EditorState) => void;\n onDestroyEditor?: () => void;\n onBlurEditor?: (view: EditorView) => void;\n onFocusEditor?: (view: EditorView) => void;\n readOnly: boolean;\n placeholder?: string;\n searchQuery?: string;\n searchMatchIndex?: number;\n queryParser?: (sql: string) => Promise<string[]>;\n autoFocus?: boolean;\n lineNumbers?: boolean;\n className?: string;\n /** Compared by identity: pass a stable object or the extension tree rebuilds every render. */\n schema?: SQLNamespace;\n /**\n * Added to schema/keyword/variable completions; unlike `CodeEditor`'s, replaces nothing.\n * Compared by identity: `useMemo` it or the extension tree rebuilds every render.\n */\n completionSource?: CompletionSource;\n variables?: EditorVariable[];\n defaultSchema?: string;\n defaultDatabase?: string;\n highlightLines?: HighlightedLines;\n dialect?: SqlDialectName;\n};\n\nexport const SqlEditor = ({\n value,\n onChange,\n onSelectionChange,\n onCreateEditor,\n onDestroyEditor,\n onBlurEditor,\n onFocusEditor,\n placeholder = '',\n searchQuery = '',\n searchMatchIndex,\n readOnly = false,\n queryParser,\n autoFocus = false,\n lineNumbers = true,\n className,\n schema,\n completionSource,\n variables,\n defaultDatabase,\n defaultSchema,\n highlightLines,\n dialect,\n}: Props) => {\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n\n // Stable identities: CodeMirror rebuilds its extension tree when a handler changes.\n const handleChange = useStableCallback((next: string) => onChange?.(next));\n const parseQueries = useStableCallback(async (sql: string) => (await queryParser?.(sql)) ?? []);\n const handleBlur = useStableCallback((view: EditorView) => onBlurEditor?.(view));\n const handleFocus = useStableCallback((view: EditorView) => onFocusEditor?.(view));\n\n const handleUpdate = useStableCallback((update: ViewUpdate) => {\n if (update.selectionSet) {\n const { main } = update.state.selection;\n\n onSelectionChange?.(update.state.sliceDoc(main.from, main.to));\n }\n });\n\n const variableCompletion = useVariableCompletion(variables);\n\n // Only a parser's presence reconfigures; swapping it does not.\n const withQueryParser = queryParser !== undefined;\n\n const tooltipLayer = useTooltipsExtension();\n\n // Shares `CodeEditor`'s cache entry — same `buildCustomTheme`.\n const customTheme = useThemedExtension('editor:syntax', buildCustomTheme);\n // `dark` sets `EditorView.darkTheme` — see `CodeEditor`'s base theme for what depends on it.\n const themeExtension = useThemedExtension('sql-editor:chrome', (scheme) =>\n EditorView.theme(buildTheme(scheme), { dark: scheme === 'dark' }),\n );\n\n const extensions = useMemo(() => {\n return [\n EditorView.lineWrapping,\n OWN_KEYMAP_EXTENSION,\n ...installExtensions({\n schema,\n defaultDatabase,\n defaultSchema,\n variableCompletion,\n completionSource,\n dialect,\n }),\n searchExtension(),\n highlightingExtension(),\n withQueryParser ? activeQueryHighlight(parseQueries) : [],\n tooltipLayer,\n themeExtension,\n EditorView.domEventHandlers({\n blur: (_, view) => handleBlur(view),\n focus: (_, view) => handleFocus(view),\n }),\n ];\n }, [\n withQueryParser,\n parseQueries,\n schema,\n completionSource,\n defaultDatabase,\n defaultSchema,\n variableCompletion,\n dialect,\n handleBlur,\n handleFocus,\n themeExtension,\n tooltipLayer,\n ]);\n\n const defaultSetup = useMemo(() => {\n return { ...buildBasicSetup(readOnly), ...OWN_KEYMAPS, lineNumbers };\n }, [readOnly, lineNumbers]);\n\n useEffect(() => {\n if (editorRef.current?.view) {\n updateHighlighting(editorRef.current.view, highlightLines);\n }\n }, [highlightLines]);\n\n useEffect(() => {\n if (editorRef.current?.view) {\n updateSearch(editorRef.current.view, searchQuery, searchMatchIndex);\n }\n }, [searchQuery, searchMatchIndex]);\n\n // Fires once on unmount, with the latest handler.\n const handleDestroy = useStableCallback(() => onDestroyEditor?.());\n useEffect(() => handleDestroy, [handleDestroy]);\n\n const handleCreate = useStableCallback((view: EditorView, state: EditorState) => {\n onCreateEditor?.(view, state);\n\n if (highlightLines) {\n updateHighlighting(view, highlightLines);\n }\n\n if (searchQuery) {\n updateSearch(view, searchQuery, searchMatchIndex);\n }\n });\n\n return (\n <CodeMirror\n ref={editorRef}\n theme={customTheme}\n extensions={extensions}\n value={value}\n onChange={handleChange}\n onUpdate={handleUpdate}\n onCreateEditor={handleCreate}\n autoFocus={autoFocus}\n placeholder={placeholder}\n className={className}\n readOnly={readOnly}\n editable={!readOnly}\n basicSetup={defaultSetup}\n />\n );\n};\n","import { ChevronsLeft, ChevronsRight } from '../../../icons';\nimport { Button } from '../../Button';\n\ntype Props = {\n side: 'left' | 'right';\n onAccept: () => void;\n};\n\nexport const AcceptButton = ({ side, onAccept }: Props) => {\n const label = `Accept ${side === 'left' ? 'production' : 'branch'} version`;\n const Chevron = side === 'left' ? ChevronsRight : ChevronsLeft;\n return (\n <Button onClick={onAccept} variant=\"outline\" size=\"icon-sm\" title={label} aria-label={label}>\n <Chevron className=\"tw:size-5\" />\n </Button>\n );\n};\n","import type { RefCallback } from 'react';\n\nimport { X } from '../../../icons';\nimport { cn } from '../../../utils';\nimport { Button } from '../../Button';\nimport { LINE_HEIGHT_PX, type MergeConflict, PANE_HEADER_HEIGHT_PX } from '../constants';\n\nimport { AcceptButton } from './AcceptButton';\n\ntype Props = {\n conflicts: MergeConflict[];\n side: 'left' | 'right';\n onAccept: (conflict: MergeConflict) => void;\n onDismiss?: (conflict: MergeConflict) => void;\n contentRef?: RefCallback<HTMLDivElement>;\n};\n\n// Column of accept/dismiss buttons between panes.\n//\n// - 28px fits the icons without crossing into the `overflow-hidden` panes; 0 when no conflicts.\n// - Inner wrapper allows x-overflow so focus rings stay visible past the column edge.\n// - The parent scroll-syncs `contentRef` to align buttons with their chunk.\nexport const AcceptControls = ({ conflicts, side, onAccept, onDismiss, contentRef }: Props) => (\n <div\n className={cn(\n 'tw:z-10 tw:flex tw:shrink-0 tw:flex-col tw:items-center',\n conflicts.length > 0 ? 'tw:w-7' : 'tw:w-0',\n )}\n >\n {conflicts.length > 0 && (\n <>\n <div className=\"tw:shrink-0\" style={{ height: `${PANE_HEADER_HEIGHT_PX}px` }} />\n <div className=\"tw:relative tw:w-full tw:flex-1 tw:overflow-y-clip tw:overflow-x-visible\">\n <div ref={contentRef} className=\"tw:relative tw:size-full\">\n {conflicts.map((conflict) => {\n const topLine = side === 'left' ? conflict.oldStartLine : conflict.newStartLine;\n const topOffset = (topLine - 1) * LINE_HEIGHT_PX - 2;\n\n return (\n <div\n key={conflict.id}\n className=\"tw:absolute tw:inset-x-0 tw:flex tw:flex-col tw:items-center tw:gap-0.5\"\n style={{ top: `${topOffset}px` }}\n >\n <AcceptButton side={side} onAccept={() => onAccept(conflict)} />\n {onDismiss && (\n <Button\n onClick={() => onDismiss(conflict)}\n variant=\"outline\"\n size=\"icon-sm\"\n title=\"Dismiss\"\n aria-label={`Dismiss ${side === 'left' ? 'production' : 'branch'} change`}\n >\n <X className=\"tw:size-4\" />\n </Button>\n )}\n </div>\n );\n })}\n </div>\n </div>\n </>\n )}\n </div>\n);\n","import {\n type Extension,\n RangeSet,\n RangeSetBuilder,\n StateEffect,\n StateField,\n} from '@codemirror/state';\nimport {\n Decoration,\n type DecorationSet,\n EditorView,\n gutterLineClass,\n GutterMarker,\n} from '@codemirror/view';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { buildDiffWash } from '../CodeEditor/diffWash';\nimport type { ResolvedColorScheme } from '../ThemeProvider/types';\n\nimport type { ChangeClassification } from './constants';\nimport { CHANGE_CLASS } from './constants';\n\ntype HighlightPayload = {\n lines: Set<number>;\n classification: Map<number, ChangeClassification>;\n};\n\nconst setHighlightedLines = StateEffect.define<HighlightPayload>();\n\nconst safeDecoration = Decoration.line({ class: 'cm-merge-safe-line' });\nconst conflictDecoration = Decoration.line({ class: 'cm-merge-conflict-line' });\n\nclass SafeGutterMarker extends GutterMarker {\n override elementClass = 'cm-merge-safe-gutter';\n}\n\nclass ConflictGutterMarker extends GutterMarker {\n override elementClass = 'cm-merge-conflict-gutter';\n}\n\nconst safeGutterMarker = new SafeGutterMarker();\nconst conflictGutterMarker = new ConflictGutterMarker();\n\ntype FieldValue = {\n decorations: DecorationSet;\n gutterMarkers: RangeSet<GutterMarker>;\n};\n\nexport const createDiffHighlightExtension = (): Extension =>\n StateField.define<FieldValue>({\n create: () => ({ decorations: Decoration.none, gutterMarkers: RangeSet.empty }),\n update(value, tr) {\n // Last effect wins\n let payload: HighlightPayload | null = null;\n for (const effect of tr.effects) {\n if (effect.is(setHighlightedLines)) {\n payload = effect.value;\n }\n }\n\n if (!payload) {\n return {\n decorations: value.decorations.map(tr.changes),\n gutterMarkers: value.gutterMarkers.map(tr.changes),\n };\n }\n\n const decoBuilder = new RangeSetBuilder<Decoration>();\n const gutterBuilder = new RangeSetBuilder<GutterMarker>();\n const doc = tr.state.doc;\n const { lines, classification } = payload;\n\n // RangeSetBuilder requires positions in order\n const sorted = [...lines].filter((l) => l >= 1 && l <= doc.lines).sort((a, b) => a - b);\n for (const i of sorted) {\n const cls = classification.get(i);\n if (!cls) continue;\n\n const isSafe = cls === CHANGE_CLASS.SAFE;\n const line = doc.line(i);\n decoBuilder.add(line.from, line.from, isSafe ? safeDecoration : conflictDecoration);\n gutterBuilder.add(line.from, line.from, isSafe ? safeGutterMarker : conflictGutterMarker);\n }\n\n return {\n decorations: decoBuilder.finish(),\n gutterMarkers: gutterBuilder.finish(),\n };\n },\n provide: (f) => [\n EditorView.decorations.from(f, (val) => val.decorations),\n gutterLineClass.from(f, (val: FieldValue) => val.gutterMarkers),\n ],\n });\n\n/**\n * The highlight palette, for `useThemedExtension`; separate from the StateField, which must stay stable across schemes.\n *\n * - `!important` overrides CodeMirror's active-line and selection backgrounds.\n * - SAFE (green): one side changed. CONFLICT (amber, not red — red reads as deletion): both did.\n * - Dark mode tints at low alpha; an opaque pastel would put light text on a light slab.\n */\nexport const buildDiffHighlightTheme = (scheme: ResolvedColorScheme): Extension => {\n const dark = scheme === 'dark';\n const { line, gutter } = buildDiffWash(scheme);\n\n // `muted-foreground` fails AA on the tinted gutter; hue-matched numbers reach ≥6:1\n const safeNumber = dark ? colors.green[300] : colors.green[900];\n const conflictNumber = dark ? colors.warning[300] : colors.warning[800];\n\n return EditorView.theme({\n '.cm-merge-safe-line': {\n backgroundColor: `${line(colors.green[500], colors.green[100])} !important`,\n boxShadow: `inset 3px 0 0 ${colors.green[500]}`,\n },\n '.cm-merge-conflict-line': {\n backgroundColor: `${line(colors.warning[500], colors.warning[100])} !important`,\n boxShadow: `inset 3px 0 0 ${colors.warning[500]}`,\n },\n '.cm-merge-safe-gutter': {\n backgroundColor: `${gutter(colors.green[500], colors.green[200])} !important`,\n color: safeNumber,\n },\n '.cm-merge-conflict-gutter': {\n backgroundColor: `${gutter(colors.warning[500], colors.warning[200])} !important`,\n color: conflictNumber,\n },\n });\n};\n\nexport const updateHighlightedLines = (\n view: EditorView,\n lines: Set<number>,\n classification: Map<number, ChangeClassification>,\n) => {\n view.dispatch({ effects: setHighlightedLines.of({ lines, classification }) });\n};\n","import { type ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { type Extension } from '@codemirror/state';\nimport { EditorView } from '@codemirror/view';\nimport CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror';\n\nimport colors from '@keboola/tailwind-config/colors';\n\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { cn } from '../../utils';\nimport { resolveToken } from '../../utils/themeTokens';\nimport { buildBasicSetup } from '../CodeEditor/helpers';\nimport { useThemedExtension } from '../CodeEditor/tokenTheme';\n\nimport { type ChangeClassification, LINE_HEIGHT_PX } from './constants';\nimport {\n buildDiffHighlightTheme,\n createDiffHighlightExtension,\n updateHighlightedLines,\n} from './decorations';\n\nconst EMPTY_LINES: Set<number> = new Set();\nconst EMPTY_CLASSIFICATION: Map<number, ChangeClassification> = new Map();\n\ntype Props = {\n value: string;\n highlightedLines: Set<number>;\n lineClassification: Map<number, ChangeClassification>;\n readOnly?: boolean;\n onChange?: (value: string) => void;\n header?: ReactNode;\n headerClassName?: string;\n className?: string;\n onScrollDOMReady?: (el: HTMLElement | null) => void;\n /** Side deleted upstream: error-red chrome, the diff still visible. */\n deleted?: boolean;\n};\n\nexport const MergePane = ({\n value,\n highlightedLines,\n lineClassification,\n readOnly = false,\n onChange,\n header,\n headerClassName,\n className,\n onScrollDOMReady,\n deleted = false,\n}: Props) => {\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n const handleChange = useStableCallback((next: string) => onChange?.(next));\n\n // The deleted wash is a fixed error hue, not a token; dark mode uses a low-alpha tint\n // because an opaque light-red slab makes near-white text unreadable.\n const themeExtension = useThemedExtension(`merge-pane:${deleted}`, (scheme) => {\n const dark = scheme === 'dark';\n const deletedSurface = dark ? `${colors.error[500]}1f` : colors.error[100];\n const deletedGutter = dark ? `${colors.error[500]}3d` : colors.error[200];\n // Stock line-number grey fails contrast on the wash.\n const deletedGutterText = dark ? colors.error[300] : colors.error[700];\n\n return EditorView.theme({\n '&.cm-editor': {\n height: '100%',\n backgroundColor: deleted ? deletedSurface : resolveToken('background', '249 250 251'),\n // Token text colour so content stays readable when `--background` goes dark.\n color: resolveToken('foreground', '30 41 59'),\n outline: 'none',\n },\n '.cm-gutters': {\n backgroundColor: deleted ? deletedGutter : resolveToken('muted', '241 245 249'),\n color: deleted ? deletedGutterText : resolveToken('muted-foreground', '100 116 139'),\n },\n '*': { lineHeight: `${LINE_HEIGHT_PX}px` },\n '.cm-lineNumbers .cm-gutterElement': { padding: '0 0 0 25px' },\n });\n });\n\n // Separate from the theme: a fresh `StateField` on reconfigure would drop the highlights.\n const diffHighlightExtension = useMemo(() => createDiffHighlightExtension(), []);\n\n // Must rebuild on scheme change — see `buildDiffHighlightTheme`.\n const diffHighlightTheme = useThemedExtension('merge-diff-highlight', buildDiffHighlightTheme);\n\n const basicSetup = useMemo(\n () => ({ ...buildBasicSetup(readOnly), lineNumbers: true }),\n [readOnly],\n );\n\n const extensions = useMemo(\n (): Extension[] => [\n diffHighlightExtension,\n diffHighlightTheme,\n themeExtension,\n // Re-measure after doc changes so late-settling layouts don't leave trailing lines blank.\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n requestAnimationFrame(() => update.view.dispatch({}));\n }\n }),\n ],\n [diffHighlightExtension, diffHighlightTheme, themeExtension],\n );\n\n // A deleted side is a file-level conflict, so it shows no line markers.\n useEffect(() => {\n const view = editorRef.current?.view;\n if (!view) return;\n updateHighlightedLines(\n view,\n deleted ? EMPTY_LINES : highlightedLines,\n deleted ? EMPTY_CLASSIFICATION : lineClassification,\n );\n }, [highlightedLines, lineClassification, deleted]);\n\n const handleCreateEditor = useCallback(\n (view: EditorView) => {\n updateHighlightedLines(\n view,\n deleted ? EMPTY_LINES : highlightedLines,\n deleted ? EMPTY_CLASSIFICATION : lineClassification,\n );\n onScrollDOMReady?.(view.scrollDOM);\n },\n [highlightedLines, lineClassification, onScrollDOMReady, deleted],\n );\n\n useEffect(() => {\n return () => onScrollDOMReady?.(null);\n }, [onScrollDOMReady]);\n\n // Parent dimensions settle after CodeMirror mounts (fullscreen modal, alerts above).\n useEffect(() => {\n const view = editorRef.current?.view;\n const wrapper = view?.dom.parentElement;\n if (!view || !wrapper) return;\n\n const observer = new ResizeObserver(() => view.dispatch({}));\n observer.observe(wrapper);\n\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n className={cn(\n 'tw:flex tw:min-w-0 tw:flex-1 tw:flex-col tw:overflow-hidden',\n className,\n deleted && 'tw:border-error-300 tw:[[data-theme=dark]_&]:border-error-500/50',\n )}\n >\n {header && (\n <div\n className={cn(\n 'tw:px-4 tw:py-3',\n // Same light/dark split as the editor wash, for the same near-white text.\n deleted\n ? 'tw:border-b tw:border-error-200 tw:bg-error-100 tw:[[data-theme=dark]_&]:border-error-500/30 tw:[[data-theme=dark]_&]:bg-error-500/15'\n : 'tw:bg-background',\n headerClassName,\n )}\n >\n {header}\n </div>\n )}\n <div className=\"tw:flex tw:h-0 tw:flex-1 tw:flex-col tw:[&_>div]:h-full\">\n <CodeMirror\n ref={editorRef}\n height=\"100%\"\n value={value}\n onChange={handleChange}\n extensions={extensions}\n readOnly={readOnly}\n onCreateEditor={handleCreateEditor}\n basicSetup={basicSetup}\n />\n </div>\n </div>\n );\n};\n","import { useCallback, useRef } from 'react';\n\nexport const useScrollSync = () => {\n const scrollersRef = useRef<(HTMLElement | null)[]>([]);\n const followersRef = useRef<Map<string, { paneIndex: number; el: HTMLElement }>>(new Map());\n const isSyncingRef = useRef(false);\n const scrollerCallbacksRef = useRef<Map<number, (el: HTMLElement | null) => void>>(new Map());\n const followerCallbacksRef = useRef<Map<string, (el: HTMLElement | null) => void>>(new Map());\n\n const updateFollowers = useCallback(() => {\n for (const [, { paneIndex, el }] of followersRef.current) {\n const scroller = scrollersRef.current[paneIndex];\n if (!scroller) continue;\n el.style.transform = `translateY(-${scroller.scrollTop}px)`;\n }\n }, []);\n\n const handleScroll = useCallback(\n (e: Event) => {\n if (isSyncingRef.current) return;\n isSyncingRef.current = true;\n\n // Px-aligned sync. All panes share LINE_HEIGHT_PX, so matching scrollTop is the same\n // as matching the line at the top of the viewport. Previous ratio-based sync drifted\n // badly when pane heights differed (e.g. 50 lines vs 500 — half-scrolling left snapped\n // right to its midpoint, not to the equivalent line). Clamp to each target's max so\n // the source can scroll past where shorter panes bottom out without errors.\n const sourceScrollTop = (e.target as HTMLElement).scrollTop;\n\n for (const scroller of scrollersRef.current) {\n if (!scroller || scroller === e.target) continue;\n const targetMax = Math.max(0, scroller.scrollHeight - scroller.clientHeight);\n scroller.scrollTop = Math.min(sourceScrollTop, targetMax);\n }\n\n updateFollowers();\n isSyncingRef.current = false;\n },\n [updateFollowers],\n );\n\n const registerScroller = useCallback(\n (index: number) => {\n const existing = scrollerCallbacksRef.current.get(index);\n if (existing) return existing;\n\n const callback = (el: HTMLElement | null) => {\n const prev = scrollersRef.current[index];\n if (prev === el) return;\n\n prev?.removeEventListener('scroll', handleScroll);\n scrollersRef.current[index] = el;\n el?.addEventListener('scroll', handleScroll, { passive: true });\n };\n\n scrollerCallbacksRef.current.set(index, callback);\n return callback;\n },\n [handleScroll],\n );\n\n const registerFollower = useCallback((paneIndex: number, key: string) => {\n const existing = followerCallbacksRef.current.get(key);\n if (existing) return existing;\n\n const callback = (el: HTMLElement | null) => {\n if (el) {\n followersRef.current.set(key, { paneIndex, el });\n } else {\n followersRef.current.delete(key);\n }\n };\n\n followerCallbacksRef.current.set(key, callback);\n return callback;\n }, []);\n\n return { registerScroller, registerFollower };\n};\n","import type { ReactNode } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { AcceptControls } from './AcceptControls/AcceptControls';\nimport type { ChangeClassification, MergeConflict } from './constants';\nimport { MergePane } from './MergePane';\nimport { useScrollSync } from './useScrollSync';\n\nconst EMPTY_LINES: Set<number> = new Set();\nconst EMPTY_CLASSIFICATION: Map<number, ChangeClassification> = new Map();\n\ntype Props = {\n mergeValue: string;\n handleMergeChange: (value: string) => void;\n leftText: string;\n rightText: string;\n leftConflicts: MergeConflict[];\n rightConflicts: MergeConflict[];\n leftHighlightedLines: Set<number>;\n rightHighlightedLines: Set<number>;\n leftClassification: Map<number, ChangeClassification>;\n rightClassification: Map<number, ChangeClassification>;\n mergeHighlightedLines: Set<number>;\n mergeClassification: Map<number, ChangeClassification>;\n acceptLeft: (conflict: MergeConflict) => void;\n acceptRight: (conflict: MergeConflict) => void;\n dismissLeft: (conflict: MergeConflict) => void;\n dismissRight: (conflict: MergeConflict) => void;\n leftHeader?: ReactNode;\n middleHeader?: ReactNode;\n middleHeaderClassName?: string;\n middleClassName?: string;\n rightHeader?: ReactNode;\n className?: string;\n /** Side deleted upstream: its pane turns error-red, its accept/dismiss controls are hidden. */\n leftDeleted?: boolean;\n rightDeleted?: boolean;\n};\n\nexport const MergeEditor = ({\n mergeValue,\n handleMergeChange,\n leftText,\n rightText,\n leftConflicts,\n rightConflicts,\n leftHighlightedLines,\n rightHighlightedLines,\n leftClassification,\n rightClassification,\n mergeHighlightedLines,\n mergeClassification,\n acceptLeft,\n acceptRight,\n dismissLeft,\n dismissRight,\n leftHeader,\n middleHeader,\n middleHeaderClassName,\n middleClassName,\n rightHeader,\n className,\n leftDeleted = false,\n rightDeleted = false,\n}: Props) => {\n const { registerScroller, registerFollower } = useScrollSync();\n\n // A deleted side makes it a keep-or-drop-the-file choice, so the middle pane shows no line markers.\n const anySideDeleted = leftDeleted || rightDeleted;\n\n return (\n <div\n className={cn(\n 'tw:flex tw:h-full tw:min-h-0 tw:overflow-hidden tw:bg-background tw:gap-3',\n className,\n )}\n >\n <MergePane\n value={leftText}\n highlightedLines={leftHighlightedLines}\n lineClassification={leftClassification}\n readOnly\n header={leftHeader}\n className=\"tw:rounded-r-lg tw:border tw:border-border\"\n onScrollDOMReady={registerScroller(0)}\n deleted={leftDeleted}\n />\n\n <AcceptControls\n conflicts={leftDeleted ? [] : leftConflicts}\n side=\"left\"\n onAccept={acceptLeft}\n onDismiss={dismissLeft}\n contentRef={registerFollower(0, 'left-controls')}\n />\n\n <MergePane\n value={mergeValue}\n highlightedLines={anySideDeleted ? EMPTY_LINES : mergeHighlightedLines}\n lineClassification={anySideDeleted ? EMPTY_CLASSIFICATION : mergeClassification}\n onChange={handleMergeChange}\n header={middleHeader}\n headerClassName={middleHeaderClassName}\n className={cn('tw:border tw:border-border tw:rounded-lg', middleClassName)}\n onScrollDOMReady={registerScroller(1)}\n />\n\n <AcceptControls\n conflicts={rightDeleted ? [] : rightConflicts}\n side=\"right\"\n onAccept={acceptRight}\n onDismiss={dismissRight}\n contentRef={registerFollower(2, 'right-controls')}\n />\n\n <MergePane\n value={rightText}\n highlightedLines={rightHighlightedLines}\n lineClassification={rightClassification}\n readOnly\n header={rightHeader}\n className=\"tw:rounded-l-lg tw:border tw:border-border\"\n onScrollDOMReady={registerScroller(2)}\n deleted={rightDeleted}\n />\n </div>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { FieldItem, type FieldItemProps } from '../../blocks/Form/connectors/FieldItem';\nimport { useFieldContext } from '../../blocks/Form/contexts';\n\nimport { CodeEditor } from './CodeEditor';\n\ntype Props = FieldItemProps &\n Omit<\n ComponentProps<typeof CodeEditor>,\n // Owned by the field / `FieldItem` — see the connector rules in AGENTS.md.\n | 'value'\n | 'onChange'\n | 'onBlur'\n | 'ariaLabel'\n | 'ariaLabelledBy'\n | 'ariaDescribedBy'\n | 'ariaInvalid'\n | 'ariaRequired'\n // Makes a viewer (no lint, no completions), not a disabled control; use `inputLocked` instead.\n | 'readOnly'\n | 'className'\n // Derived from `required`, so a call site cannot contradict its own validation.\n | 'allowBlankDocument'\n > & {\n /** Styles the editor box; `className` styles the field frame. */\n editorClassName?: string;\n };\n\n/**\n * Code / JSON editor field; state is the raw editor text, never a parsed value.\n *\n * - In `@keboola/design/editors`, not `useAppForm`: keeps CodeMirror (~170 kB) out of the main entry.\n * - Reads the field from context, so use it inside `<form.AppField>` like a connector.\n * - JSON is invalid mid-edit; parse in the schema or at submit.\n * - Labelled via `aria-labelledby`: CodeMirror's `div[role=\"textbox\"]` is not labelable.\n */\nexport const CodeEditorField = ({\n label,\n action,\n required,\n requiredMark,\n help,\n tooltip,\n className,\n 'aria-describedby': ariaDescribedBy,\n editorClassName,\n variant = 'field',\n ...editorProps\n}: Props) => {\n const field = useFieldContext<string>();\n\n return (\n <FieldItem\n label={label}\n action={action}\n required={required}\n requiredMark={requiredMark}\n labelling=\"aria-labelledby\"\n help={help}\n tooltip={tooltip}\n className={className}\n aria-describedby={ariaDescribedBy}\n >\n {(control) => (\n <CodeEditor\n {...editorProps}\n variant={variant}\n className={editorClassName}\n // Camel-cased: CodeEditor writes them onto CodeMirror's focused content node.\n ariaLabelledBy={control['aria-labelledby']}\n ariaDescribedBy={control['aria-describedby']}\n ariaInvalid={control['aria-invalid']}\n ariaRequired={control['aria-required']}\n // Empty is valid for an optional field, so hide the \"Unexpected end of input\" lint mark.\n allowBlankDocument={!required}\n value={field.state.value ?? ''}\n onChange={field.handleChange}\n onBlur={field.handleBlur}\n />\n )}\n </FieldItem>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAKA,MAAM,uBAAuB,WAAW,KAAK,EAAE,OAAO,wCAAwC,CAAC;AAC/F,MAAM,wBAAwB,WAAW,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAC1E,MAAM,sBAAsB,WAAW,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAC7F,MAAM,wBAAwB,WAAW,KAAK,EAC5C,OAAO,6DACT,CAAC;;AAKD,MAAa,wBACX,KACA,WACA,eACwC;CACxC,IAAI,WAAW,WAAW,GAAG,OAAO;CAEpC,IAAI,QAAmC,WAAW,WAAW,SAAS;CACtE,KAAK,MAAM,YAAY,YACrB,IAAI,aAAa,SAAS,IAAI;EAC5B,QAAQ;EACR;CACF;CAGF,IAAI,CAAC,OAAO,OAAO;CAEnB,MAAM,YAAY,IAAI,MAAM,MAAM,MAAM,MAAM,EAAE;CAChD,MAAM,oBAAoB,UAAU,SAAS,UAAU,UAAU,CAAC,CAAC;CACnE,MAAM,qBAAqB,UAAU,SAAS,UAAU,QAAQ,CAAC,CAAC;CAElE,MAAM,eAAe,MAAM,OAAO;CAClC,MAAM,aAAa,MAAM,KAAK;CAE9B,IAAI,gBAAgB,YAAY,OAAO;CAEvC,OAAO;EAAE,MAAM;EAAc,IAAI;CAAW;AAC9C;;;;;;;;AASA,MAAa,qBAAqB,SAAmB,cAAuC;CAC1F,MAAM,aAA8B,CAAC;CACrC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,UAAU,WAAW;EACzB,WAAW,KAAK;GAAE,MAAM;GAAQ,IAAI,KAAK,IAAI,SAAS,MAAM,QAAQ,SAAS;EAAE,CAAC;EAChF,UAAU,MAAM;CAClB;CACA,OAAO;AACT;;;;;;;;AASA,MAAa,+BACX,YACA,YACoB;CACpB,MAAM,UAAU,QAAQ;CACxB,MAAM,SAA0B,CAAC;CACjC,KAAK,MAAM,KAAK,YAAY;EAC1B,MAAM,OAAO,QAAQ,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,EAAE;EACtE,MAAM,KAAK,QAAQ,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC;EACjE,IAAI,OAAO,IAAI,OAAO,KAAK;GAAE;GAAM;EAAG,CAAC;CACzC;CACA,OAAO;AACT;AAEA,MAAM,oBAAoB,MAAkB,UAAwC;CAClF,MAAM,YAAY,KAAK,MAAM,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC;CACpD,MAAM,UAAU,KAAK,MAAM,IAAI,OAAO,MAAM,EAAE,CAAC,CAAC;CAEhD,MAAM,cAAmC,CAAC;CAC1C,KAAK,IAAI,UAAU,WAAW,WAAW,SAAS,WAAW;EAC3D,MAAM,YAAY,KAAK,MAAM,IAAI,KAAK,OAAO,CAAC,CAAC;EAC/C,IAAI,cAAc,SAChB,YAAY,KAAK,sBAAsB,MAAM,SAAS,CAAC;OAClD,IAAI,YAAY,WACrB,YAAY,KAAK,qBAAqB,MAAM,SAAS,CAAC;OACjD,IAAI,YAAY,SACrB,YAAY,KAAK,oBAAoB,MAAM,SAAS,CAAC;OAErD,YAAY,KAAK,sBAAsB,MAAM,SAAS,CAAC;CAE3D;CAEA,OAAO,WAAW,IAAI,WAAW;AACnC;AAEA,MAAa,wBAAwB,iBAAqD;CACxF,OAAO,CACL,WAAW,UACT,MAAM;EACJ,cAAc,WAAW;EACzB,gBAA8D;EAC9D,MAAc;EACd,YAAoB;EACpB,mBAA4C,CAAC;EAC7C,YAAoB;EAEpB,YAAY,MAAkB;GAC5B,KAAK,iBAAiB,IAAI;EAC5B;EAEA,OAAO,QAAoB;GACzB,IAAI,OAAO,gBAAgB,CAAC,OAAO,KAAK,UAAU;IAChD,KAAK,cAAc,WAAW;IAC9B;GACF;GAEA,IAAI,OAAO,YAAY;IAErB,IAAI,KAAK,iBAAiB,SAAS,GAAG;KACpC,KAAK,mBAAmB,4BACtB,KAAK,kBACL,OAAO,OACT;KACA,KAAK,YAAY,OAAO,MAAM,IAAI,SAAS;KAC3C,KAAK,gBAAgB,OAAO,IAAI;IAClC;IAEA,KAAK,iBAAiB,OAAO,IAAI;GACnC,OAAO,IAAI,OAAO,gBAAiB,OAAO,gBAAgB,OAAO,KAAK,UACpE,KAAK,gBAAgB,OAAO,IAAI;EAEpC;EAEA,UAAU;GACR,KAAK,YAAY;GACjB,IAAI,KAAK,eAAe,aAAa,KAAK,aAAa;EACzD;;EAGA,gBAAwB,MAAkB;GACxC,IAAI,CAAC,KAAK,UAAU;IAClB,KAAK,cAAc,WAAW;IAC9B;GACF;GAEA,MAAM,EAAE,SAAS,KAAK,MAAM;GAE5B,IAAI,KAAK,SAAS,KAAK,IAAI;IACzB,KAAK,cAAc,WAAW;IAC9B;GACF;GAEA,MAAM,MAAM,KAAK,MAAM,IAAI,SAAS;GACpC,IAAI,QAAQ,KAAK,WAAW;GAC5B,IAAI,KAAK,iBAAiB,WAAW,GAAG;IACtC,KAAK,cAAc,WAAW;IAC9B;GACF;GAEA,MAAM,QAAQ,qBAAqB,KAAK,KAAK,MAAM,KAAK,gBAAgB;GACxE,KAAK,cAAc,QAAQ,iBAAiB,MAAM,KAAK,IAAI,WAAW;EACxE;EAEA,iBAAyB,MAAkB;GACzC,IAAI,KAAK,eAAe,aAAa,KAAK,aAAa;GAEvD,KAAK,gBAAgB,WAAW,YAAY;IAC1C,MAAM,MAAM,EAAE,KAAK;IACnB,MAAM,MAAM,KAAK,MAAM,IAAI,SAAS;IAEpC,IAAI,CAAC,IAAI,KAAK,GAAG;KACf,KAAK,YAAY;KACjB,KAAK,mBAAmB,CAAC;KACzB,IAAI,KAAK,gBAAgB,WAAW,MAAM;MACxC,KAAK,cAAc,WAAW;MAC9B,IAAI,CAAC,KAAK,WAAW,KAAK,SAAS;KACrC;KACA;IACF;IAEA,IAAI;IACJ,IAAI;KACF,UAAU,MAAM,aAAa,GAAG;IAClC,QAAQ;KACN;IACF;IAGA,IAAI,KAAK,aAAa,QAAQ,KAAK,KAAK;IAExC,KAAK,YAAY;IACjB,KAAK,mBAAmB,kBAAkB,SAAS,IAAI,MAAM;IAE7D,KAAK,gBAAgB,IAAI;IACzB,IAAI,CAAC,KAAK,WAAW,KAAK,SAAS;GACrC,GAAG,GAAG;EACR;CACF,GACA,EAAE,cAAc,MAAM,EAAE,YAAY,CACtC,GACA,WAAW,UAAU;EACnB,oBAAoB;GAClB,WAAW,oBAAoB,OAAO,KAAK,KAAK,oBAAoB,OAAO,KAAK;GAChF,aAAa;EACf;EACA,0BAA0B;GACxB,WAAW,oBAAoB,OAAO,KAAK,KAAK,oBAAoB,OAAO,KAAK,KAAK,oBAAoB,OAAO,KAAK;GACrH,cAAc;EAChB;EACA,yBAAyB;GACvB,WAAW,oBAAoB,OAAO,KAAK,KAAK,oBAAoB,OAAO,KAAK,KAAK,qBAAqB,OAAO,KAAK;GACtH,cAAc;EAChB;EACA,+CAA+C;GAC7C,WAAW,mBAAmB,OAAO,KAAK;GAC1C,cAAc;EAChB;CACF,CAAC,CACH;AACF;;ACpNA,IAAM,kBAAN,cAA8B,aAAa;CACzC,QAAiB;EACf,MAAM,SAAS,SAAS,cAAc,KAAK;EAC3C,OAAO,YAAY;EACnB,OAAO;CACT;AACF;AAEA,MAAM,kBAAkB,IAAI,gBAAgB;AAG5C,MAAM,sBACJ,KACA,MACA,IACA,aACQ;CACR,MAAM,UAAe,CAAC;CAGtB,MAAM,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC;CACrC,MAAM,SAAS,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC;CAEzC,KAAK,IAAI,IAAI,UAAU,KAAK,QAAQ,KAAK;EACvC,MAAM,OAAO,IAAI,KAAK,CAAC;EACvB,QAAQ,KAAK,SAAS,KAAK,IAAI,CAAC;CAClC;CAEA,OAAO;AACT;AAGA,MAAM,4BAA4B,YAAY,OAAyB;AAGvE,MAAM,wBAAwB,WAAW,OAAyB;CAChE,SAAS;EACP,OAAO;CACT;CACA,OAAO,OAAO,aAAa;EACzB,KAAK,MAAM,UAAU,YAAY,SAC/B,IAAI,OAAO,GAAG,yBAAyB,GACrC,OAAO,OAAO;EAGlB,OAAO;CACT;AACF,CAAC;AAGD,MAAM,kBAAkB,OAAO;CAC7B,OAAO;CACP,UAAU,SAAiC;EACzC,MAAM,gBAAgB,KAAK,MAAM,MAAM,uBAAuB,KAAK;EAEnE,IAAI,CAAC,eACH,OAAO,SAAS;EAIlB,MAAM,UAAU,mBACd,KAAK,MAAM,KACX,cAAc,MACd,cAAc,KACb,aAAa,gBAAgB,MAAM,QAAQ,CAC9C;EAEA,OAAO,SAAS,GAAG,OAAO;CAC5B;AACF,CAAC;AAGD,MAAM,uBAAuB,WAAW,OAAO;CAC7C,SAAS;EACP,OAAO,WAAW;CACpB;CACA,OAAO,aAAa,aAAa;EAC/B,cAAc,YAAY,IAAI,YAAY,OAAO;EACjD,KAAK,MAAM,UAAU,YAAY,SAAS;GACxC,IAAI,CAAC,OAAO,GAAG,yBAAyB,GACtC;GAGF,IAAI,CAAC,OAAO,SAAS,CAAC,OAAO,MAAM,OACjC,OAAO,WAAW;GAIpB,MAAM,kBAAkB,mBACtB,YAAY,MAAM,KAClB,OAAO,MAAM,MAAM,MACnB,OAAO,MAAM,MAAM,KAClB,aAAa,WAAW,KAAK,EAAE,OAAO,gBAAgB,CAAC,CAAC,CAAC,MAAM,QAAQ,CAC1E;GAEA,OAAO,WAAW,IAAI,eAAe;EACvC;EACA,OAAO;CACT;CACA,UAAU,MAAM,WAAW,YAAY,KAAK,CAAC;AAC/C,CAAC;AAGD,MAAM,4BAA4B,WAAW,OAAO;CAClD,SAAS;EACP,OAAO,WAAW;CACpB;CACA,OAAO,aAAa,aAAa;EAC/B,cAAc,YAAY,IAAI,YAAY,OAAO;EACjD,KAAK,MAAM,UAAU,YAAY,SAAS;GACxC,IAAI,CAAC,OAAO,GAAG,yBAAyB,GACtC;GAGF,IAAI,CAAC,OAAO,SAAS,CAAC,OAAO,MAAM,YACjC,OAAO,WAAW;GAGpB,MAAM,kBAAkB,mBACtB,YAAY,MAAM,KAClB,OAAO,MAAM,WAAW,MACxB,OAAO,MAAM,WAAW,KACvB,aAAa,WAAW,KAAK,EAAE,OAAO,qBAAqB,CAAC,CAAC,CAAC,MAAM,QAAQ,CAC/E;GAEA,OAAO,WAAW,IAAI,eAAe;EACvC;EACA,OAAO;CACT;CACA,UAAU,MAAM,WAAW,YAAY,KAAK,CAAC;AAC/C,CAAC;;;;;;;;;;AAWD,MAAM,wBAAwB,WAAW,UAAU;CACjD,wBAAwB;EACtB,OAAO;EACP,aAAa;CACf;CACA,wBAAwB;EACtB,OAAO;EACP,QAAQ;EACR,iBAAiB,OAAO,KAAK;CAC/B;CACA,kBAAkB,EAChB,iBAAiB,GAAG,OAAO,MAAM,KAAK,aACxC;CACA,uBAAuB,EACrB,iBAAiB,GAAG,OAAO,KAAK,KAAK,aACvC;CAEA,wBAAwB,EACtB,iBAAiB,GAAG,OAAO,MAAM,oBACnC;CACA,6BAA6B,EAC3B,iBAAiB,GAAG,OAAO,KAAK,oBAClC;AACF,CAAC;AAGD,SAAgB,wBAAqC;CACnD,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;AAEA,SAAgB,mBAAmB,MAAkB,OAA0B;CAC7E,KAAK,SAAS,EAAE,SAAS,0BAA0B,GAAG,SAAS,IAAI,EAAE,CAAC;AACxE;;ACtKA,MAAM,cAAc;CAClB,eAAe;CACf,kBAAkB;CAClB,cAAc;AAChB;AAEA,MAAM,gBAA8B,CAClC;CACE,KAAK;CACL,iBAAiB;CACjB,MAAM,SAAqB;EACzB,KAAK,WAAW,KAAK;EACrB,OAAO;CACT;AACF,CACF;AAEA,MAAM,uBAAuBA,SAAO,GAAG,CAAC,GAAG,eAAe,GAAG,aAAa,CAAC;AAG3E,MAAM,cAAc,YAAiC;CACnD,GAAG,qBAAqB,MAAM;CAC9B,GAAG,kBAAkB,kBAAkB,CAAC;AAC1C;AAgCA,MAAa,aAAa,EACxB,OACA,UACA,mBACA,gBACA,iBACA,cACA,eACA,cAAc,IACd,cAAc,IACd,kBACA,WAAW,OACX,aACA,YAAY,OACZ,cAAc,MACd,WACA,QACA,kBACA,WACA,iBACA,eACA,gBACA,cACW;CACX,MAAM,YAAY,OAA2B,IAAI;CAGjD,MAAM,eAAe,mBAAmB,SAAiB,WAAW,IAAI,CAAC;CACzE,MAAM,eAAe,kBAAkB,OAAO,QAAiB,MAAM,cAAc,GAAG,KAAM,CAAC,CAAC;CAC9F,MAAM,aAAa,mBAAmB,SAAqB,eAAe,IAAI,CAAC;CAC/E,MAAM,cAAc,mBAAmB,SAAqB,gBAAgB,IAAI,CAAC;CAEjF,MAAM,eAAe,mBAAmB,WAAuB;EAC7D,IAAI,OAAO,cAAc;GACvB,MAAM,EAAE,SAAS,OAAO,MAAM;GAE9B,oBAAoB,OAAO,MAAM,SAAS,KAAK,MAAM,KAAK,EAAE,CAAC;EAC/D;CACF,CAAC;CAED,MAAM,qBAAqB,sBAAsB,SAAS;CAG1D,MAAM,kBAAkB,gBAAgB,KAAA;CAExC,MAAM,eAAe,qBAAqB;CAG1C,MAAM,cAAc,mBAAmB,iBAAiB,gBAAgB;CAExE,MAAM,iBAAiB,mBAAmB,sBAAsB,WAC9DC,aAAW,MAAM,WAAW,MAAM,GAAG,EAAE,MAAM,WAAW,OAAO,CAAC,CAClE;CAEA,MAAM,aAAa,cAAc;EAC/B,OAAO;GACLA,aAAW;GACX;GACA,GAAG,kBAAkB;IACnB;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,gBAAgB;GAChB,sBAAsB;GACtB,kBAAkB,qBAAqB,YAAY,IAAI,CAAC;GACxD;GACA;GACAA,aAAW,iBAAiB;IAC1B,OAAO,GAAG,SAAS,WAAW,IAAI;IAClC,QAAQ,GAAG,SAAS,YAAY,IAAI;GACtC,CAAC;EACH;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,eAAe,cAAc;EACjC,OAAO;GAAE,GAAG,gBAAgB,QAAQ;GAAG,GAAG;GAAa;EAAY;CACrE,GAAG,CAAC,UAAU,WAAW,CAAC;CAE1B,gBAAgB;EACd,IAAI,UAAU,SAAS,MACrB,mBAAmB,UAAU,QAAQ,MAAM,cAAc;CAE7D,GAAG,CAAC,cAAc,CAAC;CAEnB,gBAAgB;EACd,IAAI,UAAU,SAAS,MACrB,aAAa,UAAU,QAAQ,MAAM,aAAa,gBAAgB;CAEtE,GAAG,CAAC,aAAa,gBAAgB,CAAC;CAGlC,MAAM,gBAAgB,wBAAwB,kBAAkB,CAAC;CACjE,gBAAgB,eAAe,CAAC,aAAa,CAAC;CAE9C,MAAM,eAAe,mBAAmB,MAAkB,UAAuB;EAC/E,iBAAiB,MAAM,KAAK;EAE5B,IAAI,gBACF,mBAAmB,MAAM,cAAc;EAGzC,IAAI,aACF,aAAa,MAAM,aAAa,gBAAgB;CAEpD,CAAC;CAED,OACE,oBAAC,YAAD;EACE,KAAK;EACL,OAAO;EACK;EACL;EACP,UAAU;EACV,UAAU;EACV,gBAAgB;EACL;EACE;EACF;EACD;EACV,UAAU,CAAC;EACX,YAAY;CACb,CAAA;AAEL;;ACxNA,MAAa,gBAAgB,EAAE,MAAM,eAAsB;CACzD,MAAM,QAAQ,UAAU,SAAS,SAAS,eAAe,SAAS;CAElE,OACE,oBAAC,QAAD;EAAQ,SAAS;EAAU,SAAQ;EAAU,MAAK;EAAU,OAAO;EAAO,cAAY;EACpF,UAAA,oBAHY,SAAS,SAAS,gBAAgB,cAG9C,EAAS,WAAU,YAAa,CAAA;CAC1B,CAAA;AAEZ;;ACMA,MAAa,kBAAkB,EAAE,WAAW,MAAM,UAAU,WAAW,iBACrE,oBAAC,OAAD;CACE,WAAW,GACT,2DACA,UAAU,SAAS,IAAI,WAAW,QACpC;CAEC,UAAA,UAAU,SAAS,KAClB,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAU;EAAc,OAAO,EAAE,QAAQ,OAA6B;CAAI,CAAA,GAC/E,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,oBAAC,OAAD;GAAK,KAAK;GAAY,WAAU;GAC7B,UAAA,UAAU,KAAK,aAAa;IAE3B,MAAM,cADU,SAAS,SAAS,SAAS,eAAe,SAAS,gBACtC,KAAA,KAAsB;IAEnD,OACE,qBAAC,OAAD;KAEE,WAAU;KACV,OAAO,EAAE,KAAK,GAAG,UAAU,IAAI;KAHjC,UAAA,CAKE,oBAAC,cAAD;MAAoB;MAAM,gBAAgB,SAAS,QAAQ;KAAI,CAAA,GAC9D,aACC,oBAAC,QAAD;MACE,eAAe,UAAU,QAAQ;MACjC,SAAQ;MACR,MAAK;MACL,OAAM;MACN,cAAY,WAAW,SAAS,SAAS,eAAe,SAAS;MAEjE,UAAA,oBAAC,GAAD,EAAG,WAAU,YAAa,CAAA;KACpB,CAAA,CAEP;IAhBE,GAAA,SAAS,EAgBX;GAET,CAAC;EACE,CAAA;CACF,CAAA,CACL,EAAA,CAAA;AAED,CAAA;;ACnCP,MAAM,sBAAsB,YAAY,OAAyB;AAEjE,MAAM,iBAAiB,WAAW,KAAK,EAAE,OAAO,qBAAqB,CAAC;AACtE,MAAM,qBAAqB,WAAW,KAAK,EAAE,OAAO,yBAAyB,CAAC;AAE9E,IAAM,mBAAN,cAA+B,aAAa;CAC1C,eAAwB;AAC1B;AAEA,IAAM,uBAAN,cAAmC,aAAa;CAC9C,eAAwB;AAC1B;AAEA,MAAM,mBAAmB,IAAI,iBAAiB;AAC9C,MAAM,uBAAuB,IAAI,qBAAqB;AAOtD,MAAa,qCACX,WAAW,OAAmB;CAC5B,eAAe;EAAE,aAAa,WAAW;EAAM,eAAe,SAAS;CAAM;CAC7E,OAAO,OAAO,IAAI;EAEhB,IAAI,UAAmC;EACvC,KAAK,MAAM,UAAU,GAAG,SACtB,IAAI,OAAO,GAAG,mBAAmB,GAC/B,UAAU,OAAO;EAIrB,IAAI,CAAC,SACH,OAAO;GACL,aAAa,MAAM,YAAY,IAAI,GAAG,OAAO;GAC7C,eAAe,MAAM,cAAc,IAAI,GAAG,OAAO;EACnD;EAGF,MAAM,cAAc,IAAI,gBAA4B;EACpD,MAAM,gBAAgB,IAAI,gBAA8B;EACxD,MAAM,MAAM,GAAG,MAAM;EACrB,MAAM,EAAE,OAAO,mBAAmB;EAGlC,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,QAAQ,MAAM,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;EACtF,KAAK,MAAM,KAAK,QAAQ;GACtB,MAAM,MAAM,eAAe,IAAI,CAAC;GAChC,IAAI,CAAC,KAAK;GAEV,MAAM,SAAS,QAAQ,aAAa;GACpC,MAAM,OAAO,IAAI,KAAK,CAAC;GACvB,YAAY,IAAI,KAAK,MAAM,KAAK,MAAM,SAAS,iBAAiB,kBAAkB;GAClF,cAAc,IAAI,KAAK,MAAM,KAAK,MAAM,SAAS,mBAAmB,oBAAoB;EAC1F;EAEA,OAAO;GACL,aAAa,YAAY,OAAO;GAChC,eAAe,cAAc,OAAO;EACtC;CACF;CACA,UAAU,MAAM,CACd,WAAW,YAAY,KAAK,IAAI,QAAQ,IAAI,WAAW,GACvD,gBAAgB,KAAK,IAAI,QAAoB,IAAI,aAAa,CAChE;AACF,CAAC;;;;;;;;AASH,MAAa,2BAA2B,WAA2C;CACjF,MAAM,OAAO,WAAW;CACxB,MAAM,EAAE,MAAM,WAAW,cAAc,MAAM;CAG7C,MAAM,aAAa,OAAO,OAAO,MAAM,OAAO,OAAO,MAAM;CAC3D,MAAM,iBAAiB,OAAO,OAAO,QAAQ,OAAO,OAAO,QAAQ;CAEnE,OAAO,WAAW,MAAM;EACtB,uBAAuB;GACrB,iBAAiB,GAAG,KAAK,OAAO,MAAM,MAAM,OAAO,MAAM,IAAI,EAAE;GAC/D,WAAW,iBAAiB,OAAO,MAAM;EAC3C;EACA,2BAA2B;GACzB,iBAAiB,GAAG,KAAK,OAAO,QAAQ,MAAM,OAAO,QAAQ,IAAI,EAAE;GACnE,WAAW,iBAAiB,OAAO,QAAQ;EAC7C;EACA,yBAAyB;GACvB,iBAAiB,GAAG,OAAO,OAAO,MAAM,MAAM,OAAO,MAAM,IAAI,EAAE;GACjE,OAAO;EACT;EACA,6BAA6B;GAC3B,iBAAiB,GAAG,OAAO,OAAO,QAAQ,MAAM,OAAO,QAAQ,IAAI,EAAE;GACrE,OAAO;EACT;CACF,CAAC;AACH;AAEA,MAAa,0BACX,MACA,OACA,mBACG;CACH,KAAK,SAAS,EAAE,SAAS,oBAAoB,GAAG;EAAE;EAAO;CAAe,CAAC,EAAE,CAAC;AAC9E;;ACrHA,MAAMC,gCAA2B,IAAI,IAAI;AACzC,MAAMC,yCAA0D,IAAI,IAAI;AAgBxE,MAAa,aAAa,EACxB,OACA,kBACA,oBACA,WAAW,OACX,UACA,QACA,iBACA,WACA,kBACA,UAAU,YACC;CACX,MAAM,YAAY,OAA2B,IAAI;CACjD,MAAM,eAAe,mBAAmB,SAAiB,WAAW,IAAI,CAAC;CAIzE,MAAM,iBAAiB,mBAAmB,cAAc,YAAY,WAAW;EAC7E,MAAM,OAAO,WAAW;EACxB,MAAM,iBAAiB,OAAO,GAAG,OAAO,MAAM,KAAK,MAAM,OAAO,MAAM;EACtE,MAAM,gBAAgB,OAAO,GAAG,OAAO,MAAM,KAAK,MAAM,OAAO,MAAM;EAErE,MAAM,oBAAoB,OAAO,OAAO,MAAM,OAAO,OAAO,MAAM;EAElE,OAAO,WAAW,MAAM;GACtB,eAAe;IACb,QAAQ;IACR,iBAAiB,UAAU,iBAAiB,aAAa,cAAc,aAAa;IAEpF,OAAO,aAAa,cAAc,UAAU;IAC5C,SAAS;GACX;GACA,eAAe;IACb,iBAAiB,UAAU,gBAAgB,aAAa,SAAS,aAAa;IAC9E,OAAO,UAAU,oBAAoB,aAAa,oBAAoB,aAAa;GACrF;GACA,KAAK,EAAE,YAAY,OAAsB;GACzC,qCAAqC,EAAE,SAAS,aAAa;EAC/D,CAAC;CACH,CAAC;CAGD,MAAM,yBAAyB,cAAc,6BAA6B,GAAG,CAAC,CAAC;CAG/E,MAAM,qBAAqB,mBAAmB,wBAAwB,uBAAuB;CAE7F,MAAM,aAAa,eACV;EAAE,GAAG,gBAAgB,QAAQ;EAAG,aAAa;CAAK,IACzD,CAAC,QAAQ,CACX;CAEA,MAAM,aAAa,cACE;EACjB;EACA;EACA;EAEA,WAAW,eAAe,IAAI,WAAW;GACvC,IAAI,OAAO,YACT,4BAA4B,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC;EAExD,CAAC;CACH,GACA;EAAC;EAAwB;EAAoB;CAAc,CAC7D;CAGA,gBAAgB;EACd,MAAM,OAAO,UAAU,SAAS;EAChC,IAAI,CAAC,MAAM;EACX,uBACE,MACA,UAAUD,gBAAc,kBACxB,UAAUC,yBAAuB,kBACnC;CACF,GAAG;EAAC;EAAkB;EAAoB;CAAO,CAAC;CAElD,MAAM,qBAAqB,aACxB,SAAqB;EACpB,uBACE,MACA,UAAUD,gBAAc,kBACxB,UAAUC,yBAAuB,kBACnC;EACA,mBAAmB,KAAK,SAAS;CACnC,GACA;EAAC;EAAkB;EAAoB;EAAkB;CAAO,CAClE;CAEA,gBAAgB;EACd,aAAa,mBAAmB,IAAI;CACtC,GAAG,CAAC,gBAAgB,CAAC;CAGrB,gBAAgB;EACd,MAAM,OAAO,UAAU,SAAS;EAChC,MAAM,UAAU,MAAM,IAAI;EAC1B,IAAI,CAAC,QAAQ,CAAC,SAAS;EAEvB,MAAM,WAAW,IAAI,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC;EAC3D,SAAS,QAAQ,OAAO;EAExB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,OACE,qBAAC,OAAD;EACE,WAAW,GACT,+DACA,WACA,WAAW,kEACb;EALF,UAAA,CAOG,UACC,oBAAC,OAAD;GACE,WAAW,GACT,mBAEA,UACI,0IACA,oBACJ,eACF;GAEC,UAAA;EACE,CAAA,GAEP,oBAAC,OAAD;GAAK,WAAU;GACb,UAAA,oBAAC,YAAD;IACE,KAAK;IACL,QAAO;IACA;IACP,UAAU;IACE;IACF;IACV,gBAAgB;IACJ;GACb,CAAA;EACE,CAAA,CACF;;AAET;;ACjLA,MAAa,sBAAsB;CACjC,MAAM,eAAe,OAA+B,CAAC,CAAC;CACtD,MAAM,eAAe,uBAA4D,IAAI,IAAI,CAAC;CAC1F,MAAM,eAAe,OAAO,KAAK;CACjC,MAAM,uBAAuB,uBAAsD,IAAI,IAAI,CAAC;CAC5F,MAAM,uBAAuB,uBAAsD,IAAI,IAAI,CAAC;CAE5F,MAAM,kBAAkB,kBAAkB;EACxC,KAAK,MAAM,GAAG,EAAE,WAAW,SAAS,aAAa,SAAS;GACxD,MAAM,WAAW,aAAa,QAAQ;GACtC,IAAI,CAAC,UAAU;GACf,GAAG,MAAM,YAAY,eAAe,SAAS,UAAU;EACzD;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,eAAe,aAClB,MAAa;EACZ,IAAI,aAAa,SAAS;EAC1B,aAAa,UAAU;EAOvB,MAAM,kBAAmB,EAAE,OAAuB;EAElD,KAAK,MAAM,YAAY,aAAa,SAAS;GAC3C,IAAI,CAAC,YAAY,aAAa,EAAE,QAAQ;GACxC,MAAM,YAAY,KAAK,IAAI,GAAG,SAAS,eAAe,SAAS,YAAY;GAC3E,SAAS,YAAY,KAAK,IAAI,iBAAiB,SAAS;EAC1D;EAEA,gBAAgB;EAChB,aAAa,UAAU;CACzB,GACA,CAAC,eAAe,CAClB;CAsCA,OAAO;EAAE,kBApCgB,aACtB,UAAkB;GACjB,MAAM,WAAW,qBAAqB,QAAQ,IAAI,KAAK;GACvD,IAAI,UAAU,OAAO;GAErB,MAAM,YAAY,OAA2B;IAC3C,MAAM,OAAO,aAAa,QAAQ;IAClC,IAAI,SAAS,IAAI;IAEjB,MAAM,oBAAoB,UAAU,YAAY;IAChD,aAAa,QAAQ,SAAS;IAC9B,IAAI,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;GAChE;GAEA,qBAAqB,QAAQ,IAAI,OAAO,QAAQ;GAChD,OAAO;EACT,GACA,CAAC,YAAY,CAmBS;EAAG,kBAhBF,aAAa,WAAmB,QAAgB;GACvE,MAAM,WAAW,qBAAqB,QAAQ,IAAI,GAAG;GACrD,IAAI,UAAU,OAAO;GAErB,MAAM,YAAY,OAA2B;IAC3C,IAAI,IACF,aAAa,QAAQ,IAAI,KAAK;KAAE;KAAW;IAAG,CAAC;SAE/C,aAAa,QAAQ,OAAO,GAAG;GAEnC;GAEA,qBAAqB,QAAQ,IAAI,KAAK,QAAQ;GAC9C,OAAO;EACT,GAAG,CAAC,CAEsC;CAAE;AAC9C;;ACrEA,MAAM,8BAA2B,IAAI,IAAI;AACzC,MAAM,uCAA0D,IAAI,IAAI;AA8BxE,MAAa,eAAe,EAC1B,YACA,mBACA,UACA,WACA,eACA,gBACA,sBACA,uBACA,oBACA,qBACA,uBACA,qBACA,YACA,aACA,aACA,cACA,YACA,cACA,uBACA,iBACA,aACA,WACA,cAAc,OACd,eAAe,YACJ;CACX,MAAM,EAAE,kBAAkB,qBAAqB,cAAc;CAG7D,MAAM,iBAAiB,eAAe;CAEtC,OACE,qBAAC,OAAD;EACE,WAAW,GACT,6EACA,SACF;EAJF,UAAA;GAME,oBAAC,WAAD;IACE,OAAO;IACP,kBAAkB;IAClB,oBAAoB;IACpB,UAAA;IACA,QAAQ;IACR,WAAU;IACV,kBAAkB,iBAAiB,CAAC;IACpC,SAAS;GACV,CAAA;GAED,oBAAC,gBAAD;IACE,WAAW,cAAc,CAAC,IAAI;IAC9B,MAAK;IACL,UAAU;IACV,WAAW;IACX,YAAY,iBAAiB,GAAG,eAAe;GAChD,CAAA;GAED,oBAAC,WAAD;IACE,OAAO;IACP,kBAAkB,iBAAiB,cAAc;IACjD,oBAAoB,iBAAiB,uBAAuB;IAC5D,UAAU;IACV,QAAQ;IACR,iBAAiB;IACjB,WAAW,GAAG,4CAA4C,eAAe;IACzE,kBAAkB,iBAAiB,CAAC;GACrC,CAAA;GAED,oBAAC,gBAAD;IACE,WAAW,eAAe,CAAC,IAAI;IAC/B,MAAK;IACL,UAAU;IACV,WAAW;IACX,YAAY,iBAAiB,GAAG,gBAAgB;GACjD,CAAA;GAED,oBAAC,WAAD;IACE,OAAO;IACP,kBAAkB;IAClB,oBAAoB;IACpB,UAAA;IACA,QAAQ;IACR,WAAU;IACV,kBAAkB,iBAAiB,CAAC;IACpC,SAAS;GACV,CAAA;EACE;;AAET;;;;;;;;;;AC3FA,MAAa,mBAAmB,EAC9B,OACA,QACA,UACA,cACA,MACA,SACA,WACA,oBAAoB,iBACpB,iBACA,UAAU,SACV,GAAG,kBACQ;CACX,MAAM,QAAQ,gBAAwB;CAEtC,OACE,oBAAC,WAAD;EACS;EACC;EACE;EACI;EACd,WAAU;EACJ;EACG;EACE;EACX,oBAAkB;EAEhB,WAAA,YACA,oBAAC,YAAD;GACE,GAAI;GACK;GACT,WAAW;GAEX,gBAAgB,QAAQ;GACxB,iBAAiB,QAAQ;GACzB,aAAa,QAAQ;GACrB,cAAc,QAAQ;GAEtB,oBAAoB,CAAC;GACrB,OAAO,MAAM,MAAM,SAAS;GAC5B,UAAU,MAAM;GAChB,QAAQ,MAAM;EACf,CAAA;CAEM,CAAA;AAEf"}
@@ -1,4 +1,4 @@
1
- //#region src/utils/findLiteralMatches.ts
1
+ // src/utils/findLiteralMatches.ts
2
2
  /**
3
3
  * Lowercase without changing the string's length, so reported offsets index the caller's text.
4
4
  *
@@ -44,7 +44,6 @@ const findLiteralTermMatches = (text, terms, { isCaseSensitive = false } = {}) =
44
44
  }));
45
45
  });
46
46
  };
47
- //#endregion
48
47
  export { findLiteralMatches, findLiteralTermMatches, hasLiteralMatch };
49
48
 
50
- //# sourceMappingURL=findLiteralMatches-DgGLzyG0.js.map
49
+ //# sourceMappingURL=findLiteralMatches-BaLZTPtx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"findLiteralMatches-DgGLzyG0.js","names":[],"sources":["../src/utils/findLiteralMatches.ts"],"sourcesContent":["/**\n * Lowercase without changing the string's length, so reported offsets index the caller's text.\n *\n * - `İ` (U+0130) is the only code point lowercasing to two code units, so it folds to `I` first.\n */\nconst foldCase = (text: string) => text.replaceAll('İ', 'I').toLowerCase();\n\n// Checked before folding, so scanning a pasted document line by line costs nothing per line.\nconst canContain = (text: string, query: string) => !!query && query.length <= text.length;\n\n// Non-overlapping occurrences, verbatim — callers own the case folding.\nconst scan = (haystack: string, needle: string) => {\n const offsets: number[] = [];\n let at = haystack.indexOf(needle);\n\n while (at !== -1) {\n offsets.push(at);\n at = haystack.indexOf(needle, at + needle.length);\n }\n\n return offsets;\n};\n\n/** Whether `text` holds `query`, ignoring case; stops at the first occurrence. */\nexport const hasLiteralMatch = (text: string, query: string) =>\n canContain(text, query) && foldCase(text).includes(foldCase(query));\n\n/**\n * Start offsets of every occurrence of `query` in `text`, ignoring case unless `isCaseSensitive`.\n *\n * - Literal, not a regex: pasted queries of tens of KB exceed what V8 compiles as a regex.\n * - Non-overlapping; an empty query matches nothing.\n * - Not CodeMirror's `SearchCursor`: it would pull CodeMirror into the root barrel.\n */\nexport const findLiteralMatches = (\n text: string,\n query: string,\n { isCaseSensitive = false }: { isCaseSensitive?: boolean } = {},\n) => {\n if (!canContain(text, query)) return [];\n\n return isCaseSensitive ? scan(text, query) : scan(foldCase(text), foldCase(query));\n};\n\n/**\n * `findLiteralMatches` for many queries over one text, as `{ from, to }` ranges.\n *\n * - Folds `text` once, not once per term.\n * - Ranges arrive in term order; ranges of different terms may overlap.\n */\nexport const findLiteralTermMatches = (\n text: string,\n terms: string[],\n { isCaseSensitive = false }: { isCaseSensitive?: boolean } = {},\n) => {\n const haystack = isCaseSensitive ? text : foldCase(text);\n\n return terms.flatMap((term) => {\n if (!canContain(text, term)) return [];\n\n return scan(haystack, isCaseSensitive ? term : foldCase(term)).map((from) => ({\n from,\n to: from + term.length,\n }));\n });\n};\n"],"mappings":";;;;;;AAKA,MAAM,YAAY,SAAiB,KAAK,WAAW,KAAK,GAAG,CAAC,CAAC,YAAY;AAGzE,MAAM,cAAc,MAAc,UAAkB,CAAC,CAAC,SAAS,MAAM,UAAU,KAAK;AAGpF,MAAM,QAAQ,UAAkB,WAAmB;CACjD,MAAM,UAAoB,CAAC;CAC3B,IAAI,KAAK,SAAS,QAAQ,MAAM;CAEhC,OAAO,OAAO,IAAI;EAChB,QAAQ,KAAK,EAAE;EACf,KAAK,SAAS,QAAQ,QAAQ,KAAK,OAAO,MAAM;CAClD;CAEA,OAAO;AACT;;AAGA,MAAa,mBAAmB,MAAc,UAC5C,WAAW,MAAM,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC;;;;;;;;AASpE,MAAa,sBACX,MACA,OACA,EAAE,kBAAkB,UAAyC,CAAC,MAC3D;CACH,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG,OAAO,CAAC;CAEtC,OAAO,kBAAkB,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,IAAI,GAAG,SAAS,KAAK,CAAC;AACnF;;;;;;;AAQA,MAAa,0BACX,MACA,OACA,EAAE,kBAAkB,UAAyC,CAAC,MAC3D;CACH,MAAM,WAAW,kBAAkB,OAAO,SAAS,IAAI;CAEvD,OAAO,MAAM,SAAS,SAAS;EAC7B,IAAI,CAAC,WAAW,MAAM,IAAI,GAAG,OAAO,CAAC;EAErC,OAAO,KAAK,UAAU,kBAAkB,OAAO,SAAS,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU;GAC5E;GACA,IAAI,OAAO,KAAK;EAClB,EAAE;CACJ,CAAC;AACH"}
1
+ {"version":3,"file":"findLiteralMatches-BaLZTPtx.js","names":[],"sources":["../src/utils/findLiteralMatches.ts"],"sourcesContent":["/**\n * Lowercase without changing the string's length, so reported offsets index the caller's text.\n *\n * - `İ` (U+0130) is the only code point lowercasing to two code units, so it folds to `I` first.\n */\nconst foldCase = (text: string) => text.replaceAll('İ', 'I').toLowerCase();\n\n// Checked before folding, so scanning a pasted document line by line costs nothing per line.\nconst canContain = (text: string, query: string) => !!query && query.length <= text.length;\n\n// Non-overlapping occurrences, verbatim — callers own the case folding.\nconst scan = (haystack: string, needle: string) => {\n const offsets: number[] = [];\n let at = haystack.indexOf(needle);\n\n while (at !== -1) {\n offsets.push(at);\n at = haystack.indexOf(needle, at + needle.length);\n }\n\n return offsets;\n};\n\n/** Whether `text` holds `query`, ignoring case; stops at the first occurrence. */\nexport const hasLiteralMatch = (text: string, query: string) =>\n canContain(text, query) && foldCase(text).includes(foldCase(query));\n\n/**\n * Start offsets of every occurrence of `query` in `text`, ignoring case unless `isCaseSensitive`.\n *\n * - Literal, not a regex: pasted queries of tens of KB exceed what V8 compiles as a regex.\n * - Non-overlapping; an empty query matches nothing.\n * - Not CodeMirror's `SearchCursor`: it would pull CodeMirror into the root barrel.\n */\nexport const findLiteralMatches = (\n text: string,\n query: string,\n { isCaseSensitive = false }: { isCaseSensitive?: boolean } = {},\n) => {\n if (!canContain(text, query)) return [];\n\n return isCaseSensitive ? scan(text, query) : scan(foldCase(text), foldCase(query));\n};\n\n/**\n * `findLiteralMatches` for many queries over one text, as `{ from, to }` ranges.\n *\n * - Folds `text` once, not once per term.\n * - Ranges arrive in term order; ranges of different terms may overlap.\n */\nexport const findLiteralTermMatches = (\n text: string,\n terms: string[],\n { isCaseSensitive = false }: { isCaseSensitive?: boolean } = {},\n) => {\n const haystack = isCaseSensitive ? text : foldCase(text);\n\n return terms.flatMap((term) => {\n if (!canContain(text, term)) return [];\n\n return scan(haystack, isCaseSensitive ? term : foldCase(term)).map((from) => ({\n from,\n to: from + term.length,\n }));\n });\n};\n"],"mappings":";;;;;;AAKA,MAAM,YAAY,SAAiB,KAAK,WAAW,KAAK,GAAG,CAAC,CAAC,YAAY;AAGzE,MAAM,cAAc,MAAc,UAAkB,CAAC,CAAC,SAAS,MAAM,UAAU,KAAK;AAGpF,MAAM,QAAQ,UAAkB,WAAmB;CACjD,MAAM,UAAoB,CAAC;CAC3B,IAAI,KAAK,SAAS,QAAQ,MAAM;CAEhC,OAAO,OAAO,IAAI;EAChB,QAAQ,KAAK,EAAE;EACf,KAAK,SAAS,QAAQ,QAAQ,KAAK,OAAO,MAAM;CAClD;CAEA,OAAO;AACT;;AAGA,MAAa,mBAAmB,MAAc,UAC5C,WAAW,MAAM,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC;;;;;;;;AASpE,MAAa,sBACX,MACA,OACA,EAAE,kBAAkB,UAAyC,CAAC,MAC3D;CACH,IAAI,CAAC,WAAW,MAAM,KAAK,GAAG,OAAO,CAAC;CAEtC,OAAO,kBAAkB,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,IAAI,GAAG,SAAS,KAAK,CAAC;AACnF;;;;;;;AAQA,MAAa,0BACX,MACA,OACA,EAAE,kBAAkB,UAAyC,CAAC,MAC3D;CACH,MAAM,WAAW,kBAAkB,OAAO,SAAS,IAAI;CAEvD,OAAO,MAAM,SAAS,SAAS;EAC7B,IAAI,CAAC,WAAW,MAAM,IAAI,GAAG,OAAO,CAAC;EAErC,OAAO,KAAK,UAAU,kBAAkB,OAAO,SAAS,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU;GAC5E;GACA,IAAI,OAAO,KAAK;EAClB,EAAE;CACJ,CAAC;AACH"}
package/dist/flint.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { ReactNode } from "react";
2
- //#region src/blocks/FlintChart/FlintChart.d.ts
3
2
  type Props = {
4
3
  /** Raw source of a ```flint fence: a flint-chart `ChartAssemblyInput` as JSON. */
5
4
  code: string;
@@ -7,6 +6,5 @@ type Props = {
7
6
  renderActions?: (safeSvg: string) => ReactNode;
8
7
  };
9
8
  declare const FlintChart: ({ code, renderActions }: Props) => import("react").JSX.Element;
10
- //#endregion
11
9
  export { FlintChart };
12
10
  //# sourceMappingURL=flint.d.ts.map
package/dist/flint.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
2
- import { DiagramSource, makeResponsive } from "./svgTransforms-Hnvev3Vs.js";
3
- import { ZoomableSvg } from "./ZoomableSvg-CxXKanUR.js";
4
- import { useThemeAttributes } from "./themeTokens-DCeb62ap.js";
5
- import { SERIES_TOKENS, createVegaColorResolver, tierTwoColour } from "./vegaTokens-DCkvpIVE.js";
6
- import { vegaTheme } from "./vegaTheme-ISwGXvof.js";
7
- import { createSvgCache, diagramCacheKey } from "./svgCache-Dhmbe-7i.js";
2
+ import { DiagramSource, makeResponsive } from "./svgTransforms-BBxxO9T6.js";
3
+ import { ZoomableSvg } from "./ZoomableSvg-BRPGgaWJ.js";
4
+ import { useThemeAttributes } from "./themeTokens-B60cQtAY.js";
5
+ import { SERIES_TOKENS, createVegaColorResolver, tierTwoColour } from "./vegaTokens-DnCcy7JY.js";
6
+ import { vegaTheme } from "./vegaTheme-BcTNRmVS.js";
7
+ import { createSvgCache, diagramCacheKey } from "./svgCache-BzvN_fgr.js";
8
8
  import { useEffect, useState } from "react";
9
9
  import { jsx } from "react/jsx-runtime";
10
- //#region src/blocks/FlintChart/flintTheme.ts
10
+ // src/blocks/FlintChart/flintTheme.ts
11
11
  /**
12
12
  * Put the design system's `--chart-1..5` palette on a Flint input.
13
13
  *
@@ -48,8 +48,7 @@ const withFlintSeriesPalette = (input, scheme, from) => {
48
48
  } }
49
49
  };
50
50
  };
51
- //#endregion
52
- //#region src/blocks/FlintChart/refuseUnsafeSpec.ts
51
+ // src/blocks/FlintChart/refuseUnsafeSpec.ts
53
52
  /**
54
53
  * The boundary in front of the flint renderer: nothing in a spec may fetch or run.
55
54
  *
@@ -131,8 +130,7 @@ const findUnsafeSpecKey = (spec) => {
131
130
  }
132
131
  return null;
133
132
  };
134
- //#endregion
135
- //#region src/blocks/FlintChart/renderFlintSvg.ts
133
+ // src/blocks/FlintChart/renderFlintSvg.ts
136
134
  /**
137
135
  * Compile a Flint `ChartAssemblyInput` to a static SVG string.
138
136
  *
@@ -155,8 +153,7 @@ const renderFlintSvg = async (runtime, input, config) => {
155
153
  view.finalize();
156
154
  }
157
155
  };
158
- //#endregion
159
- //#region src/blocks/FlintChart/FlintChart.tsx
156
+ // src/blocks/FlintChart/FlintChart.tsx
160
157
  let runtimePromise = null;
161
158
  const getFlintRuntime = () => {
162
159
  if (!runtimePromise) runtimePromise = Promise.all([
@@ -249,7 +246,6 @@ const FlintChart = ({ code, renderActions }) => {
249
246
  }, svg);
250
247
  return /* @__PURE__ */ jsx(DiagramSkeleton, {});
251
248
  };
252
- //#endregion
253
249
  export { FlintChart };
254
250
 
255
251
  //# sourceMappingURL=flint.js.map
package/dist/flint.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"flint.js","names":[],"sources":["../src/blocks/FlintChart/flintTheme.ts","../src/blocks/FlintChart/refuseUnsafeSpec.ts","../src/blocks/FlintChart/renderFlintSvg.ts","../src/blocks/FlintChart/FlintChart.tsx"],"sourcesContent":["import type { ChartAssemblyInput } from 'flint-chart';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { createVegaColorResolver, SERIES_TOKENS, tierTwoColour } from '../../vega/vegaTokens';\n\n/**\n * Put the design system's `--chart-1..5` palette on a Flint input.\n *\n * - Flint resolves series colours during assembly, so they ride `theme_spec`, not `vegaTheme`.\n * - An author-supplied `theme_spec` is passed through untouched.\n * - A `null` `theme_spec` is replaced like a missing one — flint throws on it.\n */\nexport const withFlintSeriesPalette = (\n input: ChartAssemblyInput,\n scheme: ResolvedColorScheme,\n from?: Element | null,\n): ChartAssemblyInput => {\n if (input.theme_spec !== undefined && input.theme_spec !== null) return input;\n\n const token = createVegaColorResolver(scheme, from);\n const categorical = SERIES_TOKENS.map((name) => token(name));\n\n return {\n ...input,\n theme_spec: {\n ink: {\n // `endpointsAgainstSurface` below needs to know what the chart sits on.\n surface: { canvas: token('card') },\n // Flint's defaults assume a light canvas, so text and structure come from tokens.\n text: {\n primary: token('foreground'),\n secondary: token('muted-foreground'),\n muted: token('muted-foreground'),\n // Ink on a filled (series-coloured) mark.\n inverse: token('card'),\n },\n structure: {\n axis: token('border'),\n grid: token('border'),\n frame: token('border'),\n rule: token('border'),\n },\n series: {\n categorical,\n // Past five series flint swaps `categorical` for its theme-blind `tableau10`;\n // this keeps 6-10 on our hues (`tierTwoColour`).\n categoricalExtended: [\n ...categorical,\n ...categorical.map((colour) => tierTwoColour(colour, scheme)),\n ],\n // The tail past even the extended set.\n overflow: token('muted-foreground'),\n // For a quantitative `color` field; flint's default starts at black, invisible on dark.\n sequential: {\n stops: [token('accent'), token('chart-1')],\n space: 'lab',\n endpointsAgainstSurface: true,\n },\n },\n },\n },\n };\n};\n","/**\n * The boundary in front of the flint renderer: nothing in a spec may fetch or run.\n *\n * - Checked on the input, before `assembleVegaLite`: compiled Vega carries its own `signals`/`expr`.\n * - Refused on a key's presence, not its value: a relative `data.url` is still a fetch.\n */\n\n/** Keys whose presence anywhere in a spec is refused: each fetches, evaluates or binds a signal. */\nconst REFUSED_KEYS = new Set(['url', 'expr', 'signal', 'signals', 'params']);\n\n/** Suffix of Vega-Lite's other expression properties; matched by shape so new ones are refused. */\nconst EXPRESSION_KEY_SUFFIX = /Expr$/;\n\n/**\n * An own property's value, or `undefined`.\n *\n * - Via a descriptor: inherited keys are ignored and a getter is never called.\n */\nconst ownValue = (node: unknown, key: string): unknown => {\n if (typeof node !== 'object' || node === null) return undefined;\n\n return Object.getOwnPropertyDescriptor(node, key)?.value;\n};\n\n/**\n * The chart's rows (`spec.data.values` only), which the walk does not descend into.\n *\n * - Rows are data vega never evaluates, so a column named `url` must not be refused.\n * - Flint takes one top-level dataset, so every other node is spec.\n * - Skipped by identity, not key name: a `values` key elsewhere must not hide a refused key.\n */\nconst inlineRows = (spec: unknown): unknown[] | null => {\n const values = ownValue(ownValue(spec, 'data'), 'values');\n\n return Array.isArray(values) ? values : null;\n};\n\n/**\n * The top-level maps flint keys by column name, so their keys are data, not spec.\n *\n * - Only the keys are exempt; each value is walked like any other node.\n * - Matched by identity, as in `inlineRows`: a nested object with the same name gets no exemption.\n */\nconst COLUMN_KEYED_MAPS = ['semantic_types', 'field_display_names'];\n\nconst columnKeyedMaps = (spec: unknown): unknown[] =>\n COLUMN_KEYED_MAPS.map((key) => ownValue(spec, key)).filter(\n (map) => typeof map === 'object' && map !== null,\n );\n\n/** Ceiling on the nodes the walk visits; exceeding it refuses, since the spec went unchecked. */\nconst MAX_SPEC_NODES = 10_000;\n\nconst TOO_LARGE = 'is too large to check';\n\n/**\n * Why this spec may not be rendered, or `null` if it may.\n *\n * - The reason goes to the console; the reader sees `DiagramSource`'s fallback.\n * - Iterative, so deep nesting cannot overflow the stack; nodes are charged on push.\n * - An accessor is refused, not skipped: its value cannot be read without running it.\n */\nexport const findUnsafeSpecKey = (spec: unknown): string | null => {\n const rows = inlineRows(spec);\n const columnKeyed = columnKeyedMaps(spec);\n const stack: unknown[] = [spec];\n let visited = 1;\n\n while (stack.length > 0) {\n const node = stack.pop();\n\n if (Array.isArray(node)) {\n visited += node.length;\n if (visited > MAX_SPEC_NODES) return TOO_LARGE;\n stack.push(...node);\n continue;\n }\n\n if (typeof node !== 'object' || node === null) continue;\n\n const keysAreColumnNames = columnKeyed.includes(node);\n\n // Descriptors: skip inherited keys and never call a getter.\n for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(node))) {\n if (!keysAreColumnNames && (REFUSED_KEYS.has(key) || EXPRESSION_KEY_SUFFIX.test(key))) {\n return `carries \\`${key}\\``;\n }\n if (!('value' in descriptor)) return `carries an accessor at \\`${key}\\``;\n\n const { value } = descriptor;\n if (rows !== null && value === rows) continue;\n\n visited += 1;\n if (visited > MAX_SPEC_NODES) return TOO_LARGE;\n stack.push(value);\n }\n }\n\n return null;\n};\n","import type { ChartAssemblyInput } from 'flint-chart';\nimport type { assembleVegaLite } from 'flint-chart/vegalite';\nimport type * as vega from 'vega';\nimport type * as vegaLite from 'vega-lite';\nimport type { Config, TopLevelSpec } from 'vega-lite';\n\nimport { findUnsafeSpecKey } from './refuseUnsafeSpec';\n\n// The lazily imported modules the pipeline needs; a parameter so tests can pass a fake runtime.\nexport type FlintRuntime = {\n assembleVegaLite: typeof assembleVegaLite;\n vega: Pick<typeof vega, 'View' | 'parse'>;\n vegaLite: Pick<typeof vegaLite, 'compile'>;\n};\n\n/**\n * Compile a Flint `ChartAssemblyInput` to a static SVG string.\n *\n * - The one place unsafe input is refused (`refuseUnsafeSpec.ts`), before anything compiles it.\n * - Flint's `_`-prefixed hint keys are not Vega-Lite schema and are stripped before compiling.\n * - `config` rides the compile options; flint's spec-side config sets no colours to conflict.\n * - Renders headless; `toSVG()` is the only output.\n */\nexport const renderFlintSvg = async (\n runtime: FlintRuntime,\n input: ChartAssemblyInput,\n config: Config,\n): Promise<string> => {\n const unsafe = findUnsafeSpecKey(input);\n if (unsafe !== null) {\n throw new Error(`Refusing to render a flint spec that ${unsafe}`);\n }\n\n const assembled: Record<string, unknown> = runtime.assembleVegaLite(input);\n // `assembleVegaLite` is typed loosely upstream; without the hint keys it is a Vega-Lite spec.\n const vlSpec = Object.fromEntries(\n Object.entries(assembled).filter(([key]) => !key.startsWith('_')),\n ) as unknown as TopLevelSpec;\n const { spec } = runtime.vegaLite.compile(vlSpec, { config });\n const view = new runtime.vega.View(runtime.vega.parse(spec), { renderer: 'none' });\n try {\n await view.runAsync();\n return await view.toSVG();\n } finally {\n view.finalize();\n }\n};\n","import { useEffect, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { ChartAssemblyInput } from 'flint-chart';\n\nimport { useThemeAttributes } from '../../components/ThemeProvider/useThemeAttributes';\nimport { ZoomableSvg } from '../../components/ZoomableSvg';\nimport { vegaTheme } from '../../vega/vegaTheme';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\nimport { createSvgCache, diagramCacheKey } from '../DiagramShared/svgCache';\nimport { makeResponsive } from '../DiagramShared/svgTransforms';\n\nimport { withFlintSeriesPalette } from './flintTheme';\nimport type { FlintRuntime } from './renderFlintSvg';\nimport { renderFlintSvg } from './renderFlintSvg';\n\nlet runtimePromise: Promise<FlintRuntime> | null = null;\n\n// Memoized chart-stack import, reset on failure so a chunk-load error can retry.\n// Mirrors `getMermaid()` in `MermaidDiagram`.\nconst getFlintRuntime = (): Promise<FlintRuntime> => {\n if (!runtimePromise) {\n runtimePromise = Promise.all([\n import('flint-chart/vegalite'),\n import('vega'),\n import('vega-lite'),\n ])\n .then(([flint, vega, vegaLite]) => ({\n assembleVegaLite: flint.assembleVegaLite,\n vega,\n vegaLite,\n }))\n .catch((err) => {\n runtimePromise = null;\n throw err;\n });\n }\n return runtimePromise;\n};\n\nconst RENDER_DEBOUNCE_MS = 300;\n\n// A streaming fence is unparseable just like a broken one, so unparseable source\n// keeps the skeleton until it has been unchanged this long, then shows as raw source.\nconst PARSE_GRACE_MS = 1500;\n\n// Parse, compile and layout are synchronous, so a larger source would freeze the chat.\n// Far above the prompt's ~50-row inline data cap.\nconst MAX_SOURCE_CHARS = 200_000;\n\n// Values are already `makeResponsive`d, so ZoomableSvg's sanitize memo stays stable.\nconst svgCache = createSvgCache();\n\n// The theme half of a cache key — tells a still-streaming spec from a theme switch.\nconst prevThemeKeyOf = (key: string): string => key.slice(0, key.indexOf('\\n'));\n\ntype Props = {\n /** Raw source of a ```flint fence: a flint-chart `ChartAssemblyInput` as JSON. */\n code: string;\n /** Extra toolbar controls (e.g. `ExportMenu`) for `ZoomableSvg`; receives the sanitized SVG. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const FlintChart = ({ code, renderActions }: Props) => {\n // - Re-renders on a scheme or brand change, same contract as MermaidDiagram.\n // - `scope` is the element tokens are read off (`null` = `<html>`); it is part of `themeKey`.\n const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();\n const cacheKey = diagramCacheKey(code, themeKey);\n\n const [svg, setSvg] = useState<string | null>(() => svgCache.get(cacheKey) ?? null);\n const [renderFailed, setRenderFailed] = useState(false);\n\n // Reset stale state synchronously on a code or theme change (no one-frame flash):\n // 1. A cache hit is applied at once.\n // 2. Same theme, source only grew (still streaming): keep the last chart, no flicker.\n // 3. Anything else clears — colours are baked in, so a stale chart is wrong.\n const [prevKey, setPrevKey] = useState(cacheKey);\n const [prevCode, setPrevCode] = useState(code);\n if (cacheKey !== prevKey) {\n const cached = svgCache.get(cacheKey);\n const sameThemeStillStreaming =\n themeKey === prevThemeKeyOf(prevKey) && code.startsWith(prevCode);\n setPrevKey(cacheKey);\n setPrevCode(code);\n if (cached) setSvg(cached);\n else if (!sameThemeStillStreaming) setSvg(null);\n setRenderFailed(false);\n }\n\n useEffect(() => {\n if (svgCache.has(cacheKey)) return;\n\n let cancelled = false;\n let graceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const debounceTimer = setTimeout(() => {\n if (code.length > MAX_SOURCE_CHARS) {\n // Never becomes renderable, so skip the grace period.\n console.error(\n `[FlintChart] source exceeds ${MAX_SOURCE_CHARS} characters (${code.length}); not rendering`,\n );\n setSvg(null);\n setRenderFailed(true);\n return;\n }\n\n let input: ChartAssemblyInput;\n try {\n input = JSON.parse(code);\n } catch (err) {\n // Likely still streaming — fail only if unchanged when the grace period ends.\n graceTimer = setTimeout(() => {\n console.debug('[FlintChart] source never became parseable JSON:', err);\n setSvg(null);\n setRenderFailed(true);\n }, PARSE_GRACE_MS - RENDER_DEBOUNCE_MS);\n return;\n }\n\n getFlintRuntime()\n .then(async (runtime) => {\n if (cancelled) return;\n // `scheme` comes from the same read as the cache key, so palette and key agree.\n const svgOutput = makeResponsive(\n await renderFlintSvg(\n runtime,\n withFlintSeriesPalette(input, scheme, scope),\n vegaTheme(scheme, scope),\n ),\n );\n if (cancelled) return;\n svgCache.set(cacheKey, svgOutput);\n setSvg(svgOutput);\n setRenderFailed(false);\n })\n .catch((err) => {\n if (cancelled) return;\n console.error('[FlintChart] render failed:', err);\n setSvg(null);\n setRenderFailed(true);\n });\n }, RENDER_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(debounceTimer);\n if (graceTimer) clearTimeout(graceTimer);\n };\n }, [cacheKey, code, scheme, scope]);\n\n if (renderFailed) {\n return <DiagramSource code={code} />;\n }\n\n if (svg) {\n return (\n <ZoomableSvg\n // Keyed by SVG, not `code`: a streaming chart is held, and a remount per chunk\n // would drop zoom/pan.\n key={svg}\n html={svg}\n copyText={`\\`\\`\\`flint\\n${code}\\n\\`\\`\\``}\n className=\"tw:my-3\"\n renderActions={renderActions}\n />\n );\n }\n\n return <DiagramSkeleton />;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"flint.js","names":[],"sources":["../src/blocks/FlintChart/flintTheme.ts","../src/blocks/FlintChart/refuseUnsafeSpec.ts","../src/blocks/FlintChart/renderFlintSvg.ts","../src/blocks/FlintChart/FlintChart.tsx"],"sourcesContent":["import type { ChartAssemblyInput } from 'flint-chart';\n\nimport type { ResolvedColorScheme } from '../../components/ThemeProvider/types';\nimport { createVegaColorResolver, SERIES_TOKENS, tierTwoColour } from '../../vega/vegaTokens';\n\n/**\n * Put the design system's `--chart-1..5` palette on a Flint input.\n *\n * - Flint resolves series colours during assembly, so they ride `theme_spec`, not `vegaTheme`.\n * - An author-supplied `theme_spec` is passed through untouched.\n * - A `null` `theme_spec` is replaced like a missing one — flint throws on it.\n */\nexport const withFlintSeriesPalette = (\n input: ChartAssemblyInput,\n scheme: ResolvedColorScheme,\n from?: Element | null,\n): ChartAssemblyInput => {\n if (input.theme_spec !== undefined && input.theme_spec !== null) return input;\n\n const token = createVegaColorResolver(scheme, from);\n const categorical = SERIES_TOKENS.map((name) => token(name));\n\n return {\n ...input,\n theme_spec: {\n ink: {\n // `endpointsAgainstSurface` below needs to know what the chart sits on.\n surface: { canvas: token('card') },\n // Flint's defaults assume a light canvas, so text and structure come from tokens.\n text: {\n primary: token('foreground'),\n secondary: token('muted-foreground'),\n muted: token('muted-foreground'),\n // Ink on a filled (series-coloured) mark.\n inverse: token('card'),\n },\n structure: {\n axis: token('border'),\n grid: token('border'),\n frame: token('border'),\n rule: token('border'),\n },\n series: {\n categorical,\n // Past five series flint swaps `categorical` for its theme-blind `tableau10`;\n // this keeps 6-10 on our hues (`tierTwoColour`).\n categoricalExtended: [\n ...categorical,\n ...categorical.map((colour) => tierTwoColour(colour, scheme)),\n ],\n // The tail past even the extended set.\n overflow: token('muted-foreground'),\n // For a quantitative `color` field; flint's default starts at black, invisible on dark.\n sequential: {\n stops: [token('accent'), token('chart-1')],\n space: 'lab',\n endpointsAgainstSurface: true,\n },\n },\n },\n },\n };\n};\n","/**\n * The boundary in front of the flint renderer: nothing in a spec may fetch or run.\n *\n * - Checked on the input, before `assembleVegaLite`: compiled Vega carries its own `signals`/`expr`.\n * - Refused on a key's presence, not its value: a relative `data.url` is still a fetch.\n */\n\n/** Keys whose presence anywhere in a spec is refused: each fetches, evaluates or binds a signal. */\nconst REFUSED_KEYS = new Set(['url', 'expr', 'signal', 'signals', 'params']);\n\n/** Suffix of Vega-Lite's other expression properties; matched by shape so new ones are refused. */\nconst EXPRESSION_KEY_SUFFIX = /Expr$/;\n\n/**\n * An own property's value, or `undefined`.\n *\n * - Via a descriptor: inherited keys are ignored and a getter is never called.\n */\nconst ownValue = (node: unknown, key: string): unknown => {\n if (typeof node !== 'object' || node === null) return undefined;\n\n return Object.getOwnPropertyDescriptor(node, key)?.value;\n};\n\n/**\n * The chart's rows (`spec.data.values` only), which the walk does not descend into.\n *\n * - Rows are data vega never evaluates, so a column named `url` must not be refused.\n * - Flint takes one top-level dataset, so every other node is spec.\n * - Skipped by identity, not key name: a `values` key elsewhere must not hide a refused key.\n */\nconst inlineRows = (spec: unknown): unknown[] | null => {\n const values = ownValue(ownValue(spec, 'data'), 'values');\n\n return Array.isArray(values) ? values : null;\n};\n\n/**\n * The top-level maps flint keys by column name, so their keys are data, not spec.\n *\n * - Only the keys are exempt; each value is walked like any other node.\n * - Matched by identity, as in `inlineRows`: a nested object with the same name gets no exemption.\n */\nconst COLUMN_KEYED_MAPS = ['semantic_types', 'field_display_names'];\n\nconst columnKeyedMaps = (spec: unknown): unknown[] =>\n COLUMN_KEYED_MAPS.map((key) => ownValue(spec, key)).filter(\n (map) => typeof map === 'object' && map !== null,\n );\n\n/** Ceiling on the nodes the walk visits; exceeding it refuses, since the spec went unchecked. */\nconst MAX_SPEC_NODES = 10_000;\n\nconst TOO_LARGE = 'is too large to check';\n\n/**\n * Why this spec may not be rendered, or `null` if it may.\n *\n * - The reason goes to the console; the reader sees `DiagramSource`'s fallback.\n * - Iterative, so deep nesting cannot overflow the stack; nodes are charged on push.\n * - An accessor is refused, not skipped: its value cannot be read without running it.\n */\nexport const findUnsafeSpecKey = (spec: unknown): string | null => {\n const rows = inlineRows(spec);\n const columnKeyed = columnKeyedMaps(spec);\n const stack: unknown[] = [spec];\n let visited = 1;\n\n while (stack.length > 0) {\n const node = stack.pop();\n\n if (Array.isArray(node)) {\n visited += node.length;\n if (visited > MAX_SPEC_NODES) return TOO_LARGE;\n stack.push(...node);\n continue;\n }\n\n if (typeof node !== 'object' || node === null) continue;\n\n const keysAreColumnNames = columnKeyed.includes(node);\n\n // Descriptors: skip inherited keys and never call a getter.\n for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(node))) {\n if (!keysAreColumnNames && (REFUSED_KEYS.has(key) || EXPRESSION_KEY_SUFFIX.test(key))) {\n return `carries \\`${key}\\``;\n }\n if (!('value' in descriptor)) return `carries an accessor at \\`${key}\\``;\n\n const { value } = descriptor;\n if (rows !== null && value === rows) continue;\n\n visited += 1;\n if (visited > MAX_SPEC_NODES) return TOO_LARGE;\n stack.push(value);\n }\n }\n\n return null;\n};\n","import type { ChartAssemblyInput } from 'flint-chart';\nimport type { assembleVegaLite } from 'flint-chart/vegalite';\nimport type * as vega from 'vega';\nimport type * as vegaLite from 'vega-lite';\nimport type { Config, TopLevelSpec } from 'vega-lite';\n\nimport { findUnsafeSpecKey } from './refuseUnsafeSpec';\n\n// The lazily imported modules the pipeline needs; a parameter so tests can pass a fake runtime.\nexport type FlintRuntime = {\n assembleVegaLite: typeof assembleVegaLite;\n vega: Pick<typeof vega, 'View' | 'parse'>;\n vegaLite: Pick<typeof vegaLite, 'compile'>;\n};\n\n/**\n * Compile a Flint `ChartAssemblyInput` to a static SVG string.\n *\n * - The one place unsafe input is refused (`refuseUnsafeSpec.ts`), before anything compiles it.\n * - Flint's `_`-prefixed hint keys are not Vega-Lite schema and are stripped before compiling.\n * - `config` rides the compile options; flint's spec-side config sets no colours to conflict.\n * - Renders headless; `toSVG()` is the only output.\n */\nexport const renderFlintSvg = async (\n runtime: FlintRuntime,\n input: ChartAssemblyInput,\n config: Config,\n): Promise<string> => {\n const unsafe = findUnsafeSpecKey(input);\n if (unsafe !== null) {\n throw new Error(`Refusing to render a flint spec that ${unsafe}`);\n }\n\n const assembled: Record<string, unknown> = runtime.assembleVegaLite(input);\n // `assembleVegaLite` is typed loosely upstream; without the hint keys it is a Vega-Lite spec.\n const vlSpec = Object.fromEntries(\n Object.entries(assembled).filter(([key]) => !key.startsWith('_')),\n ) as unknown as TopLevelSpec;\n const { spec } = runtime.vegaLite.compile(vlSpec, { config });\n const view = new runtime.vega.View(runtime.vega.parse(spec), { renderer: 'none' });\n try {\n await view.runAsync();\n return await view.toSVG();\n } finally {\n view.finalize();\n }\n};\n","import { useEffect, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { ChartAssemblyInput } from 'flint-chart';\n\nimport { useThemeAttributes } from '../../components/ThemeProvider/useThemeAttributes';\nimport { ZoomableSvg } from '../../components/ZoomableSvg';\nimport { vegaTheme } from '../../vega/vegaTheme';\nimport { DiagramSkeleton } from '../DiagramShared/DiagramSkeleton';\nimport { DiagramSource } from '../DiagramShared/DiagramSource';\nimport { createSvgCache, diagramCacheKey } from '../DiagramShared/svgCache';\nimport { makeResponsive } from '../DiagramShared/svgTransforms';\n\nimport { withFlintSeriesPalette } from './flintTheme';\nimport type { FlintRuntime } from './renderFlintSvg';\nimport { renderFlintSvg } from './renderFlintSvg';\n\nlet runtimePromise: Promise<FlintRuntime> | null = null;\n\n// Memoized chart-stack import, reset on failure so a chunk-load error can retry.\n// Mirrors `getMermaid()` in `MermaidDiagram`.\nconst getFlintRuntime = (): Promise<FlintRuntime> => {\n if (!runtimePromise) {\n runtimePromise = Promise.all([\n import('flint-chart/vegalite'),\n import('vega'),\n import('vega-lite'),\n ])\n .then(([flint, vega, vegaLite]) => ({\n assembleVegaLite: flint.assembleVegaLite,\n vega,\n vegaLite,\n }))\n .catch((err) => {\n runtimePromise = null;\n throw err;\n });\n }\n return runtimePromise;\n};\n\nconst RENDER_DEBOUNCE_MS = 300;\n\n// A streaming fence is unparseable just like a broken one, so unparseable source\n// keeps the skeleton until it has been unchanged this long, then shows as raw source.\nconst PARSE_GRACE_MS = 1500;\n\n// Parse, compile and layout are synchronous, so a larger source would freeze the chat.\n// Far above the prompt's ~50-row inline data cap.\nconst MAX_SOURCE_CHARS = 200_000;\n\n// Values are already `makeResponsive`d, so ZoomableSvg's sanitize memo stays stable.\nconst svgCache = createSvgCache();\n\n// The theme half of a cache key — tells a still-streaming spec from a theme switch.\nconst prevThemeKeyOf = (key: string): string => key.slice(0, key.indexOf('\\n'));\n\ntype Props = {\n /** Raw source of a ```flint fence: a flint-chart `ChartAssemblyInput` as JSON. */\n code: string;\n /** Extra toolbar controls (e.g. `ExportMenu`) for `ZoomableSvg`; receives the sanitized SVG. */\n renderActions?: (safeSvg: string) => ReactNode;\n};\n\nexport const FlintChart = ({ code, renderActions }: Props) => {\n // - Re-renders on a scheme or brand change, same contract as MermaidDiagram.\n // - `scope` is the element tokens are read off (`null` = `<html>`); it is part of `themeKey`.\n const { scheme, cacheKey: themeKey, scope } = useThemeAttributes();\n const cacheKey = diagramCacheKey(code, themeKey);\n\n const [svg, setSvg] = useState<string | null>(() => svgCache.get(cacheKey) ?? null);\n const [renderFailed, setRenderFailed] = useState(false);\n\n // Reset stale state synchronously on a code or theme change (no one-frame flash):\n // 1. A cache hit is applied at once.\n // 2. Same theme, source only grew (still streaming): keep the last chart, no flicker.\n // 3. Anything else clears — colours are baked in, so a stale chart is wrong.\n const [prevKey, setPrevKey] = useState(cacheKey);\n const [prevCode, setPrevCode] = useState(code);\n if (cacheKey !== prevKey) {\n const cached = svgCache.get(cacheKey);\n const sameThemeStillStreaming =\n themeKey === prevThemeKeyOf(prevKey) && code.startsWith(prevCode);\n setPrevKey(cacheKey);\n setPrevCode(code);\n if (cached) setSvg(cached);\n else if (!sameThemeStillStreaming) setSvg(null);\n setRenderFailed(false);\n }\n\n useEffect(() => {\n if (svgCache.has(cacheKey)) return;\n\n let cancelled = false;\n let graceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const debounceTimer = setTimeout(() => {\n if (code.length > MAX_SOURCE_CHARS) {\n // Never becomes renderable, so skip the grace period.\n console.error(\n `[FlintChart] source exceeds ${MAX_SOURCE_CHARS} characters (${code.length}); not rendering`,\n );\n setSvg(null);\n setRenderFailed(true);\n return;\n }\n\n let input: ChartAssemblyInput;\n try {\n input = JSON.parse(code);\n } catch (err) {\n // Likely still streaming — fail only if unchanged when the grace period ends.\n graceTimer = setTimeout(() => {\n console.debug('[FlintChart] source never became parseable JSON:', err);\n setSvg(null);\n setRenderFailed(true);\n }, PARSE_GRACE_MS - RENDER_DEBOUNCE_MS);\n return;\n }\n\n getFlintRuntime()\n .then(async (runtime) => {\n if (cancelled) return;\n // `scheme` comes from the same read as the cache key, so palette and key agree.\n const svgOutput = makeResponsive(\n await renderFlintSvg(\n runtime,\n withFlintSeriesPalette(input, scheme, scope),\n vegaTheme(scheme, scope),\n ),\n );\n if (cancelled) return;\n svgCache.set(cacheKey, svgOutput);\n setSvg(svgOutput);\n setRenderFailed(false);\n })\n .catch((err) => {\n if (cancelled) return;\n console.error('[FlintChart] render failed:', err);\n setSvg(null);\n setRenderFailed(true);\n });\n }, RENDER_DEBOUNCE_MS);\n\n return () => {\n cancelled = true;\n clearTimeout(debounceTimer);\n if (graceTimer) clearTimeout(graceTimer);\n };\n }, [cacheKey, code, scheme, scope]);\n\n if (renderFailed) {\n return <DiagramSource code={code} />;\n }\n\n if (svg) {\n return (\n <ZoomableSvg\n // Keyed by SVG, not `code`: a streaming chart is held, and a remount per chunk\n // would drop zoom/pan.\n key={svg}\n html={svg}\n copyText={`\\`\\`\\`flint\\n${code}\\n\\`\\`\\``}\n className=\"tw:my-3\"\n renderActions={renderActions}\n />\n );\n }\n\n return <DiagramSkeleton />;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAYA,MAAa,0BACX,OACA,QACA,SACuB;CACvB,IAAI,MAAM,eAAe,KAAA,KAAa,MAAM,eAAe,MAAM,OAAO;CAExE,MAAM,QAAQ,wBAAwB,QAAQ,IAAI;CAClD,MAAM,cAAc,cAAc,KAAK,SAAS,MAAM,IAAI,CAAC;CAE3D,OAAO;EACL,GAAG;EACH,YAAY,EACV,KAAK;GAEH,SAAS,EAAE,QAAQ,MAAM,MAAM,EAAE;GAEjC,MAAM;IACJ,SAAS,MAAM,YAAY;IAC3B,WAAW,MAAM,kBAAkB;IACnC,OAAO,MAAM,kBAAkB;IAE/B,SAAS,MAAM,MAAM;GACvB;GACA,WAAW;IACT,MAAM,MAAM,QAAQ;IACpB,MAAM,MAAM,QAAQ;IACpB,OAAO,MAAM,QAAQ;IACrB,MAAM,MAAM,QAAQ;GACtB;GACA,QAAQ;IACN;IAGA,qBAAqB,CACnB,GAAG,aACH,GAAG,YAAY,KAAK,WAAW,cAAc,QAAQ,MAAM,CAAC,CAC9D;IAEA,UAAU,MAAM,kBAAkB;IAElC,YAAY;KACV,OAAO,CAAC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC;KACzC,OAAO;KACP,yBAAyB;IAC3B;GACF;EACF,EACF;CACF;AACF;;;;;;;;;ACtDA,MAAM,+BAAe,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU;CAAW;AAAQ,CAAC;;AAG3E,MAAM,wBAAwB;;;;;;AAO9B,MAAM,YAAY,MAAe,QAAyB;CACxD,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO,KAAA;CAEtD,OAAO,OAAO,yBAAyB,MAAM,GAAG,CAAC,EAAE;AACrD;;;;;;;;AASA,MAAM,cAAc,SAAoC;CACtD,MAAM,SAAS,SAAS,SAAS,MAAM,MAAM,GAAG,QAAQ;CAExD,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS;AAC1C;;;;;;;AAQA,MAAM,oBAAoB,CAAC,kBAAkB,qBAAqB;AAElE,MAAM,mBAAmB,SACvB,kBAAkB,KAAK,QAAQ,SAAS,MAAM,GAAG,CAAC,CAAC,CAAC,QACjD,QAAQ,OAAO,QAAQ,YAAY,QAAQ,IAC9C;;AAGF,MAAM,iBAAiB;AAEvB,MAAM,YAAY;;;;;;;;AASlB,MAAa,qBAAqB,SAAiC;CACjE,MAAM,OAAO,WAAW,IAAI;CAC5B,MAAM,cAAc,gBAAgB,IAAI;CACxC,MAAM,QAAmB,CAAC,IAAI;CAC9B,IAAI,UAAU;CAEd,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,OAAO,MAAM,IAAI;EAEvB,IAAI,MAAM,QAAQ,IAAI,GAAG;GACvB,WAAW,KAAK;GAChB,IAAI,UAAU,gBAAgB,OAAO;GACrC,MAAM,KAAK,GAAG,IAAI;GAClB;EACF;EAEA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAE/C,MAAM,qBAAqB,YAAY,SAAS,IAAI;EAGpD,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,OAAO,0BAA0B,IAAI,CAAC,GAAG;GACtF,IAAI,CAAC,uBAAuB,aAAa,IAAI,GAAG,KAAK,sBAAsB,KAAK,GAAG,IACjF,OAAO,aAAa,IAAI;GAE1B,IAAI,EAAE,WAAW,aAAa,OAAO,4BAA4B,IAAI;GAErE,MAAM,EAAE,UAAU;GAClB,IAAI,SAAS,QAAQ,UAAU,MAAM;GAErC,WAAW;GACX,IAAI,UAAU,gBAAgB,OAAO;GACrC,MAAM,KAAK,KAAK;EAClB;CACF;CAEA,OAAO;AACT;;;;;;;;;;AC5EA,MAAa,iBAAiB,OAC5B,SACA,OACA,WACoB;CACpB,MAAM,SAAS,kBAAkB,KAAK;CACtC,IAAI,WAAW,MACb,MAAM,IAAI,MAAM,wCAAwC,QAAQ;CAGlE,MAAM,YAAqC,QAAQ,iBAAiB,KAAK;CAEzE,MAAM,SAAS,OAAO,YACpB,OAAO,QAAQ,SAAS,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,WAAW,GAAG,CAAC,CAClE;CACA,MAAM,EAAE,SAAS,QAAQ,SAAS,QAAQ,QAAQ,EAAE,OAAO,CAAC;CAC5D,MAAM,OAAO,IAAI,QAAQ,KAAK,KAAK,QAAQ,KAAK,MAAM,IAAI,GAAG,EAAE,UAAU,OAAO,CAAC;CACjF,IAAI;EACF,MAAM,KAAK,SAAS;EACpB,OAAO,MAAM,KAAK,MAAM;CAC1B,UAAU;EACR,KAAK,SAAS;CAChB;AACF;;AC9BA,IAAI,iBAA+C;AAInD,MAAM,wBAA+C;CACnD,IAAI,CAAC,gBACH,iBAAiB,QAAQ,IAAI;EAC3B,OAAO;EACP,OAAO;EACP,OAAO;CACT,CAAC,CAAC,CACC,MAAM,CAAC,OAAO,MAAM,eAAe;EAClC,kBAAkB,MAAM;EACxB;EACA;CACF,EAAE,CAAC,CACF,OAAO,QAAQ;EACd,iBAAiB;EACjB,MAAM;CACR,CAAC;CAEL,OAAO;AACT;AAEA,MAAM,qBAAqB;AAQ3B,MAAM,mBAAmB;AAGzB,MAAM,WAAW,eAAe;AAGhC,MAAM,kBAAkB,QAAwB,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,CAAC;AAS9E,MAAa,cAAc,EAAE,MAAM,oBAA2B;CAG5D,MAAM,EAAE,QAAQ,UAAU,UAAU,UAAU,mBAAmB;CACjE,MAAM,WAAW,gBAAgB,MAAM,QAAQ;CAE/C,MAAM,CAAC,KAAK,UAAU,eAA8B,SAAS,IAAI,QAAQ,KAAK,IAAI;CAClF,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CAMtD,MAAM,CAAC,SAAS,cAAc,SAAS,QAAQ;CAC/C,MAAM,CAAC,UAAU,eAAe,SAAS,IAAI;CAC7C,IAAI,aAAa,SAAS;EACxB,MAAM,SAAS,SAAS,IAAI,QAAQ;EACpC,MAAM,0BACJ,aAAa,eAAe,OAAO,KAAK,KAAK,WAAW,QAAQ;EAClE,WAAW,QAAQ;EACnB,YAAY,IAAI;EAChB,IAAI,QAAQ,OAAO,MAAM;OACpB,IAAI,CAAC,yBAAyB,OAAO,IAAI;EAC9C,gBAAgB,KAAK;CACvB;CAEA,gBAAgB;EACd,IAAI,SAAS,IAAI,QAAQ,GAAG;EAE5B,IAAI,YAAY;EAChB,IAAI;EAEJ,MAAM,gBAAgB,iBAAiB;GACrC,IAAI,KAAK,SAAS,kBAAkB;IAElC,QAAQ,MACN,+BAA+B,iBAAiB,eAAe,KAAK,OAAO,iBAC7E;IACA,OAAO,IAAI;IACX,gBAAgB,IAAI;IACpB;GACF;GAEA,IAAI;GACJ,IAAI;IACF,QAAQ,KAAK,MAAM,IAAI;GACzB,SAAS,KAAK;IAEZ,aAAa,iBAAiB;KAC5B,QAAQ,MAAM,oDAAoD,GAAG;KACrE,OAAO,IAAI;KACX,gBAAgB,IAAI;IACtB,GAAG,IAAmC;IACtC;GACF;GAEA,gBAAgB,CAAC,CACd,KAAK,OAAO,YAAY;IACvB,IAAI,WAAW;IAEf,MAAM,YAAY,eAChB,MAAM,eACJ,SACA,uBAAuB,OAAO,QAAQ,KAAK,GAC3C,UAAU,QAAQ,KAAK,CACzB,CACF;IACA,IAAI,WAAW;IACf,SAAS,IAAI,UAAU,SAAS;IAChC,OAAO,SAAS;IAChB,gBAAgB,KAAK;GACvB,CAAC,CAAC,CACD,OAAO,QAAQ;IACd,IAAI,WAAW;IACf,QAAQ,MAAM,+BAA+B,GAAG;IAChD,OAAO,IAAI;IACX,gBAAgB,IAAI;GACtB,CAAC;EACL,GAAG,kBAAkB;EAErB,aAAa;GACX,YAAY;GACZ,aAAa,aAAa;GAC1B,IAAI,YAAY,aAAa,UAAU;EACzC;CACF,GAAG;EAAC;EAAU;EAAM;EAAQ;CAAK,CAAC;CAElC,IAAI,cACF,OAAO,oBAAC,eAAD,EAAqB,KAAO,CAAA;CAGrC,IAAI,KACF,OACE,oBAAC,aAAD;EAIE,MAAM;EACN,UAAU,gBAAgB,KAAK;EAC/B,WAAU;EACK;CAChB,GALM,GAKN;CAIL,OAAO,oBAAC,iBAAD,CAAkB,CAAA;AAC3B"}
@@ -6,7 +6,7 @@ import { StreamLanguage } from "@codemirror/language";
6
6
  import { shell } from "@codemirror/legacy-modes/mode/shell";
7
7
  import { highlightCode as highlightCode$1, tagHighlighter, tags } from "@lezer/highlight";
8
8
  import { yaml } from "@codemirror/legacy-modes/mode/yaml";
9
- //#region src/blocks/AIKit/highlightCode.ts
9
+ // src/blocks/AIKit/highlightCode.ts
10
10
  const GRAMMARS = {
11
11
  sql: StandardSQL.language,
12
12
  python: pythonLanguage,
@@ -75,7 +75,6 @@ const highlightCode = (code, grammar) => {
75
75
  }));
76
76
  return tokens;
77
77
  };
78
- //#endregion
79
78
  export { highlightCode };
80
79
 
81
- //# sourceMappingURL=highlightCode-D354tCXO.js.map
80
+ //# sourceMappingURL=highlightCode-2spZP7ZA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"highlightCode-D354tCXO.js","names":[],"sources":["../src/blocks/AIKit/highlightCode.ts"],"sourcesContent":["import {\n javascriptLanguage,\n jsxLanguage,\n tsxLanguage,\n typescriptLanguage,\n} from '@codemirror/lang-javascript';\nimport { jsonLanguage } from '@codemirror/lang-json';\nimport { pythonLanguage } from '@codemirror/lang-python';\nimport { StandardSQL } from '@codemirror/lang-sql';\nimport type { Language } from '@codemirror/language';\nimport { StreamLanguage } from '@codemirror/language';\nimport { shell } from '@codemirror/legacy-modes/mode/shell';\nimport { yaml } from '@codemirror/legacy-modes/mode/yaml';\nimport { highlightCode as walkHighlights, tagHighlighter, tags } from '@lezer/highlight';\n\nimport type { Highlighter, HighlightToken } from './highlightChunk';\nimport type { HighlightGrammar } from './highlightLanguages';\n\nconst GRAMMARS: Record<HighlightGrammar, Language> = {\n sql: StandardSQL.language,\n python: pythonLanguage,\n javascript: javascriptLanguage,\n jsx: jsxLanguage,\n typescript: typescriptLanguage,\n tsx: tsxLanguage,\n json: jsonLanguage,\n shell: StreamLanguage.define(shell),\n yaml: StreamLanguage.define(yaml),\n};\n\n/**\n * Syntax tag → token classes.\n *\n * - Semantic tokens only, so a brand recolours code with the rest of the answer.\n * - A sub-tag (`controlKeyword`) falls back to its parent's rule.\n */\nconst highlighter = tagHighlighter([\n { tag: [tags.keyword, tags.operatorKeyword, tags.modifier], class: 'tw:text-primary' },\n { tag: [tags.string, tags.special(tags.string), tags.regexp], class: 'tw:text-success' },\n { tag: tags.comment, class: 'tw:text-muted-foreground tw:italic' },\n { tag: [tags.number, tags.bool, tags.null, tags.atom], class: 'tw:text-info' },\n {\n tag: [tags.function(tags.variableName), tags.function(tags.propertyName)],\n class: 'tw:font-semibold',\n },\n { tag: [tags.typeName, tags.className], class: 'tw:text-info' },\n]);\n\n/** Splits `code` into runs, each with the classes its syntax earns; line breaks are `\\n` runs. */\nexport const highlightCode: Highlighter = (code, grammar) => {\n const tokens: HighlightToken[] = [];\n walkHighlights(\n code,\n GRAMMARS[grammar].parser.parse(code),\n highlighter,\n (text, className) => tokens.push({ text, className }),\n () => tokens.push({ text: '\\n', className: '' }),\n );\n return tokens;\n};\n"],"mappings":";;;;;;;;;AAkBA,MAAM,WAA+C;CACnD,KAAK,YAAY;CACjB,QAAQ;CACR,YAAY;CACZ,KAAK;CACL,YAAY;CACZ,KAAK;CACL,MAAM;CACN,OAAO,eAAe,OAAO,KAAK;CAClC,MAAM,eAAe,OAAO,IAAI;AAClC;;;;;;;AAQA,MAAM,cAAc,eAAe;CACjC;EAAE,KAAK;GAAC,KAAK;GAAS,KAAK;GAAiB,KAAK;EAAQ;EAAG,OAAO;CAAkB;CACrF;EAAE,KAAK;GAAC,KAAK;GAAQ,KAAK,QAAQ,KAAK,MAAM;GAAG,KAAK;EAAM;EAAG,OAAO;CAAkB;CACvF;EAAE,KAAK,KAAK;EAAS,OAAO;CAAqC;CACjE;EAAE,KAAK;GAAC,KAAK;GAAQ,KAAK;GAAM,KAAK;GAAM,KAAK;EAAI;EAAG,OAAO;CAAe;CAC7E;EACE,KAAK,CAAC,KAAK,SAAS,KAAK,YAAY,GAAG,KAAK,SAAS,KAAK,YAAY,CAAC;EACxE,OAAO;CACT;CACA;EAAE,KAAK,CAAC,KAAK,UAAU,KAAK,SAAS;EAAG,OAAO;CAAe;AAChE,CAAC;;AAGD,MAAa,iBAA8B,MAAM,YAAY;CAC3D,MAAM,SAA2B,CAAC;CAClC,gBACE,MACA,SAAS,QAAQ,CAAC,OAAO,MAAM,IAAI,GACnC,cACC,MAAM,cAAc,OAAO,KAAK;EAAE;EAAM;CAAU,CAAC,SAC9C,OAAO,KAAK;EAAE,MAAM;EAAM,WAAW;CAAG,CAAC,CACjD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"highlightCode-2spZP7ZA.js","names":[],"sources":["../src/blocks/AIKit/highlightCode.ts"],"sourcesContent":["import {\n javascriptLanguage,\n jsxLanguage,\n tsxLanguage,\n typescriptLanguage,\n} from '@codemirror/lang-javascript';\nimport { jsonLanguage } from '@codemirror/lang-json';\nimport { pythonLanguage } from '@codemirror/lang-python';\nimport { StandardSQL } from '@codemirror/lang-sql';\nimport type { Language } from '@codemirror/language';\nimport { StreamLanguage } from '@codemirror/language';\nimport { shell } from '@codemirror/legacy-modes/mode/shell';\nimport { yaml } from '@codemirror/legacy-modes/mode/yaml';\nimport { highlightCode as walkHighlights, tagHighlighter, tags } from '@lezer/highlight';\n\nimport type { Highlighter, HighlightToken } from './highlightChunk';\nimport type { HighlightGrammar } from './highlightLanguages';\n\nconst GRAMMARS: Record<HighlightGrammar, Language> = {\n sql: StandardSQL.language,\n python: pythonLanguage,\n javascript: javascriptLanguage,\n jsx: jsxLanguage,\n typescript: typescriptLanguage,\n tsx: tsxLanguage,\n json: jsonLanguage,\n shell: StreamLanguage.define(shell),\n yaml: StreamLanguage.define(yaml),\n};\n\n/**\n * Syntax tag → token classes.\n *\n * - Semantic tokens only, so a brand recolours code with the rest of the answer.\n * - A sub-tag (`controlKeyword`) falls back to its parent's rule.\n */\nconst highlighter = tagHighlighter([\n { tag: [tags.keyword, tags.operatorKeyword, tags.modifier], class: 'tw:text-primary' },\n { tag: [tags.string, tags.special(tags.string), tags.regexp], class: 'tw:text-success' },\n { tag: tags.comment, class: 'tw:text-muted-foreground tw:italic' },\n { tag: [tags.number, tags.bool, tags.null, tags.atom], class: 'tw:text-info' },\n {\n tag: [tags.function(tags.variableName), tags.function(tags.propertyName)],\n class: 'tw:font-semibold',\n },\n { tag: [tags.typeName, tags.className], class: 'tw:text-info' },\n]);\n\n/** Splits `code` into runs, each with the classes its syntax earns; line breaks are `\\n` runs. */\nexport const highlightCode: Highlighter = (code, grammar) => {\n const tokens: HighlightToken[] = [];\n walkHighlights(\n code,\n GRAMMARS[grammar].parser.parse(code),\n highlighter,\n (text, className) => tokens.push({ text, className }),\n () => tokens.push({ text: '\\n', className: '' }),\n );\n return tokens;\n};\n"],"mappings":";;;;;;;;;AAkBA,MAAM,WAA+C;CACnD,KAAK,YAAY;CACjB,QAAQ;CACR,YAAY;CACZ,KAAK;CACL,YAAY;CACZ,KAAK;CACL,MAAM;CACN,OAAO,eAAe,OAAO,KAAK;CAClC,MAAM,eAAe,OAAO,IAAI;AAClC;;;;;;;AAQA,MAAM,cAAc,eAAe;CACjC;EAAE,KAAK;GAAC,KAAK;GAAS,KAAK;GAAiB,KAAK;EAAQ;EAAG,OAAO;CAAkB;CACrF;EAAE,KAAK;GAAC,KAAK;GAAQ,KAAK,QAAQ,KAAK,MAAM;GAAG,KAAK;EAAM;EAAG,OAAO;CAAkB;CACvF;EAAE,KAAK,KAAK;EAAS,OAAO;CAAqC;CACjE;EAAE,KAAK;GAAC,KAAK;GAAQ,KAAK;GAAM,KAAK;GAAM,KAAK;EAAI;EAAG,OAAO;CAAe;CAC7E;EACE,KAAK,CAAC,KAAK,SAAS,KAAK,YAAY,GAAG,KAAK,SAAS,KAAK,YAAY,CAAC;EACxE,OAAO;CACT;CACA;EAAE,KAAK,CAAC,KAAK,UAAU,KAAK,SAAS;EAAG,OAAO;CAAe;AAChE,CAAC;;AAGD,MAAa,iBAA8B,MAAM,YAAY;CAC3D,MAAM,SAA2B,CAAC;CAClC,gBACE,MACA,SAAS,QAAQ,CAAC,OAAO,MAAM,IAAI,GACnC,cACC,MAAM,cAAc,OAAO,KAAK;EAAE;EAAM;CAAU,CAAC,SAC9C,OAAO,KAAK;EAAE,MAAM;EAAM,WAAW;CAAG,CAAC,CACjD;CACA,OAAO;AACT"}