@akropolys/kiku 1.6.3 → 1.6.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/index.d.mts CHANGED
@@ -4,7 +4,7 @@ import { SearchResult, AkropolysTheme, ChatSource, Product, VisualSearchResponse
4
4
  interface SearchBarProps {
5
5
  placeholder?: string;
6
6
  limit?: number;
7
- /** Debounce in ms — default 300 for smooth type-ahead */
7
+ /** Debounce in ms — default 150 for instant type-ahead */
8
8
  debounceMs?: number;
9
9
  onSelect?: (result: SearchResult) => void;
10
10
  className?: string;
@@ -65,12 +65,15 @@ interface KikuButtonProps {
65
65
  };
66
66
  /** Enable 🎙️ voice input via browser Web Speech API (free) */
67
67
  enableVoice?: boolean;
68
+ /** BCP-47 tag for voice transcription (e.g. 'sw-KE', 'fr-FR'). Defaults to
69
+ the page's <html lang>, then the browser language. */
70
+ voiceLang?: string;
68
71
  /** Enable 📷 visual style-match search via Gemini (requires backend GEMINI_API_KEY) */
69
72
  enableVision?: boolean;
70
73
  /** Optional category hint for visual search (e.g. 'dress', 'curtains') */
71
74
  visionCategoryHint?: string;
72
75
  }
73
- declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
76
+ declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, voiceLang, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
74
77
 
75
78
  interface SparkleProps {
76
79
  productName: string;
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { SearchResult, AkropolysTheme, ChatSource, Product, VisualSearchResponse
4
4
  interface SearchBarProps {
5
5
  placeholder?: string;
6
6
  limit?: number;
7
- /** Debounce in ms — default 300 for smooth type-ahead */
7
+ /** Debounce in ms — default 150 for instant type-ahead */
8
8
  debounceMs?: number;
9
9
  onSelect?: (result: SearchResult) => void;
10
10
  className?: string;
@@ -65,12 +65,15 @@ interface KikuButtonProps {
65
65
  };
66
66
  /** Enable 🎙️ voice input via browser Web Speech API (free) */
67
67
  enableVoice?: boolean;
68
+ /** BCP-47 tag for voice transcription (e.g. 'sw-KE', 'fr-FR'). Defaults to
69
+ the page's <html lang>, then the browser language. */
70
+ voiceLang?: string;
68
71
  /** Enable 📷 visual style-match search via Gemini (requires backend GEMINI_API_KEY) */
69
72
  enableVision?: boolean;
70
73
  /** Optional category hint for visual search (e.g. 'dress', 'curtains') */
71
74
  visionCategoryHint?: string;
72
75
  }
73
- declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
76
+ declare function KikuButton({ label, title, placeholder, backdropColor, backdropBlur, className, onSelectSource, defaultCurrency, chips, theme, classNames, enableVoice, voiceLang, enableVision, visionCategoryHint, }: KikuButtonProps): React.JSX.Element;
74
77
 
75
78
  interface SparkleProps {
76
79
  productName: string;
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ var SearchIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { wid
52
52
  function SearchBar({
53
53
  placeholder = "Search products\u2026",
54
54
  limit = 10,
55
- debounceMs = 300,
55
+ debounceMs = 150,
56
56
  onSelect,
57
57
  className,
58
58
  inputClassName,
@@ -63,10 +63,8 @@ function SearchBar({
63
63
  }) {
64
64
  const [query, setQuery] = (0, import_react.useState)("");
65
65
  const [open, setOpen] = (0, import_react.useState)(false);
66
- const [isDebouncing, setIsDebouncing] = (0, import_react.useState)(false);
67
- const { results, loading, search, clear } = (0, import_sdk.useSearch)();
66
+ const { results, loading, search, clear } = (0, import_sdk.useSearch)({ debounceMs });
68
67
  const client = (0, import_sdk.useAkropolysContext)();
69
- const timer = (0, import_react.useRef)();
70
68
  const wrap = (0, import_react.useRef)(null);
71
69
  const ignoreNextQueryChange = (0, import_react.useRef)(false);
72
70
  (0, import_react.useEffect)(() => {
@@ -74,20 +72,13 @@ function SearchBar({
74
72
  ignoreNextQueryChange.current = false;
75
73
  return;
76
74
  }
77
- clearTimeout(timer.current);
78
75
  if (!query.trim()) {
79
76
  clear();
80
77
  setOpen(false);
81
- setIsDebouncing(false);
82
78
  return;
83
79
  }
84
80
  setOpen(true);
85
- setIsDebouncing(true);
86
- timer.current = setTimeout(() => {
87
- setIsDebouncing(false);
88
- search(query, limit);
89
- }, debounceMs);
90
- return () => clearTimeout(timer.current);
81
+ search(query, limit);
91
82
  }, [query]);
92
83
  (0, import_react.useEffect)(() => {
93
84
  const h = (e) => {
@@ -143,8 +134,8 @@ function SearchBar({
143
134
  }
144
135
  ),
145
136
  showDrop && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("hsk-sb-drop", classNames.dropdown, dropdownClassName), style: { position: "absolute" }, children: [
146
- (loading || isDebouncing) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-loading-bar" }),
147
- (loading || isDebouncing) && results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
137
+ loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-loading-bar" }),
138
+ loading && results.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
148
139
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-skeleton-row", children: [
149
140
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-skeleton-icon" }),
150
141
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
@@ -160,36 +151,52 @@ function SearchBar({
160
151
  ] })
161
152
  ] })
162
153
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
163
- results.length === 0 && !loading && !isDebouncing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-empty", children: [
154
+ results.length === 0 && !loading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-empty", children: [
164
155
  "No results for \u201C",
165
156
  query,
166
157
  "\u201D"
167
158
  ] }),
168
- results.map((r, i) => renderResult ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
169
- "div",
170
- {
171
- onClick: () => handleSelect(r),
172
- className: "hsk-sb-fade",
173
- style: { animationDelay: `${i * 18}ms` },
174
- children: renderResult(r)
175
- },
176
- r.id
177
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
178
- "div",
179
- {
180
- className: cn("hsk-sb-row hsk-sb-fade", classNames.row),
181
- style: { animationDelay: `${i * 18}ms` },
182
- onClick: () => handleSelect(r),
183
- children: [
184
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-row-icon", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) }),
185
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
186
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-title", children: r.entity.title ?? r.entity.name }),
187
- (r.entity.category || r.entity.brand) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-sub", children: r.entity.category ?? r.entity.brand })
188
- ] })
189
- ]
190
- },
191
- r.id
192
- ))
159
+ results.map((r, i) => {
160
+ if (renderResult) {
161
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
162
+ "div",
163
+ {
164
+ onClick: () => handleSelect(r),
165
+ className: "hsk-sb-fade",
166
+ style: { animationDelay: `${i * 18}ms` },
167
+ children: renderResult(r)
168
+ },
169
+ r.id
170
+ );
171
+ }
172
+ const thumb = r.entity.image ?? r.entity.thumbnail ?? r.entity.images?.[0];
173
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
174
+ "div",
175
+ {
176
+ className: cn("hsk-sb-row hsk-sb-fade", classNames.row),
177
+ style: { animationDelay: `${i * 18}ms` },
178
+ onClick: () => handleSelect(r),
179
+ children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hsk-sb-row-thumb", children: thumb ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
+ "img",
182
+ {
183
+ src: thumb,
184
+ alt: "",
185
+ loading: "lazy",
186
+ onError: (e) => {
187
+ e.currentTarget.style.display = "none";
188
+ }
189
+ }
190
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchIcon, {}) }),
191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "hsk-sb-row-body", children: [
192
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-title", children: r.entity.title ?? r.entity.name }),
193
+ (r.entity.category || r.entity.brand) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "hsk-sb-row-sub", children: r.entity.category ?? r.entity.brand })
194
+ ] })
195
+ ]
196
+ },
197
+ r.id
198
+ );
199
+ })
193
200
  ] })
