@xbrain-swe/nova-chat-widget 0.1.6 → 0.1.8

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.cjs CHANGED
@@ -1523,6 +1523,7 @@ function XbNovaChat({
1523
1523
  backdropStyle,
1524
1524
  defaultOpen = false,
1525
1525
  idleText = "AI\uC5D0\uAC8C \uC774 \uCC28 \uBB3C\uC5B4\uBCF4\uAE30",
1526
+ avatarSize = 28,
1526
1527
  onVerdictAction
1527
1528
  }) {
1528
1529
  const { auth, trackRegistry, factsRegistry, visitorId, clientActionHandlers, theme } = useXbNovaInternal();
@@ -1530,6 +1531,7 @@ function XbNovaChat({
1530
1531
  "--xbnova-accent-1": theme.accentFrom,
1531
1532
  "--xbnova-accent-2": theme.accentTo
1532
1533
  };
1534
+ const headerAvatarSize = Math.min(36, Math.max(24, Math.round(avatarSize * 0.8)));
1533
1535
  const avatarGradientStyle = {
1534
1536
  background: "linear-gradient(135deg, var(--xbnova-accent-1), var(--xbnova-accent-2))"
1535
1537
  };
@@ -1550,6 +1552,28 @@ function XbNovaChat({
1550
1552
  nudgeNodeId: activeNudgeNodeId,
1551
1553
  onDismissSheet: () => setOpen(false)
1552
1554
  });
1555
+ const effectiveBotId = activeBotId ?? botId;
1556
+ const [cachedBranding, setCachedBranding] = (0, import_react9.useState)(null);
1557
+ (0, import_react9.useEffect)(() => {
1558
+ try {
1559
+ const raw = window.localStorage.getItem(`xbnova_branding:${effectiveBotId}`);
1560
+ setCachedBranding(raw ? JSON.parse(raw) : null);
1561
+ } catch {
1562
+ setCachedBranding(null);
1563
+ }
1564
+ }, [effectiveBotId]);
1565
+ (0, import_react9.useEffect)(() => {
1566
+ if (!onboarding?.branding) return;
1567
+ try {
1568
+ window.localStorage.setItem(
1569
+ `xbnova_branding:${effectiveBotId}`,
1570
+ JSON.stringify({ logo_url: onboarding.branding.logo_url, avatar_text: onboarding.branding.avatar_text })
1571
+ );
1572
+ } catch {
1573
+ }
1574
+ }, [onboarding?.branding, effectiveBotId]);
1575
+ const branding = onboarding?.branding ?? cachedBranding ?? void 0;
1576
+ const brandingReady = Boolean(onboarding) || cachedBranding !== null || Boolean(error);
1553
1577
  (0, import_react9.useEffect)(() => {
1554
1578
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
1555
1579
  }, [messages]);
@@ -1677,8 +1701,10 @@ function XbNovaChat({
1677
1701
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1678
1702
  Avatar,
1679
1703
  {
1680
- branding: onboarding?.branding,
1681
- className: "h-7 w-7 text-[11px] shadow-md",
1704
+ branding,
1705
+ ready: brandingReady,
1706
+ size: avatarSize,
1707
+ className: "shadow-md",
1682
1708
  gradient: avatarGradientStyle
1683
1709
  }
1684
1710
  )
@@ -1725,8 +1751,10 @@ function XbNovaChat({
1725
1751
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1726
1752
  Avatar,
1727
1753
  {
1728
- branding: onboarding?.branding,
1729
- className: "h-6 w-6 shrink-0 text-[10px]",
1754
+ branding,
1755
+ ready: brandingReady,
1756
+ size: headerAvatarSize,
1757
+ className: "shrink-0",
1730
1758
  gradient: avatarGradientStyle
1731
1759
  }
1732
1760
  ),
@@ -1844,31 +1872,34 @@ function XbNovaChat({
1844
1872
  }
1845
1873
  function Avatar({
1846
1874
  branding,
1847
- className,
1875
+ ready,
1876
+ size,
1877
+ className = "",
1848
1878
  gradient
1849
1879
  }) {
1880
+ const box = { width: size, height: size };
1850
1881
  const logoUrl = branding?.logo_url?.trim() ?? "";
1851
1882
  const [failedUrl, setFailedUrl] = (0, import_react9.useState)("");
1883
+ const [loadedUrl, setLoadedUrl] = (0, import_react9.useState)("");
1884
+ const base = `${className} relative flex flex-none items-center justify-center overflow-hidden rounded-full font-bold text-white`;
1885
+ if (!ready) {
1886
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: base, style: { ...gradient, ...box }, "aria-hidden": true });
1887
+ }
1852
1888
  if (logoUrl && failedUrl !== logoUrl) {
1853
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1889
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: base, style: { ...gradient, ...box }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1854
1890
  "img",
1855
1891
  {
1856
1892
  src: logoUrl,
1857
1893
  alt: "",
1894
+ onLoad: () => setLoadedUrl(logoUrl),
1858
1895
  onError: () => setFailedUrl(logoUrl),
1859
- className: `${className} flex-none rounded-full bg-white object-cover`
1896
+ className: "absolute inset-0 h-full w-full rounded-full bg-white object-cover transition-opacity duration-200",
1897
+ style: { opacity: loadedUrl === logoUrl ? 1 : 0 }
1860
1898
  }
1861
- );
1899
+ ) });
1862
1900
  }
1863
1901
  const text = branding?.avatar_text?.trim() || "AI";
1864
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1865
- "span",
1866
- {
1867
- className: `${className} flex items-center justify-center rounded-full font-bold text-white`,
1868
- style: gradient,
1869
- children: text
1870
- }
1871
- );
1902
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: base, style: { ...gradient, ...box, fontSize: Math.max(10, Math.round(size * 0.4)) }, children: text });
1872
1903
  }
1873
1904
  function Bubble({ role, children }) {
1874
1905
  const mine = role === "user";