@customerhero/react 2.1.0 → 2.2.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.js CHANGED
@@ -97,6 +97,10 @@ function useChat() {
97
97
  consumePendingPrefill: useCallback(
98
98
  () => client.consumePendingPrefill(),
99
99
  [client]
100
+ ),
101
+ dismissIncidentBanner: useCallback(
102
+ () => client.dismissIncidentBanner(),
103
+ [client]
100
104
  )
101
105
  };
102
106
  }
@@ -186,7 +190,7 @@ function ChatBubble() {
186
190
  }
187
191
 
188
192
  // src/components/chat-window.tsx
189
- import { useEffect as useEffect7, useState as useState7 } from "react";
193
+ import { useEffect as useEffect7, useState as useState8 } from "react";
190
194
 
191
195
  // src/components/chat-header.tsx
192
196
  import { useState as useState3, useEffect as useEffect4, useRef as useRef2 } from "react";
@@ -711,9 +715,11 @@ function renderMarkdown(source, opts = {}) {
711
715
  style: {
712
716
  margin: "0 0 8px",
713
717
  paddingLeft: 20,
714
- lineHeight: 1.5
718
+ lineHeight: 1.5,
719
+ listStyleType: "disc",
720
+ listStylePosition: "outside"
715
721
  },
716
- children: block.lines.map((l, i) => /* @__PURE__ */ jsx4("li", { children: renderInline(l) }, i))
722
+ children: block.lines.map((l, i) => /* @__PURE__ */ jsx4("li", { style: { display: "list-item" }, children: renderInline(l) }, i))
717
723
  },
718
724
  key
719
725
  );
@@ -724,9 +730,11 @@ function renderMarkdown(source, opts = {}) {
724
730
  style: {
725
731
  margin: "0 0 8px",
726
732
  paddingLeft: 22,
727
- lineHeight: 1.5
733
+ lineHeight: 1.5,
734
+ listStyleType: "decimal",
735
+ listStylePosition: "outside"
728
736
  },
729
- children: block.lines.map((l, i) => /* @__PURE__ */ jsx4("li", { children: renderInline(l) }, i))
737
+ children: block.lines.map((l, i) => /* @__PURE__ */ jsx4("li", { style: { display: "list-item" }, children: renderInline(l) }, i))
730
738
  },
731
739
  key
732
740
  );