194
201
  ] })
195
202
  ] });
@@ -1727,18 +1734,7 @@ var getFriendlyError = (err) => {
1727
1734
  return str;
1728
1735
  }
1729
1736
  };
1730
- var MK_ADJ = ["flying", "silent", "golden", "lucky", "brave", "swift", "royal", "cosmic"];
1731
- var MK_NOUN = ["thunder", "falcon", "river", "ember", "tiger", "comet", "willow", "onyx"];
1732
- function generateMagicWord() {
1733
- return MK_ADJ[Math.floor(Math.random() * MK_ADJ.length)] + MK_NOUN[Math.floor(Math.random() * MK_NOUN.length)];
1734
- }
1735
- function parseMemoryKey(raw) {
1736
- const cleaned = raw.trim().replace(/\s+/g, "");
1737
- const m = cleaned.match(/^(\d{6,})([a-zA-Z].*)?$/);
1738
- const phone = m?.[1] || cleaned.replace(/\D/g, "");
1739
- const word = (m?.[2] || "").toLowerCase() || generateMagicWord();
1740
- return { phone, word };
1741
- }
1737
+ var KIKU_KEY_REVEAL_SECONDS = 60;
1742
1738
  function parseThinking(text) {
1743
1739
  const openMatch = text.match(/<\s*thinking\s*>/i);
1744
1740
  if (!openMatch) {
@@ -1846,6 +1842,7 @@ function ChatModal({
1846
1842
  theme,
1847
1843
  classNames = {},
1848
1844
  enableVoice = false,
1845
+ voiceLang,
1849
1846
  enableVision = false,
1850
1847
  visionCategoryHint
1851
1848
  }) {
@@ -1879,7 +1876,7 @@ function ChatModal({
1879
1876
  if (!hasSpeechAPI || voiceState !== "idle") return;
1880
1877
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
1881
1878
  const recognition = new SR();
1882
- recognition.lang = "en-US";
1879
+ recognition.lang = voiceLang || document.documentElement.lang || navigator.language || "en-US";
1883
1880
  recognition.interimResults = true;
1884
1881
  recognition.maxAlternatives = 1;
1885
1882
  recognitionRef.current = recognition;
@@ -1912,7 +1909,7 @@ function ChatModal({
1912
1909
  setVoiceState((prev) => prev === "listening" ? "idle" : prev);
1913
1910
  };
1914
1911
  recognition.start();
1915
- }, [hasSpeechAPI, voiceState]);
1912
+ }, [hasSpeechAPI, voiceState, voiceLang]);
1916
1913
  const stopVoice = (0, import_react5.useCallback)(() => {
1917
1914
  recognitionRef.current?.stop();
1918
1915
  setVoiceState("idle");
@@ -1927,14 +1924,11 @@ function ChatModal({
1927
1924
  const [selectedProduct, setSelectedProduct] = (0, import_react5.useState)(null);
1928
1925
  const bottomRef = (0, import_react5.useRef)(null);
1929
1926
  const textareaRef = (0, import_react5.useRef)(null);
1930
- const [phoneInput, setPhoneInput] = (0, import_react5.useState)(() => {
1931
- if (typeof window !== "undefined") {
1932
- return localStorage.getItem("akropolys_user_phone") || "";
1933
- }
1934
- return "";
1935
- });
1936
- const [paymentPhase, setPaymentPhase] = (0, import_react5.useState)("idle");
1937
- const [memoryKey, setMemoryKey] = (0, import_react5.useState)(null);
1927
+ const [keyInput, setKeyInput] = (0, import_react5.useState)("");
1928
+ const [keyPhase, setKeyPhase] = (0, import_react5.useState)("idle");
1929
+ const [mintedKey, setMintedKey] = (0, import_react5.useState)(null);
1930
+ const [keyCountdown, setKeyCountdown] = (0, import_react5.useState)(KIKU_KEY_REVEAL_SECONDS);
1931
+ const [minting, setMinting] = (0, import_react5.useState)(false);
1938
1932
  const [showKikuPicker, setShowKikuPicker] = (0, import_react5.useState)(false);
1939
1933
  const [showAtPicker, setShowAtPicker] = (0, import_react5.useState)(false);
1940
1934
  const [sessions, setSessions] = (0, import_react5.useState)(() => loadSessions());
@@ -1942,10 +1936,25 @@ function ChatModal({
1942
1936
  const [replayMessages, setReplayMessages] = (0, import_react5.useState)(null);
1943
1937
  (0, import_react5.useEffect)(() => {
1944
1938
  if (!lastAction) return;
1945
- if (lastAction.type === "request_phone") {
1946
- setPaymentPhase("prompt_phone");
1939
+ if (lastAction.type === "request_kiku_key") {
1940
+ setKeyPhase("prompt_key");
1947
1941
  }
1948
1942
  }, [lastAction]);
1943
+ (0, import_react5.useEffect)(() => {
1944
+ if (!mintedKey) return;
1945
+ setKeyCountdown(KIKU_KEY_REVEAL_SECONDS);
1946
+ const t = setInterval(() => {
1947
+ setKeyCountdown((s) => {
1948
+ if (s <= 1) {
1949
+ clearInterval(t);
1950
+ setMintedKey(null);
1951
+ return 0;
1952
+ }
1953
+ return s - 1;
1954
+ });
1955
+ }, 1e3);
1956
+ return () => clearInterval(t);
1957
+ }, [mintedKey]);
1949
1958
  const isStringTheme = typeof theme === "string";
1950
1959
  const hskThemeAttr = isStringTheme ? theme : void 0;
1951
1960
  const customStyles = !isStringTheme && theme ? {
@@ -1955,16 +1964,30 @@ function ChatModal({
1955
1964
  ...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
1956
1965
  ...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
1957
1966
  } : void 0;
1958
- const handlePhoneSubmit = async () => {
1959
- if (!phoneInput.trim()) return;
1960
- const { phone, word } = parseMemoryKey(phoneInput);
1961
- if (!phone) return;
1962
- if (typeof window !== "undefined") localStorage.setItem("akropolys_user_phone", phone);
1963
- client.setShopperIdentity(phone, word);
1964
- setMemoryKey(phone + word);
1965
- setPaymentPhase("idle");
1967
+ const retryLastMessage = async () => {
1966
1968
  const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
1967
- if (lastUserMsg) await send(lastUserMsg.content);
1969
+ if (lastUserMsg) await handleSend(lastUserMsg.content);
1970
+ };
1971
+ const handleUseExistingKey = async () => {
1972
+ const key = keyInput.trim();
1973
+ if (!key) return;
1974
+ client.setKikuKey(key);
1975
+ setKeyInput("");
1976
+ setKeyPhase("idle");
1977
+ await retryLastMessage();
1978
+ };
1979
+ const handleCreateKey = async () => {
1980
+ if (minting) return;
1981
+ setMinting(true);
1982
+ try {
1983
+ const key = await client.mintKikuKey();
1984
+ setMintedKey(key);
1985
+ setKeyPhase("idle");
1986
+ await retryLastMessage();
1987
+ } catch {
1988
+ } finally {
1989
+ setMinting(false);
1990
+ }
1968
1991
  };
1969
1992
  const msgsContainerRef = (0, import_react5.useRef)(null);
1970
1993
  (0, import_react5.useEffect)(() => {
@@ -1999,7 +2022,7 @@ function ChatModal({
1999
2022
  saveCurrentSession();
2000
2023
  reset();
2001
2024
  setReplayMessages(null);
2002
- setPaymentPhase("idle");
2025
+ setKeyPhase("idle");
2003
2026
  }, [reset, saveCurrentSession]);
2004
2027
  const handleSourceClick = (src) => {
2005
2028
  setSelectedProduct(src);
@@ -2252,7 +2275,7 @@ function ChatModal({
2252
2275
  ] });
2253
2276
  })(),
2254
2277
  isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ComparisonMatrix, { sources, defaultCurrency }),
2255
- isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "request_phone" && lastAction?.type !== "awaiting_payment" && lastAction?.type !== "checkout" && lastAction?.type !== "capture" && lastAction?.type !== "delete" && lastAction?.type !== "view_history" && !msg.cartSnapshot && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2278
+ isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "request_kiku_key" && lastAction?.type !== "awaiting_payment" && lastAction?.type !== "checkout" && lastAction?.type !== "capture" && lastAction?.type !== "delete" && lastAction?.type !== "view_history" && !msg.cartSnapshot && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2256
2279
  SourcesCarousel,
2257
2280
  {
2258
2281
  sources,
@@ -2325,38 +2348,45 @@ function ChatModal({
2325
2348
  ] })
2326
2349
  ] }),
2327
2350
  error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
2328
- !replayMessages && paymentPhase === "prompt_phone" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
2351
+ !replayMessages && keyPhase === "prompt_key" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
2329
2352
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}) }),
2330
2353
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-phone-form", children: [
2331
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "hsk-cb-phone-label", children: "Your phone number \u2014 or paste your memory key" }),
2354
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "hsk-cb-phone-label", children: "Paste your kiku key \u2014 or create one" }),
2332
2355
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2333
2356
  "input",
