@burdenoff/website-sdk 2026.829.1 → 2026.829.3
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/components/explore.js +281 -66
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +282 -67
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +50 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +50 -1
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +281 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +282 -67
- package/dist/index.mjs.map +1 -1
- package/dist/{use-explore-chat-DhvZhH8f.d.mts → use-explore-chat-B-E7jN1H.d.mts} +21 -2
- package/dist/{use-explore-chat-DhvZhH8f.d.ts → use-explore-chat-B-E7jN1H.d.ts} +21 -2
- package/package.json +1 -1
|
@@ -489,6 +489,7 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
489
489
|
description
|
|
490
490
|
product
|
|
491
491
|
imageUrl
|
|
492
|
+
index
|
|
492
493
|
}
|
|
493
494
|
ctas {
|
|
494
495
|
kind
|
|
@@ -496,6 +497,8 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
496
497
|
url
|
|
497
498
|
product
|
|
498
499
|
}
|
|
500
|
+
followUps
|
|
501
|
+
answered
|
|
499
502
|
errorCode
|
|
500
503
|
createdAt
|
|
501
504
|
completedAt
|
|
@@ -561,6 +564,26 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
|
|
|
561
564
|
}
|
|
562
565
|
`
|
|
563
566
|
);
|
|
567
|
+
var RECORD_EXPLORE_CLICK_MUTATION = (
|
|
568
|
+
/* GraphQL */
|
|
569
|
+
`
|
|
570
|
+
mutation RecordExploreClick($input: RecordExploreClickInput!) {
|
|
571
|
+
recordExploreClick(input: $input) {
|
|
572
|
+
recorded
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
`
|
|
576
|
+
);
|
|
577
|
+
var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
|
|
578
|
+
/* GraphQL */
|
|
579
|
+
`
|
|
580
|
+
mutation CreateExploreShareLink($conversationToken: String!) {
|
|
581
|
+
createExploreShareLink(conversationToken: $conversationToken) {
|
|
582
|
+
shareToken
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
`
|
|
586
|
+
);
|
|
564
587
|
|
|
565
588
|
// src/data/products.ts
|
|
566
589
|
var ECOSYSTEM_PRODUCTS = [
|
|
@@ -1493,6 +1516,30 @@ function useExploreChat(options = {}) {
|
|
|
1493
1516
|
return null;
|
|
1494
1517
|
}, [messages]);
|
|
1495
1518
|
const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
|
|
1519
|
+
const createShareLink = React.useCallback(async () => {
|
|
1520
|
+
const token = conversationTokenRef.current;
|
|
1521
|
+
if (!token) return null;
|
|
1522
|
+
try {
|
|
1523
|
+
const result = await client.mutate(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });
|
|
1524
|
+
return result?.data?.createExploreShareLink?.shareToken ?? null;
|
|
1525
|
+
} catch {
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
}, [client]);
|
|
1529
|
+
const recordClick = React.useCallback(
|
|
1530
|
+
(messageId, kind, url) => {
|
|
1531
|
+
const token = conversationTokenRef.current;
|
|
1532
|
+
if (!token) return;
|
|
1533
|
+
try {
|
|
1534
|
+
void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
|
|
1535
|
+
input: { conversationToken: token, messageId, kind, url }
|
|
1536
|
+
}).catch(() => {
|
|
1537
|
+
});
|
|
1538
|
+
} catch {
|
|
1539
|
+
}
|
|
1540
|
+
},
|
|
1541
|
+
[client]
|
|
1542
|
+
);
|
|
1496
1543
|
return {
|
|
1497
1544
|
phase,
|
|
1498
1545
|
catalog,
|
|
@@ -1510,7 +1557,9 @@ function useExploreChat(options = {}) {
|
|
|
1510
1557
|
history: archive,
|
|
1511
1558
|
openConversation,
|
|
1512
1559
|
deleteConversation,
|
|
1513
|
-
clearHistory
|
|
1560
|
+
clearHistory,
|
|
1561
|
+
recordClick,
|
|
1562
|
+
createShareLink
|
|
1514
1563
|
};
|
|
1515
1564
|
}
|
|
1516
1565
|
var optimisticCounter = 0;
|
|
@@ -2007,7 +2056,10 @@ function logoUrlOf(url) {
|
|
|
2007
2056
|
return null;
|
|
2008
2057
|
}
|
|
2009
2058
|
}
|
|
2010
|
-
function ReferenceCard({
|
|
2059
|
+
function ReferenceCard({
|
|
2060
|
+
reference,
|
|
2061
|
+
onFollow
|
|
2062
|
+
}) {
|
|
2011
2063
|
const [imageFailed, setImageFailed] = React.useState(false);
|
|
2012
2064
|
const [logoFailed, setLogoFailed] = React.useState(false);
|
|
2013
2065
|
const host = hostnameOf(reference.url);
|
|
@@ -2029,9 +2081,11 @@ function ReferenceCard({ reference }) {
|
|
|
2029
2081
|
"a",
|
|
2030
2082
|
{
|
|
2031
2083
|
"data-boff-explore": "reference",
|
|
2084
|
+
"data-index": reference.index ?? void 0,
|
|
2032
2085
|
href: reference.url,
|
|
2033
2086
|
target: "_blank",
|
|
2034
2087
|
rel: "noopener noreferrer",
|
|
2088
|
+
onClick: () => onFollow?.(reference.url),
|
|
2035
2089
|
className: "group flex flex-row items-center gap-3 overflow-hidden rounded-xl border border-border bg-card p-2 transition-colors hover:border-primary/40 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:flex-col sm:items-stretch sm:gap-0 sm:p-0",
|
|
2036
2090
|
children: [
|
|
2037
2091
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
|
|
@@ -2055,7 +2109,10 @@ function ReferenceCard({ reference }) {
|
|
|
2055
2109
|
}
|
|
2056
2110
|
) }) : letterPlate }),
|
|
2057
2111
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
|
|
2058
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2112
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: [
|
|
2113
|
+
reference.index ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-bold text-primary", children: reference.index }) : null,
|
|
2114
|
+
reference.title || host || reference.url
|
|
2115
|
+
] }),
|
|
2059
2116
|
reference.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
|
|
2060
2117
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
|
|
2061
2118
|
reference.product ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground max-sm:hidden", children: reference.product }) : null,
|
|
@@ -2071,7 +2128,8 @@ function ReferenceCard({ reference }) {
|
|
|
2071
2128
|
}
|
|
2072
2129
|
function CtaButton({
|
|
2073
2130
|
cta,
|
|
2074
|
-
onNavigate
|
|
2131
|
+
onNavigate,
|
|
2132
|
+
onFollow
|
|
2075
2133
|
}) {
|
|
2076
2134
|
const variant = CTA_VARIANTS[cta.kind] ?? "outline";
|
|
2077
2135
|
const internal = isInternalPath(cta.url);
|
|
@@ -2084,7 +2142,10 @@ function CtaButton({
|
|
|
2084
2142
|
type: "button",
|
|
2085
2143
|
size: "sm",
|
|
2086
2144
|
variant,
|
|
2087
|
-
onClick: () =>
|
|
2145
|
+
onClick: () => {
|
|
2146
|
+
onFollow?.(cta.url);
|
|
2147
|
+
onNavigate(cta.url);
|
|
2148
|
+
},
|
|
2088
2149
|
children: cta.label
|
|
2089
2150
|
}
|
|
2090
2151
|
);
|
|
@@ -2095,6 +2156,7 @@ function CtaButton({
|
|
|
2095
2156
|
"data-boff-explore": "cta",
|
|
2096
2157
|
"data-kind": cta.kind,
|
|
2097
2158
|
href: cta.url,
|
|
2159
|
+
onClick: () => onFollow?.(cta.url),
|
|
2098
2160
|
...internal ? {} : { target: "_blank", rel: "noopener noreferrer" },
|
|
2099
2161
|
children: [
|
|
2100
2162
|
cta.label,
|
|
@@ -2146,7 +2208,9 @@ function AssistantBubble({
|
|
|
2146
2208
|
message,
|
|
2147
2209
|
activity,
|
|
2148
2210
|
onNavigate,
|
|
2149
|
-
anchorRef
|
|
2211
|
+
anchorRef,
|
|
2212
|
+
onFollow,
|
|
2213
|
+
onFollowUp
|
|
2150
2214
|
}) {
|
|
2151
2215
|
const streaming = message.status === "PENDING" || message.status === "RUNNING";
|
|
2152
2216
|
const body = message.content || message.partialContent || "";
|
|
@@ -2168,6 +2232,34 @@ function AssistantBubble({
|
|
|
2168
2232
|
}
|
|
2169
2233
|
),
|
|
2170
2234
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
|
|
2235
|
+
message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2236
|
+
"div",
|
|
2237
|
+
{
|
|
2238
|
+
"data-boff-explore": "no-answer",
|
|
2239
|
+
className: "flex items-start gap-2 rounded-xl border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-foreground",
|
|
2240
|
+
children: [
|
|
2241
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
|
|
2242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2243
|
+
"I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
|
|
2244
|
+
" ",
|
|
2245
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2246
|
+
"a",
|
|
2247
|
+
{
|
|
2248
|
+
href: "/contact",
|
|
2249
|
+
className: "underline underline-offset-2 hover:text-primary",
|
|
2250
|
+
onClick: (event) => {
|
|
2251
|
+
if (!onNavigate) return;
|
|
2252
|
+
event.preventDefault();
|
|
2253
|
+
onNavigate("/contact");
|
|
2254
|
+
},
|
|
2255
|
+
children: "ask a human"
|
|
2256
|
+
}
|
|
2257
|
+
),
|
|
2258
|
+
"."
|
|
2259
|
+
] })
|
|
2260
|
+
]
|
|
2261
|
+
}
|
|
2262
|
+
) : null,
|
|
2171
2263
|
body ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
2172
2264
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { children: body }) }),
|
|
2173
2265
|
streaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
@@ -2176,16 +2268,41 @@ function AssistantBubble({
|
|
|
2176
2268
|
failed && !body ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-2xl rounded-tl-md border border-border bg-muted px-4 py-3 text-sm text-muted-foreground", children: "That answer didn't come through. Try asking again." }) : null,
|
|
2177
2269
|
message.references.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2178
2270
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
|
|
2179
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2271
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2272
|
+
ReferenceCard,
|
|
2273
|
+
{
|
|
2274
|
+
reference,
|
|
2275
|
+
onFollow: (url) => onFollow?.("REFERENCE", url)
|
|
2276
|
+
},
|
|
2277
|
+
reference.url
|
|
2278
|
+
)) })
|
|
2180
2279
|
] }) : null,
|
|
2181
2280
|
message.ctas.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 pt-0.5", children: message.ctas.map((cta) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2182
2281
|
CtaButton,
|
|
2183
2282
|
{
|
|
2184
2283
|
cta,
|
|
2185
|
-
onNavigate
|
|
2284
|
+
onNavigate,
|
|
2285
|
+
onFollow: (url) => onFollow?.("CTA", url)
|
|
2186
2286
|
},
|
|
2187
2287
|
`${cta.kind}-${cta.url}`
|
|
2188
|
-
)) }) : null
|
|
2288
|
+
)) }) : null,
|
|
2289
|
+
message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
|
|
2290
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
|
|
2291
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2292
|
+
"button",
|
|
2293
|
+
{
|
|
2294
|
+
"data-boff-explore": "follow-up",
|
|
2295
|
+
type: "button",
|
|
2296
|
+
onClick: () => onFollowUp?.(question),
|
|
2297
|
+
className: "group inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1 text-left text-xs text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2298
|
+
children: [
|
|
2299
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: question }),
|
|
2300
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
2301
|
+
]
|
|
2302
|
+
},
|
|
2303
|
+
question
|
|
2304
|
+
)) })
|
|
2305
|
+
] }) : null
|
|
2189
2306
|
] })
|
|
2190
2307
|
]
|
|
2191
2308
|
}
|
|
@@ -2259,6 +2376,9 @@ function PromptCarousel({
|
|
|
2259
2376
|
"div",
|
|
2260
2377
|
{
|
|
2261
2378
|
className: "flex min-w-0 items-center gap-1.5",
|
|
2379
|
+
role: "group",
|
|
2380
|
+
"aria-roledescription": "carousel",
|
|
2381
|
+
"aria-label": "Example questions",
|
|
2262
2382
|
onMouseEnter: () => setPaused(true),
|
|
2263
2383
|
onMouseLeave: () => setPaused(false),
|
|
2264
2384
|
onFocusCapture: () => setPaused(true),
|
|
@@ -2281,6 +2401,8 @@ function PromptCarousel({
|
|
|
2281
2401
|
"data-chip-kind": "prompt",
|
|
2282
2402
|
type: "button",
|
|
2283
2403
|
disabled,
|
|
2404
|
+
"aria-label": `Ask: ${current}`,
|
|
2405
|
+
"aria-live": paused ? "polite" : "off",
|
|
2284
2406
|
onClick: () => onPrompt(current),
|
|
2285
2407
|
className: "boff-explore-fade group flex min-w-0 flex-1 items-center gap-2 rounded-full border border-border bg-card px-4 py-2 text-left text-sm text-card-foreground shadow-sm transition-colors hover:border-primary/50 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2286
2408
|
children: [
|
|
@@ -2315,72 +2437,108 @@ function ProductStrip({
|
|
|
2315
2437
|
"shrink-0 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2316
2438
|
active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
2317
2439
|
);
|
|
2318
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2440
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2441
|
+
"div",
|
|
2442
|
+
{
|
|
2443
|
+
className: "flex min-w-0 items-center gap-2",
|
|
2444
|
+
role: "group",
|
|
2445
|
+
"aria-label": "Focus the assistant on one product",
|
|
2446
|
+
children: [
|
|
2447
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2448
|
+
"div",
|
|
2449
|
+
{
|
|
2450
|
+
className: cn(
|
|
2451
|
+
"boff-explore-strip flex min-w-0 flex-1 gap-2",
|
|
2452
|
+
expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
|
|
2453
|
+
),
|
|
2454
|
+
children: [
|
|
2455
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2456
|
+
"button",
|
|
2457
|
+
{
|
|
2458
|
+
"data-boff-explore": "chip",
|
|
2459
|
+
"data-chip-kind": "product",
|
|
2460
|
+
"data-product": "all",
|
|
2461
|
+
type: "button",
|
|
2462
|
+
"aria-pressed": focusProduct === null,
|
|
2463
|
+
onClick: () => onFocus(null),
|
|
2464
|
+
className: chipClass(focusProduct === null),
|
|
2465
|
+
children: "All products"
|
|
2466
|
+
}
|
|
2467
|
+
),
|
|
2468
|
+
products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2469
|
+
"button",
|
|
2470
|
+
{
|
|
2471
|
+
"data-boff-explore": "chip",
|
|
2472
|
+
"data-chip-kind": "product",
|
|
2473
|
+
"data-product": product.slug,
|
|
2474
|
+
type: "button",
|
|
2475
|
+
"aria-pressed": focusProduct === product.slug,
|
|
2476
|
+
title: product.tagline ?? product.name,
|
|
2477
|
+
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2478
|
+
className: chipClass(focusProduct === product.slug),
|
|
2479
|
+
children: product.name
|
|
2480
|
+
},
|
|
2481
|
+
product.slug
|
|
2482
|
+
))
|
|
2483
|
+
]
|
|
2484
|
+
}
|
|
2325
2485
|
),
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2341
|
-
"button",
|
|
2342
|
-
{
|
|
2343
|
-
"data-boff-explore": "chip",
|
|
2344
|
-
"data-chip-kind": "product",
|
|
2345
|
-
"data-product": product.slug,
|
|
2346
|
-
type: "button",
|
|
2347
|
-
"aria-pressed": focusProduct === product.slug,
|
|
2348
|
-
title: product.tagline ?? product.name,
|
|
2349
|
-
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2350
|
-
className: chipClass(focusProduct === product.slug),
|
|
2351
|
-
children: product.name
|
|
2352
|
-
},
|
|
2353
|
-
product.slug
|
|
2354
|
-
))
|
|
2355
|
-
]
|
|
2356
|
-
}
|
|
2357
|
-
),
|
|
2358
|
-
products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2359
|
-
"button",
|
|
2360
|
-
{
|
|
2361
|
-
type: "button",
|
|
2362
|
-
"data-boff-explore": "products-toggle",
|
|
2363
|
-
onClick: () => setExpanded((v) => !v),
|
|
2364
|
-
className: "shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2365
|
-
children: expanded ? "Show less" : `All ${products.length}`
|
|
2366
|
-
}
|
|
2367
|
-
) : null
|
|
2368
|
-
] });
|
|
2486
|
+
products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2487
|
+
"button",
|
|
2488
|
+
{
|
|
2489
|
+
type: "button",
|
|
2490
|
+
"data-boff-explore": "products-toggle",
|
|
2491
|
+
"aria-expanded": expanded,
|
|
2492
|
+
onClick: () => setExpanded((v) => !v),
|
|
2493
|
+
className: "shrink-0 whitespace-nowrap rounded-full px-2 py-1 text-xs font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
2494
|
+
children: expanded ? "Show less" : `All ${products.length}`
|
|
2495
|
+
}
|
|
2496
|
+
) : null
|
|
2497
|
+
]
|
|
2498
|
+
}
|
|
2499
|
+
);
|
|
2369
2500
|
}
|
|
2370
2501
|
function DisclaimerDialog({
|
|
2371
2502
|
open,
|
|
2372
2503
|
onClose,
|
|
2373
2504
|
captchaOn
|
|
2374
2505
|
}) {
|
|
2506
|
+
const panelRef = React.useRef(null);
|
|
2375
2507
|
const closeRef = React.useRef(null);
|
|
2508
|
+
const titleId = "boff-explore-disclaimer-title";
|
|
2376
2509
|
React.useEffect(() => {
|
|
2377
2510
|
if (!open) return;
|
|
2511
|
+
const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
2512
|
+
const focusable = () => Array.from(
|
|
2513
|
+
panelRef.current?.querySelectorAll(
|
|
2514
|
+
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
|
|
2515
|
+
) ?? []
|
|
2516
|
+
);
|
|
2378
2517
|
const onKey = (event) => {
|
|
2379
|
-
if (event.key === "Escape")
|
|
2518
|
+
if (event.key === "Escape") {
|
|
2519
|
+
onClose();
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
if (event.key !== "Tab") return;
|
|
2523
|
+
const items = focusable();
|
|
2524
|
+
if (items.length === 0) return;
|
|
2525
|
+
const first = items[0];
|
|
2526
|
+
const last = items[items.length - 1];
|
|
2527
|
+
const active = document.activeElement;
|
|
2528
|
+
if (event.shiftKey && (active === first || !panelRef.current?.contains(active))) {
|
|
2529
|
+
event.preventDefault();
|
|
2530
|
+
last?.focus();
|
|
2531
|
+
} else if (!event.shiftKey && active === last) {
|
|
2532
|
+
event.preventDefault();
|
|
2533
|
+
first?.focus();
|
|
2534
|
+
}
|
|
2380
2535
|
};
|
|
2381
2536
|
document.addEventListener("keydown", onKey);
|
|
2382
2537
|
closeRef.current?.focus();
|
|
2383
|
-
return () =>
|
|
2538
|
+
return () => {
|
|
2539
|
+
document.removeEventListener("keydown", onKey);
|
|
2540
|
+
opener?.focus();
|
|
2541
|
+
};
|
|
2384
2542
|
}, [open, onClose]);
|
|
2385
2543
|
if (!open) return null;
|
|
2386
2544
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2389,19 +2547,34 @@ function DisclaimerDialog({
|
|
|
2389
2547
|
"data-boff-explore": "disclaimer-dialog",
|
|
2390
2548
|
role: "dialog",
|
|
2391
2549
|
"aria-modal": "true",
|
|
2392
|
-
"aria-
|
|
2550
|
+
"aria-labelledby": titleId,
|
|
2393
2551
|
className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
|
|
2394
2552
|
onClick: onClose,
|
|
2395
2553
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2396
2554
|
"div",
|
|
2397
2555
|
{
|
|
2556
|
+
ref: panelRef,
|
|
2398
2557
|
className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
|
|
2399
2558
|
onClick: (event) => event.stopPropagation(),
|
|
2400
2559
|
children: [
|
|
2401
2560
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
|
|
2402
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2562
|
+
"span",
|
|
2563
|
+
{
|
|
2564
|
+
"aria-hidden": "true",
|
|
2565
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",
|
|
2566
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-4 w-4" })
|
|
2567
|
+
}
|
|
2568
|
+
),
|
|
2403
2569
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
2404
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2570
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2571
|
+
"p",
|
|
2572
|
+
{
|
|
2573
|
+
id: titleId,
|
|
2574
|
+
className: "text-sm font-semibold text-card-foreground",
|
|
2575
|
+
children: "How this assistant works"
|
|
2576
|
+
}
|
|
2577
|
+
),
|
|
2405
2578
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
|
|
2406
2579
|
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
|
|
2407
2580
|
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Conversations are saved in this browser so you can come back to them, and are also stored on our servers to help us improve these answers. Please don't share personal or confidential information." }),
|
|
@@ -2513,7 +2686,9 @@ function ExplorePage({
|
|
|
2513
2686
|
history,
|
|
2514
2687
|
openConversation,
|
|
2515
2688
|
deleteConversation,
|
|
2516
|
-
clearHistory
|
|
2689
|
+
clearHistory,
|
|
2690
|
+
recordClick,
|
|
2691
|
+
createShareLink
|
|
2517
2692
|
} = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
|
|
2518
2693
|
const [draft, setDraft] = React.useState("");
|
|
2519
2694
|
const textareaRef = React.useRef(null);
|
|
@@ -2533,6 +2708,7 @@ function ExplorePage({
|
|
|
2533
2708
|
});
|
|
2534
2709
|
speechStopRef.current = speech.stop;
|
|
2535
2710
|
const [disclaimerOpen, setDisclaimerOpen] = React.useState(false);
|
|
2711
|
+
const [shareLabel, setShareLabel] = React.useState("Share");
|
|
2536
2712
|
const scrollRef = React.useRef(null);
|
|
2537
2713
|
const latestAssistantRef = React.useRef(null);
|
|
2538
2714
|
const alignedForRef = React.useRef(null);
|
|
@@ -2587,6 +2763,25 @@ function ExplorePage({
|
|
|
2587
2763
|
if (!el) return;
|
|
2588
2764
|
el.scrollTop = el.scrollHeight;
|
|
2589
2765
|
}, [activity, latestAssistantId, messages]);
|
|
2766
|
+
const handleShare = React.useCallback(async () => {
|
|
2767
|
+
setShareLabel("Copying\u2026");
|
|
2768
|
+
const token = await createShareLink();
|
|
2769
|
+
if (!token) {
|
|
2770
|
+
setShareLabel("Unavailable");
|
|
2771
|
+
setTimeout(() => setShareLabel("Share"), 2500);
|
|
2772
|
+
return;
|
|
2773
|
+
}
|
|
2774
|
+
const base = (pageUrl ?? window.location.href).split("?")[0];
|
|
2775
|
+
const url = `${base}?c=${encodeURIComponent(token)}`;
|
|
2776
|
+
try {
|
|
2777
|
+
await navigator.clipboard.writeText(url);
|
|
2778
|
+
setShareLabel("Copied");
|
|
2779
|
+
} catch {
|
|
2780
|
+
window.prompt("Copy this link", url);
|
|
2781
|
+
setShareLabel("Share");
|
|
2782
|
+
}
|
|
2783
|
+
setTimeout(() => setShareLabel("Share"), 2500);
|
|
2784
|
+
}, [createShareLink, pageUrl]);
|
|
2590
2785
|
const submitDraft = React.useCallback(() => {
|
|
2591
2786
|
const text = draft.trim();
|
|
2592
2787
|
if (!text || overLimit || busy || !canSend) return;
|
|
@@ -2669,6 +2864,24 @@ function ExplorePage({
|
|
|
2669
2864
|
]
|
|
2670
2865
|
}
|
|
2671
2866
|
),
|
|
2867
|
+
messages.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2868
|
+
Button,
|
|
2869
|
+
{
|
|
2870
|
+
"data-boff-explore": "share",
|
|
2871
|
+
type: "button",
|
|
2872
|
+
size: "sm",
|
|
2873
|
+
variant: "ghost",
|
|
2874
|
+
className: "shrink-0 text-muted-foreground",
|
|
2875
|
+
title: "Copy a read-only link to this conversation",
|
|
2876
|
+
onClick: () => {
|
|
2877
|
+
void handleShare();
|
|
2878
|
+
},
|
|
2879
|
+
children: [
|
|
2880
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: "h-3.5 w-3.5" }),
|
|
2881
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: shareLabel })
|
|
2882
|
+
]
|
|
2883
|
+
}
|
|
2884
|
+
) : null,
|
|
2672
2885
|
history.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2673
2886
|
Button,
|
|
2674
2887
|
{
|
|
@@ -2787,7 +3000,9 @@ function ExplorePage({
|
|
|
2787
3000
|
message,
|
|
2788
3001
|
activity,
|
|
2789
3002
|
onNavigate,
|
|
2790
|
-
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
|
|
3003
|
+
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
|
|
3004
|
+
onFollow: (kind, url) => recordClick(message.id, kind, url),
|
|
3005
|
+
onFollowUp: sendPrompt
|
|
2791
3006
|
},
|
|
2792
3007
|
message.id
|
|
2793
3008
|
)
|