@@ -929,11 +937,11 @@ function MessageStatusPill({
929
937
  const containerStyle = {
930
938
  display: "flex",
931
939
  alignItems: "center",
940
+ justifyContent: "flex-end",
932
941
  gap: 4,
933
942
  marginTop: 2,
934
943
  fontSize: 11,
935
- color: failed ? "#b91c1c" : "#888",
936
- alignSelf: "flex-end"
944
+ color: failed ? "#b91c1c" : "#888"
937
945
  };
938
946
  const labelKey = status === "sending" ? "status_sending" : status === "sent" ? "status_sent" : "status_failed";
939
947
  return /* @__PURE__ */ jsxs4("div", { style: containerStyle, "aria-live": "polite", children: [
@@ -1242,13 +1250,20 @@ function Message({
1242
1250
  };
1243
1251
  const linkColor = isUser ? "#ffffff" : config.primaryColor;
1244
1252
  return /* @__PURE__ */ jsxs4(AnimatedMessage, { isUser, animate, reduced, children: [
1245
- /* @__PURE__ */ jsx6("div", { style: bubbleStyle, children: isUser ? message.content : /* @__PURE__ */ jsxs4(Fragment3, { children: [
1246
- renderMarkdown(message.content, {
1247
- sources: message.sources,
1248
- linkColor
1249
- }),
1250
- message.streaming && /* @__PURE__ */ jsx6(StreamingCursor, { reduced })
1251
- ] }) }),
1253
+ /* @__PURE__ */ jsx6(
1254
+ "div",
1255
+ {
1256
+ style: bubbleStyle,
1257
+ "data-streaming-bubble": !isUser && message.streaming ? "true" : void 0,
1258
+ children: isUser ? message.content : /* @__PURE__ */ jsxs4(Fragment3, { children: [
1259
+ renderMarkdown(message.content, {
1260
+ sources: message.sources,
1261
+ linkColor
1262
+ }),
1263
+ message.streaming && /* @__PURE__ */ jsx6(StreamingCursor, { reduced })
1264
+ ] })
1265
+ }
1266
+ ),
1252
1267
  isUser && message.status && /* @__PURE__ */ jsx6(MessageStatusPill, { status: message.status, t }),
1253
1268
  !isUser && message.blocks?.map((block, i) => /* @__PURE__ */ jsx6(
1254
1269
  BlockRenderer,
@@ -1333,16 +1348,51 @@ function ChatMessages() {
1333
1348
  t
1334
1349
  } = useChat();
1335
1350
  const reduced = useReducedMotion();
1351
+ const containerRef = useRef3(null);
1336
1352
  const messagesEndRef = useRef3(null);
1337
1353
  const isFirstRender = useRef3(true);
1338
1354
  const prevMessageCount = useRef3(0);
1355
+ const stickRef = useRef3(true);
1356
+ const suppressScrollRef = useRef3(false);
1357
+ const autoScrollTo = (top) => {
1358
+ const el = containerRef.current;
1359
+ if (!el) return;
1360
+ suppressScrollRef.current = true;
1361
+ el.scrollTop = top;
1362
+ requestAnimationFrame(() => {
1363
+ suppressScrollRef.current = false;
1364
+ });
1365
+ };
1366
+ const handleScroll = () => {
1367
+ if (suppressScrollRef.current) return;
1368
+ const el = containerRef.current;
1369
+ if (!el) return;
1370
+ const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
1371
+ stickRef.current = distFromBottom < 60;
1372
+ };
1339
1373
  useEffect5(() => {
1340
- if (messagesEndRef.current) {
1341
- messagesEndRef.current.scrollIntoView({
1342
- behavior: isFirstRender.current || reduced ? "auto" : "smooth"
1343
- });
1344
- isFirstRender.current = false;
1374
+ const el = containerRef.current;
1375
+ if (!el) return;
1376
+ const lastMsg2 = messages[messages.length - 1];
1377
+ if (messages.length > prevMessageCount.current && lastMsg2?.role === "user") {
1378
+ stickRef.current = true;
1345
1379
  }
1380
+ if (!stickRef.current && !isFirstRender.current) {
1381
+ return;
1382
+ }
1383
+ const streamingBubble = el.querySelector(
1384
+ "[data-streaming-bubble='true']"
1385
+ );
1386
+ let target = el.scrollHeight - el.clientHeight;
1387
+ if (streamingBubble && streamingBubble.offsetHeight > el.clientHeight - 24) {
1388
+ const containerTop = el.getBoundingClientRect().top;
1389
+ const bubbleTop = streamingBubble.getBoundingClientRect().top;
1390
+ const TOP_GAP = 16;
1391
+ target = el.scrollTop + (bubbleTop - containerTop) - TOP_GAP;
1392
+ stickRef.current = false;
1393
+ }
1394
+ autoScrollTo(target);
1395
+ isFirstRender.current = false;
1346
1396
  }, [messages, isLoading, reduced]);
1347
1397
  const newStartIndex = isFirstRender.current ? messages.length : prevMessageCount.current;
1348
1398
  useEffect5(() => {
@@ -1365,7 +1415,7 @@ function ChatMessages() {
1365
1415
  };
1366
1416
  const lastMsg = messages[messages.length - 1];
1367
1417
  const waitingForFirstToken = isLoading && (lastMsg?.role !== "bot" || lastMsg.streaming !== true);
1368
- return /* @__PURE__ */ jsxs4("div", { style: containerStyle, children: [
1418
+ return /* @__PURE__ */ jsxs4("div", { ref: containerRef, style: containerStyle, onScroll: handleScroll, children: [
1369
1419
  messages.map((msg, i) => /* @__PURE__ */ jsx6(
1370
1420
  Message,
1371
1421
  {
@@ -1454,6 +1504,7 @@ function ChatSuggestions() {
1454
1504
  // src/components/chat-input.tsx
1455
1505
  import {
1456
1506
  useEffect as useEffect6,
1507
+ useLayoutEffect,
1457
1508
  useRef as useRef4,
1458
1509
  useState as useState6
1459
1510
  } from "react";
@@ -1492,12 +1543,23 @@ function ChatInput() {
1492
1543
  const [dragActive, setDragActive] = useState6(false);
1493
1544
  const [transientError, setTransientError] = useState6(null);
1494
1545
  const fileInputRef = useRef4(null);
1546
+ const textInputRef = useRef4(null);
1495
1547
  const menuRef = useRef4(null);
1496
1548
  const menuButtonRef = useRef4(null);
1497
1549
  const dragCounterRef = useRef4(0);
1498
1550
  useEffect6(() => {
1499
1551
  setCaptureSupported(canCaptureScreenshot());
1500
1552
  }, []);
1553
+ useEffect6(() => {
1554
+ const id = requestAnimationFrame(() => textInputRef.current?.focus());
1555
+ return () => cancelAnimationFrame(id);
1556
+ }, []);
1557
+ useLayoutEffect(() => {
1558
+ const el = textInputRef.current;
1559
+ if (!el) return;
1560
+ el.style.height = "auto";
1561
+ el.style.height = `${el.scrollHeight}px`;
1562
+ }, [value]);
1501
1563
  useEffect6(() => {
1502
1564
  if (pendingPrefill === null) return;
1503
1565
  const text = consumePendingPrefill();
@@ -1675,19 +1737,27 @@ function ChatInput() {
1675
1737
  };
1676
1738
  const rowStyle = {
1677
1739
  display: "flex",
1678
- alignItems: "center",
1740
+ // Anchor the icon buttons to the bottom of the row so a multi-line
1741
+ // textarea grows upward without dragging them along.
1742
+ alignItems: "flex-end",
1679
1743
  gap: 8
1680
1744
  };
1745
+ const TEXTAREA_MAX_HEIGHT = 140;
1681
1746
  const inputStyle = {
1682
1747
  flex: 1,
1683
1748
  border: "1px solid #e0e0e0",
1684
- borderRadius: 24,
1749
+ borderRadius: 18,
1685
1750
  padding: "10px 16px",
1686
1751
  fontSize: 14,
1752
+ lineHeight: 1.4,
1687
1753
  outline: "none",
1688
1754
  background: "#fafafa",
1689
1755
  color: config.textColor,
1690
- fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
1756
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
1757
+ resize: "none",
1758
+ overflowY: "auto",
1759
+ maxHeight: TEXTAREA_MAX_HEIGHT,
1760
+ boxSizing: "border-box"
1691
1761
  };
1692
1762
  const sendButtonStyle = {
1693
1763
  width: 36,
@@ -1745,6 +1815,7 @@ function ChatInput() {
1745
1815
  fontSize: 14,
1746
1816
  color: "#333",
1747
1817
  textAlign: "left",
1818
+ whiteSpace: "nowrap",
1748
1819
  fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
1749
1820
  };
1750
1821
  const dropOverlayStyle = {
@@ -1871,9 +1942,10 @@ function ChatInput() {
1871
1942
  }
1872
1943
  ),
1873
1944
  /* @__PURE__ */ jsx8(
1874
- "input",
1945
+ "textarea",
1875
1946
  {
1876
- type: "text",
1947
+ ref: textInputRef,
1948
+ rows: 1,
1877
1949
  value,
1878
1950
  onChange: (e) => setValue(e.target.value),
1879
1951
  onKeyDown: handleKeyDown,
@@ -2146,8 +2218,231 @@ function Spinner2() {
2146
2218
  ] });
2147
2219
  }
2148
2220
 
2221
+ // src/components/incident-banner.tsx
2222
+ import { useState as useState7 } from "react";
2223
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2224
+ var PALETTE = {
2225
+ info: {
2226
+ bg: "#EFF6FF",
2227
+ fg: "#1E3A8A",
2228
+ fgMuted: "#3B5BA9",
2229
+ accent: "#2563EB",
2230
+ iconBg: "#DBEAFE",
2231
+ iconFg: "#2563EB"
2232
+ },
2233
+ warning: {
2234
+ bg: "#FFFBEB",
2235
+ fg: "#78350F",
2236
+ fgMuted: "#92541A",
2237
+ accent: "#B45309",
2238
+ iconBg: "#FEF3C7",
2239
+ iconFg: "#B45309"
2240
+ },
2241
+ outage: {
2242
+ bg: "#FEF2F2",
2243
+ fg: "#991B1B",
2244
+ fgMuted: "#B23A3A",
2245
+ accent: "#DC2626",
2246
+ iconBg: "#FEE2E2",
2247
+ iconFg: "#DC2626"
2248
+ }
2249
+ };
2250
+ function SeverityIcon({
2251
+ severity,
2252
+ color
2253
+ }) {
2254
+ const props = {
2255
+ width: 14,
2256
+ height: 14,
2257
+ viewBox: "0 0 24 24",
2258
+ fill: "none",
2259
+ stroke: color,
2260
+ strokeWidth: 2.25,
2261
+ strokeLinecap: "round",
2262
+ strokeLinejoin: "round",
2263
+ "aria-hidden": true
2264
+ };
2265
+ if (severity === "outage") {
2266
+ return /* @__PURE__ */ jsxs6("svg", { ...props, children: [
2267
+ /* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r: "10" }),
2268
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
2269
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
2270
+ ] });
2271
+ }
2272
+ if (severity === "warning") {
2273
+ return /* @__PURE__ */ jsxs6("svg", { ...props, children: [
2274
+ /* @__PURE__ */ jsx9("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
2275
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
2276
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
2277
+ ] });
2278
+ }
2279
+ return /* @__PURE__ */ jsxs6("svg", { ...props, children: [
2280
+ /* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r: "10" }),
2281
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
2282
+ /* @__PURE__ */ jsx9("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
2283
+ ] });
2284
+ }
2285
+ function IncidentBanner() {
2286
+ const { incidentBanner, incidentBannerDismissed, dismissIncidentBanner, t } = useChat();
2287
+ const [linkHover, setLinkHover] = useState7(false);
2288
+ const [closeHover, setCloseHover] = useState7(false);
2289
+ if (!incidentBanner || incidentBannerDismissed) return null;
2290
+ const palette = PALETTE[incidentBanner.severity];
2291
+ const wrap = {
2292
+ background: palette.bg,
2293
+ color: palette.fg,
2294
+ padding: "12px 14px 12px 12px",
2295
+ display: "flex",
2296
+ gap: 10,
2297
+ alignItems: "flex-start",
2298
+ fontSize: 13,
2299
+ lineHeight: 1.45,
2300
+ boxShadow: "inset 0 -1px 0 rgba(0,0,0,0.04)"
2301
+ };
2302
+ const iconBadge = {
2303
+ width: 22,
2304
+ height: 22,
2305
+ borderRadius: "50%",
2306
+ background: palette.iconBg,
2307
+ display: "flex",
2308
+ alignItems: "center",
2309
+ justifyContent: "center",
2310
+ flexShrink: 0,
2311
+ marginTop: 1
2312
+ };
2313
+ const titleStyle = {
2314
+ margin: 0,
2315
+ fontSize: 13,
2316
+ fontWeight: 600,
2317
+ letterSpacing: "-0.005em"
2318
+ };
2319
+ const bodyStyle = {
2320
+ margin: "3px 0 0",
2321
+ fontSize: 12.5,
2322
+ color: palette.fgMuted
2323
+ };
2324
+ const footerRowStyle = {
2325
+ display: "flex",
2326
+ flexWrap: "wrap",
2327
+ alignItems: "center",
2328
+ gap: 10,
2329
+ marginTop: 8
2330
+ };
2331
+ const etaStyle = {
2332
+ display: "inline-block",
2333
+ padding: "2px 8px",
2334
+ borderRadius: 4,
2335
+ fontSize: 11,
2336
+ fontWeight: 500,
2337
+ color: palette.accent,
2338
+ background: palette.iconBg,
2339
+ lineHeight: 1.4
2340
+ };
2341
+ const linkStyle = {
2342
+ display: "inline-flex",
2343
+ alignItems: "center",
2344
+ gap: 4,
2345
+ color: palette.accent,
2346
+ textDecoration: linkHover ? "underline" : "none",
2347
+ textUnderlineOffset: 3,
2348
+ fontSize: 12.5,
2349
+ fontWeight: 600
2350
+ };
2351
+ const closeButtonStyle = {
2352
+ background: closeHover ? "rgba(0,0,0,0.06)" : "transparent",
2353
+ border: "none",
2354
+ color: palette.fgMuted,
2355
+ cursor: "pointer",
2356
+ padding: 4,
2357
+ borderRadius: 6,
2358
+ flexShrink: 0,
2359
+ lineHeight: 0,
2360
+ marginTop: -2,
2361
+ marginRight: -2,
2362
+ transition: "background-color 0.12s ease"
2363
+ };
2364
+ const role = incidentBanner.severity === "outage" ? "alert" : "status";
2365
+ return /* @__PURE__ */ jsxs6("div", { role, style: wrap, children: [
2366
+ /* @__PURE__ */ jsx9("div", { style: iconBadge, children: /* @__PURE__ */ jsx9(
2367
+ SeverityIcon,
2368
+ {
2369
+ severity: incidentBanner.severity,
2370
+ color: palette.iconFg
2371
+ }
2372
+ ) }),
2373
+ /* @__PURE__ */ jsxs6("div", { style: { flex: 1, minWidth: 0 }, children: [
2374
+ /* @__PURE__ */ jsx9("p", { style: titleStyle, children: incidentBanner.title }),
2375
+ incidentBanner.body ? /* @__PURE__ */ jsx9("p", { style: bodyStyle, children: incidentBanner.body }) : null,
2376
+ incidentBanner.eta || incidentBanner.link ? /* @__PURE__ */ jsxs6("div", { style: footerRowStyle, children: [
2377
+ incidentBanner.eta ? /* @__PURE__ */ jsx9("span", { style: etaStyle, children: incidentBanner.eta }) : null,
2378
+ incidentBanner.link ? /* @__PURE__ */ jsxs6(
2379
+ "a",
2380
+ {
2381
+ href: incidentBanner.link.url,
2382
+ target: "_blank",
2383
+ rel: "noopener noreferrer",
2384
+ style: linkStyle,
2385
+ onMouseEnter: () => setLinkHover(true),
2386
+ onMouseLeave: () => setLinkHover(false),
2387
+ children: [
2388
+ incidentBanner.link.label ?? t("incident_default_link_label"),
2389
+ /* @__PURE__ */ jsxs6(
2390
+ "svg",
2391
+ {
2392
+ width: "12",
2393
+ height: "12",
2394
+ viewBox: "0 0 24 24",
2395
+ fill: "none",
2396
+ stroke: "currentColor",
2397
+ strokeWidth: "2.5",
2398
+ strokeLinecap: "round",
2399
+ strokeLinejoin: "round",
2400
+ "aria-hidden": "true",
2401
+ children: [
2402
+ /* @__PURE__ */ jsx9("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
2403
+ /* @__PURE__ */ jsx9("polyline", { points: "12 5 19 12 12 19" })
2404
+ ]
2405
+ }
2406
+ )
2407
+ ]
2408
+ }
2409
+ ) : null
2410
+ ] }) : null
2411
+ ] }),
2412
+ /* @__PURE__ */ jsx9(
2413
+ "button",
2414
+ {
2415
+ type: "button",
2416
+ onClick: dismissIncidentBanner,
2417
+ "aria-label": t("incident_dismiss"),
2418
+ style: closeButtonStyle,
2419
+ onMouseEnter: () => setCloseHover(true),
2420
+ onMouseLeave: () => setCloseHover(false),
2421
+ children: /* @__PURE__ */ jsxs6(
2422
+ "svg",
2423
+ {
2424
+ width: "14",
2425
+ height: "14",
2426
+ viewBox: "0 0 24 24",
2427
+ fill: "none",
2428
+ stroke: "currentColor",
2429
+ strokeWidth: "2",
2430
+ strokeLinecap: "round",
2431
+ strokeLinejoin: "round",
2432
+ "aria-hidden": "true",
2433
+ children: [
2434
+ /* @__PURE__ */ jsx9("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2435
+ /* @__PURE__ */ jsx9("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2436
+ ]
2437
+ }
2438
+ )
2439
+ }
2440
+ )
2441
+ ] });
2442
+ }
2443
+
2149
2444
  // src/components/chat-window.tsx
2150
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2445
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2151
2446
  function ConfigError({ message, title }) {
2152
2447
  const errorStyle = {
2153
2448
  flex: 1,
@@ -2159,8 +2454,8 @@ function ConfigError({ message, title }) {
2159
2454
  textAlign: "center",
2160
2455
  gap: 8
2161
2456
  };
2162
- return /* @__PURE__ */ jsxs6("div", { style: errorStyle, children: [
2163
- /* @__PURE__ */ jsxs6(
2457
+ return /* @__PURE__ */ jsxs7("div", { style: errorStyle, children: [
2458
+ /* @__PURE__ */ jsxs7(
2164
2459
  "svg",
2165
2460
  {
2166
2461
  width: "32",
@@ -2172,14 +2467,14 @@ function ConfigError({ message, title }) {
2172
2467
  strokeLinecap: "round",
2173
2468
  strokeLinejoin: "round",
2174
2469
  children: [
2175
- /* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r: "10" }),
2176
- /* @__PURE__ */ jsx9("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
2177
- /* @__PURE__ */ jsx9("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
2470
+ /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "10" }),
2471
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
2472
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
2178
2473
  ]
2179
2474
  }
2180
2475
  ),
2181
- /* @__PURE__ */ jsx9("p", { style: { fontSize: 14, fontWeight: 500, color: "#333", margin: 0 }, children: title }),
2182
- /* @__PURE__ */ jsx9("p", { style: { fontSize: 12, color: "#999", margin: 0 }, children: message })
2476
+ /* @__PURE__ */ jsx10("p", { style: { fontSize: 14, fontWeight: 500, color: "#333", margin: 0 }, children: title }),
2477
+ /* @__PURE__ */ jsx10("p", { style: { fontSize: 12, color: "#999", margin: 0 }, children: message })
2183
2478
  ] });
2184
2479
  }
2185
2480
  function fieldKey(field) {
@@ -2206,9 +2501,9 @@ function validateField(field, value) {
2206
2501
  }
2207
2502
  function PreChatFormView() {
2208
2503
  const { preChatForm, submitPreChatForm, cancelPreChatForm, config, t } = useChat();
2209
- const [values, setValues] = useState7({});
2210
- const [errors, setErrors] = useState7({});
2211
- const [submitting, setSubmitting] = useState7(false);
2504
+ const [values, setValues] = useState8({});
2505
+ const [errors, setErrors] = useState8({});
2506
+ const [submitting, setSubmitting] = useState8(false);
2212
2507
  if (!preChatForm) return null;
2213
2508
  function setValue(key, value) {
2214
2509
  setValues((prev) => ({ ...prev, [key]: value }));
@@ -2304,15 +2599,15 @@ function PreChatFormView() {
2304
2599
  fontSize: 14,
2305
2600
  cursor: "pointer"
2306
2601
  };
2307
- return /* @__PURE__ */ jsxs6(
2602
+ return /* @__PURE__ */ jsxs7(
2308
2603
  "form",
2309
2604
  {
2310
2605
  style: containerStyle,
2311
2606
  onSubmit: handleSubmit,
2312
2607
  "data-customerhero-prechat-form": true,
2313
2608
  children: [
2314
- preChatForm.title && /* @__PURE__ */ jsx9("h3", { style: { fontSize: 16, fontWeight: 600, margin: 0 }, children: preChatForm.title }),
2315
- preChatForm.description && /* @__PURE__ */ jsx9("p", { style: { fontSize: 13, margin: 0, opacity: 0.8 }, children: preChatForm.description }),
2609
+ preChatForm.title && /* @__PURE__ */ jsx10("h3", { style: { fontSize: 16, fontWeight: 600, margin: 0 }, children: preChatForm.title }),
2610
+ preChatForm.description && /* @__PURE__ */ jsx10("p", { style: { fontSize: 13, margin: 0, opacity: 0.8 }, children: preChatForm.description }),
2316
2611
  preChatForm.fields.map((field) => {
2317
2612
  const k = fieldKey(field);
2318
2613
  const v = values[k];
@@ -2320,12 +2615,12 @@ function PreChatFormView() {
2320
2615
  const required = "required" in field ? !!field.required : false;
2321
2616
  const label = fieldLabel(field);
2322
2617
  if (field.kind === "textarea") {
2323
- return /* @__PURE__ */ jsxs6("label", { style: labelStyle, children: [
2324
- /* @__PURE__ */ jsxs6("span", { children: [
2618
+ return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
2619
+ /* @__PURE__ */ jsxs7("span", { children: [
2325
2620
  label,
2326
2621
  required && " *"
2327
2622
  ] }),
2328
- /* @__PURE__ */ jsx9(
2623
+ /* @__PURE__ */ jsx10(
2329
2624
  "textarea",
2330
2625
  {
2331
2626
  style: { ...inputStyle, minHeight: 80, resize: "vertical" },
@@ -2334,32 +2629,32 @@ function PreChatFormView() {
2334
2629
  onChange: (e) => setValue(k, e.target.value)
2335
2630
  }
2336
2631
  ),
2337
- err && /* @__PURE__ */ jsx9("span", { style: errorStyle, children: err })
2632
+ err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
2338
2633
  ] }, k);
2339
2634
  }
2340
2635
  if (field.kind === "select") {
2341
- return /* @__PURE__ */ jsxs6("label", { style: labelStyle, children: [
2342
- /* @__PURE__ */ jsxs6("span", { children: [
2636
+ return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
2637
+ /* @__PURE__ */ jsxs7("span", { children: [
2343
2638
  label,
2344
2639
  required && " *"
2345
2640
  ] }),
2346
- /* @__PURE__ */ jsxs6(
2641
+ /* @__PURE__ */ jsxs7(
2347
2642
  "select",
2348
2643
  {
2349
2644
  style: inputStyle,
2350
2645
  value: v ?? "",
2351
2646
  onChange: (e) => setValue(k, e.target.value),
2352
2647
  children: [
2353
- /* @__PURE__ */ jsx9("option", { value: "", children: "\u2014" }),
2354
- field.options.map((opt) => /* @__PURE__ */ jsx9("option", { value: opt.value, children: opt.label }, opt.value))
2648
+ /* @__PURE__ */ jsx10("option", { value: "", children: "\u2014" }),
2649
+ field.options.map((opt) => /* @__PURE__ */ jsx10("option", { value: opt.value, children: opt.label }, opt.value))
2355
2650
  ]
2356
2651
  }
2357
2652
  ),
2358
- err && /* @__PURE__ */ jsx9("span", { style: errorStyle, children: err })
2653
+ err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
2359
2654
  ] }, k);
2360
2655
  }
2361
2656
  if (field.kind === "consent") {
2362
- return /* @__PURE__ */ jsxs6(
2657
+ return /* @__PURE__ */ jsxs7(
2363
2658
  "label",
2364
2659
  {
2365
2660
  style: {
@@ -2369,7 +2664,7 @@ function PreChatFormView() {
2369
2664
  gap: 8
2370
2665
  },
2371
2666
  children: [
2372
- /* @__PURE__ */ jsx9(
2667
+ /* @__PURE__ */ jsx10(
2373
2668
  "input",
2374
2669
  {
2375
2670
  type: "checkbox",
@@ -2378,11 +2673,11 @@ function PreChatFormView() {
2378
2673
  style: { marginTop: 3 }
2379
2674
  }
2380
2675
  ),
2381
- /* @__PURE__ */ jsxs6("span", { style: { fontSize: 13, fontWeight: 400 }, children: [
2676
+ /* @__PURE__ */ jsxs7("span", { style: { fontSize: 13, fontWeight: 400 }, children: [
2382
2677
  field.label,
2383
- field.url && /* @__PURE__ */ jsxs6(Fragment5, { children: [
2678
+ field.url && /* @__PURE__ */ jsxs7(Fragment5, { children: [
2384
2679
  " ",
2385
- /* @__PURE__ */ jsx9(
2680
+ /* @__PURE__ */ jsx10(
2386
2681
  "a",
2387
2682
  {
2388
2683
  href: field.url,
@@ -2394,7 +2689,7 @@ function PreChatFormView() {
2394
2689
  )
2395
2690
  ] })
2396
2691
  ] }),
2397
- err && /* @__PURE__ */ jsx9("span", { style: errorStyle, children: err })
2692
+ err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
2398
2693
  ]
2399
2694
  },
2400
2695
  k
@@ -2402,12 +2697,12 @@ function PreChatFormView() {
2402
2697
  }
2403
2698
  const inputType = field.kind === "email" ? "email" : field.kind === "phone" ? "tel" : "text";
2404
2699
  const maxLength = field.kind === "text" ? field.maxLength : void 0;
2405
- return /* @__PURE__ */ jsxs6("label", { style: labelStyle, children: [
2406
- /* @__PURE__ */ jsxs6("span", { children: [
2700
+ return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
2701
+ /* @__PURE__ */ jsxs7("span", { children: [
2407
2702
  label,
2408
2703
  required && " *"
2409
2704
  ] }),
2410
- /* @__PURE__ */ jsx9(
2705
+ /* @__PURE__ */ jsx10(
2411
2706
  "input",
2412
2707
  {
2413
2708
  type: inputType,
@@ -2417,11 +2712,11 @@ function PreChatFormView() {
2417
2712
  onChange: (e) => setValue(k, e.target.value)
2418
2713
  }
2419
2714
  ),
2420
- err && /* @__PURE__ */ jsx9("span", { style: errorStyle, children: err })
2715
+ err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
2421
2716
  ] }, k);
2422
2717
  }),
2423
- /* @__PURE__ */ jsxs6("div", { style: buttonRowStyle, children: [
2424
- /* @__PURE__ */ jsx9(
2718
+ /* @__PURE__ */ jsxs7("div", { style: buttonRowStyle, children: [
2719
+ /* @__PURE__ */ jsx10(
2425
2720
  "button",
2426
2721
  {
2427
2722
  type: "button",
@@ -2431,7 +2726,7 @@ function PreChatFormView() {
2431
2726
  children: t("action_cancel")
2432
2727
  }
2433
2728
  ),
2434
- /* @__PURE__ */ jsx9("button", { type: "submit", style: submitStyle, disabled: submitting, children: preChatForm.submitLabel })
2729
+ /* @__PURE__ */ jsx10("button", { type: "submit", style: submitStyle, disabled: submitting, children: preChatForm.submitLabel })
2435
2730
  ] })
2436
2731
  ]
2437
2732
  }
@@ -2440,8 +2735,8 @@ function PreChatFormView() {
2440
2735
  function ChatWindow() {
2441
2736
  const { isOpen, config, configError, t, isRtl, preChatFormVisible } = useChat();
2442
2737
  const reduced = useReducedMotion();
2443
- const [visible, setVisible] = useState7(false);
2444
- const [shouldRender, setShouldRender] = useState7(false);
2738
+ const [visible, setVisible] = useState8(false);
2739
+ const [shouldRender, setShouldRender] = useState8(false);
2445
2740
  useEffect7(() => {
2446
2741
  if (isOpen) {
2447
2742
  setShouldRender(true);
@@ -2491,17 +2786,18 @@ function ChatWindow() {
2491
2786
  textDecoration: "underline",
2492
2787
  textUnderlineOffset: 2
2493
2788
  };
2494
- return /* @__PURE__ */ jsxs6("div", { style, dir: isRtl ? "rtl" : "ltr", children: [
2495
- /* @__PURE__ */ jsx9(ChatHeader, {}),
2496
- configError ? /* @__PURE__ */ jsx9(ConfigError, { title: t("unable_to_load"), message: configError }) : preChatFormVisible ? /* @__PURE__ */ jsx9(PreChatFormView, {}) : /* @__PURE__ */ jsxs6(Fragment5, { children: [
2497
- /* @__PURE__ */ jsx9(ChatMessages, {}),
2498
- /* @__PURE__ */ jsx9(ChatSuggestions, {}),
2499
- /* @__PURE__ */ jsx9(ChatInput, {})
2789
+ return /* @__PURE__ */ jsxs7("div", { style, dir: isRtl ? "rtl" : "ltr", children: [
2790
+ /* @__PURE__ */ jsx10(ChatHeader, {}),
2791
+ /* @__PURE__ */ jsx10(IncidentBanner, {}),
2792
+ configError ? /* @__PURE__ */ jsx10(ConfigError, { title: t("unable_to_load"), message: configError }) : preChatFormVisible ? /* @__PURE__ */ jsx10(PreChatFormView, {}) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
2793
+ /* @__PURE__ */ jsx10(ChatMessages, {}),
2794
+ /* @__PURE__ */ jsx10(ChatSuggestions, {}),
2795
+ /* @__PURE__ */ jsx10(ChatInput, {})
2500
2796
  ] }),
2501
- /* @__PURE__ */ jsxs6("div", { style: poweredStyle, children: [
2797
+ /* @__PURE__ */ jsxs7("div", { style: poweredStyle, children: [
2502
2798
  t("powered_by"),
2503
2799
  " ",
2504
- /* @__PURE__ */ jsx9(
2800
+ /* @__PURE__ */ jsx10(
2505
2801
  "a",
2506
2802
  {
2507
2803
  href: "https://customerhero.app",
@@ -2516,7 +2812,7 @@ function ChatWindow() {
2516
2812
  }
2517
2813
 
2518
2814
  // src/components/chat-widget.tsx
2519
- import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2815
+ import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2520
2816
  function ChatWidgetInner({ identity }) {
2521
2817
  const client = useCustomerHeroClient();
2522
2818
  const { configLoaded, configError } = useChat();
@@ -2531,13 +2827,13 @@ function ChatWidgetInner({ identity }) {
2531
2827
  }
2532
2828
  }, [identity, client]);
2533
2829
  if (!configLoaded || configError) return null;
2534
- return /* @__PURE__ */ jsxs7(Fragment6, { children: [
2535
- /* @__PURE__ */ jsx10(ChatBubble, {}),
2536
- /* @__PURE__ */ jsx10(ChatWindow, {})
2830
+ return /* @__PURE__ */ jsxs8(Fragment6, { children: [
2831
+ /* @__PURE__ */ jsx11(ChatBubble, {}),
2832
+ /* @__PURE__ */ jsx11(ChatWindow, {})
2537
2833
  ] });
2538
2834
  }
2539
2835
  function ChatWidget({ identity, ...config }) {
2540
- return /* @__PURE__ */ jsx10(CustomerHeroProvider, { ...config, children: /* @__PURE__ */ jsx10(ChatWidgetInner, { identity }) });
2836
+ return /* @__PURE__ */ jsx11(CustomerHeroProvider, { ...config, children: /* @__PURE__ */ jsx11(ChatWidgetInner, { identity }) });
2541
2837
  }
2542
2838
  export {
2543
2839
  ActionConfirmationCard,