@akropolys/kiku 1.5.1 → 1.5.4

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.js CHANGED
@@ -472,18 +472,31 @@ var ArrowUpIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { w
472
472
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m5 12 7-7 7 7" }),
473
473
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19V5" })
474
474
  ] });
475
- function SourceCard({ source, defaultCurrency, onSelect }) {
476
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-source-card", onClick: () => onSelect?.(source), children: [
477
- source.image && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: source.image, alt: source.name, className: "hsk-source-img" }),
478
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
479
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-source-name", children: source.name }),
480
- source.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-source-price", children: [
481
- source.currency ?? defaultCurrency,
482
- " ",
483
- source.price
484
- ] })
485
- ] })
486
- ] });
475
+ function SourceCard({
476
+ source,
477
+ defaultCurrency,
478
+ onSelect,
479
+ isReferenced
480
+ }) {
481
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
482
+ "div",
483
+ {
484
+ className: cn("hsk-source-card", isReferenced && "hsk-source-card--referenced"),
485
+ onClick: () => onSelect?.(source),
486
+ children: [
487
+ source.image && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: source.image, alt: source.name, className: "hsk-source-img" }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: [
489
+ isReferenced && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", style: { top: "0", right: "0" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon, {}) }),
490
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-source-name", style: { paddingRight: isReferenced ? "20px" : void 0 }, children: source.name }),
491
+ source.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-source-price", children: [
492
+ source.currency ?? defaultCurrency,
493
+ " ",
494
+ source.price
495
+ ] })
496
+ ] })
497
+ ]
498
+ }
499
+ );
487
500
  }
488
501
  function ChatWidget({
489
502
  title = "AI Shopping Assistant",
@@ -499,7 +512,7 @@ function ChatWidget({
499
512
  enableVision = false,
500
513
  visionCategoryHint
501
514
  }) {
502
- const { messages, sources, loading: chatLoading, error, send, reset } = (0, import_sdk3.useKiku)();
515
+ const { messages, sources, referencedIds, loading: chatLoading, streaming, error, send, reset } = (0, import_sdk3.useKiku)();
503
516
  const [input, setInput] = (0, import_react4.useState)("");
504
517
  const [visualLoading, setVisualLoading] = (0, import_react4.useState)(false);
505
518
  const bottomRef = (0, import_react4.useRef)(null);
@@ -657,7 +670,54 @@ I couldn't find any matching products in the store.`;
657
670
  ] })
658
671
  ] }),
659
672
  msg.role === "assistant" && msg.visualSources && msg.visualSources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: msg.visualSources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SourceCard, { source: src, defaultCurrency, onSelect: onSelectSource }, si)) }) }),
660
- msg.role === "assistant" && idx === chatHistory.length - 1 && !msg.visualSources && sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: sources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SourceCard, { source: src, defaultCurrency, onSelect: onSelectSource }, si)) }) })
673
+ msg.role === "assistant" && idx === chatHistory.length - 1 && !msg.visualSources && sources.length > 0 && (() => {
674
+ const isStreamingActive = chatLoading || streaming;
675
+ if (isStreamingActive) {
676
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: sources.map((src, si) => {
677
+ const isReferenced = !!(src.id && referencedIds.includes(src.id));
678
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
679
+ SourceCard,
680
+ {
681
+ source: src,
682
+ defaultCurrency,
683
+ onSelect: onSelectSource,
684
+ isReferenced
685
+ },
686
+ si
687
+ );
688
+ }) }) });
689
+ }
690
+ const featured = sources.filter((src) => src.id && referencedIds.includes(src.id));
691
+ const general = sources.filter((src) => !src.id || !referencedIds.includes(src.id));
692
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-container", children: [
693
+ featured.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-group", style: { marginBottom: "10px" }, children: [
694
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-group-title", children: "\u2B50 Featured in response" }),
695
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: featured.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
696
+ SourceCard,
697
+ {
698
+ source: src,
699
+ defaultCurrency,
700
+ onSelect: onSelectSource,
701
+ isReferenced: true
702
+ },
703
+ `feat-${si}`
704
+ )) })
705
+ ] }),
706
+ general.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-group", children: [
707
+ featured.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-group-title", children: "All matches" }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: general.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
709
+ SourceCard,
710
+ {
711
+ source: src,
712
+ defaultCurrency,
713
+ onSelect: onSelectSource,
714
+ isReferenced: false
715
+ },
716
+ `gen-${si}`
717
+ )) })
718
+ ] })
719
+ ] });
720
+ })()
661
721
  ] }, idx)),
662
722
  loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-msg-row", children: [