2334
2357
  {
2335
2358
  type: "text",
2336
2359
  className: "hsk-cb-phone-input",
2337
- placeholder: "0712345678 or 0712345678flyingthunder",
2338
- value: phoneInput,
2339
- onChange: (e) => setPhoneInput(e.target.value.replace(/[^0-9a-zA-Z]/g, "")),
2340
- onKeyDown: (e) => e.key === "Enter" && handlePhoneSubmit(),
2360
+ placeholder: "kiku_\u2026",
2361
+ value: keyInput,
2362
+ onChange: (e) => setKeyInput(e.target.value),
2363
+ onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
2341
2364
  autoFocus: true
2342
2365
  }
2343
2366
  ),
2344
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", onClick: handlePhoneSubmit, children: "Save & sync my items" })
2367
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
2368
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my key" }),
2369
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create my key" })
2370
+ ] })
2345
2371
  ] }) }) })
2346
2372
  ] }),
2347
- !replayMessages && memoryKey && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
2373
+ !replayMessages && mintedKey && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-ai-msg", children: [
2348
2374
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}) }),
2349
2375
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { padding: "10px 12px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: 8 }, children: [
2350
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your memory key" }),
2351
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: memoryKey }),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your kiku key \u2014 shown only once" }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
2352
2378
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
2353
2379
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
2354
2380
  try {
2355
- navigator.clipboard?.writeText(memoryKey);
2381
+ navigator.clipboard?.writeText(mintedKey);
2356
2382
  } catch {
2357
2383
  }
2358
2384
  }, children: "Copy" }),
2359
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontSize: 11, opacity: 0.7 }, children: "Save it \u2014 enter it on any site to get your items back." })
2385
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { fontSize: 11, opacity: 0.7 }, children: [
2386
+ "Disappears in ",
2387
+ keyCountdown,
2388
+ "s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
2389
+ ] })
2360
2390
  ] })
2361
2391
  ] }) }) })
2362
2392
  ] }),
@@ -2481,6 +2511,7 @@ function KikuButton({
2481
2511
  theme,
2482
2512
  classNames = {},
2483
2513
  enableVoice = false,
2514
+ voiceLang,
2484
2515
  enableVision = false,
2485
2516
  visionCategoryHint
2486
2517
  }) {
@@ -2550,6 +2581,7 @@ function KikuButton({
2550
2581
  theme,
2551
2582
  classNames,
2552
2583
  enableVoice,
2584
+ voiceLang,
2553
2585
  enableVision,
2554
2586
  visionCategoryHint
2555
2587
  }