@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.cjs +376 -81
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +373 -77
- package/package.json +2 -2
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
|
|
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(
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
"
|
|
1945
|
+
"textarea",
|
|
1875
1946
|
{
|
|
1876
|
-
|
|
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
|
|
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__ */
|
|
2163
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
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] =
|
|
2210
|
-
const [errors, setErrors] =
|
|
2211
|
-
const [submitting, setSubmitting] =
|
|
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__ */
|
|
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__ */
|
|
2315
|
-
preChatForm.description && /* @__PURE__ */
|
|
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__ */
|
|
2324
|
-
/* @__PURE__ */
|
|
2618
|
+
return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
|
|
2619
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2325
2620
|
label,
|
|
2326
2621
|
required && " *"
|
|
2327
2622
|
] }),
|
|
2328
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2632
|
+
err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
|
|
2338
2633
|
] }, k);
|
|
2339
2634
|
}
|
|
2340
2635
|
if (field.kind === "select") {
|
|
2341
|
-
return /* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2636
|
+
return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
|
|
2637
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2343
2638
|
label,
|
|
2344
2639
|
required && " *"
|
|
2345
2640
|
] }),
|
|
2346
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2354
|
-
field.options.map((opt) => /* @__PURE__ */
|
|
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__ */
|
|
2653
|
+
err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
|
|
2359
2654
|
] }, k);
|
|
2360
2655
|
}
|
|
2361
2656
|
if (field.kind === "consent") {
|
|
2362
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2676
|
+
/* @__PURE__ */ jsxs7("span", { style: { fontSize: 13, fontWeight: 400 }, children: [
|
|
2382
2677
|
field.label,
|
|
2383
|
-
field.url && /* @__PURE__ */
|
|
2678
|
+
field.url && /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2384
2679
|
" ",
|
|
2385
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2406
|
-
/* @__PURE__ */
|
|
2700
|
+
return /* @__PURE__ */ jsxs7("label", { style: labelStyle, children: [
|
|
2701
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2407
2702
|
label,
|
|
2408
2703
|
required && " *"
|
|
2409
2704
|
] }),
|
|
2410
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2715
|
+
err && /* @__PURE__ */ jsx10("span", { style: errorStyle, children: err })
|
|
2421
2716
|
] }, k);
|
|
2422
2717
|
}),
|
|
2423
|
-
/* @__PURE__ */
|
|
2424
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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] =
|
|
2444
|
-
const [shouldRender, setShouldRender] =
|
|
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__ */
|
|
2495
|
-
/* @__PURE__ */
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
/* @__PURE__ */
|
|
2499
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2797
|
+
/* @__PURE__ */ jsxs7("div", { style: poweredStyle, children: [
|
|
2502
2798
|
t("powered_by"),
|
|
2503
2799
|
" ",
|
|
2504
|
-
/* @__PURE__ */
|
|
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
|
|
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__ */
|
|
2535
|
-
/* @__PURE__ */
|
|
2536
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2836
|
+
return /* @__PURE__ */ jsx11(CustomerHeroProvider, { ...config, children: /* @__PURE__ */ jsx11(ChatWidgetInner, { identity }) });
|
|
2541
2837
|
}
|
|
2542
2838
|
export {
|
|
2543
2839
|
ActionConfirmationCard,
|