@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 +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +119 -87
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -87
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +22 -3
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -20,7 +20,7 @@ var SearchIcon = () => /* @__PURE__ */ jsxs("svg", { width: "15", height: "15",
|
|
|
20
20
|
function SearchBar({
|
|
21
21
|
placeholder = "Search products\u2026",
|
|
22
22
|
limit = 10,
|
|
23
|
-
debounceMs =
|
|
23
|
+
debounceMs = 150,
|
|
24
24
|
onSelect,
|
|
25
25
|
className,
|
|
26
26
|
inputClassName,
|
|
@@ -31,10 +31,8 @@ function SearchBar({
|
|
|
31
31
|
}) {
|
|
32
32
|
const [query, setQuery] = useState("");
|
|
33
33
|
const [open, setOpen] = useState(false);
|
|
34
|
-
const
|
|
35
|
-
const { results, loading, search, clear } = useSearch();
|
|
34
|
+
const { results, loading, search, clear } = useSearch({ debounceMs });
|
|
36
35
|
const client = useAkropolysContext();
|
|
37
|
-
const timer = useRef();
|
|
38
36
|
const wrap = useRef(null);
|
|
39
37
|
const ignoreNextQueryChange = useRef(false);
|
|
40
38
|
useEffect(() => {
|
|
@@ -42,20 +40,13 @@ function SearchBar({
|
|
|
42
40
|
ignoreNextQueryChange.current = false;
|
|
43
41
|
return;
|
|
44
42
|
}
|
|
45
|
-
clearTimeout(timer.current);
|
|
46
43
|
if (!query.trim()) {
|
|
47
44
|
clear();
|
|
48
45
|
setOpen(false);
|
|
49
|
-
setIsDebouncing(false);
|
|
50
46
|
return;
|
|
51
47
|
}
|
|
52
48
|
setOpen(true);
|
|
53
|
-
|
|
54
|
-
timer.current = setTimeout(() => {
|
|
55
|
-
setIsDebouncing(false);
|
|
56
|
-
search(query, limit);
|
|
57
|
-
}, debounceMs);
|
|
58
|
-
return () => clearTimeout(timer.current);
|
|
49
|
+
search(query, limit);
|
|
59
50
|
}, [query]);
|
|
60
51
|
useEffect(() => {
|
|
61
52
|
const h = (e) => {
|
|
@@ -111,8 +102,8 @@ function SearchBar({
|
|
|
111
102
|
}
|
|
112
103
|
),
|
|
113
104
|
showDrop && /* @__PURE__ */ jsxs("div", { className: cn("hsk-sb-drop", classNames.dropdown, dropdownClassName), style: { position: "absolute" }, children: [
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
loading && /* @__PURE__ */ jsx("div", { className: "hsk-sb-loading-bar" }),
|
|
106
|
+
loading && results.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
116
107
|
/* @__PURE__ */ jsxs("div", { className: "hsk-sb-skeleton-row", children: [
|
|
117
108
|
/* @__PURE__ */ jsx("span", { className: "hsk-sb-skeleton-icon" }),
|
|
118
109
|
/* @__PURE__ */ jsxs("div", { className: "hsk-sb-row-body", children: [
|
|
@@ -128,36 +119,52 @@ function SearchBar({
|
|
|
128
119
|
] })
|
|
129
120
|
] })
|
|
130
121
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
131
|
-
results.length === 0 && !loading &&
|
|
122
|
+
results.length === 0 && !loading && /* @__PURE__ */ jsxs("div", { className: "hsk-sb-empty", children: [
|
|
132
123
|
"No results for \u201C",
|
|
133
124
|
query,
|
|
134
125
|
"\u201D"
|
|
135
126
|
] }),
|
|
136
|
-
results.map((r, i) =>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
127
|
+
results.map((r, i) => {
|
|
128
|
+
if (renderResult) {
|
|
129
|
+
return /* @__PURE__ */ jsx(
|
|
130
|
+
"div",
|
|
131
|
+
{
|
|
132
|
+
onClick: () => handleSelect(r),
|
|
133
|
+
className: "hsk-sb-fade",
|
|
134
|
+
style: { animationDelay: `${i * 18}ms` },
|
|
135
|
+
children: renderResult(r)
|
|
136
|
+
},
|
|
137
|
+
r.id
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
const thumb = r.entity.image ?? r.entity.thumbnail ?? r.entity.images?.[0];
|
|
141
|
+
return /* @__PURE__ */ jsxs(
|
|
142
|
+
"div",
|
|
143
|
+
{
|
|
144
|
+
className: cn("hsk-sb-row hsk-sb-fade", classNames.row),
|
|
145
|
+
style: { animationDelay: `${i * 18}ms` },
|
|
146
|
+
onClick: () => handleSelect(r),
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsx("span", { className: "hsk-sb-row-thumb", children: thumb ? /* @__PURE__ */ jsx(
|
|
149
|
+
"img",
|
|
150
|
+
{
|
|
151
|
+
src: thumb,
|
|
152
|
+
alt: "",
|
|
153
|
+
loading: "lazy",
|
|
154
|
+
onError: (e) => {
|
|
155
|
+
e.currentTarget.style.display = "none";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
) : /* @__PURE__ */ jsx(SearchIcon, {}) }),
|
|
159
|
+
/* @__PURE__ */ jsxs("div", { className: "hsk-sb-row-body", children: [
|
|
160
|
+
/* @__PURE__ */ jsx("div", { className: "hsk-sb-row-title", children: r.entity.title ?? r.entity.name }),
|
|
161
|
+
(r.entity.category || r.entity.brand) && /* @__PURE__ */ jsx("div", { className: "hsk-sb-row-sub", children: r.entity.category ?? r.entity.brand })
|
|
162
|
+
] })
|
|
163
|
+
]
|
|
164
|
+
},
|
|
165
|
+
r.id
|
|
166
|
+
);
|
|
167
|
+
})
|
|
161
168
|
] })
|
|
162
169
|
] })
|
|
163
170
|
] });
|
|
@@ -1695,18 +1702,7 @@ var getFriendlyError = (err) => {
|
|
|
1695
1702
|
return str;
|
|
1696
1703
|
}
|
|
1697
1704
|
};
|
|
1698
|
-
var
|
|
1699
|
-
var MK_NOUN = ["thunder", "falcon", "river", "ember", "tiger", "comet", "willow", "onyx"];
|
|
1700
|
-
function generateMagicWord() {
|
|
1701
|
-
return MK_ADJ[Math.floor(Math.random() * MK_ADJ.length)] + MK_NOUN[Math.floor(Math.random() * MK_NOUN.length)];
|
|
1702
|
-
}
|
|
1703
|
-
function parseMemoryKey(raw) {
|
|
1704
|
-
const cleaned = raw.trim().replace(/\s+/g, "");
|
|
1705
|
-
const m = cleaned.match(/^(\d{6,})([a-zA-Z].*)?$/);
|
|
1706
|
-
const phone = m?.[1] || cleaned.replace(/\D/g, "");
|
|
1707
|
-
const word = (m?.[2] || "").toLowerCase() || generateMagicWord();
|
|
1708
|
-
return { phone, word };
|
|
1709
|
-
}
|
|
1705
|
+
var KIKU_KEY_REVEAL_SECONDS = 60;
|
|
1710
1706
|
function parseThinking(text) {
|
|
1711
1707
|
const openMatch = text.match(/<\s*thinking\s*>/i);
|
|
1712
1708
|
if (!openMatch) {
|
|
@@ -1814,6 +1810,7 @@ function ChatModal({
|
|
|
1814
1810
|
theme,
|
|
1815
1811
|
classNames = {},
|
|
1816
1812
|
enableVoice = false,
|
|
1813
|
+
voiceLang,
|
|
1817
1814
|
enableVision = false,
|
|
1818
1815
|
visionCategoryHint
|
|
1819
1816
|
}) {
|
|
@@ -1847,7 +1844,7 @@ function ChatModal({
|
|
|
1847
1844
|
if (!hasSpeechAPI || voiceState !== "idle") return;
|
|
1848
1845
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
1849
1846
|
const recognition = new SR();
|
|
1850
|
-
recognition.lang = "en-US";
|
|
1847
|
+
recognition.lang = voiceLang || document.documentElement.lang || navigator.language || "en-US";
|
|
1851
1848
|
recognition.interimResults = true;
|
|
1852
1849
|
recognition.maxAlternatives = 1;
|
|
1853
1850
|
recognitionRef.current = recognition;
|
|
@@ -1880,7 +1877,7 @@ function ChatModal({
|
|
|
1880
1877
|
setVoiceState((prev) => prev === "listening" ? "idle" : prev);
|
|
1881
1878
|
};
|
|
1882
1879
|
recognition.start();
|
|
1883
|
-
}, [hasSpeechAPI, voiceState]);
|
|
1880
|
+
}, [hasSpeechAPI, voiceState, voiceLang]);
|
|
1884
1881
|
const stopVoice = useCallback2(() => {
|
|
1885
1882
|
recognitionRef.current?.stop();
|
|
1886
1883
|
setVoiceState("idle");
|
|
@@ -1895,14 +1892,11 @@ function ChatModal({
|
|
|
1895
1892
|
const [selectedProduct, setSelectedProduct] = useState5(null);
|
|
1896
1893
|
const bottomRef = useRef5(null);
|
|
1897
1894
|
const textareaRef = useRef5(null);
|
|
1898
|
-
const [
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
});
|
|
1904
|
-
const [paymentPhase, setPaymentPhase] = useState5("idle");
|
|
1905
|
-
const [memoryKey, setMemoryKey] = useState5(null);
|
|
1895
|
+
const [keyInput, setKeyInput] = useState5("");
|
|
1896
|
+
const [keyPhase, setKeyPhase] = useState5("idle");
|
|
1897
|
+
const [mintedKey, setMintedKey] = useState5(null);
|
|
1898
|
+
const [keyCountdown, setKeyCountdown] = useState5(KIKU_KEY_REVEAL_SECONDS);
|
|
1899
|
+
const [minting, setMinting] = useState5(false);
|
|
1906
1900
|
const [showKikuPicker, setShowKikuPicker] = useState5(false);
|
|
1907
1901
|
const [showAtPicker, setShowAtPicker] = useState5(false);
|
|
1908
1902
|
const [sessions, setSessions] = useState5(() => loadSessions());
|
|
@@ -1910,10 +1904,25 @@ function ChatModal({
|
|
|
1910
1904
|
const [replayMessages, setReplayMessages] = useState5(null);
|
|
1911
1905
|
useEffect3(() => {
|
|
1912
1906
|
if (!lastAction) return;
|
|
1913
|
-
if (lastAction.type === "
|
|
1914
|
-
|
|
1907
|
+
if (lastAction.type === "request_kiku_key") {
|
|
1908
|
+
setKeyPhase("prompt_key");
|
|
1915
1909
|
}
|
|
1916
1910
|
}, [lastAction]);
|
|
1911
|
+
useEffect3(() => {
|
|
1912
|
+
if (!mintedKey) return;
|
|
1913
|
+
setKeyCountdown(KIKU_KEY_REVEAL_SECONDS);
|
|
1914
|
+
const t = setInterval(() => {
|
|
1915
|
+
setKeyCountdown((s) => {
|
|
1916
|
+
if (s <= 1) {
|
|
1917
|
+
clearInterval(t);
|
|
1918
|
+
setMintedKey(null);
|
|
1919
|
+
return 0;
|
|
1920
|
+
}
|
|
1921
|
+
return s - 1;
|
|
1922
|
+
});
|
|
1923
|
+
}, 1e3);
|
|
1924
|
+
return () => clearInterval(t);
|
|
1925
|
+
}, [mintedKey]);
|
|
1917
1926
|
const isStringTheme = typeof theme === "string";
|
|
1918
1927
|
const hskThemeAttr = isStringTheme ? theme : void 0;
|
|
1919
1928
|
const customStyles = !isStringTheme && theme ? {
|
|
@@ -1923,16 +1932,30 @@ function ChatModal({
|
|
|
1923
1932
|
...theme?.fontFamily && { "--hsk-font": theme.fontFamily },
|
|
1924
1933
|
...theme?.borderRadius && { "--hsk-border-radius": theme.borderRadius }
|
|
1925
1934
|
} : void 0;
|
|
1926
|
-
const
|
|
1927
|
-
if (!phoneInput.trim()) return;
|
|
1928
|
-
const { phone, word } = parseMemoryKey(phoneInput);
|
|
1929
|
-
if (!phone) return;
|
|
1930
|
-
if (typeof window !== "undefined") localStorage.setItem("akropolys_user_phone", phone);
|
|
1931
|
-
client.setShopperIdentity(phone, word);
|
|
1932
|
-
setMemoryKey(phone + word);
|
|
1933
|
-
setPaymentPhase("idle");
|
|
1935
|
+
const retryLastMessage = async () => {
|
|
1934
1936
|
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
1935
|
-
if (lastUserMsg) await
|
|
1937
|
+
if (lastUserMsg) await handleSend(lastUserMsg.content);
|
|
1938
|
+
};
|
|
1939
|
+
const handleUseExistingKey = async () => {
|
|
1940
|
+
const key = keyInput.trim();
|
|
1941
|
+
if (!key) return;
|
|
1942
|
+
client.setKikuKey(key);
|
|
1943
|
+
setKeyInput("");
|
|
1944
|
+
setKeyPhase("idle");
|
|
1945
|
+
await retryLastMessage();
|
|
1946
|
+
};
|
|
1947
|
+
const handleCreateKey = async () => {
|
|
1948
|
+
if (minting) return;
|
|
1949
|
+
setMinting(true);
|
|
1950
|
+
try {
|
|
1951
|
+
const key = await client.mintKikuKey();
|
|
1952
|
+
setMintedKey(key);
|
|
1953
|
+
setKeyPhase("idle");
|
|
1954
|
+
await retryLastMessage();
|
|
1955
|
+
} catch {
|
|
1956
|
+
} finally {
|
|
1957
|
+
setMinting(false);
|
|
1958
|
+
}
|
|
1936
1959
|
};
|
|
1937
1960
|
const msgsContainerRef = useRef5(null);
|
|
1938
1961
|
useEffect3(() => {
|
|
@@ -1967,7 +1990,7 @@ function ChatModal({
|
|
|
1967
1990
|
saveCurrentSession();
|
|
1968
1991
|
reset();
|
|
1969
1992
|
setReplayMessages(null);
|
|
1970
|
-
|
|
1993
|
+
setKeyPhase("idle");
|
|
1971
1994
|
}, [reset, saveCurrentSession]);
|
|
1972
1995
|
const handleSourceClick = (src) => {
|
|
1973
1996
|
setSelectedProduct(src);
|
|
@@ -2220,7 +2243,7 @@ function ChatModal({
|
|
|
2220
2243
|
] });
|
|
2221
2244
|
})(),
|
|
2222
2245
|
isLast && lastIntent === "compare" && sources.length >= 2 && !replayMessages && /* @__PURE__ */ jsx7(ComparisonMatrix, { sources, defaultCurrency }),
|
|
2223
|
-
isLast && referencedIds.length > 0 && lastIntent !== "compare" && lastAction?.type !== "
|
|
2246
|
+
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__ */ jsx7(
|
|
2224
2247
|
SourcesCarousel,
|
|
2225
2248
|
{
|
|
2226
2249
|
sources,
|
|
@@ -2293,38 +2316,45 @@ function ChatModal({
|
|
|
2293
2316
|
] })
|
|
2294
2317
|
] }),
|
|
2295
2318
|
error && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
|
|
2296
|
-
!replayMessages &&
|
|
2319
|
+
!replayMessages && keyPhase === "prompt_key" && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
|
|
2297
2320
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
|
|
2298
2321
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-phone-form", children: [
|
|
2299
|
-
/* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "
|
|
2322
|
+
/* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "Paste your kiku key \u2014 or create one" }),
|
|
2300
2323
|
/* @__PURE__ */ jsx7(
|
|
2301
2324
|
"input",
|
|
2302
2325
|
{
|
|
2303
2326
|
type: "text",
|
|
2304
2327
|
className: "hsk-cb-phone-input",
|
|
2305
|
-
placeholder: "
|
|
2306
|
-
value:
|
|
2307
|
-
onChange: (e) =>
|
|
2308
|
-
onKeyDown: (e) => e.key === "Enter" &&
|
|
2328
|
+
placeholder: "kiku_\u2026",
|
|
2329
|
+
value: keyInput,
|
|
2330
|
+
onChange: (e) => setKeyInput(e.target.value),
|
|
2331
|
+
onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
|
|
2309
2332
|
autoFocus: true
|
|
2310
2333
|
}
|
|
2311
2334
|
),
|
|
2312
|
-
/* @__PURE__ */
|
|
2335
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8 }, children: [
|
|
2336
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my key" }),
|
|
2337
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create my key" })
|
|
2338
|
+
] })
|
|
2313
2339
|
] }) }) })
|
|
2314
2340
|
] }),
|
|
2315
|
-
!replayMessages &&
|
|
2341
|
+
!replayMessages && mintedKey && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
|
|
2316
2342
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
|
|
2317
2343
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { style: { padding: "10px 12px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: 8 }, children: [
|
|
2318
|
-
/* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your
|
|
2319
|
-
/* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children:
|
|
2344
|
+
/* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "\u{1F511} Your kiku key \u2014 shown only once" }),
|
|
2345
|
+
/* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
|
|
2320
2346
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
2321
2347
|
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
|
|
2322
2348
|
try {
|
|
2323
|
-
navigator.clipboard?.writeText(
|
|
2349
|
+
navigator.clipboard?.writeText(mintedKey);
|
|
2324
2350
|
} catch {
|
|
2325
2351
|
}
|
|
2326
2352
|
}, children: "Copy" }),
|
|
2327
|
-
/* @__PURE__ */
|
|
2353
|
+
/* @__PURE__ */ jsxs6("span", { style: { fontSize: 11, opacity: 0.7 }, children: [
|
|
2354
|
+
"Disappears in ",
|
|
2355
|
+
keyCountdown,
|
|
2356
|
+
"s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
|
|
2357
|
+
] })
|
|
2328
2358
|
] })
|
|
2329
2359
|
] }) }) })
|
|
2330
2360
|
] }),
|
|
@@ -2449,6 +2479,7 @@ function KikuButton({
|
|
|
2449
2479
|
theme,
|
|
2450
2480
|
classNames = {},
|
|
2451
2481
|
enableVoice = false,
|
|
2482
|
+
voiceLang,
|
|
2452
2483
|
enableVision = false,
|
|
2453
2484
|
visionCategoryHint
|
|
2454
2485
|
}) {
|
|
@@ -2518,6 +2549,7 @@ function KikuButton({
|
|
|
2518
2549
|
theme,
|
|
2519
2550
|
classNames,
|
|
2520
2551
|
enableVoice,
|
|
2552
|
+
voiceLang,
|
|
2521
2553
|
enableVision,
|
|
2522
2554
|
visionCategoryHint
|
|
2523
2555
|
}
|