@burdenoff/website-sdk 2026.829.1 → 2026.829.2

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.d.mts CHANGED
@@ -18,7 +18,7 @@ export { ProblemSolved, ProblemsSolvedSection, ProblemsSolvedSectionProps } from
18
18
  export { DetectedPlatform, ElectronDownloadLink, ElectronDownloadLinkProps, detectElectronPlatform } from './components/electron-download.mjs';
19
19
  export { ExplorePage, ExplorePageProps } from './components/explore.mjs';
20
20
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.mjs';
21
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, e as EXPLORE_CATALOG_QUERY, f as EXPLORE_MESSAGE_QUERY, g as ExploreCatalog, h as ExploreCatalogQueryData, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, i as ExploreConversation, j as ExploreCtaKind, k as ExploreCtaLink, l as ExploreErrorCode, m as ExploreLimits, n as ExploreMessage, o as ExploreMessageQueryData, p as ExploreMessageRole, q as ExploreMessageStatus, r as ExploreProduct, s as ExploreReference, F as FALLBACK_EXPLORE_LIMITS, S as SEND_EXPLORE_MESSAGE_MUTATION, t as SendExploreMessageInput, v as SendExploreMessageMutationData, w as SendExploreMessageResult, U as UseExploreChatOptions, c as UseExploreChatResult, d as classifyExploreError, u as useExploreChat } from './use-explore-chat-DhvZhH8f.mjs';
21
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, e as EXPLORE_CATALOG_QUERY, f as EXPLORE_MESSAGE_QUERY, g as ExploreCatalog, h as ExploreCatalogQueryData, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, i as ExploreConversation, j as ExploreCtaKind, k as ExploreCtaLink, l as ExploreErrorCode, m as ExploreLimits, n as ExploreMessage, o as ExploreMessageQueryData, p as ExploreMessageRole, q as ExploreMessageStatus, r as ExploreProduct, s as ExploreReference, F as FALLBACK_EXPLORE_LIMITS, S as SEND_EXPLORE_MESSAGE_MUTATION, t as SendExploreMessageInput, v as SendExploreMessageMutationData, w as SendExploreMessageResult, U as UseExploreChatOptions, c as UseExploreChatResult, d as classifyExploreError, u as useExploreChat } from './use-explore-chat-8eL7WdLc.mjs';
22
22
  export { RybbitAnalytics, RybbitAnalyticsProps } from './analytics/index.mjs';
23
23
  export { PageHead, PageHeadProps } from './seo/index.mjs';
24
24
  export { ProductData, ProductProvider, ProductProviderProps, useProduct, useProductConfig } from './product/index.mjs';
