@schandlergarcia/sf-web-components 1.0.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/.a4drules/skills/building-data-visualization/SKILL.md +72 -0
- package/.a4drules/skills/building-data-visualization/implementation/bar-line-chart.md +316 -0
- package/.a4drules/skills/building-data-visualization/implementation/dashboard-layout.md +189 -0
- package/.a4drules/skills/building-data-visualization/implementation/donut-chart.md +181 -0
- package/.a4drules/skills/building-data-visualization/implementation/stat-card.md +150 -0
- package/.a4drules/skills/building-react-components/SKILL.md +96 -0
- package/.a4drules/skills/building-react-components/implementation/component.md +78 -0
- package/.a4drules/skills/building-react-components/implementation/header-footer.md +132 -0
- package/.a4drules/skills/building-react-components/implementation/page.md +93 -0
- package/.a4drules/skills/configuring-csp-trusted-sites/SKILL.md +90 -0
- package/.a4drules/skills/configuring-csp-trusted-sites/implementation/metadata-format.md +281 -0
- package/.a4drules/skills/configuring-webapp-metadata/SKILL.md +158 -0
- package/.a4drules/skills/creating-webapp/SKILL.md +140 -0
- package/.a4drules/skills/deploying-to-salesforce/SKILL.md +226 -0
- package/.a4drules/skills/implementing-file-upload/SKILL.md +396 -0
- package/.a4drules/skills/installing-webapp-features/SKILL.md +210 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/SKILL.md +186 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/constraints.md +134 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/examples.md +132 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/style-tokens.md +101 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/troubleshooting.md +57 -0
- package/.a4drules/skills/using-salesforce-data/SKILL.md +363 -0
- package/.a4drules/skills/using-salesforce-data/graphql-search.sh +139 -0
- package/.a4drules/webapp-data.md +353 -0
- package/.a4drules/webapp-ui.md +16 -0
- package/README.md +124 -0
- package/dist/components/library/cards/ActionList.js +27 -0
- package/dist/components/library/cards/ActionList.js.map +1 -0
- package/dist/components/library/cards/ActivityCard.js +40 -0
- package/dist/components/library/cards/ActivityCard.js.map +1 -0
- package/dist/components/library/cards/BaseCard.js +89 -0
- package/dist/components/library/cards/BaseCard.js.map +1 -0
- package/dist/components/library/cards/CalloutCard.js +28 -0
- package/dist/components/library/cards/CalloutCard.js.map +1 -0
- package/dist/components/library/cards/ChartCard.js +79 -0
- package/dist/components/library/cards/ChartCard.js.map +1 -0
- package/dist/components/library/cards/FeedPanel.js +38 -0
- package/dist/components/library/cards/FeedPanel.js.map +1 -0
- package/dist/components/library/cards/ListCard.js +112 -0
- package/dist/components/library/cards/ListCard.js.map +1 -0
- package/dist/components/library/cards/MetricCard.js +86 -0
- package/dist/components/library/cards/MetricCard.js.map +1 -0
- package/dist/components/library/cards/MetricsStrip.js +60 -0
- package/dist/components/library/cards/MetricsStrip.js.map +1 -0
- package/dist/components/library/cards/SectionCard.js +59 -0
- package/dist/components/library/cards/SectionCard.js.map +1 -0
- package/dist/components/library/cards/StatusCard.js +137 -0
- package/dist/components/library/cards/StatusCard.js.map +1 -0
- package/dist/components/library/cards/TableCard.js +244 -0
- package/dist/components/library/cards/TableCard.js.map +1 -0
- package/dist/components/library/cards/WidgetCard.js +60 -0
- package/dist/components/library/cards/WidgetCard.js.map +1 -0
- package/dist/components/library/charts/D3Chart.js +74 -0
- package/dist/components/library/charts/D3Chart.js.map +1 -0
- package/dist/components/library/charts/D3ChartTemplates.js +44 -0
- package/dist/components/library/charts/D3ChartTemplates.js.map +1 -0
- package/dist/components/library/charts/GeoMap.js +229 -0
- package/dist/components/library/charts/GeoMap.js.map +1 -0
- package/dist/components/library/chat/ChatBar.js +194 -0
- package/dist/components/library/chat/ChatBar.js.map +1 -0
- package/dist/components/library/chat/ChatInput.js +67 -0
- package/dist/components/library/chat/ChatInput.js.map +1 -0
- package/dist/components/library/chat/ChatMessage.js +112 -0
- package/dist/components/library/chat/ChatMessage.js.map +1 -0
- package/dist/components/library/chat/ChatMessageList.js +50 -0
- package/dist/components/library/chat/ChatMessageList.js.map +1 -0
- package/dist/components/library/chat/ChatPanel.js +77 -0
- package/dist/components/library/chat/ChatPanel.js.map +1 -0
- package/dist/components/library/chat/ChatSuggestions.js +22 -0
- package/dist/components/library/chat/ChatSuggestions.js.map +1 -0
- package/dist/components/library/chat/ChatToolCall.js +87 -0
- package/dist/components/library/chat/ChatToolCall.js.map +1 -0
- package/dist/components/library/chat/ChatTypingIndicator.js +20 -0
- package/dist/components/library/chat/ChatTypingIndicator.js.map +1 -0
- package/dist/components/library/chat/ChatWelcome.js +24 -0
- package/dist/components/library/chat/ChatWelcome.js.map +1 -0
- package/dist/components/library/chat/useChatState.js +77 -0
- package/dist/components/library/chat/useChatState.js.map +1 -0
- package/dist/components/library/data/DataModeProvider.js +47 -0
- package/dist/components/library/data/DataModeProvider.js.map +1 -0
- package/dist/components/library/data/DataModeToggle.js +28 -0
- package/dist/components/library/data/DataModeToggle.js.map +1 -0
- package/dist/components/library/data/filterUtils.js +71 -0
- package/dist/components/library/data/filterUtils.js.map +1 -0
- package/dist/components/library/data/useDataSource.js +13 -0
- package/dist/components/library/data/useDataSource.js.map +1 -0
- package/dist/components/library/data/usePageFilters.js +46 -0
- package/dist/components/library/data/usePageFilters.js.map +1 -0
- package/dist/components/library/filters/FilterBar.js +89 -0
- package/dist/components/library/filters/FilterBar.js.map +1 -0
- package/dist/components/library/filters/SearchFilter.js +44 -0
- package/dist/components/library/filters/SearchFilter.js.map +1 -0
- package/dist/components/library/filters/SelectFilter.js +44 -0
- package/dist/components/library/filters/SelectFilter.js.map +1 -0
- package/dist/components/library/filters/ToggleFilter.js +48 -0
- package/dist/components/library/filters/ToggleFilter.js.map +1 -0
- package/dist/components/library/forms/FormField.js +256 -0
- package/dist/components/library/forms/FormField.js.map +1 -0
- package/dist/components/library/forms/FormModal.js +161 -0
- package/dist/components/library/forms/FormModal.js.map +1 -0
- package/dist/components/library/forms/FormRenderer.js +32 -0
- package/dist/components/library/forms/FormRenderer.js.map +1 -0
- package/dist/components/library/forms/FormSection.js +49 -0
- package/dist/components/library/forms/FormSection.js.map +1 -0
- package/dist/components/library/forms/useFormState.js +85 -0
- package/dist/components/library/forms/useFormState.js.map +1 -0
- package/dist/components/library/heroui/Accordion.js +12 -0
- package/dist/components/library/heroui/Accordion.js.map +1 -0
- package/dist/components/library/heroui/Alert.js +12 -0
- package/dist/components/library/heroui/Alert.js.map +1 -0
- package/dist/components/library/heroui/Badge.js +12 -0
- package/dist/components/library/heroui/Badge.js.map +1 -0
- package/dist/components/library/heroui/Breadcrumbs.js +12 -0
- package/dist/components/library/heroui/Breadcrumbs.js.map +1 -0
- package/dist/components/library/heroui/Button.js +18 -0
- package/dist/components/library/heroui/Button.js.map +1 -0
- package/dist/components/library/heroui/Card.js +12 -0
- package/dist/components/library/heroui/Card.js.map +1 -0
- package/dist/components/library/heroui/Drawer.js +12 -0
- package/dist/components/library/heroui/Drawer.js.map +1 -0
- package/dist/components/library/heroui/Dropdown.js +12 -0
- package/dist/components/library/heroui/Dropdown.js.map +1 -0
- package/dist/components/library/heroui/Input.js +10 -0
- package/dist/components/library/heroui/Input.js.map +1 -0
- package/dist/components/library/heroui/Kbd.js +12 -0
- package/dist/components/library/heroui/Kbd.js.map +1 -0
- package/dist/components/library/heroui/Meter.js +12 -0
- package/dist/components/library/heroui/Meter.js.map +1 -0
- package/dist/components/library/heroui/Modal.js +12 -0
- package/dist/components/library/heroui/Modal.js.map +1 -0
- package/dist/components/library/heroui/Pagination.js +12 -0
- package/dist/components/library/heroui/Pagination.js.map +1 -0
- package/dist/components/library/heroui/ProgressBar.js +12 -0
- package/dist/components/library/heroui/ProgressBar.js.map +1 -0
- package/dist/components/library/heroui/ProgressCircle.js +12 -0
- package/dist/components/library/heroui/ProgressCircle.js.map +1 -0
- package/dist/components/library/heroui/ScrollShadow.js +12 -0
- package/dist/components/library/heroui/ScrollShadow.js.map +1 -0
- package/dist/components/library/heroui/Select.js +12 -0
- package/dist/components/library/heroui/Select.js.map +1 -0
- package/dist/components/library/heroui/Separator.js +12 -0
- package/dist/components/library/heroui/Separator.js.map +1 -0
- package/dist/components/library/heroui/Skeleton.js +12 -0
- package/dist/components/library/heroui/Skeleton.js.map +1 -0
- package/dist/components/library/heroui/Tabs.js +12 -0
- package/dist/components/library/heroui/Tabs.js.map +1 -0
- package/dist/components/library/heroui/Toast.js +13 -0
- package/dist/components/library/heroui/Toast.js.map +1 -0
- package/dist/components/library/heroui/Toggle.js +12 -0
- package/dist/components/library/heroui/Toggle.js.map +1 -0
- package/dist/components/library/heroui/Tooltip.js +12 -0
- package/dist/components/library/heroui/Tooltip.js.map +1 -0
- package/dist/components/library/layout/PageContainer.js +9 -0
- package/dist/components/library/layout/PageContainer.js.map +1 -0
- package/dist/components/library/skeletons/CardSkeleton.js +29 -0
- package/dist/components/library/skeletons/CardSkeleton.js.map +1 -0
- package/dist/components/library/theme/AppThemeProvider.js +55 -0
- package/dist/components/library/theme/AppThemeProvider.js.map +1 -0
- package/dist/components/library/theme/tokens.js +55 -0
- package/dist/components/library/theme/tokens.js.map +1 -0
- package/dist/components/library/ui/Avatar.js +33 -0
- package/dist/components/library/ui/Avatar.js.map +1 -0
- package/dist/components/library/ui/Button.js +50 -0
- package/dist/components/library/ui/Button.js.map +1 -0
- package/dist/components/library/ui/Card.js +21 -0
- package/dist/components/library/ui/Card.js.map +1 -0
- package/dist/components/library/ui/Chip.js +31 -0
- package/dist/components/library/ui/Chip.js.map +1 -0
- package/dist/components/library/ui/Container.js +42 -0
- package/dist/components/library/ui/Container.js.map +1 -0
- package/dist/components/library/ui/EmptyState.js +27 -0
- package/dist/components/library/ui/EmptyState.js.map +1 -0
- package/dist/components/library/ui/Input.js +22 -0
- package/dist/components/library/ui/Input.js.map +1 -0
- package/dist/components/library/ui/Spinner.js +64 -0
- package/dist/components/library/ui/Spinner.js.map +1 -0
- package/dist/components/library/ui/Text.js +43 -0
- package/dist/components/library/ui/Text.js.map +1 -0
- package/dist/components/library/ui/Toggle.js +47 -0
- package/dist/components/library/ui/Toggle.js.map +1 -0
- package/dist/components/workspace/ComponentRegistry.js +231 -0
- package/dist/components/workspace/ComponentRegistry.js.map +1 -0
- package/dist/index.js +185 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/node_modules/clsx/dist/clsx.js +17 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +2925 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +81 -0
- package/scripts/get-graphql-schema.mjs +68 -0
- package/scripts/reset-command-center.sh +358 -0
- package/scripts/rewrite-e2e-assets.mjs +23 -0
- package/scripts/validate-dashboard.sh +290 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsxs as g, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import { useState as m, useRef as p, useEffect as x } from "react";
|
|
3
|
+
import { StopCircleIcon as k, PaperAirplaneIcon as w } from "@heroicons/react/24/solid";
|
|
4
|
+
function S({
|
|
5
|
+
onSend: d,
|
|
6
|
+
disabled: n = !1,
|
|
7
|
+
isLoading: c = !1,
|
|
8
|
+
onStop: s,
|
|
9
|
+
placeholder: h = "Type a message…",
|
|
10
|
+
maxRows: i = 6
|
|
11
|
+
}) {
|
|
12
|
+
const [t, l] = m(""), r = p(null);
|
|
13
|
+
x(() => {
|
|
14
|
+
const e = r.current;
|
|
15
|
+
if (!e) return;
|
|
16
|
+
e.style.height = "auto";
|
|
17
|
+
const f = 22 * i;
|
|
18
|
+
e.style.height = `${Math.min(e.scrollHeight, f)}px`;
|
|
19
|
+
}, [t, i]);
|
|
20
|
+
function o() {
|
|
21
|
+
!t.trim() || n || (d?.(t), l(""), r.current && (r.current.style.height = "auto"));
|
|
22
|
+
}
|
|
23
|
+
function u(e) {
|
|
24
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), o());
|
|
25
|
+
}
|
|
26
|
+
const b = t.trim().length > 0 && !n;
|
|
27
|
+
return /* @__PURE__ */ g("div", { className: "flex items-end gap-2 rounded-xl border border-slate-200 bg-white p-2 shadow-sm transition-colors focus-within:border-brand-300 focus-within:ring-2 focus-within:ring-brand-500/20 dark:border-slate-700 dark:bg-slate-900 dark:focus-within:border-brand-700 dark:focus-within:ring-brand-400/20", children: [
|
|
28
|
+
/* @__PURE__ */ a(
|
|
29
|
+
"textarea",
|
|
30
|
+
{
|
|
31
|
+
ref: r,
|
|
32
|
+
value: t,
|
|
33
|
+
onChange: (e) => l(e.target.value),
|
|
34
|
+
onKeyDown: u,
|
|
35
|
+
placeholder: h,
|
|
36
|
+
disabled: n,
|
|
37
|
+
rows: 1,
|
|
38
|
+
className: "max-h-36 min-h-[22px] flex-1 resize-none bg-transparent px-2 py-1.5 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-60 dark:text-slate-50 dark:placeholder:text-slate-500",
|
|
39
|
+
"aria-label": "Chat message input"
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
c && s ? /* @__PURE__ */ a(
|
|
43
|
+
"button",
|
|
44
|
+
{
|
|
45
|
+
type: "button",
|
|
46
|
+
onClick: s,
|
|
47
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300",
|
|
48
|
+
"aria-label": "Stop generating",
|
|
49
|
+
children: /* @__PURE__ */ a(k, { className: "h-5 w-5" })
|
|
50
|
+
}
|
|
51
|
+
) : /* @__PURE__ */ a(
|
|
52
|
+
"button",
|
|
53
|
+
{
|
|
54
|
+
type: "button",
|
|
55
|
+
onClick: o,
|
|
56
|
+
disabled: !b,
|
|
57
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-brand-600 text-white transition hover:bg-brand-500 disabled:cursor-not-allowed disabled:opacity-40 dark:bg-brand-500 dark:hover:bg-brand-400",
|
|
58
|
+
"aria-label": "Send message",
|
|
59
|
+
children: /* @__PURE__ */ a(w, { className: "h-4 w-4" })
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
S as default
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=ChatInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatInput.js","sources":["../../../../src/components/library/chat/ChatInput.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { PaperAirplaneIcon, StopCircleIcon } from \"@heroicons/react/24/solid\";\n\n/**\n * Chat input with auto-resize textarea, Send button, and keyboard shortcuts.\n * Enter sends, Shift+Enter inserts newline.\n *\n * @param {Function} onSend — (content: string) => void\n * @param {boolean} disabled — disable input while agent is processing\n * @param {boolean} isLoading — show stop button instead of send\n * @param {Function} onStop — optional: called when stop is clicked\n * @param {string} placeholder\n * @param {number} maxRows — max visible rows before scroll (default 6)\n */\nexport default function ChatInput({\n onSend,\n disabled = false,\n isLoading = false,\n onStop,\n placeholder = \"Type a message…\",\n maxRows = 6,\n}) {\n const [value, setValue] = useState(\"\");\n const textareaRef = useRef(null);\n\n useEffect(() => {\n const ta = textareaRef.current;\n if (!ta) return;\n ta.style.height = \"auto\";\n const lineHeight = 22;\n const maxHeight = lineHeight * maxRows;\n ta.style.height = `${Math.min(ta.scrollHeight, maxHeight)}px`;\n }, [value, maxRows]);\n\n function handleSend() {\n if (!value.trim() || disabled) return;\n onSend?.(value);\n setValue(\"\");\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n }\n }\n\n function handleKeyDown(e) {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n }\n\n const canSend = value.trim().length > 0 && !disabled;\n\n return (\n <div className=\"flex items-end gap-2 rounded-xl border border-slate-200 bg-white p-2 shadow-sm transition-colors focus-within:border-brand-300 focus-within:ring-2 focus-within:ring-brand-500/20 dark:border-slate-700 dark:bg-slate-900 dark:focus-within:border-brand-700 dark:focus-within:ring-brand-400/20\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n className=\"max-h-36 min-h-[22px] flex-1 resize-none bg-transparent px-2 py-1.5 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-60 dark:text-slate-50 dark:placeholder:text-slate-500\"\n aria-label=\"Chat message input\"\n />\n\n {isLoading && onStop ? (\n <button\n type=\"button\"\n onClick={onStop}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300\"\n aria-label=\"Stop generating\"\n >\n <StopCircleIcon className=\"h-5 w-5\" />\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-brand-600 text-white transition hover:bg-brand-500 disabled:cursor-not-allowed disabled:opacity-40 dark:bg-brand-500 dark:hover:bg-brand-400\"\n aria-label=\"Send message\"\n >\n <PaperAirplaneIcon className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n );\n}\n"],"names":["ChatInput","onSend","disabled","isLoading","onStop","placeholder","maxRows","value","setValue","useState","textareaRef","useRef","useEffect","ta","maxHeight","handleSend","handleKeyDown","canSend","jsxs","jsx","StopCircleIcon","PaperAirplaneIcon"],"mappings":";;;AAcA,SAAwBA,EAAU;AAAA,EAChC,QAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,QAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,SAAAC,IAAU;AACZ,GAAG;AACD,QAAM,CAACC,GAAOC,CAAQ,IAAIC,EAAS,EAAE,GAC/BC,IAAcC,EAAO,IAAI;AAE/B,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAKH,EAAY;AACvB,QAAI,CAACG,EAAI;AACT,IAAAA,EAAG,MAAM,SAAS;AAElB,UAAMC,IADa,KACYR;AAC/B,IAAAO,EAAG,MAAM,SAAS,GAAG,KAAK,IAAIA,EAAG,cAAcC,CAAS,CAAC;AAAA,EAC3D,GAAG,CAACP,GAAOD,CAAO,CAAC;AAEnB,WAASS,IAAa;AACpB,IAAI,CAACR,EAAM,KAAA,KAAUL,MACrBD,IAASM,CAAK,GACdC,EAAS,EAAE,GACPE,EAAY,YACdA,EAAY,QAAQ,MAAM,SAAS;AAAA,EAEvC;AAEA,WAASM,EAAc,GAAG;AACxB,IAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,aAC1B,EAAE,eAAA,GACFD,EAAA;AAAA,EAEJ;AAEA,QAAME,IAAUV,EAAM,KAAA,EAAO,SAAS,KAAK,CAACL;AAE5C,SACE,gBAAAgB,EAAC,OAAA,EAAI,WAAU,oSACb,UAAA;AAAA,IAAA,gBAAAC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKT;AAAA,QACL,OAAAH;AAAA,QACA,UAAU,CAAC,MAAMC,EAAS,EAAE,OAAO,KAAK;AAAA,QACxC,WAAWQ;AAAA,QACX,aAAAX;AAAA,QACA,UAAAH;AAAA,QACA,MAAM;AAAA,QACN,WAAU;AAAA,QACV,cAAW;AAAA,MAAA;AAAA,IAAA;AAAA,IAGZC,KAAaC,IACZ,gBAAAe;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAASf;AAAA,QACT,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,UAAA,gBAAAe,EAACC,GAAA,EAAe,WAAU,UAAA,CAAU;AAAA,MAAA;AAAA,IAAA,IAGtC,gBAAAD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAASJ;AAAA,QACT,UAAU,CAACE;AAAA,QACX,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,UAAA,gBAAAE,EAACE,GAAA,EAAkB,WAAU,UAAA,CAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACzC,GAEJ;AAEJ;"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx as r, jsxs as c } from "react/jsx-runtime";
|
|
2
|
+
import m from "react";
|
|
3
|
+
import { renderSchemaComponent as h } from "../../workspace/ComponentRegistry.js";
|
|
4
|
+
import p from "./ChatToolCall.js";
|
|
5
|
+
import { UserCircleIcon as u, CpuChipIcon as f } from "@heroicons/react/24/solid";
|
|
6
|
+
function i(...t) {
|
|
7
|
+
return t.filter(Boolean).join(" ");
|
|
8
|
+
}
|
|
9
|
+
function b(t) {
|
|
10
|
+
if (!t) return null;
|
|
11
|
+
const s = [];
|
|
12
|
+
let e = 0;
|
|
13
|
+
const a = /```(\w*)\n?([\s\S]*?)```/g;
|
|
14
|
+
let n = 0, l;
|
|
15
|
+
for (; (l = a.exec(t)) !== null; )
|
|
16
|
+
l.index > n && s.push(
|
|
17
|
+
/* @__PURE__ */ r("span", { children: x(t.slice(n, l.index)) }, e++)
|
|
18
|
+
), s.push(
|
|
19
|
+
/* @__PURE__ */ r(
|
|
20
|
+
"pre",
|
|
21
|
+
{
|
|
22
|
+
className: "my-2 overflow-x-auto rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs leading-relaxed dark:border-slate-700 dark:bg-slate-800/50",
|
|
23
|
+
children: /* @__PURE__ */ r("code", { children: l[2] })
|
|
24
|
+
},
|
|
25
|
+
e++
|
|
26
|
+
)
|
|
27
|
+
), n = l.index + l[0].length;
|
|
28
|
+
return n < t.length && s.push(
|
|
29
|
+
/* @__PURE__ */ r("span", { children: x(t.slice(n)) }, e++)
|
|
30
|
+
), s;
|
|
31
|
+
}
|
|
32
|
+
function x(t) {
|
|
33
|
+
return t.split(/(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*)/g).map((e, a) => e.startsWith("**") && e.endsWith("**") ? /* @__PURE__ */ r("strong", { className: "font-semibold", children: e.slice(2, -2) }, a) : e.startsWith("*") && e.endsWith("*") ? /* @__PURE__ */ r("em", { children: e.slice(1, -1) }, a) : e.startsWith("`") && e.endsWith("`") ? /* @__PURE__ */ r(
|
|
34
|
+
"code",
|
|
35
|
+
{
|
|
36
|
+
className: "rounded bg-slate-100 px-1 py-0.5 text-xs font-mono dark:bg-slate-800",
|
|
37
|
+
children: e.slice(1, -1)
|
|
38
|
+
},
|
|
39
|
+
a
|
|
40
|
+
) : e.split(`
|
|
41
|
+
`).map((n, l, d) => /* @__PURE__ */ c(m.Fragment, { children: [
|
|
42
|
+
n,
|
|
43
|
+
l < d.length - 1 ? /* @__PURE__ */ r("br", {}) : null
|
|
44
|
+
] }, `${a}-${l}`)));
|
|
45
|
+
}
|
|
46
|
+
function C({ message: t, avatar: s }) {
|
|
47
|
+
const e = t.role === "user", a = t.role === "system", n = t.role === "assistant", l = e ? /* @__PURE__ */ r(u, { className: "h-7 w-7 text-slate-400 dark:text-slate-500" }) : /* @__PURE__ */ r("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-brand-100 dark:bg-brand-900/40", children: /* @__PURE__ */ r(f, { className: "h-4 w-4 text-brand-600 dark:text-brand-400" }) });
|
|
48
|
+
return a ? /* @__PURE__ */ r(
|
|
49
|
+
"div",
|
|
50
|
+
{
|
|
51
|
+
className: i(
|
|
52
|
+
"mx-auto max-w-lg rounded-lg px-4 py-2 text-center text-xs",
|
|
53
|
+
t.isError ? "bg-red-50 text-red-600 dark:bg-red-950/30 dark:text-red-400" : "text-slate-400 dark:text-slate-500"
|
|
54
|
+
),
|
|
55
|
+
children: t.content
|
|
56
|
+
}
|
|
57
|
+
) : /* @__PURE__ */ c(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
className: i(
|
|
61
|
+
"flex gap-3",
|
|
62
|
+
e ? "flex-row-reverse" : "flex-row"
|
|
63
|
+
),
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ r("div", { className: "shrink-0 pt-0.5", children: s ?? l }),
|
|
66
|
+
/* @__PURE__ */ c(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
className: i(
|
|
70
|
+
"max-w-[80%] space-y-2",
|
|
71
|
+
e ? "items-end" : "items-start"
|
|
72
|
+
),
|
|
73
|
+
children: [
|
|
74
|
+
t.content ? /* @__PURE__ */ r(
|
|
75
|
+
"div",
|
|
76
|
+
{
|
|
77
|
+
className: i(
|
|
78
|
+
"rounded-2xl px-4 py-2.5 text-sm leading-relaxed",
|
|
79
|
+
e ? "rounded-tr-md bg-brand-600 text-white dark:bg-brand-500" : "rounded-tl-md bg-slate-100 text-slate-800 dark:bg-slate-800 dark:text-slate-100",
|
|
80
|
+
t.isStreaming && "animate-pulse"
|
|
81
|
+
),
|
|
82
|
+
children: n ? b(t.content) : t.content
|
|
83
|
+
}
|
|
84
|
+
) : null,
|
|
85
|
+
t.toolCalls?.length ? /* @__PURE__ */ r("div", { className: "space-y-1.5 pl-1", children: t.toolCalls.map((d, o) => /* @__PURE__ */ r(p, { toolCall: d }, d.id ?? o)) }) : null,
|
|
86
|
+
t.components?.length ? /* @__PURE__ */ r("div", { className: "w-full space-y-3 pt-1", children: t.components.map(
|
|
87
|
+
(d, o) => h(d, o)
|
|
88
|
+
) }) : null,
|
|
89
|
+
t.timestamp ? /* @__PURE__ */ r(
|
|
90
|
+
"div",
|
|
91
|
+
{
|
|
92
|
+
className: i(
|
|
93
|
+
"px-1 text-[10px] text-slate-400 dark:text-slate-500",
|
|
94
|
+
e ? "text-right" : "text-left"
|
|
95
|
+
),
|
|
96
|
+
children: new Date(t.timestamp).toLocaleTimeString([], {
|
|
97
|
+
hour: "2-digit",
|
|
98
|
+
minute: "2-digit"
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
) : null
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
C as default
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=ChatMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatMessage.js","sources":["../../../../src/components/library/chat/ChatMessage.jsx"],"sourcesContent":["import React from \"react\";\nimport { renderSchemaComponent } from \"@/components/workspace/ComponentRegistry\";\nimport ChatToolCall from \"./ChatToolCall\";\nimport { UserCircleIcon, CpuChipIcon } from \"@heroicons/react/24/solid\";\n\nfunction cx(...classes) {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Lightweight inline formatter for assistant messages.\n * Handles code blocks, inline code, bold, italic, and line breaks.\n */\nfunction formatContent(text) {\n if (!text) return null;\n const parts = [];\n let key = 0;\n\n const codeBlockRegex = /```(\\w*)\\n?([\\s\\S]*?)```/g;\n let lastIndex = 0;\n let match;\n\n while ((match = codeBlockRegex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n parts.push(\n <span key={key++}>{formatInline(text.slice(lastIndex, match.index))}</span>\n );\n }\n parts.push(\n <pre\n key={key++}\n className=\"my-2 overflow-x-auto rounded-lg border border-slate-200 bg-slate-50 p-3 text-xs leading-relaxed dark:border-slate-700 dark:bg-slate-800/50\"\n >\n <code>{match[2]}</code>\n </pre>\n );\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n parts.push(\n <span key={key++}>{formatInline(text.slice(lastIndex))}</span>\n );\n }\n\n return parts;\n}\n\nfunction formatInline(text) {\n const tokens = text.split(/(`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*)/g);\n return tokens.map((token, i) => {\n if (token.startsWith(\"**\") && token.endsWith(\"**\")) {\n return <strong key={i} className=\"font-semibold\">{token.slice(2, -2)}</strong>;\n }\n if (token.startsWith(\"*\") && token.endsWith(\"*\")) {\n return <em key={i}>{token.slice(1, -1)}</em>;\n }\n if (token.startsWith(\"`\") && token.endsWith(\"`\")) {\n return (\n <code\n key={i}\n className=\"rounded bg-slate-100 px-1 py-0.5 text-xs font-mono dark:bg-slate-800\"\n >\n {token.slice(1, -1)}\n </code>\n );\n }\n return token.split(\"\\n\").map((line, j, arr) => (\n <React.Fragment key={`${i}-${j}`}>\n {line}\n {j < arr.length - 1 ? <br /> : null}\n </React.Fragment>\n ));\n });\n}\n\n/**\n * Renders a single chat message.\n *\n * @param {Object} message — { id, role, content, components?, toolCalls?, isError?, isStreaming?, timestamp? }\n * @param {React.ReactNode} avatar — custom avatar override\n */\nexport default function ChatMessage({ message, avatar }) {\n const isUser = message.role === \"user\";\n const isSystem = message.role === \"system\";\n const isAssistant = message.role === \"assistant\";\n\n const defaultAvatar = isUser ? (\n <UserCircleIcon className=\"h-7 w-7 text-slate-400 dark:text-slate-500\" />\n ) : (\n <div className=\"flex h-7 w-7 items-center justify-center rounded-lg bg-brand-100 dark:bg-brand-900/40\">\n <CpuChipIcon className=\"h-4 w-4 text-brand-600 dark:text-brand-400\" />\n </div>\n );\n\n if (isSystem) {\n return (\n <div\n className={cx(\n \"mx-auto max-w-lg rounded-lg px-4 py-2 text-center text-xs\",\n message.isError\n ? \"bg-red-50 text-red-600 dark:bg-red-950/30 dark:text-red-400\"\n : \"text-slate-400 dark:text-slate-500\"\n )}\n >\n {message.content}\n </div>\n );\n }\n\n return (\n <div\n className={cx(\n \"flex gap-3\",\n isUser ? \"flex-row-reverse\" : \"flex-row\"\n )}\n >\n {/* Avatar */}\n <div className=\"shrink-0 pt-0.5\">{avatar ?? defaultAvatar}</div>\n\n {/* Bubble */}\n <div\n className={cx(\n \"max-w-[80%] space-y-2\",\n isUser ? \"items-end\" : \"items-start\"\n )}\n >\n {/* Text content */}\n {message.content ? (\n <div\n className={cx(\n \"rounded-2xl px-4 py-2.5 text-sm leading-relaxed\",\n isUser\n ? \"rounded-tr-md bg-brand-600 text-white dark:bg-brand-500\"\n : \"rounded-tl-md bg-slate-100 text-slate-800 dark:bg-slate-800 dark:text-slate-100\",\n message.isStreaming && \"animate-pulse\"\n )}\n >\n {isAssistant ? formatContent(message.content) : message.content}\n </div>\n ) : null}\n\n {/* Tool calls */}\n {message.toolCalls?.length ? (\n <div className=\"space-y-1.5 pl-1\">\n {message.toolCalls.map((tc, idx) => (\n <ChatToolCall key={tc.id ?? idx} toolCall={tc} />\n ))}\n </div>\n ) : null}\n\n {/* Inline components — render real command center components */}\n {message.components?.length ? (\n <div className=\"w-full space-y-3 pt-1\">\n {message.components.map((comp, idx) =>\n renderSchemaComponent(comp, idx)\n )}\n </div>\n ) : null}\n\n {/* Timestamp */}\n {message.timestamp ? (\n <div\n className={cx(\n \"px-1 text-[10px] text-slate-400 dark:text-slate-500\",\n isUser ? \"text-right\" : \"text-left\"\n )}\n >\n {new Date(message.timestamp).toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n })}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"names":["cx","classes","formatContent","text","parts","key","codeBlockRegex","lastIndex","match","jsx","formatInline","token","i","line","j","arr","jsxs","React","ChatMessage","message","avatar","isUser","isSystem","isAssistant","defaultAvatar","UserCircleIcon","CpuChipIcon","tc","idx","ChatToolCall","comp","renderSchemaComponent"],"mappings":";;;;;AAKA,SAASA,KAAMC,GAAS;AACtB,SAAOA,EAAQ,OAAO,OAAO,EAAE,KAAK,GAAG;AACzC;AAMA,SAASC,EAAcC,GAAM;AAC3B,MAAI,CAACA,EAAM,QAAO;AAClB,QAAMC,IAAQ,CAAA;AACd,MAAIC,IAAM;AAEV,QAAMC,IAAiB;AACvB,MAAIC,IAAY,GACZC;AAEJ,UAAQA,IAAQF,EAAe,KAAKH,CAAI,OAAO;AAC7C,IAAIK,EAAM,QAAQD,KAChBH,EAAM;AAAA,MACJ,gBAAAK,EAAC,QAAA,EAAkB,UAAAC,EAAaP,EAAK,MAAMI,GAAWC,EAAM,KAAK,CAAC,EAAA,GAAvDH,GAAyD;AAAA,IAAA,GAGxED,EAAM;AAAA,MACJ,gBAAAK;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,WAAU;AAAA,UAEV,UAAA,gBAAAA,EAAC,QAAA,EAAM,UAAAD,EAAM,CAAC,EAAA,CAAE;AAAA,QAAA;AAAA,QAHXH;AAAA,MAAA;AAAA,IAIP,GAEFE,IAAYC,EAAM,QAAQA,EAAM,CAAC,EAAE;AAGrC,SAAID,IAAYJ,EAAK,UACnBC,EAAM;AAAA,IACJ,gBAAAK,EAAC,UAAkB,UAAAC,EAAaP,EAAK,MAAMI,CAAS,CAAC,KAA1CF,GAA4C;AAAA,EAAA,GAIpDD;AACT;AAEA,SAASM,EAAaP,GAAM;AAE1B,SADeA,EAAK,MAAM,oCAAoC,EAChD,IAAI,CAACQ,GAAOC,MACpBD,EAAM,WAAW,IAAI,KAAKA,EAAM,SAAS,IAAI,IACxC,gBAAAF,EAAC,YAAe,WAAU,iBAAiB,YAAM,MAAM,GAAG,EAAE,EAAA,GAA/CG,CAAiD,IAEnED,EAAM,WAAW,GAAG,KAAKA,EAAM,SAAS,GAAG,sBACrC,MAAA,EAAY,UAAAA,EAAM,MAAM,GAAG,EAAE,KAArBC,CAAuB,IAErCD,EAAM,WAAW,GAAG,KAAKA,EAAM,SAAS,GAAG,IAE3C,gBAAAF;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,WAAU;AAAA,MAET,UAAAE,EAAM,MAAM,GAAG,EAAE;AAAA,IAAA;AAAA,IAHbC;AAAA,EAAA,IAOJD,EAAM,MAAM;AAAA,CAAI,EAAE,IAAI,CAACE,GAAMC,GAAGC,MACrC,gBAAAC,EAACC,EAAM,UAAN,EACE,UAAA;AAAA,IAAAJ;AAAA,IACAC,IAAIC,EAAI,SAAS,IAAI,gBAAAN,EAAC,QAAG,IAAK;AAAA,EAAA,EAAA,GAFZ,GAAGG,CAAC,IAAIE,CAAC,EAG9B,CACD,CACF;AACH;AAQA,SAAwBI,EAAY,EAAE,SAAAC,GAAS,QAAAC,KAAU;AACvD,QAAMC,IAASF,EAAQ,SAAS,QAC1BG,IAAWH,EAAQ,SAAS,UAC5BI,IAAcJ,EAAQ,SAAS,aAE/BK,IAAgBH,IACpB,gBAAAZ,EAACgB,GAAA,EAAe,WAAU,8CAA6C,IAEvE,gBAAAhB,EAAC,OAAA,EAAI,WAAU,yFACb,UAAA,gBAAAA,EAACiB,GAAA,EAAY,WAAU,8CAA6C,GACtE;AAGF,SAAIJ,IAEA,gBAAAb;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWT;AAAA,QACT;AAAA,QACAmB,EAAQ,UACJ,gEACA;AAAA,MAAA;AAAA,MAGL,UAAAA,EAAQ;AAAA,IAAA;AAAA,EAAA,IAMb,gBAAAH;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWhB;AAAA,QACT;AAAA,QACAqB,IAAS,qBAAqB;AAAA,MAAA;AAAA,MAIhC,UAAA;AAAA,QAAA,gBAAAZ,EAAC,OAAA,EAAI,WAAU,mBAAmB,UAAAW,KAAUI,GAAc;AAAA,QAG1D,gBAAAR;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWhB;AAAA,cACT;AAAA,cACAqB,IAAS,cAAc;AAAA,YAAA;AAAA,YAIxB,UAAA;AAAA,cAAAF,EAAQ,UACP,gBAAAV;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAWT;AAAA,oBACT;AAAA,oBACAqB,IACI,4DACA;AAAA,oBACJF,EAAQ,eAAe;AAAA,kBAAA;AAAA,kBAGxB,UAAAI,IAAcrB,EAAciB,EAAQ,OAAO,IAAIA,EAAQ;AAAA,gBAAA;AAAA,cAAA,IAExD;AAAA,cAGHA,EAAQ,WAAW,SAClB,gBAAAV,EAAC,SAAI,WAAU,oBACZ,UAAAU,EAAQ,UAAU,IAAI,CAACQ,GAAIC,MAC1B,gBAAAnB,EAACoB,KAAgC,UAAUF,EAAA,GAAxBA,EAAG,MAAMC,CAAmB,CAChD,EAAA,CACH,IACE;AAAA,cAGHT,EAAQ,YAAY,SACnB,gBAAAV,EAAC,SAAI,WAAU,yBACZ,YAAQ,WAAW;AAAA,gBAAI,CAACqB,GAAMF,MAC7BG,EAAsBD,GAAMF,CAAG;AAAA,cAAA,GAEnC,IACE;AAAA,cAGHT,EAAQ,YACP,gBAAAV;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAWT;AAAA,oBACT;AAAA,oBACAqB,IAAS,eAAe;AAAA,kBAAA;AAAA,kBAGzB,cAAI,KAAKF,EAAQ,SAAS,EAAE,mBAAmB,IAAI;AAAA,oBAClD,MAAM;AAAA,oBACN,QAAQ;AAAA,kBAAA,CACT;AAAA,gBAAA;AAAA,cAAA,IAED;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACN;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as e, jsxs as m } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as s, useEffect as d } from "react";
|
|
3
|
+
import x from "./ChatMessage.js";
|
|
4
|
+
import c from "./ChatTypingIndicator.js";
|
|
5
|
+
import v from "./ChatSuggestions.js";
|
|
6
|
+
function N({
|
|
7
|
+
messages: l = [],
|
|
8
|
+
isLoading: o = !1,
|
|
9
|
+
isStreaming: t = !1,
|
|
10
|
+
suggestions: n = [],
|
|
11
|
+
onSuggestion: f,
|
|
12
|
+
renderAvatar: i
|
|
13
|
+
}) {
|
|
14
|
+
const r = s(null), h = s(null);
|
|
15
|
+
d(() => {
|
|
16
|
+
r.current?.scrollIntoView({ behavior: "smooth" });
|
|
17
|
+
}, [l.length, o, t]);
|
|
18
|
+
const u = l[l.length - 1], p = n.length > 0 && !o && !t && u?.role === "assistant";
|
|
19
|
+
return /* @__PURE__ */ e(
|
|
20
|
+
"div",
|
|
21
|
+
{
|
|
22
|
+
ref: h,
|
|
23
|
+
className: "flex-1 overflow-y-auto px-4 py-4",
|
|
24
|
+
children: /* @__PURE__ */ m("div", { className: "mx-auto max-w-3xl space-y-4", children: [
|
|
25
|
+
l.map((a) => /* @__PURE__ */ e(
|
|
26
|
+
x,
|
|
27
|
+
{
|
|
28
|
+
message: a,
|
|
29
|
+
avatar: i?.(a)
|
|
30
|
+
},
|
|
31
|
+
a.id
|
|
32
|
+
)),
|
|
33
|
+
p ? /* @__PURE__ */ e("div", { className: "pl-10", children: /* @__PURE__ */ e(
|
|
34
|
+
v,
|
|
35
|
+
{
|
|
36
|
+
suggestions: n,
|
|
37
|
+
onSelect: f
|
|
38
|
+
}
|
|
39
|
+
) }) : null,
|
|
40
|
+
o && !t ? /* @__PURE__ */ e(c, { label: "Thinking" }) : null,
|
|
41
|
+
t ? /* @__PURE__ */ e(c, { label: "Generating" }) : null,
|
|
42
|
+
/* @__PURE__ */ e("div", { ref: r })
|
|
43
|
+
] })
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
N as default
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=ChatMessageList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatMessageList.js","sources":["../../../../src/components/library/chat/ChatMessageList.jsx"],"sourcesContent":["import React, { useRef, useEffect } from \"react\";\nimport ChatMessage from \"./ChatMessage\";\nimport ChatTypingIndicator from \"./ChatTypingIndicator\";\nimport ChatSuggestions from \"./ChatSuggestions\";\n\n/**\n * Scrollable message area with auto-scroll to latest message.\n *\n * @param {Array} messages — array of message objects\n * @param {boolean} isLoading — show typing indicator\n * @param {boolean} isStreaming — agent is streaming (show different indicator text)\n * @param {string[]} suggestions — follow-up suggestions shown after last assistant message\n * @param {Function} onSuggestion — (text) => void\n * @param {Function} renderAvatar — (message) => ReactNode, optional per-message avatar\n */\nexport default function ChatMessageList({\n messages = [],\n isLoading = false,\n isStreaming = false,\n suggestions = [],\n onSuggestion,\n renderAvatar,\n}) {\n const bottomRef = useRef(null);\n const containerRef = useRef(null);\n\n useEffect(() => {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages.length, isLoading, isStreaming]);\n\n const lastMessage = messages[messages.length - 1];\n const showSuggestions =\n suggestions.length > 0 &&\n !isLoading &&\n !isStreaming &&\n lastMessage?.role === \"assistant\";\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 overflow-y-auto px-4 py-4\"\n >\n <div className=\"mx-auto max-w-3xl space-y-4\">\n {messages.map((msg) => (\n <ChatMessage\n key={msg.id}\n message={msg}\n avatar={renderAvatar?.(msg)}\n />\n ))}\n\n {showSuggestions ? (\n <div className=\"pl-10\">\n <ChatSuggestions\n suggestions={suggestions}\n onSelect={onSuggestion}\n />\n </div>\n ) : null}\n\n {isLoading && !isStreaming ? (\n <ChatTypingIndicator label=\"Thinking\" />\n ) : null}\n\n {isStreaming ? (\n <ChatTypingIndicator label=\"Generating\" />\n ) : null}\n\n <div ref={bottomRef} />\n </div>\n </div>\n );\n}\n"],"names":["ChatMessageList","messages","isLoading","isStreaming","suggestions","onSuggestion","renderAvatar","bottomRef","useRef","containerRef","useEffect","lastMessage","showSuggestions","jsx","jsxs","msg","ChatMessage","ChatSuggestions","ChatTypingIndicator"],"mappings":";;;;;AAeA,SAAwBA,EAAgB;AAAA,EACtC,UAAAC,IAAW,CAAA;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,aAAAC,IAAc;AAAA,EACd,aAAAC,IAAc,CAAA;AAAA,EACd,cAAAC;AAAA,EACA,cAAAC;AACF,GAAG;AACD,QAAMC,IAAYC,EAAO,IAAI,GACvBC,IAAeD,EAAO,IAAI;AAEhC,EAAAE,EAAU,MAAM;AACd,IAAAH,EAAU,SAAS,eAAe,EAAE,UAAU,UAAU;AAAA,EAC1D,GAAG,CAACN,EAAS,QAAQC,GAAWC,CAAW,CAAC;AAE5C,QAAMQ,IAAcV,EAASA,EAAS,SAAS,CAAC,GAC1CW,IACJR,EAAY,SAAS,KACrB,CAACF,KACD,CAACC,KACDQ,GAAa,SAAS;AAExB,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKJ;AAAA,MACL,WAAU;AAAA,MAEV,UAAA,gBAAAK,EAAC,OAAA,EAAI,WAAU,+BACZ,UAAA;AAAA,QAAAb,EAAS,IAAI,CAACc,MACb,gBAAAF;AAAA,UAACG;AAAA,UAAA;AAAA,YAEC,SAASD;AAAA,YACT,QAAQT,IAAeS,CAAG;AAAA,UAAA;AAAA,UAFrBA,EAAI;AAAA,QAAA,CAIZ;AAAA,QAEAH,IACC,gBAAAC,EAAC,OAAA,EAAI,WAAU,SACb,UAAA,gBAAAA;AAAA,UAACI;AAAA,UAAA;AAAA,YACC,aAAAb;AAAA,YACA,UAAUC;AAAA,UAAA;AAAA,QAAA,GAEd,IACE;AAAA,QAEHH,KAAa,CAACC,sBACZe,GAAA,EAAoB,OAAM,YAAW,IACpC;AAAA,QAEHf,IACC,gBAAAU,EAACK,GAAA,EAAoB,OAAM,cAAa,IACtC;AAAA,QAEJ,gBAAAL,EAAC,OAAA,EAAI,KAAKN,EAAA,CAAW;AAAA,MAAA,EAAA,CACvB;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsxs as r, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import f from "./ChatMessageList.js";
|
|
4
|
+
import p from "./ChatInput.js";
|
|
5
|
+
import u from "./ChatWelcome.js";
|
|
6
|
+
import x from "./useChatState.js";
|
|
7
|
+
import { TrashIcon as k } from "@heroicons/react/24/outline";
|
|
8
|
+
function w({
|
|
9
|
+
title: o = "AI Assistant",
|
|
10
|
+
onSend: l,
|
|
11
|
+
initialMessages: i = [],
|
|
12
|
+
welcomeTitle: n,
|
|
13
|
+
welcomeSubtitle: d,
|
|
14
|
+
suggestions: a = [],
|
|
15
|
+
placeholder: m,
|
|
16
|
+
className: g = "",
|
|
17
|
+
renderAvatar: h,
|
|
18
|
+
showHeader: c = !0
|
|
19
|
+
}) {
|
|
20
|
+
const e = x({ initialMessages: i, onSend: l }), b = e.messages.length === 0;
|
|
21
|
+
return /* @__PURE__ */ r(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
className: [
|
|
25
|
+
"flex flex-col overflow-hidden rounded-xl border border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900",
|
|
26
|
+
g
|
|
27
|
+
].filter(Boolean).join(" "),
|
|
28
|
+
children: [
|
|
29
|
+
c ? /* @__PURE__ */ r("div", { className: "flex items-center justify-between border-b border-slate-100 px-4 py-3 dark:border-slate-800", children: [
|
|
30
|
+
/* @__PURE__ */ t("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-50", children: o }),
|
|
31
|
+
e.messages.length > 0 ? /* @__PURE__ */ t(
|
|
32
|
+
"button",
|
|
33
|
+
{
|
|
34
|
+
type: "button",
|
|
35
|
+
onClick: e.clearMessages,
|
|
36
|
+
className: "rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300",
|
|
37
|
+
"aria-label": "Clear chat",
|
|
38
|
+
children: /* @__PURE__ */ t(k, { className: "h-4 w-4" })
|
|
39
|
+
}
|
|
40
|
+
) : null
|
|
41
|
+
] }) : null,
|
|
42
|
+
b ? /* @__PURE__ */ t(
|
|
43
|
+
u,
|
|
44
|
+
{
|
|
45
|
+
title: n,
|
|
46
|
+
subtitle: d,
|
|
47
|
+
suggestions: a,
|
|
48
|
+
onSuggestion: (s) => e.sendMessage(s)
|
|
49
|
+
}
|
|
50
|
+
) : /* @__PURE__ */ t(
|
|
51
|
+
f,
|
|
52
|
+
{
|
|
53
|
+
messages: e.messages,
|
|
54
|
+
isLoading: e.isLoading,
|
|
55
|
+
isStreaming: e.isStreaming,
|
|
56
|
+
suggestions: a,
|
|
57
|
+
onSuggestion: (s) => e.sendMessage(s),
|
|
58
|
+
renderAvatar: h
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ t("div", { className: "border-t border-slate-100 p-3 dark:border-slate-800", children: /* @__PURE__ */ t(
|
|
62
|
+
p,
|
|
63
|
+
{
|
|
64
|
+
onSend: (s) => e.sendMessage(s),
|
|
65
|
+
disabled: e.isLoading,
|
|
66
|
+
isLoading: e.isLoading,
|
|
67
|
+
placeholder: m
|
|
68
|
+
}
|
|
69
|
+
) })
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
w as default
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=ChatPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatPanel.js","sources":["../../../../src/components/library/chat/ChatPanel.jsx"],"sourcesContent":["import React from \"react\";\nimport ChatMessageList from \"./ChatMessageList\";\nimport ChatInput from \"./ChatInput\";\nimport ChatWelcome from \"./ChatWelcome\";\nimport useChatState from \"./useChatState\";\nimport { TrashIcon } from \"@heroicons/react/24/outline\";\n\n/**\n * All-in-one chat panel. Composes ChatMessageList, ChatInput, ChatWelcome,\n * and useChatState into a single drop-in component.\n *\n * @param {string} title — panel header title\n * @param {Function} onSend — async (userMessage, history, helpers) => assistantMessage?\n * @param {Array} initialMessages — seed messages\n * @param {string} welcomeTitle — welcome screen heading\n * @param {string} welcomeSubtitle — welcome screen description\n * @param {string[]} suggestions — starter and follow-up prompts\n * @param {string} placeholder — input placeholder\n * @param {string} className — additional classes on the root container\n * @param {Function} renderAvatar — (message) => ReactNode\n * @param {boolean} showHeader — show the title bar (default true)\n */\nexport default function ChatPanel({\n title = \"AI Assistant\",\n onSend,\n initialMessages = [],\n welcomeTitle,\n welcomeSubtitle,\n suggestions = [],\n placeholder,\n className = \"\",\n renderAvatar,\n showHeader = true,\n}) {\n const chat = useChatState({ initialMessages, onSend });\n\n const isEmpty = chat.messages.length === 0;\n\n return (\n <div\n className={[\n \"flex flex-col overflow-hidden rounded-xl border border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {/* Header */}\n {showHeader ? (\n <div className=\"flex items-center justify-between border-b border-slate-100 px-4 py-3 dark:border-slate-800\">\n <h3 className=\"text-sm font-semibold text-slate-900 dark:text-slate-50\">\n {title}\n </h3>\n {chat.messages.length > 0 ? (\n <button\n type=\"button\"\n onClick={chat.clearMessages}\n className=\"rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300\"\n aria-label=\"Clear chat\"\n >\n <TrashIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n </div>\n ) : null}\n\n {/* Messages or welcome */}\n {isEmpty ? (\n <ChatWelcome\n title={welcomeTitle}\n subtitle={welcomeSubtitle}\n suggestions={suggestions}\n onSuggestion={(text) => chat.sendMessage(text)}\n />\n ) : (\n <ChatMessageList\n messages={chat.messages}\n isLoading={chat.isLoading}\n isStreaming={chat.isStreaming}\n suggestions={suggestions}\n onSuggestion={(text) => chat.sendMessage(text)}\n renderAvatar={renderAvatar}\n />\n )}\n\n {/* Input */}\n <div className=\"border-t border-slate-100 p-3 dark:border-slate-800\">\n <ChatInput\n onSend={(content) => chat.sendMessage(content)}\n disabled={chat.isLoading}\n isLoading={chat.isLoading}\n placeholder={placeholder}\n />\n </div>\n </div>\n );\n}\n"],"names":["ChatPanel","title","onSend","initialMessages","welcomeTitle","welcomeSubtitle","suggestions","placeholder","className","renderAvatar","showHeader","chat","useChatState","isEmpty","jsxs","jsx","TrashIcon","ChatWelcome","text","ChatMessageList","ChatInput","content"],"mappings":";;;;;;;AAsBA,SAAwBA,EAAU;AAAA,EAChC,OAAAC,IAAQ;AAAA,EACR,QAAAC;AAAA,EACA,iBAAAC,IAAkB,CAAA;AAAA,EAClB,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,aAAAC,IAAc,CAAA;AAAA,EACd,aAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,cAAAC;AAAA,EACA,YAAAC,IAAa;AACf,GAAG;AACD,QAAMC,IAAOC,EAAa,EAAE,iBAAAT,GAAiB,QAAAD,GAAQ,GAE/CW,IAAUF,EAAK,SAAS,WAAW;AAEzC,SACE,gBAAAG;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACAN;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MAGV,UAAA;AAAA,QAAAE,IACC,gBAAAI,EAAC,OAAA,EAAI,WAAU,+FACb,UAAA;AAAA,UAAA,gBAAAC,EAAC,MAAA,EAAG,WAAU,2DACX,UAAAd,GACH;AAAA,UACCU,EAAK,SAAS,SAAS,IACtB,gBAAAI;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAASJ,EAAK;AAAA,cACd,WAAU;AAAA,cACV,cAAW;AAAA,cAEX,UAAA,gBAAAI,EAACC,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,YAAA;AAAA,UAAA,IAE/B;AAAA,QAAA,EAAA,CACN,IACE;AAAA,QAGHH,IACC,gBAAAE;AAAA,UAACE;AAAA,UAAA;AAAA,YACC,OAAOb;AAAA,YACP,UAAUC;AAAA,YACV,aAAAC;AAAA,YACA,cAAc,CAACY,MAASP,EAAK,YAAYO,CAAI;AAAA,UAAA;AAAA,QAAA,IAG/C,gBAAAH;AAAA,UAACI;AAAA,UAAA;AAAA,YACC,UAAUR,EAAK;AAAA,YACf,WAAWA,EAAK;AAAA,YAChB,aAAaA,EAAK;AAAA,YAClB,aAAAL;AAAA,YACA,cAAc,CAACY,MAASP,EAAK,YAAYO,CAAI;AAAA,YAC7C,cAAAT;AAAA,UAAA;AAAA,QAAA;AAAA,QAKJ,gBAAAM,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA,gBAAAA;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,QAAQ,CAACC,MAAYV,EAAK,YAAYU,CAAO;AAAA,YAC7C,UAAUV,EAAK;AAAA,YACf,WAAWA,EAAK;AAAA,YAChB,aAAAJ;AAAA,UAAA;AAAA,QAAA,EACF,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as a, jsxs as d } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { SparklesIcon as n } from "@heroicons/react/24/outline";
|
|
4
|
+
function i({ suggestions: e = [], onSelect: t }) {
|
|
5
|
+
return e.length ? /* @__PURE__ */ a("div", { className: "flex flex-wrap gap-2", children: e.map((r) => /* @__PURE__ */ d(
|
|
6
|
+
"button",
|
|
7
|
+
{
|
|
8
|
+
type: "button",
|
|
9
|
+
onClick: () => t?.(r),
|
|
10
|
+
className: "inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:border-brand-700 dark:hover:bg-brand-950/30 dark:hover:text-brand-300",
|
|
11
|
+
children: [
|
|
12
|
+
/* @__PURE__ */ a(n, { className: "h-3 w-3", "aria-hidden": "true" }),
|
|
13
|
+
r
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
r
|
|
17
|
+
)) }) : null;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
i as default
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=ChatSuggestions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatSuggestions.js","sources":["../../../../src/components/library/chat/ChatSuggestions.jsx"],"sourcesContent":["import React from \"react\";\nimport { SparklesIcon } from \"@heroicons/react/24/outline\";\n\n/**\n * Quick-action prompt buttons. Place above the input or after an assistant message.\n *\n * @param {string[]} suggestions — prompt strings\n * @param {Function} onSelect — (suggestion) => void\n */\nexport default function ChatSuggestions({ suggestions = [], onSelect }) {\n if (!suggestions.length) return null;\n\n return (\n <div className=\"flex flex-wrap gap-2\">\n {suggestions.map((text) => (\n <button\n key={text}\n type=\"button\"\n onClick={() => onSelect?.(text)}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:border-brand-700 dark:hover:bg-brand-950/30 dark:hover:text-brand-300\"\n >\n <SparklesIcon className=\"h-3 w-3\" aria-hidden=\"true\" />\n {text}\n </button>\n ))}\n </div>\n );\n}\n"],"names":["ChatSuggestions","suggestions","onSelect","text","jsxs","jsx","SparklesIcon"],"mappings":";;;AASA,SAAwBA,EAAgB,EAAE,aAAAC,IAAc,CAAA,GAAI,UAAAC,KAAY;AACtE,SAAKD,EAAY,2BAGd,OAAA,EAAI,WAAU,wBACZ,UAAAA,EAAY,IAAI,CAACE,MAChB,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAMF,IAAWC,CAAI;AAAA,MAC9B,WAAU;AAAA,MAEV,UAAA;AAAA,QAAA,gBAAAE,EAACC,GAAA,EAAa,WAAU,WAAU,eAAY,QAAO;AAAA,QACpDH;AAAA,MAAA;AAAA,IAAA;AAAA,IANIA;AAAA,EAAA,CAQR,GACH,IAf8B;AAiBlC;"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsxs as r, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { useState as i } from "react";
|
|
3
|
+
import c from "../ui/Spinner.js";
|
|
4
|
+
import { WrenchScrewdriverIcon as o, ChevronDownIcon as m, XCircleIcon as x, CheckCircleIcon as b } from "@heroicons/react/24/outline";
|
|
5
|
+
const d = {
|
|
6
|
+
running: {
|
|
7
|
+
icon: /* @__PURE__ */ t(c, { size: "xs", tone: "brand", label: "Running" }),
|
|
8
|
+
text: "text-brand-600 dark:text-brand-400",
|
|
9
|
+
bg: "bg-brand-50 border-brand-100 dark:bg-brand-950/20 dark:border-brand-900/30",
|
|
10
|
+
label: "Running"
|
|
11
|
+
},
|
|
12
|
+
complete: {
|
|
13
|
+
icon: /* @__PURE__ */ t(b, { className: "h-3.5 w-3.5 text-emerald-500" }),
|
|
14
|
+
text: "text-emerald-700 dark:text-emerald-300",
|
|
15
|
+
bg: "bg-emerald-50 border-emerald-100 dark:bg-emerald-950/20 dark:border-emerald-900/30",
|
|
16
|
+
label: "Complete"
|
|
17
|
+
},
|
|
18
|
+
error: {
|
|
19
|
+
icon: /* @__PURE__ */ t(x, { className: "h-3.5 w-3.5 text-red-500" }),
|
|
20
|
+
text: "text-red-700 dark:text-red-300",
|
|
21
|
+
bg: "bg-red-50 border-red-100 dark:bg-red-950/20 dark:border-red-900/30",
|
|
22
|
+
label: "Failed"
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function h({ toolCall: e }) {
|
|
26
|
+
const [s, l] = i(!1), a = d[e.status] ?? d.running, n = e.args || e.result;
|
|
27
|
+
return /* @__PURE__ */ r(
|
|
28
|
+
"div",
|
|
29
|
+
{
|
|
30
|
+
className: [
|
|
31
|
+
"rounded-lg border text-xs",
|
|
32
|
+
a.bg
|
|
33
|
+
].join(" "),
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ r(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
type: "button",
|
|
39
|
+
onClick: () => n && l(!s),
|
|
40
|
+
className: [
|
|
41
|
+
"flex w-full items-center gap-2 px-3 py-1.5",
|
|
42
|
+
n ? "cursor-pointer" : "cursor-default"
|
|
43
|
+
].join(" "),
|
|
44
|
+
children: [
|
|
45
|
+
a.icon,
|
|
46
|
+
/* @__PURE__ */ t(o, { className: "h-3 w-3 text-slate-400 dark:text-slate-500" }),
|
|
47
|
+
/* @__PURE__ */ t("span", { className: ["font-medium", a.text].join(" "), children: e.name }),
|
|
48
|
+
/* @__PURE__ */ r("span", { className: "text-slate-400 dark:text-slate-500", children: [
|
|
49
|
+
"— ",
|
|
50
|
+
a.label
|
|
51
|
+
] }),
|
|
52
|
+
n ? /* @__PURE__ */ t(
|
|
53
|
+
m,
|
|
54
|
+
{
|
|
55
|
+
className: [
|
|
56
|
+
"ml-auto h-3 w-3 text-slate-400 transition-transform dark:text-slate-500",
|
|
57
|
+
s ? "rotate-180" : ""
|
|
58
|
+
].join(" ")
|
|
59
|
+
}
|
|
60
|
+
) : null
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
s && n ? /* @__PURE__ */ r("div", { className: "border-t border-inherit px-3 py-2 font-mono text-[11px] leading-relaxed text-slate-600 dark:text-slate-300", children: [
|
|
65
|
+
e.args ? /* @__PURE__ */ r("div", { className: "mb-1", children: [
|
|
66
|
+
/* @__PURE__ */ r("span", { className: "font-sans font-semibold text-slate-500 dark:text-slate-400", children: [
|
|
67
|
+
"Args:",
|
|
68
|
+
" "
|
|
69
|
+
] }),
|
|
70
|
+
typeof e.args == "string" ? e.args : JSON.stringify(e.args, null, 2)
|
|
71
|
+
] }) : null,
|
|
72
|
+
e.result ? /* @__PURE__ */ r("div", { children: [
|
|
73
|
+
/* @__PURE__ */ r("span", { className: "font-sans font-semibold text-slate-500 dark:text-slate-400", children: [
|
|
74
|
+
"Result:",
|
|
75
|
+
" "
|
|
76
|
+
] }),
|
|
77
|
+
typeof e.result == "string" ? e.result : JSON.stringify(e.result, null, 2)
|
|
78
|
+
] }) : null
|
|
79
|
+
] }) : null
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
h as default
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=ChatToolCall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatToolCall.js","sources":["../../../../src/components/library/chat/ChatToolCall.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport Spinner from \"../ui/Spinner\";\nimport {\n WrenchScrewdriverIcon,\n CheckCircleIcon,\n XCircleIcon,\n ChevronDownIcon,\n} from \"@heroicons/react/24/outline\";\n\nconst STATUS_CONFIG = {\n running: {\n icon: <Spinner size=\"xs\" tone=\"brand\" label=\"Running\" />,\n text: \"text-brand-600 dark:text-brand-400\",\n bg: \"bg-brand-50 border-brand-100 dark:bg-brand-950/20 dark:border-brand-900/30\",\n label: \"Running\",\n },\n complete: {\n icon: <CheckCircleIcon className=\"h-3.5 w-3.5 text-emerald-500\" />,\n text: \"text-emerald-700 dark:text-emerald-300\",\n bg: \"bg-emerald-50 border-emerald-100 dark:bg-emerald-950/20 dark:border-emerald-900/30\",\n label: \"Complete\",\n },\n error: {\n icon: <XCircleIcon className=\"h-3.5 w-3.5 text-red-500\" />,\n text: \"text-red-700 dark:text-red-300\",\n bg: \"bg-red-50 border-red-100 dark:bg-red-950/20 dark:border-red-900/30\",\n label: \"Failed\",\n },\n};\n\n/**\n * Displays an agent tool call / function execution step.\n *\n * @param {Object} toolCall — { id?, name, args?, status: \"running\"|\"complete\"|\"error\", result? }\n */\nexport default function ChatToolCall({ toolCall }) {\n const [expanded, setExpanded] = useState(false);\n const config = STATUS_CONFIG[toolCall.status] ?? STATUS_CONFIG.running;\n const hasDetails = toolCall.args || toolCall.result;\n\n return (\n <div\n className={[\n \"rounded-lg border text-xs\",\n config.bg,\n ].join(\" \")}\n >\n <button\n type=\"button\"\n onClick={() => hasDetails && setExpanded(!expanded)}\n className={[\n \"flex w-full items-center gap-2 px-3 py-1.5\",\n hasDetails ? \"cursor-pointer\" : \"cursor-default\",\n ].join(\" \")}\n >\n {config.icon}\n <WrenchScrewdriverIcon className=\"h-3 w-3 text-slate-400 dark:text-slate-500\" />\n <span className={[\"font-medium\", config.text].join(\" \")}>\n {toolCall.name}\n </span>\n <span className=\"text-slate-400 dark:text-slate-500\">\n — {config.label}\n </span>\n {hasDetails ? (\n <ChevronDownIcon\n className={[\n \"ml-auto h-3 w-3 text-slate-400 transition-transform dark:text-slate-500\",\n expanded ? \"rotate-180\" : \"\",\n ].join(\" \")}\n />\n ) : null}\n </button>\n\n {expanded && hasDetails ? (\n <div className=\"border-t border-inherit px-3 py-2 font-mono text-[11px] leading-relaxed text-slate-600 dark:text-slate-300\">\n {toolCall.args ? (\n <div className=\"mb-1\">\n <span className=\"font-sans font-semibold text-slate-500 dark:text-slate-400\">\n Args:{\" \"}\n </span>\n {typeof toolCall.args === \"string\"\n ? toolCall.args\n : JSON.stringify(toolCall.args, null, 2)}\n </div>\n ) : null}\n {toolCall.result ? (\n <div>\n <span className=\"font-sans font-semibold text-slate-500 dark:text-slate-400\">\n Result:{\" \"}\n </span>\n {typeof toolCall.result === \"string\"\n ? toolCall.result\n : JSON.stringify(toolCall.result, null, 2)}\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n"],"names":["STATUS_CONFIG","Spinner","jsx","CheckCircleIcon","XCircleIcon","ChatToolCall","toolCall","expanded","setExpanded","useState","config","hasDetails","jsxs","WrenchScrewdriverIcon","ChevronDownIcon"],"mappings":";;;;AASA,MAAMA,IAAgB;AAAA,EACpB,SAAS;AAAA,IACP,wBAAOC,GAAA,EAAQ,MAAK,MAAK,MAAK,SAAQ,OAAM,WAAU;AAAA,IACtD,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,EAAA;AAAA,EAET,UAAU;AAAA,IACR,MAAM,gBAAAC,EAACC,GAAA,EAAgB,WAAU,+BAAA,CAA+B;AAAA,IAChE,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,EAAA;AAAA,EAET,OAAO;AAAA,IACL,MAAM,gBAAAD,EAACE,GAAA,EAAY,WAAU,2BAAA,CAA2B;AAAA,IACxD,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,EAAA;AAEX;AAOA,SAAwBC,EAAa,EAAE,UAAAC,KAAY;AACjD,QAAM,CAACC,GAAUC,CAAW,IAAIC,EAAS,EAAK,GACxCC,IAASV,EAAcM,EAAS,MAAM,KAAKN,EAAc,SACzDW,IAAaL,EAAS,QAAQA,EAAS;AAE7C,SACE,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACAF,EAAO;AAAA,MAAA,EACP,KAAK,GAAG;AAAA,MAEV,UAAA;AAAA,QAAA,gBAAAE;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAMD,KAAcH,EAAY,CAACD,CAAQ;AAAA,YAClD,WAAW;AAAA,cACT;AAAA,cACAI,IAAa,mBAAmB;AAAA,YAAA,EAChC,KAAK,GAAG;AAAA,YAET,UAAA;AAAA,cAAAD,EAAO;AAAA,cACR,gBAAAR,EAACW,GAAA,EAAsB,WAAU,6CAAA,CAA6C;AAAA,cAC9E,gBAAAX,EAAC,QAAA,EAAK,WAAW,CAAC,eAAeQ,EAAO,IAAI,EAAE,KAAK,GAAG,GACnD,UAAAJ,EAAS,KAAA,CACZ;AAAA,cACA,gBAAAM,EAAC,QAAA,EAAK,WAAU,sCAAqC,UAAA;AAAA,gBAAA;AAAA,gBAChDF,EAAO;AAAA,cAAA,GACZ;AAAA,cACCC,IACC,gBAAAT;AAAA,gBAACY;AAAA,gBAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACAP,IAAW,eAAe;AAAA,kBAAA,EAC1B,KAAK,GAAG;AAAA,gBAAA;AAAA,cAAA,IAEV;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGLA,KAAYI,IACX,gBAAAC,EAAC,OAAA,EAAI,WAAU,8GACZ,UAAA;AAAA,UAAAN,EAAS,OACR,gBAAAM,EAAC,OAAA,EAAI,WAAU,QACb,UAAA;AAAA,YAAA,gBAAAA,EAAC,QAAA,EAAK,WAAU,8DAA6D,UAAA;AAAA,cAAA;AAAA,cACrE;AAAA,YAAA,GACR;AAAA,YACC,OAAON,EAAS,QAAS,WACtBA,EAAS,OACT,KAAK,UAAUA,EAAS,MAAM,MAAM,CAAC;AAAA,UAAA,EAAA,CAC3C,IACE;AAAA,UACHA,EAAS,SACR,gBAAAM,EAAC,OAAA,EACC,UAAA;AAAA,YAAA,gBAAAA,EAAC,QAAA,EAAK,WAAU,8DAA6D,UAAA;AAAA,cAAA;AAAA,cACnE;AAAA,YAAA,GACV;AAAA,YACC,OAAON,EAAS,UAAW,WACxBA,EAAS,SACT,KAAK,UAAUA,EAAS,QAAQ,MAAM,CAAC;AAAA,UAAA,EAAA,CAC7C,IACE;AAAA,QAAA,EAAA,CACN,IACE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsxs as e, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { CpuChipIcon as t } from "@heroicons/react/24/solid";
|
|
4
|
+
function r({ label: s = "Thinking" }) {
|
|
5
|
+
return /* @__PURE__ */ e("div", { className: "flex items-start gap-3", children: [
|
|
6
|
+
/* @__PURE__ */ a("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-brand-100 dark:bg-brand-900/40", children: /* @__PURE__ */ a(t, { className: "h-4 w-4 text-brand-600 dark:text-brand-400" }) }),
|
|
7
|
+
/* @__PURE__ */ e("div", { className: "flex items-center gap-2 rounded-2xl rounded-tl-md bg-slate-100 px-4 py-3 dark:bg-slate-800", children: [
|
|
8
|
+
/* @__PURE__ */ e("div", { className: "flex gap-1", children: [
|
|
9
|
+
/* @__PURE__ */ a("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:0ms]" }),
|
|
10
|
+
/* @__PURE__ */ a("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:150ms]" }),
|
|
11
|
+
/* @__PURE__ */ a("span", { className: "h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:300ms]" })
|
|
12
|
+
] }),
|
|
13
|
+
/* @__PURE__ */ a("span", { className: "text-xs text-slate-400 dark:text-slate-500", children: s })
|
|
14
|
+
] })
|
|
15
|
+
] });
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
r as default
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=ChatTypingIndicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatTypingIndicator.js","sources":["../../../../src/components/library/chat/ChatTypingIndicator.jsx"],"sourcesContent":["import React from \"react\";\nimport { CpuChipIcon } from \"@heroicons/react/24/solid\";\n\n/**\n * Animated typing indicator shown while the agent is processing.\n */\nexport default function ChatTypingIndicator({ label = \"Thinking\" }) {\n return (\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-brand-100 dark:bg-brand-900/40\">\n <CpuChipIcon className=\"h-4 w-4 text-brand-600 dark:text-brand-400\" />\n </div>\n <div className=\"flex items-center gap-2 rounded-2xl rounded-tl-md bg-slate-100 px-4 py-3 dark:bg-slate-800\">\n <div className=\"flex gap-1\">\n <span className=\"h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:0ms]\" />\n <span className=\"h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:150ms]\" />\n <span className=\"h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400 dark:bg-slate-500 [animation-delay:300ms]\" />\n </div>\n <span className=\"text-xs text-slate-400 dark:text-slate-500\">{label}</span>\n </div>\n </div>\n );\n}\n"],"names":["ChatTypingIndicator","label","jsxs","jsx","CpuChipIcon"],"mappings":";;;AAMA,SAAwBA,EAAoB,EAAE,OAAAC,IAAQ,cAAc;AAClE,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,IAAA,gBAAAC,EAAC,SAAI,WAAU,kGACb,4BAACC,GAAA,EAAY,WAAU,8CAA6C,EAAA,CACtE;AAAA,IACA,gBAAAF,EAAC,OAAA,EAAI,WAAU,8FACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,cACb,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,WAAU,+FAAA,CAA+F;AAAA,QAC/G,gBAAAA,EAAC,QAAA,EAAK,WAAU,iGAAA,CAAiG;AAAA,QACjH,gBAAAA,EAAC,QAAA,EAAK,WAAU,iGAAA,CAAiG;AAAA,MAAA,GACnH;AAAA,MACA,gBAAAA,EAAC,QAAA,EAAK,WAAU,8CAA8C,UAAAF,EAAA,CAAM;AAAA,IAAA,EAAA,CACtE;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsxs as a, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { CpuChipIcon as o } from "@heroicons/react/24/solid";
|
|
4
|
+
import c from "./ChatSuggestions.js";
|
|
5
|
+
function h({
|
|
6
|
+
title: r = "How can I help?",
|
|
7
|
+
subtitle: l = "Ask me anything about your data, or try one of the suggestions below.",
|
|
8
|
+
suggestions: t = [],
|
|
9
|
+
onSuggestion: s,
|
|
10
|
+
icon: n
|
|
11
|
+
}) {
|
|
12
|
+
return /* @__PURE__ */ a("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 px-6 py-12 text-center", children: [
|
|
13
|
+
n ?? /* @__PURE__ */ e("div", { className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-brand-100 dark:bg-brand-900/40", children: /* @__PURE__ */ e(o, { className: "h-7 w-7 text-brand-600 dark:text-brand-400" }) }),
|
|
14
|
+
/* @__PURE__ */ a("div", { children: [
|
|
15
|
+
/* @__PURE__ */ e("h3", { className: "text-base font-semibold text-slate-900 dark:text-slate-50", children: r }),
|
|
16
|
+
/* @__PURE__ */ e("p", { className: "mt-1 text-sm text-slate-500 dark:text-slate-400", children: l })
|
|
17
|
+
] }),
|
|
18
|
+
t.length ? /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e(c, { suggestions: t, onSelect: s }) }) : null
|
|
19
|
+
] });
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
h as default
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=ChatWelcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatWelcome.js","sources":["../../../../src/components/library/chat/ChatWelcome.jsx"],"sourcesContent":["import React from \"react\";\nimport { CpuChipIcon } from \"@heroicons/react/24/solid\";\nimport ChatSuggestions from \"./ChatSuggestions\";\n\n/**\n * Empty-state welcome screen shown before the first message.\n *\n * @param {string} title — welcome heading\n * @param {string} subtitle — description text\n * @param {string[]} suggestions — starter prompt suggestions\n * @param {Function} onSuggestion — (text) => void\n * @param {React.ReactNode} icon — custom icon override\n */\nexport default function ChatWelcome({\n title = \"How can I help?\",\n subtitle = \"Ask me anything about your data, or try one of the suggestions below.\",\n suggestions = [],\n onSuggestion,\n icon,\n}) {\n return (\n <div className=\"flex flex-1 flex-col items-center justify-center gap-4 px-6 py-12 text-center\">\n {icon ?? (\n <div className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-brand-100 dark:bg-brand-900/40\">\n <CpuChipIcon className=\"h-7 w-7 text-brand-600 dark:text-brand-400\" />\n </div>\n )}\n <div>\n <h3 className=\"text-base font-semibold text-slate-900 dark:text-slate-50\">\n {title}\n </h3>\n <p className=\"mt-1 text-sm text-slate-500 dark:text-slate-400\">\n {subtitle}\n </p>\n </div>\n {suggestions.length ? (\n <div className=\"mt-2\">\n <ChatSuggestions suggestions={suggestions} onSelect={onSuggestion} />\n </div>\n ) : null}\n </div>\n );\n}\n"],"names":["ChatWelcome","title","subtitle","suggestions","onSuggestion","icon","jsxs","jsx","CpuChipIcon","ChatSuggestions"],"mappings":";;;;AAaA,SAAwBA,EAAY;AAAA,EAClC,OAAAC,IAAQ;AAAA,EACR,UAAAC,IAAW;AAAA,EACX,aAAAC,IAAc,CAAA;AAAA,EACd,cAAAC;AAAA,EACA,MAAAC;AACF,GAAG;AACD,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAU,iFACZ,UAAA;AAAA,IAAAD,KACC,gBAAAE,EAAC,SAAI,WAAU,4FACb,4BAACC,GAAA,EAAY,WAAU,8CAA6C,EAAA,CACtE;AAAA,sBAED,OAAA,EACC,UAAA;AAAA,MAAA,gBAAAD,EAAC,MAAA,EAAG,WAAU,6DACX,UAAAN,GACH;AAAA,MACA,gBAAAM,EAAC,KAAA,EAAE,WAAU,mDACV,UAAAL,EAAA,CACH;AAAA,IAAA,GACF;AAAA,IACCC,EAAY,SACX,gBAAAI,EAAC,OAAA,EAAI,WAAU,QACb,UAAA,gBAAAA,EAACE,GAAA,EAAgB,aAAAN,GAA0B,UAAUC,EAAA,CAAc,EAAA,CACrE,IACE;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { useState as g, useRef as k, useCallback as o } from "react";
|
|
2
|
+
let v = 1;
|
|
3
|
+
function S() {
|
|
4
|
+
return `msg-${Date.now()}-${v++}`;
|
|
5
|
+
}
|
|
6
|
+
function R({ initialMessages: h = [], onSend: I } = {}) {
|
|
7
|
+
const [r, a] = g(
|
|
8
|
+
() => h.map((e) => ({ id: S(), timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...e }))
|
|
9
|
+
), [x, M] = g(!1), [D, w] = g(!1), [O, l] = g(null), y = k(I);
|
|
10
|
+
y.current = I;
|
|
11
|
+
const c = o((e) => {
|
|
12
|
+
const t = { id: S(), timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...e };
|
|
13
|
+
return a((s) => [...s, t]), t.id;
|
|
14
|
+
}, []), d = o((e, t) => {
|
|
15
|
+
a(
|
|
16
|
+
(s) => s.map((n) => n.id === e ? { ...n, ...t } : n)
|
|
17
|
+
);
|
|
18
|
+
}, []), f = o((e, t) => {
|
|
19
|
+
a(
|
|
20
|
+
(s) => s.map(
|
|
21
|
+
(n) => n.id === e ? { ...n, content: (n.content ?? "") + t } : n
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
}, []), C = o((e) => {
|
|
25
|
+
a((t) => t.filter((s) => s.id !== e));
|
|
26
|
+
}, []), L = o(() => {
|
|
27
|
+
a([]), l(null);
|
|
28
|
+
}, []), m = o(
|
|
29
|
+
async (e, t = {}) => {
|
|
30
|
+
if (!e?.trim()) return;
|
|
31
|
+
l(null);
|
|
32
|
+
const s = { role: "user", content: e.trim(), ...t }, n = S(), p = { ...s, id: n, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
33
|
+
a((i) => [...i, p]), M(!0);
|
|
34
|
+
try {
|
|
35
|
+
const i = [...r, p], u = await y.current?.(p, i, {
|
|
36
|
+
addMessage: c,
|
|
37
|
+
updateMessage: d,
|
|
38
|
+
appendChunk: f,
|
|
39
|
+
setStreaming: w
|
|
40
|
+
});
|
|
41
|
+
u && typeof u == "object" && u.role && c(u);
|
|
42
|
+
} catch (i) {
|
|
43
|
+
l(i?.message ?? "Failed to send message"), c({
|
|
44
|
+
role: "system",
|
|
45
|
+
content: i?.message ?? "Something went wrong. Please try again.",
|
|
46
|
+
isError: !0
|
|
47
|
+
});
|
|
48
|
+
} finally {
|
|
49
|
+
M(!1), w(!1);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[r, c, d, f]
|
|
53
|
+
), b = o(() => {
|
|
54
|
+
const e = [...r].reverse().find((s) => s.role === "user");
|
|
55
|
+
if (!e) return;
|
|
56
|
+
const t = r.lastIndexOf(e);
|
|
57
|
+
a(r.slice(0, t)), l(null), m(e.content);
|
|
58
|
+
}, [r, m]);
|
|
59
|
+
return {
|
|
60
|
+
messages: r,
|
|
61
|
+
isLoading: x,
|
|
62
|
+
isStreaming: D,
|
|
63
|
+
error: O,
|
|
64
|
+
sendMessage: m,
|
|
65
|
+
addMessage: c,
|
|
66
|
+
updateMessage: d,
|
|
67
|
+
appendChunk: f,
|
|
68
|
+
removeMessage: C,
|
|
69
|
+
clearMessages: L,
|
|
70
|
+
retryLast: b,
|
|
71
|
+
setError: l
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
R as default
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=useChatState.js.map
|