663
723
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-msg-avatar ai", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon, {}) }),
@@ -1187,8 +1247,10 @@ function ActionPills({ cart, actionType, onSend, loading }) {
1187
1247
  const pills = [];
1188
1248
  if (hasItems && lastItem) {
1189
1249
  if (actionType === "add_to_cart") {
1190
- pills.push({ emoji: "\u2795", label: "Add 1 more", query: `Add one more ${lastItem.name} to my cart` });
1191
- pills.push({ emoji: "\u{1F5D1}\uFE0F", label: `Remove ${lastItem.name.split(" ")[0]}`, query: `Remove the ${lastItem.name} from my cart` });
1250
+ const name = lastItem.name || "item";
1251
+ const shortName = name.split(" ")[0] || "item";
1252
+ pills.push({ emoji: "\u2795", label: "Add 1 more", query: `Add one more ${name} to my cart` });
1253
+ pills.push({ emoji: "\u{1F5D1}\uFE0F", label: `Remove ${shortName}`, query: `Remove the ${name} from my cart` });
1192
1254
  }
1193
1255
  if (cart.items.length > 1) {
1194
1256
  pills.push({ emoji: "\u{1F6D2}", label: "View cart", query: "Show me my cart" });
@@ -1219,7 +1281,7 @@ function ActionPills({ cart, actionType, onSend, loading }) {
1219
1281
  pill.query
1220
1282
  )) });
1221
1283
  }
1222
- function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
1284
+ function SourcesCarousel({ sources, defaultCurrency, onSelectSource, referencedIds = [] }) {
1223
1285
  const client = (0, import_sdk6.useAkropolysContext)();
1224
1286
  const isProperty = client?.vertical === "property";
1225
1287
  const railRef = (0, import_react5.useRef)(null);
@@ -1246,44 +1308,51 @@ function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
1246
1308
  railRef.current?.scrollBy({ left: 170, behavior: "smooth" });
1247
1309
  };
1248
1310
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-sources-wrap", children: [
1249
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-sources", ref: railRef, children: sources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1250
- "div",
1251
- {
1252
- className: "hsk-cb-source",
1253
- style: { animationDelay: `${si * 50}ms` },
1254
- onClick: () => onSelectSource?.(src),
1255
- children: [
1256
- src.image ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-imgwrap", style: { position: "relative" }, children: [
1257
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: src.image, alt: src.name, loading: "lazy" }),
1258
- isProperty && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
1259
- position: "absolute",
1260
- top: "6px",
1261
- right: "6px",
1262
- background: "rgba(14, 14, 15, 0.75)",
1263
- backdropFilter: "blur(4px)",
1264
- borderRadius: "50%",
1265
- width: "24px",
1266
- height: "24px",
1267
- display: "flex",
1268
- alignItems: "center",
1269
- justifyContent: "center",
1270
- color: "#fbbf24",
1271
- // Gold sparkle badge
1272
- boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
1273
- }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 12 }) })
1274
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-src-imgwrap-empty", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}) }),
1275
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-info", children: [
1276
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-src-name", children: src.name }),
1277
- src.price && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-price", children: [
1278
- src.currency ?? defaultCurrency,
1279
- " ",
1280
- parseFloat(String(src.price).replace(/[^0-9.]/g, "") || "0").toLocaleString()
1311
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-sources", ref: railRef, children: sources.map((src, si) => {
1312
+ const isReferenced = !!(src.id && referencedIds.includes(src.id));
1313
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1314
+ "div",
1315
+ {
1316
+ className: cn("hsk-cb-source", isReferenced && "hsk-cb-source--referenced"),
1317
+ style: { animationDelay: `${si * 50}ms` },
1318
+ onClick: () => onSelectSource?.(src),
1319
+ children: [
1320
+ src.image ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-imgwrap", style: { position: "relative" }, children: [
1321
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: src.image, alt: src.name, loading: "lazy" }),
1322
+ isReferenced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 10 }) }),
1323
+ isProperty && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
1324
+ position: "absolute",
1325
+ top: "6px",
1326
+ right: "6px",
1327
+ background: "rgba(14, 14, 15, 0.75)",
1328
+ backdropFilter: "blur(4px)",
1329
+ borderRadius: "50%",
1330
+ width: "24px",
1331
+ height: "24px",
1332
+ display: "flex",
1333
+ alignItems: "center",
1334
+ justifyContent: "center",
1335
+ color: "#fbbf24",
1336
+ // Gold sparkle badge
1337
+ boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
1338
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 12 }) })
1339
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-imgwrap-empty", style: { position: "relative" }, children: [
1340
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}),
1341
+ isReferenced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 10 }) })
1342
+ ] }),
1343
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-info", children: [
1344
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-src-name", children: src.name }),
1345
+ src.price && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-price", children: [
1346
+ src.currency ?? defaultCurrency,
1347
+ " ",
1348
+ parseFloat(String(src.price).replace(/[^0-9.]/g, "") || "0").toLocaleString()
1349
+ ] })
1281
1350
  ] })
