@burdenoff/website-sdk 2026.922.3 → 2026.922.5
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.d.mts +92 -2
- package/dist/components/explore.d.ts +92 -2
- package/dist/components/explore.js +1171 -17
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +1169 -20
- package/dist/components/explore.mjs.map +1 -1
- package/dist/{explore-types-CPF1QoMn.d.mts → explore-types-DvQPiL1t.d.mts} +58 -2
- package/dist/{explore-types-CPF1QoMn.d.ts → explore-types-DvQPiL1t.d.ts} +58 -2
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +417 -8
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +415 -9
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +53 -3
- package/dist/index.d.ts +53 -3
- package/dist/index.js +1179 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1177 -28
- package/dist/index.mjs.map +1 -1
- package/dist/{use-explore-chat--CxNtkrJ.d.ts → use-progressive-reveal-BfU_IHip.d.ts} +36 -2
- package/dist/{use-explore-chat-C6Y8JQMj.d.mts → use-progressive-reveal-Ha3gYPfs.d.mts} +36 -2
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version } from 'react';
|
|
2
|
+
import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect, useId, version, Children, isValidElement, cloneElement } 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, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Info, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, ExternalLink, ThumbsUp, ThumbsDown } from 'lucide-react';
|
|
4
|
+
import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, ImageIcon, ChevronRight, Maximize2, Check, ArrowLeft, Sparkles, RotateCcw, Link2, History, Trash2, Paperclip, X, Mic, Square, ArrowUp, Info, ChevronLeft, BookOpenText, Layers, TriangleAlert, FileText, ExternalLink, Copy, ThumbsUp, ThumbsDown, Volume2 } 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';
|
|
@@ -2408,16 +2408,16 @@ function useRateLimit(maxAttempts, windowMinutes) {
|
|
|
2408
2408
|
}
|
|
2409
2409
|
}, [maxAttempts]);
|
|
2410
2410
|
function recordAttempt() {
|
|
2411
|
-
const
|
|
2411
|
+
const now2 = Date.now();
|
|
2412
2412
|
const state = rateLimitRef.current;
|
|
2413
|
-
if (state &&
|
|
2413
|
+
if (state && now2 > state.resetTime) {
|
|
2414
2414
|
rateLimitRef.current = null;
|
|
2415
2415
|
}
|
|
2416
2416
|
const current = rateLimitRef.current;
|
|
2417
2417
|
if (!current) {
|
|
2418
2418
|
rateLimitRef.current = {
|
|
2419
2419
|
attempts: 1,
|
|
2420
|
-
resetTime:
|
|
2420
|
+
resetTime: now2 + windowMinutes * 60 * 1e3
|
|
2421
2421
|
};
|
|
2422
2422
|
return false;
|
|
2423
2423
|
}
|
|
@@ -3512,16 +3512,16 @@ function useRateLimit2(maxAttempts, windowMinutes) {
|
|
|
3512
3512
|
const [isLimited, setIsLimited] = useState(false);
|
|
3513
3513
|
const [resetTime, setResetTime] = useState(null);
|
|
3514
3514
|
function recordAttempt() {
|
|
3515
|
-
const
|
|
3515
|
+
const now2 = Date.now();
|
|
3516
3516
|
const state = rateLimitRef.current;
|
|
3517
|
-
if (state &&
|
|
3517
|
+
if (state && now2 > state.resetTime) {
|
|
3518
3518
|
rateLimitRef.current = null;
|
|
3519
3519
|
}
|
|
3520
3520
|
const current = rateLimitRef.current;
|
|
3521
3521
|
if (!current) {
|
|
3522
3522
|
rateLimitRef.current = {
|
|
3523
3523
|
attempts: 1,
|
|
3524
|
-
resetTime:
|
|
3524
|
+
resetTime: now2 + windowMinutes * 60 * 1e3
|
|
3525
3525
|
};
|
|
3526
3526
|
return false;
|
|
3527
3527
|
}
|
|
@@ -4555,8 +4555,8 @@ function LaunchCountdown({
|
|
|
4555
4555
|
launchedMessage = "We have launched!",
|
|
4556
4556
|
className
|
|
4557
4557
|
}) {
|
|
4558
|
-
const [
|
|
4559
|
-
const remainingMs = launchDate -
|
|
4558
|
+
const [now2, setNow] = useState(() => Date.now());
|
|
4559
|
+
const remainingMs = launchDate - now2;
|
|
4560
4560
|
const hasLaunched = remainingMs <= 0;
|
|
4561
4561
|
useEffect(() => {
|
|
4562
4562
|
if (hasLaunched) return;
|
|
@@ -5974,6 +5974,23 @@ var EN = {
|
|
|
5974
5974
|
nextSuggestion: "Next suggestion",
|
|
5975
5975
|
conceptIllustration: "Concept illustration",
|
|
5976
5976
|
opensInNewTab: "opens in a new tab",
|
|
5977
|
+
conceptStripTitle: "Or start from a concept",
|
|
5978
|
+
conceptStripLabel: "Concepts you can ask about",
|
|
5979
|
+
conceptAsk: "Ask about {title} in {product}",
|
|
5980
|
+
conceptAskQuestion: "How does {title} work in {product}?",
|
|
5981
|
+
copyAnswer: "Copy answer",
|
|
5982
|
+
copyFailed: "Couldn't copy",
|
|
5983
|
+
readAloud: "Read aloud",
|
|
5984
|
+
stopReading: "Stop reading",
|
|
5985
|
+
answerTable: "Table",
|
|
5986
|
+
groundedIn: "What this answer is based on",
|
|
5987
|
+
sourceCountOne: "1 source",
|
|
5988
|
+
sourceCountMany: "{count} sources",
|
|
5989
|
+
sourceKindConcept: "Concept",
|
|
5990
|
+
sourceKindDocs: "Documentation",
|
|
5991
|
+
sourceKindPricing: "Pricing",
|
|
5992
|
+
sourceKindUseCase: "Use case",
|
|
5993
|
+
sourceKindPage: "Product page",
|
|
5977
5994
|
seoTitle: "Describe a problem, get an answer",
|
|
5978
5995
|
seoDescription: "Describe the problem you're facing in your own words and get an answer drawn from our product documentation, with links to the exact pages it came from.",
|
|
5979
5996
|
seoDescriptionProduct: "Describe the problem you're facing in your own words and get an answer drawn from {product}'s documentation \u2014 and every other product we build \u2014 with links to the exact pages it came from.",
|
|
@@ -6042,6 +6059,23 @@ var ZH = {
|
|
|
6042
6059
|
nextSuggestion: "\u4E0B\u4E00\u4E2A\u5EFA\u8BAE",
|
|
6043
6060
|
conceptIllustration: "\u6982\u5FF5\u793A\u610F\u56FE",
|
|
6044
6061
|
opensInNewTab: "\u5728\u65B0\u6807\u7B7E\u9875\u4E2D\u6253\u5F00",
|
|
6062
|
+
conceptStripTitle: "\u6216\u8005\u4ECE\u4E00\u4E2A\u6982\u5FF5\u5F00\u59CB",
|
|
6063
|
+
conceptStripLabel: "\u4F60\u53EF\u4EE5\u8BE2\u95EE\u7684\u6982\u5FF5",
|
|
6064
|
+
conceptAsk: "\u8BE2\u95EE {product} \u4E2D\u7684 {title}",
|
|
6065
|
+
conceptAskQuestion: "{product} \u7684 {title} \u662F\u600E\u4E48\u8FD0\u4F5C\u7684\uFF1F",
|
|
6066
|
+
copyAnswer: "\u590D\u5236\u56DE\u7B54",
|
|
6067
|
+
copyFailed: "\u590D\u5236\u5931\u8D25",
|
|
6068
|
+
readAloud: "\u6717\u8BFB",
|
|
6069
|
+
stopReading: "\u505C\u6B62\u6717\u8BFB",
|
|
6070
|
+
answerTable: "\u8868\u683C",
|
|
6071
|
+
groundedIn: "\u8FD9\u4E2A\u56DE\u7B54\u7684\u4F9D\u636E",
|
|
6072
|
+
sourceCountOne: "1 \u4E2A\u6765\u6E90",
|
|
6073
|
+
sourceCountMany: "{count} \u4E2A\u6765\u6E90",
|
|
6074
|
+
sourceKindConcept: "\u6982\u5FF5",
|
|
6075
|
+
sourceKindDocs: "\u6587\u6863",
|
|
6076
|
+
sourceKindPricing: "\u4EF7\u683C",
|
|
6077
|
+
sourceKindUseCase: "\u5E94\u7528\u573A\u666F",
|
|
6078
|
+
sourceKindPage: "\u4EA7\u54C1\u9875\u9762",
|
|
6045
6079
|
seoTitle: "\u63CF\u8FF0\u95EE\u9898\uFF0C\u83B7\u5F97\u7B54\u6848",
|
|
6046
6080
|
seoDescription: "\u7528\u4F60\u81EA\u5DF1\u7684\u8BDD\u63CF\u8FF0\u9047\u5230\u7684\u95EE\u9898\uFF0C\u5373\u53EF\u83B7\u5F97\u6765\u81EA\u6211\u4EEC\u4EA7\u54C1\u6587\u6863\u7684\u56DE\u7B54\uFF0C\u5E76\u9644\u4E0A\u7B54\u6848\u51FA\u5904\u7684\u9875\u9762\u94FE\u63A5\u3002",
|
|
6047
6081
|
seoDescriptionProduct: "\u7528\u4F60\u81EA\u5DF1\u7684\u8BDD\u63CF\u8FF0\u9047\u5230\u7684\u95EE\u9898\uFF0C\u5373\u53EF\u83B7\u5F97\u6765\u81EA {product} \u53CA\u6211\u4EEC\u5176\u4ED6\u4EA7\u54C1\u6587\u6863\u7684\u56DE\u7B54\uFF0C\u5E76\u9644\u4E0A\u7B54\u6848\u51FA\u5904\u7684\u9875\u9762\u94FE\u63A5\u3002",
|
|
@@ -6106,6 +6140,23 @@ var HI = {
|
|
|
6106
6140
|
nextSuggestion: "\u0905\u0917\u0932\u093E \u0938\u0941\u091D\u093E\u0935",
|
|
6107
6141
|
conceptIllustration: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E \u091A\u093F\u0924\u094D\u0930\u0923",
|
|
6108
6142
|
opensInNewTab: "\u0928\u090F \u091F\u0948\u092C \u092E\u0947\u0902 \u0916\u0941\u0932\u0924\u093E \u0939\u0948",
|
|
6143
|
+
conceptStripTitle: "\u092F\u093E \u0915\u093F\u0938\u0940 \u0905\u0935\u0927\u093E\u0930\u0923\u093E \u0938\u0947 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
|
|
6144
|
+
conceptStripLabel: "\u091C\u093F\u0928 \u0905\u0935\u0927\u093E\u0930\u0923\u093E\u0913\u0902 \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0906\u092A \u092A\u0942\u091B \u0938\u0915\u0924\u0947 \u0939\u0948\u0902",
|
|
6145
|
+
conceptAsk: "{product} \u092E\u0947\u0902 {title} \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u092A\u0942\u091B\u0947\u0902",
|
|
6146
|
+
conceptAskQuestion: "{product} \u092E\u0947\u0902 {title} \u0915\u0948\u0938\u0947 \u0915\u093E\u092E \u0915\u0930\u0924\u093E \u0939\u0948?",
|
|
6147
|
+
copyAnswer: "\u0909\u0924\u094D\u0924\u0930 \u0915\u0949\u092A\u0940 \u0915\u0930\u0947\u0902",
|
|
6148
|
+
copyFailed: "\u0915\u0949\u092A\u0940 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E",
|
|
6149
|
+
readAloud: "\u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0902",
|
|
6150
|
+
stopReading: "\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
6151
|
+
answerTable: "\u0924\u093E\u0932\u093F\u0915\u093E",
|
|
6152
|
+
groundedIn: "\u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u0915\u093F\u0938 \u092A\u0930 \u0906\u0927\u093E\u0930\u093F\u0924 \u0939\u0948",
|
|
6153
|
+
sourceCountOne: "1 \u0938\u094D\u0930\u094B\u0924",
|
|
6154
|
+
sourceCountMany: "{count} \u0938\u094D\u0930\u094B\u0924",
|
|
6155
|
+
sourceKindConcept: "\u0905\u0935\u0927\u093E\u0930\u0923\u093E",
|
|
6156
|
+
sourceKindDocs: "\u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C",
|
|
6157
|
+
sourceKindPricing: "\u092E\u0942\u0932\u094D\u092F",
|
|
6158
|
+
sourceKindUseCase: "\u0909\u092A\u092F\u094B\u0917 \u0915\u093E \u0909\u0926\u093E\u0939\u0930\u0923",
|
|
6159
|
+
sourceKindPage: "\u0909\u0924\u094D\u092A\u093E\u0926 \u092A\u0947\u091C",
|
|
6109
6160
|
seoTitle: "\u0938\u092E\u0938\u094D\u092F\u093E \u092C\u0924\u093E\u090F\u0902, \u091C\u0935\u093E\u092C \u092A\u093E\u090F\u0902",
|
|
6110
6161
|
seoDescription: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u0905\u092A\u0928\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092C\u0924\u093E\u090F\u0902 \u0914\u0930 \u0939\u092E\u093E\u0930\u0947 \u0909\u0924\u094D\u092A\u093E\u0926 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u0938\u0947 \u0932\u093F\u092F\u093E \u0917\u092F\u093E \u091C\u0935\u093E\u092C \u092A\u093E\u090F\u0902, \u0938\u093E\u0925 \u092E\u0947\u0902 \u0909\u0928\u094D\u0939\u0940\u0902 \u092A\u0928\u094D\u0928\u094B\u0902 \u0915\u0947 \u0932\u093F\u0902\u0915 \u091C\u0939\u093E\u0901 \u0938\u0947 \u0935\u0939 \u0906\u092F\u093E \u0939\u0948\u0964",
|
|
6111
6162
|
seoDescriptionProduct: "\u0905\u092A\u0928\u0940 \u0938\u092E\u0938\u094D\u092F\u093E \u0905\u092A\u0928\u0947 \u0936\u092C\u094D\u0926\u094B\u0902 \u092E\u0947\u0902 \u092C\u0924\u093E\u090F\u0902 \u0914\u0930 {product} \u0924\u0925\u093E \u0939\u092E\u093E\u0930\u0947 \u092C\u093E\u0915\u0940 \u0909\u0924\u094D\u092A\u093E\u0926\u094B\u0902 \u0915\u0947 \u0926\u0938\u094D\u0924\u093E\u0935\u0947\u091C\u093C\u094B\u0902 \u0938\u0947 \u0932\u093F\u092F\u093E \u0917\u092F\u093E \u091C\u0935\u093E\u092C \u092A\u093E\u090F\u0902, \u0938\u093E\u0925 \u092E\u0947\u0902 \u0909\u0928\u094D\u0939\u0940\u0902 \u092A\u0928\u094D\u0928\u094B\u0902 \u0915\u0947 \u0932\u093F\u0902\u0915 \u091C\u0939\u093E\u0901 \u0938\u0947 \u0935\u0939 \u0906\u092F\u093E \u0939\u0948\u0964",
|
|
@@ -6174,6 +6225,23 @@ var ES = {
|
|
|
6174
6225
|
nextSuggestion: "Sugerencia siguiente",
|
|
6175
6226
|
conceptIllustration: "Ilustraci\xF3n del concepto",
|
|
6176
6227
|
opensInNewTab: "se abre en una pesta\xF1a nueva",
|
|
6228
|
+
conceptStripTitle: "O empieza por un concepto",
|
|
6229
|
+
conceptStripLabel: "Conceptos sobre los que puedes preguntar",
|
|
6230
|
+
conceptAsk: "Preguntar por {title} en {product}",
|
|
6231
|
+
conceptAskQuestion: "\xBFC\xF3mo funciona {title} en {product}?",
|
|
6232
|
+
copyAnswer: "Copiar respuesta",
|
|
6233
|
+
copyFailed: "No se pudo copiar",
|
|
6234
|
+
readAloud: "Leer en voz alta",
|
|
6235
|
+
stopReading: "Dejar de leer",
|
|
6236
|
+
answerTable: "Tabla",
|
|
6237
|
+
groundedIn: "En qu\xE9 se basa esta respuesta",
|
|
6238
|
+
sourceCountOne: "1 fuente",
|
|
6239
|
+
sourceCountMany: "{count} fuentes",
|
|
6240
|
+
sourceKindConcept: "Concepto",
|
|
6241
|
+
sourceKindDocs: "Documentaci\xF3n",
|
|
6242
|
+
sourceKindPricing: "Precios",
|
|
6243
|
+
sourceKindUseCase: "Caso de uso",
|
|
6244
|
+
sourceKindPage: "P\xE1gina de producto",
|
|
6177
6245
|
seoTitle: "Describe un problema y obt\xE9n una respuesta",
|
|
6178
6246
|
seoDescription: "Describe con tus palabras el problema que tienes y recibe una respuesta extra\xEDda de la documentaci\xF3n de nuestros productos, con enlaces a las p\xE1ginas exactas de las que procede.",
|
|
6179
6247
|
seoDescriptionProduct: "Describe con tus palabras el problema que tienes y recibe una respuesta extra\xEDda de la documentaci\xF3n de {product} y del resto de nuestros productos, con enlaces a las p\xE1ginas exactas de las que procede.",
|
|
@@ -6242,6 +6310,23 @@ var AR = {
|
|
|
6242
6310
|
nextSuggestion: "\u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D \u0627\u0644\u062A\u0627\u0644\u064A",
|
|
6243
6311
|
conceptIllustration: "\u0631\u0633\u0645 \u062A\u0648\u0636\u064A\u062D\u064A \u0644\u0644\u0645\u0641\u0647\u0648\u0645",
|
|
6244
6312
|
opensInNewTab: "\u064A\u064F\u0641\u062A\u062D \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u062C\u062F\u064A\u062F\u0629",
|
|
6313
|
+
conceptStripTitle: "\u0623\u0648 \u0627\u0628\u062F\u0623 \u0645\u0646 \u0645\u0641\u0647\u0648\u0645",
|
|
6314
|
+
conceptStripLabel: "\u0645\u0641\u0627\u0647\u064A\u0645 \u064A\u0645\u0643\u0646\u0643 \u0627\u0644\u0633\u0624\u0627\u0644 \u0639\u0646\u0647\u0627",
|
|
6315
|
+
conceptAsk: "\u0627\u0633\u0623\u0644 \u0639\u0646 {title} \u0641\u064A {product}",
|
|
6316
|
+
conceptAskQuestion: "\u0643\u064A\u0641 \u064A\u0639\u0645\u0644 {title} \u0641\u064A {product}\u061F",
|
|
6317
|
+
copyAnswer: "\u0646\u0633\u062E \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
|
|
6318
|
+
copyFailed: "\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0646\u0633\u062E",
|
|
6319
|
+
readAloud: "\u0627\u0642\u0631\u0623 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D",
|
|
6320
|
+
stopReading: "\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0642\u0631\u0627\u0621\u0629",
|
|
6321
|
+
answerTable: "\u062C\u062F\u0648\u0644",
|
|
6322
|
+
groundedIn: "\u0639\u0644\u0649 \u0645\u0627\u0630\u0627 \u062A\u0633\u062A\u0646\u062F \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629",
|
|
6323
|
+
sourceCountOne: "\u0645\u0635\u062F\u0631 \u0648\u0627\u062D\u062F",
|
|
6324
|
+
sourceCountMany: "{count} \u0645\u0635\u0627\u062F\u0631",
|
|
6325
|
+
sourceKindConcept: "\u0645\u0641\u0647\u0648\u0645",
|
|
6326
|
+
sourceKindDocs: "\u0627\u0644\u062A\u0648\u062B\u064A\u0642",
|
|
6327
|
+
sourceKindPricing: "\u0627\u0644\u0623\u0633\u0639\u0627\u0631",
|
|
6328
|
+
sourceKindUseCase: "\u062D\u0627\u0644\u0629 \u0627\u0633\u062A\u062E\u062F\u0627\u0645",
|
|
6329
|
+
sourceKindPage: "\u0635\u0641\u062D\u0629 \u0627\u0644\u0645\u0646\u062A\u062C",
|
|
6245
6330
|
seoTitle: "\u0635\u0641 \u0645\u0634\u0643\u0644\u062A\u0643 \u0648\u0627\u062D\u0635\u0644 \u0639\u0644\u0649 \u0625\u062C\u0627\u0628\u0629",
|
|
6246
6331
|
seoDescription: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062A\u064A \u062A\u0648\u0627\u062C\u0647\u0647\u0627 \u0628\u0643\u0644\u0645\u0627\u062A\u0643 \u0648\u0627\u062D\u0635\u0644 \u0639\u0644\u0649 \u0625\u062C\u0627\u0628\u0629 \u0645\u0633\u062A\u0645\u062F\u0629 \u0645\u0646 \u0648\u062B\u0627\u0626\u0642 \u0645\u0646\u062A\u062C\u0627\u062A\u0646\u0627\u060C \u0645\u0639 \u0631\u0648\u0627\u0628\u0637 \u0625\u0644\u0649 \u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u062C\u0627\u0621\u062A \u0645\u0646\u0647\u0627.",
|
|
6247
6332
|
seoDescriptionProduct: "\u0635\u0641 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062A\u064A \u062A\u0648\u0627\u062C\u0647\u0647\u0627 \u0628\u0643\u0644\u0645\u0627\u062A\u0643 \u0648\u0627\u062D\u0635\u0644 \u0639\u0644\u0649 \u0625\u062C\u0627\u0628\u0629 \u0645\u0633\u062A\u0645\u062F\u0629 \u0645\u0646 \u0648\u062B\u0627\u0626\u0642 {product} \u0648\u0628\u0642\u064A\u0629 \u0645\u0646\u062A\u062C\u0627\u062A\u0646\u0627\u060C \u0645\u0639 \u0631\u0648\u0627\u0628\u0637 \u0625\u0644\u0649 \u0627\u0644\u0635\u0641\u062D\u0627\u062A \u0627\u0644\u062A\u064A \u062C\u0627\u0621\u062A \u0645\u0646\u0647\u0627.",
|
|
@@ -6310,6 +6395,23 @@ var TA = {
|
|
|
6310
6395
|
nextSuggestion: "\u0B85\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4 \u0BAA\u0BB0\u0BBF\u0BA8\u0BCD\u0BA4\u0BC1\u0BB0\u0BC8",
|
|
6311
6396
|
conceptIllustration: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1 \u0BB5\u0BBF\u0BB3\u0B95\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0B9F\u0BAE\u0BCD",
|
|
6312
6397
|
opensInNewTab: "\u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BBF\u0BB1\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD",
|
|
6398
|
+
conceptStripTitle: "\u0B85\u0BB2\u0BCD\u0BB2\u0BA4\u0BC1 \u0B92\u0BB0\u0BC1 \u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
6399
|
+
conceptStripLabel: "\u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B95\u0BC7\u0B9F\u0BCD\u0B95\u0B95\u0BCD\u0B95\u0BC2\u0B9F\u0BBF\u0BAF \u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1\u0B95\u0BB3\u0BCD",
|
|
6400
|
+
conceptAsk: "{product} \u0B87\u0BB2\u0BCD {title} \u0BAA\u0BB1\u0BCD\u0BB1\u0BBF\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
6401
|
+
conceptAskQuestion: "{product} \u0B87\u0BB2\u0BCD {title} \u0B8E\u0BAA\u0BCD\u0BAA\u0B9F\u0BBF \u0BB5\u0BC7\u0BB2\u0BC8 \u0B9A\u0BC6\u0BAF\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1?",
|
|
6402
|
+
copyAnswer: "\u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1",
|
|
6403
|
+
copyFailed: "\u0BA8\u0B95\u0BB2\u0BC6\u0B9F\u0BC1\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8",
|
|
6404
|
+
readAloud: "\u0B9A\u0BA4\u0BCD\u0BA4\u0BAE\u0BBE\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF",
|
|
6405
|
+
stopReading: "\u0BAA\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0BA4\u0BC8 \u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
|
|
6406
|
+
answerTable: "\u0B85\u0B9F\u0BCD\u0B9F\u0BB5\u0BA3\u0BC8",
|
|
6407
|
+
groundedIn: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B8E\u0BA4\u0BC8 \u0B85\u0B9F\u0BBF\u0BAA\u0BCD\u0BAA\u0B9F\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BA4\u0BC1",
|
|
6408
|
+
sourceCountOne: "1 \u0BAE\u0BC2\u0BB2\u0BAE\u0BCD",
|
|
6409
|
+
sourceCountMany: "{count} \u0BAE\u0BC2\u0BB2\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
6410
|
+
sourceKindConcept: "\u0B95\u0BB0\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1",
|
|
6411
|
+
sourceKindDocs: "\u0B86\u0BB5\u0BA3\u0BAE\u0BCD",
|
|
6412
|
+
sourceKindPricing: "\u0BB5\u0BBF\u0BB2\u0BC8",
|
|
6413
|
+
sourceKindUseCase: "\u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0BBE\u0B9F\u0BCD\u0B9F\u0BC1 \u0BA8\u0BBF\u0BB2\u0BC8",
|
|
6414
|
+
sourceKindPage: "\u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0BAA\u0BCD \u0BAA\u0B95\u0BCD\u0B95\u0BAE\u0BCD",
|
|
6313
6415
|
seoTitle: "\u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BAA\u0BC6\u0BB1\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD",
|
|
6314
6416
|
seoDescription: "\u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0BAE\u0BCD \u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0BB5\u0BBE\u0BB0\u0BCD\u0BA4\u0BCD\u0BA4\u0BC8\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD; \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1 \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD, \u0B85\u0BA4\u0BC1 \u0BB5\u0BA8\u0BCD\u0BA4 \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B87\u0BA3\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC1\u0B9F\u0BA9\u0BCD.",
|
|
6315
6417
|
seoDescriptionProduct: "{product} \u0BAE\u0BB1\u0BCD\u0BB1\u0BC1\u0BAE\u0BCD \u0B8E\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BBF\u0BB1 \u0BA4\u0BAF\u0BBE\u0BB0\u0BBF\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BA9\u0BCD \u0B86\u0BB5\u0BA3\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BBF\u0BB0\u0BC1\u0BA8\u0BCD\u0BA4\u0BC1 \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0BAA\u0BC6\u0BB1, \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B8E\u0BA4\u0BBF\u0BB0\u0BCD\u0B95\u0BCA\u0BB3\u0BCD\u0BB3\u0BC1\u0BAE\u0BCD \u0B9A\u0BBF\u0B95\u0BCD\u0B95\u0BB2\u0BC8 \u0B89\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0B9A\u0BCA\u0BA8\u0BCD\u0BA4 \u0BB5\u0BBE\u0BB0\u0BCD\u0BA4\u0BCD\u0BA4\u0BC8\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BB5\u0BBF\u0BB5\u0BB0\u0BBF\u0BAF\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u2014 \u0B85\u0BA4\u0BC1 \u0BB5\u0BA8\u0BCD\u0BA4 \u0BAA\u0B95\u0BCD\u0B95\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0B95\u0BCD\u0B95\u0BBE\u0BA9 \u0B87\u0BA3\u0BC8\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BC1\u0B9F\u0BA9\u0BCD.",
|
|
@@ -6333,6 +6435,17 @@ var STRINGS = {
|
|
|
6333
6435
|
ar: AR,
|
|
6334
6436
|
ta: TA
|
|
6335
6437
|
};
|
|
6438
|
+
var SPEECH_TAGS = {
|
|
6439
|
+
en: "en-US",
|
|
6440
|
+
zh: "zh-CN",
|
|
6441
|
+
hi: "hi-IN",
|
|
6442
|
+
es: "es-ES",
|
|
6443
|
+
ar: "ar-SA",
|
|
6444
|
+
ta: "ta-IN"
|
|
6445
|
+
};
|
|
6446
|
+
function speechLocaleOf(locale) {
|
|
6447
|
+
return SPEECH_TAGS[locale];
|
|
6448
|
+
}
|
|
6336
6449
|
function resolveExploreLocale(explicit) {
|
|
6337
6450
|
const candidates = [
|
|
6338
6451
|
explicit,
|
|
@@ -6411,11 +6524,9 @@ var EXPLORE_OWN_MESSAGE_FIELDS = (
|
|
|
6411
6524
|
}
|
|
6412
6525
|
`
|
|
6413
6526
|
);
|
|
6414
|
-
var
|
|
6527
|
+
var EXPLORE_CATALOG_ESTABLISHED_FIELDS = (
|
|
6415
6528
|
/* GraphQL */
|
|
6416
6529
|
`
|
|
6417
|
-
query ExploreCatalog($productSlug: String) {
|
|
6418
|
-
exploreCatalog(productSlug: $productSlug) {
|
|
6419
6530
|
enabled
|
|
6420
6531
|
products {
|
|
6421
6532
|
slug
|
|
@@ -6433,11 +6544,35 @@ var EXPLORE_CATALOG_QUERY = (
|
|
|
6433
6544
|
historyTurns
|
|
6434
6545
|
}
|
|
6435
6546
|
captchaRequired
|
|
6436
|
-
recaptchaSiteKey
|
|
6547
|
+
recaptchaSiteKey`
|
|
6548
|
+
);
|
|
6549
|
+
var EXPLORE_CATALOG_HIGHLIGHT_FIELD = (
|
|
6550
|
+
/* GraphQL */
|
|
6551
|
+
`
|
|
6552
|
+
conceptHighlights {
|
|
6553
|
+
product
|
|
6554
|
+
productName
|
|
6555
|
+
title
|
|
6556
|
+
url
|
|
6557
|
+
imageUrl
|
|
6558
|
+
alt
|
|
6559
|
+
}`
|
|
6560
|
+
);
|
|
6561
|
+
function exploreCatalogDocument(extraFields) {
|
|
6562
|
+
return (
|
|
6563
|
+
/* GraphQL */
|
|
6564
|
+
`
|
|
6565
|
+
query ExploreCatalog($productSlug: String) {
|
|
6566
|
+
exploreCatalog(productSlug: $productSlug) {${EXPLORE_CATALOG_ESTABLISHED_FIELDS}${extraFields}
|
|
6437
6567
|
}
|
|
6438
6568
|
}
|
|
6439
6569
|
`
|
|
6570
|
+
);
|
|
6571
|
+
}
|
|
6572
|
+
var EXPLORE_CATALOG_QUERY = exploreCatalogDocument(
|
|
6573
|
+
EXPLORE_CATALOG_HIGHLIGHT_FIELD
|
|
6440
6574
|
);
|
|
6575
|
+
var EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS = exploreCatalogDocument("");
|
|
6441
6576
|
var EXPLORE_MESSAGE_QUERY = (
|
|
6442
6577
|
/* GraphQL */
|
|
6443
6578
|
`
|
|
@@ -6978,7 +7113,12 @@ function buildFallbackCatalog(examplePrompts, welcome) {
|
|
|
6978
7113
|
welcomeBody: welcome?.body ?? FALLBACK_WELCOME_BODY,
|
|
6979
7114
|
limits: FALLBACK_EXPLORE_LIMITS,
|
|
6980
7115
|
captchaRequired: false,
|
|
6981
|
-
recaptchaSiteKey: null
|
|
7116
|
+
recaptchaSiteKey: null,
|
|
7117
|
+
// Empty, and deliberately not synthesised from `ECOSYSTEM_PRODUCTS`: a concept highlight
|
|
7118
|
+
// needs a real published illustration URL, and this SDK has no registry of them. An
|
|
7119
|
+
// invented path would render 38 broken frames on the one screen every prerender captures.
|
|
7120
|
+
// The strip renders nothing at all when the list is empty, which is the honest fallback.
|
|
7121
|
+
conceptHighlights: []
|
|
6982
7122
|
};
|
|
6983
7123
|
}
|
|
6984
7124
|
function normalizeCatalog(raw, fallback) {
|
|
@@ -6995,9 +7135,27 @@ function normalizeCatalog(raw, fallback) {
|
|
|
6995
7135
|
historyTurns: raw.limits?.historyTurns || fallback.limits.historyTurns
|
|
6996
7136
|
},
|
|
6997
7137
|
captchaRequired: raw.captchaRequired === true,
|
|
6998
|
-
recaptchaSiteKey: raw.recaptchaSiteKey ?? null
|
|
7138
|
+
recaptchaSiteKey: raw.recaptchaSiteKey ?? null,
|
|
7139
|
+
// `[ExploreConceptHighlight!]!` on the wire, so a gateway that KNOWS the field always
|
|
7140
|
+
// sends an array. The one response that arrives without it is the retry against an older
|
|
7141
|
+
// supergraph (`EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS`) — that gateway does not answer
|
|
7142
|
+
// the full document at all, it refuses it. Either way
|
|
7143
|
+
// `catalog.conceptHighlights.filter(...)` on `undefined` would throw inside render,
|
|
7144
|
+
// blanking the welcome screen over a decorative strip.
|
|
7145
|
+
conceptHighlights: raw.conceptHighlights?.length ? raw.conceptHighlights : fallback.conceptHighlights
|
|
6999
7146
|
};
|
|
7000
7147
|
}
|
|
7148
|
+
var CATALOG_DOCUMENT_REJECTED_CODES = /* @__PURE__ */ new Set([
|
|
7149
|
+
"GRAPHQL_VALIDATION_FAILED",
|
|
7150
|
+
"HTTP_400"
|
|
7151
|
+
]);
|
|
7152
|
+
function catalogRejectedTheHighlightField(res) {
|
|
7153
|
+
if (res.data?.exploreCatalog) return false;
|
|
7154
|
+
return (res.errors ?? []).some((error) => {
|
|
7155
|
+
const code = error.extensions?.code;
|
|
7156
|
+
return typeof code === "string" && CATALOG_DOCUMENT_REJECTED_CODES.has(code) || error.message.includes("conceptHighlights");
|
|
7157
|
+
});
|
|
7158
|
+
}
|
|
7001
7159
|
var RATE_LIMIT_CODES = /* @__PURE__ */ new Set([
|
|
7002
7160
|
"RATE_LIMITED",
|
|
7003
7161
|
"HTTP_429",
|
|
@@ -7337,11 +7495,19 @@ function useExploreChat(options = {}) {
|
|
|
7337
7495
|
useEffect(() => {
|
|
7338
7496
|
let cancelled = false;
|
|
7339
7497
|
const load = async () => {
|
|
7340
|
-
const
|
|
7498
|
+
const variables = { productSlug: productSlug ?? null };
|
|
7499
|
+
let res = await client.query(
|
|
7341
7500
|
EXPLORE_CATALOG_QUERY,
|
|
7342
|
-
|
|
7501
|
+
variables
|
|
7343
7502
|
);
|
|
7344
7503
|
if (cancelled || !mountedRef.current) return;
|
|
7504
|
+
if (catalogRejectedTheHighlightField(res)) {
|
|
7505
|
+
res = await client.query(
|
|
7506
|
+
EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS,
|
|
7507
|
+
variables
|
|
7508
|
+
);
|
|
7509
|
+
if (cancelled || !mountedRef.current) return;
|
|
7510
|
+
}
|
|
7345
7511
|
const raw = res.data?.exploreCatalog;
|
|
7346
7512
|
if (res.errors?.length || !raw) {
|
|
7347
7513
|
console.warn(
|
|
@@ -7787,6 +7953,224 @@ function makeOptimisticId() {
|
|
|
7787
7953
|
optimisticCounter += 1;
|
|
7788
7954
|
return `boff-explore-local-${Date.now()}-${optimisticCounter}`;
|
|
7789
7955
|
}
|
|
7956
|
+
var DRAIN_TARGET_MS = 1200;
|
|
7957
|
+
var MIN_CHARS_PER_SECOND = 90;
|
|
7958
|
+
var MAX_CHARS_PER_SECOND = 2200;
|
|
7959
|
+
var MAX_STEP_MS = 250;
|
|
7960
|
+
var COMMIT_INTERVAL_MS = 45;
|
|
7961
|
+
var FALLBACK_STEP_MS = 50;
|
|
7962
|
+
var FENCE = /^ {0,3}(?:```|~~~)/;
|
|
7963
|
+
var TABLE_ROW = /^ {0,3}\|/;
|
|
7964
|
+
var EMPTY_BLOCK_MARKER = /^ {0,3}(?:[-+>]|#{1,6}|\d{1,9}[.)])\s*$/;
|
|
7965
|
+
function isWordCharacter(char) {
|
|
7966
|
+
return char !== void 0 && /[\p{L}\p{N}]/u.test(char);
|
|
7967
|
+
}
|
|
7968
|
+
function clamp(value, min, max) {
|
|
7969
|
+
return Math.min(Math.max(value, min), max);
|
|
7970
|
+
}
|
|
7971
|
+
function now() {
|
|
7972
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
7973
|
+
}
|
|
7974
|
+
function isHighSurrogate(code) {
|
|
7975
|
+
return code >= 55296 && code <= 56319;
|
|
7976
|
+
}
|
|
7977
|
+
function safeInlineEnd(line) {
|
|
7978
|
+
let codeSpan = null;
|
|
7979
|
+
let link = null;
|
|
7980
|
+
const emphasis = [];
|
|
7981
|
+
let at = 0;
|
|
7982
|
+
while (at < line.length) {
|
|
7983
|
+
const char = line[at] ?? "";
|
|
7984
|
+
if (char === "\\") {
|
|
7985
|
+
at += 2;
|
|
7986
|
+
continue;
|
|
7987
|
+
}
|
|
7988
|
+
if (char === "`") {
|
|
7989
|
+
let run = 1;
|
|
7990
|
+
while (line[at + run] === "`") run += 1;
|
|
7991
|
+
codeSpan = codeSpan === null ? at : null;
|
|
7992
|
+
at += run;
|
|
7993
|
+
continue;
|
|
7994
|
+
}
|
|
7995
|
+
if (codeSpan !== null) {
|
|
7996
|
+
at += 1;
|
|
7997
|
+
continue;
|
|
7998
|
+
}
|
|
7999
|
+
if (char === "[") {
|
|
8000
|
+
if (link === null) link = line[at - 1] === "!" ? at - 1 : at;
|
|
8001
|
+
at += 1;
|
|
8002
|
+
continue;
|
|
8003
|
+
}
|
|
8004
|
+
if (char === "]") {
|
|
8005
|
+
if (link !== null && line[at + 1] !== "(") link = null;
|
|
8006
|
+
at += 1;
|
|
8007
|
+
continue;
|
|
8008
|
+
}
|
|
8009
|
+
if (char === ")") {
|
|
8010
|
+
link = null;
|
|
8011
|
+
at += 1;
|
|
8012
|
+
continue;
|
|
8013
|
+
}
|
|
8014
|
+
if (char === "*" || char === "_" || char === "~") {
|
|
8015
|
+
let run = 1;
|
|
8016
|
+
while (line[at + run] === char) run += 1;
|
|
8017
|
+
const start = at;
|
|
8018
|
+
at += run;
|
|
8019
|
+
const before = line[start - 1];
|
|
8020
|
+
const after = line[start + run];
|
|
8021
|
+
if (run < 2) continue;
|
|
8022
|
+
if (char === "_" && isWordCharacter(before) && isWordCharacter(after)) {
|
|
8023
|
+
continue;
|
|
8024
|
+
}
|
|
8025
|
+
const marker = char.repeat(run);
|
|
8026
|
+
const open2 = emphasis.findIndex((entry) => entry.marker === marker);
|
|
8027
|
+
if (open2 !== -1) {
|
|
8028
|
+
emphasis.splice(open2, 1);
|
|
8029
|
+
continue;
|
|
8030
|
+
}
|
|
8031
|
+
if (after !== void 0 && /\s/.test(after)) continue;
|
|
8032
|
+
emphasis.push({ marker, start });
|
|
8033
|
+
continue;
|
|
8034
|
+
}
|
|
8035
|
+
at += 1;
|
|
8036
|
+
}
|
|
8037
|
+
const open = [codeSpan, link, emphasis[0]?.start ?? null].filter(
|
|
8038
|
+
(value) => value !== null
|
|
8039
|
+
);
|
|
8040
|
+
return open.length === 0 ? line.length : Math.min(...open);
|
|
8041
|
+
}
|
|
8042
|
+
function revealBoundary(text, limit) {
|
|
8043
|
+
if (limit <= 0) return 0;
|
|
8044
|
+
const caughtUp = limit >= text.length;
|
|
8045
|
+
const head = caughtUp ? text : text.slice(0, limit);
|
|
8046
|
+
const lineStart = head.lastIndexOf("\n") + 1;
|
|
8047
|
+
const line = head.slice(lineStart);
|
|
8048
|
+
let fenceStart = null;
|
|
8049
|
+
let tableStart = null;
|
|
8050
|
+
let tableRows = 0;
|
|
8051
|
+
let at = 0;
|
|
8052
|
+
while (at < lineStart) {
|
|
8053
|
+
const breakAt = head.indexOf("\n", at);
|
|
8054
|
+
const end = breakAt === -1 ? lineStart : breakAt;
|
|
8055
|
+
const row = head.slice(at, end);
|
|
8056
|
+
if (fenceStart !== null) {
|
|
8057
|
+
if (FENCE.test(row)) fenceStart = null;
|
|
8058
|
+
} else if (FENCE.test(row)) {
|
|
8059
|
+
fenceStart = at;
|
|
8060
|
+
} else if (TABLE_ROW.test(row)) {
|
|
8061
|
+
if (tableStart === null) {
|
|
8062
|
+
tableStart = at;
|
|
8063
|
+
tableRows = 0;
|
|
8064
|
+
}
|
|
8065
|
+
tableRows += 1;
|
|
8066
|
+
} else if (tableStart !== null) {
|
|
8067
|
+
tableStart = null;
|
|
8068
|
+
tableRows = 0;
|
|
8069
|
+
}
|
|
8070
|
+
at = end + 1;
|
|
8071
|
+
}
|
|
8072
|
+
if (fenceStart === null) {
|
|
8073
|
+
const lastIsRow = TABLE_ROW.test(line);
|
|
8074
|
+
if (lastIsRow && tableStart === null) {
|
|
8075
|
+
tableStart = lineStart;
|
|
8076
|
+
tableRows = 0;
|
|
8077
|
+
} else if (!lastIsRow && line !== "") {
|
|
8078
|
+
tableStart = null;
|
|
8079
|
+
tableRows = 0;
|
|
8080
|
+
}
|
|
8081
|
+
if (tableStart !== null && tableRows < 2) return tableStart;
|
|
8082
|
+
}
|
|
8083
|
+
if (caughtUp) return text.length;
|
|
8084
|
+
if (fenceStart !== null) return fenceStart;
|
|
8085
|
+
if (TABLE_ROW.test(line)) return lineStart;
|
|
8086
|
+
if (EMPTY_BLOCK_MARKER.test(line)) return lineStart;
|
|
8087
|
+
const cut = lineStart + safeInlineEnd(line);
|
|
8088
|
+
return isHighSurrogate(text.charCodeAt(cut - 1)) ? cut - 1 : cut;
|
|
8089
|
+
}
|
|
8090
|
+
function prefersReducedMotion() {
|
|
8091
|
+
if (typeof window === "undefined") return true;
|
|
8092
|
+
try {
|
|
8093
|
+
return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
|
|
8094
|
+
} catch {
|
|
8095
|
+
return false;
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
function useProgressiveReveal(text, settled) {
|
|
8099
|
+
const [, setFrame] = useState(0);
|
|
8100
|
+
const [reduced] = useState(prefersReducedMotion);
|
|
8101
|
+
const immediate = settled || reduced;
|
|
8102
|
+
const textRef = useRef(text);
|
|
8103
|
+
const cursorRef = useRef(immediate ? text.length : 0);
|
|
8104
|
+
const cutRef = useRef(immediate ? text.length : 0);
|
|
8105
|
+
const committedRef = useRef(0);
|
|
8106
|
+
if (text !== textRef.current) {
|
|
8107
|
+
const revealed = textRef.current.slice(0, Math.floor(cursorRef.current));
|
|
8108
|
+
if (revealed !== "" && !text.startsWith(revealed)) {
|
|
8109
|
+
cursorRef.current = text.length;
|
|
8110
|
+
}
|
|
8111
|
+
cursorRef.current = Math.min(cursorRef.current, text.length);
|
|
8112
|
+
cutRef.current = Math.min(cutRef.current, text.length);
|
|
8113
|
+
textRef.current = text;
|
|
8114
|
+
}
|
|
8115
|
+
if (immediate) cursorRef.current = text.length;
|
|
8116
|
+
const cut = immediate ? text.length : Math.max(
|
|
8117
|
+
cutRef.current,
|
|
8118
|
+
revealBoundary(text, Math.floor(cursorRef.current))
|
|
8119
|
+
);
|
|
8120
|
+
cutRef.current = cut;
|
|
8121
|
+
useEffect(() => {
|
|
8122
|
+
if (immediate) return;
|
|
8123
|
+
if (cursorRef.current >= text.length) return;
|
|
8124
|
+
let cancelled = false;
|
|
8125
|
+
let cancelStep = null;
|
|
8126
|
+
let previous = now();
|
|
8127
|
+
const commit = (at, force) => {
|
|
8128
|
+
if (!force && at - committedRef.current < COMMIT_INTERVAL_MS) return;
|
|
8129
|
+
committedRef.current = at;
|
|
8130
|
+
setFrame((value) => value + 1);
|
|
8131
|
+
};
|
|
8132
|
+
const step = () => {
|
|
8133
|
+
cancelStep = null;
|
|
8134
|
+
if (cancelled) return;
|
|
8135
|
+
const at = now();
|
|
8136
|
+
const elapsed = clamp(at - previous, 0, MAX_STEP_MS);
|
|
8137
|
+
previous = at;
|
|
8138
|
+
const length = textRef.current.length;
|
|
8139
|
+
const pending = length - cursorRef.current;
|
|
8140
|
+
if (pending <= 0) {
|
|
8141
|
+
commit(at, true);
|
|
8142
|
+
return;
|
|
8143
|
+
}
|
|
8144
|
+
const perSecond = clamp(
|
|
8145
|
+
pending / (DRAIN_TARGET_MS / 1e3),
|
|
8146
|
+
MIN_CHARS_PER_SECOND,
|
|
8147
|
+
MAX_CHARS_PER_SECOND
|
|
8148
|
+
);
|
|
8149
|
+
cursorRef.current = Math.min(
|
|
8150
|
+
length,
|
|
8151
|
+
cursorRef.current + perSecond * elapsed / 1e3
|
|
8152
|
+
);
|
|
8153
|
+
const done = cursorRef.current >= length;
|
|
8154
|
+
commit(at, done);
|
|
8155
|
+
if (!done) schedule();
|
|
8156
|
+
};
|
|
8157
|
+
const schedule = () => {
|
|
8158
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
8159
|
+
const id2 = window.requestAnimationFrame(step);
|
|
8160
|
+
cancelStep = () => window.cancelAnimationFrame(id2);
|
|
8161
|
+
return;
|
|
8162
|
+
}
|
|
8163
|
+
const id = setTimeout(step, FALLBACK_STEP_MS);
|
|
8164
|
+
cancelStep = () => clearTimeout(id);
|
|
8165
|
+
};
|
|
8166
|
+
schedule();
|
|
8167
|
+
return () => {
|
|
8168
|
+
cancelled = true;
|
|
8169
|
+
cancelStep?.();
|
|
8170
|
+
};
|
|
8171
|
+
}, [text, immediate]);
|
|
8172
|
+
return text.slice(0, cut);
|
|
8173
|
+
}
|
|
7790
8174
|
function getRecognitionCtor() {
|
|
7791
8175
|
if (typeof window === "undefined") return null;
|
|
7792
8176
|
const w = window;
|
|
@@ -8005,6 +8389,141 @@ function useSpeechInput({
|
|
|
8005
8389
|
);
|
|
8006
8390
|
return { supported, listening, interim, error, start, stop, toggle };
|
|
8007
8391
|
}
|
|
8392
|
+
var SILENT_FAILURE_MS = 1500;
|
|
8393
|
+
function speechPlatform() {
|
|
8394
|
+
if (typeof window === "undefined") return null;
|
|
8395
|
+
const scope = window;
|
|
8396
|
+
const synth = scope.speechSynthesis;
|
|
8397
|
+
const Utterance = scope.SpeechSynthesisUtterance;
|
|
8398
|
+
if (!synth || typeof synth.speak !== "function") return null;
|
|
8399
|
+
if (typeof Utterance !== "function") return null;
|
|
8400
|
+
return { synth, Utterance };
|
|
8401
|
+
}
|
|
8402
|
+
function normaliseTag(tag) {
|
|
8403
|
+
return tag.trim().toLowerCase().replace(/_/g, "-");
|
|
8404
|
+
}
|
|
8405
|
+
function primaryOf(tag) {
|
|
8406
|
+
return normaliseTag(tag).split("-")[0] ?? "";
|
|
8407
|
+
}
|
|
8408
|
+
function pickVoice(voices, lang) {
|
|
8409
|
+
const wanted = normaliseTag(lang);
|
|
8410
|
+
if (wanted === "") return null;
|
|
8411
|
+
const primary = primaryOf(wanted);
|
|
8412
|
+
const exact = voices.filter((voice) => normaliseTag(voice.lang) === wanted);
|
|
8413
|
+
const related = voices.filter((voice) => primaryOf(voice.lang) === primary);
|
|
8414
|
+
return exact.find((voice) => voice.default) ?? exact[0] ?? related.find((voice) => voice.default) ?? related[0] ?? null;
|
|
8415
|
+
}
|
|
8416
|
+
var activeOwner = null;
|
|
8417
|
+
var activeStop = null;
|
|
8418
|
+
function stopSpeaking() {
|
|
8419
|
+
activeStop?.();
|
|
8420
|
+
}
|
|
8421
|
+
function useSpeechOutput({
|
|
8422
|
+
lang
|
|
8423
|
+
} = {}) {
|
|
8424
|
+
const [available, setAvailable] = useState(() => speechPlatform() !== null);
|
|
8425
|
+
const [speaking, setSpeaking] = useState(false);
|
|
8426
|
+
const utteranceRef = useRef(null);
|
|
8427
|
+
const watchdogRef = useRef(null);
|
|
8428
|
+
const ownerRef = useRef({});
|
|
8429
|
+
const stopRef = useRef(() => void 0);
|
|
8430
|
+
const langRef = useRef(lang);
|
|
8431
|
+
langRef.current = lang;
|
|
8432
|
+
const clearWatchdog = useCallback(() => {
|
|
8433
|
+
if (watchdogRef.current === null) return;
|
|
8434
|
+
clearTimeout(watchdogRef.current);
|
|
8435
|
+
watchdogRef.current = null;
|
|
8436
|
+
}, []);
|
|
8437
|
+
const settle = useCallback(() => {
|
|
8438
|
+
clearWatchdog();
|
|
8439
|
+
utteranceRef.current = null;
|
|
8440
|
+
if (activeOwner === ownerRef.current) {
|
|
8441
|
+
activeOwner = null;
|
|
8442
|
+
activeStop = null;
|
|
8443
|
+
}
|
|
8444
|
+
setSpeaking(false);
|
|
8445
|
+
}, [clearWatchdog]);
|
|
8446
|
+
const stop = useCallback(() => {
|
|
8447
|
+
const owned = utteranceRef.current !== null;
|
|
8448
|
+
settle();
|
|
8449
|
+
if (owned) speechPlatform()?.synth.cancel();
|
|
8450
|
+
}, [settle]);
|
|
8451
|
+
stopRef.current = stop;
|
|
8452
|
+
const speak = useCallback(
|
|
8453
|
+
(text) => {
|
|
8454
|
+
const platform = speechPlatform();
|
|
8455
|
+
if (!platform) {
|
|
8456
|
+
setAvailable(false);
|
|
8457
|
+
return;
|
|
8458
|
+
}
|
|
8459
|
+
const spoken = text.trim();
|
|
8460
|
+
if (spoken === "") return;
|
|
8461
|
+
if (activeStop && activeOwner !== ownerRef.current) activeStop();
|
|
8462
|
+
platform.synth.cancel();
|
|
8463
|
+
const utterance = new platform.Utterance(spoken);
|
|
8464
|
+
const wanted = langRef.current;
|
|
8465
|
+
if (wanted !== void 0 && wanted !== "") {
|
|
8466
|
+
const voice = pickVoice(platform.synth.getVoices(), wanted);
|
|
8467
|
+
utterance.lang = voice?.lang ?? wanted;
|
|
8468
|
+
if (voice) utterance.voice = voice;
|
|
8469
|
+
}
|
|
8470
|
+
const mine = () => utteranceRef.current === utterance;
|
|
8471
|
+
utterance.onstart = () => {
|
|
8472
|
+
if (!mine()) return;
|
|
8473
|
+
clearWatchdog();
|
|
8474
|
+
setSpeaking(true);
|
|
8475
|
+
};
|
|
8476
|
+
utterance.onend = () => {
|
|
8477
|
+
if (!mine()) return;
|
|
8478
|
+
settle();
|
|
8479
|
+
};
|
|
8480
|
+
utterance.onerror = (event) => {
|
|
8481
|
+
if (!mine()) return;
|
|
8482
|
+
const code = typeof event?.error === "string" ? event.error : "";
|
|
8483
|
+
settle();
|
|
8484
|
+
if (code !== "interrupted" && code !== "canceled") setAvailable(false);
|
|
8485
|
+
};
|
|
8486
|
+
utteranceRef.current = utterance;
|
|
8487
|
+
activeOwner = ownerRef.current;
|
|
8488
|
+
activeStop = () => {
|
|
8489
|
+
stopRef.current();
|
|
8490
|
+
};
|
|
8491
|
+
setSpeaking(true);
|
|
8492
|
+
platform.synth.speak(utterance);
|
|
8493
|
+
clearWatchdog();
|
|
8494
|
+
watchdogRef.current = setTimeout(() => {
|
|
8495
|
+
watchdogRef.current = null;
|
|
8496
|
+
if (!mine()) return;
|
|
8497
|
+
if (platform.synth.speaking) return;
|
|
8498
|
+
settle();
|
|
8499
|
+
setAvailable(false);
|
|
8500
|
+
}, SILENT_FAILURE_MS);
|
|
8501
|
+
},
|
|
8502
|
+
[clearWatchdog, settle]
|
|
8503
|
+
);
|
|
8504
|
+
const toggle = useCallback(
|
|
8505
|
+
(text) => {
|
|
8506
|
+
if (speaking) stop();
|
|
8507
|
+
else speak(text);
|
|
8508
|
+
},
|
|
8509
|
+
[speak, speaking, stop]
|
|
8510
|
+
);
|
|
8511
|
+
useEffect(() => {
|
|
8512
|
+
if (!speaking || typeof window === "undefined") return;
|
|
8513
|
+
const onHide = () => {
|
|
8514
|
+
stopRef.current();
|
|
8515
|
+
};
|
|
8516
|
+
window.addEventListener("pagehide", onHide);
|
|
8517
|
+
return () => window.removeEventListener("pagehide", onHide);
|
|
8518
|
+
}, [speaking]);
|
|
8519
|
+
useEffect(
|
|
8520
|
+
() => () => {
|
|
8521
|
+
stopRef.current();
|
|
8522
|
+
},
|
|
8523
|
+
[]
|
|
8524
|
+
);
|
|
8525
|
+
return { supported: available, speaking, speak, stop, toggle };
|
|
8526
|
+
}
|
|
8008
8527
|
var SWIPE_THRESHOLD = 40;
|
|
8009
8528
|
function useSwipe({
|
|
8010
8529
|
onSwipeLeft,
|
|
@@ -8272,6 +8791,115 @@ var EXPLORE_CSS = `
|
|
|
8272
8791
|
height: auto;
|
|
8273
8792
|
}
|
|
8274
8793
|
|
|
8794
|
+
/* ---- Comparison and pricing tables ----------------------------------------------------
|
|
8795
|
+
The harness emits a comparison, and a set of plans, as a GFM table whose FIRST column is
|
|
8796
|
+
the subject \u2014 the product, or the plan (CONTRACT.md \xA77). Two things have to be true of it:
|
|
8797
|
+
the page must not scroll sideways because of it, and it has to be readable on a 320px
|
|
8798
|
+
phone, which a four-column grid of 1px borders is not.
|
|
8799
|
+
|
|
8800
|
+
Wide: a contained scroller. \`max-width: 100%\` keeps the box inside the bubble and
|
|
8801
|
+
\`overflow-x: auto\` keeps the columns inside the box, so the widest possible table still
|
|
8802
|
+
cannot widen the document. \`overscroll-behavior-x: contain\` stops a swipe that runs out
|
|
8803
|
+
of table from chaining to the page \u2014 the same rule the transcript needed. */
|
|
8804
|
+
.boff-explore-body .boff-explore-table {
|
|
8805
|
+
max-width: 100%;
|
|
8806
|
+
overflow-x: auto;
|
|
8807
|
+
overscroll-behavior-x: contain;
|
|
8808
|
+
margin: 0.75rem 0;
|
|
8809
|
+
border: 1px solid hsl(var(--border));
|
|
8810
|
+
border-radius: 0.75rem;
|
|
8811
|
+
background-color: hsl(var(--card));
|
|
8812
|
+
}
|
|
8813
|
+
.boff-explore-body .boff-explore-table:focus-visible {
|
|
8814
|
+
outline: 2px solid hsl(var(--ring));
|
|
8815
|
+
outline-offset: 2px;
|
|
8816
|
+
}
|
|
8817
|
+
.boff-explore-body .boff-explore-table table {
|
|
8818
|
+
/* Beats the blanket \`display: block\` above, which is the unwrapped fallback. */
|
|
8819
|
+
display: table;
|
|
8820
|
+
width: 100%;
|
|
8821
|
+
max-width: none;
|
|
8822
|
+
margin: 0;
|
|
8823
|
+
border-collapse: collapse;
|
|
8824
|
+
font-size: 0.8125rem;
|
|
8825
|
+
}
|
|
8826
|
+
.boff-explore-body .boff-explore-table th,
|
|
8827
|
+
.boff-explore-body .boff-explore-table td {
|
|
8828
|
+
border: 0;
|
|
8829
|
+
border-top: 1px solid hsl(var(--border));
|
|
8830
|
+
padding: 0.5rem 0.75rem;
|
|
8831
|
+
/* \`start\`, never \`left\`: the page root carries dir="rtl" in Arabic, and a left-aligned
|
|
8832
|
+
table there reads against the grain of every other line on the page. */
|
|
8833
|
+
text-align: start;
|
|
8834
|
+
vertical-align: top;
|
|
8835
|
+
overflow-wrap: anywhere;
|
|
8836
|
+
/* Prices in a column line up under each other instead of drifting by digit width. */
|
|
8837
|
+
font-variant-numeric: tabular-nums;
|
|
8838
|
+
min-width: 6rem;
|
|
8839
|
+
}
|
|
8840
|
+
.boff-explore-body .boff-explore-table thead th {
|
|
8841
|
+
border-top: 0;
|
|
8842
|
+
background-color: hsl(var(--muted));
|
|
8843
|
+
color: hsl(var(--foreground));
|
|
8844
|
+
font-weight: 600;
|
|
8845
|
+
white-space: nowrap;
|
|
8846
|
+
}
|
|
8847
|
+
/* The first column is what the row is ABOUT \u2014 the product, or the plan name. Reading it as
|
|
8848
|
+
the row's heading is what makes a price list scannable rather than a grid of strings. */
|
|
8849
|
+
.boff-explore-body .boff-explore-table tbody td:first-child {
|
|
8850
|
+
font-weight: 600;
|
|
8851
|
+
color: hsl(var(--card-foreground));
|
|
8852
|
+
}
|
|
8853
|
+
|
|
8854
|
+
/* Narrow: one card per row. Each cell prints its own column heading, so a value is never
|
|
8855
|
+
stranded without the question it answers, and the subject cell becomes the card's title.
|
|
8856
|
+
A media query rather than a measured width \u2014 these pages are serialised post-hydration,
|
|
8857
|
+
so anything measured here would ship to every phone as static HTML. */
|
|
8858
|
+
@media (max-width: 30rem) {
|
|
8859
|
+
.boff-explore-body .boff-explore-table {
|
|
8860
|
+
overflow-x: visible;
|
|
8861
|
+
}
|
|
8862
|
+
.boff-explore-body .boff-explore-table table,
|
|
8863
|
+
.boff-explore-body .boff-explore-table tbody,
|
|
8864
|
+
.boff-explore-body .boff-explore-table tr,
|
|
8865
|
+
.boff-explore-body .boff-explore-table td {
|
|
8866
|
+
display: block;
|
|
8867
|
+
width: 100%;
|
|
8868
|
+
min-width: 0;
|
|
8869
|
+
}
|
|
8870
|
+
.boff-explore-body .boff-explore-table thead {
|
|
8871
|
+
display: none;
|
|
8872
|
+
}
|
|
8873
|
+
.boff-explore-body .boff-explore-table tr {
|
|
8874
|
+
border-top: 1px solid hsl(var(--border));
|
|
8875
|
+
padding: 0.5rem 0;
|
|
8876
|
+
}
|
|
8877
|
+
.boff-explore-body .boff-explore-table tr:first-child {
|
|
8878
|
+
border-top: 0;
|
|
8879
|
+
}
|
|
8880
|
+
.boff-explore-body .boff-explore-table td {
|
|
8881
|
+
border: 0;
|
|
8882
|
+
padding: 0.125rem 0.75rem;
|
|
8883
|
+
}
|
|
8884
|
+
.boff-explore-body .boff-explore-table td[data-label]::before {
|
|
8885
|
+
content: attr(data-label);
|
|
8886
|
+
display: block;
|
|
8887
|
+
font-size: 0.6875rem;
|
|
8888
|
+
font-weight: 600;
|
|
8889
|
+
text-transform: uppercase;
|
|
8890
|
+
letter-spacing: 0.04em;
|
|
8891
|
+
color: hsl(var(--muted-foreground));
|
|
8892
|
+
}
|
|
8893
|
+
.boff-explore-body .boff-explore-table tbody td:first-child {
|
|
8894
|
+
font-size: 0.9375rem;
|
|
8895
|
+
padding-bottom: 0.25rem;
|
|
8896
|
+
}
|
|
8897
|
+
.boff-explore-body .boff-explore-table tbody td:first-child::before {
|
|
8898
|
+
/* The plan's own name is the heading here; repeating "Plan" over it says nothing. */
|
|
8899
|
+
display: none;
|
|
8900
|
+
}
|
|
8901
|
+
}
|
|
8902
|
+
|
|
8275
8903
|
/* ---- Ambient backdrop -----------------------------------------------------------------
|
|
8276
8904
|
Two very low-opacity radial washes behind the welcome state, drifting slowly. Painted on
|
|
8277
8905
|
a pseudo-element with pointer-events:none so it can never intercept a click \u2014 a
|
|
@@ -8443,7 +9071,7 @@ function isOwnElement(el, root) {
|
|
|
8443
9071
|
function visualViewportHeight() {
|
|
8444
9072
|
return window.visualViewport?.height ?? window.innerHeight;
|
|
8445
9073
|
}
|
|
8446
|
-
function
|
|
9074
|
+
function clamp2(value, min, max) {
|
|
8447
9075
|
return Math.min(Math.max(value, min), max);
|
|
8448
9076
|
}
|
|
8449
9077
|
function isRestoredNavigation() {
|
|
@@ -8508,14 +9136,196 @@ function isInlineImageAllowed(src, origins) {
|
|
|
8508
9136
|
if (url.protocol !== "https:" || url.username || url.password) return false;
|
|
8509
9137
|
return origins.has(url.origin);
|
|
8510
9138
|
}
|
|
8511
|
-
var
|
|
9139
|
+
var REFERENCE_KIND_ORDER = [
|
|
9140
|
+
"CONCEPT",
|
|
9141
|
+
"DOCS",
|
|
9142
|
+
"PRICING",
|
|
9143
|
+
"USE_CASE",
|
|
9144
|
+
"PAGE"
|
|
9145
|
+
];
|
|
9146
|
+
var PRODUCT_SUBDOMAINS = [
|
|
9147
|
+
"alphadocs.",
|
|
9148
|
+
"alphaapp.",
|
|
9149
|
+
"docs.",
|
|
9150
|
+
"alpha.",
|
|
9151
|
+
"app.",
|
|
9152
|
+
"www."
|
|
9153
|
+
];
|
|
9154
|
+
function readCatalogUrl(raw) {
|
|
9155
|
+
let parsed;
|
|
9156
|
+
try {
|
|
9157
|
+
parsed = new URL(raw);
|
|
9158
|
+
} catch {
|
|
9159
|
+
return null;
|
|
9160
|
+
}
|
|
9161
|
+
if (parsed.protocol !== "https:") return null;
|
|
9162
|
+
const host = parsed.hostname.toLowerCase();
|
|
9163
|
+
const prefix = PRODUCT_SUBDOMAINS.find(
|
|
9164
|
+
(candidate) => host.startsWith(candidate)
|
|
9165
|
+
);
|
|
9166
|
+
const apex = prefix === void 0 ? host : host.slice(prefix.length);
|
|
9167
|
+
const port = parsed.port ? `:${parsed.port}` : "";
|
|
9168
|
+
return {
|
|
9169
|
+
origin: `https://${apex}${port}`,
|
|
9170
|
+
prefix,
|
|
9171
|
+
pathname: parsed.pathname
|
|
9172
|
+
};
|
|
9173
|
+
}
|
|
9174
|
+
function referenceKindOf(url, origins) {
|
|
9175
|
+
const parsed = readCatalogUrl(url);
|
|
9176
|
+
if (parsed === null || !origins.has(parsed.origin)) return null;
|
|
9177
|
+
if (parsed.prefix === "docs." || parsed.prefix === "alphadocs.")
|
|
9178
|
+
return "DOCS";
|
|
9179
|
+
const segment = parsed.pathname.toLowerCase().split("/").filter(Boolean)[0] ?? "";
|
|
9180
|
+
if (segment === "concept" || segment === "concepts") return "CONCEPT";
|
|
9181
|
+
if (segment === "docs") return "DOCS";
|
|
9182
|
+
if (segment === "pricing" || segment === "plans") return "PRICING";
|
|
9183
|
+
if (segment === "use-case" || segment === "use-cases" || segment === "solutions") {
|
|
9184
|
+
return "USE_CASE";
|
|
9185
|
+
}
|
|
9186
|
+
return "PAGE";
|
|
9187
|
+
}
|
|
9188
|
+
function productNamesByOrigin(products) {
|
|
9189
|
+
const names = /* @__PURE__ */ new Map();
|
|
9190
|
+
for (const product of products) {
|
|
9191
|
+
let url;
|
|
9192
|
+
try {
|
|
9193
|
+
url = new URL(product.website);
|
|
9194
|
+
} catch {
|
|
9195
|
+
continue;
|
|
9196
|
+
}
|
|
9197
|
+
if (url.protocol !== "https:") continue;
|
|
9198
|
+
const apex = url.hostname.replace(/^www\./, "");
|
|
9199
|
+
const port = url.port ? `:${url.port}` : "";
|
|
9200
|
+
const key = `https://${apex}${port}`;
|
|
9201
|
+
if (!names.has(key)) names.set(key, product.name);
|
|
9202
|
+
}
|
|
9203
|
+
return names;
|
|
9204
|
+
}
|
|
9205
|
+
function summariseReferences(references, origins, productNames) {
|
|
9206
|
+
const counts = /* @__PURE__ */ new Map();
|
|
9207
|
+
const products = [];
|
|
9208
|
+
for (const reference of references) {
|
|
9209
|
+
const kind = referenceKindOf(reference.url, origins);
|
|
9210
|
+
if (kind !== null) counts.set(kind, (counts.get(kind) ?? 0) + 1);
|
|
9211
|
+
const parsed = readCatalogUrl(reference.url);
|
|
9212
|
+
const name = (parsed === null ? void 0 : productNames.get(parsed.origin)) ?? (reference.product || null);
|
|
9213
|
+
if (name != null && !products.includes(name)) products.push(name);
|
|
9214
|
+
}
|
|
9215
|
+
return {
|
|
9216
|
+
total: references.length,
|
|
9217
|
+
kinds: REFERENCE_KIND_ORDER.filter((kind) => counts.has(kind)).map(
|
|
9218
|
+
(kind) => ({ kind, count: counts.get(kind) ?? 0 })
|
|
9219
|
+
),
|
|
9220
|
+
products
|
|
9221
|
+
};
|
|
9222
|
+
}
|
|
9223
|
+
var CODE_FENCE = /^\s*(?:```|~~~)/;
|
|
9224
|
+
var TABLE_ROW_LINE = /^\s{0,3}\|/;
|
|
9225
|
+
var TABLE_DELIMITER_ROW = /^\s{0,3}\|[\s:|-]*-[\s:|-]*$/;
|
|
9226
|
+
function readableLine(raw, mode) {
|
|
9227
|
+
let line = raw;
|
|
9228
|
+
line = line.replace(/!\[[^\]]*\]\([^)\s]*(?:\s+"[^"]*")?\)/g, "");
|
|
9229
|
+
line = mode === "speech" ? (
|
|
9230
|
+
// A voice reading "h-t-t-p-s colon slash slash…" mid-sentence is noise, and the
|
|
9231
|
+
// prompt asks for two to five links in every answer. The label IS the words.
|
|
9232
|
+
line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1")
|
|
9233
|
+
) : line.replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, "$1 ($2)");
|
|
9234
|
+
line = mode === "speech" ? line.replace(/<(https?:\/\/[^>\s]+)>/g, "") : line.replace(/<(https?:\/\/[^>\s]+)>/g, "$1");
|
|
9235
|
+
line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
|
|
9236
|
+
line = line.replace(/^\s{0,3}>\s?/, "");
|
|
9237
|
+
if (/^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/.test(line)) return "";
|
|
9238
|
+
line = line.replace(/`([^`]+)`/g, "$1");
|
|
9239
|
+
line = line.replace(/\*\*([^*]+)\*\*/g, "$1");
|
|
9240
|
+
line = line.replace(/__([^_]+)__/g, "$1");
|
|
9241
|
+
line = line.replace(/(^|[^*\w])\*([^*\n]+)\*(?![*\w])/g, "$1$2");
|
|
9242
|
+
line = line.replace(/(^|[^_\w])_([^_\n]+)_(?![_\w])/g, "$1$2");
|
|
9243
|
+
return line.replace(/[ \t]+$/, "");
|
|
9244
|
+
}
|
|
9245
|
+
function tableCells(row) {
|
|
9246
|
+
const trimmed = row.trim();
|
|
9247
|
+
const cells = [];
|
|
9248
|
+
let cell = "";
|
|
9249
|
+
for (let at = 0; at < trimmed.length; at += 1) {
|
|
9250
|
+
const char = trimmed[at] ?? "";
|
|
9251
|
+
if (char === "\\") {
|
|
9252
|
+
cell += char + (trimmed[at + 1] ?? "");
|
|
9253
|
+
at += 1;
|
|
9254
|
+
continue;
|
|
9255
|
+
}
|
|
9256
|
+
if (char === "|") {
|
|
9257
|
+
cells.push(cell.trim());
|
|
9258
|
+
cell = "";
|
|
9259
|
+
continue;
|
|
9260
|
+
}
|
|
9261
|
+
cell += char;
|
|
9262
|
+
}
|
|
9263
|
+
cells.push(cell.trim());
|
|
9264
|
+
if (trimmed.startsWith("|") && cells[0] === "") cells.shift();
|
|
9265
|
+
if (trimmed.endsWith("|") && cells[cells.length - 1] === "") cells.pop();
|
|
9266
|
+
return cells;
|
|
9267
|
+
}
|
|
9268
|
+
function asSentence(text) {
|
|
9269
|
+
return /[.!?]$/.test(text) ? text : `${text}.`;
|
|
9270
|
+
}
|
|
9271
|
+
function spokenTable(rows) {
|
|
9272
|
+
if (rows.length < 2 || !TABLE_DELIMITER_ROW.test(rows[1] ?? "")) return rows;
|
|
9273
|
+
const labels = tableCells(rows[0] ?? "");
|
|
9274
|
+
const spoken = [];
|
|
9275
|
+
for (const row of rows.slice(2)) {
|
|
9276
|
+
const parts = [];
|
|
9277
|
+
tableCells(row).forEach((value, column) => {
|
|
9278
|
+
if (value === "") return;
|
|
9279
|
+
const label = column === 0 ? "" : labels[column] ?? "";
|
|
9280
|
+
parts.push(label === "" ? value : `${label}: ${value}`);
|
|
9281
|
+
});
|
|
9282
|
+
if (parts.length > 0) spoken.push(asSentence(parts.join(". ")));
|
|
9283
|
+
}
|
|
9284
|
+
return spoken;
|
|
9285
|
+
}
|
|
9286
|
+
function readableText(markdown, mode) {
|
|
9287
|
+
const lines = [];
|
|
9288
|
+
let inFence = false;
|
|
9289
|
+
let table = [];
|
|
9290
|
+
const flushTable = () => {
|
|
9291
|
+
if (table.length === 0) return;
|
|
9292
|
+
for (const line of spokenTable(table)) lines.push(readableLine(line, mode));
|
|
9293
|
+
table = [];
|
|
9294
|
+
};
|
|
9295
|
+
for (const raw of markdown.split("\n")) {
|
|
9296
|
+
if (CODE_FENCE.test(raw)) {
|
|
9297
|
+
flushTable();
|
|
9298
|
+
inFence = !inFence;
|
|
9299
|
+
continue;
|
|
9300
|
+
}
|
|
9301
|
+
if (inFence) {
|
|
9302
|
+
lines.push(raw);
|
|
9303
|
+
continue;
|
|
9304
|
+
}
|
|
9305
|
+
if (mode === "speech" && TABLE_ROW_LINE.test(raw)) {
|
|
9306
|
+
table.push(raw);
|
|
9307
|
+
continue;
|
|
9308
|
+
}
|
|
9309
|
+
flushTable();
|
|
9310
|
+
lines.push(readableLine(raw, mode));
|
|
9311
|
+
}
|
|
9312
|
+
flushTable();
|
|
9313
|
+
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
9314
|
+
}
|
|
9315
|
+
function answerPlainText(markdown) {
|
|
9316
|
+
return readableText(markdown, "clipboard");
|
|
9317
|
+
}
|
|
9318
|
+
function answerSpeechText(markdown) {
|
|
9319
|
+
return readableText(markdown, "speech");
|
|
9320
|
+
}
|
|
9321
|
+
var AnswerScopeContext = createContext(null);
|
|
8512
9322
|
var InsideLinkContext = createContext(false);
|
|
8513
9323
|
function AnswerLink(props) {
|
|
8514
9324
|
return /* @__PURE__ */ jsx(InsideLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx(MarkdownLink, { ...props }) });
|
|
8515
9325
|
}
|
|
8516
9326
|
var INLINE_IMAGE_FRAME = "relative inline-block max-w-full overflow-hidden rounded-xl border border-border bg-muted align-top shadow-sm";
|
|
8517
9327
|
function InlineConceptImage({ src, alt }) {
|
|
8518
|
-
const scope = useContext(
|
|
9328
|
+
const scope = useContext(AnswerScopeContext);
|
|
8519
9329
|
const insideLink = useContext(InsideLinkContext);
|
|
8520
9330
|
if (!scope || !scope.enabled || !isInlineImageAllowed(src, scope.origins) || scope.failed.has(src)) {
|
|
8521
9331
|
return null;
|
|
@@ -8563,9 +9373,70 @@ function InlineConceptImage({ src, alt }) {
|
|
|
8563
9373
|
}
|
|
8564
9374
|
) });
|
|
8565
9375
|
}
|
|
9376
|
+
function markdownText(node) {
|
|
9377
|
+
if (!node) return "";
|
|
9378
|
+
if (typeof node.value === "string") return node.value;
|
|
9379
|
+
return (node.children ?? []).map(markdownText).join("");
|
|
9380
|
+
}
|
|
9381
|
+
function hasHeaderCells(node) {
|
|
9382
|
+
return (node?.children ?? []).some((cell) => cell.tagName === "th");
|
|
9383
|
+
}
|
|
9384
|
+
function findHeaderRow(node) {
|
|
9385
|
+
for (const child of node?.children ?? []) {
|
|
9386
|
+
if (child.tagName === "tr" && hasHeaderCells(child)) return child;
|
|
9387
|
+
const nested = findHeaderRow(child);
|
|
9388
|
+
if (nested !== null) return nested;
|
|
9389
|
+
}
|
|
9390
|
+
return null;
|
|
9391
|
+
}
|
|
9392
|
+
function tableColumnLabels(node) {
|
|
9393
|
+
const row = findHeaderRow(node);
|
|
9394
|
+
if (row === null) return [];
|
|
9395
|
+
return (row.children ?? []).filter((cell) => cell.tagName === "th").map((cell) => markdownText(cell).trim());
|
|
9396
|
+
}
|
|
9397
|
+
var TableColumnsContext = createContext([]);
|
|
9398
|
+
function AnswerTable({ node, children }) {
|
|
9399
|
+
const scope = useContext(AnswerScopeContext);
|
|
9400
|
+
const table = /* @__PURE__ */ jsx(TableColumnsContext.Provider, { value: tableColumnLabels(node), children: /* @__PURE__ */ jsx("table", { children }) });
|
|
9401
|
+
if (!scope) return table;
|
|
9402
|
+
return /* @__PURE__ */ jsx(
|
|
9403
|
+
"div",
|
|
9404
|
+
{
|
|
9405
|
+
"data-boff-explore": "table",
|
|
9406
|
+
role: "region",
|
|
9407
|
+
"aria-label": scope.strings.answerTable,
|
|
9408
|
+
tabIndex: 0,
|
|
9409
|
+
className: "boff-explore-table",
|
|
9410
|
+
children: table
|
|
9411
|
+
}
|
|
9412
|
+
);
|
|
9413
|
+
}
|
|
9414
|
+
function AnswerTableRow({
|
|
9415
|
+
node,
|
|
9416
|
+
children,
|
|
9417
|
+
...props
|
|
9418
|
+
}) {
|
|
9419
|
+
const labels = useContext(TableColumnsContext);
|
|
9420
|
+
if (labels.length === 0 || hasHeaderCells(node)) {
|
|
9421
|
+
return /* @__PURE__ */ jsx("tr", { ...props, children });
|
|
9422
|
+
}
|
|
9423
|
+
let column = 0;
|
|
9424
|
+
const cells = Children.map(children, (cell) => {
|
|
9425
|
+
if (!isValidElement(cell)) return cell;
|
|
9426
|
+
const label = labels[column] ?? "";
|
|
9427
|
+
column += 1;
|
|
9428
|
+
if (label === "") return cell;
|
|
9429
|
+
return cloneElement(cell, {
|
|
9430
|
+
"data-label": label
|
|
9431
|
+
});
|
|
9432
|
+
});
|
|
9433
|
+
return /* @__PURE__ */ jsx("tr", { ...props, children: cells });
|
|
9434
|
+
}
|
|
8566
9435
|
var ANSWER_MARKDOWN_COMPONENTS = {
|
|
8567
9436
|
a: AnswerLink,
|
|
8568
|
-
img: InlineConceptImage
|
|
9437
|
+
img: InlineConceptImage,
|
|
9438
|
+
table: AnswerTable,
|
|
9439
|
+
tr: AnswerTableRow
|
|
8569
9440
|
};
|
|
8570
9441
|
function ReferenceCard({
|
|
8571
9442
|
reference,
|
|
@@ -8905,6 +9776,148 @@ function AnswerFeedback({
|
|
|
8905
9776
|
}
|
|
8906
9777
|
);
|
|
8907
9778
|
}
|
|
9779
|
+
var PROVENANCE_CHIP = "inline-flex max-w-full items-center gap-1 rounded-full border border-border bg-muted/60 px-2 py-0.5 text-[11px] leading-5 text-muted-foreground";
|
|
9780
|
+
function ProvenanceChips({
|
|
9781
|
+
strings: T,
|
|
9782
|
+
provenance
|
|
9783
|
+
}) {
|
|
9784
|
+
if (provenance.total === 0) return null;
|
|
9785
|
+
const kindLabels = {
|
|
9786
|
+
CONCEPT: T.sourceKindConcept,
|
|
9787
|
+
DOCS: T.sourceKindDocs,
|
|
9788
|
+
PRICING: T.sourceKindPricing,
|
|
9789
|
+
USE_CASE: T.sourceKindUseCase,
|
|
9790
|
+
PAGE: T.sourceKindPage
|
|
9791
|
+
};
|
|
9792
|
+
return /* @__PURE__ */ jsxs(
|
|
9793
|
+
"ul",
|
|
9794
|
+
{
|
|
9795
|
+
"data-boff-explore": "provenance",
|
|
9796
|
+
"aria-label": T.groundedIn,
|
|
9797
|
+
className: "flex flex-wrap items-center gap-1.5",
|
|
9798
|
+
children: [
|
|
9799
|
+
/* @__PURE__ */ jsxs("li", { "data-boff-explore": "provenance-count", className: PROVENANCE_CHIP, children: [
|
|
9800
|
+
/* @__PURE__ */ jsx(BookOpenText, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
|
|
9801
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: provenance.total === 1 ? T.sourceCountOne : fill(T.sourceCountMany, { count: String(provenance.total) }) })
|
|
9802
|
+
] }),
|
|
9803
|
+
provenance.kinds.map(({ kind, count }) => /* @__PURE__ */ jsx(
|
|
9804
|
+
"li",
|
|
9805
|
+
{
|
|
9806
|
+
"data-boff-explore": "provenance-kind",
|
|
9807
|
+
"data-kind": kind,
|
|
9808
|
+
"data-count": count,
|
|
9809
|
+
className: PROVENANCE_CHIP,
|
|
9810
|
+
children: /* @__PURE__ */ jsx("span", { className: "truncate", children: count > 1 ? `${kindLabels[kind]} \xB7 ${count}` : kindLabels[kind] })
|
|
9811
|
+
},
|
|
9812
|
+
kind
|
|
9813
|
+
)),
|
|
9814
|
+
provenance.products.map((name) => /* @__PURE__ */ jsx(
|
|
9815
|
+
"li",
|
|
9816
|
+
{
|
|
9817
|
+
"data-boff-explore": "provenance-product",
|
|
9818
|
+
className: PROVENANCE_CHIP,
|
|
9819
|
+
children: /* @__PURE__ */ jsx("span", { className: "truncate", children: name })
|
|
9820
|
+
},
|
|
9821
|
+
name
|
|
9822
|
+
))
|
|
9823
|
+
]
|
|
9824
|
+
}
|
|
9825
|
+
);
|
|
9826
|
+
}
|
|
9827
|
+
var COPY_FEEDBACK_MS = 2500;
|
|
9828
|
+
var ANSWER_ACTION_PILL = "inline-flex max-w-full items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
|
|
9829
|
+
var ANSWER_ACTION_IDLE = "border-border bg-card text-muted-foreground hover:border-primary/40 hover:bg-accent hover:text-foreground";
|
|
9830
|
+
var ANSWER_ACTION_ACTIVE = "border-primary/40 bg-accent text-primary";
|
|
9831
|
+
function ReadAloudButton({
|
|
9832
|
+
strings: T,
|
|
9833
|
+
text,
|
|
9834
|
+
lang
|
|
9835
|
+
}) {
|
|
9836
|
+
const speech = useSpeechOutput({ lang });
|
|
9837
|
+
if (!speech.supported) return null;
|
|
9838
|
+
const label = speech.speaking ? T.stopReading : T.readAloud;
|
|
9839
|
+
return /* @__PURE__ */ jsxs(
|
|
9840
|
+
"button",
|
|
9841
|
+
{
|
|
9842
|
+
"data-boff-explore": "read-aloud",
|
|
9843
|
+
"data-speaking": speech.speaking ? "true" : "false",
|
|
9844
|
+
type: "button",
|
|
9845
|
+
title: label,
|
|
9846
|
+
"aria-pressed": speech.speaking,
|
|
9847
|
+
onClick: () => speech.toggle(text),
|
|
9848
|
+
className: cn(
|
|
9849
|
+
ANSWER_ACTION_PILL,
|
|
9850
|
+
speech.speaking ? ANSWER_ACTION_ACTIVE : ANSWER_ACTION_IDLE
|
|
9851
|
+
),
|
|
9852
|
+
children: [
|
|
9853
|
+
/* @__PURE__ */ jsx(Volume2, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
|
|
9854
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: label })
|
|
9855
|
+
]
|
|
9856
|
+
}
|
|
9857
|
+
);
|
|
9858
|
+
}
|
|
9859
|
+
function AnswerActions({
|
|
9860
|
+
strings: T,
|
|
9861
|
+
text,
|
|
9862
|
+
speechText,
|
|
9863
|
+
speechLang
|
|
9864
|
+
}) {
|
|
9865
|
+
const [outcome, setOutcome] = useState("idle");
|
|
9866
|
+
const resetRef = useRef(null);
|
|
9867
|
+
useEffect(
|
|
9868
|
+
() => () => {
|
|
9869
|
+
if (resetRef.current !== null) clearTimeout(resetRef.current);
|
|
9870
|
+
},
|
|
9871
|
+
[]
|
|
9872
|
+
);
|
|
9873
|
+
const copy = useCallback(async () => {
|
|
9874
|
+
let copied = false;
|
|
9875
|
+
try {
|
|
9876
|
+
const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
|
|
9877
|
+
if (typeof clipboard?.writeText === "function") {
|
|
9878
|
+
await clipboard.writeText(text);
|
|
9879
|
+
copied = true;
|
|
9880
|
+
}
|
|
9881
|
+
} catch {
|
|
9882
|
+
copied = false;
|
|
9883
|
+
}
|
|
9884
|
+
setOutcome(copied ? "copied" : "failed");
|
|
9885
|
+
if (resetRef.current !== null) clearTimeout(resetRef.current);
|
|
9886
|
+
resetRef.current = setTimeout(() => setOutcome("idle"), COPY_FEEDBACK_MS);
|
|
9887
|
+
}, [text]);
|
|
9888
|
+
const label = outcome === "copied" ? T.copied : outcome === "failed" ? T.copyFailed : T.copyAnswer;
|
|
9889
|
+
return /* @__PURE__ */ jsxs(
|
|
9890
|
+
"div",
|
|
9891
|
+
{
|
|
9892
|
+
"data-boff-explore": "answer-actions",
|
|
9893
|
+
className: "flex flex-wrap items-center gap-2 pt-0.5",
|
|
9894
|
+
children: [
|
|
9895
|
+
/* @__PURE__ */ jsxs(
|
|
9896
|
+
"button",
|
|
9897
|
+
{
|
|
9898
|
+
"data-boff-explore": "copy-answer",
|
|
9899
|
+
"data-outcome": outcome,
|
|
9900
|
+
type: "button",
|
|
9901
|
+
title: label,
|
|
9902
|
+
onClick: () => {
|
|
9903
|
+
void copy();
|
|
9904
|
+
},
|
|
9905
|
+
className: cn(
|
|
9906
|
+
ANSWER_ACTION_PILL,
|
|
9907
|
+
outcome === "failed" ? "border-destructive/40 bg-card text-destructive" : ANSWER_ACTION_IDLE
|
|
9908
|
+
),
|
|
9909
|
+
children: [
|
|
9910
|
+
outcome === "copied" ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" }),
|
|
9911
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: label })
|
|
9912
|
+
]
|
|
9913
|
+
}
|
|
9914
|
+
),
|
|
9915
|
+
/* @__PURE__ */ jsx(ReadAloudButton, { strings: T, text: speechText, lang: speechLang }),
|
|
9916
|
+
/* @__PURE__ */ jsx("span", { "data-boff-explore": "copy-status", role: "status", className: "sr-only", children: outcome === "idle" ? "" : label })
|
|
9917
|
+
]
|
|
9918
|
+
}
|
|
9919
|
+
);
|
|
9920
|
+
}
|
|
8908
9921
|
function UserBubble({
|
|
8909
9922
|
strings: T,
|
|
8910
9923
|
message
|
|
@@ -8950,6 +9963,8 @@ function AssistantBubble({
|
|
|
8950
9963
|
message,
|
|
8951
9964
|
activity,
|
|
8952
9965
|
imageOrigins,
|
|
9966
|
+
productNames,
|
|
9967
|
+
speechLang,
|
|
8953
9968
|
onNavigate,
|
|
8954
9969
|
anchorRef,
|
|
8955
9970
|
onFollow,
|
|
@@ -8960,6 +9975,7 @@ function AssistantBubble({
|
|
|
8960
9975
|
const body = message.content || message.partialContent || "";
|
|
8961
9976
|
const failed = message.status === "FAILED";
|
|
8962
9977
|
const completed = message.status === "COMPLETED";
|
|
9978
|
+
const visible = useProgressiveReveal(body, !streaming);
|
|
8963
9979
|
const [failedImages, setFailedImages] = useState(
|
|
8964
9980
|
() => /* @__PURE__ */ new Set()
|
|
8965
9981
|
);
|
|
@@ -8968,7 +9984,7 @@ function AssistantBubble({
|
|
|
8968
9984
|
(current) => current.has(src) ? current : new Set(current).add(src)
|
|
8969
9985
|
);
|
|
8970
9986
|
}, []);
|
|
8971
|
-
const
|
|
9987
|
+
const answerScope = useMemo(
|
|
8972
9988
|
() => ({
|
|
8973
9989
|
strings: T,
|
|
8974
9990
|
enabled: completed,
|
|
@@ -8978,6 +9994,19 @@ function AssistantBubble({
|
|
|
8978
9994
|
}),
|
|
8979
9995
|
[T, completed, imageOrigins, failedImages, markImageFailed]
|
|
8980
9996
|
);
|
|
9997
|
+
const provenance = useMemo(
|
|
9998
|
+
() => summariseReferences(message.references, imageOrigins, productNames),
|
|
9999
|
+
[message.references, imageOrigins, productNames]
|
|
10000
|
+
);
|
|
10001
|
+
const copyText = useMemo(
|
|
10002
|
+
() => answerPlainText(message.content),
|
|
10003
|
+
[message.content]
|
|
10004
|
+
);
|
|
10005
|
+
const speechText = useMemo(
|
|
10006
|
+
() => answerSpeechText(message.content),
|
|
10007
|
+
[message.content]
|
|
10008
|
+
);
|
|
10009
|
+
const grounded = completed && message.answered !== false;
|
|
8981
10010
|
return /* @__PURE__ */ jsxs(
|
|
8982
10011
|
"div",
|
|
8983
10012
|
{
|
|
@@ -9023,10 +10052,11 @@ function AssistantBubble({
|
|
|
9023
10052
|
]
|
|
9024
10053
|
}
|
|
9025
10054
|
) : null,
|
|
9026
|
-
|
|
9027
|
-
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(
|
|
10055
|
+
visible ? /* @__PURE__ */ jsxs("div", { className: "rounded-2xl rounded-tl-md border border-border bg-card px-4 py-3 shadow-sm", children: [
|
|
10056
|
+
/* @__PURE__ */ jsx("div", { className: "boff-prose boff-prose-sm boff-explore-body min-w-0 text-card-foreground", children: /* @__PURE__ */ jsx(AnswerScopeContext.Provider, { value: answerScope, children: /* @__PURE__ */ jsx(Markdown, { components: ANSWER_MARKDOWN_COMPONENTS, children: visible }) }) }),
|
|
9028
10057
|
streaming ? /* @__PURE__ */ jsx("span", { className: "boff-explore-caret", "aria-hidden": "true" }) : null
|
|
9029
10058
|
] }) : null,
|
|
10059
|
+
grounded && provenance.total > 0 ? /* @__PURE__ */ jsx(ProvenanceChips, { strings: T, provenance }) : null,
|
|
9030
10060
|
streaming ? /* @__PURE__ */ jsx(ThinkingIndicator, { activity }) : null,
|
|
9031
10061
|
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: T.answerDidNotArrive }) : null,
|
|
9032
10062
|
message.references.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -9066,6 +10096,15 @@ function AssistantBubble({
|
|
|
9066
10096
|
question
|
|
9067
10097
|
)) })
|
|
9068
10098
|
] }) : null,
|
|
10099
|
+
completed && copyText !== "" ? /* @__PURE__ */ jsx(
|
|
10100
|
+
AnswerActions,
|
|
10101
|
+
{
|
|
10102
|
+
strings: T,
|
|
10103
|
+
text: copyText,
|
|
10104
|
+
speechText,
|
|
10105
|
+
speechLang
|
|
10106
|
+
}
|
|
10107
|
+
) : null,
|
|
9069
10108
|
completed && onFeedback ? /* @__PURE__ */ jsx(
|
|
9070
10109
|
AnswerFeedback,
|
|
9071
10110
|
{
|
|
@@ -9278,6 +10317,96 @@ function ProductStrip({
|
|
|
9278
10317
|
}
|
|
9279
10318
|
);
|
|
9280
10319
|
}
|
|
10320
|
+
var MAX_CONCEPT_CARDS = 6;
|
|
10321
|
+
function ConceptStrip({
|
|
10322
|
+
strings: T,
|
|
10323
|
+
highlights,
|
|
10324
|
+
onAsk,
|
|
10325
|
+
disabled
|
|
10326
|
+
}) {
|
|
10327
|
+
const [failed, setFailed] = useState(() => /* @__PURE__ */ new Set());
|
|
10328
|
+
const markFailed = useCallback((src) => {
|
|
10329
|
+
setFailed(
|
|
10330
|
+
(current) => current.has(src) ? current : new Set(current).add(src)
|
|
10331
|
+
);
|
|
10332
|
+
}, []);
|
|
10333
|
+
const visible = highlights.filter(
|
|
10334
|
+
(highlight) => highlight.imageUrl !== "" && !failed.has(highlight.imageUrl)
|
|
10335
|
+
).slice(0, MAX_CONCEPT_CARDS);
|
|
10336
|
+
if (visible.length === 0) return null;
|
|
10337
|
+
return /* @__PURE__ */ jsxs(
|
|
10338
|
+
"div",
|
|
10339
|
+
{
|
|
10340
|
+
"data-boff-explore": "concept-strip-block",
|
|
10341
|
+
className: "boff-explore-rise boff-explore-rise-1 mt-6",
|
|
10342
|
+
children: [
|
|
10343
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: T.conceptStripTitle }),
|
|
10344
|
+
/* @__PURE__ */ jsx(
|
|
10345
|
+
"ul",
|
|
10346
|
+
{
|
|
10347
|
+
"data-boff-explore": "concept-strip",
|
|
10348
|
+
"aria-label": T.conceptStripLabel,
|
|
10349
|
+
className: "boff-explore-strip flex min-w-0 snap-x gap-3 overflow-x-auto pb-1",
|
|
10350
|
+
children: visible.map((highlight) => /* @__PURE__ */ jsx(
|
|
10351
|
+
"li",
|
|
10352
|
+
{
|
|
10353
|
+
className: "shrink-0 snap-start",
|
|
10354
|
+
children: /* @__PURE__ */ jsxs(
|
|
10355
|
+
"button",
|
|
10356
|
+
{
|
|
10357
|
+
"data-boff-explore": "concept-card",
|
|
10358
|
+
"data-product": highlight.product,
|
|
10359
|
+
type: "button",
|
|
10360
|
+
disabled,
|
|
10361
|
+
"aria-label": fill(T.conceptAsk, {
|
|
10362
|
+
title: highlight.title,
|
|
10363
|
+
product: highlight.productName
|
|
10364
|
+
}),
|
|
10365
|
+
onClick: () => onAsk(
|
|
10366
|
+
fill(T.conceptAskQuestion, {
|
|
10367
|
+
title: highlight.title,
|
|
10368
|
+
product: highlight.productName
|
|
10369
|
+
})
|
|
10370
|
+
),
|
|
10371
|
+
className: "group flex w-40 flex-col overflow-hidden rounded-xl border border-border bg-card text-left 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 sm:w-48",
|
|
10372
|
+
children: [
|
|
10373
|
+
/* @__PURE__ */ jsxs("span", { className: "relative block aspect-[16/9] w-full overflow-hidden bg-muted", children: [
|
|
10374
|
+
/* @__PURE__ */ jsx(
|
|
10375
|
+
"img",
|
|
10376
|
+
{
|
|
10377
|
+
src: highlight.imageUrl,
|
|
10378
|
+
alt: highlight.alt,
|
|
10379
|
+
loading: "lazy",
|
|
10380
|
+
decoding: "async",
|
|
10381
|
+
onError: () => markFailed(highlight.imageUrl),
|
|
10382
|
+
className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
|
|
10383
|
+
}
|
|
10384
|
+
),
|
|
10385
|
+
/* @__PURE__ */ jsx(
|
|
10386
|
+
"span",
|
|
10387
|
+
{
|
|
10388
|
+
"aria-hidden": "true",
|
|
10389
|
+
className: "pointer-events-none absolute left-1.5 top-1.5 rounded-full border border-border bg-background/90 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-foreground",
|
|
10390
|
+
children: T.conceptIllustration
|
|
10391
|
+
}
|
|
10392
|
+
)
|
|
10393
|
+
] }),
|
|
10394
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col gap-0.5 p-2.5", children: [
|
|
10395
|
+
/* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-xs font-semibold leading-snug text-card-foreground", children: highlight.title }),
|
|
10396
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: highlight.productName })
|
|
10397
|
+
] })
|
|
10398
|
+
]
|
|
10399
|
+
}
|
|
10400
|
+
)
|
|
10401
|
+
},
|
|
10402
|
+
`${highlight.product}:${highlight.url}`
|
|
10403
|
+
))
|
|
10404
|
+
}
|
|
10405
|
+
)
|
|
10406
|
+
]
|
|
10407
|
+
}
|
|
10408
|
+
);
|
|
10409
|
+
}
|
|
9281
10410
|
function DisclaimerDialog({
|
|
9282
10411
|
open,
|
|
9283
10412
|
onClose,
|
|
@@ -9384,6 +10513,7 @@ function WelcomeState({
|
|
|
9384
10513
|
body,
|
|
9385
10514
|
prompts,
|
|
9386
10515
|
products,
|
|
10516
|
+
conceptHighlights,
|
|
9387
10517
|
focusProduct,
|
|
9388
10518
|
onPrompt,
|
|
9389
10519
|
onFocus,
|
|
@@ -9398,6 +10528,15 @@ function WelcomeState({
|
|
|
9398
10528
|
/* @__PURE__ */ jsx("h1", { className: "mt-4 text-balance break-words text-2xl font-bold tracking-tight sm:text-4xl", children: title }),
|
|
9399
10529
|
/* @__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 })
|
|
9400
10530
|
] }),
|
|
10531
|
+
/* @__PURE__ */ jsx(
|
|
10532
|
+
ConceptStrip,
|
|
10533
|
+
{
|
|
10534
|
+
strings: T,
|
|
10535
|
+
highlights: conceptHighlights,
|
|
10536
|
+
onAsk: onPrompt,
|
|
10537
|
+
disabled
|
|
10538
|
+
}
|
|
10539
|
+
),
|
|
9401
10540
|
/* @__PURE__ */ jsx("ul", { className: "boff-explore-rise boff-explore-rise-1 mt-6 grid grid-cols-3 gap-2 sm:mt-7 sm:gap-2.5", children: CAPABILITIES.map(({ icon: Icon, body: capBody }, i) => /* @__PURE__ */ jsxs(
|
|
9402
10541
|
"li",
|
|
9403
10542
|
{
|
|
@@ -9459,6 +10598,7 @@ function ExplorePage({
|
|
|
9459
10598
|
);
|
|
9460
10599
|
const T = useMemo(() => exploreStrings(activeLocale), [activeLocale]);
|
|
9461
10600
|
const rtl = isRtlLocale(activeLocale);
|
|
10601
|
+
const speechLang = speechLocaleOf(activeLocale);
|
|
9462
10602
|
const {
|
|
9463
10603
|
phase,
|
|
9464
10604
|
catalog,
|
|
@@ -9543,6 +10683,10 @@ function ExplorePage({
|
|
|
9543
10683
|
() => inlineImageOrigins(catalog.products),
|
|
9544
10684
|
[catalog.products]
|
|
9545
10685
|
);
|
|
10686
|
+
const productNames = useMemo(
|
|
10687
|
+
() => productNamesByOrigin(catalog.products),
|
|
10688
|
+
[catalog.products]
|
|
10689
|
+
);
|
|
9546
10690
|
useEffect(() => {
|
|
9547
10691
|
const el = textareaRef.current;
|
|
9548
10692
|
if (!el) return;
|
|
@@ -9559,11 +10703,11 @@ function ExplorePage({
|
|
|
9559
10703
|
const layoutHeight = window.innerHeight;
|
|
9560
10704
|
if (layoutHeight === 0) return;
|
|
9561
10705
|
const top = Math.round(
|
|
9562
|
-
|
|
10706
|
+
clamp2(el.getBoundingClientRect().top, 0, layoutHeight)
|
|
9563
10707
|
);
|
|
9564
10708
|
const viewport = window.visualViewport;
|
|
9565
10709
|
const inset = viewport ? Math.round(
|
|
9566
|
-
|
|
10710
|
+
clamp2(
|
|
9567
10711
|
layoutHeight - viewport.height - viewport.offsetTop,
|
|
9568
10712
|
0,
|
|
9569
10713
|
layoutHeight
|
|
@@ -9844,6 +10988,7 @@ function ExplorePage({
|
|
|
9844
10988
|
const text = draft.trim();
|
|
9845
10989
|
if (!text || overLimit || busy || !canSend) return;
|
|
9846
10990
|
stopDictation();
|
|
10991
|
+
stopSpeaking();
|
|
9847
10992
|
setDraft("");
|
|
9848
10993
|
stickToBottomRef.current = true;
|
|
9849
10994
|
void send(text, toPayload(stagedRef.current));
|
|
@@ -9854,6 +10999,7 @@ function ExplorePage({
|
|
|
9854
10999
|
const sendPrompt = useCallback(
|
|
9855
11000
|
(prompt) => {
|
|
9856
11001
|
if (!canSend || busy) return;
|
|
11002
|
+
stopSpeaking();
|
|
9857
11003
|
setDraft("");
|
|
9858
11004
|
stickToBottomRef.current = true;
|
|
9859
11005
|
void send(prompt, toPayload(stagedRef.current));
|
|
@@ -10074,6 +11220,7 @@ function ExplorePage({
|
|
|
10074
11220
|
body: resolvedBody,
|
|
10075
11221
|
prompts,
|
|
10076
11222
|
products: catalog.products,
|
|
11223
|
+
conceptHighlights: catalog.conceptHighlights,
|
|
10077
11224
|
focusProduct,
|
|
10078
11225
|
onPrompt: sendPrompt,
|
|
10079
11226
|
onFocus: setFocusProduct,
|
|
@@ -10087,6 +11234,8 @@ function ExplorePage({
|
|
|
10087
11234
|
message,
|
|
10088
11235
|
activity,
|
|
10089
11236
|
imageOrigins,
|
|
11237
|
+
productNames,
|
|
11238
|
+
speechLang,
|
|
10090
11239
|
onNavigate,
|
|
10091
11240
|
anchorRef: message.id === latestAssistantId ? latestAssistantRef : void 0,
|
|
10092
11241
|
onFollow: (kind, url) => recordClick(message.id, kind, url),
|
|
@@ -15048,6 +16197,6 @@ function StoreProductDetailPage({
|
|
|
15048
16197
|
] });
|
|
15049
16198
|
}
|
|
15050
16199
|
|
|
15051
|
-
export { BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, EXPLORE_CATALOG_QUERY, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, classifyExploreError, cn, conceptPath, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatDownloads, formatPrice2 as formatPrice, getConceptBySlug, getRecaptchaV3Token, isValidUrl, loadRecaptchaV3, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useWebSDK, useWebSDKConfig };
|
|
16200
|
+
export { BlogListPage, BlogPostPage, Button, CONCEPTS_PATH, CONCEPT_ILLUSTRATION_NOTICE, CONCEPT_PATH_PREFIX, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ConceptDetailPage, ConceptsPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, DEFAULT_EXPLORE_EXAMPLE_PROMPTS, ECOSYSTEM_PRODUCTS, EXPLORE_CATALOG_QUERY, EXPLORE_CATALOG_QUERY_WITHOUT_HIGHLIGHTS, EXPLORE_LOCALES, EXPLORE_MESSAGE_QUERY, EXPLORE_RECAPTCHA_ACTION, ElectronDownloadLink, ExploreCta, ExplorePage, FALLBACK_EXPLORE_LIMITS, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, SEND_EXPLORE_MESSAGE_MUTATION, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, classifyExploreError, cn, conceptPath, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, fetchPublicJobPostingsForSubmission, formatDownloads, formatPrice2 as formatPrice, getConceptBySlug, getRecaptchaV3Token, isValidUrl, loadRecaptchaV3, speechLocaleOf, stopSpeaking, useContentPage, useContentPages, useExploreChat, useProduct, useProductConfig, useProgressiveReveal, usePublicJobPosting, usePublicJobPostings, usePublicJobPostingsForSubmission, useSpeechOutput, useWebSDK, useWebSDKConfig };
|
|
15052
16201
|
//# sourceMappingURL=index.mjs.map
|
|
15053
16202
|
//# sourceMappingURL=index.mjs.map
|