@mordn/chat-widget 0.4.2 → 0.5.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/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +47 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -15
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -67,6 +67,21 @@ interface ChatWidgetConfig {
|
|
|
67
67
|
* (e.g. setting their open state, navigating away).
|
|
68
68
|
*/
|
|
69
69
|
onClose?: () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Controlled open state for `popup` layout. When provided, the consumer
|
|
72
|
+
* owns the show/hide lifecycle and the widget will NOT render its own
|
|
73
|
+
* floating toggle button (FAB). The consumer renders whatever trigger
|
|
74
|
+
* they want and toggles `open` themselves.
|
|
75
|
+
*
|
|
76
|
+
* Leave undefined to use the widget's built-in uncontrolled behaviour
|
|
77
|
+
* (FAB appears when closed, click opens, internal state).
|
|
78
|
+
*/
|
|
79
|
+
open?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Called when the widget wants to change its open state (e.g. user
|
|
82
|
+
* clicked the close X). Required when using `open` (controlled mode).
|
|
83
|
+
*/
|
|
84
|
+
onOpenChange?: (open: boolean) => void;
|
|
70
85
|
/**
|
|
71
86
|
* Custom buttons rendered in the widget header next to the close X.
|
|
72
87
|
* Use this for "expand to full page", "settings", or any consumer-defined
|
|
@@ -211,7 +226,7 @@ interface ChatWidgetProps extends ChatWidgetConfig {
|
|
|
211
226
|
*/
|
|
212
227
|
widgetId?: string;
|
|
213
228
|
}
|
|
214
|
-
declare function ChatWidget({ userId, conversationId, initialMessages, className, model, systemPrompt, temperature, theme, features, display, starterPrompts, onClose, headerActions, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
|
|
229
|
+
declare function ChatWidget({ userId, conversationId, initialMessages, className, model, systemPrompt, temperature, theme, features, display, starterPrompts, onClose, headerActions, open, onOpenChange, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
|
|
215
230
|
|
|
216
231
|
interface ChatTheme {
|
|
217
232
|
lightPrimary: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -67,6 +67,21 @@ interface ChatWidgetConfig {
|
|
|
67
67
|
* (e.g. setting their open state, navigating away).
|
|
68
68
|
*/
|
|
69
69
|
onClose?: () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Controlled open state for `popup` layout. When provided, the consumer
|
|
72
|
+
* owns the show/hide lifecycle and the widget will NOT render its own
|
|
73
|
+
* floating toggle button (FAB). The consumer renders whatever trigger
|
|
74
|
+
* they want and toggles `open` themselves.
|
|
75
|
+
*
|
|
76
|
+
* Leave undefined to use the widget's built-in uncontrolled behaviour
|
|
77
|
+
* (FAB appears when closed, click opens, internal state).
|
|
78
|
+
*/
|
|
79
|
+
open?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Called when the widget wants to change its open state (e.g. user
|
|
82
|
+
* clicked the close X). Required when using `open` (controlled mode).
|
|
83
|
+
*/
|
|
84
|
+
onOpenChange?: (open: boolean) => void;
|
|
70
85
|
/**
|
|
71
86
|
* Custom buttons rendered in the widget header next to the close X.
|
|
72
87
|
* Use this for "expand to full page", "settings", or any consumer-defined
|
|
@@ -211,7 +226,7 @@ interface ChatWidgetProps extends ChatWidgetConfig {
|
|
|
211
226
|
*/
|
|
212
227
|
widgetId?: string;
|
|
213
228
|
}
|
|
214
|
-
declare function ChatWidget({ userId, conversationId, initialMessages, className, model, systemPrompt, temperature, theme, features, display, starterPrompts, onClose, headerActions, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
|
|
229
|
+
declare function ChatWidget({ userId, conversationId, initialMessages, className, model, systemPrompt, temperature, theme, features, display, starterPrompts, onClose, headerActions, open, onOpenChange, }: ChatWidgetProps): react_jsx_runtime.JSX.Element;
|
|
215
230
|
|
|
216
231
|
interface ChatTheme {
|
|
217
232
|
lightPrimary: string;
|
package/dist/index.js
CHANGED
|
@@ -520,7 +520,11 @@ var PromptInput = ({
|
|
|
520
520
|
"form",
|
|
521
521
|
{
|
|
522
522
|
className: cn(
|
|
523
|
-
|
|
523
|
+
// The form border + horizontal divider colour both come from
|
|
524
|
+
// the styles.src.css `.chat-widget-container form ...` rules so
|
|
525
|
+
// there's a single token (--chat-divider) controlling both.
|
|
526
|
+
// No utility classes for border colour here.
|
|
527
|
+
"w-full overflow-hidden rounded-xl bg-background transition-colors",
|
|
524
528
|
"[&:focus-within]:shadow-none [&:focus]:shadow-none shadow-none",
|
|
525
529
|
className
|
|
526
530
|
),
|
|
@@ -1194,7 +1198,7 @@ var CodeBlock = ({
|
|
|
1194
1198
|
"div",
|
|
1195
1199
|
{
|
|
1196
1200
|
className: cn(
|
|
1197
|
-
"relative w-full overflow-hidden rounded-lg bg-[hsl(var(--chat-text)/0.03)] border border-[
|
|
1201
|
+
"relative w-full overflow-hidden rounded-lg bg-[hsl(var(--chat-text)/0.03)] border border-[var(--chat-divider)]",
|
|
1198
1202
|
className
|
|
1199
1203
|
),
|
|
1200
1204
|
...props,
|
|
@@ -1261,7 +1265,7 @@ var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
|
1261
1265
|
var Tool = ({ className, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1262
1266
|
Collapsible,
|
|
1263
1267
|
{
|
|
1264
|
-
className: cn("not-prose w-full rounded-md border border-[
|
|
1268
|
+
className: cn("not-prose w-full rounded-md border border-[var(--chat-divider)]", className),
|
|
1265
1269
|
...props
|
|
1266
1270
|
}
|
|
1267
1271
|
);
|
|
@@ -1287,6 +1291,7 @@ var ToolHeader = ({
|
|
|
1287
1291
|
className,
|
|
1288
1292
|
title,
|
|
1289
1293
|
type,
|
|
1294
|
+
toolName,
|
|
1290
1295
|
state,
|
|
1291
1296
|
...props
|
|
1292
1297
|
}) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
@@ -1300,7 +1305,7 @@ var ToolHeader = ({
|
|
|
1300
1305
|
children: [
|
|
1301
1306
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1302
1307
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react9.WrenchIcon, { className: "size-4 text-muted-foreground" }),
|
|
1303
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-sm", children: title ?? type.split("-").slice(1).join("-") }),
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-sm", children: title ?? toolName ?? type.split("-").slice(1).join("-") }),
|
|
1304
1309
|
getStatusBadge(state)
|
|
1305
1310
|
] }),
|
|
1306
1311
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react9.ChevronDownIcon, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
|
|
@@ -1379,7 +1384,10 @@ function StarterMessages({
|
|
|
1379
1384
|
onClick: () => onPromptSelect(prompt)
|
|
1380
1385
|
}
|
|
1381
1386
|
),
|
|
1382
|
-
index < prompts.length - 1 &&
|
|
1387
|
+
index < prompts.length - 1 && // 1px-tall element used as a divider — same --chat-divider token
|
|
1388
|
+
// every other separator in the widget uses, so consumers only
|
|
1389
|
+
// need to override one variable to recolour all of them.
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "h-px mx-3", style: { backgroundColor: "var(--chat-divider)" } })
|
|
1383
1391
|
] }, index))
|
|
1384
1392
|
}
|
|
1385
1393
|
);
|
|
@@ -1452,6 +1460,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
1452
1460
|
const [activeTabId, setActiveTabId] = (0, import_react9.useState)("");
|
|
1453
1461
|
const [initialTabCreated, setInitialTabCreated] = (0, import_react9.useState)(false);
|
|
1454
1462
|
const [isInitializing, setIsInitializing] = (0, import_react9.useState)(true);
|
|
1463
|
+
const [isLoadingMessages, setIsLoadingMessages] = (0, import_react9.useState)(false);
|
|
1455
1464
|
const lastSyncedTabId = (0, import_react9.useRef)("");
|
|
1456
1465
|
const hasInitialized = (0, import_react9.useRef)(false);
|
|
1457
1466
|
const { messages, sendMessage, status, setMessages } = (0, import_react11.useChat)({
|
|
@@ -1631,7 +1640,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
1631
1640
|
}))
|
|
1632
1641
|
);
|
|
1633
1642
|
setActiveTabId(tabId);
|
|
1634
|
-
|
|
1643
|
+
setIsLoadingMessages(true);
|
|
1644
|
+
try {
|
|
1645
|
+
await loadConversation(tabId);
|
|
1646
|
+
} finally {
|
|
1647
|
+
setIsLoadingMessages(false);
|
|
1648
|
+
}
|
|
1635
1649
|
};
|
|
1636
1650
|
const closeTab = (tabId) => {
|
|
1637
1651
|
if (tabs.length <= 1) return;
|
|
@@ -1856,7 +1870,14 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
1856
1870
|
if (part.type.startsWith("tool-") || part.type === "dynamic-tool") {
|
|
1857
1871
|
const toolPart = part;
|
|
1858
1872
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tool, { children: [
|
|
1859
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1873
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1874
|
+
ToolHeader,
|
|
1875
|
+
{
|
|
1876
|
+
type: part.type,
|
|
1877
|
+
toolName: toolPart.toolName,
|
|
1878
|
+
state: toolPart.state
|
|
1879
|
+
}
|
|
1880
|
+
),
|
|
1860
1881
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(ToolContent, { children: [
|
|
1861
1882
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolInput, { input: toolPart.input }),
|
|
1862
1883
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolOutput, { output: toolPart.output, errorText: toolPart.errorText })
|
|
@@ -1922,7 +1943,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
1922
1943
|
),
|
|
1923
1944
|
children: [
|
|
1924
1945
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 px-3 py-2 border-b backdrop-blur-sm relative z-20", style: {
|
|
1925
|
-
borderColor: "var(--chat-
|
|
1946
|
+
borderColor: "var(--chat-divider)",
|
|
1926
1947
|
backgroundColor: "var(--chat-header-bg)"
|
|
1927
1948
|
}, children: [
|
|
1928
1949
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center gap-1 flex-1 min-w-0 overflow-x-auto scrollbar-hide py-0.5 scroll-smooth", children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
@@ -2024,10 +2045,10 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
2024
2045
|
),
|
|
2025
2046
|
showHistory && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-72 rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_24px_rgba(0,0,0,0.3)] z-50 animate-in fade-in slide-in-from-top-1 duration-150 overflow-hidden", style: {
|
|
2026
2047
|
backgroundColor: "hsl(var(--chat-background))",
|
|
2027
|
-
border: `1px solid ${"var(--chat-
|
|
2048
|
+
border: `1px solid ${"var(--chat-divider)"}`
|
|
2028
2049
|
}, children: [
|
|
2029
2050
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "p-2.5 border-b", style: {
|
|
2030
|
-
borderColor: "var(--chat-
|
|
2051
|
+
borderColor: "var(--chat-divider)",
|
|
2031
2052
|
backgroundColor: "var(--chat-overlay)"
|
|
2032
2053
|
}, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2033
2054
|
"input",
|
|
@@ -2039,7 +2060,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
2039
2060
|
className: "w-full h-7 px-2.5 text-[13px] rounded-lg focus:outline-none transition-all",
|
|
2040
2061
|
style: {
|
|
2041
2062
|
backgroundColor: "hsl(var(--chat-surface-deep))",
|
|
2042
|
-
border: `1px solid ${"var(--chat-
|
|
2063
|
+
border: `1px solid ${"var(--chat-divider)"}`,
|
|
2043
2064
|
color: "hsl(var(--chat-text))"
|
|
2044
2065
|
}
|
|
2045
2066
|
}
|
|
@@ -2136,7 +2157,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
2136
2157
|
] }),
|
|
2137
2158
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "px-5 pb-5", children: [
|
|
2138
2159
|
uploadError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "mb-3 px-4 py-3 bg-red-50 dark:bg-red-900/20 border border-red-200/60 dark:border-red-800/60 rounded-2xl text-sm text-red-700 dark:text-red-400 shadow-sm", children: uploadError }),
|
|
2139
|
-
isInitializing ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "h-4 w-4 rounded-full border-2 border-current border-t-transparent animate-spin", style: { color: "hsl(var(--chat-text-muted))" } }) }) : messages.length === 0 && status !== "submitted" && config?.starterPrompts && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2160
|
+
isInitializing || isLoadingMessages ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "h-4 w-4 rounded-full border-2 border-current border-t-transparent animate-spin", style: { color: "hsl(var(--chat-text-muted))" } }) }) : messages.length === 0 && status !== "submitted" && config?.starterPrompts && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2140
2161
|
StarterMessages,
|
|
2141
2162
|
{
|
|
2142
2163
|
prompts: config.starterPrompts,
|
|
@@ -2220,15 +2241,26 @@ function ChatWidget({
|
|
|
2220
2241
|
display,
|
|
2221
2242
|
starterPrompts,
|
|
2222
2243
|
onClose,
|
|
2223
|
-
headerActions
|
|
2244
|
+
headerActions,
|
|
2245
|
+
open,
|
|
2246
|
+
onOpenChange
|
|
2224
2247
|
}) {
|
|
2225
2248
|
const layout = display?.layout || "popup";
|
|
2226
|
-
const
|
|
2249
|
+
const isControlled = open !== void 0;
|
|
2250
|
+
const showToggleButton = !isControlled && display?.showToggleButton !== false;
|
|
2227
2251
|
const resizable = layout === "popup" && display?.resizable !== false;
|
|
2228
2252
|
const size = display?.size || "default";
|
|
2229
|
-
const [
|
|
2253
|
+
const [internalIsOpen, setInternalIsOpen] = (0, import_react12.useState)(
|
|
2230
2254
|
layout !== "popup" ? true : display?.defaultOpen || false
|
|
2231
2255
|
);
|
|
2256
|
+
const isOpen = isControlled ? open : internalIsOpen;
|
|
2257
|
+
const setIsOpen = (next) => {
|
|
2258
|
+
if (isControlled) {
|
|
2259
|
+
onOpenChange?.(next);
|
|
2260
|
+
} else {
|
|
2261
|
+
setInternalIsOpen(next);
|
|
2262
|
+
}
|
|
2263
|
+
};
|
|
2232
2264
|
const [isResizing, setIsResizing] = (0, import_react12.useState)(false);
|
|
2233
2265
|
const containerRef = (0, import_react12.useRef)(null);
|
|
2234
2266
|
const customStyles = (0, import_react12.useMemo)(() => {
|