@@ -62,7 +62,7 @@ declare function CareersSubmissionForm({ productName, recaptchaSiteKey, postings
62
62
 
63
63
  declare const buttonVariants: (props?: ({
64
64
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
65
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
65
+ size?: "icon" | "default" | "sm" | "lg" | null | undefined;
66
66
  } & class_variance_authority_types.ClassProp) | undefined) => string;
67
67
  interface ButtonProps extends react.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
68
68
  asChild?: boolean;
package/dist/index.d.ts CHANGED
@@ -18,7 +18,7 @@ export { ProblemSolved, ProblemsSolvedSection, ProblemsSolvedSectionProps } from
18
18
  export { DetectedPlatform, ElectronDownloadLink, ElectronDownloadLinkProps, detectElectronPlatform } from './components/electron-download.js';
19
19
  export { ExplorePage, ExplorePageProps } from './components/explore.js';
20
20
  export { ExploreCta, ExploreCtaProps } from './components/explore-cta.js';
21
- export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, e as EXPLORE_CATALOG_QUERY, f as EXPLORE_MESSAGE_QUERY, g as ExploreCatalog, h as ExploreCatalogQueryData, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, i as ExploreConversation, j as ExploreCtaKind, k as ExploreCtaLink, l as ExploreErrorCode, m as ExploreLimits, n as ExploreMessage, o as ExploreMessageQueryData, p as ExploreMessageRole, q as ExploreMessageStatus, r as ExploreProduct, s as ExploreReference, F as FALLBACK_EXPLORE_LIMITS, S as SEND_EXPLORE_MESSAGE_MUTATION, t as SendExploreMessageInput, v as SendExploreMessageMutationData, w as SendExploreMessageResult, U as UseExploreChatOptions, c as UseExploreChatResult, d as classifyExploreError, u as useExploreChat } from './use-explore-chat-DhvZhH8f.js';
21
+ export { D as DEFAULT_EXPLORE_EXAMPLE_PROMPTS, e as EXPLORE_CATALOG_QUERY, f as EXPLORE_MESSAGE_QUERY, g as ExploreCatalog, h as ExploreCatalogQueryData, E as ExploreChatError, a as ExploreChatErrorKind, b as ExploreChatPhase, i as ExploreConversation, j as ExploreCtaKind, k as ExploreCtaLink, l as ExploreErrorCode, m as ExploreLimits, n as ExploreMessage, o as ExploreMessageQueryData, p as ExploreMessageRole, q as ExploreMessageStatus, r as ExploreProduct, s as ExploreReference, F as FALLBACK_EXPLORE_LIMITS, S as SEND_EXPLORE_MESSAGE_MUTATION, t as SendExploreMessageInput, v as SendExploreMessageMutationData, w as SendExploreMessageResult, U as UseExploreChatOptions, c as UseExploreChatResult, d as classifyExploreError, u as useExploreChat } from './use-explore-chat-8eL7WdLc.js';
22
22
  export { RybbitAnalytics, RybbitAnalyticsProps } from './analytics/index.js';
23
23
  export { PageHead, PageHeadProps } from './seo/index.js';
24
24
  export { ProductData, ProductProvider, ProductProviderProps, useProduct, useProductConfig } from './product/index.js';
@@ -62,7 +62,7 @@ declare function CareersSubmissionForm({ productName, recaptchaSiteKey, postings
62
62
 
63
63
  declare const buttonVariants: (props?: ({
64
64
  variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
65
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
65
+ size?: "icon" | "default" | "sm" | "lg" | null | undefined;
66
66
  } & class_variance_authority_types.ClassProp) | undefined) => string;
67
67
  interface ButtonProps extends react.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
68
68
  asChild?: boolean;
package/dist/index.js CHANGED
@@ -4959,6 +4959,7 @@ var EXPLORE_MESSAGE_FIELDS = (
4959
4959
  description
4960
4960
  product
4961
4961
  imageUrl
4962
+ index
4962
4963
  }
4963
4964
  ctas {
4964
4965
  kind
@@ -4966,6 +4967,8 @@ var EXPLORE_MESSAGE_FIELDS = (
4966
4967
  url
4967
4968
  product
4968
4969
  }
4970
+ followUps
4971
+ answered
4969
4972
  errorCode
4970
4973
  createdAt
4971
4974
  completedAt
@@ -5031,6 +5034,16 @@ var SEND_EXPLORE_MESSAGE_MUTATION = (
5031
5034
  }
5032
5035
  `
5033
5036
  );
5037
+ var RECORD_EXPLORE_CLICK_MUTATION = (
5038
+ /* GraphQL */
5039
+ `
5040
+ mutation RecordExploreClick($input: RecordExploreClickInput!) {
5041
+ recordExploreClick(input: $input) {
5042
+ recorded
5043
+ }
5044
+ }
5045
+ `
5046
+ );
5034
5047
 
5035
5048
  // src/data/products.ts
5036
5049
  var ECOSYSTEM_PRODUCTS = [
@@ -5963,6 +5976,20 @@ function useExploreChat(options = {}) {
5963
5976
  return null;
5964
5977
  }, [messages]);
5965
5978
  const canSend = (phase === "ready" || phase === "error") && catalog.enabled && turnCount < catalog.limits.maxTurnsPerConversation;
5979
+ const recordClick = React.useCallback(
5980
+ (messageId, kind, url) => {
5981
+ const token = conversationTokenRef.current;
5982
+ if (!token) return;
5983
+ try {
5984
+ void client.mutate(RECORD_EXPLORE_CLICK_MUTATION, {
5985
+ input: { conversationToken: token, messageId, kind, url }
5986
+ }).catch(() => {
5987
+ });
5988
+ } catch {
5989
+ }
5990
+ },
5991
+ [client]
5992
+ );
5966
5993
  return {
5967
5994
  phase,
5968
5995
  catalog,
@@ -5980,7 +6007,8 @@ function useExploreChat(options = {}) {
5980
6007
  history: archive,
5981
6008
  openConversation,
5982
6009
  deleteConversation,
5983
- clearHistory
6010
+ clearHistory,
6011
+ recordClick
5984
6012
  };
5985
6013
  }
5986
6014
  var optimisticCounter = 0;
@@ -6352,7 +6380,10 @@ function logoUrlOf(url) {
6352
6380
  return null;
6353
6381
  }
6354
6382
  }
6355
- function ReferenceCard({ reference }) {
6383
+ function ReferenceCard({
6384
+ reference,
6385
+ onFollow
6386
+ }) {
6356
6387
  const [imageFailed, setImageFailed] = React.useState(false);
6357
6388
  const [logoFailed, setLogoFailed] = React.useState(false);
6358
6389
  const host = hostnameOf(reference.url);
@@ -6374,9 +6405,11 @@ function ReferenceCard({ reference }) {
6374
6405
  "a",
6375
6406
  {
6376
6407
  "data-boff-explore": "reference",
6408
+ "data-index": reference.index ?? void 0,
6377
6409
  href: reference.url,
6378
6410
  target: "_blank",
6379
6411
  rel: "noopener noreferrer",
6412
+ onClick: () => onFollow?.(reference.url),
6380
6413
  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",
6381
6414
  children: [
6382
6415
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-11 w-11 shrink-0 overflow-hidden rounded-lg bg-muted sm:hidden", children: logoImg }),
@@ -6400,7 +6433,10 @@ function ReferenceCard({ reference }) {
6400
6433
  }
6401
6434
  ) }) : letterPlate }),
6402
6435
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:gap-1.5 sm:p-3", children: [
6403
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: reference.title || host || reference.url }),
6436
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "line-clamp-2 text-sm font-semibold leading-snug text-card-foreground", children: [
6437
+ 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,
6438
+ reference.title || host || reference.url
6439
+ ] }),
6404
6440
  reference.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground max-sm:hidden", children: reference.description }) : null,
6405
6441
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:mt-auto sm:pt-2", children: [
6406
6442
  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,
@@ -6416,7 +6452,8 @@ function ReferenceCard({ reference }) {
6416
6452
  }
6417
6453
  function CtaButton({
6418
6454
  cta,
6419
- onNavigate
6455
+ onNavigate,
6456
+ onFollow
6420
6457
  }) {
6421
6458
  const variant = CTA_VARIANTS[cta.kind] ?? "outline";
6422
6459
  const internal = isInternalPath(cta.url);
@@ -6429,7 +6466,10 @@ function CtaButton({
6429
6466
  type: "button",
6430
6467
  size: "sm",
6431
6468
  variant,
6432
- onClick: () => onNavigate(cta.url),
6469
+ onClick: () => {
6470
+ onFollow?.(cta.url);
6471
+ onNavigate(cta.url);
6472
+ },
6433
6473
  children: cta.label
6434
6474
  }
6435
6475
  );
@@ -6440,6 +6480,7 @@ function CtaButton({
6440
6480
  "data-boff-explore": "cta",
6441
6481
  "data-kind": cta.kind,
6442
6482
  href: cta.url,
6483
+ onClick: () => onFollow?.(cta.url),
6443
6484
  ...internal ? {} : { target: "_blank", rel: "noopener noreferrer" },
6444
6485
  children: [
6445
6486
  cta.label,
@@ -6491,7 +6532,9 @@ function AssistantBubble({
6491
6532
  message,
6492
6533
  activity,
6493
6534
  onNavigate,
6494
- anchorRef
6535
+ anchorRef,
6536
+ onFollow,
6537
+ onFollowUp
6495
6538
  }) {
6496
6539
  const streaming = message.status === "PENDING" || message.status === "RUNNING";
6497
6540
  const body = message.content || message.partialContent || "";
@@ -6513,6 +6556,34 @@ function AssistantBubble({
6513
6556
  }
6514
6557
  ),
6515
6558
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
6559
+ message.status === "COMPLETED" && message.answered === false ? /* @__PURE__ */ jsxRuntime.jsxs(
6560
+ "div",
6561
+ {
6562
+ "data-boff-explore": "no-answer",
6563
+ 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",
6564
+ children: [
6565
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" }),
6566
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6567
+ "I couldn't find this in our documentation, so the answer below is not grounded in a source. Try rephrasing, or",
6568
+ " ",
6569
+ /* @__PURE__ */ jsxRuntime.jsx(
6570
+ "a",
6571
+ {
6572
+ href: "/contact",
6573
+ className: "underline underline-offset-2 hover:text-primary",
6574
+ onClick: (event) => {
6575
+ if (!onNavigate) return;
6576
+ event.preventDefault();
6577
+ onNavigate("/contact");
6578
+ },
6579
+ children: "ask a human"
6580
+ }
6581
+ ),
6582
+ "."
6583
+ ] })
6584
+ ]
6585
+ }
6586
+ ) : null,
6516
6587
  body ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
6517
6588
  /* @__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 }) }),
6518
6589
  streaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
@@ -6521,16 +6592,41 @@ function AssistantBubble({
6521
6592
  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,
6522
6593
  message.references.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6523
6594
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Sources" }),
6524
- /* @__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(ReferenceCard, { reference }, reference.url)) })
6595
+ /* @__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(
6596
+ ReferenceCard,
6597
+ {
6598
+ reference,
6599
+ onFollow: (url) => onFollow?.("REFERENCE", url)
6600
+ },
6601
+ reference.url
6602
+ )) })
6525
6603
  ] }) : null,
6526
6604
  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(
6527
6605
  CtaButton,
6528
6606
  {
6529
6607
  cta,
6530
- onNavigate
6608
+ onNavigate,
6609
+ onFollow: (url) => onFollow?.("CTA", url)
6531
6610
  },
6532
6611
  `${cta.kind}-${cta.url}`
6533
- )) }) : null
6612
+ )) }) : null,
6613
+ message.status === "COMPLETED" && (message.followUps?.length ?? 0) > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 pt-0.5", children: [
6614
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Next you could ask" }),
6615
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: (message.followUps ?? []).map((question) => /* @__PURE__ */ jsxRuntime.jsxs(
6616
+ "button",
6617
+ {
6618
+ "data-boff-explore": "follow-up",
6619
+ type: "button",
6620
+ onClick: () => onFollowUp?.(question),
6621
+ 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",
6622
+ children: [
6623
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: question }),
6624
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3 w-3 shrink-0 rotate-45 text-muted-foreground transition-colors group-hover:text-primary" })
6625
+ ]
6626
+ },
6627
+ question
6628
+ )) })
6629
+ ] }) : null
6534
6630
  ] })
6535
6631
  ]
6536
6632
  }
@@ -6604,6 +6700,9 @@ function PromptCarousel({
6604
6700
  "div",
6605
6701
  {
6606
6702
  className: "flex min-w-0 items-center gap-1.5",
6703
+ role: "group",
6704
+ "aria-roledescription": "carousel",
6705
+ "aria-label": "Example questions",
6607
6706
  onMouseEnter: () => setPaused(true),
6608
6707
  onMouseLeave: () => setPaused(false),
6609
6708
  onFocusCapture: () => setPaused(true),
@@ -6626,6 +6725,8 @@ function PromptCarousel({
6626
6725
  "data-chip-kind": "prompt",
6627
6726
  type: "button",
6628
6727
  disabled,
6728
+ "aria-label": `Ask: ${current}`,
6729
+ "aria-live": paused ? "polite" : "off",
6629
6730
  onClick: () => onPrompt(current),
6630
6731
  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",
6631
6732
  children: [
@@ -6660,72 +6761,108 @@ function ProductStrip({
6660
6761
  "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",
6661
6762
  active ? "border-primary bg-primary text-primary-foreground" : "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground"
6662
6763
  );
6663
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
6664
- /* @__PURE__ */ jsxRuntime.jsxs(
6665
- "div",
6666
- {
6667
- className: cn(
6668
- "boff-explore-strip flex min-w-0 flex-1 gap-2",
6669
- expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
6764
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6765
+ "div",
6766
+ {
6767
+ className: "flex min-w-0 items-center gap-2",
6768
+ role: "group",
6769
+ "aria-label": "Focus the assistant on one product",
6770
+ children: [
6771
+ /* @__PURE__ */ jsxRuntime.jsxs(
6772
+ "div",
6773
+ {
6774
+ className: cn(
6775
+ "boff-explore-strip flex min-w-0 flex-1 gap-2",
6776
+ expanded ? "flex-wrap" : "flex-nowrap overflow-x-auto"
6777
+ ),
6778
+ children: [
6779
+ /* @__PURE__ */ jsxRuntime.jsx(
6780
+ "button",
6781
+ {
6782
+ "data-boff-explore": "chip",
6783
+ "data-chip-kind": "product",
6784
+ "data-product": "all",
6785
+ type: "button",
6786
+ "aria-pressed": focusProduct === null,
6787
+ onClick: () => onFocus(null),
6788
+ className: chipClass(focusProduct === null),
6789
+ children: "All products"
6790
+ }
6791
+ ),
6792
+ products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
6793
+ "button",
6794
+ {
6795
+ "data-boff-explore": "chip",
6796
+ "data-chip-kind": "product",
6797
+ "data-product": product.slug,
6798
+ type: "button",
6799
+ "aria-pressed": focusProduct === product.slug,
6800
+ title: product.tagline ?? product.name,
6801
+ onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
6802
+ className: chipClass(focusProduct === product.slug),
6803
+ children: product.name
6804
+ },
6805
+ product.slug
6806
+ ))
6807
+ ]
6808
+ }
6670
6809
  ),
6671
- children: [
6672
- /* @__PURE__ */ jsxRuntime.jsx(
6673
- "button",
6674
- {
6675
- "data-boff-explore": "chip",
6676
- "data-chip-kind": "product",
6677
- "data-product": "all",
6678
- type: "button",
6679
- "aria-pressed": focusProduct === null,
6680
- onClick: () => onFocus(null),
6681
- className: chipClass(focusProduct === null),
6682
- children: "All products"
6683
- }
6684
- ),
6685
- products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
6686
- "button",
6687
- {
6688
- "data-boff-explore": "chip",
6689
- "data-chip-kind": "product",
6690
- "data-product": product.slug,
6691
- type: "button",
6692
- "aria-pressed": focusProduct === product.slug,
6693
- title: product.tagline ?? product.name,
6694
- onClick: () => onFocus(focusProduct === product.slug ? null : product.slug),
6695
- className: chipClass(focusProduct === product.slug),
6696
- children: product.name
6697
- },
6698
- product.slug
6699
- ))
6700
- ]
6701
- }
6702
- ),
6703
- products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6704
- "button",
6705
- {
6706
- type: "button",
6707
- "data-boff-explore": "products-toggle",
6708
- onClick: () => setExpanded((v) => !v),
6709
- 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",
6710
- children: expanded ? "Show less" : `All ${products.length}`
6711
- }
6712
- ) : null
6713
- ] });
6810
+ products.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6811
+ "button",
6812
+ {
6813
+ type: "button",
6814
+ "data-boff-explore": "products-toggle",
6815
+ "aria-expanded": expanded,
6816
+ onClick: () => setExpanded((v) => !v),
6817
+ 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",
6818
+ children: expanded ? "Show less" : `All ${products.length}`
6819
+ }
6820
+ ) : null
6821
+ ]
6822
+ }
6823
+ );
6714
6824
  }
6715
6825
  function DisclaimerDialog({
6716
6826
  open,
6717
6827
  onClose,
6718
6828
  captchaOn
6719
6829
  }) {
6830
+ const panelRef = React.useRef(null);
6720
6831
  const closeRef = React.useRef(null);
6832
+ const titleId = "boff-explore-disclaimer-title";
6721
6833
  React.useEffect(() => {
6722
6834
  if (!open) return;
6835
+ const opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
6836
+ const focusable = () => Array.from(
6837
+ panelRef.current?.querySelectorAll(
6838
+ 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
6839
+ ) ?? []
6840
+ );
6723
6841
  const onKey = (event) => {
6724
- if (event.key === "Escape") onClose();
6842
+ if (event.key === "Escape") {
6843
+ onClose();
6844
+ return;
6845
+ }
6846
+ if (event.key !== "Tab") return;
6847
+ const items = focusable();
6848
+ if (items.length === 0) return;
6849
+ const first = items[0];
6850
+ const last = items[items.length - 1];
6851
+ const active = document.activeElement;
6852
+ if (event.shiftKey && (active === first || !panelRef.current?.contains(active))) {
6853
+ event.preventDefault();
6854
+ last?.focus();
6855
+ } else if (!event.shiftKey && active === last) {
6856
+ event.preventDefault();
6857
+ first?.focus();
6858
+ }
6725
6859
  };
6726
6860
  document.addEventListener("keydown", onKey);
6727
6861
  closeRef.current?.focus();
6728
- return () => document.removeEventListener("keydown", onKey);
6862
+ return () => {
6863
+ document.removeEventListener("keydown", onKey);
6864
+ opener?.focus();
6865
+ };
6729
6866
  }, [open, onClose]);
6730
6867
  if (!open) return null;
6731
6868
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -6734,19 +6871,34 @@ function DisclaimerDialog({
6734
6871
  "data-boff-explore": "disclaimer-dialog",
6735
6872
  role: "dialog",
6736
6873
  "aria-modal": "true",
6737
- "aria-label": "How this assistant works",
6874
+ "aria-labelledby": titleId,
6738
6875
  className: "fixed inset-0 z-50 flex items-end justify-center bg-foreground/40 p-4 backdrop-blur-sm sm:items-center",
6739
6876
  onClick: onClose,
6740
6877
  children: /* @__PURE__ */ jsxRuntime.jsxs(
6741
6878
  "div",
6742
6879
  {
6880
+ ref: panelRef,
6743
6881
  className: "w-full max-w-md rounded-2xl border border-border bg-card p-5 shadow-xl",
6744
6882
  onClick: (event) => event.stopPropagation(),
6745
6883
  children: [
6746
6884
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
6747
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-4 w-4" }) }),
6885
+ /* @__PURE__ */ jsxRuntime.jsx(
6886
+ "span",
6887
+ {
6888
+ "aria-hidden": "true",
6889
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary",
6890
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-4 w-4" })
6891
+ }
6892
+ ),
6748
6893
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
6749
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-card-foreground", children: "How this assistant works" }),
6894
+ /* @__PURE__ */ jsxRuntime.jsx(
6895
+ "p",
6896
+ {
6897
+ id: titleId,
6898
+ className: "text-sm font-semibold text-card-foreground",
6899
+ children: "How this assistant works"
6900
+ }
6901
+ ),
6750
6902
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 space-y-2 text-xs leading-relaxed text-muted-foreground", children: [
6751
6903
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Answers are generated from our public documentation and can be imperfect \u2014 check anything important against the linked sources." }),
6752
6904
  /* @__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." }),
@@ -6858,7 +7010,8 @@ function ExplorePage({
6858
7010
  history,
6859
7011
  openConversation,
6860
7012
  deleteConversation,
6861
- clearHistory
7013
+ clearHistory,
7014
+ recordClick
6862
7015
  } = useExploreChat({ productSlug, pageUrl, onSend, examplePrompts });
6863
7016
  const [draft, setDraft] = React.useState("");
6864
7017
  const textareaRef = React.useRef(null);
@@ -7132,7 +7285,9 @@ function ExplorePage({
7132
7285
  message,
7133
7286
  activity,
7134
7287
  onNavigate,
7135
- anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0
7288
+ anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
7289
+ onFollow: (kind, url) => recordClick(message.id, kind, url),
7290
+ onFollowUp: sendPrompt
7136
7291
  },
7137
7292
  message.id
7138
7293
  )