@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/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, Link2, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
4
+ import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, Sparkles, RotateCcw, Link2, History, Trash2, Mic, Square, ArrowUp, BookOpenText, Layers, TriangleAlert, ChevronLeft, ChevronRight, FileText, ExternalLink } from 'lucide-react';
5
5
  import ReCAPTCHA4 from 'react-google-recaptcha';
6
6
  import { toast } from 'sonner';
7
7
  import { Helmet } from 'react-helmet-async';
@@ -4929,6 +4929,7 @@ var EXPLORE_MESSAGE_FIELDS = (
4929
4929
  description
4930
4930
  product
4931
4931
  imageUrl
4932
+ index
4932
4933
  }
4933
4934
  ctas {
4934
4935
  kind
@@ -4936,6 +4937,8 @@ var EXPLORE_MESSAGE_FIELDS = (
4936
4937
  url
4937
4938
  product
4938
4939
  }
4940
+ followUps
4941
+ answered
4939
4942
  errorCode
4940
4943
  createdAt
4941
4944
  completedAt
@@ -5001,6 +5004,26 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
5001
5004
  }
5002
5005
  `
5003
5006
  );
5007
+ var RECORD_EXPLORE_CLICK_MUTATION = (
5008
+ /* GraphQL */
5009
+ `
5010
+ mutation RecordExploreClick($input: RecordExploreClickInput!) {
5011
+ recordExploreClick(input: $input) {
5012
+ recorded
5013
+ }
5014
+ }
5015
+ `
5016
+ );
5017
+ var CREATE_EXPLORE_SHARE_LINK_MUTATION = (
5018
+ /* GraphQL */
5019
+ `
5020
+ mutation CreateExploreShareLink($conversationToken: String!) {
5021
+ createExploreShareLink(conversationToken: $conversationToken) {
5022
+ shareToken
5023
+ }
5024
+ }
5025
+ `
5026
+ );
5004
5027
 
5005
5028
  // src/data/products.ts
5006
5029
  var ECOSYSTEM_PRODUCTS = [
@@ -5933,6 +5956,30 @@ function useExploreChat(options = {}) {
5933
5956
  return null;
5934
5957
  }, [messages]);
5935
5958
  const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
5959
+ const createShareLink = useCallback(async () => {
5960
+ const token = conversationTokenRef.current;
5961
+ if (!token) return null;
5962
+ try {
5963
+ const result = await client.mutate(CREATE_EXPLORE_SHARE_LINK_MUTATION, { conversationToken: token });
5964
+ return result?.data?.createExploreShareLink?.shareToken ?? null;
5965
+ } catch {
5966
+ return null;
5967
+ }
5968
+ }, [client]);
5969
+ const recordClick = useCallback(
5970
+ (messageId, kind, url) => {
5971
+ const token = conversationTokenRef.current;
5972
+ if (!token) return;
5973
+ try {
5974
+ void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
5975
+ input: { conversationToken: token, messageId, kind, url }
5976
+ }).catch(() => {
5977
+ });
5978
+ } catch {
5979
+ }
5980
+ },
5981
+ [client]
5982
+ );
5936
5983
  return {
5937
5984
  phase,
5938
5985
  catalog,
@@ -5950,7 +5997,9 @@ function useExploreChat(options = {}) {
5950
5997
  history: archive,
5951
5998
  openConversation,
5952
5999
  deleteConversation,
5953
- clearHistory
6000
+ clearHistory,
6001
+ recordClick,
6002
+ createShareLink
5954
6003
  };
5955
6004
  }
5956
6005
  var optimisticCounter = 0;
@@ -6322,7 +6371,10 @@ function logoUrlOf(url) {
6322
6371
  return null;
6323
6372
  }
6324
6373
  }
6325
- function ReferenceCard({ reference }) {
6374
+ function ReferenceCard({
6375
+ reference,
6376
+ onFollow
6377
+ }) {
6326
6378
  const [imageFailed, setImageFailed] = useState(false);
6327
6379
  const [logoFailed, setLogoFailed] = useState(false);
6328
6380
  const host = hostnameOf(reference.url);
@@ -6344,9 +6396,11 @@ function ReferenceCard({ reference }) {
6344
6396
  "a",
6345
6397
  {
6346
6398
  "data-boff-explore": "reference",
6399
+ "data-index": reference.index ?? void 0,
6347
6400
  href: reference.url,
6348
6401
  target: "_blank",
6349
6402
  rel: "noopener noreferrer",
6403
+ onClick: () => onFollow?.(reference.url),
6350
6404
  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",
6351
6405
  children: [
6352
6406
  /* @__PURE__ */ jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
@@ -6370,7 +6424,10 @@ function ReferenceCard({ reference }) {
6370
6424
  }
6371
6425
  ) }) : letterPlate }),
6372
6426
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
6373
- /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: reference.title || host || reference.url }),
6427
+ /* @__PURE__ */ jsxs("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: [
6428
+ 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,
6429
+ reference.title || host || reference.url
6430
+ ] }),
6374
6431
  reference.description ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
6375
6432
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
6376
6433
  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,
@@ -6386,7 +6443,8 @@ function ReferenceCard({ reference }) {
6386
6443
  }
6387
6444
  function CtaButton({
6388
6445
  cta,
6389
- onNavigate
6446
+ onNavigate,
6447
+ onFollow
6390
6448
  }) {
6391
6449
  const variant = CTA_VARIANTS[cta.kind] ?? "outline";
6392
6450
  const internal = isInternalPath(cta.url);
@@ -6399,7 +6457,10 @@ function CtaButton({
6399
6457
  type: "button",
6400
6458
  size: "sm",
6401
6459
  variant,
6402
- onClick: () => onNavigate(cta.url),
6460
+ onClick: () => {
6461
+ onFollow?.(cta.url);
6462
+ onNavigate(cta.url);
6463
+ },
6403
6464
  children: cta.label
6404
6465
  }
6405
6466
  );
@@ -6410,6 +6471,7 @@ function CtaButton({
6410
6471
  "data-boff-explore": "cta",
6411
6472
  "data-kind": cta.kind,
6412
6473
  href: cta.url,
6474
+ onClick: () => onFollow?.(cta.url),
6413
6475
  ...internal ? {} : { target: "_blank", rel: "noopener noreferrer" },
6414
6476
  children: [
6415
6477
  cta.label,
@@ -6461,7 +6523,9 @@ function AssistantBubble({
6461
6523
  message,
6462
6524
  activity,
6463
6525
  onNavigate,
6464
- anchorRef
6526
+ anchorRef,
6527
+ onFollow,
6528
+ onFollowUp
6465
6529
  }) {
6466
6530
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
6467
6531
  const body = message.content || message.partialContent || "";
@@ -6483,6 +6547,34 @@ function AssistantBubble({
6483
6547
  }
6484
6548
  ),
6485
6549
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
6550
+ message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxs(
6551
+ "div",
6552
+ {
6553
+ "data-boff-explore": "no-answer",
6554
+ 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",
6555
+ children: [
6556
+ /* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
6557
+ /* @__PURE__ */ jsxs("span", { children: [
6558
+ "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
6559
+ " ",
6560
+ /* @__PURE__ */ jsx(
6561
+ "a",
6562
+ {
6563
+ href: "/contact",
6564
+ className: "underline underline-offset-2 hover:text-primary",
6565
+ onClick: (event) => {
6566
+ if (!onNavigate) return;
6567
+ event.preventDefault();
6568
+ onNavigate("/contact");
6569
+ },
6570
+ children: "ask a human"
6571
+ }
6572
+ ),
6573
+ "."
6574
+ ] })
6575
+ ]
6576
+ }
6577
+ ) : null,
6486
6578
  body ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
6487
6579
  /* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(Markdown, { children: body }) }),
6488
6580
  streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
@@ -6491,16 +6583,41 @@ function AssistantBubble({
6491
6583
  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,
6492
6584
  message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
6493
6585
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
6494
- /* @__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(ReferenceCard, { reference }, reference.url)) })
6586
+ /* @__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(
6587
+ ReferenceCard,
6588
+ {
6589
+ reference,
6590
+ onFollow: (url) => onFollow?.("REFERENCE", url)
6591
+ },
6592
+ reference.url
6593
+ )) })
6495
6594
  ] }) : null,
6496
6595
  message.ctas.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 pt-0.5", children: message.ctas.map((cta) => /* @__PURE__ */ jsx(
6497
6596
  CtaButton,
6498
6597
  {
6499
6598
  cta,
6500
- onNavigate
6599
+ onNavigate,
6600
+ onFollow: (url) => onFollow?.("CTA", url)
6501
6601
  },
6502
6602
  `${cta.kind}-${cta.url}`
6503
- )) }) : null
6603
+ )) }) : null,
6604
+ message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
6605
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
6606
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxs(
6607
+ "button",
6608
+ {
6609
+ "data-boff-explore": "follow-up",
6610
+ type: "button",
6611
+ onClick: () => onFollowUp?.(question),
6612
+ 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",
6613
+ children: [
6614
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: question }),
6615
+ /* @__PURE__ */ jsx(ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
6616
+ ]
6617
+ },
6618
+ question
6619
+ )) })
6620
+ ] }) : null
6504
6621
  ] })
6505
6622
  ]
6506
6623
  }
@@ -6574,6 +6691,9 @@ function PromptCarousel({
6574
6691
  "div",
6575
6692
  {
6576
6693
  className: "flex min-w-0 items-center gap-1.5",
6694
+ role: "group",
6695
+ "aria-roledescription": "carousel",
6696
+ "aria-label": "Example questions",
6577
6697
  onMouseEnter: () => setPaused(true),
6578
6698
  onMouseLeave: () => setPaused(false),
6579
6699
  onFocusCapture: () => setPaused(true),
@@ -6596,6 +6716,8 @@ function PromptCarousel({
6596
6716
  "data-chip-kind": "prompt",
6597
6717
  type: "button",
6598
6718
  disabled,
6719
+ "aria-label": `Ask: ${current}`,
6720
+ "aria-live": paused ? "polite" : "off",
6599
6721
  onClick: () => onPrompt(current),
6600
6722
  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
6723
  children: [
@@ -6630,72 +6752,108 @@ function ProductStrip({
6630
6752
  "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
6753
  active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
6632
6754
  );
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"
6755
+ return /* @__PURE__ */ jsxs(
6756
+ "div",
6757
+ {
6758
+ className: "flex min-w-0 items-center gap-2",
6759
+ role: "group",
6760
+ "aria-label": "Focus the assistant on one product",
6761
+ children: [
6762
+ /* @__PURE__ */ jsxs(
6763
+ "div",
6764
+ {
6765
+ className: cn(
6766
+ "boff-explore-strip flex min-w-0 flex-1 gap-2",
6767
+ expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
6768
+ ),
6769
+ children: [
6770
+ /* @__PURE__ */ jsx(
6771
+ "button",
6772
+ {
6773
+ "data-boff-explore": "chip",
6774
+ "data-chip-kind": "product",
6775
+ "data-product": "all",
6776
+ type: "button",
6777
+ "aria-pressed": focusProduct === null,
6778
+ onClick: () => onFocus(null),
6779
+ className: chipClass(focusProduct === null),
6780
+ children: "All products"
6781
+ }
6782
+ ),
6783
+ products.map((product) => /* @__PURE__ */ jsx(
6784
+ "button",
6785
+ {
6786
+ "data-boff-explore": "chip",
6787
+ "data-chip-kind": "product",
6788
+ "data-product": product.slug,
6789
+ type: "button",
6790
+ "aria-pressed": focusProduct === product.slug,
6791
+ title: product.tagline ?? product.name,
6792
+ onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
6793
+ className: chipClass(focusProduct === product.slug),
6794
+ children: product.name
6795
+ },
6796
+ product.slug
6797
+ ))
6798
+ ]
6799
+ }
6640
6800
  ),
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
- ] });
6801
+ products.length > 0 ? /* @__PURE__ */ jsx(
6802
+ "button",
6803
+ {
6804
+ type: "button",
6805
+ "data-boff-explore": "products-toggle",
6806
+ "aria-expanded": expanded,
6807
+ onClick: () => setExpanded((v) => !v),
6808
+ 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",
6809
+ children: expanded ? "Show less" : `All ${products.length}`
6810
+ }
6811
+ ) : null
6812
+ ]
6813
+ }
6814
+ );
6684
6815
  }
6685
6816
  function DisclaimerDialog({
6686
6817
  open,
6687
6818
  onClose,
6688
6819
  captchaOn
6689
6820
  }) {
6821
+ const panelRef = useRef(null);
6690
6822
  const closeRef = useRef(null);
6823
+ const titleId = "boff-explore-disclaimer-title";
6691
6824
  useEffect(() => {
6692
6825
  if (!open) return;
6826
+ const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
6827
+ const focusable = () => Array.from(
6828
+ panelRef.current?.querySelectorAll(
6829
+ 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
6830
+ ) ?? []
6831
+ );
6693
6832
  const onKey = (event) => {
6694
- if (event.key === "Escape") onClose();
6833
+ if (event.key === "Escape") {
6834
+ onClose();
6835
+ return;
6836
+ }
6837
+ if (event.key !== "Tab") return;
6838
+ const items = focusable();
6839
+ if (items.length === 0) return;
6840
+ const first = items[0];
6841
+ const last = items[items.length - 1];
6842
+ const active = document.activeElement;
6843
+ if (event.shiftKey && (active === first || !panelRef.current?.contains(active))) {
6844
+ event.preventDefault();
6845
+ last?.focus();
6846
+ } else if (!event.shiftKey && active === last) {
6847
+ event.preventDefault();
6848
+ first?.focus();
6849
+ }
6695
6850
  };
6696
6851
  document.addEventListener("keydown", onKey);
6697
6852
  closeRef.current?.focus();
6698
- return () => document.removeEventListener("keydown", onKey);
6853
+ return () => {
6854
+ document.removeEventListener("keydown", onKey);
6855
+ opener?.focus();
6856
+ };
6699
6857
  }, [open, onClose]);
6700
6858
  if (!open) return null;
6701
6859
  return /* @__PURE__ */ jsx(
@@ -6704,19 +6862,34 @@ function DisclaimerDialog({
6704
6862
  "data-boff-explore": "disclaimer-dialog",
6705
6863
  role: "dialog",
6706
6864
  "aria-modal": "true",
6707
- "aria-label": "How this assistant works",
6865
+ "aria-labelledby": titleId,
6708
6866
  className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
6709
6867
  onClick: onClose,
6710
6868
  children: /* @__PURE__ */ jsxs(
6711
6869
  "div",
6712
6870
  {
6871
+ ref: panelRef,
6713
6872
  className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
6714
6873
  onClick: (event) => event.stopPropagation(),
6715
6874
  children: [
6716
6875
  /* @__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" }) }),
6876
+ /* @__PURE__ */ jsx(
6877
+ "span",
6878
+ {
6879
+ "aria-hidden": "true",
6880
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",
6881
+ children: /* @__PURE__ */ jsx(TriangleAlert, { className: "h-4 w-4" })
6882
+ }
6883
+ ),
6718
6884
  /* @__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" }),
6885
+ /* @__PURE__ */ jsx(
6886
+ "p",
6887
+ {
6888
+ id: titleId,
6889
+ className: "text-sm font-semibold text-card-foreground",
6890
+ children: "How this assistant works"
6891
+ }
6892
+ ),
6720
6893
  /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
6721
6894
  /* @__PURE__ */ jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
6722
6895
  /* @__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." }),
@@ -6828,7 +7001,9 @@ function ExplorePage({
6828
7001
  history,
6829
7002
  openConversation,
6830
7003
  deleteConversation,
6831
- clearHistory
7004
+ clearHistory,
7005
+ recordClick,
7006
+ createShareLink
6832
7007
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
6833
7008
  const [draft, setDraft] = useState("");
6834
7009
  const textareaRef = useRef(null);
@@ -6848,6 +7023,7 @@ function ExplorePage({
6848
7023
  });
6849
7024
  speechStopRef.current = speech.stop;
6850
7025
  const [disclaimerOpen, setDisclaimerOpen] = useState(false);
7026
+ const [shareLabel, setShareLabel] = useState("Share");
6851
7027
  const scrollRef = useRef(null);
6852
7028
  const latestAssistantRef = useRef(null);
6853
7029
  const alignedForRef = useRef(null);
@@ -6902,6 +7078,25 @@ function ExplorePage({
6902
7078
  if (!el) return;
6903
7079
  el.scrollTop = el.scrollHeight;
6904
7080
  }, [activity, latestAssistantId, messages]);
7081
+ const handleShare = useCallback(async () => {
7082
+ setShareLabel("Copying\u2026");
7083
+ const token = await createShareLink();
7084
+ if (!token) {
7085
+ setShareLabel("Unavailable");
7086
+ setTimeout(() => setShareLabel("Share"), 2500);
7087
+ return;
7088
+ }
7089
+ const base = (pageUrl ?? window.location.href).split("?")[0];
7090
+ const url = `${base}?c=${encodeURIComponent(token)}`;
7091
+ try {
7092
+ await navigator.clipboard.writeText(url);
7093
+ setShareLabel("Copied");
7094
+ } catch {
7095
+ window.prompt("Copy this link", url);
7096
+ setShareLabel("Share");
7097
+ }
7098
+ setTimeout(() => setShareLabel("Share"), 2500);
7099
+ }, [createShareLink, pageUrl]);
6905
7100
  const submitDraft = useCallback(() => {
6906
7101
  const text = draft.trim();
6907
7102
  if (!text || overLimit || busy || !canSend) return;
@@ -6984,6 +7179,24 @@ function ExplorePage({
6984
7179
  ]
6985
7180
  }
6986
7181
  ),
7182
+ messages.length > 0 ? /* @__PURE__ */ jsxs(
7183
+ Button,
7184
+ {
7185
+ "data-boff-explore": "share",
7186
+ type: "button",
7187
+ size: "sm",
7188
+ variant: "ghost",
7189
+ className: "shrink-0 text-muted-foreground",
7190
+ title: "Copy a read-only link to this conversation",
7191
+ onClick: () => {
7192
+ void handleShare();
7193
+ },
7194
+ children: [
7195
+ /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" }),
7196
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: shareLabel })
7197
+ ]
7198
+ }
7199
+ ) : null,
6987
7200
  history.length > 0 ? /* @__PURE__ */ jsxs(
6988
7201
  Button,
6989
7202
  {
@@ -7102,7 +7315,9 @@ function ExplorePage({
7102
7315
  message,
7103
7316
  activity,
7104
7317
  onNavigate,
7105
- anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
7318
+ anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
7319
+ onFollow: (kind, url) => recordClick(message.id, kind, url),
7320
+ onFollowUp: sendPrompt
7106
7321
  },
7107
7322
  message.id
7108
7323
  )