@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, useMemo, useState, useRef, useCallback, useEffect, useContext } from 'react';
|
|
3
|
-
import { Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers,
|
|
3
|
+
import { Sparkles, RotateCcw, Link2, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, ExternalLink } from 'lucide-react';
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
5
|
import rehypeSanitize from 'rehype-sanitize';
|
|
6
6
|
import remarkGfm from 'remark-gfm';
|
|
@@ -463,6 +463,7 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
463
463
|
description
|
|
464
464
|
product
|
|
465
465
|
imageUrl
|
|
466
|
+
index
|
|
466
467
|
}
|
|
467
468
|
ctas {
|
|
468
469
|
kind
|
|
@@ -470,6 +471,8 @@ var EXPLORE_MESSAGE_FIELDS = (
|
|
|
470
471
|
url
|
|
471
472
|
product
|
|
472
473
|
}
|
|
474
|
+
followUps
|
|
475
|
+
answered
|
|
473
476
|
errorCode
|
|
474
477
|
createdAt
|
|
475
478
|
completedAt
|
|
@@ -535,6 +538,26 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
|
|
|
535
538
|
}
|
|
536
539
|
`
|
|
537
540
|
);
|
|
541
|
+
var RECORD_EXPLORE_CLICK_MUTATION = (
|
|
542
|
+
/* GraphQL */
|
|
543
|
+
`
|
|
544
|
+
mutation RecordExploreClick($input: RecordExploreClickInput!) {
|
|
545
|
+
recordExploreClick(input: $input) {
|
|
546
|
+
recorded
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
`
|
|
550
|
+
);
|
|
551
|
+
var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
|
|
552
|
+
/* GraphQL */
|
|
553
|
+
`
|
|
554
|
+
mutation CreateExploreShareLink($conversationToken: String!) {
|
|
555
|
+
createExploreShareLink(conversationToken: $conversationToken) {
|
|
556
|
+
shareToken
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
`
|
|
560
|
+
);
|
|
538
561
|
|
|
539
562
|
// src/data/products.ts
|
|
540
563
|
var ECOSYSTEM_PRODUCTS = [
|
|
@@ -1467,6 +1490,30 @@ function useExploreChat(options = {}) {
|
|
|
1467
1490
|
return null;
|
|
1468
1491
|
}, [messages]);
|
|
1469
1492
|
const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
|
|
1493
|
+
const createShareLink = useCallback(async () => {
|
|
1494
|
+
const token = conversationTokenRef.current;
|
|
1495
|
+
if (!token) return null;
|
|
1496
|
+
try {
|
|
1497
|
+
const result = await client.mutate(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });
|
|
1498
|
+
return result?.data?.createExploreShareLink?.shareToken ?? null;
|
|
1499
|
+
} catch {
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
}, [client]);
|
|
1503
|
+
const recordClick = useCallback(
|
|
1504
|
+
(messageId, kind, url) => {
|
|
1505
|
+
const token = conversationTokenRef.current;
|
|
1506
|
+
if (!token) return;
|
|
1507
|
+
try {
|
|
1508
|
+
void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
|
|
1509
|
+
input: { conversationToken: token, messageId, kind, url }
|
|
1510
|
+
}).catch(() => {
|
|
1511
|
+
});
|
|
1512
|
+
} catch {
|
|
1513
|
+
}
|
|
1514
|
+
},
|
|
1515
|
+
[client]
|
|
1516
|
+
);
|
|
1470
1517
|
return {
|
|
1471
1518
|
phase,
|
|
1472
1519
|
catalog,
|
|
@@ -1484,7 +1531,9 @@ function useExploreChat(options = {}) {
|
|
|
1484
1531
|
history: archive,
|
|
1485
1532
|
openConversation,
|
|
1486
1533
|
deleteConversation,
|
|
1487
|
-
clearHistory
|
|
1534
|
+
clearHistory,
|
|
1535
|
+
recordClick,
|
|
1536
|
+
createShareLink
|
|
1488
1537
|
};
|
|
1489
1538
|
}
|
|
1490
1539
|
var optimisticCounter = 0;
|
|
@@ -1981,7 +2030,10 @@ function logoUrlOf(url) {
|
|
|
1981
2030
|
return null;
|
|
1982
2031
|
}
|
|
1983
2032
|
}
|
|
1984
|
-
function ReferenceCard({
|
|
2033
|
+
function ReferenceCard({
|
|
2034
|
+
reference,
|
|
2035
|
+
onFollow
|
|
2036
|
+
}) {
|
|
1985
2037
|
const [imageFailed, setImageFailed] = useState(false);
|
|
1986
2038
|
const [logoFailed, setLogoFailed] = useState(false);
|
|
1987
2039
|
const host = hostnameOf(reference.url);
|
|
@@ -2003,9 +2055,11 @@ function ReferenceCard({ reference }) {
|
|
|
2003
2055
|
"a",
|
|
2004
2056
|
{
|
|
2005
2057
|
"data-boff-explore": "reference",
|
|
2058
|
+
"data-index": reference.index ?? void 0,
|
|
2006
2059
|
href: reference.url,
|
|
2007
2060
|
target: "_blank",
|
|
2008
2061
|
rel: "noopener noreferrer",
|
|
2062
|
+
onClick: () => onFollow?.(reference.url),
|
|
2009
2063
|
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",
|
|
2010
2064
|
children: [
|
|
2011
2065
|
/* @__PURE__ */ jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
|
|
@@ -2029,7 +2083,10 @@ function ReferenceCard({ reference }) {
|
|
|
2029
2083
|
}
|
|
2030
2084
|
) }) : letterPlate }),
|
|
2031
2085
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
|
|
2032
|
-
/* @__PURE__ */
|
|
2086
|
+
/* @__PURE__ */ jsxs("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: [
|
|
2087
|
+
reference.index ? /* @__PURE__ */ 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,
|
|
2088
|
+
reference.title || host || reference.url
|
|
2089
|
+
] }),
|
|
2033
2090
|
reference.description ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
|
|
2034
2091
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
|
|
2035
2092
|
reference.product ? /* @__PURE__ */ 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,
|
|
@@ -2045,7 +2102,8 @@ function ReferenceCard({ reference }) {
|
|
|
2045
2102
|
}
|
|
2046
2103
|
function CtaButton({
|
|
2047
2104
|
cta,
|
|
2048
|
-
onNavigate
|
|
2105
|
+
onNavigate,
|
|
2106
|
+
onFollow
|
|
2049
2107
|
}) {
|
|
2050
2108
|
const variant = CTA_VARIANTS[cta.kind] ?? "outline";
|
|
2051
2109
|
const internal = isInternalPath(cta.url);
|
|
@@ -2058,7 +2116,10 @@ function CtaButton({
|
|
|
2058
2116
|
type: "button",
|
|
2059
2117
|
size: "sm",
|
|
2060
2118
|
variant,
|
|
2061
|
-
onClick: () =>
|
|
2119
|
+
onClick: () => {
|
|
2120
|
+
onFollow?.(cta.url);
|
|
2121
|
+
onNavigate(cta.url);
|
|
2122
|
+
},
|
|
2062
2123
|
children: cta.label
|
|
2063
2124
|
}
|
|
2064
2125
|
);
|
|
@@ -2069,6 +2130,7 @@ function CtaButton({
|
|
|
2069
2130
|
"data-boff-explore": "cta",
|
|
2070
2131
|
"data-kind": cta.kind,
|
|
2071
2132
|
href: cta.url,
|
|
2133
|
+
onClick: () => onFollow?.(cta.url),
|
|
2072
2134
|
...internal ? {} : { target: "_blank", rel: "noopener noreferrer" },
|
|
2073
2135
|
children: [
|
|
2074
2136
|
cta.label,
|
|
@@ -2120,7 +2182,9 @@ function AssistantBubble({
|
|
|
2120
2182
|
message,
|
|
2121
2183
|
activity,
|
|
2122
2184
|
onNavigate,
|
|
2123
|
-
anchorRef
|
|
2185
|
+
anchorRef,
|
|
2186
|
+
onFollow,
|
|
2187
|
+
onFollowUp
|
|
2124
2188
|
}) {
|
|
2125
2189
|
const streaming = message.status === "PENDING" || message.status === "RUNNING";
|
|
2126
2190
|
const body = message.content || message.partialContent || "";
|
|
@@ -2142,6 +2206,34 @@ function AssistantBubble({
|
|
|
2142
2206
|
}
|
|
2143
2207
|
),
|
|
2144
2208
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
|
|
2209
|
+
message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxs(
|
|
2210
|
+
"div",
|
|
2211
|
+
{
|
|
2212
|
+
"data-boff-explore": "no-answer",
|
|
2213
|
+
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",
|
|
2214
|
+
children: [
|
|
2215
|
+
/* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
|
|
2216
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2217
|
+
"I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
|
|
2218
|
+
" ",
|
|
2219
|
+
/* @__PURE__ */ jsx(
|
|
2220
|
+
"a",
|
|
2221
|
+
{
|
|
2222
|
+
href: "/contact",
|
|
2223
|
+
className: "underline underline-offset-2 hover:text-primary",
|
|
2224
|
+
onClick: (event) => {
|
|
2225
|
+
if (!onNavigate) return;
|
|
2226
|
+
event.preventDefault();
|
|
2227
|
+
onNavigate("/contact");
|
|
2228
|
+
},
|
|
2229
|
+
children: "ask a human"
|
|
2230
|
+
}
|
|
2231
|
+
),
|
|
2232
|
+
"."
|
|
2233
|
+
] })
|
|
2234
|
+
]
|
|
2235
|
+
}
|
|
2236
|
+
) : null,
|
|
2145
2237
|
body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
2146
2238
|
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
|
|
2147
2239
|
streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
@@ -2150,16 +2242,41 @@ function AssistantBubble({
|
|
|
2150
2242
|
failed && !body ? /* @__PURE__ */ 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,
|
|
2151
2243
|
message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
|
2152
2244
|
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
|
|
2153
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsx(
|
|
2245
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: message.references.map((reference) => /* @__PURE__ */ jsx(
|
|
2246
|
+
ReferenceCard,
|
|
2247
|
+
{
|
|
2248
|
+
reference,
|
|
2249
|
+
onFollow: (url) => onFollow?.("REFERENCE", url)
|
|
2250
|
+
},
|
|
2251
|
+
reference.url
|
|
2252
|
+
)) })
|
|
2154
2253
|
] }) : null,
|
|
2155
2254
|
message.ctas.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 pt-0.5", children: message.ctas.map((cta) => /* @__PURE__ */ jsx(
|
|
2156
2255
|
CtaButton,
|
|
2157
2256
|
{
|
|
2158
2257
|
cta,
|
|
2159
|
-
onNavigate
|
|
2258
|
+
onNavigate,
|
|
2259
|
+
onFollow: (url) => onFollow?.("CTA", url)
|
|
2160
2260
|
},
|
|
2161
2261
|
`${cta.kind}-${cta.url}`
|
|
2162
|
-
)) }) : null
|
|
2262
|
+
)) }) : null,
|
|
2263
|
+
message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
|
|
2264
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
|
|
2265
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxs(
|
|
2266
|
+
"button",
|
|
2267
|
+
{
|
|
2268
|
+
"data-boff-explore": "follow-up",
|
|
2269
|
+
type: "button",
|
|
2270
|
+
onClick: () => onFollowUp?.(question),
|
|
2271
|
+
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",
|
|
2272
|
+
children: [
|
|
2273
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: question }),
|
|
2274
|
+
/* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
2275
|
+
]
|
|
2276
|
+
},
|
|
2277
|
+
question
|
|
2278
|
+
)) })
|
|
2279
|
+
] }) : null
|
|
2163
2280
|
] })
|
|
2164
2281
|
]
|
|
2165
2282
|
}
|
|
@@ -2233,6 +2350,9 @@ function PromptCarousel({
|
|
|
2233
2350
|
"div",
|
|
2234
2351
|
{
|
|
2235
2352
|
className: "flex min-w-0 items-center gap-1.5",
|
|
2353
|
+
role: "group",
|
|
2354
|
+
"aria-roledescription": "carousel",
|
|
2355
|
+
"aria-label": "Example questions",
|
|
2236
2356
|
onMouseEnter: () => setPaused(true),
|
|
2237
2357
|
onMouseLeave: () => setPaused(false),
|
|
2238
2358
|
onFocusCapture: () => setPaused(true),
|
|
@@ -2255,6 +2375,8 @@ function PromptCarousel({
|
|
|
2255
2375
|
"data-chip-kind": "prompt",
|
|
2256
2376
|
type: "button",
|
|
2257
2377
|
disabled,
|
|
2378
|
+
"aria-label": `Ask: ${current}`,
|
|
2379
|
+
"aria-live": paused ? "polite" : "off",
|
|
2258
2380
|
onClick: () => onPrompt(current),
|
|
2259
2381
|
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",
|
|
2260
2382
|
children: [
|
|
@@ -2289,72 +2411,108 @@ function ProductStrip({
|
|
|
2289
2411
|
"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",
|
|
2290
2412
|
active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
2291
2413
|
);
|
|
2292
|
-
return /* @__PURE__ */ jsxs(
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2414
|
+
return /* @__PURE__ */ jsxs(
|
|
2415
|
+
"div",
|
|
2416
|
+
{
|
|
2417
|
+
className: "flex min-w-0 items-center gap-2",
|
|
2418
|
+
role: "group",
|
|
2419
|
+
"aria-label": "Focus the assistant on one product",
|
|
2420
|
+
children: [
|
|
2421
|
+
/* @__PURE__ */ jsxs(
|
|
2422
|
+
"div",
|
|
2423
|
+
{
|
|
2424
|
+
className: cn(
|
|
2425
|
+
"boff-explore-strip flex min-w-0 flex-1 gap-2",
|
|
2426
|
+
expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
|
|
2427
|
+
),
|
|
2428
|
+
children: [
|
|
2429
|
+
/* @__PURE__ */ jsx(
|
|
2430
|
+
"button",
|
|
2431
|
+
{
|
|
2432
|
+
"data-boff-explore": "chip",
|
|
2433
|
+
"data-chip-kind": "product",
|
|
2434
|
+
"data-product": "all",
|
|
2435
|
+
type: "button",
|
|
2436
|
+
"aria-pressed": focusProduct === null,
|
|
2437
|
+
onClick: () => onFocus(null),
|
|
2438
|
+
className: chipClass(focusProduct === null),
|
|
2439
|
+
children: "All products"
|
|
2440
|
+
}
|
|
2441
|
+
),
|
|
2442
|
+
products.map((product) => /* @__PURE__ */ jsx(
|
|
2443
|
+
"button",
|
|
2444
|
+
{
|
|
2445
|
+
"data-boff-explore": "chip",
|
|
2446
|
+
"data-chip-kind": "product",
|
|
2447
|
+
"data-product": product.slug,
|
|
2448
|
+
type: "button",
|
|
2449
|
+
"aria-pressed": focusProduct === product.slug,
|
|
2450
|
+
title: product.tagline ?? product.name,
|
|
2451
|
+
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2452
|
+
className: chipClass(focusProduct === product.slug),
|
|
2453
|
+
children: product.name
|
|
2454
|
+
},
|
|
2455
|
+
product.slug
|
|
2456
|
+
))
|
|
2457
|
+
]
|
|
2458
|
+
}
|
|
2299
2459
|
),
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
products.map((product) => /* @__PURE__ */ jsx(
|
|
2315
|
-
"button",
|
|
2316
|
-
{
|
|
2317
|
-
"data-boff-explore": "chip",
|
|
2318
|
-
"data-chip-kind": "product",
|
|
2319
|
-
"data-product": product.slug,
|
|
2320
|
-
type: "button",
|
|
2321
|
-
"aria-pressed": focusProduct === product.slug,
|
|
2322
|
-
title: product.tagline ?? product.name,
|
|
2323
|
-
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
2324
|
-
className: chipClass(focusProduct === product.slug),
|
|
2325
|
-
children: product.name
|
|
2326
|
-
},
|
|
2327
|
-
product.slug
|
|
2328
|
-
))
|
|
2329
|
-
]
|
|
2330
|
-
}
|
|
2331
|
-
),
|
|
2332
|
-
products.length > 0 ? /* @__PURE__ */ jsx(
|
|
2333
|
-
"button",
|
|
2334
|
-
{
|
|
2335
|
-
type: "button",
|
|
2336
|
-
"data-boff-explore": "products-toggle",
|
|
2337
|
-
onClick: () => setExpanded((v) => !v),
|
|
2338
|
-
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",
|
|
2339
|
-
children: expanded ? "Show less" : `All ${products.length}`
|
|
2340
|
-
}
|
|
2341
|
-
) : null
|
|
2342
|
-
] });
|
|
2460
|
+
products.length > 0 ? /* @__PURE__ */ jsx(
|
|
2461
|
+
"button",
|
|
2462
|
+
{
|
|
2463
|
+
type: "button",
|
|
2464
|
+
"data-boff-explore": "products-toggle",
|
|
2465
|
+
"aria-expanded": expanded,
|
|
2466
|
+
onClick: () => setExpanded((v) => !v),
|
|
2467
|
+
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",
|
|
2468
|
+
children: expanded ? "Show less" : `All ${products.length}`
|
|
2469
|
+
}
|
|
2470
|
+
) : null
|
|
2471
|
+
]
|
|
2472
|
+
}
|
|
2473
|
+
);
|
|
2343
2474
|
}
|
|
2344
2475
|
function DisclaimerDialog({
|
|
2345
2476
|
open,
|
|
2346
2477
|
onClose,
|
|
2347
2478
|
captchaOn
|
|
2348
2479
|
}) {
|
|
2480
|
+
const panelRef = useRef(null);
|
|
2349
2481
|
const closeRef = useRef(null);
|
|
2482
|
+
const titleId = "boff-explore-disclaimer-title";
|
|
2350
2483
|
useEffect(() => {
|
|
2351
2484
|
if (!open) return;
|
|
2485
|
+
const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
2486
|
+
const focusable = () => Array.from(
|
|
2487
|
+
panelRef.current?.querySelectorAll(
|
|
2488
|
+
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
|
|
2489
|
+
) ?? []
|
|
2490
|
+
);
|
|
2352
2491
|
const onKey = (event) => {
|
|
2353
|
-
if (event.key === "Escape")
|
|
2492
|
+
if (event.key === "Escape") {
|
|
2493
|
+
onClose();
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
if (event.key !== "Tab") return;
|
|
2497
|
+
const items = focusable();
|
|
2498
|
+
if (items.length === 0) return;
|
|
2499
|
+
const first = items[0];
|
|
2500
|
+
const last = items[items.length - 1];
|
|
2501
|
+
const active = document.activeElement;
|
|
2502
|
+
if (event.shiftKey && (active === first || !panelRef.current?.contains(active))) {
|
|
2503
|
+
event.preventDefault();
|
|
2504
|
+
last?.focus();
|
|
2505
|
+
} else if (!event.shiftKey && active === last) {
|
|
2506
|
+
event.preventDefault();
|
|
2507
|
+
first?.focus();
|
|
2508
|
+
}
|
|
2354
2509
|
};
|
|
2355
2510
|
document.addEventListener("keydown", onKey);
|
|
2356
2511
|
closeRef.current?.focus();
|
|
2357
|
-
return () =>
|
|
2512
|
+
return () => {
|
|
2513
|
+
document.removeEventListener("keydown", onKey);
|
|
2514
|
+
opener?.focus();
|
|
2515
|
+
};
|
|
2358
2516
|
}, [open, onClose]);
|
|
2359
2517
|
if (!open) return null;
|
|
2360
2518
|
return /* @__PURE__ */ jsx(
|
|
@@ -2363,19 +2521,34 @@ function DisclaimerDialog({
|
|
|
2363
2521
|
"data-boff-explore": "disclaimer-dialog",
|
|
2364
2522
|
role: "dialog",
|
|
2365
2523
|
"aria-modal": "true",
|
|
2366
|
-
"aria-
|
|
2524
|
+
"aria-labelledby": titleId,
|
|
2367
2525
|
className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
|
|
2368
2526
|
onClick: onClose,
|
|
2369
2527
|
children: /* @__PURE__ */ jsxs(
|
|
2370
2528
|
"div",
|
|
2371
2529
|
{
|
|
2530
|
+
ref: panelRef,
|
|
2372
2531
|
className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
|
|
2373
2532
|
onClick: (event) => event.stopPropagation(),
|
|
2374
2533
|
children: [
|
|
2375
2534
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
2376
|
-
/* @__PURE__ */ jsx(
|
|
2535
|
+
/* @__PURE__ */ jsx(
|
|
2536
|
+
"span",
|
|
2537
|
+
{
|
|
2538
|
+
"aria-hidden": "true",
|
|
2539
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",
|
|
2540
|
+
children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" })
|
|
2541
|
+
}
|
|
2542
|
+
),
|
|
2377
2543
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
2378
|
-
/* @__PURE__ */ jsx(
|
|
2544
|
+
/* @__PURE__ */ jsx(
|
|
2545
|
+
"p",
|
|
2546
|
+
{
|
|
2547
|
+
id: titleId,
|
|
2548
|
+
className: "text-sm font-semibold text-card-foreground",
|
|
2549
|
+
children: "How this assistant works"
|
|
2550
|
+
}
|
|
2551
|
+
),
|
|
2379
2552
|
/* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
|
|
2380
2553
|
/* @__PURE__ */ jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
|
|
2381
2554
|
/* @__PURE__ */ 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." }),
|
|
@@ -2487,7 +2660,9 @@ function ExplorePage({
|
|
|
2487
2660
|
history,
|
|
2488
2661
|
openConversation,
|
|
2489
2662
|
deleteConversation,
|
|
2490
|
-
clearHistory
|
|
2663
|
+
clearHistory,
|
|
2664
|
+
recordClick,
|
|
2665
|
+
createShareLink
|
|
2491
2666
|
} = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
|
|
2492
2667
|
const [draft, setDraft] = useState("");
|
|
2493
2668
|
const textareaRef = useRef(null);
|
|
@@ -2507,6 +2682,7 @@ function ExplorePage({
|
|
|
2507
2682
|
});
|
|
2508
2683
|
speechStopRef.current = speech.stop;
|
|
2509
2684
|
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
|
2685
|
+
const [shareLabel, setShareLabel] = useState("Share");
|
|
2510
2686
|
const scrollRef = useRef(null);
|
|
2511
2687
|
const latestAssistantRef = useRef(null);
|
|
2512
2688
|
const alignedForRef = useRef(null);
|
|
@@ -2561,6 +2737,25 @@ function ExplorePage({
|
|
|
2561
2737
|
if (!el) return;
|
|
2562
2738
|
el.scrollTop = el.scrollHeight;
|
|
2563
2739
|
}, [activity, latestAssistantId, messages]);
|
|
2740
|
+
const handleShare = useCallback(async () => {
|
|
2741
|
+
setShareLabel("Copying\u2026");
|
|
2742
|
+
const token = await createShareLink();
|
|
2743
|
+
if (!token) {
|
|
2744
|
+
setShareLabel("Unavailable");
|
|
2745
|
+
setTimeout(() => setShareLabel("Share"), 2500);
|
|
2746
|
+
return;
|
|
2747
|
+
}
|
|
2748
|
+
const base = (pageUrl ?? window.location.href).split("?")[0];
|
|
2749
|
+
const url = `${base}?c=${encodeURIComponent(token)}`;
|
|
2750
|
+
try {
|
|
2751
|
+
await navigator.clipboard.writeText(url);
|
|
2752
|
+
setShareLabel("Copied");
|
|
2753
|
+
} catch {
|
|
2754
|
+
window.prompt("Copy this link", url);
|
|
2755
|
+
setShareLabel("Share");
|
|
2756
|
+
}
|
|
2757
|
+
setTimeout(() => setShareLabel("Share"), 2500);
|
|
2758
|
+
}, [createShareLink, pageUrl]);
|
|
2564
2759
|
const submitDraft = useCallback(() => {
|
|
2565
2760
|
const text = draft.trim();
|
|
2566
2761
|
if (!text || overLimit || busy || !canSend) return;
|
|
@@ -2643,6 +2838,24 @@ function ExplorePage({
|
|
|
2643
2838
|
]
|
|
2644
2839
|
}
|
|
2645
2840
|
),
|
|
2841
|
+
messages.length > 0 ? /* @__PURE__ */ jsxs(
|
|
2842
|
+
Button,
|
|
2843
|
+
{
|
|
2844
|
+
"data-boff-explore": "share",
|
|
2845
|
+
type: "button",
|
|
2846
|
+
size: "sm",
|
|
2847
|
+
variant: "ghost",
|
|
2848
|
+
className: "shrink-0 text-muted-foreground",
|
|
2849
|
+
title: "Copy a read-only link to this conversation",
|
|
2850
|
+
onClick: () => {
|
|
2851
|
+
void handleShare();
|
|
2852
|
+
},
|
|
2853
|
+
children: [
|
|
2854
|
+
/* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" }),
|
|
2855
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: shareLabel })
|
|
2856
|
+
]
|
|
2857
|
+
}
|
|
2858
|
+
) : null,
|
|
2646
2859
|
history.length > 0 ? /* @__PURE__ */ jsxs(
|
|
2647
2860
|
Button,
|
|
2648
2861
|
{
|
|
@@ -2761,7 +2974,9 @@ function ExplorePage({
|
|
|
2761
2974
|
message,
|
|
2762
2975
|
activity,
|
|
2763
2976
|
onNavigate,
|
|
2764
|
-
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
|
|
2977
|
+
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
|
|
2978
|
+
onFollow: (kind, url) => recordClick(message.id, kind, url),
|
|
2979
|
+
onFollowUp: sendPrompt
|
|
2765
2980
|
},
|
|
2766
2981
|
message.id
|
|
2767
2982
|
)
|