@keboola/design 11.3.0 → 11.4.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 (229) hide show
  1. package/AGENTS.md +17 -0
  2. package/CHANGELOG.md +170 -0
  3. package/COMPONENT-API.md +32 -31
  4. package/dist/{AIKit-DaFT7p92.js → AIKit-DDg5DBCG.js} +142 -63
  5. package/dist/AIKit-DDg5DBCG.js.map +1 -0
  6. package/dist/{Alert-CseY3yAj.js → Alert-DHJFrWnS.js} +3 -3
  7. package/dist/{Alert-CseY3yAj.js.map → Alert-DHJFrWnS.js.map} +1 -1
  8. package/dist/{AlertModal-DQAGpsEy.js → AlertModal-BGJdaRRj.js} +3 -3
  9. package/dist/{AlertModal-DQAGpsEy.js.map → AlertModal-BGJdaRRj.js.map} +1 -1
  10. package/dist/{AppShell-BUoxM3fv.js → AppShell-DRgJxpXW.js} +2 -2
  11. package/dist/{AppShell-BUoxM3fv.js.map → AppShell-DRgJxpXW.js.map} +1 -1
  12. package/dist/{BrandEditor-BnTLMRMp.js → BrandEditor-Go7w8Zj2.js} +7 -7
  13. package/dist/{BrandEditor-BnTLMRMp.js.map → BrandEditor-Go7w8Zj2.js.map} +1 -1
  14. package/dist/{BrandLogo-V2pRUAeO.js → BrandLogo-Dmi7jo21.js} +2 -2
  15. package/dist/{BrandLogo-V2pRUAeO.js.map → BrandLogo-Dmi7jo21.js.map} +1 -1
  16. package/dist/{Breadcrumb-CQTPn_KB.js → Breadcrumb-uEkM6adI.js} +3 -3
  17. package/dist/{Breadcrumb-CQTPn_KB.js.map → Breadcrumb-uEkM6adI.js.map} +1 -1
  18. package/dist/{Button-CPsEQuTN.js → Button-DsRrU5F1.js} +6 -5
  19. package/dist/Button-DsRrU5F1.js.map +1 -0
  20. package/dist/{Card-Cd5HSBmv.js → Card-Dyo7055Q.js} +2 -2
  21. package/dist/{Card-Cd5HSBmv.js.map → Card-Dyo7055Q.js.map} +1 -1
  22. package/dist/{Checkbox-5VNCcV7E.js → Checkbox-fC0BuO2B.js} +3 -3
  23. package/dist/{Checkbox-5VNCcV7E.js.map → Checkbox-fC0BuO2B.js.map} +1 -1
  24. package/dist/{Clipboard-B7rckqV_.js → Clipboard-ChPdiUy3.js} +2 -2
  25. package/dist/{Clipboard-B7rckqV_.js.map → Clipboard-ChPdiUy3.js.map} +1 -1
  26. package/dist/{ClipboardButton-CQ6Aewpg.js → ClipboardButton-D9pDjgkB.js} +3 -3
  27. package/dist/{ClipboardButton-CQ6Aewpg.js.map → ClipboardButton-D9pDjgkB.js.map} +1 -1
  28. package/dist/{CodeEditor-CUse8znx.js → CodeEditor-Cxy3HnKH.js} +15 -26
  29. package/dist/CodeEditor-Cxy3HnKH.js.map +1 -0
  30. package/dist/{ColorInput-Q1D9Vcc_.js → ColorInput-Bxj-1eLT.js} +3 -3
  31. package/dist/{ColorInput-Q1D9Vcc_.js.map → ColorInput-Bxj-1eLT.js.map} +1 -1
  32. package/dist/{ColorModeSwitch-B5PXCVqB.js → ColorModeSwitch-CsWLiTBX.js} +3 -3
  33. package/dist/{ColorModeSwitch-B5PXCVqB.js.map → ColorModeSwitch-CsWLiTBX.js.map} +1 -1
  34. package/dist/{Combobox-CyoRA7oY.js → Combobox-Cs_1pj2q.js} +29 -22
  35. package/dist/Combobox-Cs_1pj2q.js.map +1 -0
  36. package/dist/{Command-Ds68v2rX.js → Command-B7ML9YMv.js} +6 -6
  37. package/dist/{Command-Ds68v2rX.js.map → Command-B7ML9YMv.js.map} +1 -1
  38. package/dist/{CopyField-DI66uY_g.js → CopyField-BO_sh-HO.js} +2 -2
  39. package/dist/{CopyField-DI66uY_g.js.map → CopyField-BO_sh-HO.js.map} +1 -1
  40. package/dist/{DateInput-BPj2pzsn.js → DateInput-ZdaMQo5i.js} +4 -4
  41. package/dist/{DateInput-BPj2pzsn.js.map → DateInput-ZdaMQo5i.js.map} +1 -1
  42. package/dist/{DatePicker-DyEGuW9m.js → DatePicker-nA8YdE84.js} +2 -2
  43. package/dist/{DatePicker-DyEGuW9m.js.map → DatePicker-nA8YdE84.js.map} +1 -1
  44. package/dist/{DateRangeInput-u9DxNbHW.js → DateRangeInput-DkvNh_sT.js} +4 -4
  45. package/dist/{DateRangeInput-u9DxNbHW.js.map → DateRangeInput-DkvNh_sT.js.map} +1 -1
  46. package/dist/{DateRangePicker-CYYhX6S7.js → DateRangePicker-DjSUFjh4.js} +5 -5
  47. package/dist/{DateRangePicker-CYYhX6S7.js.map → DateRangePicker-DjSUFjh4.js.map} +1 -1
  48. package/dist/{DropdownMenu-DpMEcyCq.js → DropdownMenu-CASr-jgl.js} +2 -2
  49. package/dist/{DropdownMenu-DpMEcyCq.js.map → DropdownMenu-CASr-jgl.js.map} +1 -1
  50. package/dist/{FieldItem-qQKGU9lF.js → FieldItem-CCd9-xnp.js} +3 -3
  51. package/dist/{FieldItem-qQKGU9lF.js.map → FieldItem-CCd9-xnp.js.map} +1 -1
  52. package/dist/{FileUpload-C336MVnU.js → FileUpload-ABThVZyg.js} +2 -2
  53. package/dist/{FileUpload-C336MVnU.js.map → FileUpload-ABThVZyg.js.map} +1 -1
  54. package/dist/{Form-CTygENDc.js → Form-k6PH-em3.js} +8 -8
  55. package/dist/{Form-CTygENDc.js.map → Form-k6PH-em3.js.map} +1 -1
  56. package/dist/{FormGroup-BnwP0jNu.js → FormGroup-DbcDtrgU.js} +3 -3
  57. package/dist/{FormGroup-BnwP0jNu.js.map → FormGroup-DbcDtrgU.js.map} +1 -1
  58. package/dist/{FullScreenModal-j-M4aPFd.js → FullScreenModal-BvPuYibe.js} +3 -3
  59. package/dist/{FullScreenModal-j-M4aPFd.js.map → FullScreenModal-BvPuYibe.js.map} +1 -1
  60. package/dist/{HoverCard-yQq-O49c.js → HoverCard-B9ZMJxjn.js} +2 -2
  61. package/dist/{HoverCard-yQq-O49c.js.map → HoverCard-B9ZMJxjn.js.map} +1 -1
  62. package/dist/{InputGroup-D7zlmqPB.js → InputGroup-BnLHY0eq.js} +3 -3
  63. package/dist/{InputGroup-D7zlmqPB.js.map → InputGroup-BnLHY0eq.js.map} +1 -1
  64. package/dist/{Kbd-D6LpR7G2.js → Kbd-CvSM3D3-.js} +2 -2
  65. package/dist/{Kbd-D6LpR7G2.js.map → Kbd-CvSM3D3-.js.map} +1 -1
  66. package/dist/MarkedText-DNGEUVWc.js +67 -0
  67. package/dist/MarkedText-DNGEUVWc.js.map +1 -0
  68. package/dist/{MermaidDiagram-JlvuGcY-.js → MermaidDiagram-WkonYErO.js} +3 -3
  69. package/dist/{MermaidDiagram-JlvuGcY-.js.map → MermaidDiagram-WkonYErO.js.map} +1 -1
  70. package/dist/{Modal-o4ATIexE.js → Modal-Coj-H02o.js} +16 -4
  71. package/dist/Modal-Coj-H02o.js.map +1 -0
  72. package/dist/{MultiActionButtonGroup-GTeFk-L8.js → MultiActionButtonGroup-CxWH7yWK.js} +3 -3
  73. package/dist/{MultiActionButtonGroup-GTeFk-L8.js.map → MultiActionButtonGroup-CxWH7yWK.js.map} +1 -1
  74. package/dist/{Navbar-CAQs4BZz.js → Navbar-B2UsolVU.js} +3 -3
  75. package/dist/{Navbar-CAQs4BZz.js.map → Navbar-B2UsolVU.js.map} +1 -1
  76. package/dist/{PageToolbar-bG2YtSa3.js → PageToolbar-DnbFt14Q.js} +3 -3
  77. package/dist/{PageToolbar-bG2YtSa3.js.map → PageToolbar-DnbFt14Q.js.map} +1 -1
  78. package/dist/{Pagination-BB3X7ooY.js → Pagination-C_b7Xhey.js} +2 -2
  79. package/dist/{Pagination-BB3X7ooY.js.map → Pagination-C_b7Xhey.js.map} +1 -1
  80. package/dist/{Popconfirm-C2Ky5hJO.js → Popconfirm-CILjmzKI.js} +3 -3
  81. package/dist/{Popconfirm-C2Ky5hJO.js.map → Popconfirm-CILjmzKI.js.map} +1 -1
  82. package/dist/{Popover-DsbI2HKu.js → Popover-BEbQrC_P.js} +22 -19
  83. package/dist/Popover-BEbQrC_P.js.map +1 -0
  84. package/dist/{RadioGroup-BMxuZEbT.js → RadioGroup-XFzFd1ti.js} +3 -3
  85. package/dist/{RadioGroup-BMxuZEbT.js.map → RadioGroup-XFzFd1ti.js.map} +1 -1
  86. package/dist/{Search-DFeECt5D.js → Search-4Bxtt8hS.js} +2 -2
  87. package/dist/{Search-DFeECt5D.js.map → Search-4Bxtt8hS.js.map} +1 -1
  88. package/dist/{SearchInput-CCpdUego.js → SearchInput-f_oY9T4Z.js} +3 -3
  89. package/dist/{SearchInput-CCpdUego.js.map → SearchInput-f_oY9T4Z.js.map} +1 -1
  90. package/dist/{SectionNav-Bw_MVL0_.js → SectionNav-BpJlisbT.js} +4 -4
  91. package/dist/{SectionNav-Bw_MVL0_.js.map → SectionNav-BpJlisbT.js.map} +1 -1
  92. package/dist/{Select-D6IZVvwL.js → Select-DpcgKqKB.js} +31 -20
  93. package/dist/Select-DpcgKqKB.js.map +1 -0
  94. package/dist/{Sheet-BIzs2K2H.js → Sheet-Chf0kX1E.js} +3 -3
  95. package/dist/{Sheet-BIzs2K2H.js.map → Sheet-Chf0kX1E.js.map} +1 -1
  96. package/dist/{Sidebar-r1TW4g_b.js → Sidebar-Cm6I4dE1.js} +9 -7
  97. package/dist/{Sidebar-r1TW4g_b.js.map → Sidebar-Cm6I4dE1.js.map} +1 -1
  98. package/dist/{Slider-CjxyfEty.js → Slider-pPC_3gz9.js} +3 -3
  99. package/dist/{Slider-CjxyfEty.js.map → Slider-pPC_3gz9.js.map} +1 -1
  100. package/dist/{Switch-BueTV03C.js → Switch-ChfPKcTE.js} +2 -2
  101. package/dist/{Switch-BueTV03C.js.map → Switch-ChfPKcTE.js.map} +1 -1
  102. package/dist/{Tabs-l72-WuhK.js → Tabs-eB974xJf.js} +2 -2
  103. package/dist/{Tabs-l72-WuhK.js.map → Tabs-eB974xJf.js.map} +1 -1
  104. package/dist/{TextInput-DhdRk8qm.js → TextInput-DHM6dHmn.js} +3 -3
  105. package/dist/{TextInput-DhdRk8qm.js.map → TextInput-DHM6dHmn.js.map} +1 -1
  106. package/dist/{ThemeProvider-DZfGdf1v.js → ThemeProvider-DrQJtzpd.js} +90 -15
  107. package/dist/ThemeProvider-DrQJtzpd.js.map +1 -0
  108. package/dist/{TimePicker-B6d2rAbX.js → TimePicker-BGeqc-Ed.js} +2 -2
  109. package/dist/{TimePicker-B6d2rAbX.js.map → TimePicker-BGeqc-Ed.js.map} +1 -1
  110. package/dist/{Toast-CxXUulYN.js → Toast-Dr6Uw7ao.js} +2 -2
  111. package/dist/{Toast-CxXUulYN.js.map → Toast-Dr6Uw7ao.js.map} +1 -1
  112. package/dist/{ZoomableSvg-CNIzRHKH.js → ZoomableSvg-BWnDkR61.js} +4 -4
  113. package/dist/{ZoomableSvg-CNIzRHKH.js.map → ZoomableSvg-BWnDkR61.js.map} +1 -1
  114. package/dist/{context-BrNtMc1H.js → context-D7X470dy.js} +4 -3
  115. package/dist/context-D7X470dy.js.map +1 -0
  116. package/dist/{defaults-CTfvj2KB.js → defaults-i_xG2F_1.js} +2 -4
  117. package/dist/defaults-i_xG2F_1.js.map +1 -0
  118. package/dist/editors.js +4 -4
  119. package/dist/findLiteralMatches-BGBw8Vbl.js +62 -0
  120. package/dist/findLiteralMatches-BGBw8Vbl.js.map +1 -0
  121. package/dist/flint.js +3 -3
  122. package/dist/index.d.ts +677 -527
  123. package/dist/index.js +59 -58
  124. package/dist/internal/blocks/AIKit.js +2 -2
  125. package/dist/internal/blocks/AppShell.js +1 -1
  126. package/dist/internal/blocks/BrandEditor.js +1 -1
  127. package/dist/internal/blocks/ChartPanel.js +1 -1
  128. package/dist/internal/blocks/ClipboardButton.js +1 -1
  129. package/dist/internal/blocks/ColorInput.js +1 -1
  130. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  131. package/dist/internal/blocks/Command.js +1 -1
  132. package/dist/internal/blocks/CopyField.js +1 -1
  133. package/dist/internal/blocks/DateInput.js +1 -1
  134. package/dist/internal/blocks/DateRangeInput.js +1 -1
  135. package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
  136. package/dist/internal/blocks/ErrorState.js +1 -1
  137. package/dist/internal/blocks/ExportMenu.js +5 -5
  138. package/dist/internal/blocks/ExportMenu.js.map +1 -1
  139. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  140. package/dist/internal/blocks/Form.js +1 -1
  141. package/dist/internal/blocks/FormGroup.js +1 -1
  142. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  143. package/dist/internal/blocks/MultiCombobox.js +14 -11
  144. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  145. package/dist/internal/blocks/NumberInput.js +1 -1
  146. package/dist/internal/blocks/PageToolbar.js +1 -1
  147. package/dist/internal/blocks/PasswordInput.js +2 -2
  148. package/dist/internal/blocks/SearchInput.js +1 -1
  149. package/dist/internal/blocks/SearchInputWithNavigation.js +3 -3
  150. package/dist/internal/blocks/SectionNav.js +1 -1
  151. package/dist/internal/blocks/SplitButton.js +2 -2
  152. package/dist/internal/blocks/StatCard.js +1 -1
  153. package/dist/internal/blocks/TextInput.js +1 -1
  154. package/dist/internal/blocks/Textarea.js +1 -1
  155. package/dist/internal/blocks/TimeInput.js +3 -3
  156. package/dist/internal/components/Alert.js +1 -1
  157. package/dist/internal/components/AlertModal.js +1 -1
  158. package/dist/internal/components/Avatar.js +1 -1
  159. package/dist/internal/components/BrandLogo.js +1 -1
  160. package/dist/internal/components/Breadcrumb.js +1 -1
  161. package/dist/internal/components/Button.js +1 -1
  162. package/dist/internal/components/Card.js +1 -1
  163. package/dist/internal/components/Checkbox.js +1 -1
  164. package/dist/internal/components/Clipboard.js +1 -1
  165. package/dist/internal/components/CollapsiblePanel.js +1 -1
  166. package/dist/internal/components/Combobox.js +1 -1
  167. package/dist/internal/components/DatePicker.js +1 -1
  168. package/dist/internal/components/DateRangePicker.js +1 -1
  169. package/dist/internal/components/DropdownMenu.js +1 -1
  170. package/dist/internal/components/FileUpload.js +1 -1
  171. package/dist/internal/components/FullScreenModal.js +1 -1
  172. package/dist/internal/components/HoverCard.js +1 -1
  173. package/dist/internal/components/InputGroup.js +1 -1
  174. package/dist/internal/components/Kbd.js +1 -1
  175. package/dist/internal/components/MarkedText.js +1 -1
  176. package/dist/internal/components/Modal.js +1 -1
  177. package/dist/internal/components/Navbar.js +1 -1
  178. package/dist/internal/components/Pagination.js +1 -1
  179. package/dist/internal/components/Popconfirm.js +1 -1
  180. package/dist/internal/components/Popover.js +1 -1
  181. package/dist/internal/components/RadioGroup.js +1 -1
  182. package/dist/internal/components/Search.js +1 -1
  183. package/dist/internal/components/Select.js +1 -1
  184. package/dist/internal/components/Sheet.js +1 -1
  185. package/dist/internal/components/Sidebar.js +1 -1
  186. package/dist/internal/components/Slider.js +1 -1
  187. package/dist/internal/components/Switch.js +1 -1
  188. package/dist/internal/components/Tabs.js +1 -1
  189. package/dist/internal/components/ThemeProvider.js +4 -4
  190. package/dist/internal/components/TimePicker.js +1 -1
  191. package/dist/internal/components/Toast.js +2 -2
  192. package/dist/internal/components/Toggle.js +3 -3
  193. package/dist/internal/components/Toggle.js.map +1 -1
  194. package/dist/internal/components/Tooltip.js +1 -1
  195. package/dist/internal/components/Truncated.js +1 -1
  196. package/dist/internal/components/ZoomableSvg.js +1 -1
  197. package/dist/internal/utils.js +3 -3
  198. package/dist/markdown-editor.js +7 -7
  199. package/dist/mermaid.js +1 -1
  200. package/dist/rjsf.js +11 -11
  201. package/dist/styles.css +1 -1
  202. package/dist/testing.js +4 -4
  203. package/dist/testing.js.map +1 -1
  204. package/dist/{themeTokens-7T1AFLhq.js → themeTokens-D70HeNVF.js} +3 -3
  205. package/dist/{themeTokens-7T1AFLhq.js.map → themeTokens-D70HeNVF.js.map} +1 -1
  206. package/dist/{toast-BweSoKn3.js → toast-DIC0iNRf.js} +2 -2
  207. package/dist/{toast-BweSoKn3.js.map → toast-DIC0iNRf.js.map} +1 -1
  208. package/dist/{useColorSchemeState-BJEk6esG.js → useColorSchemeState-klihG9-i.js} +2 -2
  209. package/dist/{useColorSchemeState-BJEk6esG.js.map → useColorSchemeState-klihG9-i.js.map} +1 -1
  210. package/dist/{utils-B-g7d_Jb.js → utils-B5Z52hYs.js} +2 -2
  211. package/dist/{utils-B-g7d_Jb.js.map → utils-B5Z52hYs.js.map} +1 -1
  212. package/dist/vega.js +2 -2
  213. package/dist/{vegaTheme-FBXgAdHK.js → vegaTheme-DfoEQhOy.js} +2 -2
  214. package/dist/{vegaTheme-FBXgAdHK.js.map → vegaTheme-DfoEQhOy.js.map} +1 -1
  215. package/package.json +5 -5
  216. package/dist/AIKit-DaFT7p92.js.map +0 -1
  217. package/dist/Button-CPsEQuTN.js.map +0 -1
  218. package/dist/CodeEditor-CUse8znx.js.map +0 -1
  219. package/dist/Combobox-CyoRA7oY.js.map +0 -1
  220. package/dist/MarkedText-Ckbft5mw.js +0 -44
  221. package/dist/MarkedText-Ckbft5mw.js.map +0 -1
  222. package/dist/Modal-o4ATIexE.js.map +0 -1
  223. package/dist/Popover-DsbI2HKu.js.map +0 -1
  224. package/dist/Select-D6IZVvwL.js.map +0 -1
  225. package/dist/ThemeProvider-DZfGdf1v.js.map +0 -1
  226. package/dist/context-BrNtMc1H.js.map +0 -1
  227. package/dist/defaults-CTfvj2KB.js.map +0 -1
  228. package/dist/escapeStringRegexp-8MxP2knR.js +0 -6
  229. package/dist/escapeStringRegexp-8MxP2knR.js.map +0 -1
