@burdenoff/website-sdk 2026.828.6 → 2026.829.1
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 +402 -190
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +404 -192
- package/dist/components/explore.mjs.map +1 -1
- package/dist/hooks/index.js +111 -69
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +111 -69
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +402 -190
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +402 -190
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -5963,23 +5963,37 @@ function getRecognitionCtor() {
|
|
|
5963
5963
|
const w = window;
|
|
5964
5964
|
return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;
|
|
5965
5965
|
}
|
|
5966
|
+
function isTouchDevice() {
|
|
5967
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
5968
|
+
try {
|
|
5969
|
+
return window.matchMedia("(pointer: coarse)").matches;
|
|
5970
|
+
} catch {
|
|
5971
|
+
return false;
|
|
5972
|
+
}
|
|
5973
|
+
}
|
|
5966
5974
|
var MIC_DENIED_MESSAGE = "Microphone access was blocked. Allow it in your browser's site settings to dictate.";
|
|
5975
|
+
var MIC_UNAVAILABLE_MESSAGE = "Dictation isn't available in this browser. You can type instead.";
|
|
5976
|
+
var RELEASE_SETTLE_MS = 250;
|
|
5977
|
+
var RETRY_DELAY_MS = 350;
|
|
5978
|
+
var sleep = (ms) => new Promise((resolve) => {
|
|
5979
|
+
setTimeout(resolve, ms);
|
|
5980
|
+
});
|
|
5967
5981
|
async function ensureMicrophoneAccess() {
|
|
5968
5982
|
const media = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
5969
|
-
if (!media?.getUserMedia)
|
|
5983
|
+
if (!media?.getUserMedia)
|
|
5984
|
+
return { ok: true, confirmed: false, primed: false };
|
|
5970
5985
|
try {
|
|
5971
5986
|
const status = await navigator.permissions?.query({
|
|
5972
5987
|
name: "microphone"
|
|
5973
5988
|
});
|
|
5974
|
-
if (status?.state === "granted")
|
|
5975
|
-
|
|
5976
|
-
return { ok: false, message: MIC_DENIED_MESSAGE };
|
|
5989
|
+
if (status?.state === "granted")
|
|
5990
|
+
return { ok: true, confirmed: true, primed: false };
|
|
5977
5991
|
} catch {
|
|
5978
5992
|
}
|
|
5979
5993
|
try {
|
|
5980
5994
|
const stream = await media.getUserMedia({ audio: true });
|
|
5981
5995
|
for (const track of stream.getTracks()) track.stop();
|
|
5982
|
-
return { ok: true };
|
|
5996
|
+
return { ok: true, confirmed: true, primed: true };
|
|
5983
5997
|
} catch (error) {
|
|
5984
5998
|
const name = typeof error === "object" && error !== null && "name" in error ? String(error.name) : "";
|
|
5985
5999
|
if (name === "NotAllowedError" || name === "SecurityError") {
|
|
@@ -6022,19 +6036,18 @@ function useSpeechInput({
|
|
|
6022
6036
|
const [error, setError] = useState(null);
|
|
6023
6037
|
const recognitionRef = useRef(null);
|
|
6024
6038
|
const startTokenRef = useRef(0);
|
|
6025
|
-
const
|
|
6026
|
-
const
|
|
6027
|
-
|
|
6028
|
-
beginRecognitionRef.current?.(Ctor, token);
|
|
6029
|
-
},
|
|
6030
|
-
[]
|
|
6031
|
-
);
|
|
6039
|
+
const micConfirmedRef = useRef(false);
|
|
6040
|
+
const wantsListeningRef = useRef(false);
|
|
6041
|
+
const retriedRef = useRef(false);
|
|
6032
6042
|
const finalRef = useRef(onFinalTranscript);
|
|
6033
6043
|
const errorRef = useRef(onError);
|
|
6034
6044
|
finalRef.current = onFinalTranscript;
|
|
6035
6045
|
errorRef.current = onError;
|
|
6046
|
+
const langRef = useRef(lang);
|
|
6047
|
+
langRef.current = lang;
|
|
6036
6048
|
const stop = useCallback(() => {
|
|
6037
6049
|
startTokenRef.current += 1;
|
|
6050
|
+
wantsListeningRef.current = false;
|
|
6038
6051
|
setListening(false);
|
|
6039
6052
|
setInterim("");
|
|
6040
6053
|
const recognition = recognitionRef.current;
|
|
@@ -6043,82 +6056,111 @@ function useSpeechInput({
|
|
|
6043
6056
|
recognition.stop();
|
|
6044
6057
|
} catch {
|
|
6045
6058
|
}
|
|
6046
|
-
setListening(false);
|
|
6047
|
-
setInterim("");
|
|
6048
6059
|
}, []);
|
|
6049
|
-
const
|
|
6060
|
+
const openSession = useCallback((token) => {
|
|
6050
6061
|
const Ctor = getRecognitionCtor();
|
|
6051
|
-
if (!Ctor) return;
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6062
|
+
if (!Ctor || token !== startTokenRef.current) return;
|
|
6063
|
+
const recognition = new Ctor();
|
|
6064
|
+
recognition.lang = langRef.current ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
6065
|
+
recognition.continuous = !isTouchDevice();
|
|
6066
|
+
recognition.interimResults = true;
|
|
6067
|
+
recognition.maxAlternatives = 1;
|
|
6068
|
+
recognition.onstart = () => {
|
|
6069
|
+
if (token !== startTokenRef.current) return;
|
|
6070
|
+
setError(null);
|
|
6071
|
+
setListening(true);
|
|
6072
|
+
};
|
|
6073
|
+
recognition.onresult = (event) => {
|
|
6074
|
+
if (token !== startTokenRef.current) return;
|
|
6075
|
+
let settled = "";
|
|
6076
|
+
let pending = "";
|
|
6077
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
6078
|
+
const result = event.results[i];
|
|
6079
|
+
if (!result) continue;
|
|
6080
|
+
const text = result[0]?.transcript ?? "";
|
|
6081
|
+
if (result.isFinal) settled += text;
|
|
6082
|
+
else pending += text;
|
|
6083
|
+
}
|
|
6084
|
+
setInterim(pending);
|
|
6085
|
+
if (settled.trim() !== "") finalRef.current(settled);
|
|
6086
|
+
};
|
|
6087
|
+
recognition.onerror = (event) => {
|
|
6088
|
+
if (token !== startTokenRef.current) return;
|
|
6089
|
+
if ((event.error === "not-allowed" || event.error === "service-not-allowed") && micConfirmedRef.current && !retriedRef.current) {
|
|
6090
|
+
retriedRef.current = true;
|
|
6091
|
+
void sleep(RETRY_DELAY_MS).then(() => {
|
|
6092
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
6093
|
+
return;
|
|
6094
|
+
openSessionRef.current?.(token);
|
|
6095
|
+
});
|
|
6096
|
+
return;
|
|
6097
|
+
}
|
|
6098
|
+
const message = micConfirmedRef.current && (event.error === "not-allowed" || event.error === "service-not-allowed") ? MIC_UNAVAILABLE_MESSAGE : describeError(event.error);
|
|
6099
|
+
wantsListeningRef.current = false;
|
|
6100
|
+
setListening(false);
|
|
6101
|
+
setInterim("");
|
|
6102
|
+
if (message !== "") {
|
|
6103
|
+
setError(message);
|
|
6104
|
+
errorRef.current?.(message);
|
|
6105
|
+
}
|
|
6106
|
+
};
|
|
6107
|
+
recognition.onend = () => {
|
|
6108
|
+
if (token !== startTokenRef.current) return;
|
|
6109
|
+
setInterim("");
|
|
6110
|
+
if (wantsListeningRef.current && isTouchDevice()) {
|
|
6111
|
+
void sleep(120).then(() => {
|
|
6112
|
+
if (token !== startTokenRef.current || !wantsListeningRef.current)
|
|
6113
|
+
return;
|
|
6114
|
+
openSessionRef.current?.(token);
|
|
6115
|
+
});
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6118
|
+
setListening(false);
|
|
6119
|
+
};
|
|
6120
|
+
recognitionRef.current = recognition;
|
|
6121
|
+
try {
|
|
6122
|
+
recognition.start();
|
|
6123
|
+
} catch {
|
|
6124
|
+
wantsListeningRef.current = false;
|
|
6125
|
+
setListening(false);
|
|
6126
|
+
}
|
|
6127
|
+
}, []);
|
|
6128
|
+
const openSessionRef = useRef(null);
|
|
6129
|
+
openSessionRef.current = openSession;
|
|
6130
|
+
const start = useCallback(() => {
|
|
6131
|
+
if (!getRecognitionCtor()) return;
|
|
6055
6132
|
startTokenRef.current += 1;
|
|
6056
6133
|
const token = startTokenRef.current;
|
|
6057
|
-
|
|
6134
|
+
wantsListeningRef.current = true;
|
|
6135
|
+
retriedRef.current = false;
|
|
6136
|
+
micConfirmedRef.current = false;
|
|
6137
|
+
setError(null);
|
|
6138
|
+
setListening(true);
|
|
6139
|
+
void ensureMicrophoneAccess().then(async (access) => {
|
|
6058
6140
|
if (token !== startTokenRef.current) return;
|
|
6059
6141
|
if (!access.ok) {
|
|
6142
|
+
wantsListeningRef.current = false;
|
|
6060
6143
|
setListening(false);
|
|
6061
6144
|
setError(access.message);
|
|
6062
6145
|
errorRef.current?.(access.message);
|
|
6063
6146
|
return;
|
|
6064
6147
|
}
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
const beginRecognitionImpl = useCallback(
|
|
6069
|
-
(Ctor, token) => {
|
|
6070
|
-
const recognition = new Ctor();
|
|
6071
|
-
recognition.lang = lang ?? (typeof navigator === "undefined" ? "en-US" : navigator.language || "en-US");
|
|
6072
|
-
recognition.continuous = true;
|
|
6073
|
-
recognition.interimResults = true;
|
|
6074
|
-
recognition.maxAlternatives = 1;
|
|
6075
|
-
recognition.onstart = () => {
|
|
6148
|
+
micConfirmedRef.current = access.confirmed;
|
|
6149
|
+
if (access.primed) {
|
|
6150
|
+
await sleep(RELEASE_SETTLE_MS);
|
|
6076
6151
|
if (token !== startTokenRef.current) return;
|
|
6077
|
-
setError(null);
|
|
6078
|
-
setListening(true);
|
|
6079
|
-
};
|
|
6080
|
-
recognition.onresult = (event) => {
|
|
6081
|
-
let settled = "";
|
|
6082
|
-
let pending = "";
|
|
6083
|
-
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
6084
|
-
const result = event.results[i];
|
|
6085
|
-
if (!result) continue;
|
|
6086
|
-
const text = result[0]?.transcript ?? "";
|
|
6087
|
-
if (result.isFinal) settled += text;
|
|
6088
|
-
else pending += text;
|
|
6089
|
-
}
|
|
6090
|
-
setInterim(pending);
|
|
6091
|
-
if (settled.trim() !== "") finalRef.current(settled);
|
|
6092
|
-
};
|
|
6093
|
-
recognition.onerror = (event) => {
|
|
6094
|
-
const message = describeError(event.error);
|
|
6095
|
-
setListening(false);
|
|
6096
|
-
setInterim("");
|
|
6097
|
-
if (message !== "") {
|
|
6098
|
-
setError(message);
|
|
6099
|
-
errorRef.current?.(message);
|
|
6100
|
-
}
|
|
6101
|
-
};
|
|
6102
|
-
recognition.onend = () => {
|
|
6103
|
-
setListening(false);
|
|
6104
|
-
setInterim("");
|
|
6105
|
-
};
|
|
6106
|
-
recognitionRef.current = recognition;
|
|
6107
|
-
try {
|
|
6108
|
-
recognition.start();
|
|
6109
|
-
} catch {
|
|
6110
|
-
setListening(false);
|
|
6111
6152
|
}
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
);
|
|
6115
|
-
beginRecognitionRef.current = beginRecognitionImpl;
|
|
6153
|
+
openSessionRef.current?.(token);
|
|
6154
|
+
});
|
|
6155
|
+
}, []);
|
|
6116
6156
|
const toggle = useCallback(() => {
|
|
6117
6157
|
if (listening) stop();
|
|
6118
6158
|
else start();
|
|
6119
6159
|
}, [listening, start, stop]);
|
|
6120
6160
|
useEffect(
|
|
6121
6161
|
() => () => {
|
|
6162
|
+
startTokenRef.current += 1;
|
|
6163
|
+
wantsListeningRef.current = false;
|
|
6122
6164
|
const recognition = recognitionRef.current;
|
|
6123
6165
|
if (!recognition) return;
|
|
6124
6166
|
recognition.onresult = null;
|
|
@@ -6177,6 +6219,50 @@ var EXPLORE_CSS = `
|
|
|
6177
6219
|
border-radius: 9999px;
|
|
6178
6220
|
background-clip: content-box;
|
|
6179
6221
|
}
|
|
6222
|
+
|
|
6223
|
+
/* The product strip scrolls inside itself; a visible scrollbar would read as a broken
|
|
6224
|
+
layout rather than an affordance, and reserving its gutter shifts the chips. */
|
|
6225
|
+
.boff-explore-strip {
|
|
6226
|
+
scrollbar-width: none;
|
|
6227
|
+
-ms-overflow-style: none;
|
|
6228
|
+
}
|
|
6229
|
+
.boff-explore-strip::-webkit-scrollbar { display: none; }
|
|
6230
|
+
|
|
6231
|
+
@keyframes boff-explore-fade-in {
|
|
6232
|
+
from { opacity: 0; transform: translateY(2px); }
|
|
6233
|
+
to { opacity: 1; transform: none; }
|
|
6234
|
+
}
|
|
6235
|
+
.boff-explore-fade { animation: boff-explore-fade-in 220ms ease-out; }
|
|
6236
|
+
@media (prefers-reduced-motion: reduce) {
|
|
6237
|
+
.boff-explore-fade { animation: none; }
|
|
6238
|
+
}
|
|
6239
|
+
|
|
6240
|
+
/* Nothing inside an answer may widen the page. Model output carries long URLs, code and
|
|
6241
|
+
tables \u2014 each of those overflows a phone by default, and one overflowing child makes the
|
|
6242
|
+
WHOLE document horizontally scrollable, not just the bubble. */
|
|
6243
|
+
.boff-explore-body,
|
|
6244
|
+
.boff-explore-body p,
|
|
6245
|
+
.boff-explore-body li,
|
|
6246
|
+
.boff-explore-body a,
|
|
6247
|
+
.boff-explore-body h1,
|
|
6248
|
+
.boff-explore-body h2,
|
|
6249
|
+
.boff-explore-body h3 {
|
|
6250
|
+
overflow-wrap: anywhere;
|
|
6251
|
+
word-break: break-word;
|
|
6252
|
+
}
|
|
6253
|
+
.boff-explore-body pre {
|
|
6254
|
+
overflow-x: auto;
|
|
6255
|
+
max-width: 100%;
|
|
6256
|
+
}
|
|
6257
|
+
.boff-explore-body table {
|
|
6258
|
+
display: block;
|
|
6259
|
+
overflow-x: auto;
|
|
6260
|
+
max-width: 100%;
|
|
6261
|
+
}
|
|
6262
|
+
.boff-explore-body img {
|
|
6263
|
+
max-width: 100%;
|
|
6264
|
+
height: auto;
|
|
6265
|
+
}
|
|
6180
6266
|
`;
|
|
6181
6267
|
function ExploreStyles() {
|
|
6182
6268
|
return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EXPLORE_CSS } });
|
|
@@ -6198,7 +6284,6 @@ var CAPABILITIES = [
|
|
|
6198
6284
|
body: "Get the sources and next steps \u2014 pricing, docs, a demo \u2014 without hunting."
|
|
6199
6285
|
}
|
|
6200
6286
|
];
|
|
6201
|
-
var PRODUCT_CHIP_PREVIEW = 12;
|
|
6202
6287
|
var CTA_VARIANTS = {
|
|
6203
6288
|
CONTACT: "default",
|
|
6204
6289
|
WAITLIST: "default",
|
|
@@ -6399,7 +6484,7 @@ function AssistantBubble({
|
|
|
6399
6484
|
),
|
|
6400
6485
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
|
|
6401
6486
|
body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
6402
|
-
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
|
|
6487
|
+
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
|
|
6403
6488
|
streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
6404
6489
|
] }) : null,
|
|
6405
6490
|
streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
|
|
@@ -6461,6 +6546,200 @@ function ErrorBanner({
|
|
|
6461
6546
|
}
|
|
6462
6547
|
);
|
|
6463
6548
|
}
|
|
6549
|
+
function PromptCarousel({
|
|
6550
|
+
prompts,
|
|
6551
|
+
onPrompt,
|
|
6552
|
+
disabled
|
|
6553
|
+
}) {
|
|
6554
|
+
const [index, setIndex] = useState(0);
|
|
6555
|
+
const [paused, setPaused] = useState(false);
|
|
6556
|
+
const count = prompts.length;
|
|
6557
|
+
const current = prompts[index % count] ?? prompts[0] ?? "";
|
|
6558
|
+
const go = useCallback(
|
|
6559
|
+
(delta) => {
|
|
6560
|
+
setIndex((i) => (i + delta + count) % count);
|
|
6561
|
+
},
|
|
6562
|
+
[count]
|
|
6563
|
+
);
|
|
6564
|
+
useEffect(() => {
|
|
6565
|
+
if (paused || disabled || count < 2) return;
|
|
6566
|
+
if (typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) {
|
|
6567
|
+
return;
|
|
6568
|
+
}
|
|
6569
|
+
const timer = setInterval(() => setIndex((i) => (i + 1) % count), 4500);
|
|
6570
|
+
return () => clearInterval(timer);
|
|
6571
|
+
}, [paused, disabled, count]);
|
|
6572
|
+
if (count === 0) return null;
|
|
6573
|
+
return /* @__PURE__ */ jsxs(
|
|
6574
|
+
"div",
|
|
6575
|
+
{
|
|
6576
|
+
className: "flex min-w-0 items-center gap-1.5",
|
|
6577
|
+
onMouseEnter: () => setPaused(true),
|
|
6578
|
+
onMouseLeave: () => setPaused(false),
|
|
6579
|
+
onFocusCapture: () => setPaused(true),
|
|
6580
|
+
onBlurCapture: () => setPaused(false),
|
|
6581
|
+
children: [
|
|
6582
|
+
count > 1 ? /* @__PURE__ */ jsx(
|
|
6583
|
+
"button",
|
|
6584
|
+
{
|
|
6585
|
+
type: "button",
|
|
6586
|
+
"aria-label": "Previous suggestion",
|
|
6587
|
+
onClick: () => go(-1),
|
|
6588
|
+
className: "hidden h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:inline-flex",
|
|
6589
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
6590
|
+
}
|
|
6591
|
+
) : null,
|
|
6592
|
+
/* @__PURE__ */ jsxs(
|
|
6593
|
+
"button",
|
|
6594
|
+
{
|
|
6595
|
+
"data-boff-explore": "chip",
|
|
6596
|
+
"data-chip-kind": "prompt",
|
|
6597
|
+
type: "button",
|
|
6598
|
+
disabled,
|
|
6599
|
+
onClick: () => onPrompt(current),
|
|
6600
|
+
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",
|
|
6601
|
+
children: [
|
|
6602
|
+
/* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 shrink-0 text-primary" }),
|
|
6603
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: current }),
|
|
6604
|
+
/* @__PURE__ */ jsx(ArrowUp, { className: "ml-auto h-3.5 w-3.5 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
6605
|
+
]
|
|
6606
|
+
},
|
|
6607
|
+
current
|
|
6608
|
+
),
|
|
6609
|
+
count > 1 ? /* @__PURE__ */ jsx(
|
|
6610
|
+
"button",
|
|
6611
|
+
{
|
|
6612
|
+
type: "button",
|
|
6613
|
+
"aria-label": "Next suggestion",
|
|
6614
|
+
onClick: () => go(1),
|
|
6615
|
+
className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
6616
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
6617
|
+
}
|
|
6618
|
+
) : null
|
|
6619
|
+
]
|
|
6620
|
+
}
|
|
6621
|
+
);
|
|
6622
|
+
}
|
|
6623
|
+
function ProductStrip({
|
|
6624
|
+
products,
|
|
6625
|
+
focusProduct,
|
|
6626
|
+
onFocus
|
|
6627
|
+
}) {
|
|
6628
|
+
const [expanded, setExpanded] = useState(false);
|
|
6629
|
+
const chipClass = (active) => cn(
|
|
6630
|
+
"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",
|
|
6631
|
+
active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
6632
|
+
);
|
|
6633
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
6634
|
+
/* @__PURE__ */ jsxs(
|
|
6635
|
+
"div",
|
|
6636
|
+
{
|
|
6637
|
+
className: cn(
|
|
6638
|
+
"boff-explore-strip flex min-w-0 flex-1 gap-2",
|
|
6639
|
+
expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
|
|
6640
|
+
),
|
|
6641
|
+
children: [
|
|
6642
|
+
/* @__PURE__ */ jsx(
|
|
6643
|
+
"button",
|
|
6644
|
+
{
|
|
6645
|
+
"data-boff-explore": "chip",
|
|
6646
|
+
"data-chip-kind": "product",
|
|
6647
|
+
"data-product": "all",
|
|
6648
|
+
type: "button",
|
|
6649
|
+
"aria-pressed": focusProduct === null,
|
|
6650
|
+
onClick: () => onFocus(null),
|
|
6651
|
+
className: chipClass(focusProduct === null),
|
|
6652
|
+
children: "All products"
|
|
6653
|
+
}
|
|
6654
|
+
),
|
|
6655
|
+
products.map((product) => /* @__PURE__ */ jsx(
|
|
6656
|
+
"button",
|
|
6657
|
+
{
|
|
6658
|
+
"data-boff-explore": "chip",
|
|
6659
|
+
"data-chip-kind": "product",
|
|
6660
|
+
"data-product": product.slug,
|
|
6661
|
+
type: "button",
|
|
6662
|
+
"aria-pressed": focusProduct === product.slug,
|
|
6663
|
+
title: product.tagline ?? product.name,
|
|
6664
|
+
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
6665
|
+
className: chipClass(focusProduct === product.slug),
|
|
6666
|
+
children: product.name
|
|
6667
|
+
},
|
|
6668
|
+
product.slug
|
|
6669
|
+
))
|
|
6670
|
+
]
|
|
6671
|
+
}
|
|
6672
|
+
),
|
|
6673
|
+
products.length > 0 ? /* @__PURE__ */ jsx(
|
|
6674
|
+
"button",
|
|
6675
|
+
{
|
|
6676
|
+
type: "button",
|
|
6677
|
+
"data-boff-explore": "products-toggle",
|
|
6678
|
+
onClick: () => setExpanded((v) => !v),
|
|
6679
|
+
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",
|
|
6680
|
+
children: expanded ? "Show less" : `All ${products.length}`
|
|
6681
|
+
}
|
|
6682
|
+
) : null
|
|
6683
|
+
] });
|
|
6684
|
+
}
|
|
6685
|
+
function DisclaimerDialog({
|
|
6686
|
+
open,
|
|
6687
|
+
onClose,
|
|
6688
|
+
captchaOn
|
|
6689
|
+
}) {
|
|
6690
|
+
const closeRef = useRef(null);
|
|
6691
|
+
useEffect(() => {
|
|
6692
|
+
if (!open) return;
|
|
6693
|
+
const onKey = (event) => {
|
|
6694
|
+
if (event.key === "Escape") onClose();
|
|
6695
|
+
};
|
|
6696
|
+
document.addEventListener("keydown", onKey);
|
|
6697
|
+
closeRef.current?.focus();
|
|
6698
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
6699
|
+
}, [open, onClose]);
|
|
6700
|
+
if (!open) return null;
|
|
6701
|
+
return /* @__PURE__ */ jsx(
|
|
6702
|
+
"div",
|
|
6703
|
+
{
|
|
6704
|
+
"data-boff-explore": "disclaimer-dialog",
|
|
6705
|
+
role: "dialog",
|
|
6706
|
+
"aria-modal": "true",
|
|
6707
|
+
"aria-label": "How this assistant works",
|
|
6708
|
+
className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
|
|
6709
|
+
onClick: onClose,
|
|
6710
|
+
children: /* @__PURE__ */ jsxs(
|
|
6711
|
+
"div",
|
|
6712
|
+
{
|
|
6713
|
+
className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
|
|
6714
|
+
onClick: (event) => event.stopPropagation(),
|
|
6715
|
+
children: [
|
|
6716
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
6717
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" }) }),
|
|
6718
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
6719
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: "How this assistant works" }),
|
|
6720
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
|
|
6721
|
+
/* @__PURE__ */ jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
|
|
6722
|
+
/* @__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." }),
|
|
6723
|
+
captchaOn ? /* @__PURE__ */ jsx("p", { children: "Protected by reCAPTCHA \u2014 the Google Privacy Policy and Terms of Service apply." }) : null
|
|
6724
|
+
] })
|
|
6725
|
+
] })
|
|
6726
|
+
] }),
|
|
6727
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ jsx(
|
|
6728
|
+
Button,
|
|
6729
|
+
{
|
|
6730
|
+
ref: closeRef,
|
|
6731
|
+
size: "sm",
|
|
6732
|
+
variant: "secondary",
|
|
6733
|
+
onClick: onClose,
|
|
6734
|
+
children: "Got it"
|
|
6735
|
+
}
|
|
6736
|
+
) })
|
|
6737
|
+
]
|
|
6738
|
+
}
|
|
6739
|
+
)
|
|
6740
|
+
}
|
|
6741
|
+
);
|
|
6742
|
+
}
|
|
6464
6743
|
function WelcomeState({
|
|
6465
6744
|
title,
|
|
6466
6745
|
body,
|
|
@@ -6471,21 +6750,19 @@ function WelcomeState({
|
|
|
6471
6750
|
onFocus,
|
|
6472
6751
|
disabled
|
|
6473
6752
|
}) {
|
|
6474
|
-
|
|
6475
|
-
const visibleProducts = showAllProducts ? products : products.slice(0, PRODUCT_CHIP_PREVIEW);
|
|
6476
|
-
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 py-10 sm:py-14", children: [
|
|
6753
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-3xl px-4 py-8 sm:py-12", children: [
|
|
6477
6754
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
6478
6755
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-muted px-3 py-1 text-xs font-medium text-muted-foreground", children: [
|
|
6479
6756
|
/* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5" }),
|
|
6480
6757
|
"AI answers, grounded in our documentation"
|
|
6481
6758
|
] }),
|
|
6482
|
-
/* @__PURE__ */ jsx("h1", { className: "mt-
|
|
6483
|
-
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-
|
|
6759
|
+
/* @__PURE__ */ jsx("h1", { className: "mt-4 text-balance break-words text-2xl font-bold tracking-tight sm:text-4xl", children: title }),
|
|
6760
|
+
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-2.5 max-w-2xl text-pretty text-sm leading-relaxed text-muted-foreground sm:text-lg", children: body })
|
|
6484
6761
|
] }),
|
|
6485
|
-
/* @__PURE__ */ jsx("ul", { className: "mt-
|
|
6762
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-7 grid gap-2.5 sm:grid-cols-3", children: CAPABILITIES.map(({ icon: Icon, title: capTitle, body: capBody }) => /* @__PURE__ */ jsxs(
|
|
6486
6763
|
"li",
|
|
6487
6764
|
{
|
|
6488
|
-
className: "rounded-xl border border-border bg-card p-
|
|
6765
|
+
className: "rounded-xl border border-border/70 bg-card/60 p-3.5 text-left transition-colors hover:border-border",
|
|
6489
6766
|
children: [
|
|
6490
6767
|
/* @__PURE__ */ jsx("span", { className: "mb-2.5 flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) }),
|
|
6491
6768
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-card-foreground", children: capTitle }),
|
|
@@ -6494,72 +6771,27 @@ function WelcomeState({
|
|
|
6494
6771
|
},
|
|
6495
6772
|
capTitle
|
|
6496
6773
|
)) }),
|
|
6497
|
-
prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-
|
|
6498
|
-
/* @__PURE__ */ jsx("p", { className: "mb-2
|
|
6499
|
-
/* @__PURE__ */ jsx(
|
|
6500
|
-
|
|
6774
|
+
prompts.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-8", children: [
|
|
6775
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Try asking" }),
|
|
6776
|
+
/* @__PURE__ */ jsx(
|
|
6777
|
+
PromptCarousel,
|
|
6501
6778
|
{
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
className: "group inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-left text-sm text-card-foreground transition-colors hover:border-primary/40 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
6508
|
-
children: [
|
|
6509
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: prompt }),
|
|
6510
|
-
/* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
|
|
6511
|
-
]
|
|
6512
|
-
},
|
|
6513
|
-
prompt
|
|
6514
|
-
)) })
|
|
6779
|
+
prompts,
|
|
6780
|
+
onPrompt,
|
|
6781
|
+
disabled
|
|
6782
|
+
}
|
|
6783
|
+
)
|
|
6515
6784
|
] }) : null,
|
|
6516
|
-
products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-
|
|
6517
|
-
/* @__PURE__ */ jsx("p", { className: "mb-2
|
|
6518
|
-
/* @__PURE__ */
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
"aria-pressed": focusProduct === null,
|
|
6527
|
-
onClick: () => onFocus(null),
|
|
6528
|
-
className: cn(
|
|
6529
|
-
"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",
|
|
6530
|
-
focusProduct === null ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
6531
|
-
),
|
|
6532
|
-
children: "All products"
|
|
6533
|
-
}
|
|
6534
|
-
),
|
|
6535
|
-
visibleProducts.map((product) => /* @__PURE__ */ jsx(
|
|
6536
|
-
"button",
|
|
6537
|
-
{
|
|
6538
|
-
"data-boff-explore": "chip",
|
|
6539
|
-
"data-chip-kind": "product",
|
|
6540
|
-
"data-product": product.slug,
|
|
6541
|
-
type: "button",
|
|
6542
|
-
"aria-pressed": focusProduct === product.slug,
|
|
6543
|
-
title: product.tagline ?? product.name,
|
|
6544
|
-
onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
|
|
6545
|
-
className: cn(
|
|
6546
|
-
"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",
|
|
6547
|
-
focusProduct === product.slug ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
6548
|
-
),
|
|
6549
|
-
children: product.name
|
|
6550
|
-
},
|
|
6551
|
-
product.slug
|
|
6552
|
-
)),
|
|
6553
|
-
products.length > PRODUCT_CHIP_PREVIEW ? /* @__PURE__ */ jsx(
|
|
6554
|
-
"button",
|
|
6555
|
-
{
|
|
6556
|
-
type: "button",
|
|
6557
|
-
onClick: () => setShowAllProducts((v) => !v),
|
|
6558
|
-
className: "rounded-full px-3 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",
|
|
6559
|
-
children: showAllProducts ? "Show fewer" : `Show all ${products.length}`
|
|
6560
|
-
}
|
|
6561
|
-
) : null
|
|
6562
|
-
] })
|
|
6785
|
+
products.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
|
|
6786
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Focus on a product" }),
|
|
6787
|
+
/* @__PURE__ */ jsx(
|
|
6788
|
+
ProductStrip,
|
|
6789
|
+
{
|
|
6790
|
+
products,
|
|
6791
|
+
focusProduct,
|
|
6792
|
+
onFocus
|
|
6793
|
+
}
|
|
6794
|
+
)
|
|
6563
6795
|
] }) : null
|
|
6564
6796
|
] });
|
|
6565
6797
|
}
|
|
@@ -6615,6 +6847,7 @@ function ExplorePage({
|
|
|
6615
6847
|
}
|
|
6616
6848
|
});
|
|
6617
6849
|
speechStopRef.current = speech.stop;
|
|
6850
|
+
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
|
6618
6851
|
const scrollRef = useRef(null);
|
|
6619
6852
|
const latestAssistantRef = useRef(null);
|
|
6620
6853
|
const alignedForRef = useRef(null);
|
|
@@ -6707,7 +6940,7 @@ function ExplorePage({
|
|
|
6707
6940
|
"data-boff-explore": "page",
|
|
6708
6941
|
"data-phase": phase,
|
|
6709
6942
|
className: cn(
|
|
6710
|
-
"flex w-full flex-col bg-background text-foreground",
|
|
6943
|
+
"flex w-full min-w-0 flex-col overflow-x-hidden bg-background text-foreground",
|
|
6711
6944
|
heightMode === "auto" && "min-h-[70vh]",
|
|
6712
6945
|
className
|
|
6713
6946
|
),
|
|
@@ -6849,7 +7082,7 @@ function ExplorePage({
|
|
|
6849
7082
|
role: "log",
|
|
6850
7083
|
"aria-live": "polite",
|
|
6851
7084
|
"aria-label": "Explore conversation",
|
|
6852
|
-
className: "boff-explore-scroll min-h-0 flex-1 overflow-y-auto",
|
|
7085
|
+
className: "boff-explore-scroll min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden",
|
|
6853
7086
|
children: showWelcome ? /* @__PURE__ */ jsx(
|
|
6854
7087
|
WelcomeState,
|
|
6855
7088
|
{
|
|
@@ -6862,7 +7095,7 @@ function ExplorePage({
|
|
|
6862
7095
|
onFocus: setFocusProduct,
|
|
6863
7096
|
disabled: !canSend || busy
|
|
6864
7097
|
}
|
|
6865
|
-
) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-3xl space-y-6 px-4 py-6", children: messages.map(
|
|
7098
|
+
) : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full min-w-0 max-w-3xl space-y-6 px-4 py-6", children: messages.map(
|
|
6866
7099
|
(message) => message.role === "USER" ? /* @__PURE__ */ jsx(UserBubble, { message }, message.id) : /* @__PURE__ */ jsx(
|
|
6867
7100
|
AssistantBubble,
|
|
6868
7101
|
{
|
|
@@ -6876,7 +7109,15 @@ function ExplorePage({
|
|
|
6876
7109
|
) })
|
|
6877
7110
|
}
|
|
6878
7111
|
),
|
|
6879
|
-
/* @__PURE__ */ jsx(
|
|
7112
|
+
/* @__PURE__ */ jsx(
|
|
7113
|
+
DisclaimerDialog,
|
|
7114
|
+
{
|
|
7115
|
+
open: disclaimerOpen,
|
|
7116
|
+
onClose: () => setDisclaimerOpen(false),
|
|
7117
|
+
captchaOn
|
|
7118
|
+
}
|
|
7119
|
+
),
|
|
7120
|
+
/* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background/85 px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3 backdrop-blur-md", children: /* @__PURE__ */ jsxs(
|
|
6880
7121
|
"form",
|
|
6881
7122
|
{
|
|
6882
7123
|
"data-boff-explore": "composer",
|
|
@@ -6891,7 +7132,7 @@ function ExplorePage({
|
|
|
6891
7132
|
"div",
|
|
6892
7133
|
{
|
|
6893
7134
|
className: cn(
|
|
6894
|
-
"flex items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-
|
|
7135
|
+
"flex min-w-0 items-end gap-2 rounded-2xl border bg-card p-2 shadow-sm transition-all",
|
|
6895
7136
|
overLimit ? "border-destructive/60" : "border-border focus-within:border-primary/40 focus-within:ring-1 focus-within:ring-ring"
|
|
6896
7137
|
),
|
|
6897
7138
|
children: [
|
|
@@ -6912,7 +7153,7 @@ function ExplorePage({
|
|
|
6912
7153
|
},
|
|
6913
7154
|
"aria-label": "Ask a question",
|
|
6914
7155
|
placeholder: composerDisabled ? phase === "limited" ? "Message limit reached \u2014 please try again later" : "Explore is unavailable right now" : focusedProductName ? `Ask about ${focusedProductName}\u2026` : "Ask anything about our products\u2026",
|
|
6915
|
-
className: "max-h-[200px] min-h-[44px] flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-sm shadow-none focus-visible:ring-0 md:text-sm"
|
|
7156
|
+
className: "max-h-[200px] min-h-[44px] w-full min-w-0 flex-1 resize-none border-0 bg-transparent px-2 py-2.5 text-sm shadow-none focus-visible:ring-0 md:text-sm"
|
|
6916
7157
|
}
|
|
6917
7158
|
),
|
|
6918
7159
|
speech.supported ? /* @__PURE__ */ jsx(
|
|
@@ -7003,48 +7244,19 @@ function ExplorePage({
|
|
|
7003
7244
|
}
|
|
7004
7245
|
)
|
|
7005
7246
|
] }),
|
|
7006
|
-
/* @__PURE__ */ jsxs(
|
|
7007
|
-
"
|
|
7008
|
-
|
|
7009
|
-
"
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
"
|
|
7013
|
-
|
|
7014
|
-
"
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
/* @__PURE__ */ jsx(
|
|
7020
|
-
"a",
|
|
7021
|
-
{
|
|
7022
|
-
href: "https://policies.google.com/privacy",
|
|
7023
|
-
target: "_blank",
|
|
7024
|
-
rel: "noopener noreferrer",
|
|
7025
|
-
className: "underline underline-offset-2 hover:text-foreground",
|
|
7026
|
-
children: "Privacy Policy"
|
|
7027
|
-
}
|
|
7028
|
-
),
|
|
7029
|
-
" ",
|
|
7030
|
-
"and",
|
|
7031
|
-
" ",
|
|
7032
|
-
/* @__PURE__ */ jsx(
|
|
7033
|
-
"a",
|
|
7034
|
-
{
|
|
7035
|
-
href: "https://policies.google.com/terms",
|
|
7036
|
-
target: "_blank",
|
|
7037
|
-
rel: "noopener noreferrer",
|
|
7038
|
-
className: "underline underline-offset-2 hover:text-foreground",
|
|
7039
|
-
children: "Terms of Service"
|
|
7040
|
-
}
|
|
7041
|
-
),
|
|
7042
|
-
" ",
|
|
7043
|
-
"apply."
|
|
7044
|
-
] }) : null
|
|
7045
|
-
]
|
|
7046
|
-
}
|
|
7047
|
-
)
|
|
7247
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
7248
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: "Grounded in our docs \u2014 check anything important." }),
|
|
7249
|
+
/* @__PURE__ */ jsx(
|
|
7250
|
+
"button",
|
|
7251
|
+
{
|
|
7252
|
+
type: "button",
|
|
7253
|
+
"data-boff-explore": "disclaimer",
|
|
7254
|
+
onClick: () => setDisclaimerOpen(true),
|
|
7255
|
+
className: "shrink-0 underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
7256
|
+
children: "Disclaimer"
|
|
7257
|
+
}
|
|
7258
|
+
)
|
|
7259
|
+
] })
|
|
7048
7260
|
]
|
|
7049
7261
|
}
|
|
7050
7262
|
) })
|