1282
- ] })
1283
- ]
1284
- },
1285
- si
1286
- )) }),
1351
+ ]
1352
+ },
1353
+ si
1354
+ );
1355
+ }) }),
1287
1356
  showNext && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1288
1357
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1289
1358
  "div",
@@ -1331,11 +1400,12 @@ function SmartContextPills({
1331
1400
  });
1332
1401
  }
1333
1402
  if (cheapest && !isProperty) {
1334
- const short = cheapest.name.split(" ").slice(0, 3).join(" ");
1403
+ const name = cheapest.name || "";
1404
+ const short = name.split(" ").slice(0, 3).join(" ");
1335
1405
  pills.push({
1336
1406
  emoji: "\u{1F6D2}",
1337
1407
  label: `Add ${short}`,
1338
- query: `Add the ${cheapest.name} to my cart`
1408
+ query: `Add the ${name} to my cart`
1339
1409
  });
1340
1410
  }
1341
1411
  if (isProperty) {
@@ -1345,11 +1415,12 @@ function SmartContextPills({
1345
1415
  }
1346
1416
  } else if (intent === "compare" && sources.length > 0) {
1347
1417
  if (cheapest && !isProperty) {
1348
- const short = cheapest.name.split(" ").slice(0, 3).join(" ");
1418
+ const name = cheapest.name || "";
1419
+ const short = name.split(" ").slice(0, 3).join(" ");
1349
1420
  pills.push({
1350
1421
  emoji: "\u{1F6D2}",
1351
1422
  label: `Add ${short}`,
1352
- query: `Add the ${cheapest.name} to my cart`
1423
+ query: `Add the ${name} to my cart`
1353
1424
  });
1354
1425
  }
1355
1426
  if (firstName) {
@@ -1452,7 +1523,7 @@ function ChatModal({
1452
1523
  visionCategoryHint
1453
1524
  }) {
1454
1525
  const client = (0, import_sdk6.useAkropolysContext)();
1455
- const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset } = (0, import_sdk4.useKiku)();
1526
+ const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset, referencedIds } = (0, import_sdk4.useKiku)();
1456
1527
  const [input, setInput] = (0, import_react5.useState)("");
1457
1528
  const [loadingMessageIndex, setLoadingMessageIndex] = (0, import_react5.useState)(0);
1458
1529
  const [attachments, setAttachments] = (0, import_react5.useState)([]);
@@ -1797,7 +1868,8 @@ function ChatModal({
1797
1868
  {
1798
1869
  sources,
1799
1870
  defaultCurrency,
1800
- onSelectSource: handleSourceClick
1871
+ onSelectSource: handleSourceClick,
1872
+ referencedIds
1801
1873
  }
1802
1874
  ),
1803
1875
  msg.cartSnapshot && msg.cartSnapshot.items?.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -2390,7 +2462,7 @@ Question: ${q}`;
2390
2462
  (() => {
2391
2463
  const similarProducts = results.filter(
2392
2464
  (r) => {
2393
- const isSameName = r.product.name.toLowerCase() === displayProduct?.name?.toLowerCase();
2465
+ const isSameName = !!(r.product.name && displayProduct?.name && r.product.name.toLowerCase() === displayProduct.name.toLowerCase());
2394
2466
  const isSameSlug = r.product.slug && displayProduct?.slug && r.product.slug.toLowerCase() === displayProduct.slug.toLowerCase();
2395
2467
  return !isSameName && !isSameSlug;
2396
2468
  }
@@ -2560,7 +2632,7 @@ Question: ${q}`;
2560
2632
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "hsk-sp-results", children: (() => {
2561
2633
  const similarProducts = results.filter(
2562
2634
  (r) => {
2563
- const isSameName = r.product.name.toLowerCase() === displayProduct?.name?.toLowerCase();
2635
+ const isSameName = !!(r.product.name && displayProduct?.name && r.product.name.toLowerCase() === displayProduct.name.toLowerCase());
2564
2636
  const isSameSlug = r.product.slug && displayProduct?.slug && r.product.slug.toLowerCase() === displayProduct.slug.toLowerCase();
2565
2637
  return !isSameName && !isSameSlug;
2566
2638
  }