@keboola/design 11.5.0 → 11.6.1
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 +7 -6
- package/CHANGELOG.md +31 -0
- package/COMPONENT-API.md +5 -5
- package/dist/{AIKit-CNX6aiKm.js → AIKit-CQxVwyAk.js} +212 -38
- package/dist/AIKit-CQxVwyAk.js.map +1 -0
- package/dist/{Alert-Ba5b2YPq.js → Alert-C4Y9IwMI.js} +2 -2
- package/dist/{Alert-Ba5b2YPq.js.map → Alert-C4Y9IwMI.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-CS9P4r2p.js} +5 -5
- package/dist/{BrandEditor-CSANsxUz.js.map → BrandEditor-CS9P4r2p.js.map} +1 -1
- package/dist/{Breadcrumb-g_xn_-Nf.js → Breadcrumb-D1id7YXd.js} +2 -2
- package/dist/{Breadcrumb-g_xn_-Nf.js.map → Breadcrumb-D1id7YXd.js.map} +1 -1
- package/dist/{Checkbox-CUIn2jap.js → Checkbox-Bqr6zXcW.js} +2 -2
- package/dist/{Checkbox-CUIn2jap.js.map → Checkbox-Bqr6zXcW.js.map} +1 -1
- package/dist/{Clipboard-BTW6C-b_.js → Clipboard-C2YBRfD8.js} +2 -2
- package/dist/{Clipboard-BTW6C-b_.js.map → Clipboard-C2YBRfD8.js.map} +1 -1
- package/dist/{ClipboardButton-CwZJdRaz.js → ClipboardButton-CrljClL1.js} +2 -2
- package/dist/{ClipboardButton-CwZJdRaz.js.map → ClipboardButton-CrljClL1.js.map} +1 -1
- package/dist/{CodeEditor-C9zy7PxK.js → CodeEditor-C9AS8Ch0.js} +4 -4
- package/dist/{CodeEditor-C9zy7PxK.js.map → CodeEditor-C9AS8Ch0.js.map} +1 -1
- package/dist/{ColorInput-BZV-u_94.js → ColorInput-Dg87lKcR.js} +2 -2
- package/dist/{ColorInput-BZV-u_94.js.map → ColorInput-Dg87lKcR.js.map} +1 -1
- package/dist/{Combobox-BfIfaVMA.js → Combobox-BfanUAqY.js} +3 -3
- package/dist/{Combobox-BfIfaVMA.js.map → Combobox-BfanUAqY.js.map} +1 -1
- package/dist/{Command-Bfa1kpbt.js → Command-CqxoI_De.js} +2 -2
- package/dist/{Command-Bfa1kpbt.js.map → Command-CqxoI_De.js.map} +1 -1
- package/dist/{CopyField-DpT0Ngz1.js → CopyField-Rx9HPTbJ.js} +2 -2
- package/dist/{CopyField-DpT0Ngz1.js.map → CopyField-Rx9HPTbJ.js.map} +1 -1
- package/dist/{DateInput-DiEd5uCL.js → DateInput-DpifECUQ.js} +2 -2
- package/dist/{DateInput-DiEd5uCL.js.map → DateInput-DpifECUQ.js.map} +1 -1
- package/dist/{DateRangeInput-DPfVYchl.js → DateRangeInput-9MIw7P6L.js} +2 -2
- package/dist/{DateRangeInput-DPfVYchl.js.map → DateRangeInput-9MIw7P6L.js.map} +1 -1
- package/dist/DiagramSource-C5_d8Gdj.js +11 -0
- package/dist/DiagramSource-C5_d8Gdj.js.map +1 -0
- package/dist/{FieldItem-B7XMmZSz.js → FieldItem-DtPTzNef.js} +3 -3
- package/dist/{FieldItem-B7XMmZSz.js.map → FieldItem-DtPTzNef.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-DAaatlBk.js} +5 -5
- package/dist/{Form-CsttTHn4.js.map → Form-DAaatlBk.js.map} +1 -1
- package/dist/{FormGroup-DHvTFdno.js → FormGroup-Bl8JmnzJ.js} +3 -3
- package/dist/{FormGroup-DHvTFdno.js.map → FormGroup-Bl8JmnzJ.js.map} +1 -1
- package/dist/{FullScreenModal-BvPuYibe.js → FullScreenModal-CN9nAs72.js} +50 -2
- package/dist/FullScreenModal-CN9nAs72.js.map +1 -0
- package/dist/{Kbd-Cvvt91Q8.js → Kbd-D1Azcc4g.js} +2 -2
- package/dist/{Kbd-Cvvt91Q8.js.map → Kbd-D1Azcc4g.js.map} +1 -1
- package/dist/{MermaidDiagram-CXG5tC6J.js → MermaidDiagram-CujFxVzk.js} +4 -3
- package/dist/{MermaidDiagram-CXG5tC6J.js.map → MermaidDiagram-CujFxVzk.js.map} +1 -1
- package/dist/{MultiActionButtonGroup-DokHbPgM.js → MultiActionButtonGroup-CNNoBQbv.js} +2 -2
- package/dist/{MultiActionButtonGroup-DokHbPgM.js.map → MultiActionButtonGroup-CNNoBQbv.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-CUBsuP7r.js} +2 -2
- package/dist/{RadioGroup-DXPbSj8P.js.map → RadioGroup-CUBsuP7r.js.map} +1 -1
- package/dist/{Search-5uQAiNIP.js → Search-DVpJuzr9.js} +2 -2
- package/dist/{Search-5uQAiNIP.js.map → Search-DVpJuzr9.js.map} +1 -1
- package/dist/{SearchInput-D4UgAXJK.js → SearchInput-Q85p8Ews.js} +2 -2
- package/dist/{SearchInput-D4UgAXJK.js.map → SearchInput-Q85p8Ews.js.map} +1 -1
- package/dist/{SectionNav-OkKCjSA-.js → SectionNav-mpmSM3OC.js} +3 -3
- package/dist/{SectionNav-OkKCjSA-.js.map → SectionNav-mpmSM3OC.js.map} +1 -1
- package/dist/{Sidebar-D3cY1kha.js → Sidebar-CTWsHZhF.js} +2 -2
- package/dist/{Sidebar-D3cY1kha.js.map → Sidebar-CTWsHZhF.js.map} +1 -1
- package/dist/{Slider-CRf-bB4y.js → Slider-Bv0B6lI0.js} +2 -2
- package/dist/{Slider-CRf-bB4y.js.map → Slider-Bv0B6lI0.js.map} +1 -1
- package/dist/{TextInput-DH5SkbsE.js → TextInput-DiEMxVF6.js} +2 -2
- package/dist/{TextInput-DH5SkbsE.js.map → TextInput-DiEMxVF6.js.map} +1 -1
- package/dist/{ThemeProvider-2RMdVGxO.js → ThemeProvider-BI6JWBdJ.js} +2 -2
- package/dist/{ThemeProvider-2RMdVGxO.js.map → ThemeProvider-BI6JWBdJ.js.map} +1 -1
- package/dist/{ZoomableSvg-pooPb1Cu.js → ZoomableSvg-U_VH3QRO.js} +3 -3
- package/dist/{ZoomableSvg-pooPb1Cu.js.map → ZoomableSvg-U_VH3QRO.js.map} +1 -1
- package/dist/editors.js +2 -2
- package/dist/flint.js +3 -2
- package/dist/flint.js.map +1 -1
- package/dist/index.d.ts +358 -283
- package/dist/index.js +32 -32
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.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 +1 -1
- 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 +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +1 -1
- 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/TextInput.js +1 -1
- package/dist/internal/blocks/TimeInput.js +1 -1
- 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/FileUpload.js +1 -1
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Progress.js +3 -1
- package/dist/internal/components/Progress.js.map +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/ThemeProvider.js +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +1 -1
- package/dist/markdown-editor.js +4 -4
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +9 -9
- package/dist/styles.css +1 -1
- package/dist/{svgTransforms-C9njt92h.js → svgTransforms-CJAYPk7o.js} +2 -10
- package/dist/svgTransforms-CJAYPk7o.js.map +1 -0
- package/dist/testing.js +1 -1
- package/dist/{utils-DSvrhU8E.js → utils-DnkrFYqY.js} +3 -5
- package/dist/utils-DnkrFYqY.js.map +1 -0
- package/package.json +16 -16
- package/dist/AIKit-CNX6aiKm.js.map +0 -1
- package/dist/FullScreenModal-BvPuYibe.js.map +0 -1
- package/dist/svgTransforms-C9njt92h.js.map +0 -1
- package/dist/utils-DSvrhU8E.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -112,12 +112,13 @@ This file answers **which** component to use; [`COMPONENT-API.md`](./COMPONENT-A
|
|
|
112
112
|
|
|
113
113
|
### Loading
|
|
114
114
|
|
|
115
|
-
| Use
|
|
116
|
-
|
|
|
117
|
-
| `Skeleton`
|
|
118
|
-
| `SkeletonList`
|
|
119
|
-
| `Button isLoading`
|
|
120
|
-
| `DotsLoader`
|
|
115
|
+
| Use | When |
|
|
116
|
+
| ------------------- | -------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| `Skeleton` | Layout-aware placeholder shown in the slot the real content will occupy (initial load, refetch) |
|
|
118
|
+
| `SkeletonList` | Pre-composed list shell (icon + row, repeated) for Table / Card-list pages |
|
|
119
|
+
| `Button isLoading` | In-flight action on a known button — swaps the icon for a spinner and disables the button |
|
|
120
|
+
| `DotsLoader` | Indeterminate background work without a layout slot (small inline progress signal) |
|
|
121
|
+
| `ThinkingIndicator` | An agent turn that is in flight with nothing to show yet — every Keboola chat says it the same way |
|
|
121
122
|
|
|
122
123
|
**Never** build a new "Loader" / "BoxLoader" / "ActionLoader" wrapper component. Compose `Skeleton` directly into the slot the real content will occupy.
|
|
123
124
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @keboola/design
|
|
2
2
|
|
|
3
|
+
## 11.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- `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.
|
|
8
|
+
|
|
9
|
+
## 11.6.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- `MarkdownTable` ships from `AIKit`: a table in an answer with the fact that it is cut off on the right said out loud. It draws a rail above the grid for the host's own actions, a fade at the cut edge that clears at the end of the scroll, and — once the table is past 1.5× the width it has — an `Open wider` action. Where wider leads is the host's: the action is a prop (`onExpand`), so a docked panel can hand it its own fullscreen switch and a standalone app a modal, and a host with nowhere wider to go omits it and keeps the fade. `surface` names the token the host paints behind the table (`card`, the default, or `background`), which is the colour the fade ends in — naming the wrong one draws a contrasting strip over the cells instead of hiding them. The table passed in has to keep its intrinsic width (`tw:min-w-max`): `Table` is `w-full` with auto layout, so a grid left to wrap into its column never overflows and neither affordance can appear.
|
|
14
|
+
|
|
15
|
+
`FullScreenModal` now moves focus into itself when it opens and returns it on close. Its `onEscapeKeyDown` is a `keydown` on the modal element, so until focus was inside, Escape reached nothing and keyboard readers went on walking the page behind. Focus is left alone where the modal's own content has already claimed it, and Escape is now answered only by the modal it was pressed in — a nested modal is portalled beside its parent but React routes its events up the logical tree, so one keypress used to dismiss both. Which modal that is comes off the DOM, where the nesting is not a lie, rather than from `stopPropagation`: a synthetic `stopPropagation` also stops the native event, and React mounts a portal's listeners on `document.body`, so it would cut off every `document`-level `keydown` handler on the page. This is not yet a focus trap: Tab still leaves for the obscured page.
|
|
16
|
+
|
|
17
|
+
- `Progress` gains `warning` and `error` variants, on the same ramps `Badge` maps `orange` and `red` to, so a meter can carry the state its label already names
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- `ThinkingIndicator` now announces itself as a live region, so a screen reader hears that an agent's turn is in flight rather than only seeing the spinner.
|
|
22
|
+
|
|
23
|
+
- Retry a failed diagram chunk instead of rendering source for the rest of the session
|
|
24
|
+
|
|
25
|
+
`Markdown` loaded `MermaidDiagram` and `FlintChart` through `lazy()`, which memoizes the settled
|
|
26
|
+
import for the life of the page. One failed fetch — a dev server restarting, a stale tab after a
|
|
27
|
+
deploy, a flaky network — left every later `mermaid` and `flint` fence in that tab rendering as
|
|
28
|
+
raw source until a full reload. The import is now attempted per mount and the failed promise is
|
|
29
|
+
cleared, and a block that fell back to source carries a Try again button — so one bad fetch costs
|
|
30
|
+
that one block rather than the session.
|
|
31
|
+
|
|
32
|
+
- `formatPercentage` prints whole numbers from 1% up, keeping one decimal only below 1%
|
|
33
|
+
|
|
3
34
|
## 11.5.0
|
|
4
35
|
|
|
5
36
|
### Minor Changes
|
package/COMPONENT-API.md
CHANGED
|
@@ -637,11 +637,11 @@ Source: `src/components/Progress/Progress.tsx`
|
|
|
637
637
|
|
|
638
638
|
> Single-value determinate progress bar.
|
|
639
639
|
|
|
640
|
-
| Prop | Type
|
|
641
|
-
| --------- |
|
|
642
|
-
| `asChild` | `boolean`
|
|
643
|
-
| `size` | `"sm" \| "lg" \| null`
|
|
644
|
-
| `variant` | `"success" \| "default" \| null` | no | — | |
|
|
640
|
+
| Prop | Type | Required | Default | Description |
|
|
641
|
+
| --------- | -------------------------------------------------------- | -------- | ------- | ----------- |
|
|
642
|
+
| `asChild` | `boolean` | no | — | |
|
|
643
|
+
| `size` | `"sm" \| "lg" \| null` | no | — | |
|
|
644
|
+
| `variant` | `"warning" \| "error" \| "success" \| "default" \| null` | no | — | |
|
|
645
645
|
|
|
646
646
|
### `SpotlightBackdrop`
|
|
647
647
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { Tooltip, TooltipProvider } from "./utils-
|
|
2
|
+
import { Tooltip, TooltipProvider } from "./utils-DnkrFYqY.js";
|
|
3
3
|
import { AlertCircle, ChevronDown, ChevronLeft, ChevronRight, CircleCheck, CirclePause, CircleX, Loader2, Maximize2, Minimize2, Play, Send, Sparkles, ThumbsDown, ThumbsUp, TriangleAlert, X, XCircle } from "./icons-Cek151jC.js";
|
|
4
4
|
import { Button } from "./Button-DsRrU5F1.js";
|
|
5
5
|
import { ButtonGroup } from "./internal/components/ButtonGroup.js";
|
|
6
|
-
import { ClipboardButton } from "./ClipboardButton-
|
|
7
|
-
import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-
|
|
6
|
+
import { ClipboardButton } from "./ClipboardButton-CrljClL1.js";
|
|
7
|
+
import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-CN9nAs72.js";
|
|
8
8
|
import { Truncated } from "./internal/components/Truncated.js";
|
|
9
9
|
import { HoverCard } from "./HoverCard-B9ZMJxjn.js";
|
|
10
|
-
import { Command } from "./Command-
|
|
11
|
-
import { TextInput } from "./TextInput-
|
|
12
|
-
import { Checkbox } from "./Checkbox-
|
|
13
|
-
import { Badge } from "./Badge-
|
|
10
|
+
import { Command } from "./Command-CqxoI_De.js";
|
|
11
|
+
import { TextInput } from "./TextInput-DiEMxVF6.js";
|
|
12
|
+
import { Checkbox } from "./Checkbox-Bqr6zXcW.js";
|
|
13
|
+
import { Badge } from "./Badge-o5jURtpB.js";
|
|
14
14
|
import { Textarea } from "./internal/blocks/Textarea.js";
|
|
15
15
|
import { Table } from "./Table-CvYuTuNU.js";
|
|
16
16
|
import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
|
|
17
|
+
import { DiagramSource } from "./DiagramSource-C5_d8Gdj.js";
|
|
17
18
|
import { Progress } from "./internal/components/Progress.js";
|
|
18
19
|
import { Slot } from "@radix-ui/react-slot";
|
|
19
|
-
import {
|
|
20
|
+
import { isValidElement, useCallback, useEffect, useId, useRef, useState } from "react";
|
|
20
21
|
import { cva } from "class-variance-authority";
|
|
21
22
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
22
23
|
import TextareaAutosize from "react-textarea-autosize";
|
|
@@ -188,15 +189,84 @@ const AnswerSummary = ({ items, variant = "success", noAnswerLabel = "No answer"
|
|
|
188
189
|
});
|
|
189
190
|
};
|
|
190
191
|
//#endregion
|
|
192
|
+
//#region src/blocks/AIKit/DiagramBlock.tsx
|
|
193
|
+
/**
|
|
194
|
+
* One diagram block: a skeleton while its chunk loads, the fence source plus a retry if it fails.
|
|
195
|
+
*
|
|
196
|
+
* - `load` runs once per mount and once per press of the retry button. The loader drops its own
|
|
197
|
+
* rejected promise, so every attempt is a fresh fetch.
|
|
198
|
+
* - Recovery is a gesture, not a timer: nothing on the page can tell when a chunk became
|
|
199
|
+
* reachable again, and a tab left open across a deploy points at a URL that is gone for good —
|
|
200
|
+
* a background loop would retry that one forever.
|
|
201
|
+
* - The failure is already logged by the loader, which knows the chunk's name.
|
|
202
|
+
* - A new `load` resets the block: every fence renders this same component type, so a block that
|
|
203
|
+
* switches dialect would otherwise keep drawing through the dialect it had before.
|
|
204
|
+
* - Both the renderer and the loader are functions held in state, so they go in through the
|
|
205
|
+
* setter form — React runs a bare function as a lazy initializer or an updater instead.
|
|
206
|
+
*/
|
|
207
|
+
const DiagramBlock = ({ load, code }) => {
|
|
208
|
+
const [Diagram, setDiagram] = useState(null);
|
|
209
|
+
const [failed, setFailed] = useState(false);
|
|
210
|
+
const [attempt, setAttempt] = useState(0);
|
|
211
|
+
const [prevLoad, setPrevLoad] = useState(() => load);
|
|
212
|
+
if (load !== prevLoad) {
|
|
213
|
+
setPrevLoad(() => load);
|
|
214
|
+
setDiagram(null);
|
|
215
|
+
setFailed(false);
|
|
216
|
+
}
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
let cancelled = false;
|
|
219
|
+
load().then((component) => {
|
|
220
|
+
if (!cancelled) setDiagram(() => component);
|
|
221
|
+
}, () => {
|
|
222
|
+
if (!cancelled) setFailed(true);
|
|
223
|
+
});
|
|
224
|
+
return () => {
|
|
225
|
+
cancelled = true;
|
|
226
|
+
};
|
|
227
|
+
}, [load, attempt]);
|
|
228
|
+
if (Diagram) return /* @__PURE__ */ jsx(Diagram, { code });
|
|
229
|
+
if (failed) return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(DiagramSource, { code }), /* @__PURE__ */ jsx(Button, {
|
|
230
|
+
variant: "inline",
|
|
231
|
+
size: "small",
|
|
232
|
+
className: "tw:mb-3",
|
|
233
|
+
onClick: () => {
|
|
234
|
+
setFailed(false);
|
|
235
|
+
setAttempt((count) => count + 1);
|
|
236
|
+
},
|
|
237
|
+
children: "Try again"
|
|
238
|
+
})] });
|
|
239
|
+
return /* @__PURE__ */ jsx(DiagramSkeleton, {});
|
|
240
|
+
};
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/blocks/AIKit/diagramChunk.ts
|
|
243
|
+
/**
|
|
244
|
+
* An on-demand diagram chunk — shared between mounts, and retryable.
|
|
245
|
+
*
|
|
246
|
+
* - `lazy()` is deliberately not used here: it memoizes the settled import for the life of the
|
|
247
|
+
* page, so one failed fetch (a dev server restarting, a stale tab after a deploy, a flaky
|
|
248
|
+
* network) leaves every diagram in that tab rendering raw source until a full reload.
|
|
249
|
+
* - A resolved import is kept, so the chunk is fetched once however many blocks mount.
|
|
250
|
+
* - A failed one is cleared, so the next mount imports again. Same contract as
|
|
251
|
+
* `getFlintRuntime()` one level down, inside `FlintChart`.
|
|
252
|
+
* - The failure is logged here, where the chunk's name is known, so the swap to plain source is
|
|
253
|
+
* never silent and a retry that fails again says so.
|
|
254
|
+
*/
|
|
255
|
+
const diagramChunk = (name, load) => {
|
|
256
|
+
let pending = null;
|
|
257
|
+
return () => {
|
|
258
|
+
pending ??= load().catch((error) => {
|
|
259
|
+
console.error(`[AIKit] failed to load the ${name} chunk`, error);
|
|
260
|
+
pending = null;
|
|
261
|
+
throw error;
|
|
262
|
+
});
|
|
263
|
+
return pending;
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
191
267
|
//#region src/blocks/AIKit/Markdown.tsx
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
return { default: ({ code }) => /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: code }) }) };
|
|
195
|
-
}));
|
|
196
|
-
const FlintChart = lazy(() => import("@keboola/design/flint").then((module) => ({ default: module.FlintChart }), (error) => {
|
|
197
|
-
console.error("[AIKit] failed to load the FlintChart chunk", error);
|
|
198
|
-
return { default: ({ code }) => /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: code }) }) };
|
|
199
|
-
}));
|
|
268
|
+
const loadMermaid = diagramChunk("MermaidDiagram", () => import("@keboola/design/mermaid").then((module) => module.MermaidDiagram));
|
|
269
|
+
const loadFlint = diagramChunk("FlintChart", () => import("@keboola/design/flint").then((module) => module.FlintChart));
|
|
200
270
|
const proseClass = "tw:prose tw:prose-sm tw:max-w-none tw:break-words tw:[&_pre]:bg-muted tw:[&_pre]:text-foreground tw:[&_:not(pre)>code]:bg-muted tw:[&_:not(pre)>code]:text-foreground tw:[&_:not(pre)>code]:rounded tw:[&_:not(pre)>code]:px-1 tw:[&_:not(pre)>code]:py-0.5 tw:[&_:not(pre)>code]:before:content-none tw:[&_:not(pre)>code]:after:content-none";
|
|
201
271
|
const getText = (node) => {
|
|
202
272
|
if (typeof node === "string") return node;
|
|
@@ -221,7 +291,7 @@ const getLanguage = (element) => {
|
|
|
221
291
|
*/
|
|
222
292
|
const baseRemarkPlugins = [remarkGfm];
|
|
223
293
|
/**
|
|
224
|
-
* Fence language → the
|
|
294
|
+
* Fence language → the on-demand chunk that draws it.
|
|
225
295
|
*
|
|
226
296
|
* - Both dialects are the agent's, not this package's: kai-agent's prompt tells the model to
|
|
227
297
|
* write ```mermaid for structure and ```flint for quantitative data, so a chat that renders
|
|
@@ -229,13 +299,13 @@ const baseRemarkPlugins = [remarkGfm];
|
|
|
229
299
|
* - `flint-chart` is an alias — it is the fence tag flint's own docs use, so a model emits it
|
|
230
300
|
* unprompted often enough to matter. `markdownComponents.tsx` in kbc-ui carries the same pair.
|
|
231
301
|
* - Read through `Object.hasOwn`, never by plain index: a fence tagged ```constructor or
|
|
232
|
-
* ```valueOf otherwise answers with an `Object.prototype` member, which is truthy, and
|
|
233
|
-
* it as a
|
|
302
|
+
* ```valueOf otherwise answers with an `Object.prototype` member, which is truthy, and calling
|
|
303
|
+
* it as a loader throws — taking the whole message subtree down with it.
|
|
234
304
|
*/
|
|
235
|
-
const
|
|
236
|
-
mermaid:
|
|
237
|
-
flint:
|
|
238
|
-
"flint-chart":
|
|
305
|
+
const DIAGRAM_CHUNKS = {
|
|
306
|
+
mermaid: loadMermaid,
|
|
307
|
+
flint: loadFlint,
|
|
308
|
+
"flint-chart": loadFlint
|
|
239
309
|
};
|
|
240
310
|
/**
|
|
241
311
|
* The fence languages this renderer draws instead of printing.
|
|
@@ -247,18 +317,18 @@ const DIAGRAM_RENDERERS = {
|
|
|
247
317
|
* - Frozen, because it is that shared contract: a consumer that pushed onto it would change how
|
|
248
318
|
* every other app in the same bundle holds a fence back.
|
|
249
319
|
*/
|
|
250
|
-
const DIAGRAM_LANGUAGES = Object.freeze(Object.keys(
|
|
320
|
+
const DIAGRAM_LANGUAGES = Object.freeze(Object.keys(DIAGRAM_CHUNKS));
|
|
251
321
|
const baseComponents = {
|
|
252
322
|
pre({ children, ...props }) {
|
|
253
323
|
const child = Array.isArray(children) ? children[0] : children;
|
|
254
324
|
const code = getText(child).replace(/\n$/, "");
|
|
255
325
|
const language = getLanguage(child);
|
|
256
|
-
const
|
|
257
|
-
if (
|
|
326
|
+
const load = language !== void 0 && Object.hasOwn(DIAGRAM_CHUNKS, language) ? DIAGRAM_CHUNKS[language] : void 0;
|
|
327
|
+
if (load) {
|
|
258
328
|
if (!code.trim()) return null;
|
|
259
|
-
return /* @__PURE__ */ jsx(
|
|
260
|
-
|
|
261
|
-
|
|
329
|
+
return /* @__PURE__ */ jsx(DiagramBlock, {
|
|
330
|
+
load,
|
|
331
|
+
code
|
|
262
332
|
});
|
|
263
333
|
}
|
|
264
334
|
const { node: _node, ...rest } = props;
|
|
@@ -343,6 +413,95 @@ const Markdown = ({ children, className, remarkPlugins, components: componentOve
|
|
|
343
413
|
});
|
|
344
414
|
};
|
|
345
415
|
//#endregion
|
|
416
|
+
//#region src/blocks/AIKit/MarkdownTable.tsx
|
|
417
|
+
/** How much wider than its column a table has to be before the column is the wrong surface. */
|
|
418
|
+
const EXPAND_RATIO = 1.5;
|
|
419
|
+
/**
|
|
420
|
+
* The token the host paints the table on, which is the colour the fade has to end in.
|
|
421
|
+
*
|
|
422
|
+
* - A gradient hides the cut-off cells by ending in the surface behind them. End it in any other
|
|
423
|
+
* token and it draws a contrasting strip over the data instead of hiding it.
|
|
424
|
+
* - Full class strings, not a composed `tw:from-${token}`: Tailwind reads literals.
|
|
425
|
+
*/
|
|
426
|
+
const FADE_SURFACE = {
|
|
427
|
+
card: "tw:from-card",
|
|
428
|
+
background: "tw:from-background"
|
|
429
|
+
};
|
|
430
|
+
/**
|
|
431
|
+
* A table in an answer, with the fact that it is cut off on the right said out loud.
|
|
432
|
+
*
|
|
433
|
+
* - `overflow-x: auto` scrolls silently, so nothing on screen says there is more to the right.
|
|
434
|
+
* - The controls sit in a rail above the grid, never over the header row or the last row — the
|
|
435
|
+
* data a reader reaches for them to get at. The rail holds its height, so revealing hover
|
|
436
|
+
* controls or crossing the ratio cannot shift the table under the pointer.
|
|
437
|
+
* - The fade marks the cut edge only while content remains, so it never reads as a border.
|
|
438
|
+
* - A painted gradient rather than the `tw:scroll-fade-x` mask, which needs scroll-driven
|
|
439
|
+
* animations: the build floor is `baseline-widely-available` (Safari 16, Firefox 104), and there
|
|
440
|
+
* the utility either fades both edges of a table that fits or, behind the `supports-` guard
|
|
441
|
+
* `PageLayout` uses, says nothing at all — which is the state this component exists to end. The
|
|
442
|
+
* mask also has to sit on the scrolling element, and that is `Table`'s own container, not ours.
|
|
443
|
+
* - Past `EXPAND_RATIO` the fade is joined by `onExpand`'s action, drawn without waiting for a
|
|
444
|
+
* hover: it reports that content is cut off, which the reader needs before going looking.
|
|
445
|
+
*/
|
|
446
|
+
const MarkdownTable = ({ children, actions, onExpand, surface = "card", className }) => {
|
|
447
|
+
const frameRef = useRef(null);
|
|
448
|
+
const [overflow, setOverflow] = useState({
|
|
449
|
+
scrollable: false,
|
|
450
|
+
atEnd: true,
|
|
451
|
+
ratio: 1
|
|
452
|
+
});
|
|
453
|
+
const measure = useCallback(() => {
|
|
454
|
+
const box = frameRef.current?.firstElementChild;
|
|
455
|
+
if (!box) return;
|
|
456
|
+
const { scrollLeft, scrollWidth, clientWidth } = box;
|
|
457
|
+
const hidden = scrollWidth - clientWidth;
|
|
458
|
+
setOverflow({
|
|
459
|
+
scrollable: hidden > 1,
|
|
460
|
+
atEnd: scrollLeft >= hidden - 1,
|
|
461
|
+
ratio: clientWidth > 0 ? scrollWidth / clientWidth : 1
|
|
462
|
+
});
|
|
463
|
+
}, []);
|
|
464
|
+
useEffect(() => {
|
|
465
|
+
const box = frameRef.current?.firstElementChild;
|
|
466
|
+
if (!box) return;
|
|
467
|
+
measure();
|
|
468
|
+
box.addEventListener("scroll", measure, { passive: true });
|
|
469
|
+
const observer = new ResizeObserver(measure);
|
|
470
|
+
observer.observe(box);
|
|
471
|
+
if (box.firstElementChild) observer.observe(box.firstElementChild);
|
|
472
|
+
return () => {
|
|
473
|
+
box.removeEventListener("scroll", measure);
|
|
474
|
+
observer.disconnect();
|
|
475
|
+
};
|
|
476
|
+
}, [measure]);
|
|
477
|
+
const showExpand = !!onExpand && overflow.scrollable && overflow.ratio >= EXPAND_RATIO;
|
|
478
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
479
|
+
className,
|
|
480
|
+
children: [(actions || onExpand) && /* @__PURE__ */ jsxs("div", {
|
|
481
|
+
className: "tw:flex tw:h-8 tw:items-center tw:justify-end tw:gap-1",
|
|
482
|
+
children: [actions, showExpand && /* @__PURE__ */ jsx(Tooltip, {
|
|
483
|
+
tooltip: "This table is wider than the space it has",
|
|
484
|
+
placement: "top",
|
|
485
|
+
triggerAsChild: true,
|
|
486
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
487
|
+
size: "small",
|
|
488
|
+
variant: "invisible",
|
|
489
|
+
onClick: onExpand,
|
|
490
|
+
children: [/* @__PURE__ */ jsx(Maximize2, { className: "tw:size-3.5" }), "Open wider"]
|
|
491
|
+
})
|
|
492
|
+
})]
|
|
493
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
494
|
+
ref: frameRef,
|
|
495
|
+
className: "tw:relative",
|
|
496
|
+
children: [children, overflow.scrollable && !overflow.atEnd && /* @__PURE__ */ jsx("span", {
|
|
497
|
+
"aria-hidden": true,
|
|
498
|
+
"data-testid": "markdown-table-fade",
|
|
499
|
+
className: cn("tw:pointer-events-none tw:absolute tw:inset-y-px tw:right-px tw:w-12 tw:rounded-r-[10px] tw:bg-gradient-to-l tw:to-transparent", FADE_SURFACE[surface])
|
|
500
|
+
})]
|
|
501
|
+
})]
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
//#endregion
|
|
346
505
|
//#region src/blocks/AIKit/MessageBubble.tsx
|
|
347
506
|
const containerClasses = cva([
|
|
348
507
|
"tw:flex",
|
|
@@ -1248,11 +1407,24 @@ const SuggestedPrompt = ({ label, disabled, onClick, icon, className }) => {
|
|
|
1248
1407
|
};
|
|
1249
1408
|
//#endregion
|
|
1250
1409
|
//#region src/blocks/AIKit/ThinkingIndicator.tsx
|
|
1410
|
+
/**
|
|
1411
|
+
* The agent's turn is in flight and has nothing to show yet.
|
|
1412
|
+
*
|
|
1413
|
+
* - Quiet chrome, matching the step rows it precedes (muted ink, no italic), so the hand-off
|
|
1414
|
+
* from "Thinking..." to the first step is seamless.
|
|
1415
|
+
* - `role="status"` because a spinner is silence to a screen reader, and for much of a turn
|
|
1416
|
+
* this is all a transcript shows. The label is the announcement, so it is never decorative.
|
|
1417
|
+
* - The icon is hidden from the tree: it says the same thing as the label beside it.
|
|
1418
|
+
*/
|
|
1251
1419
|
const ThinkingIndicator = ({ label = "Thinking..." }) => {
|
|
1252
1420
|
return /* @__PURE__ */ jsxs("div", {
|
|
1253
1421
|
className: "tw:flex tw:items-center tw:gap-1.5",
|
|
1422
|
+
role: "status",
|
|
1254
1423
|
"data-testid": "chat-thinking-indicator",
|
|
1255
|
-
children: [/* @__PURE__ */ jsx(Loader2, {
|
|
1424
|
+
children: [/* @__PURE__ */ jsx(Loader2, {
|
|
1425
|
+
"aria-hidden": true,
|
|
1426
|
+
className: "tw:size-3.5 tw:animate-spin tw:text-muted-foreground"
|
|
1427
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1256
1428
|
className: "tw:text-xs tw:font-medium tw:text-muted-foreground",
|
|
1257
1429
|
children: label
|
|
1258
1430
|
})]
|
|
@@ -1470,16 +1642,18 @@ const ToolCallStatusHeader = ({ icon: IconComponent, iconSpin, status, text, nee
|
|
|
1470
1642
|
*/
|
|
1471
1643
|
const clampPercentage = (value) => Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;
|
|
1472
1644
|
/**
|
|
1473
|
-
* A percentage as text — `72%`, `
|
|
1645
|
+
* A percentage as text — `72%`, `0.2%`, `99%`.
|
|
1474
1646
|
*
|
|
1475
|
-
* -
|
|
1476
|
-
* -
|
|
1647
|
+
* - Whole numbers from 1% up; a decimal only below 1%, where rounding would read as `0%`.
|
|
1648
|
+
* - A non-zero share never prints as `0.0%` — it floors at `0.1%`.
|
|
1649
|
+
* - Never `100%` for a value under 100: the text would disagree with the at-limit state computed
|
|
1477
1650
|
* from the raw value, exactly at the boundary everything else turns on.
|
|
1478
|
-
* - The `1e-9` nudge is for floating-point noise — `11 / 1000 * 100` is `1.0999999999999999`.
|
|
1479
1651
|
*/
|
|
1480
1652
|
const formatPercentage = (value) => {
|
|
1481
|
-
const
|
|
1482
|
-
|
|
1653
|
+
const oneDecimal = Math.round(value * 10) / 10;
|
|
1654
|
+
if (value > 0 && oneDecimal < 1) return `${Math.max(.1, oneDecimal).toFixed(1)}%`;
|
|
1655
|
+
const rounded = Math.round(value);
|
|
1656
|
+
return `${value < 100 ? Math.min(rounded, 99) : rounded}%`;
|
|
1483
1657
|
};
|
|
1484
1658
|
//#endregion
|
|
1485
1659
|
//#region src/blocks/AIKit/UsageStatsRing.tsx
|
|
@@ -1541,6 +1715,6 @@ const UsageStats = ({ value, alert = false, children, className, ariaLabel, alig
|
|
|
1541
1715
|
});
|
|
1542
1716
|
};
|
|
1543
1717
|
//#endregion
|
|
1544
|
-
export { AnswerActions, AnswerSummary, CollapsibleStepHeader, DIAGRAM_LANGUAGES, InlineStepDetail, InlineStepLabel, Markdown, MessageBubble, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageStats, UsageStatsRing, clampPercentage, formatPercentage };
|
|
1718
|
+
export { AnswerActions, AnswerSummary, CollapsibleStepHeader, DIAGRAM_LANGUAGES, InlineStepDetail, InlineStepLabel, Markdown, MarkdownTable, MessageBubble, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageStats, UsageStatsRing, clampPercentage, formatPercentage };
|
|
1545
1719
|
|
|
1546
|
-
//# sourceMappingURL=AIKit-
|
|
1720
|
+
//# sourceMappingURL=AIKit-CQxVwyAk.js.map
|