@keboola/design 11.6.0 → 11.9.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.
- package/AGENTS.md +16 -1
- package/CHANGELOG.md +92 -0
- package/COMPONENT-API.md +47 -46
- package/README.md +1 -1
- package/dist/{AIKit-BExvt9pt.js → AIKit-ELIsegJz.js} +551 -104
- package/dist/AIKit-ELIsegJz.js.map +1 -0
- package/dist/{Alert-Ba5b2YPq.js → Alert-BsIM_oFK.js} +2 -2
- package/dist/{Alert-Ba5b2YPq.js.map → Alert-BsIM_oFK.js.map} +1 -1
- package/dist/{Badge-D0pXdekt.js → Badge-o5jURtpB.js} +2 -2
- package/dist/{Badge-D0pXdekt.js.map → Badge-o5jURtpB.js.map} +1 -1
- package/dist/{BrandEditor-CSANsxUz.js → BrandEditor-BsTBM3s6.js} +5 -5
- package/dist/{BrandEditor-CSANsxUz.js.map → BrandEditor-BsTBM3s6.js.map} +1 -1
- package/dist/{Breadcrumb-g_xn_-Nf.js → Breadcrumb-xqEUxfwn.js} +2 -2
- package/dist/{Breadcrumb-g_xn_-Nf.js.map → Breadcrumb-xqEUxfwn.js.map} +1 -1
- package/dist/{Checkbox-CUIn2jap.js → Checkbox-Dq5fPNrO.js} +2 -2
- package/dist/{Checkbox-CUIn2jap.js.map → Checkbox-Dq5fPNrO.js.map} +1 -1
- package/dist/{Clipboard-BTW6C-b_.js → Clipboard-BZitKiSA.js} +2 -2
- package/dist/{Clipboard-BTW6C-b_.js.map → Clipboard-BZitKiSA.js.map} +1 -1
- package/dist/{ClipboardButton-CwZJdRaz.js → ClipboardButton-KHQnPEh_.js} +2 -2
- package/dist/{ClipboardButton-CwZJdRaz.js.map → ClipboardButton-KHQnPEh_.js.map} +1 -1
- package/dist/{CodeEditor-C9zy7PxK.js → CodeEditor-BJKJXA0c.js} +4 -4
- package/dist/{CodeEditor-C9zy7PxK.js.map → CodeEditor-BJKJXA0c.js.map} +1 -1
- package/dist/{ColorInput-BZV-u_94.js → ColorInput-Bj3dfPFA.js} +3 -3
- package/dist/{ColorInput-BZV-u_94.js.map → ColorInput-Bj3dfPFA.js.map} +1 -1
- package/dist/{ColorModeSwitch-CsWLiTBX.js → ColorModeSwitch-CWt-DZGC.js} +2 -2
- package/dist/{ColorModeSwitch-CsWLiTBX.js.map → ColorModeSwitch-CWt-DZGC.js.map} +1 -1
- package/dist/{Combobox-BfIfaVMA.js → Combobox-D8PrEqTG.js} +4 -4
- package/dist/{Combobox-BfIfaVMA.js.map → Combobox-D8PrEqTG.js.map} +1 -1
- package/dist/{Command-Bfa1kpbt.js → Command-BDU3C1gg.js} +2 -2
- package/dist/{Command-Bfa1kpbt.js.map → Command-BDU3C1gg.js.map} +1 -1
- package/dist/{CopyField-DpT0Ngz1.js → CopyField-BHRQUyuF.js} +2 -2
- package/dist/{CopyField-DpT0Ngz1.js.map → CopyField-BHRQUyuF.js.map} +1 -1
- package/dist/{DateInput-DiEd5uCL.js → DateInput-B6N8g0ra.js} +3 -3
- package/dist/{DateInput-DiEd5uCL.js.map → DateInput-B6N8g0ra.js.map} +1 -1
- package/dist/{DateRangeInput-DPfVYchl.js → DateRangeInput-7M9Z4cVO.js} +3 -3
- package/dist/{DateRangeInput-DPfVYchl.js.map → DateRangeInput-7M9Z4cVO.js.map} +1 -1
- package/dist/{DropdownMenu-CASr-jgl.js → DropdownMenu-CgVwhDvl.js} +9 -4
- package/dist/DropdownMenu-CgVwhDvl.js.map +1 -0
- package/dist/{FieldItem-B7XMmZSz.js → FieldItem-DZGIdiXE.js} +3 -3
- package/dist/{FieldItem-B7XMmZSz.js.map → FieldItem-DZGIdiXE.js.map} +1 -1
- package/dist/{FileUpload-ABThVZyg.js → FileUpload-DYQCTGjU.js} +3 -3
- package/dist/{FileUpload-ABThVZyg.js.map → FileUpload-DYQCTGjU.js.map} +1 -1
- package/dist/{Form-CsttTHn4.js → Form-CcK7dRrC.js} +5 -5
- package/dist/{Form-CsttTHn4.js.map → Form-CcK7dRrC.js.map} +1 -1
- package/dist/{FormGroup-DHvTFdno.js → FormGroup-DR_gZ25-.js} +3 -3
- package/dist/{FormGroup-DHvTFdno.js.map → FormGroup-DR_gZ25-.js.map} +1 -1
- package/dist/{InputGroup-DcZRlVnN.js → InputGroup-Do8K2hvD.js} +2 -1
- package/dist/InputGroup-Do8K2hvD.js.map +1 -0
- package/dist/{Kbd-Cvvt91Q8.js → Kbd-LCFMumoq.js} +2 -2
- package/dist/{Kbd-Cvvt91Q8.js.map → Kbd-LCFMumoq.js.map} +1 -1
- package/dist/{MermaidDiagram-DSI7xMu2.js → MermaidDiagram-ZG0iiDV_.js} +2 -2
- package/dist/{MermaidDiagram-DSI7xMu2.js.map → MermaidDiagram-ZG0iiDV_.js.map} +1 -1
- package/dist/{Modal-Coj-H02o.js → Modal-I3VWk2oo.js} +2 -2
- package/dist/{Modal-Coj-H02o.js.map → Modal-I3VWk2oo.js.map} +1 -1
- package/dist/{ModalTitle-C76ke2eo.js → ModalTitle-CeLM_mX9.js} +2 -2
- package/dist/ModalTitle-CeLM_mX9.js.map +1 -0
- package/dist/{MultiActionButtonGroup-DokHbPgM.js → MultiActionButtonGroup-CYZ8IgSf.js} +2 -2
- package/dist/{MultiActionButtonGroup-DokHbPgM.js.map → MultiActionButtonGroup-CYZ8IgSf.js.map} +1 -1
- package/dist/{PageToolbar-DExqEYGl.js → PageToolbar-BKVJiDAL.js} +2 -2
- package/dist/{PageToolbar-DExqEYGl.js.map → PageToolbar-BKVJiDAL.js.map} +1 -1
- package/dist/{RadioGroup-DXPbSj8P.js → RadioGroup-Byc2mym4.js} +2 -2
- package/dist/{RadioGroup-DXPbSj8P.js.map → RadioGroup-Byc2mym4.js.map} +1 -1
- package/dist/{Search-5uQAiNIP.js → Search-Dhig_hPD.js} +2 -2
- package/dist/{Search-5uQAiNIP.js.map → Search-Dhig_hPD.js.map} +1 -1
- package/dist/{SearchInput-D4UgAXJK.js → SearchInput-92r2bkA7.js} +3 -3
- package/dist/{SearchInput-D4UgAXJK.js.map → SearchInput-92r2bkA7.js.map} +1 -1
- package/dist/{SectionNav-OkKCjSA-.js → SectionNav-CNLJsiVG.js} +4 -4
- package/dist/{SectionNav-OkKCjSA-.js.map → SectionNav-CNLJsiVG.js.map} +1 -1
- package/dist/{Sheet-Chf0kX1E.js → Sheet-OparjIi-.js} +2 -2
- package/dist/{Sheet-Chf0kX1E.js.map → Sheet-OparjIi-.js.map} +1 -1
- package/dist/{Sidebar-D3cY1kha.js → Sidebar-CLEbBtNY.js} +190 -25
- package/dist/Sidebar-CLEbBtNY.js.map +1 -0
- package/dist/{Slider-CRf-bB4y.js → Slider-DLclvRws.js} +2 -2
- package/dist/{Slider-CRf-bB4y.js.map → Slider-DLclvRws.js.map} +1 -1
- package/dist/{TextInput-DH5SkbsE.js → TextInput-CFTf4Cz1.js} +5 -4
- package/dist/TextInput-CFTf4Cz1.js.map +1 -0
- package/dist/{ThemeProvider-2RMdVGxO.js → ThemeProvider-DAmNn9Sd.js} +2 -2
- package/dist/{ThemeProvider-2RMdVGxO.js.map → ThemeProvider-DAmNn9Sd.js.map} +1 -1
- package/dist/{Timeline-BG5Xogxh.js → Timeline-C8-wnRRr.js} +2 -2
- package/dist/{Timeline-BG5Xogxh.js.map → Timeline-C8-wnRRr.js.map} +1 -1
- package/dist/{ZoomableSvg-pooPb1Cu.js → ZoomableSvg-BZlk3PFJ.js} +3 -3
- package/dist/{ZoomableSvg-pooPb1Cu.js.map → ZoomableSvg-BZlk3PFJ.js.map} +1 -1
- package/dist/editors.js +2 -2
- package/dist/flint.js +1 -1
- package/dist/index.d.ts +900 -561
- package/dist/index.js +39 -37
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChipEditor.js +137 -0
- package/dist/internal/blocks/ChipEditor.js.map +1 -0
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/ExportMenu.js +2 -2
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +18 -28
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +2 -2
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +1 -1
- package/dist/internal/blocks/TimeInput.js +2 -2
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/Badge.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +1 -1
- package/dist/internal/components/DropdownMenu.js +1 -1
- package/dist/internal/components/FileUpload.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Modal.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Sheet.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/StatusDot.js +67 -0
- package/dist/internal/components/StatusDot.js.map +1 -0
- package/dist/internal/components/ThemeProvider.js +1 -1
- package/dist/internal/components/Timeline.js +1 -1
- package/dist/internal/components/Tooltip.js +2 -2
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/hooks/useScrollbarPosition.js +1 -1
- package/dist/internal/utils/mergeRefs.js +27 -9
- package/dist/internal/utils/mergeRefs.js.map +1 -1
- package/dist/internal/utils.js +2 -2
- package/dist/markdown-editor.js +5 -5
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +9 -9
- package/dist/styles.css +1 -1
- package/dist/testing.js +1 -1
- package/dist/useElement-BK3AAiIf.js +24 -0
- package/dist/useElement-BK3AAiIf.js.map +1 -0
- package/dist/{utils-DSvrhU8E.js → utils-BW4AE8VP.js} +33 -7
- package/dist/utils-BW4AE8VP.js.map +1 -0
- package/package.json +14 -13
- package/dist/AIKit-BExvt9pt.js.map +0 -1
- package/dist/DropdownMenu-CASr-jgl.js.map +0 -1
- package/dist/InputGroup-DcZRlVnN.js.map +0 -1
- package/dist/ModalTitle-C76ke2eo.js.map +0 -1
- package/dist/Sidebar-D3cY1kha.js.map +0 -1
- package/dist/TextInput-DH5SkbsE.js.map +0 -1
- package/dist/useElement-DkF6esWL.js +0 -15
- package/dist/useElement-DkF6esWL.js.map +0 -1
- package/dist/utils-DSvrhU8E.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -97,7 +97,7 @@ This file answers **which** component to use; [`COMPONENT-API.md`](./COMPONENT-A
|
|
|
97
97
|
|
|
98
98
|
`FileUpload` composes `FileUpload.DropZone` (the dashed box, owning the drag / error visuals) with `FileUpload.FileList` (selected files; `invalid` tints the rows). It deliberately ships **no** rejection copy — the wording is product copy, so read the current rejections with `useFileUploadRejections()` inside `FileUpload` and write the sentence yourself. Reach for `useFileDropTarget` only when there is no box to render: it returns `getRootProps()` / `isDragActive` for an affordance you style, and `noClick` / `noKeyboard` keep an already-interactive subtree (a composer, a form) from opening the file dialog on every click.
|
|
99
99
|
|
|
100
|
-
**`InputGroup.Addon` (`align="inline-start"` / `"inline-end"`) keeps its own content width** — it no longer gives up space to the input, so a badge or a rendered selection stays fully visible instead of being squeezed to an ellipsis. Bound long, caller-controlled content yourself (a `max-w-[…] overflow-hidden` on the addon) if it isn't a fixed-size icon or button. `InputGroup`'s padding/sizing rules reach any descendant `input`/`textarea`, not just a direct child, so a consumer that wraps the input in its own layout (chips, an overlay) picks up that padding automatically — cancel it with `!px-0`/`!py-0` where the wrapping layout already owns its own edge padding (see `MultiCombobox`).
|
|
100
|
+
**`InputGroup.Addon` (`align="inline-start"` / `"inline-end"`) keeps its own content width** — it no longer gives up space to the input, so a badge or a rendered selection stays fully visible instead of being squeezed to an ellipsis. Bound long, caller-controlled content yourself (a `max-w-[…] overflow-hidden` on the addon) if it isn't a fixed-size icon or button. The exception is `TextInput`'s `rightSuffixVariant="addon"` suffix, which shrinks and ellipsizes inline content instead. `InputGroup`'s padding/sizing rules reach any descendant `input`/`textarea`, not just a direct child, so a consumer that wraps the input in its own layout (chips, an overlay) picks up that padding automatically — cancel it with `!px-0`/`!py-0` where the wrapping layout already owns its own edge padding (see `MultiCombobox`).
|
|
101
101
|
|
|
102
102
|
### Status surfaces
|
|
103
103
|
|
|
@@ -107,9 +107,16 @@ This file answers **which** component to use; [`COMPONENT-API.md`](./COMPONENT-A
|
|
|
107
107
|
| `Toaster` | Mount once at app root |
|
|
108
108
|
| `Alert` | Persistent contextual message in page layout |
|
|
109
109
|
| `FormGroup state="error"` | Field-level validation errors inline below input |
|
|
110
|
+
| `StatusDot` | One entity's state as a coloured dot beside its name |
|
|
110
111
|
|
|
111
112
|
**Never** use `Alert` for ephemeral success (use `toast()`) or `toast()` for blocking errors (use `Alert`).
|
|
112
113
|
|
|
114
|
+
**Never** paint a state with a hue of your own — no `tw:bg-amber-400` span, no `color` prop taking a
|
|
115
|
+
hue. `StatusDot`'s `status` (`success` / `warning` / `info` / `destructive` / `neutral`) is its whole
|
|
116
|
+
colour API, so it reads the themeable status tokens and a customer brand recolours every dot at once.
|
|
117
|
+
Colour never carries the meaning alone: pair the dot with the text, or give it a `label` so a screen
|
|
118
|
+
reader gets the state too.
|
|
119
|
+
|
|
113
120
|
### Loading
|
|
114
121
|
|
|
115
122
|
| Use | When |
|
|
@@ -230,6 +237,8 @@ Vertical rhythm: prefer `tw:gap-*` on a flex column parent over `tw:mt-*` on chi
|
|
|
230
237
|
|
|
231
238
|
**`SectionNav` is not `Sidebar`.** `Sidebar` is the app's left rail — global, one per shell, outside `PageLayout`, with `SidebarProvider` state and icon-collapse. `SectionNav` is scoped to a single page's sections, lives in `PageLayout.Content nav`, and holds nothing but an open/closed flag per group. Reach for `SectionNav` when a page has more sections than a tab row can hold, or sections that group; `Tabs` when they don't.
|
|
232
239
|
|
|
240
|
+
**`Sidebar` can become a `Sheet` under 768px — opt in per side.** `SidebarProvider` takes `leftMobileSheet` / `rightMobileSheet`; both default to off, because a `Sidebar` is also the shape of a container rail nested in a modal or a builder canvas, where a full-screen phone sheet means nothing. A side that opts in occupies no grid column below the breakpoint — the page takes the full width — and the rail opens as a sheet, with the focus trap, the Escape handling and the overlay that come with one. An app that opts in owes the sheet a way in: put a `Sidebar.Trigger` in the header and let it be the only one, since the provider swaps what `toggle` does and the same control collapses the column above the breakpoint and opens the sheet below it. Choosing a destination dismisses the sheet; a button that opens a popup or that is itself a `Sidebar.Trigger` does not. Read `isMobile` off `useSidebar(side)` only for a call site whose whole purpose is the collapse axis (a mode picker) — everything else composes unchanged, and a call site's own `mode` prop is never written. `keepMounted` and `mountAfterEnter` describe the column's transition and do not apply to a side that is a sheet — its content mounts on open and unmounts on close, so state worth surviving a close lives above the panel.
|
|
241
|
+
|
|
233
242
|
### Separators
|
|
234
243
|
|
|
235
244
|
| Use | When |
|
|
@@ -250,10 +259,16 @@ The `label` prop implies `orientation="horizontal"` — labels are not rendered
|
|
|
250
259
|
| `ColorInput` | Design-token-driven brand color picker |
|
|
251
260
|
| `Combobox` | Single selection from a searchable list |
|
|
252
261
|
| `MultiCombobox` | Multiple selections from a searchable list |
|
|
262
|
+
| `ChipEditor` | Several free-text values the user types — there is no list |
|
|
253
263
|
| `Select` | Single selection from a short enum (≤ ~10 options, no search) |
|
|
254
264
|
| `CodeEditor` | Generic code editing (JSON, YAML, shell) |
|
|
255
265
|
| `SqlEditor` | SQL editing (syntax + autocomplete) |
|
|
256
266
|
|
|
267
|
+
`ChipEditor` is the chip row without the popup — tags, feature flags, permitted email domains, any
|
|
268
|
+
list of strings the user writes rather than picks. A `MultiCombobox` with `allowCreate` is still the
|
|
269
|
+
right call the moment there is a list worth searching, even an open-ended one; **never** hand-roll an
|
|
270
|
+
input-plus-chips row from `InputGroup` + `Badge`.
|
|
271
|
+
|
|
257
272
|
`Select` is wrong above ~10 items — use `Combobox`. How richly the **selected** value has to render decides nothing here: both controls carry a rich selection (see below), so a short enum whose selection is a badge is still a `Select`. `CodeEditor`/`SqlEditor` load the full CodeMirror bundle and ship from the `@keboola/design/editors` subpath (not the root); reserve for real code editing.
|
|
258
273
|
|
|
259
274
|
#### Clear affordance
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
# @keboola/design
|
|
2
2
|
|
|
3
|
+
## 11.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- `InlineStepGroup` joins the AI Kit: the collapsible frame an assistant turn draws a run of steps in — header, animated collapse, and the connector rule the step icons mask themselves against. It takes the rows as children, so a product supplies its own vocabulary and its own step components; `surface` names the colour the icons mask against, for a transcript that does not sit on the page background.
|
|
8
|
+
|
|
9
|
+
A closed group is `inert` and `aria-hidden`: `grid-template-rows: 0fr` is layout only, so without them a screen reader reads out steps nobody can see and Tab lands inside a closed run. `CollapsibleStepHeader` carries its outcome as `data-variant` too — the outcome is otherwise carried by the icon's shape and ink alone, which no test and no E2E selector reads. The same outcome joins the header's accessible name as a short sr-only phrase, so a closed group announces how the run came out and not only what it was called.
|
|
10
|
+
|
|
11
|
+
The frame carries `role="group"` rather than the `<section>`'s own landmark semantics: a transcript draws one group per run of steps, so a long conversation would hand a screen reader a landmark list of dozens of identically named regions. A named `group` still announces its name, and it is the role the grounding panel already gives its repeated named answer sections.
|
|
12
|
+
|
|
13
|
+
- `Markdown` draws inline `icon:<name>` tokens, and `ChatInlineIcon` ships the name→Lucide registry behind them.
|
|
14
|
+
|
|
15
|
+
A Kai prompt teaches the model the `@keboola/agent-vocabulary` icon names, so any chat rendering its answers has to draw them — until now only kbc-ui could, from a fork of the map. The base `code` renderer turns an inline token into the icon it names and leaves every other inline code alone, and `getChatInlineIconName` + `ChatInlineIcon` are the seam for a caller that overrides `code` itself. Producing the token stays the app's: the remark plugin that finds bare `icon:…` text lives in `@keboola/kai-chat`. The glyph is `aria-hidden`: it replaces the token's text and carries no label of its own, so exposing it would announce an unnamed graphic ahead of every phrase it decorates. `icon:spinner` spins, which `MAINTAINING.md` makes part of the mapping rather than the caller's job — a still `Loader2` is an arc, and reads as a damaged ring rather than as waiting. A name the registry cannot draw is not a token: `getChatInlineIconName` answers `undefined` for it, so the code the author typed survives. A name that is only the start of one it can draw is the other state: an answer streams `icon:t`, `icon:ta`, `icon:tab` before `icon:table` lands, so that half-name draws nothing rather than flashing as a code chip that reflows the line. `Markdown` renders more than agent answers — vendor component descriptions, dashboard text widgets — and `icon:` is an ordinary way to name a property there.
|
|
16
|
+
|
|
17
|
+
- `SidebarProvider`'s `leftMobileSheet` / `rightMobileSheet` now take a width as well as a flag.
|
|
18
|
+
- `boolean` keeps the shared 768px breakpoint; a number names the width under which that side is a sheet.
|
|
19
|
+
- Per side, because the width at which a rail stops fitting is the rail's own — a 320px context panel beside a capped reading column runs out of room long before a navigation rail does.
|
|
20
|
+
|
|
21
|
+
## 11.8.1
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Keep a long `Modal.Header` description inside the modal frame
|
|
26
|
+
|
|
27
|
+
`ModalDescription` now breaks anywhere, like `ModalTitle` already did. The slot routinely carries an identifier — a Storage table id, a fully-qualified name — which offers no break opportunity and paints outside the frame at narrow viewports.
|
|
28
|
+
|
|
29
|
+
## 11.8.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- `AnswerActions` takes a `split` layout and an `actions` slot, so a chat can put the verdict under
|
|
34
|
+
the left edge of an answer and its own controls under the right.
|
|
35
|
+
|
|
36
|
+
It also takes `size`, `labels` and `confirmation`: a roomier row for a panel a reader sits in, the
|
|
37
|
+
noun the surface rates ("response" or "answer"), and a word back once the vote lands.
|
|
38
|
+
|
|
39
|
+
- `Sidebar` can become a `Sheet` under 768px, so a phone gets the page's full width.
|
|
40
|
+
- Opt-in per side on `SidebarProvider`: `leftMobileSheet` / `rightMobileSheet`, both off by default. A `Sidebar` is also the shape of a container rail nested in a modal or a builder canvas, where a full-screen phone sheet means nothing — so no existing call site changes until it asks.
|
|
41
|
+
- An opted-in side renders no grid column below the breakpoint — `calcEffectiveWidths` reports zero, and the shell's sidebar slot collapses. The rail opens as a `Sheet`, which brings the focus trap, the Escape handling and the overlay. Closing it returns focus to whatever opened it.
|
|
42
|
+
- `Sidebar.Trigger` opens and closes that sheet instead of toggling the collapse axis, so a header trigger is one control rather than a mobile fork. Choosing a destination closes the sheet; a menu button that opens a popup (`aria-haspopup` / `aria-expanded`) or that is wrapped in a `Sidebar.Trigger` does not.
|
|
43
|
+
- Above the breakpoint the rail behaves exactly as before: `mode`, `collapsible` and `variant` are untouched. Two things do change for every call site — `Sidebar.Trigger` now states `aria-expanded` on both axes (the sheet's open state on a phone, the column's mode above it), so a trigger child must not supply its own; and `mergeRefs` passes a callback ref's cleanup through instead of dropping it, which is what lets a merged ref release its element on React 19. On a rail that is currently a sheet the collapse axis has nothing to act on, so `setMode` is inert — a stored desktop preference survives the trip through a narrow viewport.
|
|
44
|
+
- New on the `useSidebar(side)` value: `isMobile`, `isMobileOpen`, `setMobileOpen`. New on `Sidebar`: `mobileTitle`, the sheet's accessible name (defaults to `Navigation` / `Side panel`).
|
|
45
|
+
|
|
46
|
+
- `PromptCommand` loses its `icon`: the `/` menu has not drawn one since its rows became label-and-description only, so the field was dead weight on every caller.
|
|
47
|
+
|
|
48
|
+
- `PromptInput` gains an `attachments` slot: images and chips already attached to a message, drawn in
|
|
49
|
+
rows above the text rather than crowded onto its first line. Both variants are columns now, and only
|
|
50
|
+
the line itself differs — `inline` keeps the prefix beside the text, `default` stacks the text over
|
|
51
|
+
its toolbar.
|
|
52
|
+
|
|
53
|
+
`PromptInput.MenuTrigger` is the composer's "add to message" button: a plus that rotates into a cross
|
|
54
|
+
while its menu is open, with `aria-expanded` following.
|
|
55
|
+
|
|
56
|
+
The `/` command popup opens below the composer when there is no room above it, is capped in width,
|
|
57
|
+
sentence-cased, and carries a close button. `DropdownMenu.SubTrigger` and `DropdownMenu.CheckboxItem`
|
|
58
|
+
accept an `icon` drawn through the same slot as `DropdownMenu.Item`, so a mixed menu keeps one icon
|
|
59
|
+
column and one icon colour.
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- `AnswerActions`: the recorded vote is green for thumbs up and red for thumbs down, instead of the same blue for both.
|
|
64
|
+
|
|
65
|
+
- Addon-variant `rightSuffix` now shrinks instead of forcing the row to overflow, truncating inline content with an ellipsis when the group is narrower than its content.
|
|
66
|
+
|
|
67
|
+
- `UsageStats`' ring is a `<button>`: it opens a card, so it takes a pointer and a focus ring, and it
|
|
68
|
+
answers the hover it has always responded to. Hosts that wrapped it in a control of their own would
|
|
69
|
+
now nest two — none in this repo does.
|
|
70
|
+
|
|
71
|
+
## 11.7.0
|
|
72
|
+
|
|
73
|
+
### Minor Changes
|
|
74
|
+
|
|
75
|
+
- `Tooltip` gains a `hintUnderline` prop that marks its trigger with the shared "this text has a tooltip" affordance — a dashed `neutral-300` underline at `underline-offset-2` with `cursor-help`. It works in both trigger modes, and leaves the trigger's own text colour alone so a coloured label keeps its colour. The same classes are exported as `HINT_UNDERLINE_CLASS_NAME` for triggers that are not a `Tooltip`.
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- `AnswerActions` takes an `onCopy` callback, so a host can record that a reader took an answer away.
|
|
80
|
+
|
|
81
|
+
- `MultiCombobox` renders the value itself when `itemToStringLabel` has no label for it, instead of throwing. The projection is typed to return a string but can still come up empty at runtime: Base UI reports the outgoing selection for the render after `items` and `itemToStringLabel` change together, so a chip is asked for a label the incoming projection cannot produce. That threw a `TypeError` out of `namedLabel` and took the surrounding page down with it.
|
|
82
|
+
|
|
83
|
+
- `InputGroup` can shrink below its content's intrinsic width instead of overflowing its row. A flex item's default `min-width: auto` floored the group at the width of its input plus its addons, so several side by side — a custom timeout's days/hours/minutes row — pushed past their container rather than sharing it. The group already clips its own content, and the input inside already carried `min-w-0`.
|
|
84
|
+
|
|
85
|
+
- Add `UsageBar` to the AI kit — a budget as a labelled row over a `Progress`, filling with what is spent and reading out what is left. `variant` is the host's to pass, so a surface whose product rules forbid a warning meter draws an untoned one.
|
|
86
|
+
|
|
87
|
+
- `UsageStats`' ring keeps its size in a flex row. It is a fixed `size-8` with no content to give, so a sibling carrying `shrink-0` — every `Button` — used to squash it first.
|
|
88
|
+
|
|
89
|
+
## 11.6.1
|
|
90
|
+
|
|
91
|
+
### Patch Changes
|
|
92
|
+
|
|
93
|
+
- `Tooltip` and `Badge` state their casing rule the way `Button` already did: standard case is the default, and only the legacy brands (`keboola-legacy-*`) uppercase the chrome. Read the other way round — an uppercase base with one opt-out per modern brand — the rule said nothing about a brand nobody had added yet, so a customer brand drew uppercase tooltips and badges over standard-case buttons.
|
|
94
|
+
|
|
3
95
|
## 11.6.0
|
|
4
96
|
|
|
5
97
|
### Minor Changes
|
package/COMPONENT-API.md
CHANGED
|
@@ -73,24 +73,24 @@ Source: `src/blocks/TextInput/TextInput.tsx`
|
|
|
73
73
|
|
|
74
74
|
> Bare input. Plus all native `<input>` attributes.
|
|
75
75
|
|
|
76
|
-
| Prop | Type | Required | Default | Description
|
|
77
|
-
| -------------------- | --------------------------------------------------------------- | -------- | --------- |
|
|
78
|
-
| `allowClear` | `boolean` | no | `false` |
|
|
79
|
-
| `defaultValue` | `string \| null` | no | — |
|
|
80
|
-
| `focusVariant` | `"off" \| "on" \| "default" \| null` | no | `default` |
|
|
81
|
-
| `leftSuffix` | `ReactNode` | no | `null` |
|
|
82
|
-
| `onClear` | `(() => void)` | no | — |
|
|
83
|
-
| `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`.
|
|
84
|
-
| `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`.
|
|
85
|
-
| `prefix` | `ReactNode` | no | `null` |
|
|
86
|
-
| `rightSuffix` | `ReactNode` | no | `null` |
|
|
87
|
-
| `rightSuffixVariant` | `"default" \| "addon"` | no | `default` |
|
|
88
|
-
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | `default` |
|
|
89
|
-
| `state` | `"warning" \| "error" \| "default" \| null` | no | `default` |
|
|
90
|
-
| `testId` | `string` | no | — |
|
|
91
|
-
| `type` | `"text" \| "email" \| "date" \| "password" \| "datetime-local"` | no | `text` |
|
|
92
|
-
| `value` | `string \| null` | no | — |
|
|
93
|
-
| `variant` | `"primary" \| "secondary" \| null` | no | — |
|
|
76
|
+
| Prop | Type | Required | Default | Description |
|
|
77
|
+
| -------------------- | --------------------------------------------------------------- | -------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `allowClear` | `boolean` | no | `false` | |
|
|
79
|
+
| `defaultValue` | `string \| null` | no | — | |
|
|
80
|
+
| `focusVariant` | `"off" \| "on" \| "default" \| null` | no | `default` | |
|
|
81
|
+
| `leftSuffix` | `ReactNode` | no | `null` | |
|
|
82
|
+
| `onClear` | `(() => void)` | no | — | |
|
|
83
|
+
| `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
|
|
84
|
+
| `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
|
|
85
|
+
| `prefix` | `ReactNode` | no | `null` | |
|
|
86
|
+
| `rightSuffix` | `ReactNode` | no | `null` | Content after the input. - `rightSuffixVariant="addon"` truncates it with an ellipsis when the group is narrower than its content. - The ellipsis only renders for inline content — pass text or a `<span>`, not a block element. |
|
|
87
|
+
| `rightSuffixVariant` | `"default" \| "addon"` | no | `default` | |
|
|
88
|
+
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | `default` | |
|
|
89
|
+
| `state` | `"warning" \| "error" \| "default" \| null` | no | `default` | |
|
|
90
|
+
| `testId` | `string` | no | — | |
|
|
91
|
+
| `type` | `"text" \| "email" \| "date" \| "password" \| "datetime-local"` | no | `text` | |
|
|
92
|
+
| `value` | `string \| null` | no | — | |
|
|
93
|
+
| `variant` | `"primary" \| "secondary" \| null` | no | — | |
|
|
94
94
|
|
|
95
95
|
### `PasswordInput`
|
|
96
96
|
|
|
@@ -148,23 +148,23 @@ Source: `src/blocks/FormGroup/FormGroupTextInput.tsx`
|
|
|
148
148
|
|
|
149
149
|
> NO `error` prop — error styling comes from the parent `FormGroup state="error"` via context. `state` is omitted from the surface for the same reason. Plus native `<input>` attributes.
|
|
150
150
|
|
|
151
|
-
| Prop | Type | Required | Default | Description
|
|
152
|
-
| -------------------- | --------------------------------------------------------------- | -------- | ------- |
|
|
153
|
-
| `allowClear` | `boolean` | no | — |
|
|
154
|
-
| `defaultValue` | `string \| null` | no | — |
|
|
155
|
-
| `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — |
|
|
156
|
-
| `leftSuffix` | `ReactNode` | no | — |
|
|
157
|
-
| `onClear` | `(() => void)` | no | — |
|
|
158
|
-
| `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`.
|
|
159
|
-
| `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`.
|
|
160
|
-
| `prefix` | `ReactNode` | no | — |
|
|
161
|
-
| `rightSuffix` | `ReactNode` | no | — |
|
|
162
|
-
| `rightSuffixVariant` | `"default" \| "addon"` | no | — |
|
|
163
|
-
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | — |
|
|
164
|
-
| `testId` | `string` | no | — |
|
|
165
|
-
| `type` | `"text" \| "email" \| "date" \| "password" \| "datetime-local"` | no | — |
|
|
166
|
-
| `value` | `string \| null` | no | — |
|
|
167
|
-
| `variant` | `"primary" \| "secondary" \| null` | no | — |
|
|
151
|
+
| Prop | Type | Required | Default | Description |
|
|
152
|
+
| -------------------- | --------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
153
|
+
| `allowClear` | `boolean` | no | — | |
|
|
154
|
+
| `defaultValue` | `string \| null` | no | — | |
|
|
155
|
+
| `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
|
|
156
|
+
| `leftSuffix` | `ReactNode` | no | — | |
|
|
157
|
+
| `onClear` | `(() => void)` | no | — | |
|
|
158
|
+
| `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
|
|
159
|
+
| `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
|
|
160
|
+
| `prefix` | `ReactNode` | no | — | |
|
|
161
|
+
| `rightSuffix` | `ReactNode` | no | — | Content after the input. - `rightSuffixVariant="addon"` truncates it with an ellipsis when the group is narrower than its content. - The ellipsis only renders for inline content — pass text or a `<span>`, not a block element. |
|
|
162
|
+
| `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
|
|
163
|
+
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
|
|
164
|
+
| `testId` | `string` | no | — | |
|
|
165
|
+
| `type` | `"text" \| "email" \| "date" \| "password" \| "datetime-local"` | no | — | |
|
|
166
|
+
| `value` | `string \| null` | no | — | |
|
|
167
|
+
| `variant` | `"primary" \| "secondary" \| null` | no | — | |
|
|
168
168
|
|
|
169
169
|
### `FormGroup.Help`
|
|
170
170
|
|
|
@@ -207,7 +207,7 @@ Source: `src/blocks/Form/connectors/TextField.tsx`
|
|
|
207
207
|
| `prefix` | `ReactNode` | no | — | |
|
|
208
208
|
| `required` | `boolean` | no | — | |
|
|
209
209
|
| `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'`. |
|
|
210
|
-
| `rightSuffix` | `ReactNode` | no | — |
|
|
210
|
+
| `rightSuffix` | `ReactNode` | no | — | Content after the input. - `rightSuffixVariant="addon"` truncates it with an ellipsis when the group is narrower than its content. - The ellipsis only renders for inline content — pass text or a `<span>`, not a block element. |
|
|
211
211
|
| `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
|
|
212
212
|
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
|
|
213
213
|
| `testId` | `string` | no | — | |
|
|
@@ -564,16 +564,17 @@ Source: `src/components/Sidebar/Sidebar.tsx`
|
|
|
564
564
|
|
|
565
565
|
> App-shell left navigation rail (host inside `AppShell.Sidebar`). Compound: `Sidebar.Header`, `Sidebar.Content`, `Sidebar.Footer`, `Sidebar.Menu`, `Sidebar.Group`, `Sidebar.SearchInput` (concrete `<input>`, no `asChild`).
|
|
566
566
|
|
|
567
|
-
| Prop | Type | Required | Default | Description
|
|
568
|
-
| ----------------- | --------------- | -------- | ------- |
|
|
569
|
-
| `className` | `string` | no | — |
|
|
570
|
-
| `container` | `boolean` | no | `false` |
|
|
571
|
-
| `id` | `string` | no | — |
|
|
572
|
-
| `keepMounted` | `boolean` | no | — |
|
|
573
|
-
| `
|
|
574
|
-
| `
|
|
575
|
-
| `
|
|
576
|
-
| `
|
|
567
|
+
| Prop | Type | Required | Default | Description |
|
|
568
|
+
| ----------------- | --------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
569
|
+
| `className` | `string` | no | — | |
|
|
570
|
+
| `container` | `boolean` | no | `false` | |
|
|
571
|
+
| `id` | `string` | no | — | |
|
|
572
|
+
| `keepMounted` | `boolean` | no | — | |
|
|
573
|
+
| `mobileTitle` | `string` | no | — | Accessible name for the sheet the rail becomes under the mobile breakpoint. - Defaults to `Navigation` on the left and `Side panel` on the right. - Rendered visually hidden — the sheet is a dialog and needs a name, but the rail's own header is already the visible one. |
|
|
574
|
+
| `mountAfterEnter` | `boolean` | no | — | Hold the panel's content back until it has finished sliding in. |
|
|
575
|
+
| `resizable` | `boolean` | no | `false` | |
|
|
576
|
+
| `side` | `SidebarSide` | no | `left` | |
|
|
577
|
+
| `style` | `CSSProperties` | no | — | |
|
|
577
578
|
|
|
578
579
|
### `SectionNav`
|
|
579
580
|
|
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ Worked examples: `src/components/Button/Button.stories.tsx` (click + disabled),
|
|
|
120
120
|
|
|
121
121
|
**Timing-sensitive:** `HoverCard` is the only test driven by a real `userEvent.hover` past a 200 ms open delay (its `findByText` carries a raised timeout). It passes headlessly today, but it's the most likely flake if CI is slow — `Tooltip` deliberately opens via keyboard focus to avoid this. Watch it when wiring CI.
|
|
122
122
|
|
|
123
|
-
**Runs in CI per-PR (
|
|
123
|
+
**Runs in CI per-PR and gates the merge (UT-4864).** The `.github/workflows/storybook-component-tests.yml` workflow runs the full suite, wired into `branch.yml` (the `story-tests` job) and gated on the same `detect-affected` design signal as the Storybook deploy — so it only runs when this package (or something it depends on) changes. The required status check is `Storybook story gate`, not the job itself: a reusable-workflow job publishes its check under a different name depending on whether it ran, so the gate job is what reports on every PR (`scripts/storybookStoryGate.mjs`). Browser mode isolates per file by default (~35 s/file on a 2-core runner — over an hour for the current 157 story files), so `vitest.config.ts` sets `isolate: false` + `fileParallelism: false` + `maxWorkers: 1` to reuse one browser context across files, and the workflow caches Vite's optimized deps to skip the ~27 s dep pre-bundling on warm runs — bringing the run down to a few minutes. If the suite ever exceeds ~5-6 min, the documented fallback is sharding across a job matrix (and/or full-suite nightly + changed-stories-only on PR). Measured over 526 executed runs in the week to 2026-09-17: job wall-clock p50 146 s / p90 161 s, of which the test step itself is 61 s — the rest is runner setup, so the suite has room to roughly quadruple before the budget bites. Sharding is not a free lever, though: `isolate: false` makes the run order-dependent, and resharding changes it. Before touching either, prove the suite still passes shuffled (`vitest run --config vitest.config.ts --sequence.shuffle=true`). Adding `@storybook/addon-a11y` for per-story accessibility checks is a separate follow-up.
|
|
124
124
|
|
|
125
125
|
#### Story-test coverage (UT-4189)
|
|
126
126
|
|