@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.mjs CHANGED
@@ -490,7 +490,11 @@ var PromptInput = ({
490
490
  "form",
491
491
  {
492
492
  className: cn(
493
- "w-full divide-y divide-[hsl(var(--chat-text)/0.1)] focus-within:divide-ring overflow-hidden rounded-xl border border-[hsl(var(--chat-text)/0.1)] bg-background focus-within:border-ring transition-colors",
493
+ // The form border + horizontal divider colour both come from
494
+ // the styles.src.css `.chat-widget-container form ...` rules so
495
+ // there's a single token (--chat-divider) controlling both.
496
+ // No utility classes for border colour here.
497
+ "w-full overflow-hidden rounded-xl bg-background transition-colors",
494
498
  "[&:focus-within]:shadow-none [&:focus]:shadow-none shadow-none",
495
499
  className
496
500
  ),
@@ -1174,7 +1178,7 @@ var CodeBlock = ({
1174
1178
  "div",
1175
1179
  {
1176
1180
  className: cn(
1177
- "relative w-full overflow-hidden rounded-lg bg-[hsl(var(--chat-text)/0.03)] border border-[hsl(var(--chat-text)/0.1)]",
1181
+ "relative w-full overflow-hidden rounded-lg bg-[hsl(var(--chat-text)/0.03)] border border-[var(--chat-divider)]",
1178
1182
  className
1179
1183
  ),
1180
1184
  ...props,
@@ -1241,7 +1245,7 @@ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
1241
1245
  var Tool = ({ className, ...props }) => /* @__PURE__ */ jsx17(
1242
1246
  Collapsible,
1243
1247
  {
1244
- className: cn("not-prose w-full rounded-md border border-[hsl(var(--chat-text)/0.1)]", className),
1248
+ className: cn("not-prose w-full rounded-md border border-[var(--chat-divider)]", className),
1245
1249
  ...props
1246
1250
  }
1247
1251
  );
@@ -1267,6 +1271,7 @@ var ToolHeader = ({
1267
1271
  className,
1268
1272
  title,
1269
1273
  type,
1274
+ toolName,
1270
1275
  state,
1271
1276
  ...props
1272
1277
  }) => /* @__PURE__ */ jsxs10(
@@ -1280,7 +1285,7 @@ var ToolHeader = ({
1280
1285
  children: [
1281
1286
  /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
1282
1287
  /* @__PURE__ */ jsx17(WrenchIcon, { className: "size-4 text-muted-foreground" }),
1283
- /* @__PURE__ */ jsx17("span", { className: "font-medium text-sm", children: title ?? type.split("-").slice(1).join("-") }),
1288
+ /* @__PURE__ */ jsx17("span", { className: "font-medium text-sm", children: title ?? toolName ?? type.split("-").slice(1).join("-") }),
1284
1289
  getStatusBadge(state)
1285
1290
  ] }),
1286
1291
  /* @__PURE__ */ jsx17(ChevronDownIcon4, { className: "size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" })
@@ -1359,7 +1364,10 @@ function StarterMessages({
1359
1364
  onClick: () => onPromptSelect(prompt)
1360
1365
  }
1361
1366
  ),
1362
- index < prompts.length - 1 && /* @__PURE__ */ jsx18("div", { className: "h-px bg-[hsl(var(--chat-text)/0.08)] mx-3" })
1367
+ index < prompts.length - 1 && // 1px-tall element used as a divider — same --chat-divider token
1368
+ // every other separator in the widget uses, so consumers only
1369
+ // need to override one variable to recolour all of them.
1370
+ /* @__PURE__ */ jsx18("div", { className: "h-px mx-3", style: { backgroundColor: "var(--chat-divider)" } })
1363
1371
  ] }, index))
1364
1372
  }
1365
1373
  );
@@ -1432,6 +1440,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1432
1440
  const [activeTabId, setActiveTabId] = useState4("");
1433
1441
  const [initialTabCreated, setInitialTabCreated] = useState4(false);
1434
1442
  const [isInitializing, setIsInitializing] = useState4(true);
1443
+ const [isLoadingMessages, setIsLoadingMessages] = useState4(false);
1435
1444
  const lastSyncedTabId = useRef3("");
1436
1445
  const hasInitialized = useRef3(false);
1437
1446
  const { messages, sendMessage, status, setMessages } = useChat({
@@ -1611,7 +1620,12 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1611
1620
  }))
1612
1621
  );
1613
1622
  setActiveTabId(tabId);
1614
- await loadConversation(tabId);
1623
+ setIsLoadingMessages(true);
1624
+ try {
1625
+ await loadConversation(tabId);
1626
+ } finally {
1627
+ setIsLoadingMessages(false);
1628
+ }
1615
1629
  };
