@keboola/design 11.4.0 → 11.6.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 +198 -7
- package/CHANGELOG.md +383 -0
- package/COMPONENT-API.md +73 -52
- package/dist/{AIKit-DDg5DBCG.js → AIKit-BExvt9pt.js} +390 -70
- package/dist/AIKit-BExvt9pt.js.map +1 -0
- package/dist/{Alert-DHJFrWnS.js → Alert-Ba5b2YPq.js} +2 -2
- package/dist/{Alert-DHJFrWnS.js.map → Alert-Ba5b2YPq.js.map} +1 -1
- package/dist/{Badge-Ch26CXoP.js → Badge-D0pXdekt.js} +2 -2
- package/dist/Badge-D0pXdekt.js.map +1 -0
- package/dist/{BrandEditor-Go7w8Zj2.js → BrandEditor-CSANsxUz.js} +6 -6
- package/dist/{BrandEditor-Go7w8Zj2.js.map → BrandEditor-CSANsxUz.js.map} +1 -1
- package/dist/{BrandLogo-Dmi7jo21.js → BrandLogo-CoKBk4MI.js} +4 -4
- package/dist/BrandLogo-CoKBk4MI.js.map +1 -0
- package/dist/{Breadcrumb-uEkM6adI.js → Breadcrumb-g_xn_-Nf.js} +2 -2
- package/dist/{Breadcrumb-uEkM6adI.js.map → Breadcrumb-g_xn_-Nf.js.map} +1 -1
- package/dist/{Checkbox-fC0BuO2B.js → Checkbox-CUIn2jap.js} +2 -2
- package/dist/{Checkbox-fC0BuO2B.js.map → Checkbox-CUIn2jap.js.map} +1 -1
- package/dist/{Clipboard-ChPdiUy3.js → Clipboard-BTW6C-b_.js} +2 -2
- package/dist/{Clipboard-ChPdiUy3.js.map → Clipboard-BTW6C-b_.js.map} +1 -1
- package/dist/{ClipboardButton-D9pDjgkB.js → ClipboardButton-CwZJdRaz.js} +2 -2
- package/dist/{ClipboardButton-D9pDjgkB.js.map → ClipboardButton-CwZJdRaz.js.map} +1 -1
- package/dist/{CodeEditor-Cxy3HnKH.js → CodeEditor-C9zy7PxK.js} +6 -6
- package/dist/{CodeEditor-Cxy3HnKH.js.map → CodeEditor-C9zy7PxK.js.map} +1 -1
- package/dist/{ColorInput-Bxj-1eLT.js → ColorInput-BZV-u_94.js} +3 -3
- package/dist/{ColorInput-Bxj-1eLT.js.map → ColorInput-BZV-u_94.js.map} +1 -1
- package/dist/{Combobox-Cs_1pj2q.js → Combobox-BfIfaVMA.js} +273 -104
- package/dist/Combobox-BfIfaVMA.js.map +1 -0
- package/dist/{Command-B7ML9YMv.js → Command-Bfa1kpbt.js} +2 -2
- package/dist/{Command-B7ML9YMv.js.map → Command-Bfa1kpbt.js.map} +1 -1
- package/dist/{CopyField-BO_sh-HO.js → CopyField-DpT0Ngz1.js} +2 -2
- package/dist/{CopyField-BO_sh-HO.js.map → CopyField-DpT0Ngz1.js.map} +1 -1
- package/dist/{DateInput-ZdaMQo5i.js → DateInput-DiEd5uCL.js} +3 -3
- package/dist/{DateInput-ZdaMQo5i.js.map → DateInput-DiEd5uCL.js.map} +1 -1
- package/dist/{DateRangeInput-DkvNh_sT.js → DateRangeInput-DPfVYchl.js} +3 -3
- package/dist/{DateRangeInput-DkvNh_sT.js.map → DateRangeInput-DPfVYchl.js.map} +1 -1
- package/dist/DiagramSource-C5_d8Gdj.js +11 -0
- package/dist/DiagramSource-C5_d8Gdj.js.map +1 -0
- package/dist/{FieldItem-CCd9-xnp.js → FieldItem-B7XMmZSz.js} +3 -3
- package/dist/{FieldItem-CCd9-xnp.js.map → FieldItem-B7XMmZSz.js.map} +1 -1
- package/dist/{Form-k6PH-em3.js → Form-CsttTHn4.js} +7 -7
- package/dist/Form-CsttTHn4.js.map +1 -0
- package/dist/{FormGroup-DbcDtrgU.js → FormGroup-DHvTFdno.js} +3 -3
- package/dist/{FormGroup-DbcDtrgU.js.map → FormGroup-DHvTFdno.js.map} +1 -1
- package/dist/{FullScreenModal-BvPuYibe.js → FullScreenModal-CN9nAs72.js} +50 -2
- package/dist/FullScreenModal-CN9nAs72.js.map +1 -0
- package/dist/{InputGroup-BnLHY0eq.js → InputGroup-DcZRlVnN.js} +22 -14
- package/dist/InputGroup-DcZRlVnN.js.map +1 -0
- package/dist/{Kbd-CvSM3D3-.js → Kbd-Cvvt91Q8.js} +14 -4
- package/dist/Kbd-Cvvt91Q8.js.map +1 -0
- package/dist/{MermaidDiagram-WkonYErO.js → MermaidDiagram-DSI7xMu2.js} +21 -19
- package/dist/MermaidDiagram-DSI7xMu2.js.map +1 -0
- package/dist/{MultiActionButtonGroup-CxWH7yWK.js → MultiActionButtonGroup-DokHbPgM.js} +2 -2
- package/dist/{MultiActionButtonGroup-CxWH7yWK.js.map → MultiActionButtonGroup-DokHbPgM.js.map} +1 -1
- package/dist/{Navbar-B2UsolVU.js → Navbar-Liy1TPI7.js} +6 -6
- package/dist/{Navbar-B2UsolVU.js.map → Navbar-Liy1TPI7.js.map} +1 -1
- package/dist/PageHeader-Q3IpCnQd.js.map +1 -1
- package/dist/{PageToolbar-DnbFt14Q.js → PageToolbar-DExqEYGl.js} +2 -2
- package/dist/{PageToolbar-DnbFt14Q.js.map → PageToolbar-DExqEYGl.js.map} +1 -1
- package/dist/{Popconfirm-CILjmzKI.js → Popconfirm-5pBzT_HQ.js} +10 -11
- package/dist/{Popconfirm-CILjmzKI.js.map → Popconfirm-5pBzT_HQ.js.map} +1 -1
- package/dist/{RadioGroup-XFzFd1ti.js → RadioGroup-DXPbSj8P.js} +2 -2
- package/dist/{RadioGroup-XFzFd1ti.js.map → RadioGroup-DXPbSj8P.js.map} +1 -1
- package/dist/{Search-4Bxtt8hS.js → Search-5uQAiNIP.js} +2 -2
- package/dist/{Search-4Bxtt8hS.js.map → Search-5uQAiNIP.js.map} +1 -1
- package/dist/{SearchInput-f_oY9T4Z.js → SearchInput-D4UgAXJK.js} +3 -3
- package/dist/{SearchInput-f_oY9T4Z.js.map → SearchInput-D4UgAXJK.js.map} +1 -1
- package/dist/{SectionNav-BpJlisbT.js → SectionNav-OkKCjSA-.js} +3 -3
- package/dist/{SectionNav-BpJlisbT.js.map → SectionNav-OkKCjSA-.js.map} +1 -1
- package/dist/{Select-DpcgKqKB.js → Select-DV3Hak_l.js} +3 -4
- package/dist/Select-DV3Hak_l.js.map +1 -0
- package/dist/{Sidebar-Cm6I4dE1.js → Sidebar-D3cY1kha.js} +44 -20
- package/dist/Sidebar-D3cY1kha.js.map +1 -0
- package/dist/{Slider-pPC_3gz9.js → Slider-CRf-bB4y.js} +2 -2
- package/dist/{Slider-pPC_3gz9.js.map → Slider-CRf-bB4y.js.map} +1 -1
- package/dist/{Switch-ChfPKcTE.js → Switch-B0WdGSjz.js} +7 -7
- package/dist/{Switch-ChfPKcTE.js.map → Switch-B0WdGSjz.js.map} +1 -1
- package/dist/{TextInput-DHM6dHmn.js → TextInput-DH5SkbsE.js} +3 -3
- package/dist/{TextInput-DHM6dHmn.js.map → TextInput-DH5SkbsE.js.map} +1 -1
- package/dist/{ThemeProvider-DrQJtzpd.js → ThemeProvider-2RMdVGxO.js} +17 -12
- package/dist/{ThemeProvider-DrQJtzpd.js.map → ThemeProvider-2RMdVGxO.js.map} +1 -1
- package/dist/{Timeline-6btyJl4D.js → Timeline-BG5Xogxh.js} +11 -11
- package/dist/{Timeline-6btyJl4D.js.map → Timeline-BG5Xogxh.js.map} +1 -1
- package/dist/{Workbench-BzE-Vvd9.js → Workbench-UR2FBC7I.js} +3 -1
- package/dist/Workbench-UR2FBC7I.js.map +1 -0
- package/dist/{ZoomableSvg-BWnDkR61.js → ZoomableSvg-pooPb1Cu.js} +3 -3
- package/dist/{ZoomableSvg-BWnDkR61.js.map → ZoomableSvg-pooPb1Cu.js.map} +1 -1
- package/dist/editors.js +4 -4
- package/dist/flint.js +136 -9
- package/dist/flint.js.map +1 -1
- package/dist/index.d.ts +801 -324
- package/dist/index.js +41 -40
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/AuthLayout.js +118 -0
- package/dist/internal/blocks/AuthLayout.js.map +1 -0
- 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 +107 -48
- 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/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/BrandLogo.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 +2 -2
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Popconfirm.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/Select.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/ThemeProvider.js +1 -1
- package/dist/internal/components/Timeline.js +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/Workbench.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +2 -2
- package/dist/markdown-editor.js +29 -23
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +22 -23
- package/dist/rjsf.js.map +1 -1
- 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/{useColorSchemeState-klihG9-i.js → themeScopeContext-D7fSyb06.js} +16 -3
- package/dist/themeScopeContext-D7fSyb06.js.map +1 -0
- package/dist/{themeTokens-D70HeNVF.js → themeTokens-qP1-55O7.js} +37 -10
- package/dist/themeTokens-qP1-55O7.js.map +1 -0
- package/dist/{utils-B5Z52hYs.js → utils-DSvrhU8E.js} +6 -2
- package/dist/{utils-B5Z52hYs.js.map → utils-DSvrhU8E.js.map} +1 -1
- package/dist/vega.d.ts +1 -1
- package/dist/vega.js +3 -3
- package/dist/vega.js.map +1 -1
- package/dist/{vegaTheme-DfoEQhOy.js → vegaTheme-CSvFEMBl.js} +6 -6
- package/dist/vegaTheme-CSvFEMBl.js.map +1 -0
- package/package.json +11 -9
- package/src/styles.css +3 -0
- package/dist/AIKit-DDg5DBCG.js.map +0 -1
- package/dist/Badge-Ch26CXoP.js.map +0 -1
- package/dist/BrandLogo-Dmi7jo21.js.map +0 -1
- package/dist/Combobox-Cs_1pj2q.js.map +0 -1
- package/dist/Form-k6PH-em3.js.map +0 -1
- package/dist/FullScreenModal-BvPuYibe.js.map +0 -1
- package/dist/InputGroup-BnLHY0eq.js.map +0 -1
- package/dist/Kbd-CvSM3D3-.js.map +0 -1
- package/dist/MermaidDiagram-WkonYErO.js.map +0 -1
- package/dist/Select-DpcgKqKB.js.map +0 -1
- package/dist/Sidebar-Cm6I4dE1.js.map +0 -1
- package/dist/Workbench-BzE-Vvd9.js.map +0 -1
- package/dist/svgTransforms-C9njt92h.js.map +0 -1
- package/dist/themeTokens-D70HeNVF.js.map +0 -1
- package/dist/useColorSchemeState-klihG9-i.js.map +0 -1
- package/dist/vegaTheme-DfoEQhOy.js.map +0 -1
|
@@ -1,26 +1,95 @@
|
|
|
1
1
|
import { cn } from "./classNames-BzrkDnOD.js";
|
|
2
|
-
import { Tooltip, TooltipProvider } from "./utils-
|
|
3
|
-
import { AlertCircle, ChevronDown, ChevronLeft, ChevronRight,
|
|
2
|
+
import { Tooltip, TooltipProvider } from "./utils-DSvrhU8E.js";
|
|
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
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { ButtonGroup } from "./internal/components/ButtonGroup.js";
|
|
6
|
+
import { ClipboardButton } from "./ClipboardButton-CwZJdRaz.js";
|
|
7
|
+
import { FullScreenModal, FullScreenModalBody, FullScreenModalHeader } from "./FullScreenModal-CN9nAs72.js";
|
|
7
8
|
import { Truncated } from "./internal/components/Truncated.js";
|
|
8
9
|
import { HoverCard } from "./HoverCard-B9ZMJxjn.js";
|
|
9
|
-
import { Command } from "./Command-
|
|
10
|
-
import { TextInput } from "./TextInput-
|
|
11
|
-
import { Checkbox } from "./Checkbox-
|
|
12
|
-
import { Badge } from "./Badge-
|
|
10
|
+
import { Command } from "./Command-Bfa1kpbt.js";
|
|
11
|
+
import { TextInput } from "./TextInput-DH5SkbsE.js";
|
|
12
|
+
import { Checkbox } from "./Checkbox-CUIn2jap.js";
|
|
13
|
+
import { Badge } from "./Badge-D0pXdekt.js";
|
|
13
14
|
import { Textarea } from "./internal/blocks/Textarea.js";
|
|
14
15
|
import { Table } from "./Table-CvYuTuNU.js";
|
|
15
16
|
import { DiagramSkeleton } from "./internal/blocks/DiagramShared/DiagramSkeleton.js";
|
|
17
|
+
import { DiagramSource } from "./DiagramSource-C5_d8Gdj.js";
|
|
16
18
|
import { Progress } from "./internal/components/Progress.js";
|
|
17
19
|
import { Slot } from "@radix-ui/react-slot";
|
|
18
|
-
import {
|
|
20
|
+
import { isValidElement, useCallback, useEffect, useId, useRef, useState } from "react";
|
|
19
21
|
import { cva } from "class-variance-authority";
|
|
20
22
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
23
|
import TextareaAutosize from "react-textarea-autosize";
|
|
22
24
|
import ReactMarkdown from "react-markdown";
|
|
23
25
|
import remarkGfm from "remark-gfm";
|
|
26
|
+
//#region src/blocks/AIKit/AnswerActions.tsx
|
|
27
|
+
const VOTE_BUTTONS = [{
|
|
28
|
+
vote: "up",
|
|
29
|
+
label: "Good answer",
|
|
30
|
+
icon: /* @__PURE__ */ jsx(ThumbsUp, { className: "tw:size-4" })
|
|
31
|
+
}, {
|
|
32
|
+
vote: "down",
|
|
33
|
+
label: "Bad answer",
|
|
34
|
+
icon: /* @__PURE__ */ jsx(ThumbsDown, { className: "tw:size-4" })
|
|
35
|
+
}];
|
|
36
|
+
/**
|
|
37
|
+
* What a reader can do with a finished answer: take it away, and say whether it was any good.
|
|
38
|
+
*
|
|
39
|
+
* - **Always rendered, never hover-only.** A reveal-on-hover row does not exist for anyone
|
|
40
|
+
* reaching it without a pointer. The buttons are quiet (`invisible`) rather than hidden.
|
|
41
|
+
* - Copy sits first: it is the one action with no round trip.
|
|
42
|
+
* - **A vote can be changed but not withdrawn.** `aria-pressed` says which one is recorded, and
|
|
43
|
+
* both buttons stay focusable so a reader can switch. Pressing the pressed one re-sends the
|
|
44
|
+
* same vote.
|
|
45
|
+
* - The recorded vote and the write are the caller's: the two chats vote against different
|
|
46
|
+
* endpoints, and only the caller knows whether a turn is finished enough to rate.
|
|
47
|
+
*/
|
|
48
|
+
const AnswerActions = ({ copyText, vote, onVote }) => {
|
|
49
|
+
return /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
50
|
+
space: "extra-small",
|
|
51
|
+
"aria-label": "Answer actions",
|
|
52
|
+
children: [copyText ? /* @__PURE__ */ jsx(ClipboardButton, {
|
|
53
|
+
text: copyText,
|
|
54
|
+
tooltip: "Copy answer",
|
|
55
|
+
size: "icon-xs",
|
|
56
|
+
variant: "invisible"
|
|
57
|
+
}) : null, VOTE_BUTTONS.map(({ vote: candidate, label, icon }) => {
|
|
58
|
+
const isRecorded = vote === candidate;
|
|
59
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
60
|
+
tooltip: label,
|
|
61
|
+
placement: "top",
|
|
62
|
+
triggerAsChild: true,
|
|
63
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
64
|
+
size: "icon-xs",
|
|
65
|
+
variant: isRecorded ? "secondary" : "invisible",
|
|
66
|
+
"aria-label": label,
|
|
67
|
+
"aria-pressed": isRecorded,
|
|
68
|
+
onClick: () => onVote(candidate),
|
|
69
|
+
children: icon
|
|
70
|
+
})
|
|
71
|
+
}, candidate);
|
|
72
|
+
})]
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/blocks/AIKit/CollapsibleBody.tsx
|
|
77
|
+
const CollapsibleBody = ({ isExpanded, isClosing, onClosed, children }) => {
|
|
78
|
+
const handleTransitionEnd = (event) => {
|
|
79
|
+
if (event.target !== event.currentTarget) return;
|
|
80
|
+
if (event.propertyName !== "grid-template-rows") return;
|
|
81
|
+
if (!isExpanded) onClosed();
|
|
82
|
+
};
|
|
83
|
+
return /* @__PURE__ */ jsx("div", {
|
|
84
|
+
className: cn("tw:grid tw:transition-[grid-template-rows] tw:duration-300 tw:ease-out tw:motion-reduce:transition-none", isExpanded ? "tw:grid-rows-[1fr]" : "tw:grid-rows-[0fr]"),
|
|
85
|
+
onTransitionEnd: handleTransitionEnd,
|
|
86
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
87
|
+
className: "tw:min-h-0 tw:overflow-hidden",
|
|
88
|
+
children: (isExpanded || isClosing) && children
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
24
93
|
//#region src/blocks/AIKit/CollapsibleStepHeader.tsx
|
|
25
94
|
const variantClasses = {
|
|
26
95
|
success: "tw:text-muted-foreground tw:focus-visible:outline-ring tw:not-disabled:hover:text-foreground",
|
|
@@ -31,8 +100,7 @@ const variantClasses = {
|
|
|
31
100
|
const iconClasses = "tw:size-3.5 tw:shrink-0 tw:basis-3.5 tw:opacity-70";
|
|
32
101
|
const renderVariantIcon$1 = (variant) => {
|
|
33
102
|
if (variant === "processing") return /* @__PURE__ */ jsx(Loader2, { className: cn(iconClasses, "tw:animate-spin") });
|
|
34
|
-
if (variant === "error") return /* @__PURE__ */ jsx(XCircle, { className: iconClasses });
|
|
35
|
-
if (variant === "dismissed") return /* @__PURE__ */ jsx(XCircle, { className: cn(iconClasses, "tw:text-neutral-500") });
|
|
103
|
+
if (variant === "error" || variant === "dismissed") return /* @__PURE__ */ jsx(XCircle, { className: iconClasses });
|
|
36
104
|
return /* @__PURE__ */ jsx(CircleCheck, { className: iconClasses });
|
|
37
105
|
};
|
|
38
106
|
const CollapsibleStepHeader = ({ isExpanded, onToggle, label, variant = "success" }) => {
|
|
@@ -51,6 +119,9 @@ const CollapsibleStepHeader = ({ isExpanded, onToggle, label, variant = "success
|
|
|
51
119
|
});
|
|
52
120
|
};
|
|
53
121
|
//#endregion
|
|
122
|
+
//#region src/blocks/AIKit/hasMotion.ts
|
|
123
|
+
const hasMotion = () => typeof window.matchMedia === "function" && !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
124
|
+
//#endregion
|
|
54
125
|
//#region src/blocks/AIKit/InlineStepDetail.tsx
|
|
55
126
|
const InlineStepDetail = ({ children }) => /* @__PURE__ */ jsx("div", {
|
|
56
127
|
className: "tw:ml-2.5 tw:whitespace-pre-wrap tw:border-l tw:border-border tw:pl-3 tw:text-xs tw:text-muted-foreground",
|
|
@@ -80,38 +151,122 @@ const SECTION_LABELS = {
|
|
|
80
151
|
success: "Answered questions",
|
|
81
152
|
dismissed: "Dismissed questions"
|
|
82
153
|
};
|
|
83
|
-
const AnswerSummary = ({ items, variant = "success", noAnswerLabel = "No answer" }) => {
|
|
154
|
+
const AnswerSummary = ({ items, variant = "success", noAnswerLabel = "No answer", onExpandToggle }) => {
|
|
84
155
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
85
|
-
const
|
|
156
|
+
const [isClosing, setIsClosing] = useState(false);
|
|
157
|
+
const toggle = () => {
|
|
158
|
+
const next = !isExpanded;
|
|
159
|
+
if (!next) setIsClosing(hasMotion());
|
|
160
|
+
setIsExpanded(next);
|
|
161
|
+
onExpandToggle?.(next);
|
|
162
|
+
};
|
|
86
163
|
const count = items.length;
|
|
87
164
|
const [firstItem] = items;
|
|
88
165
|
const label = count === 1 && firstItem ? firstItem.question : `${count} questions`;
|
|
89
166
|
return /* @__PURE__ */ jsxs("section", {
|
|
90
|
-
className: "tw:mt-4 tw:flex tw:flex-col
|
|
167
|
+
className: "tw:mt-4 tw:flex tw:flex-col",
|
|
91
168
|
"aria-label": SECTION_LABELS[variant],
|
|
92
169
|
children: [/* @__PURE__ */ jsx(CollapsibleStepHeader, {
|
|
93
170
|
isExpanded,
|
|
94
171
|
onToggle: toggle,
|
|
95
172
|
variant,
|
|
96
173
|
label
|
|
97
|
-
}),
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
174
|
+
}), /* @__PURE__ */ jsx(CollapsibleBody, {
|
|
175
|
+
isExpanded,
|
|
176
|
+
isClosing,
|
|
177
|
+
onClosed: () => setIsClosing(false),
|
|
178
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
179
|
+
className: "tw:flex tw:flex-col tw:gap-4 tw:pt-4 tw:pl-5",
|
|
180
|
+
children: items.map(({ question, answer }, index) => /* @__PURE__ */ jsxs("div", {
|
|
181
|
+
className: "tw:flex tw:flex-col tw:gap-1",
|
|
182
|
+
children: [/* @__PURE__ */ jsx(InlineStepLabel, {
|
|
183
|
+
variant,
|
|
184
|
+
children: question
|
|
185
|
+
}), /* @__PURE__ */ jsx(InlineStepDetail, { children: answer && answer.length > 0 ? answer : noAnswerLabel })]
|
|
186
|
+
}, `${index}-${question}`))
|
|
187
|
+
})
|
|
106
188
|
})]
|
|
107
189
|
});
|
|
108
190
|
};
|
|
109
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
|
|
110
267
|
//#region src/blocks/AIKit/Markdown.tsx
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
return { default: ({ code }) => /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: code }) }) };
|
|
114
|
-
}));
|
|
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));
|
|
115
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";
|
|
116
271
|
const getText = (node) => {
|
|
117
272
|
if (typeof node === "string") return node;
|
|
@@ -135,19 +290,48 @@ const getLanguage = (element) => {
|
|
|
135
290
|
* - A caller's own plugins are appended to these, never substituted for them.
|
|
136
291
|
*/
|
|
137
292
|
const baseRemarkPlugins = [remarkGfm];
|
|
293
|
+
/**
|
|
294
|
+
* Fence language → the on-demand chunk that draws it.
|
|
295
|
+
*
|
|
296
|
+
* - Both dialects are the agent's, not this package's: kai-agent's prompt tells the model to
|
|
297
|
+
* write ```mermaid for structure and ```flint for quantitative data, so a chat that renders
|
|
298
|
+
* one and not the other drops output the agent was instructed to produce.
|
|
299
|
+
* - `flint-chart` is an alias — it is the fence tag flint's own docs use, so a model emits it
|
|
300
|
+
* unprompted often enough to matter. `markdownComponents.tsx` in kbc-ui carries the same pair.
|
|
301
|
+
* - Read through `Object.hasOwn`, never by plain index: a fence tagged ```constructor or
|
|
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.
|
|
304
|
+
*/
|
|
305
|
+
const DIAGRAM_CHUNKS = {
|
|
306
|
+
mermaid: loadMermaid,
|
|
307
|
+
flint: loadFlint,
|
|
308
|
+
"flint-chart": loadFlint
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* The fence languages this renderer draws instead of printing.
|
|
312
|
+
*
|
|
313
|
+
* - For a caller that streams: a diagram mounts a lazily loaded chunk, so an answer arriving a
|
|
314
|
+
* token at a time has to keep a fence that is still open an ordinary code block, or every
|
|
315
|
+
* keystroke fetches the chunk. Sharing the list is what keeps that hold-back from missing a
|
|
316
|
+
* dialect this map has and the caller does not.
|
|
317
|
+
* - Frozen, because it is that shared contract: a consumer that pushed onto it would change how
|
|
318
|
+
* every other app in the same bundle holds a fence back.
|
|
319
|
+
*/
|
|
320
|
+
const DIAGRAM_LANGUAGES = Object.freeze(Object.keys(DIAGRAM_CHUNKS));
|
|
138
321
|
const baseComponents = {
|
|
139
322
|
pre({ children, ...props }) {
|
|
140
323
|
const child = Array.isArray(children) ? children[0] : children;
|
|
141
|
-
|
|
142
|
-
|
|
324
|
+
const code = getText(child).replace(/\n$/, "");
|
|
325
|
+
const language = getLanguage(child);
|
|
326
|
+
const load = language !== void 0 && Object.hasOwn(DIAGRAM_CHUNKS, language) ? DIAGRAM_CHUNKS[language] : void 0;
|
|
327
|
+
if (load) {
|
|
143
328
|
if (!code.trim()) return null;
|
|
144
|
-
return /* @__PURE__ */ jsx(
|
|
145
|
-
|
|
146
|
-
|
|
329
|
+
return /* @__PURE__ */ jsx(DiagramBlock, {
|
|
330
|
+
load,
|
|
331
|
+
code
|
|
147
332
|
});
|
|
148
333
|
}
|
|
149
334
|
const { node: _node, ...rest } = props;
|
|
150
|
-
const code = getText(child).replace(/\n$/, "");
|
|
151
335
|
return /* @__PURE__ */ jsxs("div", {
|
|
152
336
|
className: "tw:group tw:relative",
|
|
153
337
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -229,6 +413,95 @@ const Markdown = ({ children, className, remarkPlugins, components: componentOve
|
|
|
229
413
|
});
|
|
230
414
|
};
|
|
231
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
|
|
232
505
|
//#region src/blocks/AIKit/MessageBubble.tsx
|
|
233
506
|
const containerClasses = cva([
|
|
234
507
|
"tw:flex",
|
|
@@ -335,7 +608,7 @@ const ExpandToggle = ({ isExpanded, onToggle, showMoreLabel, showLessLabel }) =>
|
|
|
335
608
|
});
|
|
336
609
|
const ChangeRequestForm = ({ value, onValueChange, onSubmit, onKeyDown, placeholder, submitLabel, formLabel, canSubmit, isSubmitting }) => /* @__PURE__ */ jsx("form", {
|
|
337
610
|
onSubmit,
|
|
338
|
-
className: "tw:border-0 tw:border-t tw:border-solid tw:border-
|
|
611
|
+
className: "tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:text-card-foreground tw:px-4 tw:py-3",
|
|
339
612
|
"aria-label": formLabel,
|
|
340
613
|
children: /* @__PURE__ */ jsxs("div", {
|
|
341
614
|
className: "tw:relative",
|
|
@@ -415,8 +688,10 @@ const PlanApproval = ({ status, title, summary, stepCount, planBody, defaultExpa
|
|
|
415
688
|
const canShowPlanBody = planBody != null;
|
|
416
689
|
const trimmedChangeRequest = changeRequest.trim();
|
|
417
690
|
const canSubmitChangeRequest = trimmedChangeRequest.length > 0 && !isSubmitting;
|
|
691
|
+
const [isClosing, setIsClosing] = useState(false);
|
|
418
692
|
const toggleExpanded = () => {
|
|
419
693
|
const next = !isExpanded;
|
|
694
|
+
if (!next) setIsClosing(hasMotion());
|
|
420
695
|
if (isExpandedProp === void 0) setUncontrolledExpanded(next);
|
|
421
696
|
onExpandToggle?.(next);
|
|
422
697
|
};
|
|
@@ -465,7 +740,7 @@ const PlanApproval = ({ status, title, summary, stepCount, planBody, defaultExpa
|
|
|
465
740
|
});
|
|
466
741
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("section", {
|
|
467
742
|
"aria-label": title,
|
|
468
|
-
className: cn("tw:flex tw:w-full tw:max-w-[800px] tw:flex-col tw:overflow-hidden tw:rounded-xl tw:border tw:border-solid tw:border-border tw:bg-
|
|
743
|
+
className: cn("tw:flex tw:w-full tw:max-w-[800px] tw:flex-col tw:overflow-hidden tw:rounded-xl tw:border tw:border-solid tw:border-border tw:bg-background tw:text-foreground", className),
|
|
469
744
|
"data-testid": "plan-approval-root",
|
|
470
745
|
"data-plan-status": status,
|
|
471
746
|
children: [
|
|
@@ -482,11 +757,11 @@ const PlanApproval = ({ status, title, summary, stepCount, planBody, defaultExpa
|
|
|
482
757
|
dismissedLabel: dismissedPillLabel,
|
|
483
758
|
changesRequestedLabel: changesRequestedPillLabel
|
|
484
759
|
}), stepCount != null && stepCount > 0 && /* @__PURE__ */ jsx("span", {
|
|
485
|
-
className: "tw:text-xs tw:leading-4 tw:text-
|
|
760
|
+
className: "tw:text-xs tw:leading-4 tw:text-muted-foreground",
|
|
486
761
|
children: stepCountLabel(stepCount)
|
|
487
762
|
})]
|
|
488
763
|
}), /* @__PURE__ */ jsx("p", {
|
|
489
|
-
className: "tw:m-0 tw:text-base tw:font-semibold tw:leading-6
|
|
764
|
+
className: "tw:m-0 tw:text-base tw:font-semibold tw:leading-6",
|
|
490
765
|
children: title
|
|
491
766
|
})]
|
|
492
767
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -515,15 +790,20 @@ const PlanApproval = ({ status, title, summary, stepCount, planBody, defaultExpa
|
|
|
515
790
|
})]
|
|
516
791
|
}),
|
|
517
792
|
summary != null && /* @__PURE__ */ jsx("div", {
|
|
518
|
-
className: cn("tw:whitespace-pre-wrap tw:border-0 tw:border-t tw:border-solid tw:border-
|
|
793
|
+
className: cn("tw:whitespace-pre-wrap tw:border-0 tw:border-t tw:border-solid tw:border-border tw:px-4 tw:pt-4 tw:text-sm", isExpanded && canShowPlanBody ? "tw:pb-4" : "tw:pb-2"),
|
|
519
794
|
children: summary
|
|
520
795
|
}),
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
796
|
+
canShowPlanBody && /* @__PURE__ */ jsx(CollapsibleBody, {
|
|
797
|
+
isExpanded,
|
|
798
|
+
isClosing,
|
|
799
|
+
onClosed: () => setIsClosing(false),
|
|
800
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
801
|
+
className: "tw:max-h-[400px] tw:overflow-y-auto tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:p-4 tw:text-sm tw:text-card-foreground",
|
|
802
|
+
children: planBody
|
|
803
|
+
})
|
|
524
804
|
}),
|
|
525
805
|
!isFullScreen && /* @__PURE__ */ jsxs(Fragment$1, { children: [showChangeRequestForm && changeRequestForm, /* @__PURE__ */ jsxs("div", {
|
|
526
|
-
className: cn("tw:flex tw:items-center tw:gap-2 tw:overflow-x-auto tw:border-0 tw:border-t tw:border-solid tw:border-
|
|
806
|
+
className: cn("tw:flex tw:items-center tw:gap-2 tw:overflow-x-auto tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:px-4 tw:py-3 tw:text-card-foreground", canShowPlanBody ? "tw:justify-between" : "tw:justify-end"),
|
|
527
807
|
children: [canShowPlanBody && /* @__PURE__ */ jsx("div", {
|
|
528
808
|
className: "tw:shrink-0",
|
|
529
809
|
children: /* @__PURE__ */ jsx(ExpandToggle, {
|
|
@@ -585,14 +865,14 @@ const PlanApproval = ({ status, title, summary, stepCount, planBody, defaultExpa
|
|
|
585
865
|
})
|
|
586
866
|
}),
|
|
587
867
|
/* @__PURE__ */ jsx(FullScreenModalBody, {
|
|
588
|
-
className: "tw:bg-
|
|
868
|
+
className: "tw:bg-card tw:px-6 tw:py-4 tw:text-card-foreground",
|
|
589
869
|
children: /* @__PURE__ */ jsx("div", {
|
|
590
|
-
className: "tw:mx-auto tw:w-full tw:max-w-[800px] tw:text-sm
|
|
870
|
+
className: "tw:mx-auto tw:w-full tw:max-w-[800px] tw:text-sm",
|
|
591
871
|
children: planBody
|
|
592
872
|
})
|
|
593
873
|
}),
|
|
594
874
|
(showChangeRequestForm || showActions) && /* @__PURE__ */ jsx("div", {
|
|
595
|
-
className: "tw:shrink-0 tw:border-0 tw:border-t tw:border-solid tw:border-
|
|
875
|
+
className: "tw:shrink-0 tw:border-0 tw:border-t tw:border-solid tw:border-border tw:bg-card tw:text-card-foreground",
|
|
596
876
|
children: /* @__PURE__ */ jsxs("div", {
|
|
597
877
|
className: "tw:mx-auto tw:w-full tw:max-w-[800px]",
|
|
598
878
|
children: [showChangeRequestForm && changeRequestForm, showActions && /* @__PURE__ */ jsx("div", {
|
|
@@ -758,11 +1038,15 @@ const wrapperVariants = cva(null, {
|
|
|
758
1038
|
inline: ""
|
|
759
1039
|
} }
|
|
760
1040
|
});
|
|
761
|
-
const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, autoFocus, ...textareaProps }) => {
|
|
1041
|
+
const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, disabled, disableSubmit, value = "", onValueChange, status = "ready", maxRows = 6, minRows, commands, autoFocus, textareaRef: publishedRef, ...textareaProps }) => {
|
|
762
1042
|
const defaultMinRows = variant === "inline" ? 1 : 2;
|
|
763
1043
|
const isDisabled = (disabled || disableSubmit || !value.trim()) && status !== "streaming" && status !== "interrupted";
|
|
764
1044
|
const textareaId = useId();
|
|
765
1045
|
const textareaRef = useRef(null);
|
|
1046
|
+
const setTextareaNode = useCallback((node) => {
|
|
1047
|
+
textareaRef.current = node;
|
|
1048
|
+
if (publishedRef) publishedRef.current = node;
|
|
1049
|
+
}, [publishedRef]);
|
|
766
1050
|
const [dismissedValue, setDismissedValue] = useState(null);
|
|
767
1051
|
const autoFocusRef = useRef(autoFocus);
|
|
768
1052
|
useEffect(() => {
|
|
@@ -833,7 +1117,7 @@ const PromptInput = ({ onSend, onAbort, onContinue, prefix, variant, suffix, dis
|
|
|
833
1117
|
minRows: minRows ?? defaultMinRows,
|
|
834
1118
|
maxRows,
|
|
835
1119
|
id: textareaId,
|
|
836
|
-
ref:
|
|
1120
|
+
ref: setTextareaNode,
|
|
837
1121
|
value,
|
|
838
1122
|
onChange: handleOnChange,
|
|
839
1123
|
onKeyDown: handleOnKeyDown,
|
|
@@ -1123,11 +1407,24 @@ const SuggestedPrompt = ({ label, disabled, onClick, icon, className }) => {
|
|
|
1123
1407
|
};
|
|
1124
1408
|
//#endregion
|
|
1125
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
|
+
*/
|
|
1126
1419
|
const ThinkingIndicator = ({ label = "Thinking..." }) => {
|
|
1127
1420
|
return /* @__PURE__ */ jsxs("div", {
|
|
1128
1421
|
className: "tw:flex tw:items-center tw:gap-1.5",
|
|
1422
|
+
role: "status",
|
|
1129
1423
|
"data-testid": "chat-thinking-indicator",
|
|
1130
|
-
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", {
|
|
1131
1428
|
className: "tw:text-xs tw:font-medium tw:text-muted-foreground",
|
|
1132
1429
|
children: label
|
|
1133
1430
|
})]
|
|
@@ -1331,14 +1628,33 @@ const ToolCallStatusHeader = ({ icon: IconComponent, iconSpin, status, text, nee
|
|
|
1331
1628
|
className: "tw:text-xs tw:font-medium tw:text-warning",
|
|
1332
1629
|
children: "Confirmation required"
|
|
1333
1630
|
}), /* @__PURE__ */ jsx(TriangleAlert, { className: "tw:size-3.5 tw:text-warning" })]
|
|
1334
|
-
}), isCollapsible &&
|
|
1631
|
+
}), isCollapsible && /* @__PURE__ */ jsx(ChevronDown, { className: cn("tw:size-3.5 tw:shrink-0 tw:text-muted-foreground", "tw:transition-transform tw:duration-300 tw:ease-out tw:motion-reduce:transition-none", !isCollapsed && "tw:rotate-180") })]
|
|
1335
1632
|
})]
|
|
1336
1633
|
});
|
|
1337
1634
|
};
|
|
1338
1635
|
//#endregion
|
|
1339
1636
|
//#region src/blocks/AIKit/usageStatsHelpers.ts
|
|
1340
|
-
/**
|
|
1637
|
+
/**
|
|
1638
|
+
* Clamp a percentage to 0–100 and normalize non-finite input to 0.
|
|
1639
|
+
*
|
|
1640
|
+
* - `Progress`'s indicator is unclamped, so a value over 100 slides the bar off-screen.
|
|
1641
|
+
* - `NaN` normalizes to 0 — `Math.min`/`Math.max` propagate it, and it renders as no bar at all.
|
|
1642
|
+
*/
|
|
1341
1643
|
const clampPercentage = (value) => Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;
|
|
1644
|
+
/**
|
|
1645
|
+
* A percentage as text — `72%`, `0.2%`, `99%`.
|
|
1646
|
+
*
|
|
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
|
|
1650
|
+
* from the raw value, exactly at the boundary everything else turns on.
|
|
1651
|
+
*/
|
|
1652
|
+
const formatPercentage = (value) => {
|
|
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}%`;
|
|
1657
|
+
};
|
|
1342
1658
|
//#endregion
|
|
1343
1659
|
//#region src/blocks/AIKit/UsageStatsRing.tsx
|
|
1344
1660
|
const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }) => {
|
|
@@ -1357,7 +1673,7 @@ const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }) => {
|
|
|
1357
1673
|
r: radius,
|
|
1358
1674
|
fill: "none",
|
|
1359
1675
|
strokeWidth,
|
|
1360
|
-
className: "tw:stroke-
|
|
1676
|
+
className: "tw:stroke-muted-foreground tw:opacity-50"
|
|
1361
1677
|
}), /* @__PURE__ */ jsx("circle", {
|
|
1362
1678
|
cx: size / 2,
|
|
1363
1679
|
cy: size / 2,
|
|
@@ -1373,28 +1689,32 @@ const UsageStatsRing = ({ value, size = 16, strokeWidth = 2.5, className }) => {
|
|
|
1373
1689
|
};
|
|
1374
1690
|
//#endregion
|
|
1375
1691
|
//#region src/blocks/AIKit/UsageStats.tsx
|
|
1376
|
-
const UsageStats = ({ value, alert = false, children, className, ariaLabel, align = "end", side = "top", sideOffset = 8 }) => {
|
|
1692
|
+
const UsageStats = ({ value, alert = false, children, className, ariaLabel, align = "end", side = "top", sideOffset = 8, open, onOpenChange }) => {
|
|
1377
1693
|
const hasAlert = Boolean(alert);
|
|
1378
1694
|
const isWarning = alert === "warning";
|
|
1379
1695
|
const defaultLabel = `Usage: ${Math.round(clampPercentage(value))}%${hasAlert ? " (usage alert)" : ""}`;
|
|
1380
|
-
return /* @__PURE__ */ jsxs(HoverCard, {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
children:
|
|
1386
|
-
"
|
|
1387
|
-
className: cn("tw:
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1696
|
+
return /* @__PURE__ */ jsxs(HoverCard, {
|
|
1697
|
+
open,
|
|
1698
|
+
onOpenChange,
|
|
1699
|
+
children: [/* @__PURE__ */ jsx(HoverCard.Trigger, {
|
|
1700
|
+
asChild: true,
|
|
1701
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
1702
|
+
"aria-label": ariaLabel ?? defaultLabel,
|
|
1703
|
+
className: cn("tw:relative tw:inline-flex tw:size-8 tw:items-center tw:justify-center", className),
|
|
1704
|
+
children: [/* @__PURE__ */ jsx(UsageStatsRing, { value }), hasAlert && /* @__PURE__ */ jsx(AlertCircle, {
|
|
1705
|
+
"data-testid": "usage-stats-alert",
|
|
1706
|
+
className: cn("tw:absolute tw:-right-0.5 tw:-top-0.5 tw:size-3", isWarning ? "tw:text-warning-500" : "tw:text-error-500")
|
|
1707
|
+
})]
|
|
1708
|
+
})
|
|
1709
|
+
}), /* @__PURE__ */ jsx(HoverCard.Content, {
|
|
1710
|
+
align,
|
|
1711
|
+
side,
|
|
1712
|
+
sideOffset,
|
|
1713
|
+
children
|
|
1714
|
+
})]
|
|
1715
|
+
});
|
|
1396
1716
|
};
|
|
1397
1717
|
//#endregion
|
|
1398
|
-
export { AnswerSummary, CollapsibleStepHeader, InlineStepDetail, InlineStepLabel, Markdown, MessageBubble, PlanApproval, PlanRewritingIndicator, PromptInput, Question, QuestionBlock, SuggestedPrompt, ThinkingIndicator, ToolCallApproval, ToolCallChip, ToolCallStatusHeader, UsageStats, UsageStatsRing };
|
|
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 };
|
|
1399
1719
|
|
|
1400
|
-
//# sourceMappingURL=AIKit-
|
|
1720
|
+
//# sourceMappingURL=AIKit-BExvt9pt.js.map
|