package/AGENTS.md CHANGED
@@ -497,6 +497,19 @@ Both router wirings (TanStack Router, and a custom named router) are in [`RECIPE
497
497
  />
498
498
  ```
499
499
 
500
+ **Pinned chip in a `MultiCombobox`** — a chip the control shows but the user does not own (a set of packages the runtime already ships, a role every member has). `pinnedChipLabels` is a render-only slot, so nothing enters `value`: there is no sentinel to strip on save and the control's own counting never sees a non-item.
501
+
502
+ ```tsx
503
+ <MultiCombobox
504
+ allowCreate
505
+ value={packages}
506
+ onValueChange={save}
507
+ pinnedChipLabels={['Default packages']}
508
+ />
509
+ ```
510
+
511
+ Don't fake one by prepending a sentinel to `value` — that costs the caller a strip on every change plus a label branch, and leaks the sentinel into the primitive's counting.
512
+
500
513
  **Sheet** — use `Sheet.Header title="…" description="…"` for a styled title + close icon; do **not** hand-roll with the raw `Sheet.Title`, which renders an unstyled `<h2>`. `Sheet.Body` provides horizontal padding only (`tw:px-4`) — add your own vertical rhythm/gap:
501
514
 
502
515
  ```tsx
@@ -535,6 +548,10 @@ Layer-0 colour usage splits into three buckets.
535
548
 
536
549
  A border **width** utility carries no colour of its own — a lone `tw:border` / `tw:border-t` / `tw:border-2` paints the element's _text_ colour, a near-black frame where a light-grey rule belongs. Pair every width with a colour: `tw:border tw:border-border` for chrome, `tw:border-input` on form controls. `pnpm test:stories` fails on any story that ships a width without one.
537
550
 
551
+ An **opacity modifier composites over `transparent`, not over the element's own rest fill.** On a control that is opaque at rest (`tw:bg-card`, `tw:bg-background`) a `tw:hover:bg-<token>/NN` therefore _replaces_ that fill, and the control shows whatever it overlaps — a flow-canvas edge, an `Alert` tint. Mix the state fill into the control's rest token instead: `tw:hover:bg-[color-mix(in_oklab,rgb(var(--muted-foreground))_15%,rgb(var(--card)))]`. Use the raw `--*` triples — `--color-*` is `@theme inline`, build-time only, and an unresolved one invalidates the declaration into `transparent`. A control that is **transparent at rest** (menu item, ghost button, table row) is the case the modifier is for; leave those alone.
552
+
553
+ A tint also cannot carry a **state change** on a light surface — a brand-primary tint stays within ~1.5:1 of the surface at any opacity that still reads as a tint. Step the border for that, and keep the roles apart: hover steps the chrome border (`border-input` → `border-muted-foreground`), `focus-visible` owns the brand border.
554
+
538
555
  **Status — themeable under argo, with AA-legible defaults.** The four semantic states — `success`, `warning`, `info`, and `destructive` (used for "error") — are brand-overridable tokens, not fixed scales. Alert `variant`, `HelpBlock` / field-error state, `ErrorState`, and `Stepper` status read them, so a brand recolours every status surface at once. **Rule:** consume the token as **tint + text/icon** — `tw:bg-<role>/10` for the surface, `tw:text-<role>` / `tw:border-<role>/25` for the mark. The default token values ship dark enough to be AA (≥4.5:1) as text/icon on their own tint, in light **and** dark mode — a brand overriding them should preserve that. Avoid solid fills with a white foreground (`tw:bg-<role>` + white): the token flips light in dark mode, so white-on-token fails there. A brand _can_ recolour "error" away from red — that is now allowed; the accessible-on-tint contract is what must hold, not the hue. **Legacy exception:** the themeable treatment is gated to argo (`data-[argo=true]:` / `group-data-[argo=true]/…:`). Under legacy chrome (`useArgoDesign()` → `false`) Alert and `ErrorState` keep their original fixed status scales (`blue-*`/`green-*`/`warning-*`/`error-*`), and the legacy brand retains its original status token hues — so legacy status colour is unchanged.
539
556
 
540
557
  **Decorative — stays fixed across brands.** The non-semantic palette that encodes category rather than state: `Badge` decorative colours (`purple`, `cyan`, `teal`, `blue`, …), chart colours, decorative tag palette. **Rule:** keep using primitive scales (`purple-500`, `cyan-500`, …). These are an identity/category contract with the consumer and do not re-skin.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,175 @@
1
1
  # @keboola/design
2
2
 
3
+ ## 11.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - The AIKit layer for Kai's redesign (DES-20, DES-170).
8
+ - `ThemeScope` (new): a subtree pins its own colour scheme regardless of the app's —
9
+ Kai's panel stays light while its minimized widget is dark. `useThemeScopeContainer`
10
+ hands portalling components the scope element, and `Popover.Content` now takes a
11
+ `container` so a portal stays inside the scope that styles it.
12
+ - `ToolCallStatusHeader` joins AIKit — the tool-call panel header kbc-ui carried,
13
+ promoted with tests and stories.
14
+ - `MessageBubble` drops its avatar; a user turn is a plain bubble. `user` is still accepted
15
+ (deprecated, ignored) so call sites keep compiling.
16
+ - `Command` takes a `variant`, so a command in a small surface (a popover) can opt out
17
+ of the full-screen palette styling the theme would pick.
18
+ - No platform token changes: Kai scopes its own sidebar accent in kbc-ui.
19
+ - The root barrel grows ~1 KB with the new exports; the size budget moves 342→344 KB.
20
+
21
+ - `CodeEditor` search matches literal text instead of a compiled pattern, and `findLiteralMatches` / `hasLiteralMatch` ship as utilities.
22
+
23
+ A search query is data, not a pattern. Compiling one meant escaping it first and living with V8's
24
+ ceiling on how large a pattern may be: a query of a few tens of kilobytes — what pasting a document
25
+ into a find box produces — threw `Regular expression too large` when the pattern was first executed.
26
+ `findMatches` now scans for the query literally, so escaping and that ceiling are both gone, and it
27
+ short-circuits before joining the document's rope when the query cannot fit in it.
28
+
29
+ `findLiteralMatches(text, query)` returns the start offsets of every case-insensitive occurrence and
30
+ `hasLiteralMatch(text, query)` answers whether there is one, stopping at the first. Both fold case
31
+ without changing the length of the string, so the offsets index the caller's own text.
32
+
33
+ Two behaviour notes for anyone matching the editor's counts elsewhere: `İ` (U+0130) now reads as a
34
+ plain `i` rather than matching only itself, and `SearchMatch` no longer carries the matched `text`,
35
+ which nothing read.
36
+
37
+ - `Markdown` accepts `remarkPlugins` and `components`.
38
+ - `remarkPlugins` runs after the built-in GFM one rather than in place of it, so tables, autolinks and task lists keep working whatever a caller adds.
39
+ - `components` is merged over the built-in element renderers by key. An override replaces that element's renderer rather than wrapping it, so a `table` override loses the design `Table` and an `a` override loses the new-tab treatment for absolute links.
40
+ - Together they are the seam an app's own inline syntax arrives through — an annotation an agent writes beside a link, read back by a renderer for that element — which is app product knowledge and does not belong in this package.
41
+ - Both are meant to be held in module constants: `Markdown` re-parses its source on every render, so a caller memoises it, and a prop object built during render defeats that.
42
+
43
+ - `MarkedText` highlights by literal scan instead of a compiled pattern, and `findLiteralMatches` takes an `isCaseSensitive` option.
44
+
45
+ The highlight query was escaped, split on spaces, and joined into one alternation regex — so a
46
+ space-free paste of a few tens of kilobytes (minified SQL, JSON, base64) exceeded V8's pattern
47
+ ceiling and threw `Regular expression too large` from a `useMemo`, taking the page down with it.
48
+ `createMarkedParts` now finds each space-separated term with `findLiteralMatches` and merges the
49
+ offsets, so no pattern is compiled at all.
50
+
51
+ One visible behaviour change: overlapping term matches now merge into one marked run — searching
52
+ `test testing` marks the whole `testing`, where the alternation used to mark only its `test` prefix
53
+ and leave `ing` plain. Adjacent matches merge the same way. Case-insensitive matching also folds
54
+ `İ` (U+0130) to a plain `i`, matching the editor search.
55
+
56
+ `escapeStringRegexp` is gone from the package's internals — nothing compiles user text as a pattern
57
+ anymore.
58
+
59
+ - `MultiCombobox`: a render-only slot for pinned chips, chip callbacks see the real item type, and a created value stops haunting the list.
60
+
61
+ `pinnedChipLabels` renders chips the caller keeps rather than the user — a set of packages the
62
+ runtime already ships, a role every member has. They sit ahead of the values, outside `maxVisible`,
63
+ carry no remove button, and never enter `value`.
64
+
65
+ `itemToChipLabel` and `itemToChipColor` now receive `Value` instead of `unknown`, so a call site
66
+ stops narrowing by hand. Existing call sites keep compiling; their `String(...)` wrappers become
67
+ redundant.
68
+
69
+ Created values were kept in a list that never shrank, so a value the user created and then removed —
70
+ or cleared — stayed in the listbox as an option for the rest of the session, and skewed
71
+ `allowSelectAll`'s "everything is selected" arithmetic. The list now tracks the selection.
72
+
73
+ - Add a `hint` slot to `Select` items, and let the top-level `Select` take `aria-label`.
74
+
75
+ `hint` renders a trailing muted note in the listbox row — "Default" beside the value the
76
+ platform falls back to. It sits outside Radix's `ItemText`, so the trigger keeps showing the
77
+ label alone once the option is picked; because Radix names an option from `ItemText` only
78
+ (`aria-labelledby`), the hint is wired into the item's `aria-describedby` instead, so a screen
79
+ reader still reads it.
80
+
81
+ `aria-label` was the one trigger a11y prop the convenience wrapper did not forward — it already
82
+ curated `aria-describedby`, `aria-invalid` and `aria-required`. Selects that stand without a
83
+ visible `Label` (a filter row, or several selects joined by "OR") need it.
84
+
85
+ - `UsageStats`: the corner alert badge now accepts a severity.
86
+
87
+ `alert` takes `boolean | 'warning' | 'error'` instead of a bare boolean. `'warning'` renders the badge
88
+ amber for an approaching-limit state that isn't at-limit yet; `'error'` (or the existing bare `true`)
89
+ keeps the red at-limit color, so existing call sites keep compiling unchanged.
90
+
91
+ ### Patch Changes
92
+
93
+ - `Button variant="outline"`: the hovered button stops dissolving into the surface behind it.
94
+
95
+ Both hover and pressed fills were tints of `transparent` (Tailwind's `bg-<token>/NN`), so hovering
96
+ replaced the variant's opaque rest fill and the button showed whatever it overlapped — an edge on a
97
+ flow canvas, the status tint inside an `Alert`. They now `color-mix` into the variant's own rest
98
+ token (`--card` under legacy chrome, `--background` under argo), which is the same colour on the
99
+ surface the variant assumes and stays opaque off it.
100
+
101
+ Argo compounded that by keeping `border-input` on hover while tinting the fill toward it, so the
102
+ button's edge contrast _dropped_ as the user reached it — measured 1.42:1 → 1.25:1 in light and
103
+ 2.28:1 → 1.62:1 in dark, against its own fill on a `--muted` surface. Its hover now steps the
104
+ border to `--muted-foreground` (4.00:1 / 5.24:1), the treatment legacy already shipped. A tint
105
+ cannot carry that signal: brand primary stays within ~1.5:1 of a light surface at any opacity that
106
+ still reads as a tint. `--primary` stays reserved for `focus-visible`, so hover and focus remain
107
+ distinguishable.
108
+
109
+ Consumers overriding the hover fill per call site to work around the leak can drop those
110
+ overrides. `packages/design/AGENTS.md` records the underlying rule in the Layer-0 chrome contract.
111
+
112
+ - Security patches for transitive dependencies: qs 6.16.0 in api-client, mermaid 11.17.2 and dompurify
113
+ 3.4.14 in design.
114
+
115
+ No API or behaviour change in either package.
116
+
117
+ - Every theme-aware subpath entry stops carrying `@keboola/brand-registry`.
118
+
119
+ `ThemeProvider/defaults.ts` imported two legacy brands for value, only to build a two-element array
120
+ of their ids — and that array had exactly one consumer, the `renderWithTheme` test helper. Because
121
+ `useThemeAttributes`, `useBrandState` and `useColorSchemeState` each read a constant from
122
+ `defaults.ts`, that one import put the whole registry in the graph of every entry that reads the
123
+ live theme.
124
+
125
+ The ids now live at the helper that uses them, so `defaults.ts` imports `Brand` as a type only. No
126
+ export moved and no behaviour changed — `keboolaLegacySidebar` / `keboolaLegacyTopnav` still resolve
127
+ from the root barrel for the consumers that render them.
128
+
129
+ What a consumer pays for a themed subpath, brotlied:
130
+
131
+ | Entry | Before | After | Δ |
132
+ | --------------------------------- | ---------: | ---------: | ----: |
133
+ | `@keboola/design/vega` | 61.9 kB | 0.9 kB | −98 % |
134
+ | `@keboola/design/editors` | 312.5 kB | 252.0 kB | −19 % |
135
+ | `@keboola/design/flint` | 439.7 kB | 380.2 kB | −14 % |
136
+ | `@keboola/design/rjsf` | 490.2 kB | 430.6 kB | −12 % |
137
+ | `@keboola/design/markdown-editor` | 1 333.9 kB | 1 272.0 kB | −5 % |
138
+ | `@keboola/design/mermaid` | 1 200.4 kB | 1 140.1 kB | −5 % |
139
+ | `{ useAppForm }` from the root | 135.2 kB | 73.9 kB | −45 % |
140
+
141
+ The root barrel is unchanged — it re-exports the brands deliberately, so an app that renders one
142
+ still pays for it once. The per-entry `size-limit` budgets drop to match, so they now measure the
143
+ entry rather than a shared dependency.
144
+
145
+ - `Modal.Footer` now lays its own actions out: right-aligned, 8px apart.
146
+
147
+ The footer owned only horizontal padding, so a bare `<Modal.Footer>` fell back to block flow — its
148
+ buttons sat left-aligned, separated by nothing but collapsed JSX whitespace. Nearly every footer in
149
+ this repo is bare, so that was the default look; a handful re-declared `tw:flex tw:justify-end
150
+ tw:gap-2` at the call site. Consumers can drop those.
151
+
152
+ Overriding the arrangement still works through `className`, but `cn` runs tailwind-merge, which
153
+ displaces only within a conflict group: `tw:justify-between` replaces `justify-end`, while
154
+ `tw:flex-col` leaves `items-center` and the gap in place, so a stacked footer wants
155
+ `tw:items-stretch` alongside it. The footer imposes no width on its children, so one that should
156
+ fill the row carries `tw:w-full` itself (`Button block`, `ButtonGroup variant="block"`).
157
+
158
+ One footer in this repo wanted the stacked arrangement — `wr-google-sheets`' `SheetModal`, which
159
+ puts a saving message above its buttons — and is the only one still passing layout classes.
160
+
161
+ `@keboola/kbc-ui` and `@keboola/control-ui` are private — nothing to release for them; they are
162
+ listed because their call sites changed.
163
+
164
+ - `PromptInput`: `autoFocus` no longer scrolls ancestors to reveal the textarea.
165
+
166
+ The prop was forwarded as the DOM attribute, and the browser's autofocus scrolls every scrollable
167
+ ancestor toward the element. A composer mounting inside a panel that is still sliding in — kbc-ui's
168
+ Kai rail opens this way — sits off-canvas at focus time, so the page scrolled sideways toward it,
169
+ shoving the whole content left until the slide finished and the overflow clamp snapped it back.
170
+ The focus is now applied imperatively on mount with `focus({ preventScroll: true })`: same focus,
171
+ same mount-only semantics, no ancestor scrolling.
172
+
3
173
  ## 11.3.0
4
174
 
5
175
  ### Minor Changes
package/COMPONENT-API.md CHANGED
@@ -319,37 +319,38 @@ Source: `src/blocks/Form/connectors/MultiComboboxField.tsx`
319
319
 
320
320
  > Several values from a searchable list — state is `string[]`, never objects, so the form value stays what gets submitted. Project labels with `itemToLabel`; add `allowCreate` for an enum the user may extend. Imported by name from `@keboola/design`, composed inside `form.AppField` — NOT reachable as `field.MultiComboboxField`.
321
321
 
322
- | Prop | Type | Required | Default | Description |
323
- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
324
- | `action` | `ReactNode` | no | — | Optional node rendered at the trailing edge of the label row (opposite the label) — e.g. a "Forgot password?" link beside a Password label. Presentational placement only; it is a sibling of the `<Label>`, not part of the field's accessible name. Provide an interactive element (`ButtonInline` / `Link`). |
325
- | `allowClear` | `boolean` | no | — | |
326
- | `allowCreate` | `boolean` | no | — | |
327
- | `allowSelectAll` | `boolean` | no | — | |
328
- | `aria-describedby` | `string` | no | — | |
329
- | `className` | `string` | no | — | |
330
- | `empty` | `ReactNode` | no | — | |
331
- | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
332
- | `groupToLabel` | `((group: Group<string>) => ReactNode)` | no | — | |
333
- | `help` | `ReactNode` | no | — | |
334
- | `indicator` | `Indicator` | no | — | |
335
- | `inputClassName` | `string` | no | — | |
336
- | `items` | `readonly (string \| Group<string>)[]` | no | — | |
337
- | `itemToChipColor` | `((item: unknown) => "gray" \| "gray-darker" \| "gray-inverse" \| "green" \| "green-darker" \| "green-inverse" \| "blue" \| "blue-inverse" \| "red" \| "orange" \| "orange-inverse" \| "amber" \| ... 9 more ...)` | no | — | |
338
- | `itemToChipLabel` | `((item: unknown) => ReactNode)` | no | — | |
339
- | `itemToDisabled` | `((item: string) => boolean)` | no | — | |
340
- | `itemToIcon` | `((item: string) => ReactNode)` | no | — | |
341
- | `itemToLabel` | `((item: string) => ReactNode)` | no | — | |
342
- | `itemToStringLabel` | `((itemValue: string) => string)` | no | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for display in the input. If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop. |
343
- | `itemToStringValue` | `((itemValue: string) => string)` | no | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for form submission. If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop. |
344
- | `label` | `ReactNode` | no | — | |
345
- | `maxVisible` | `number` | no | — | |
346
- | `queryToCreateLabel` | `((query: string) => ReactNode)` | no | — | |
347
- | `queryToCreateValue` | `((query: string) => string)` | no | — | |
348
- | `required` | `boolean` | no | — | |
349
- | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
350
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
351
- | `tooltip` | `ReactNode` | no | — | |
352
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
322
+ | Prop | Type | Required | Default | Description |
323
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
324
+ | `action` | `ReactNode` | no | — | Optional node rendered at the trailing edge of the label row (opposite the label) — e.g. a "Forgot password?" link beside a Password label. Presentational placement only; it is a sibling of the `<Label>`, not part of the field's accessible name. Provide an interactive element (`ButtonInline` / `Link`). |
325
+ | `allowClear` | `boolean` | no | — | |
326
+ | `allowCreate` | `boolean` | no | — | |
327
+ | `allowSelectAll` | `boolean` | no | — | |
328
+ | `aria-describedby` | `string` | no | — | |
329
+ | `className` | `string` | no | — | |
330
+ | `empty` | `ReactNode` | no | — | |
331
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
332
+ | `groupToLabel` | `((group: Group<string>) => ReactNode)` | no | — | |
333
+ | `help` | `ReactNode` | no | — | |
334
+ | `indicator` | `Indicator` | no | — | |
335
+ | `inputClassName` | `string` | no | — | |
336
+ | `items` | `readonly (string \| Group<string>)[]` | no | — | |
337
+ | `itemToChipColor` | `((item: string) => "gray" \| "gray-darker" \| "gray-inverse" \| "green" \| "green-darker" \| "green-inverse" \| "blue" \| "blue-inverse" \| "red" \| "orange" \| "orange-inverse" \| "amber" \| ... 9 more ...)` | no | — | |
338
+ | `itemToChipLabel` | `((item: string) => ReactNode)` | no | — | |
339
+ | `itemToDisabled` | `((item: string) => boolean)` | no | — | |
340
+ | `itemToIcon` | `((item: string) => ReactNode)` | no | — | |
341
+ | `itemToLabel` | `((item: string) => ReactNode)` | no | — | |
342
+ | `itemToStringLabel` | `((itemValue: string) => string)` | no | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for display in the input. If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop. |
343
+ | `itemToStringValue` | `((itemValue: string) => string)` | no | — | When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for form submission. If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop. |
344
+ | `label` | `ReactNode` | no | — | |
345
+ | `maxVisible` | `number` | no | — | |
346
+ | `pinnedChipLabels` | `ReactNode[]` | no | — | Labels for chips the control shows but the user does not own — a pinned set the caller keeps. - Each label gets a chip of its own, ahead of the values and outside the `maxVisible` slice. - No remove button, and no entry in `value` — there is nothing for a removal to report. |
347
+ | `queryToCreateLabel` | `((query: string) => ReactNode)` | no | — | |
348
+ | `queryToCreateValue` | `((query: string) => string)` | no | — | |
349
+ | `required` | `boolean` | no | — | |
350
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
351
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
352
+ | `tooltip` | `ReactNode` | no | — | |
353
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
353
354
 
354
355
  ### `field.CheckboxField`
355
356