1616
1630
  const closeTab = (tabId) => {
1617
1631
  if (tabs.length <= 1) return;
@@ -1836,7 +1850,14 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1836
1850
  if (part.type.startsWith("tool-") || part.type === "dynamic-tool") {
1837
1851
  const toolPart = part;
1838
1852
  return /* @__PURE__ */ jsxs12(Tool, { children: [
1839
- /* @__PURE__ */ jsx20(ToolHeader, { type: part.type, state: toolPart.state }),
1853
+ /* @__PURE__ */ jsx20(
1854
+ ToolHeader,
1855
+ {
1856
+ type: part.type,
1857
+ toolName: toolPart.toolName,
1858
+ state: toolPart.state
1859
+ }
1860
+ ),
1840
1861
  /* @__PURE__ */ jsxs12(ToolContent, { children: [
1841
1862
  /* @__PURE__ */ jsx20(ToolInput, { input: toolPart.input }),
1842
1863
  /* @__PURE__ */ jsx20(ToolOutput, { output: toolPart.output, errorText: toolPart.errorText })
@@ -1902,7 +1923,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
1902
1923
  ),
1903
1924
  children: [
1904
1925
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 px-3 py-2 border-b backdrop-blur-sm relative z-20", style: {
1905
- borderColor: "var(--chat-border-soft)",
1926
+ borderColor: "var(--chat-divider)",
1906
1927
  backgroundColor: "var(--chat-header-bg)"
1907
1928
  }, children: [
1908
1929
  /* @__PURE__ */ jsx20("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__ */ jsxs12(
@@ -2004,10 +2025,10 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2004
2025
  ),
2005
2026
  showHistory && /* @__PURE__ */ jsxs12("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: {
2006
2027
  backgroundColor: "hsl(var(--chat-background))",
2007
- border: `1px solid ${"var(--chat-border-medium)"}`
2028
+ border: `1px solid ${"var(--chat-divider)"}`
2008
2029
  }, children: [
2009
2030
  /* @__PURE__ */ jsx20("div", { className: "p-2.5 border-b", style: {
2010
- borderColor: "var(--chat-border-soft)",
2031
+ borderColor: "var(--chat-divider)",
2011
2032
  backgroundColor: "var(--chat-overlay)"
2012
2033
  }, children: /* @__PURE__ */ jsx20("div", { className: "relative", children: /* @__PURE__ */ jsx20(
2013
2034
  "input",
@@ -2019,7 +2040,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2019
2040
  className: "w-full h-7 px-2.5 text-[13px] rounded-lg focus:outline-none transition-all",
2020
2041
  style: {
2021
2042
  backgroundColor: "hsl(var(--chat-surface-deep))",
2022
- border: `1px solid ${"var(--chat-border-medium)"}`,
2043
+ border: `1px solid ${"var(--chat-divider)"}`,
2023
2044
  color: "hsl(var(--chat-text))"
2024
2045
  }
2025
2046
  }
@@ -2116,7 +2137,7 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
2116
2137
  ] }),
2117
2138
  /* @__PURE__ */ jsxs12("div", { className: "px-5 pb-5", children: [
2118
2139
  uploadError && /* @__PURE__ */ jsx20("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 }),
2119
- isInitializing ? /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ jsx20("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__ */ jsx20(
2140
+ isInitializing || isLoadingMessages ? /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center py-8", role: "status", "aria-label": "Loading conversation", children: /* @__PURE__ */ jsx20("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__ */ jsx20(
2120
2141
  StarterMessages,
2121
2142
  {
2122
2143
  prompts: config.starterPrompts,
@@ -2200,15 +2221,26 @@ function ChatWidget({
2200
2221
  display,
2201
2222
  starterPrompts,
2202
2223
  onClose,
2203
- headerActions
2224
+ headerActions,
2225
+ open,
2226
+ onOpenChange
2204
2227
  }) {
2205
2228
  const layout = display?.layout || "popup";
2206
- const showToggleButton = display?.showToggleButton !== false;
2229
+ const isControlled = open !== void 0;
2230
+ const showToggleButton = !isControlled && display?.showToggleButton !== false;
2207
2231
  const resizable = layout === "popup" && display?.resizable !== false;
2208
2232
  const size = display?.size || "default";
2209
- const [isOpen, setIsOpen] = useState5(
2233
+ const [internalIsOpen, setInternalIsOpen] = useState5(
2210
2234
  layout !== "popup" ? true : display?.defaultOpen || false
2211
2235
  );
2236
+ const isOpen = isControlled ? open : internalIsOpen;
2237
+ const setIsOpen = (next) => {
2238
+ if (isControlled) {
2239
+ onOpenChange?.(next);
2240
+ } else {
2241
+ setInternalIsOpen(next);
2242
+ }
2243
+ };
2212
2244
  const [isResizing, setIsResizing] = useState5(false);
2213
2245
  const containerRef = useRef4(null);
2214
2246
  const customStyles = useMemo3(() => {