admesh-ui-sdk
Version:
Beautiful, modern React components for displaying AI-powered product recommendations with citation-based conversation ads, auto-triggered widgets, floating chat, conversational interfaces, persistent sidebar, and built-in tracking. Includes zero-code SDK
1,182 lines • 166 kB
JavaScript
var ot = Object.defineProperty;
var nt = (t, e, n) => e in t ? ot(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
var oe = (t, e, n) => nt(t, typeof e != "symbol" ? e + "" : e, n);
import { jsx as h, jsxs as z, Fragment as ye } from "react/jsx-runtime";
import xe, { useRef as P, useState as ne, useCallback as he, useEffect as H, createContext as at, useContext as it } from "react";
import He from "react-dom/client";
import { createPortal as Ye } from "react-dom";
let _e = !1;
var Ge;
try {
typeof globalThis.importMeta < "u" && ((Ge = globalThis.importMeta.env) != null && Ge.PROD) && (_e = !0);
} catch {
}
_e || (_e = typeof process < "u" && process.env.NODE_ENV === "production" || typeof process < "u" && process.env.ADMESH_ENV === "production");
const o = {
log: (...t) => {
_e || console.log(...t);
},
warn: (...t) => {
_e || console.warn(...t);
},
error: (...t) => {
console.error(...t);
},
info: (...t) => {
_e || console.info(...t);
},
debug: (...t) => {
_e || console.debug(...t);
}
};
function st(t, e, n) {
const i = t * e > 242500;
return { ...{
visibilityThreshold: i ? 0.3 : 0.5,
// 30% for large, 50% for standard
minimumDuration: 1e3,
// 1 second in milliseconds
isLargeAd: i
}, ...n };
}
function dt(t) {
return t < 768 ? "mobile" : t < 1024 ? "tablet" : "desktop";
}
function ct(t) {
const e = t.getBoundingClientRect(), n = window.innerHeight || document.documentElement.clientHeight, r = window.innerWidth || document.documentElement.clientWidth, i = e.height, a = e.width;
if (i === 0 || a === 0) return 0;
const s = Math.max(0, e.top), c = Math.min(n, e.bottom), m = Math.max(0, e.left), u = Math.min(r, e.right), d = Math.max(0, c - s), l = Math.max(0, u - m), y = d * l, g = i * a;
return g > 0 ? y / g : 0;
}
function Ve() {
const t = window.innerHeight, e = document.documentElement.scrollHeight, n = window.pageYOffset || document.documentElement.scrollTop, r = e - t;
return r <= 0 ? 100 : Math.min(100, n / r * 100);
}
function lt(t) {
const e = t.getBoundingClientRect(), n = window.pageYOffset || document.documentElement.scrollTop, r = window.pageXOffset || document.documentElement.scrollLeft;
return {
top: e.top + n,
left: e.left + r
};
}
function mt(t) {
const e = t.getBoundingClientRect(), n = lt(t), r = window.innerWidth || document.documentElement.clientWidth, i = window.innerHeight || document.documentElement.clientHeight, a = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
return {
pageUrl: window.location.href,
pageTitle: document.title,
referrer: document.referrer,
deviceType: dt(r),
viewportWidth: r,
viewportHeight: i,
adWidth: e.width,
adHeight: e.height,
adPositionTop: n.top,
adPositionLeft: n.left,
isDarkMode: a,
language: navigator.language,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
};
}
function ut() {
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
}
function pt(t, e, n) {
return t >= n.visibilityThreshold && e >= n.minimumDuration;
}
function je(t = /* @__PURE__ */ new Date()) {
return t.toISOString();
}
function ht(t) {
return t.length === 0 ? 0 : t.reduce((n, r) => n + r, 0) / t.length;
}
function Ke(t, e) {
let n;
return function(...i) {
n || (t(...i), n = !0, setTimeout(() => n = !1, e));
};
}
const gt = {
enabled: !0,
// Analytics endpoint disabled - no analytics will be sent
apiEndpoint: "",
// Empty string disables analytics sending
enableBatching: !1,
// Disabled since no endpoint
batchSize: 10,
batchTimeout: 5e3,
// 5 seconds
debug: !1,
enableRetry: !1,
maxRetries: 3,
retryDelay: 1e3
};
let ft = gt;
function bt({
productId: t,
offerId: e,
agentId: n,
recommendationId: r,
elementRef: i,
config: a
}) {
const s = { ...ft, ...a }, c = P(ut()), [m, u] = ne({
isVisible: !1,
isViewable: !1,
visibilityPercentage: 0,
timeMetrics: {
loadedAt: je(),
totalVisibleDuration: 0,
totalViewableDuration: 0,
totalHoverDuration: 0,
totalFocusDuration: 0
},
engagementMetrics: {
currentScrollDepth: 0,
viewportEnterCount: 0,
viewportExitCount: 0,
hoverCount: 0,
wasClicked: !1,
maxVisibilityPercentage: 0,
averageVisibilityPercentage: 0
},
isTracking: s.enabled
}), d = P(null), l = P(null), y = P(null), g = P(null), f = P(null), _ = P([]), w = P([]), p = P(null), E = he((x) => {
s.debug && o.log(`[AdMesh Viewability] ${x}`);
}, [s.debug]), b = he(async (x, T) => {
if (!(!s.enabled || !i.current || !d.current) && (E(`Analytics disabled - skipping event: ${x}`), s.onEvent)) {
const v = mt(i.current), I = {
eventType: x,
timestamp: je(),
sessionId: c.current,
productId: t,
offerId: e,
agentId: n,
recommendationId: r,
timeMetrics: m.timeMetrics,
engagementMetrics: m.engagementMetrics,
contextMetrics: v,
mrcStandards: d.current,
isViewable: m.isViewable,
metadata: T
};
s.onEvent(I);
}
}, [s, t, e, n, r, i, m, E]), N = he(async () => {
w.current.length !== 0 && (E("Analytics disabled - clearing batch without sending"), w.current = [], p.current && (clearTimeout(p.current), p.current = null));
}, [E]), M = he(Ke(() => {
if (!i.current) return;
const x = ct(i.current), T = Date.now(), v = new Date(m.timeMetrics.loadedAt).getTime();
u((I) => {
const A = { ...I };
x > 0 && _.current.push(x);
const F = I.isVisible, S = x > 0;
if (S && !F)
l.current = T, A.engagementMetrics.viewportEnterCount++, A.timeMetrics.timeToFirstVisible || (A.timeMetrics.timeToFirstVisible = T - v, A.engagementMetrics.scrollDepthAtFirstVisible = Ve(), b("ad_visible"));
else if (!S && F) {
if (l.current) {
const B = T - l.current;
A.timeMetrics.totalVisibleDuration += B, l.current = null;
}
A.engagementMetrics.viewportExitCount++, b("ad_hidden");
} else if (S && F && l.current) {
const B = T - l.current;
A.timeMetrics.totalVisibleDuration += B, l.current = T;
}
if (A.isVisible = S, A.visibilityPercentage = x, x > A.engagementMetrics.maxVisibilityPercentage && (A.engagementMetrics.maxVisibilityPercentage = x), _.current.length > 0 && (A.engagementMetrics.averageVisibilityPercentage = ht(_.current)), d.current) {
const B = I.isViewable, k = pt(
x,
A.timeMetrics.totalVisibleDuration,
d.current
);
if (k && !B)
A.isViewable = !0, A.timeMetrics.timeToViewable = T - v, y.current = T, b("ad_viewable");
else if (k && B && y.current) {
const D = T - y.current;
A.timeMetrics.totalViewableDuration += D, y.current = T;
}
}
return A.engagementMetrics.currentScrollDepth = Ve(), A;
});
}, 100), [i, m.timeMetrics.loadedAt, b]);
return H(() => {
if (!i.current) return;
const x = i.current.getBoundingClientRect();
d.current = st(x.width, x.height, s.mrcStandards), E("Initialized MRC standards"), b("ad_loaded");
}, [i, s.mrcStandards, E, b]), H(() => {
if (!s.enabled || !i.current) return;
const x = new IntersectionObserver(
(T) => {
T.forEach(() => {
M();
});
},
{
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
rootMargin: "0px"
}
);
return x.observe(i.current), () => {
x.disconnect();
};
}, [s.enabled, i, M]), H(() => {
if (!s.enabled) return;
const x = Ke(() => {
M();
}, 100);
return window.addEventListener("scroll", x, { passive: !0 }), () => window.removeEventListener("scroll", x);
}, [s.enabled, M]), H(() => {
if (!s.enabled || !i.current) return;
const x = i.current, T = () => {
g.current = Date.now(), u((I) => ({
...I,
engagementMetrics: {
...I.engagementMetrics,
hoverCount: I.engagementMetrics.hoverCount + 1
}
})), b("ad_hover_start");
}, v = () => {
if (g.current) {
const I = Date.now() - g.current;
u((A) => ({
...A,
timeMetrics: {
...A.timeMetrics,
totalHoverDuration: A.timeMetrics.totalHoverDuration + I
}
})), g.current = null, b("ad_hover_end", { hoverDuration: I });
}
};
return x.addEventListener("mouseenter", T), x.addEventListener("mouseleave", v), () => {
x.removeEventListener("mouseenter", T), x.removeEventListener("mouseleave", v);
};
}, [s.enabled, i, b]), H(() => {
if (!s.enabled || !i.current) return;
const x = i.current, T = () => {
f.current = Date.now(), b("ad_focus");
}, v = () => {
if (f.current) {
const I = Date.now() - f.current;
u((A) => ({
...A,
timeMetrics: {
...A.timeMetrics,
totalFocusDuration: A.timeMetrics.totalFocusDuration + I
}
})), f.current = null, b("ad_blur", { focusDuration: I });
}
};
return x.addEventListener("focus", T), x.addEventListener("blur", v), () => {
x.removeEventListener("focus", T), x.removeEventListener("blur", v);
};
}, [s.enabled, i, b]), H(() => {
if (!s.enabled || !i.current) return;
const x = i.current, T = () => {
u((v) => ({
...v,
engagementMetrics: {
...v.engagementMetrics,
wasClicked: !0
}
})), b("ad_click");
};
return x.addEventListener("click", T), () => {
x.removeEventListener("click", T);
};
}, [s.enabled, i, b]), H(() => () => {
const x = Date.now(), T = new Date(m.timeMetrics.loadedAt).getTime(), v = x - T;
u((I) => ({
...I,
timeMetrics: {
...I.timeMetrics,
sessionDuration: v
}
})), b("ad_unloaded", { sessionDuration: v }), N();
}, []), m;
}
const Ie = ({
productId: t,
offerId: e,
agentId: n,
recommendationId: r,
exposureUrl: i,
sessionId: a,
children: s,
config: c,
className: m,
style: u,
onViewabilityChange: d,
onVisible: l,
onViewable: y,
onClick: g
}) => {
const f = P(null), _ = P(!1), w = bt({
productId: t,
offerId: e,
agentId: n,
recommendationId: r,
elementRef: f,
config: c
}), p = P(w.isViewable);
H(() => {
w.isViewable !== p.current && (p.current = w.isViewable, d && d(w.isViewable), w.isViewable && y && y(), w.isViewable && !_.current && (o.log("[AdMeshViewabilityTracker] 🎯 Ad is viewable, checking exposure pixel requirements:", {
exposureUrl: i ? "present" : "MISSING",
sessionId: a ? "present" : "MISSING",
recommendationId: r
}), i && a ? (_.current = !0, o.log("[AdMeshViewabilityTracker] 🔥 Firing exposure pixel:", i), fetch(i, { method: "GET", keepalive: !0 }).then(() => {
o.log("[AdMesh] ✅ Exposure pixel fired successfully");
}).catch((N) => {
o.warn("[AdMesh] ⚠️ Failed to fire exposure pixel:", N), _.current = !1;
})) : o.warn("[AdMeshViewabilityTracker] ⚠️ Cannot fire exposure pixel - missing required data:", {
hasExposureUrl: !!i,
hasSessionId: !!a
})));
}, [w.isViewable, d, y, i, a, r]);
const E = P(w.isVisible);
return H(() => {
w.isVisible !== E.current && (E.current = w.isVisible, w.isVisible && l && l());
}, [w.isVisible, l]), /* @__PURE__ */ h(
"div",
{
ref: f,
className: m,
style: u,
onClick: () => {
g && g();
},
"data-admesh-viewability-tracker": !0,
"data-recommendation-id": r,
"data-is-viewable": w.isViewable,
"data-is-visible": w.isVisible,
"data-visibility-percentage": w.visibilityPercentage.toFixed(2),
children: s
}
);
};
Ie.displayName = "AdMeshViewabilityTracker";
const Ne = xe.createContext(
void 0
);
function xt() {
const t = xe.useContext(Ne);
if (!t)
throw new Error(
"useAdMeshContext must be used within an <AdMeshProvider>. Make sure your component is wrapped with <AdMeshProvider>."
);
return t;
}
const vt = (t) => {
try {
return new URL(t), !0;
} catch {
return !1;
}
}, wt = (t) => t && t.trim() ? t.trim() : "", Ze = ({
recommendations: t,
theme: e,
className: n = "",
style: r = {},
sessionId: i
}) => {
var Y, le, ce, me, ie, $, be, ke, ue, ge, Ae;
const a = xe.useContext(Ne), s = a == null ? void 0 : a.userId, c = a == null ? void 0 : a.model, m = a == null ? void 0 : a.sessionId, u = (a == null ? void 0 : a.sdk) || null, d = i || m, [l, y] = xe.useState(!1), [g, f] = xe.useState(!1), [_, w] = xe.useState(!1);
if (!t || t.length === 0)
return o.log("[AdMesh Tail Ad] No recommendations provided - not rendering"), null;
if (l)
return null;
const p = t[0], E = p == null ? void 0 : p.product_id, b = p == null ? void 0 : p.exposure_url, N = (p == null ? void 0 : p.recommendation_id) || "", M = (p == null ? void 0 : p.creative_input) || {}, x = M.short_description || "", T = M.offer_summary || "", v = M.brand_name || (p == null ? void 0 : p.title) || "", I = M.product_name || "", F = (M.assets || {}).logo_url || "", S = (p == null ? void 0 : p.click_url) || (p == null ? void 0 : p.admesh_link) || M.cta_url || (p == null ? void 0 : p.url), B = wt(M.cta_label);
if (!v)
return o.log("[AdMesh Tail Ad] No valid recommendation data provided - not rendering", {
reason: "brandName is missing",
brandName: v,
hasFirstRecommendation: !!p,
hasCreativeInput: !!M,
creativeInputBrandName: M.brand_name,
recommendationTitle: p == null ? void 0 : p.title,
recommendationId: N,
recommendationKeys: p ? Object.keys(p) : []
}), null;
let k = v, D = "";
T ? D = T : I && (D = I), D && (k = `${v} — ${D}`), o.debug("[AdMeshTailAd] 📊 Rendering with tracking data:", {
recommendationId: N,
productId: E,
exposureUrl: b ? "present" : "MISSING",
sessionId: i ? "present" : "MISSING",
recommendationsCount: t.length,
clickUrl: S || "MISSING",
clickUrlSource: p != null && p.click_url ? "click_url" : p != null && p.admesh_link ? "admesh_link" : M.cta_url ? "cta_url" : p != null && p.url ? "url" : "none",
shortDescription: x ? "present" : "MISSING",
offerSummary: T || "MISSING",
brandName: v,
productName: I,
headlineText: k
});
const Z = (L, te) => {
o.log(`AdMesh tail ad ${L} clicked`), typeof window < "u" && window.admeshTracker && window.admeshTracker.trackClick({
recommendationId: p.recommendation_id,
productId: p.product_id,
clickUrl: S,
source: L
}).catch(() => {
o.error(`[AdMesh] Failed to track ${L} click`);
});
}, X = (L) => {
L.stopPropagation(), Z("tail_ad_brand_name");
}, ee = (L) => {
L.stopPropagation(), Z("tail_ad_cta");
}, ae = (L) => {
L.stopPropagation(), Z("tail_ad_logo");
}, G = () => u && typeof u.getApiBaseUrl == "function" ? u.getApiBaseUrl() : u && u.apiBaseUrl ? u.apiBaseUrl : typeof window < "u" && window.__ADMESH_API_BASE_URL__ ? window.__ADMESH_API_BASE_URL__ : "https://api.useadmesh.com", se = async (L) => {
if (!(g || _)) {
w(!0);
try {
const te = G(), ve = (p == null ? void 0 : p.agent_id) || "", we = {
message_index: 0,
// Default to 0, can be enhanced later if message_index is available
feedback: L,
session_id: d || null,
user_id: s || null,
agent_id: ve || null,
model_used: c || null,
recommendationId: N || null
}, Se = `${te}/user/feedback/submit`;
o.log(`[AdMesh Tail Ad] Submitting feedback: ${L}`, {
endpoint: Se,
payload: we
});
const re = await fetch(Se, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(we)
});
if (o.log(`[AdMesh Tail Ad] Feedback response status: ${re.status} ${re.statusText}`), !re.ok) {
let Te = `Feedback submission failed: ${re.status} ${re.statusText}`;
try {
const fe = await re.json().catch(() => null);
fe != null && fe.detail && (Te = `Feedback submission failed: ${fe.detail}`), o.error("[AdMesh Tail Ad] Error response body:", fe);
} catch {
}
throw new Error(Te);
}
const Me = await re.json();
o.log(`[AdMesh Tail Ad] ✅ Feedback submitted successfully: ${L}`, Me), f(!0), L === "dislike" && y(!0);
} catch (te) {
const ve = te instanceof Error ? {
message: te.message,
name: te.name,
stack: te.stack
} : String(te);
o.error(`[AdMesh Tail Ad] ❌ Failed to submit feedback: ${L}`, {
error: ve,
apiBaseUrl: G(),
endpoint: `${G()}/user/feedback/submit`
}), w(!1);
}
}
}, C = (L) => {
L.stopPropagation(), L.preventDefault(), se("like");
}, U = (L) => {
L.stopPropagation(), L.preventDefault(), se("dislike");
}, [de, pe] = xe.useState(!1), W = v ? v.charAt(0).toUpperCase() : "B", j = (e == null ? void 0 : e.mode) === "dark" || typeof window < "u" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches, R = (e == null ? void 0 : e.surfaceColor) || ((le = (Y = e == null ? void 0 : e.components) == null ? void 0 : Y.card) == null ? void 0 : le.backgroundColor) || (j ? "#1f2937" : "#ffffff"), V = (e == null ? void 0 : e.borderColor) || ((me = (ce = e == null ? void 0 : e.components) == null ? void 0 : ce.card) == null ? void 0 : me.borderColor) || (j ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)"), q = (e == null ? void 0 : e.borderRadius) || (($ = (ie = e == null ? void 0 : e.components) == null ? void 0 : ie.card) == null ? void 0 : $.borderRadius) || "8px", J = j ? "0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)" : "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)", Q = j ? "0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)" : "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)", K = ((be = e == null ? void 0 : e.shadows) == null ? void 0 : be.medium) || ((ue = (ke = e == null ? void 0 : e.components) == null ? void 0 : ke.card) == null ? void 0 : ue.boxShadow) || J, O = ((ge = e == null ? void 0 : e.shadows) == null ? void 0 : ge.large) || Q;
return /* @__PURE__ */ h(
Ie,
{
productId: E,
recommendationId: N,
exposureUrl: b,
sessionId: i,
className: `admesh-tail-ad ${n}`,
style: {
fontFamily: (e == null ? void 0 : e.fontFamily) || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
...r
},
children: /* @__PURE__ */ z(
"div",
{
className: "tail-ad-container flex flex-row gap-3",
style: {
backgroundColor: R,
borderRadius: q,
padding: "16px",
boxShadow: K,
border: `1px solid ${V}`,
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
transform: "translateY(0)",
...(Ae = e == null ? void 0 : e.components) == null ? void 0 : Ae.card
},
onMouseEnter: (L) => {
L.currentTarget.style.boxShadow = O, L.currentTarget.style.transform = "translateY(-2px)";
},
onMouseLeave: (L) => {
L.currentTarget.style.boxShadow = K, L.currentTarget.style.transform = "translateY(0)";
},
children: [
F && /* @__PURE__ */ h(
"div",
{
className: "flex-shrink-0 flex items-center justify-center pr-2",
style: {
width: "10%",
minWidth: "48px"
},
children: !de && vt(F) ? /* @__PURE__ */ h(
"a",
{
href: S || "#",
target: S ? "_blank" : void 0,
rel: S ? "noopener noreferrer" : void 0,
onClick: S ? ae : void 0,
className: "block",
style: {
cursor: S ? "pointer" : "default",
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "100%",
maxWidth: "64px"
},
children: /* @__PURE__ */ h(
"img",
{
src: F,
alt: `${v} logo`,
className: "object-cover",
style: {
width: "100%",
height: "auto",
maxWidth: "64px",
maxHeight: "64px",
objectFit: "contain",
borderRadius: "8px"
},
onError: () => {
pe(!0), o.debug("[AdMesh Tail Ad] Logo failed to load, showing fallback");
}
}
)
}
) : /* @__PURE__ */ h(
"div",
{
className: "flex items-center justify-center text-lg font-semibold text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-gray-800",
style: {
width: "100%",
maxWidth: "64px",
aspectRatio: "1",
borderRadius: "8px",
minHeight: "48px"
},
children: W
}
)
}
),
/* @__PURE__ */ z(
"div",
{
className: "flex-1",
style: {
width: F ? "90%" : "100%",
minWidth: 0
// Allow flex item to shrink below content size
},
children: [
k && /* @__PURE__ */ h("div", { className: "mb-2", children: /* @__PURE__ */ h("h3", { className: "text-black dark:text-white font-semibold text-base", style: { fontSize: "0.7rem" }, children: S && v ? /* @__PURE__ */ z(ye, { children: [
/* @__PURE__ */ h(
"a",
{
href: S,
target: "_blank",
rel: "noopener noreferrer",
className: "text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline decoration-blue-600 dark:decoration-blue-400 hover:decoration-blue-800 dark:hover:decoration-blue-300 transition-colors duration-200 font-semibold",
style: {
color: "#2563eb",
textDecoration: "underline",
textDecorationColor: "#2563eb",
textUnderlineOffset: "2px"
},
onClick: X,
children: v
}
),
D && ` — ${D}`
] }) : k }) }),
x && /* @__PURE__ */ h("p", { className: "text-gray-700 dark:text-gray-300 text-sm mb-3 leading-relaxed", style: { fontSize: "0.7rem" }, children: x }),
/* @__PURE__ */ z("div", { className: "flex items-center justify-between mt-2", children: [
/* @__PURE__ */ h("div", { className: "flex items-center gap-2", children: B && S && /* @__PURE__ */ h(
"a",
{
href: S,
target: "_blank",
rel: "noopener noreferrer",
className: "text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline decoration-blue-600 dark:decoration-blue-400 hover:decoration-blue-800 dark:hover:decoration-blue-300 transition-colors duration-200 font-medium text-sm",
style: {
color: "#2563eb",
textDecoration: "underline",
textDecorationColor: "#2563eb",
textUnderlineOffset: "2px"
},
onClick: ee,
children: B
}
) }),
/* @__PURE__ */ z("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ h(
"button",
{
onClick: C,
disabled: g || _,
"aria-label": "Mark as helpful",
className: "flex items-center justify-center px-2 py-1 rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
style: {
color: g && !l ? "#10b981" : j ? "#9ca3af" : "#6b7280",
backgroundColor: "transparent",
border: "none",
cursor: g || _ ? "not-allowed" : "pointer",
fontSize: "0.75rem",
fontWeight: "500",
minHeight: "24px"
},
onMouseEnter: (L) => {
!g && !_ && (L.currentTarget.style.color = "#10b981", L.currentTarget.style.backgroundColor = "rgba(16, 185, 129, 0.1)");
},
onMouseLeave: (L) => {
g || (L.currentTarget.style.color = g ? "#10b981" : j ? "#9ca3af" : "#6b7280", L.currentTarget.style.backgroundColor = "transparent");
},
children: "Helpful"
}
),
/* @__PURE__ */ h(
"button",
{
onClick: U,
disabled: g || _,
"aria-label": "Mark as not helpful",
className: "flex items-center justify-center px-2 py-1 rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
style: {
color: l ? "#ef4444" : j ? "#9ca3af" : "#6b7280",
backgroundColor: "transparent",
border: "none",
cursor: g || _ ? "not-allowed" : "pointer",
fontSize: "0.75rem",
fontWeight: "500",
minHeight: "24px"
},
onMouseEnter: (L) => {
!g && !_ && (L.currentTarget.style.color = "#ef4444", L.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.1)");
},
onMouseLeave: (L) => {
l || (L.currentTarget.style.color = j ? "#9ca3af" : "#6b7280", L.currentTarget.style.backgroundColor = "transparent");
},
children: "Not Helpful"
}
),
/* @__PURE__ */ h("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Sponsored" })
] })
] })
]
}
)
]
}
)
}
);
};
function Ee() {
const t = xt();
return {
/** AdMesh SDK instance */
sdk: t.sdk,
/** API key */
apiKey: t.apiKey,
/** Session ID */
sessionId: t.sessionId,
/** Theme configuration */
theme: t.theme,
/** User language in BCP 47 format (e.g., "en-US") - from AdMeshProvider */
language: t.language,
/** User country code in ISO 3166-1 alpha-2 format (e.g., "US") - from AdMeshProvider */
geo_country: t.geo_country,
/** Anonymous hashed user ID - from AdMeshProvider */
userId: t.userId,
/** AI model identifier (e.g., "gpt-4o") - from AdMeshProvider */
model: t.model,
/** Conversation history - from AdMeshProvider */
messages: t.messages,
/** Set of processed message IDs (for deduplication) */
processedMessageIds: t.processedMessageIds,
/** Mark a message as processed to prevent duplicate recommendations */
markMessageAsProcessed: t.markMessageAsProcessed,
/** Check if a message has already been processed */
isMessageProcessed: t.isMessageProcessed
};
}
const yt = (t, e) => {
if (!t) return "Get Started";
let n = "";
const r = [
/(?:set up|setup|integrate|add|install|use)\s+([A-Z][a-zA-Z0-9\s]+?)(?:\.|$|,| by)/i,
/(?:by|from)\s+([A-Z][a-zA-Z0-9\s]+?)(?:\.|$|,)/
];
for (const s of r) {
const c = t.match(s);
if (c && c[1]) {
n = c[1].trim();
break;
}
}
const i = e || n;
if (i)
return `Integrate ${i.split(/\s+/).slice(0, 2).join(" ")}`;
const a = t.match(/to\s+set\s+up\s+([a-zA-Z0-9\s]+?)(?:\s+by|\s*[.,]|$)/i);
return a && a[1] ? `Integrate ${a[1].trim().split(/\s+/).slice(0, 2).join(" ")}` : "Integrate";
}, Xe = ({
recommendation: t,
theme: e,
className: n = "",
style: r = {},
sessionId: i,
onLinkClick: a,
onPasteToInput: s
}) => {
var M, x, T, v, I, A, F;
const c = t.creative_input || {}, m = c.bridge_headline || "", u = c.bridge_description || "", d = c.bridge_prompt || c.bridge_content || "", l = c.product_name || "", y = c.cta_label || "";
if (!u && !d)
return null;
const g = t.product_id || "", f = t.recommendation_id || "", { sdk: _, sessionId: w } = Ee(), p = i || w, E = async (S) => {
if (S.preventDefault(), !!d) {
if (f && p)
try {
const B = (_ == null ? void 0 : _.apiBaseUrl) || typeof window < "u" && window.__ADMESH_API_BASE_URL__ || "https://api.useadmesh.com", k = await fetch(`${B}/click/bridge-engagement`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
recommendation_id: f,
session_id: p,
agent_id: t.agent_id,
user_id: t.user_id || void 0,
is_test: !1
// TODO: Get from config if needed
})
});
k.ok ? o.log("[AdMesh Bridge] ✅ Engagement tracked successfully") : o.warn("[AdMesh Bridge] ⚠️ Failed to track engagement:", k.statusText);
} catch (B) {
o.error("[AdMesh Bridge] ❌ Error tracking engagement:", B);
}
a && a(t), s ? s(d) : typeof window < "u" && window.__admesh_setMessage && window.__admesh_setMessage(d);
}
}, b = y || yt(d, l), N = !!b;
return /* @__PURE__ */ h(
Ie,
{
productId: g,
recommendationId: t.recommendation_id || "",
exposureUrl: t.exposure_url,
sessionId: i,
className: `admesh-bridge-format ${n}`,
style: {
fontFamily: (e == null ? void 0 : e.fontFamily) || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
padding: "1rem",
border: "none",
borderRadius: (e == null ? void 0 : e.borderRadius) || "0.5rem",
backgroundColor: "transparent",
color: (e == null ? void 0 : e.textColor) || "inherit",
...r
},
children: /* @__PURE__ */ z("div", { "data-admesh-theme": (e == null ? void 0 : e.mode) || "light", children: [
m && /* @__PURE__ */ h(
"div",
{
className: "admesh-bridge-headline",
style: {
marginBottom: u ? "0.75rem" : N ? "1rem" : "0",
fontSize: ((M = e == null ? void 0 : e.fontSize) == null ? void 0 : M.large) || "1rem",
fontWeight: 600,
color: (e == null ? void 0 : e.textColor) || "inherit",
lineHeight: "1.4"
},
children: m
}
),
u && /* @__PURE__ */ h(
"div",
{
className: "admesh-bridge-description",
style: {
marginBottom: N || (x = t.creative_input) != null && x.offer_summary ? "1rem" : "0",
lineHeight: "1.6",
fontSize: ((T = e == null ? void 0 : e.fontSize) == null ? void 0 : T.base) || "0.875rem",
color: (e == null ? void 0 : e.textColor) || "inherit"
},
children: u
}
),
((v = t.creative_input) == null ? void 0 : v.offer_summary) && /* @__PURE__ */ h(
"div",
{
className: "admesh-bridge-offer-summary",
style: {
marginBottom: N ? "1rem" : "0",
lineHeight: "1.5",
fontSize: ((I = e == null ? void 0 : e.fontSize) == null ? void 0 : I.small) || "0.75rem",
color: e != null && e.textSecondaryColor || (e == null ? void 0 : e.mode) === "dark" ? "#9ca3af" : "#6b7280",
fontStyle: "italic"
},
children: t.creative_input.offer_summary
}
),
N && /* @__PURE__ */ h("div", { style: { marginBottom: "0.75rem" }, children: /* @__PURE__ */ h(
"button",
{
onClick: E,
className: "admesh-bridge-cta-button",
style: {
padding: "0.5rem 1rem",
backgroundColor: "#000000",
color: "#ffffff",
fontSize: ((A = e == null ? void 0 : e.fontSize) == null ? void 0 : A.small) || "0.875rem",
fontWeight: 500,
borderRadius: (e == null ? void 0 : e.borderRadius) || "0.5rem",
border: "none",
cursor: "pointer",
transition: "background-color 0.2s, opacity 0.2s"
},
onMouseEnter: (S) => {
S.currentTarget.style.backgroundColor = "#1a1a1a", S.currentTarget.style.opacity = "0.9";
},
onMouseLeave: (S) => {
S.currentTarget.style.backgroundColor = "#000000", S.currentTarget.style.opacity = "1";
},
children: b
}
) }),
/* @__PURE__ */ h("div", { style: { display: "flex", justifyContent: "flex-end", marginTop: "0.5rem" }, children: /* @__PURE__ */ h(
"div",
{
className: "admesh-bridge-label",
style: {
fontSize: ((F = e == null ? void 0 : e.fontSize) == null ? void 0 : F.small) || "0.75rem",
color: e != null && e.textSecondaryColor || (e == null ? void 0 : e.mode) === "dark" ? "#9ca3af" : "#6b7280",
fontStyle: "italic"
},
children: "Sponsored"
}
) })
] })
}
);
};
function _t(t) {
return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t;
}
var Fe = { exports: {} };
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
var Oe;
function kt() {
return Oe || (Oe = 1, (function(t) {
(function() {
var e = {}.hasOwnProperty;
function n() {
for (var a = "", s = 0; s < arguments.length; s++) {
var c = arguments[s];
c && (a = i(a, r(c)));
}
return a;
}
function r(a) {
if (typeof a == "string" || typeof a == "number")
return a;
if (typeof a != "object")
return "";
if (Array.isArray(a))
return n.apply(null, a);
if (a.toString !== Object.prototype.toString && !a.toString.toString().includes("[native code]"))
return a.toString();
var s = "";
for (var c in a)
e.call(a, c) && a[c] && (s = i(s, c));
return s;
}
function i(a, s) {
return s ? a ? a + " " + s : a + s : a;
}
t.exports ? (n.default = n, t.exports = n) : window.classNames = n;
})();
})(Fe)), Fe.exports;
}
var At = kt();
const Ce = /* @__PURE__ */ _t(At), Je = ({
recommendationId: t,
admeshLink: e,
productId: n,
children: r,
trackingData: i,
className: a,
style: s
}) => {
const c = P(null);
H(() => {
if (!c.current) return;
c.current.querySelectorAll("a").forEach((d) => {
(!d.hasAttribute("target") || d.getAttribute("target") !== "_blank") && (d.setAttribute("target", "_blank"), d.setAttribute("rel", "noopener noreferrer"));
});
}, [r]);
const m = he((u) => {
const l = u.target.closest("a");
l ? ((!l.href || l.href === "#" || l.href === "") && e && (l.href = e), (!l.hasAttribute("target") || l.getAttribute("target") !== "_blank") && (l.setAttribute("target", "_blank"), l.setAttribute("rel", "noopener noreferrer"))) : e ? window.open(e, "_blank", "noopener,noreferrer") : o.warn("[AdMeshLinkTracker] No admeshLink provided for click tracking");
}, [e]);
return /* @__PURE__ */ h(
"div",
{
ref: c,
className: a,
onClick: m,
style: {
cursor: "pointer",
...s
},
children: r
}
);
};
Je.displayName = "AdMeshLinkTracker";
const et = ({
brand: t,
title: e = "Product Recommendations",
showTitle: n = !1,
className: r = "",
cardClassName: i = "",
onProductClick: a,
maxCards: s = 10,
cardWidth: c = "md",
theme: m = "auto",
borderRadius: u = "md",
shadow: d = "sm",
sessionId: l,
onFeedback: y
}) => {
const [g, f] = xe.useState(null);
if (!t)
return o.log("[AdMesh Ecommerce Cards] Brand object is required but was not provided"), null;
if (!t.products || t.products.length === 0)
return o.log("[AdMesh Ecommerce Cards] Products array is required but was empty or missing. Both brand info and products are required for ecommerce cards."), null;
const _ = t.products.slice(0, s), w = () => {
var C;
return t.brand_name || ((C = t.creative_input) == null ? void 0 : C.brand_name) || "";
}, p = () => {
var C, U;
return ((U = (C = t.creative_input) == null ? void 0 : C.assets) == null ? void 0 : U.logo_url) || "";
}, E = () => {
var C;
return ((C = t.creative_input) == null ? void 0 : C.short_description) || t.description || "";
}, b = (C) => C.product_link || C.product_click_url || "", N = (C) => C.product_cta_label || "Shop", M = (C) => {
const U = C.product_price;
if (U != null) {
if (typeof U == "string") return U;
if (typeof U == "number") return `$${U.toFixed(2)}`;
}
return "";
}, x = (C) => C.product_name || "", T = (C) => {
if (C.product_features && C.product_features.length > 0) {
let U = 0;
const de = C.product_id || "";
for (let W = 0; W < de.length; W++)
U = (U << 5) - U + de.charCodeAt(W), U |= 0;
const pe = Math.abs(U) % C.product_features.length;
return C.product_features[pe];
}
return C.product_description || "";
}, v = (C) => C.product_image_url || null, I = (C) => {
const U = C.product_discount;
if (U != null) {
if (typeof U == "string") return U;
if (typeof U == "number") return `${U}%`;
}
return null;
}, A = () => {
switch (c) {
case "sm":
return "w-[305px] min-w-[305px] max-w-[305px]";
case "md":
return "w-[345px] min-w-[345px] max-w-[345px]";
case "lg":
return "w-[385px] min-w-[385px] max-w-[385px]";
default:
return "w-[345px] min-w-[345px] max-w-[345px]";
}
}, F = () => {
switch (u) {
case "none":
return "rounded-none";
case "sm":
return "rounded-sm";
case "md":
return "rounded-lg";
case "lg":
return "rounded-xl";
default:
return "rounded-lg";
}
}, S = () => {
switch (d) {
case "none":
return "";
case "sm":
return "shadow-sm hover:shadow-md";
case "md":
return "shadow-md hover:shadow-lg";
case "lg":
return "shadow-lg hover:shadow-xl";
default:
return "shadow-sm hover:shadow-md";
}
}, B = () => m === "dark" ? "bg-gray-900 text-white" : m === "light" ? "bg-white text-gray-900" : "bg-white dark:bg-gray-900 text-gray-900 dark:text-white", k = (C) => {
if (a)
a(C);
else {
const U = C.product_link || C.product_click_url;
U && window.open(U, "_blank", "noopener,noreferrer");
}
}, D = w(), Z = p(), X = E(), { sessionId: ee, userId: ae } = Ee(), G = l || ee, se = t.exposure_url;
return /* @__PURE__ */ z(
Ie,
{
recommendationId: t.recommendation_id,
exposureUrl: se,
sessionId: G,
className: Ce("w-full", r),
children: [
/* @__PURE__ */ z("div", { className: Ce(
"bg-white dark:bg-gray-900",
"border border-gray-200 dark:border-gray-700",
"rounded-xl",
"shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-1px_rgba(0,0,0,0.06)]",
"dark:shadow-[0_4px_6px_-1px_rgba(0,0,0,0.3),0_2px_4px_-1px_rgba(0,0,0,0.2)]",
"p-6",
"transition-shadow duration-200",
"hover:shadow-[0_10px_15px_-3px_rgba(0,0,0,0.1),0_4px_6px_-2px_rgba(0,0,0,0.05)]",
"dark:hover:shadow-[0_10px_15px_-3px_rgba(0,0,0,0.4),0_4px_6px_-2px_rgba(0,0,0,0.3)]"
), children: [
(D || Z || X) && /* @__PURE__ */ h("div", { className: "mb-4", children: /* @__PURE__ */ z("div", { className: "flex items-start gap-3", children: [
Z && /* @__PURE__ */ h("div", { className: "flex-shrink-0", children: /* @__PURE__ */ h(
"div",
{
className: "rounded-full overflow-hidden bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center",
style: { aspectRatio: "1", width: "48px", height: "48px" },
children: /* @__PURE__ */ h(
"img",
{
src: Z,
alt: `${D} logo`,
className: "w-full h-full object-contain",
style: { aspectRatio: "1" },
onError: (C) => {
C.target.style.display = "none";
}
}
)
}
) }),
/* @__PURE__ */ z("div", { className: "flex-1", children: [
D && /* @__PURE__ */ h("div", { className: "font-bold text-gray-900 dark:text-white text-base mb-1", children: D }),
X && /* @__PURE__ */ h("p", { className: "text-sm text-gray-600 dark:text-gray-400", children: X })
] })
] }) }),
/* @__PURE__ */ z("div", { className: "relative", children: [
_.length === 0 ? /* @__PURE__ */ h("div", { className: "text-center py-8 text-gray-500", children: "No products to display" }) : /* @__PURE__ */ h("div", { className: "flex gap-3 sm:gap-4 overflow-x-auto pb-4 scrollbar-hide", children: _.map((C) => {
const U = C.product_id, de = U, pe = b(C), W = N(C), j = M(C), R = x(C), V = T(C), q = I(C), J = v(C), Q = C.product_link || C.product_click_url || "", K = t.recommendation_id;
return /* @__PURE__ */ h(
Je,
{
recommendationId: K,
admeshLink: Q,
productId: U,
trackingData: {
sessionId: G,
userId: ae
},
children: /* @__PURE__ */ h(
"div",
{
className: Ce(
A(),
F(),
S(),
B(),
"flex-shrink-0 border border-gray-200 dark:border-gray-700 transition-all duration-200 cursor-pointer hover:scale-[1.02] overflow-hidden box-border",
i
),
style: { width: c === "sm" ? "305px" : c === "lg" ? "385px" : "345px", minWidth: c === "sm" ? "305px" : c === "lg" ? "385px" : "345px", maxWidth: c === "sm" ? "305px" : c === "lg" ? "385px" : "345px" },
onClick: () => k(C),
children: /* @__PURE__ */ z("div", { className: "p-3 w-full overflow-hidden box-border", children: [
/* @__PURE__ */ z("div", { className: "flex items-start gap-3 mb-3 w-full", children: [
/* @__PURE__ */ h("div", { className: "flex-shrink-0", children: /* @__PURE__ */ h(
"div",
{
className: "rounded-full overflow-hidden bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center",
style: { aspectRatio: "1", width: "48px", height: "48px" },
children: J ? /* @__PURE__ */ h(
"img",
{
src: J,
alt: R,
className: "w-full h-full object-cover",
style: { aspectRatio: "1" },
onError: (O) => {
O.target.style.display = "none";
const Y = O.target.parentElement;
Y && (Y.innerHTML = `
<svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
`);
}
}
) : (
/* Placeholder icon when no product image */
/* @__PURE__ */ h("svg", { className: "w-6 h-6 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ h("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
)
}
) }),
/* @__PURE__ */ z("div", { className: "flex-1 min-w-0 max-w-full overflow-hidden", children: [
R && /* @__PURE__ */ h("h4", { className: "text-sm font-medium text-gray-900 dark:text-white mb-1 leading-tight break-words overflow-wrap-anywhere", children: R }),
V && /* @__PURE__ */ h("p", { className: "text-xs text-gray-600 dark:text-gray-400 break-words overflow-wrap-anywhere line-clamp-2", title: V, children: V })
] })
] }),
/* @__PURE__ */ z("div", { className: "mt-3 flex items-center justify-between gap-2", children: [
/* @__PURE__ */ z("div", { className: "flex items-center gap-2", children: [
j && /* @__PURE__ */ h("span", { className: "text-sm font-semibold text-gray-900 dark:text-white", children: j }),
q && /* @__PURE__ */ z("span", { className: "text-xs text-red-600 dark:text-red-400 font-medium", children: [
q,
" OFF"
] })
] }),
pe && /* @__PURE__ */ h(
"button",
{
onClick: (O) => {
O.stopPropagation(), k(C);
},
className: "px-3 py-1.5 text-xs font-medium text-gray-100 bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 rounded-md transition-colors duration-200 whitespace-nowrap",
children: W
}
)
] })
] })
}
)
},
de
);
}) }),
_.length > 0 && /* @__PURE__ */ z(ye, { children: [
/* @__PURE__ */ h("div", { className: "absolute top-1/2 -left-2 transform -translate-y-1/2 bg-white dark:bg-gray-800 rounded-full shadow-lg p-1 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ h("svg", { className: "w-4 h-4 text-gray-600 dark:text-gray-300", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ h("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
/* @__PURE__ */ h("div", { className: "absolute top-1/2 -right-2 transform -translate-y-1/2 bg-white dark:bg-gray-800 rounded-full shadow-lg p-1 opacity-0 group-hover:opacity-100 transi