@liforma/client 0.4.5 → 0.4.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/CHANGELOG.md +36 -0
- package/README.md +23 -0
- package/dist/next/index.js +23 -4
- package/dist/next/index.js.map +1 -1
- package/dist/next/next/thumbnail.d.ts +5 -0
- package/dist/next/next/thumbnail.d.ts.map +1 -0
- package/dist/next/react/thumbnail.d.ts +4 -0
- package/dist/next/react/thumbnail.d.ts.map +1 -0
- package/dist/next/thumbnail.js +396 -0
- package/dist/next/thumbnail.js.map +1 -0
- package/dist/next/v2/embed/iframeHost.d.ts +3 -1
- package/dist/next/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/next/v2/embed/protocol.d.ts +10 -1
- package/dist/next/v2/embed/protocol.d.ts.map +1 -1
- package/dist/next/v2/experience.d.ts +10 -2
- package/dist/next/v2/experience.d.ts.map +1 -1
- package/dist/next/v2/experienceEvents.d.ts +2 -0
- package/dist/next/v2/experienceEvents.d.ts.map +1 -1
- package/dist/next/v2/types/sessionInteraction.d.ts +30 -0
- package/dist/next/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/npm/index.js +23 -4
- package/dist/npm/index.js.map +1 -1
- package/dist/npm/thumbnail/index.js +231 -0
- package/dist/npm/thumbnail/index.js.map +1 -0
- package/dist/npm/v2/embed/iframeHost.d.ts +3 -1
- package/dist/npm/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/npm/v2/embed/protocol.d.ts +10 -1
- package/dist/npm/v2/embed/protocol.d.ts.map +1 -1
- package/dist/npm/v2/experience.d.ts +10 -2
- package/dist/npm/v2/experience.d.ts.map +1 -1
- package/dist/npm/v2/experienceEvents.d.ts +2 -0
- package/dist/npm/v2/experienceEvents.d.ts.map +1 -1
- package/dist/npm/v2/index.d.ts +1 -1
- package/dist/npm/v2/index.d.ts.map +1 -1
- package/dist/npm/v2/npm.d.ts +1 -1
- package/dist/npm/v2/npm.d.ts.map +1 -1
- package/dist/npm/v2/thumbnail-cdn.d.ts +17 -0
- package/dist/npm/v2/thumbnail-cdn.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts +30 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/react/component/experienceComponentRuntime.d.ts +1 -0
- package/dist/react/component/experienceComponentRuntime.d.ts.map +1 -1
- package/dist/react/component/experienceComponentTypes.d.ts +8 -0
- package/dist/react/component/experienceComponentTypes.d.ts.map +1 -1
- package/dist/react/index.js +119 -96
- package/dist/react/index.js.map +1 -1
- package/dist/react/react/Experience.d.ts.map +1 -1
- package/dist/react/react/thumbnail.d.ts +4 -0
- package/dist/react/react/thumbnail.d.ts.map +1 -0
- package/dist/react/thumbnail.js +396 -0
- package/dist/react/thumbnail.js.map +1 -0
- package/dist/react/v2/embed/iframeHost.d.ts +3 -1
- package/dist/react/v2/embed/iframeHost.d.ts.map +1 -1
- package/dist/react/v2/embed/protocol.d.ts +10 -1
- package/dist/react/v2/embed/protocol.d.ts.map +1 -1
- package/dist/react/v2/experience.d.ts +10 -2
- package/dist/react/v2/experience.d.ts.map +1 -1
- package/dist/react/v2/experienceEvents.d.ts +2 -0
- package/dist/react/v2/experienceEvents.d.ts.map +1 -1
- package/dist/react/v2/types/sessionInteraction.d.ts +30 -0
- package/dist/react/v2/types/sessionInteraction.d.ts.map +1 -1
- package/dist/sdk/v2/client.js +3 -810
- package/dist/sdk/v2/client.js.map +1 -1
- package/dist/sdk/v2/thumbnail.js +222 -0
- package/dist/sdk/v2/thumbnail.js.map +1 -0
- package/dist/svelte/Experience.svelte +11 -0
- package/dist/svelte/Experience.svelte.d.ts +1 -0
- package/dist/svelte/ExperienceThumbnail.svelte +1 -1
- package/dist/svelte/ExperienceThumbnail.svelte.d.ts +1 -1
- package/dist/svelte/thumbnail.d.ts +2 -0
- package/dist/svelte/thumbnail.js +1 -0
- package/package.json +24 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Experience.d.ts","sourceRoot":"","sources":["../../../src/react/Experience.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAE/F,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"Experience.d.ts","sourceRoot":"","sources":["../../../src/react/Experience.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAE/F,eAAO,MAAM,UAAU,8GAmNrB,CAAC;AAEH,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thumbnail.d.ts","sourceRoot":"","sources":["../../../src/react/thumbnail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { useEffect as e, useMemo as t, useRef as n, useState as r } from "react";
|
|
4
|
+
import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
|
+
//#region src/thumbnail/types.ts
|
|
6
|
+
function s(e) {
|
|
7
|
+
return e === "face" ? "liforma-et--fit-face" : e === "medium" ? "liforma-et--fit-medium" : "";
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/thumbnail/toGalleryThumbUrl.ts
|
|
11
|
+
var c = /(\/avatars\/[^/]+\/)(\d+)(\/)/i, l = /_CH(\.webp)/i, u = /(-)(\d+x\d+)(\.webp)(\?|$)/i;
|
|
12
|
+
function d(e) {
|
|
13
|
+
let t = e.trim();
|
|
14
|
+
if (!t) return t;
|
|
15
|
+
let n = t.replace(c, (e, t, n, r) => n === "256" ? `${t}${n}${r}` : `${t}256${r}`);
|
|
16
|
+
return n = n.replace(l, "_neutral$1"), n = n.replace(u, (e, t, n, r, i) => n === "256x256" ? `${t}${n}${r}${i}` : `${t}256x256${r}${i}`), n;
|
|
17
|
+
}
|
|
18
|
+
function ee(e) {
|
|
19
|
+
let t = e.avatarImage?.trim() || e.galleryThumb?.avatarImage?.trim() || "";
|
|
20
|
+
if (!t) return null;
|
|
21
|
+
let n = e.backgroundImage?.trim() || e.galleryThumb?.backgroundImage?.trim() || "", r = e.foregroundImage?.trim() || e.galleryThumb?.foregroundImage?.trim() || "", i = e.fallbackImage?.trim() || "";
|
|
22
|
+
return {
|
|
23
|
+
avatarImage: d(t),
|
|
24
|
+
...n ? { backgroundImage: d(n) } : {},
|
|
25
|
+
...r ? { foregroundImage: d(r) } : {},
|
|
26
|
+
...i ? { fallbackImage: d(i) } : {}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/shims/localStack.ts
|
|
31
|
+
function f() {
|
|
32
|
+
if (globalThis.__LIFORMA_STACK === "local") return !0;
|
|
33
|
+
if (typeof location > "u") return !1;
|
|
34
|
+
try {
|
|
35
|
+
return new URLSearchParams(location.search).get("stack") === "local";
|
|
36
|
+
} catch {
|
|
37
|
+
return !1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/thumbnail/hostedLaunchUrl.ts
|
|
42
|
+
var p = "https://player.liforma.ai", m = "http://localhost:3002";
|
|
43
|
+
function te(e) {
|
|
44
|
+
return e.href?.trim() ? "anchor" : e.hasClickHandler ? "button" : e.experienceId?.trim() ? "anchor" : "presentational";
|
|
45
|
+
}
|
|
46
|
+
function h(e) {
|
|
47
|
+
let t = e?.trim();
|
|
48
|
+
return t ? t.replace(/\/$/, "") : f() ? m : p;
|
|
49
|
+
}
|
|
50
|
+
function ne(e) {
|
|
51
|
+
let t = e.experienceId.trim(), n = h(e.playerBaseUrl), r = new URL(`${n}/${encodeURIComponent(t)}`), i = e.returnUrl?.trim();
|
|
52
|
+
return i && r.searchParams.set("returnUrl", i), r.toString();
|
|
53
|
+
}
|
|
54
|
+
function re(e) {
|
|
55
|
+
let t = e.href?.trim();
|
|
56
|
+
if (t) return t;
|
|
57
|
+
let n = e.experienceId?.trim();
|
|
58
|
+
if (!n) return;
|
|
59
|
+
let r = e.returnUrl?.trim();
|
|
60
|
+
return !r && e.useCurrentPageAsReturnUrl && typeof window < "u" && (r = window.location.href), ne({
|
|
61
|
+
experienceId: n,
|
|
62
|
+
...r ? { returnUrl: r } : {},
|
|
63
|
+
playerBaseUrl: e.playerBaseUrl
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function g() {
|
|
67
|
+
return typeof window > "u" ? !1 : window.matchMedia("(hover: none), (pointer: coarse)").matches;
|
|
68
|
+
}
|
|
69
|
+
var _ = 0, v = [];
|
|
70
|
+
function y() {
|
|
71
|
+
return g() ? 4 : Infinity;
|
|
72
|
+
}
|
|
73
|
+
function ie() {
|
|
74
|
+
return g() ? 160 : 0;
|
|
75
|
+
}
|
|
76
|
+
function b() {
|
|
77
|
+
let e = y();
|
|
78
|
+
for (; _ < e && v.length > 0;) {
|
|
79
|
+
let e = v.shift();
|
|
80
|
+
if (!e || e.cancelled) continue;
|
|
81
|
+
_ += 1, e.start();
|
|
82
|
+
let t = ie();
|
|
83
|
+
if (t <= 0) {
|
|
84
|
+
_ = Math.max(0, _ - 1);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
window.setTimeout(() => {
|
|
88
|
+
_ = Math.max(0, _ - 1), b();
|
|
89
|
+
}, t);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function x(e) {
|
|
93
|
+
if (!g()) return e(), () => {};
|
|
94
|
+
let t = {
|
|
95
|
+
start: e,
|
|
96
|
+
cancelled: !1
|
|
97
|
+
};
|
|
98
|
+
return v.push(t), b(), () => {
|
|
99
|
+
t.cancelled = !0;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/thumbnail/lazyLoad.ts
|
|
104
|
+
function S() {
|
|
105
|
+
return g() ? "96px 0px" : "280px 0px";
|
|
106
|
+
}
|
|
107
|
+
function C(e) {
|
|
108
|
+
let t = e.trim().split(/\s+/)[0] ?? "0px", n = Number.parseFloat(t);
|
|
109
|
+
return Number.isFinite(n) ? Math.abs(n) : 280;
|
|
110
|
+
}
|
|
111
|
+
function w(e, t) {
|
|
112
|
+
if (typeof window > "u") return !1;
|
|
113
|
+
let n = e.getBoundingClientRect();
|
|
114
|
+
return n.bottom >= -t && n.top <= window.innerHeight + t;
|
|
115
|
+
}
|
|
116
|
+
function ae(e, t) {
|
|
117
|
+
let { onVisibleChange: n } = t, r = t.rootMargin ?? S(), i = C(r), a = !1, o = !1, s = null, c = () => {
|
|
118
|
+
o || (s?.(), s = x(() => {
|
|
119
|
+
s = null, o = !0, n(!0);
|
|
120
|
+
}));
|
|
121
|
+
}, l = (e) => {
|
|
122
|
+
if (e !== a) {
|
|
123
|
+
if (a = e, e) {
|
|
124
|
+
c();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
s?.(), s = null, n(!1);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
if (typeof IntersectionObserver > "u") return c(), () => {
|
|
131
|
+
s?.(), s = null;
|
|
132
|
+
};
|
|
133
|
+
let u = new IntersectionObserver((e) => {
|
|
134
|
+
l(e.some((e) => e.isIntersecting));
|
|
135
|
+
}, {
|
|
136
|
+
root: null,
|
|
137
|
+
rootMargin: r,
|
|
138
|
+
threshold: 0
|
|
139
|
+
});
|
|
140
|
+
return u.observe(e), w(e, i) && l(!0), () => {
|
|
141
|
+
s?.(), s = null, u.disconnect();
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/thumbnail/scrollParallax.ts
|
|
146
|
+
function T() {
|
|
147
|
+
return typeof window > "u" || window.matchMedia("(prefers-reduced-motion: reduce)").matches ? !1 : window.matchMedia("(hover: none), (pointer: coarse)").matches;
|
|
148
|
+
}
|
|
149
|
+
function E(e, t) {
|
|
150
|
+
return ((e.top + e.height / 2) / Math.max(t, 1) - .5) * 2;
|
|
151
|
+
}
|
|
152
|
+
var D = /* @__PURE__ */ new Set(), O = !1, k = 0;
|
|
153
|
+
function A() {
|
|
154
|
+
if (k = 0, D.size === 0 || typeof window > "u") return;
|
|
155
|
+
let e = window.innerHeight;
|
|
156
|
+
for (let t of D) {
|
|
157
|
+
if (t.pointerActive?.()) continue;
|
|
158
|
+
let n = t.element.getBoundingClientRect();
|
|
159
|
+
n.bottom < -64 || n.top > e + 64 || t.onParallax(E(n, e));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function j() {
|
|
163
|
+
k === 0 && (k = requestAnimationFrame(A));
|
|
164
|
+
}
|
|
165
|
+
function M() {
|
|
166
|
+
O || typeof window > "u" || (O = !0, window.addEventListener("scroll", j, { passive: !0 }), window.addEventListener("resize", j, { passive: !0 }));
|
|
167
|
+
}
|
|
168
|
+
function N() {
|
|
169
|
+
D.size > 0 || !O || typeof window > "u" || (O = !1, k !== 0 && (cancelAnimationFrame(k), k = 0), window.removeEventListener("scroll", j), window.removeEventListener("resize", j));
|
|
170
|
+
}
|
|
171
|
+
function oe(e, t) {
|
|
172
|
+
if (!T()) return () => {};
|
|
173
|
+
let n = {
|
|
174
|
+
element: e,
|
|
175
|
+
onParallax: t.onParallax,
|
|
176
|
+
pointerActive: t.pointerActive
|
|
177
|
+
};
|
|
178
|
+
return D.add(n), M(), n.pointerActive?.() || t.onParallax(E(e.getBoundingClientRect(), window.innerHeight)), () => {
|
|
179
|
+
D.delete(n), N();
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/thumbnail/styles.ts
|
|
184
|
+
var se = ".liforma-et {\n --liforma-et-parallax-x: 0;\n --liforma-et-parallax-y: 0;\n --liforma-et-bg-scale: 1;\n --liforma-et-fg-scale: 1;\n --liforma-et-avatar-scale: 1;\n --liforma-et-bg-shift: 0px;\n --liforma-et-fg-shift: 0px;\n --liforma-et-avatar-shift: 0px;\n --liforma-et-reveal-duration: 420ms;\n\n box-sizing: border-box;\n position: relative;\n display: block;\n width: 100%;\n height: 100%;\n min-height: 0;\n margin: 0;\n padding: 0;\n border: 0;\n border-radius: 0.65rem;\n overflow: hidden;\n background: #111;\n color: inherit;\n text-decoration: none;\n cursor: inherit;\n -webkit-tap-highlight-color: transparent;\n}\n\na.liforma-et,\nbutton.liforma-et {\n cursor: pointer;\n}\n\nbutton.liforma-et {\n font: inherit;\n appearance: none;\n}\n\n.liforma-et__placeholder {\n position: absolute;\n inset: 0;\n z-index: 0;\n background:\n radial-gradient(120% 90% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 58%),\n linear-gradient(180deg, #1a1a1a 0%, #101010 100%);\n opacity: 1;\n transition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n.liforma-et--revealed .liforma-et__placeholder {\n opacity: 0;\n}\n\n.liforma-et__media {\n opacity: 0;\n transition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n.liforma-et__media--ready {\n opacity: 1;\n}\n\n.liforma-et__background {\n position: absolute;\n inset: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n object-fit: cover;\n object-position: center center;\n transform: translate(\n calc(var(--liforma-et-parallax-x) * var(--liforma-et-bg-shift)),\n calc(var(--liforma-et-parallax-y) * var(--liforma-et-bg-shift))\n )\n scale(var(--liforma-et-bg-scale));\n transform-origin: center center;\n transition:\n opacity var(--liforma-et-reveal-duration) ease,\n transform 160ms ease;\n}\n\n.liforma-et__avatar {\n position: relative;\n z-index: 2;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n object-position: center bottom;\n transform: scale(var(--liforma-et-avatar-scale))\n translate(\n calc(var(--liforma-et-parallax-x) * var(--liforma-et-avatar-shift)),\n calc(var(--liforma-et-parallax-y) * var(--liforma-et-avatar-shift))\n );\n transform-origin: center center;\n transition:\n opacity var(--liforma-et-reveal-duration) ease,\n transform 160ms ease;\n}\n\n/* Gallery plates are typically square in a square tile — contain vs cover is a no-op\n without a zoom. Scale the whole scene from the upper third so Face matches\n player fit (location + avatar crop together). */\n.liforma-et--fit-face {\n --liforma-et-avatar-scale: 1.85;\n --liforma-et-bg-scale: 1.85;\n --liforma-et-fg-scale: 1.85;\n}\n\n.liforma-et--fit-face .liforma-et__avatar,\n.liforma-et--fit-face .liforma-et__background,\n.liforma-et--fit-face .liforma-et__foreground {\n transform-origin: 50% 18%;\n}\n\n.liforma-et--fit-face .liforma-et__avatar {\n object-fit: cover;\n object-position: 50% 18%;\n}\n\n/* Bust / medium: less zoom than face so upper chest stays in frame (player 3.75H window). */\n.liforma-et--fit-medium {\n --liforma-et-avatar-scale: 1.35;\n --liforma-et-bg-scale: 1.35;\n --liforma-et-fg-scale: 1.35;\n}\n\n.liforma-et--fit-medium .liforma-et__avatar,\n.liforma-et--fit-medium .liforma-et__background,\n.liforma-et--fit-medium .liforma-et__foreground {\n transform-origin: 50% 28%;\n}\n\n.liforma-et--fit-medium .liforma-et__avatar {\n object-fit: cover;\n object-position: 50% 28%;\n}\n\n.liforma-et__foreground {\n position: absolute;\n inset: 0;\n z-index: 3;\n width: 100%;\n height: 100%;\n object-fit: cover;\n object-position: center center;\n pointer-events: none;\n transform: translate(\n calc(var(--liforma-et-parallax-x) * var(--liforma-et-fg-shift) * -1),\n calc(var(--liforma-et-parallax-y) * var(--liforma-et-fg-shift) * -1)\n )\n scale(var(--liforma-et-fg-scale));\n transform-origin: center center;\n transition:\n opacity var(--liforma-et-reveal-duration) ease,\n transform 160ms ease;\n}\n\n.liforma-et--parallax {\n --liforma-et-bg-scale: 1.08;\n --liforma-et-fg-scale: 1.05;\n --liforma-et-avatar-scale: 1.08;\n --liforma-et-bg-shift: 10px;\n --liforma-et-fg-shift: 4px;\n --liforma-et-avatar-shift: 4px;\n}\n\n/* Promote layers only while parallax is active — avoids N compositor surfaces on galleries. */\n.liforma-et--parallax .liforma-et__background,\n.liforma-et--parallax .liforma-et__foreground,\n.liforma-et--parallax .liforma-et__avatar {\n will-change: transform;\n}\n\n.liforma-et--parallax.liforma-et--fit-face {\n --liforma-et-avatar-scale: 1.95;\n --liforma-et-bg-scale: 1.95;\n --liforma-et-fg-scale: 1.95;\n --liforma-et-avatar-shift: 0px;\n}\n\n.liforma-et--parallax.liforma-et--fit-medium {\n --liforma-et-avatar-scale: 1.42;\n --liforma-et-bg-scale: 1.42;\n --liforma-et-fg-scale: 1.42;\n --liforma-et-avatar-shift: 0px;\n}\n\n.liforma-et--scroll-parallax .liforma-et__background,\n.liforma-et--scroll-parallax .liforma-et__foreground,\n.liforma-et--scroll-parallax .liforma-et__avatar {\n transition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .liforma-et {\n --liforma-et-reveal-duration: 0ms;\n }\n\n .liforma-et--parallax {\n --liforma-et-bg-scale: 1;\n --liforma-et-fg-scale: 1;\n --liforma-et-avatar-scale: 1;\n --liforma-et-bg-shift: 0px;\n --liforma-et-fg-shift: 0px;\n --liforma-et-avatar-shift: 0px;\n }\n\n .liforma-et--parallax.liforma-et--fit-face {\n --liforma-et-avatar-scale: 1.85;\n --liforma-et-bg-scale: 1.85;\n --liforma-et-fg-scale: 1.85;\n }\n\n .liforma-et__background,\n .liforma-et__foreground,\n .liforma-et__avatar {\n transition: none;\n }\n}", P = !1;
|
|
185
|
+
function ce(e) {
|
|
186
|
+
if (typeof document > "u" || P) return;
|
|
187
|
+
if (document.querySelector("style[data-liforma-et]")) {
|
|
188
|
+
P = !0;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
let t = document.createElement("style");
|
|
192
|
+
t.setAttribute("data-liforma-et", ""), t.textContent = e, document.head.appendChild(t), P = !0;
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/react/ExperienceThumbnail.tsx
|
|
196
|
+
function F(e, t) {
|
|
197
|
+
return `${e} liforma-et__media${t ? " liforma-et__media--ready" : ""}`;
|
|
198
|
+
}
|
|
199
|
+
function I(c) {
|
|
200
|
+
let { galleryThumb: l, avatarImage: u, backgroundImage: d, foregroundImage: f, alt: p, experienceId: m, href: h, target: ne, rel: g, onClick: _, returnUrl: v, playerBaseUrl: y, parallax: ie = !0, fit: b = "full", lazy: x = !0, className: S = "", fallbackImage: C } = c, w = t(() => ee({
|
|
201
|
+
galleryThumb: l,
|
|
202
|
+
avatarImage: u,
|
|
203
|
+
backgroundImage: d,
|
|
204
|
+
foregroundImage: f,
|
|
205
|
+
fallbackImage: C
|
|
206
|
+
}), [
|
|
207
|
+
l,
|
|
208
|
+
u,
|
|
209
|
+
d,
|
|
210
|
+
f,
|
|
211
|
+
C
|
|
212
|
+
]), T = te({
|
|
213
|
+
href: h,
|
|
214
|
+
hasClickHandler: typeof _ == "function",
|
|
215
|
+
experienceId: m
|
|
216
|
+
}), D = T === "anchor" && !h?.trim() && !!m?.trim(), O = !!w?.backgroundImage, k = ie !== !1, A = n(null), j = n(!1), [M, N] = r(!x), [P, I] = r(!1), [L, le] = r(!1), [ue, R] = r(0), [de, z] = r(0), [fe, B] = r(!1), [V, H] = r(!1), [pe, U] = r(!1), [me, W] = r(!1), [G, he] = r(), K = w ? fe && w.fallbackImage ? w.fallbackImage : w.avatarImage : "";
|
|
217
|
+
e(() => {
|
|
218
|
+
ce(se);
|
|
219
|
+
}, []), e(() => {
|
|
220
|
+
he(re({
|
|
221
|
+
href: h,
|
|
222
|
+
experienceId: m,
|
|
223
|
+
returnUrl: v,
|
|
224
|
+
playerBaseUrl: y,
|
|
225
|
+
useCurrentPageAsReturnUrl: D && !v?.trim()
|
|
226
|
+
}));
|
|
227
|
+
}, [
|
|
228
|
+
h,
|
|
229
|
+
m,
|
|
230
|
+
v,
|
|
231
|
+
y,
|
|
232
|
+
D
|
|
233
|
+
]), e(() => {
|
|
234
|
+
H(!1), U(!1), W(!1), B(!1);
|
|
235
|
+
}, [
|
|
236
|
+
w?.backgroundImage,
|
|
237
|
+
w?.foregroundImage,
|
|
238
|
+
K
|
|
239
|
+
]), e(() => {
|
|
240
|
+
let e = A.current;
|
|
241
|
+
if (e) {
|
|
242
|
+
if (!x) {
|
|
243
|
+
N(!0);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
return ae(e, { onVisibleChange: (e) => {
|
|
247
|
+
e && N(!0);
|
|
248
|
+
} });
|
|
249
|
+
}
|
|
250
|
+
}, [
|
|
251
|
+
x,
|
|
252
|
+
w,
|
|
253
|
+
T,
|
|
254
|
+
G
|
|
255
|
+
]), e(() => {
|
|
256
|
+
let e = A.current;
|
|
257
|
+
if (!(!e || !k)) return oe(e, {
|
|
258
|
+
onParallax: (e) => {
|
|
259
|
+
le(!0), j.current || (R(e), z(0));
|
|
260
|
+
},
|
|
261
|
+
pointerActive: () => j.current
|
|
262
|
+
});
|
|
263
|
+
}, [
|
|
264
|
+
k,
|
|
265
|
+
w,
|
|
266
|
+
T,
|
|
267
|
+
G
|
|
268
|
+
]);
|
|
269
|
+
let ge = (e) => {
|
|
270
|
+
if (!k || L) return;
|
|
271
|
+
let t = e.currentTarget.getBoundingClientRect();
|
|
272
|
+
t.width <= 0 || t.height <= 0 || (R(((e.clientX - t.left) / t.width - .5) * 2), z(((e.clientY - t.top) / t.height - .5) * 2));
|
|
273
|
+
}, q = (e) => {
|
|
274
|
+
let t = j.current;
|
|
275
|
+
j.current = !1, I(!1), L && t ? (R(E(e.getBoundingClientRect(), window.innerHeight)), z(0)) : L || (R(0), z(0));
|
|
276
|
+
}, _e = (e) => {
|
|
277
|
+
if (!k) return;
|
|
278
|
+
j.current = !0, e.pointerType === "mouse" && I(!0);
|
|
279
|
+
let t = e.currentTarget, n = () => {
|
|
280
|
+
q(t), window.removeEventListener("pointerup", n), window.removeEventListener("pointercancel", n);
|
|
281
|
+
};
|
|
282
|
+
window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n);
|
|
283
|
+
}, ve = (e) => {
|
|
284
|
+
if (_?.(e), !e.defaultPrevented && D && !v?.trim()) {
|
|
285
|
+
let t = re({
|
|
286
|
+
experienceId: m,
|
|
287
|
+
playerBaseUrl: y,
|
|
288
|
+
useCurrentPageAsReturnUrl: !0
|
|
289
|
+
});
|
|
290
|
+
t && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && (e.preventDefault(), window.location.assign(t));
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
if (!w) return null;
|
|
294
|
+
let ye = k && (P || L), be = M && (pe || V || me), J = [
|
|
295
|
+
"liforma-et",
|
|
296
|
+
O ? "liforma-et--scene" : "",
|
|
297
|
+
s(b),
|
|
298
|
+
ye ? "liforma-et--parallax" : "",
|
|
299
|
+
L ? "liforma-et--scroll-parallax" : "",
|
|
300
|
+
M && !be ? "liforma-et--loading" : "",
|
|
301
|
+
be ? "liforma-et--revealed" : "",
|
|
302
|
+
S
|
|
303
|
+
].filter(Boolean).join(" "), Y = {
|
|
304
|
+
"--liforma-et-parallax-x": ue,
|
|
305
|
+
"--liforma-et-parallax-y": de
|
|
306
|
+
}, X = (e, t) => {
|
|
307
|
+
e.complete && t(!0);
|
|
308
|
+
}, Z = /* @__PURE__ */ o(i, { children: [
|
|
309
|
+
/* @__PURE__ */ a("span", {
|
|
310
|
+
className: "liforma-et__placeholder",
|
|
311
|
+
"aria-hidden": "true"
|
|
312
|
+
}),
|
|
313
|
+
M && w.backgroundImage ? /* @__PURE__ */ a("img", {
|
|
314
|
+
className: F("liforma-et__background", V),
|
|
315
|
+
src: w.backgroundImage,
|
|
316
|
+
alt: "",
|
|
317
|
+
decoding: "async",
|
|
318
|
+
ref: (e) => {
|
|
319
|
+
e && X(e, H);
|
|
320
|
+
},
|
|
321
|
+
onLoad: () => H(!0),
|
|
322
|
+
onError: () => H(!0)
|
|
323
|
+
}) : null,
|
|
324
|
+
M && K ? /* @__PURE__ */ a("img", {
|
|
325
|
+
className: F("liforma-et__avatar", pe),
|
|
326
|
+
src: K,
|
|
327
|
+
alt: "",
|
|
328
|
+
decoding: "async",
|
|
329
|
+
ref: (e) => {
|
|
330
|
+
e && X(e, U);
|
|
331
|
+
},
|
|
332
|
+
onLoad: () => U(!0),
|
|
333
|
+
onError: () => {
|
|
334
|
+
w.fallbackImage ? B(!0) : U(!0);
|
|
335
|
+
}
|
|
336
|
+
}) : null,
|
|
337
|
+
M && w.foregroundImage ? /* @__PURE__ */ a("img", {
|
|
338
|
+
className: F("liforma-et__foreground", me),
|
|
339
|
+
src: w.foregroundImage,
|
|
340
|
+
alt: "",
|
|
341
|
+
decoding: "async",
|
|
342
|
+
ref: (e) => {
|
|
343
|
+
e && X(e, W);
|
|
344
|
+
},
|
|
345
|
+
onLoad: () => W(!0),
|
|
346
|
+
onError: () => W(!0)
|
|
347
|
+
}) : null
|
|
348
|
+
] }), Q = {
|
|
349
|
+
onPointerDown: _e,
|
|
350
|
+
onPointerUp: (e) => q(e.currentTarget),
|
|
351
|
+
onPointerCancel: (e) => q(e.currentTarget),
|
|
352
|
+
onPointerEnter: (e) => {
|
|
353
|
+
k && e.pointerType === "mouse" && I(!0);
|
|
354
|
+
},
|
|
355
|
+
onPointerMove: ge,
|
|
356
|
+
onPointerLeave: () => {
|
|
357
|
+
j.current || (I(!1), L || (R(0), z(0)));
|
|
358
|
+
}
|
|
359
|
+
}, $ = (e) => {
|
|
360
|
+
A.current = e;
|
|
361
|
+
};
|
|
362
|
+
return T === "anchor" && G ? /* @__PURE__ */ a("a", {
|
|
363
|
+
ref: $,
|
|
364
|
+
className: J,
|
|
365
|
+
style: Y,
|
|
366
|
+
href: G,
|
|
367
|
+
target: ne,
|
|
368
|
+
rel: g,
|
|
369
|
+
"aria-label": p,
|
|
370
|
+
onClick: ve,
|
|
371
|
+
...Q,
|
|
372
|
+
children: Z
|
|
373
|
+
}) : T === "button" ? /* @__PURE__ */ a("button", {
|
|
374
|
+
type: "button",
|
|
375
|
+
ref: $,
|
|
376
|
+
className: J,
|
|
377
|
+
style: Y,
|
|
378
|
+
"aria-label": p,
|
|
379
|
+
onClick: ve,
|
|
380
|
+
...Q,
|
|
381
|
+
children: Z
|
|
382
|
+
}) : /* @__PURE__ */ a("div", {
|
|
383
|
+
ref: $,
|
|
384
|
+
className: J,
|
|
385
|
+
style: Y,
|
|
386
|
+
role: p ? "img" : void 0,
|
|
387
|
+
"aria-label": p || void 0,
|
|
388
|
+
"aria-hidden": p ? void 0 : !0,
|
|
389
|
+
...Q,
|
|
390
|
+
children: Z
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
//#endregion
|
|
394
|
+
export { I as ExperienceThumbnail };
|
|
395
|
+
|
|
396
|
+
//# sourceMappingURL=thumbnail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thumbnail.js","names":[],"sources":["../../src/thumbnail/types.ts","../../src/thumbnail/toGalleryThumbUrl.ts","../../src/shims/localStack.ts","../../src/thumbnail/hostedLaunchUrl.ts","../../src/thumbnail/thumbLoadScheduler.ts","../../src/thumbnail/lazyLoad.ts","../../src/thumbnail/scrollParallax.ts","../../src/thumbnail/styles.ts","../../src/thumbnail/ensureStyles.ts","../../src/react/ExperienceThumbnail.tsx"],"sourcesContent":["/** Catalog-shaped layered gallery preview (CDN URLs). */\nexport type GalleryThumb = {\n\treadonly avatarImage: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n};\n\nexport type ThumbnailInteractionKind = 'anchor' | 'button' | 'presentational';\n\nexport type ResolveThumbnailInteractionInput = {\n\treadonly href?: string | null;\n\treadonly hasClickHandler?: boolean;\n\treadonly experienceId?: string | null;\n};\n\nexport type ThumbnailLayers = {\n\treadonly avatarImage: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n\treadonly fallbackImage?: string;\n};\n\n/** Shared props across Svelte / React / Next (React uses `onClick`). */\nexport type ExperienceThumbnailBaseProps = {\n\treadonly galleryThumb?: GalleryThumb;\n\treadonly avatarImage?: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n\treadonly alt: string;\n\treadonly experienceId?: string;\n\treadonly href?: string;\n\treadonly target?: string;\n\treadonly rel?: string;\n\treadonly returnUrl?: string;\n\treadonly playerBaseUrl?: string;\n\treadonly parallax?: boolean;\n\t/** Same as `<Experience fit>`: `full` (default), `medium`, or `face`. */\n\treadonly fit?: 'full' | 'face' | 'medium';\n\treadonly lazy?: boolean;\n\treadonly className?: string;\n\treadonly fallbackImage?: string;\n};\n\nexport function thumbnailFitClass(fit?: 'full' | 'face' | 'medium'): string {\n\tif (fit === 'face') return 'liforma-et--fit-face';\n\tif (fit === 'medium') return 'liforma-et--fit-medium';\n\treturn '';\n}\n","const AVATAR_TIER_RE = /(\\/avatars\\/[^/]+\\/)(\\d+)(\\/)/i;\nconst AVATAR_CH_PLATE_RE = /_CH(\\.webp)/i;\nconst LOCATION_SIZE_RE = /(-)(\\d+x\\d+)(\\.webp)(\\?|$)/i;\n\n/**\n * Rewrite known Liforma CDN URLs to gallery thumb tiers.\n * Avatars: /{tier}/ → /256/; locations: -{WxH}.webp → -256x256.webp.\n * Unrecognized URLs are returned unchanged.\n */\nexport function toGalleryThumbUrl(url: string): string {\n\tconst raw = url.trim();\n\tif (!raw) return raw;\n\n\tlet next = raw.replace(AVATAR_TIER_RE, (_match, prefix: string, tier: string, slash: string) => {\n\t\tif (tier === '256') return `${prefix}${tier}${slash}`;\n\t\treturn `${prefix}256${slash}`;\n\t});\n\tnext = next.replace(AVATAR_CH_PLATE_RE, '_neutral$1');\n\n\tnext = next.replace(\n\t\tLOCATION_SIZE_RE,\n\t\t(_match, dash: string, size: string, ext: string, end: string) => {\n\t\t\tif (size === '256x256') return `${dash}${size}${ext}${end}`;\n\t\t\treturn `${dash}256x256${ext}${end}`;\n\t\t}\n\t);\n\n\treturn next;\n}\n\nexport function resolveThumbnailLayers(input: {\n\treadonly galleryThumb?: {\n\t\treadonly avatarImage?: string;\n\t\treadonly backgroundImage?: string;\n\t\treadonly foregroundImage?: string;\n\t};\n\treadonly avatarImage?: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n\treadonly fallbackImage?: string;\n}): {\n\treadonly avatarImage: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n\treadonly fallbackImage?: string;\n} | null {\n\tconst avatarSource =\n\t\tinput.avatarImage?.trim() ||\n\t\tinput.galleryThumb?.avatarImage?.trim() ||\n\t\t'';\n\tif (!avatarSource) return null;\n\n\tconst backgroundSource =\n\t\tinput.backgroundImage?.trim() || input.galleryThumb?.backgroundImage?.trim() || '';\n\tconst foregroundSource =\n\t\tinput.foregroundImage?.trim() || input.galleryThumb?.foregroundImage?.trim() || '';\n\tconst fallbackSource = input.fallbackImage?.trim() || '';\n\n\treturn {\n\t\tavatarImage: toGalleryThumbUrl(avatarSource),\n\t\t...(backgroundSource ? { backgroundImage: toGalleryThumbUrl(backgroundSource) } : {}),\n\t\t...(foregroundSource ? { foregroundImage: toGalleryThumbUrl(foregroundSource) } : {}),\n\t\t...(fallbackSource ? { fallbackImage: toGalleryThumbUrl(fallbackSource) } : {})\n\t};\n}\n","/**\n * Opt-in local monorepo stack (api :3001, player :3002).\n * Never inferred from hostname alone — third-party demos run on localhost against production.\n */\nexport function useExplicitLocalStack(): boolean {\n\tif ((globalThis as { __LIFORMA_STACK?: string }).__LIFORMA_STACK === 'local') {\n\t\treturn true;\n\t}\n\n\tif (typeof location === 'undefined') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\treturn new URLSearchParams(location.search).get('stack') === 'local';\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import { useExplicitLocalStack } from '../shims/localStack';\nimport type { ResolveThumbnailInteractionInput, ThumbnailInteractionKind } from './types';\n\nconst PRODUCTION_PLAYER_ORIGIN = 'https://player.liforma.ai';\nconst LOCAL_PLAYER_ORIGIN = 'http://localhost:3002';\n\n/** Priority: href → click-only → hosted (experienceId) → presentational. */\nexport function resolveThumbnailInteraction(\n\tinput: ResolveThumbnailInteractionInput\n): ThumbnailInteractionKind {\n\tif (input.href?.trim()) return 'anchor';\n\tif (input.hasClickHandler) return 'button';\n\tif (input.experienceId?.trim()) return 'anchor';\n\treturn 'presentational';\n}\n\nexport function resolvePlayerBaseUrl(playerBaseUrl?: string): string {\n\tconst configured = playerBaseUrl?.trim();\n\tif (configured) return configured.replace(/\\/$/, '');\n\n\tif (useExplicitLocalStack()) {\n\t\treturn LOCAL_PLAYER_ORIGIN;\n\t}\n\n\treturn PRODUCTION_PLAYER_ORIGIN;\n}\n\n/**\n * Build hosted player launch URL: `{player}/{experienceId}?returnUrl=…`\n * When `returnUrl` is omitted, callers should assign on click (SSR-safe) or pass an explicit URL.\n */\nexport function buildHostedLaunchUrl(options: {\n\treadonly experienceId: string;\n\treadonly returnUrl?: string;\n\treadonly playerBaseUrl?: string;\n}): string {\n\tconst experienceId = options.experienceId.trim();\n\tconst base = resolvePlayerBaseUrl(options.playerBaseUrl);\n\tconst url = new URL(`${base}/${encodeURIComponent(experienceId)}`);\n\tconst returnUrl = options.returnUrl?.trim();\n\tif (returnUrl) {\n\t\turl.searchParams.set('returnUrl', returnUrl);\n\t}\n\treturn url.toString();\n}\n\n/** Resolve href for anchor mode (app link or hosted launch). */\nexport function resolveThumbnailHref(options: {\n\treadonly href?: string;\n\treadonly experienceId?: string;\n\treadonly returnUrl?: string;\n\treadonly playerBaseUrl?: string;\n\t/** When true and returnUrl omitted, use window.location.href (browser only). */\n\treadonly useCurrentPageAsReturnUrl?: boolean;\n}): string | undefined {\n\tconst href = options.href?.trim();\n\tif (href) return href;\n\n\tconst experienceId = options.experienceId?.trim();\n\tif (!experienceId) return undefined;\n\n\tlet returnUrl = options.returnUrl?.trim();\n\tif (!returnUrl && options.useCurrentPageAsReturnUrl && typeof window !== 'undefined') {\n\t\treturnUrl = window.location.href;\n\t}\n\n\treturn buildHostedLaunchUrl({\n\t\texperienceId,\n\t\t...(returnUrl ? { returnUrl } : {}),\n\t\tplayerBaseUrl: options.playerBaseUrl\n\t});\n}\n","/** Touch / coarse pointers — limit how many thumbs start loading at once. */\nexport const COARSE_THUMB_LOAD_CONCURRENCY = 4;\n/** Delay before a started thumb frees its queue slot for the next card. */\nexport const COARSE_THUMB_LOAD_STAGGER_MS = 160;\n\nexport function prefersCoarsePointer(): boolean {\n\tif (typeof window === 'undefined') return false;\n\treturn window.matchMedia('(hover: none), (pointer: coarse)').matches;\n}\n\ntype QueuedLoad = {\n\treadonly start: () => void;\n\tcancelled: boolean;\n};\n\nlet inflight = 0;\nconst waiting: QueuedLoad[] = [];\n\nfunction maxConcurrent(): number {\n\treturn prefersCoarsePointer() ? COARSE_THUMB_LOAD_CONCURRENCY : Number.POSITIVE_INFINITY;\n}\n\nfunction staggerMs(): number {\n\treturn prefersCoarsePointer() ? COARSE_THUMB_LOAD_STAGGER_MS : 0;\n}\n\nfunction pump(): void {\n\tconst limit = maxConcurrent();\n\twhile (inflight < limit && waiting.length > 0) {\n\t\tconst next = waiting.shift();\n\t\tif (!next || next.cancelled) continue;\n\t\tinflight += 1;\n\t\tnext.start();\n\t\tconst delay = staggerMs();\n\t\tif (delay <= 0) {\n\t\t\tinflight = Math.max(0, inflight - 1);\n\t\t\tcontinue;\n\t\t}\n\t\twindow.setTimeout(() => {\n\t\t\tinflight = Math.max(0, inflight - 1);\n\t\t\tpump();\n\t\t}, delay);\n\t}\n}\n\n/**\n * On coarse pointers, start thumb image loads in small waves so old devices\n * are not hit with dozens of concurrent decodes. Fine pointers start immediately.\n * Returns a cancel function (no-op after start has run).\n */\nexport function scheduleThumbLoad(start: () => void): () => void {\n\tif (!prefersCoarsePointer()) {\n\t\tstart();\n\t\treturn () => {};\n\t}\n\n\tconst item: QueuedLoad = { start, cancelled: false };\n\twaiting.push(item);\n\tpump();\n\n\treturn () => {\n\t\titem.cancelled = true;\n\t};\n}\n\n/** Test helper — clear queue state between vitest cases. */\nexport function resetThumbLoadSchedulerForTests(): void {\n\tinflight = 0;\n\twaiting.length = 0;\n}\n","import { prefersCoarsePointer, scheduleThumbLoad } from './thumbLoadScheduler';\n\nexport type LazyThumbOptions = {\n\treadonly rootMargin?: string;\n\treadonly onVisibleChange: (visible: boolean) => void;\n};\n\n/** Desktop: prefetch earlier. Coarse/touch: tighter margin to cut burst loads. */\nexport function getDefaultLazyRootMargin(): string {\n\treturn prefersCoarsePointer() ? '96px 0px' : '280px 0px';\n}\n\nfunction parseVerticalRootMarginPx(rootMargin: string): number {\n\tconst first = rootMargin.trim().split(/\\s+/)[0] ?? '0px';\n\tconst value = Number.parseFloat(first);\n\treturn Number.isFinite(value) ? Math.abs(value) : 280;\n}\n\nfunction isNearViewport(element: HTMLElement, marginPx: number): boolean {\n\tif (typeof window === 'undefined') return false;\n\tconst rect = element.getBoundingClientRect();\n\treturn rect.bottom >= -marginPx && rect.top <= window.innerHeight + marginPx;\n}\n\n/** Observe the thumb and enable image loads when near the viewport. */\nexport function attachLazyThumb(element: HTMLElement, options: LazyThumbOptions): () => void {\n\tconst { onVisibleChange } = options;\n\tconst rootMargin = options.rootMargin ?? getDefaultLazyRootMargin();\n\tconst marginPx = parseVerticalRootMarginPx(rootMargin);\n\tlet visible = false;\n\tlet loadStarted = false;\n\tlet cancelScheduled: (() => void) | null = null;\n\n\tconst requestLoad = () => {\n\t\tif (loadStarted) return;\n\t\tcancelScheduled?.();\n\t\tcancelScheduled = scheduleThumbLoad(() => {\n\t\t\tcancelScheduled = null;\n\t\t\tloadStarted = true;\n\t\t\tonVisibleChange(true);\n\t\t});\n\t};\n\n\tconst setVisible = (next: boolean) => {\n\t\tif (next === visible) return;\n\t\tvisible = next;\n\t\tif (next) {\n\t\t\trequestLoad();\n\t\t\treturn;\n\t\t}\n\t\t// Keep images once started; only cancel a queued (not-yet-started) load.\n\t\tcancelScheduled?.();\n\t\tcancelScheduled = null;\n\t\tonVisibleChange(false);\n\t};\n\n\tif (typeof IntersectionObserver === 'undefined') {\n\t\trequestLoad();\n\t\treturn () => {\n\t\t\tcancelScheduled?.();\n\t\t\tcancelScheduled = null;\n\t\t};\n\t}\n\n\tconst observer = new IntersectionObserver(\n\t\t(entries) => {\n\t\t\tsetVisible(entries.some((entry) => entry.isIntersecting));\n\t\t},\n\t\t{ root: null, rootMargin, threshold: 0 }\n\t);\n\n\tobserver.observe(element);\n\n\tif (isNearViewport(element, marginPx)) {\n\t\tsetVisible(true);\n\t}\n\n\treturn () => {\n\t\tcancelScheduled?.();\n\t\tcancelScheduled = null;\n\t\tobserver.disconnect();\n\t};\n}\n\nexport function attachImageReady(element: HTMLImageElement, onReady: () => void): () => void {\n\tconst notify = () => onReady();\n\tif (element.complete) {\n\t\tqueueMicrotask(notify);\n\t} else {\n\t\telement.addEventListener('load', notify, { once: true });\n\t\telement.addEventListener('error', notify, { once: true });\n\t}\n\treturn () => {\n\t\telement.removeEventListener('load', notify);\n\t\telement.removeEventListener('error', notify);\n\t};\n}\n","/** Touch devices without hover — drive thumbnail parallax from scroll position. */\nexport function prefersScrollLinkedParallax(): boolean {\n\tif (typeof window === 'undefined') return false;\n\tif (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return false;\n\treturn window.matchMedia('(hover: none), (pointer: coarse)').matches;\n}\n\n/**\n * Map an element's vertical centre in the viewport to horizontal parallax in [-1, 1].\n */\nexport function horizontalParallaxFromViewportY(rect: DOMRect, viewportHeight: number): number {\n\tconst centerY = rect.top + rect.height / 2;\n\tconst t = centerY / Math.max(viewportHeight, 1);\n\treturn (t - 0.5) * 2;\n}\n\nexport type ScrollLinkedParallaxOptions = {\n\treadonly onParallax: (x: number) => void;\n\treadonly pointerActive?: () => boolean;\n};\n\ntype ScrollParallaxSubscriber = {\n\treadonly element: HTMLElement;\n\treadonly onParallax: (x: number) => void;\n\treadonly pointerActive?: () => boolean;\n};\n\nconst subscribers = new Set<ScrollParallaxSubscriber>();\nlet listening = false;\nlet frame = 0;\n\nfunction syncAll(): void {\n\tframe = 0;\n\tif (subscribers.size === 0 || typeof window === 'undefined') return;\n\tconst viewportHeight = window.innerHeight;\n\tfor (const entry of subscribers) {\n\t\tif (entry.pointerActive?.()) continue;\n\t\tconst rect = entry.element.getBoundingClientRect();\n\t\t// Skip off-screen thumbs — avoids N layout reads + framework updates per scroll.\n\t\tif (rect.bottom < -64 || rect.top > viewportHeight + 64) continue;\n\t\tentry.onParallax(horizontalParallaxFromViewportY(rect, viewportHeight));\n\t}\n}\n\nfunction scheduleSync(): void {\n\tif (frame !== 0) return;\n\tframe = requestAnimationFrame(syncAll);\n}\n\nfunction ensureListening(): void {\n\tif (listening || typeof window === 'undefined') return;\n\tlistening = true;\n\twindow.addEventListener('scroll', scheduleSync, { passive: true });\n\twindow.addEventListener('resize', scheduleSync, { passive: true });\n}\n\nfunction stopListeningIfIdle(): void {\n\tif (subscribers.size > 0 || !listening || typeof window === 'undefined') return;\n\tlistening = false;\n\tif (frame !== 0) {\n\t\tcancelAnimationFrame(frame);\n\t\tframe = 0;\n\t}\n\twindow.removeEventListener('scroll', scheduleSync);\n\twindow.removeEventListener('resize', scheduleSync);\n}\n\n/**\n * Subscribe to scroll/resize and update horizontal parallax from viewport Y.\n * Uses one shared window listener for all thumbs (old iPads with large galleries).\n */\nexport function attachScrollLinkedParallax(\n\telement: HTMLElement,\n\toptions: ScrollLinkedParallaxOptions\n): () => void {\n\tif (!prefersScrollLinkedParallax()) return () => {};\n\n\tconst entry: ScrollParallaxSubscriber = {\n\t\telement,\n\t\tonParallax: options.onParallax,\n\t\tpointerActive: options.pointerActive\n\t};\n\tsubscribers.add(entry);\n\tensureListening();\n\n\tif (!entry.pointerActive?.()) {\n\t\toptions.onParallax(\n\t\t\thorizontalParallaxFromViewportY(element.getBoundingClientRect(), window.innerHeight)\n\t\t);\n\t}\n\n\treturn () => {\n\t\tsubscribers.delete(entry);\n\t\tstopListeningIfIdle();\n\t};\n}\n\n/** Test helper — clear shared scroll state between vitest cases. */\nexport function resetScrollLinkedParallaxForTests(): void {\n\tsubscribers.clear();\n\tif (typeof window !== 'undefined' && listening) {\n\t\twindow.removeEventListener('scroll', scheduleSync);\n\t\twindow.removeEventListener('resize', scheduleSync);\n\t}\n\tlistening = false;\n\tif (frame !== 0) {\n\t\tcancelAnimationFrame(frame);\n\t\tframe = 0;\n\t}\n}\n","/** Shared styles for ExperienceThumbnail (class prefix `liforma-et`). */\nexport const EXPERIENCE_THUMBNAIL_CSS = `\n.liforma-et {\n\t--liforma-et-parallax-x: 0;\n\t--liforma-et-parallax-y: 0;\n\t--liforma-et-bg-scale: 1;\n\t--liforma-et-fg-scale: 1;\n\t--liforma-et-avatar-scale: 1;\n\t--liforma-et-bg-shift: 0px;\n\t--liforma-et-fg-shift: 0px;\n\t--liforma-et-avatar-shift: 0px;\n\t--liforma-et-reveal-duration: 420ms;\n\n\tbox-sizing: border-box;\n\tposition: relative;\n\tdisplay: block;\n\twidth: 100%;\n\theight: 100%;\n\tmin-height: 0;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tborder-radius: 0.65rem;\n\toverflow: hidden;\n\tbackground: #111;\n\tcolor: inherit;\n\ttext-decoration: none;\n\tcursor: inherit;\n\t-webkit-tap-highlight-color: transparent;\n}\n\na.liforma-et,\nbutton.liforma-et {\n\tcursor: pointer;\n}\n\nbutton.liforma-et {\n\tfont: inherit;\n\tappearance: none;\n}\n\n.liforma-et__placeholder {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 0;\n\tbackground:\n\t\tradial-gradient(120% 90% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 58%),\n\t\tlinear-gradient(180deg, #1a1a1a 0%, #101010 100%);\n\topacity: 1;\n\ttransition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n.liforma-et--revealed .liforma-et__placeholder {\n\topacity: 0;\n}\n\n.liforma-et__media {\n\topacity: 0;\n\ttransition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n.liforma-et__media--ready {\n\topacity: 1;\n}\n\n.liforma-et__background {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 1;\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: cover;\n\tobject-position: center center;\n\ttransform: translate(\n\t\t\tcalc(var(--liforma-et-parallax-x) * var(--liforma-et-bg-shift)),\n\t\t\tcalc(var(--liforma-et-parallax-y) * var(--liforma-et-bg-shift))\n\t\t)\n\t\tscale(var(--liforma-et-bg-scale));\n\ttransform-origin: center center;\n\ttransition:\n\t\topacity var(--liforma-et-reveal-duration) ease,\n\t\ttransform 160ms ease;\n}\n\n.liforma-et__avatar {\n\tposition: relative;\n\tz-index: 2;\n\tdisplay: block;\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: contain;\n\tobject-position: center bottom;\n\ttransform: scale(var(--liforma-et-avatar-scale))\n\t\ttranslate(\n\t\t\tcalc(var(--liforma-et-parallax-x) * var(--liforma-et-avatar-shift)),\n\t\t\tcalc(var(--liforma-et-parallax-y) * var(--liforma-et-avatar-shift))\n\t\t);\n\ttransform-origin: center center;\n\ttransition:\n\t\topacity var(--liforma-et-reveal-duration) ease,\n\t\ttransform 160ms ease;\n}\n\n/* Gallery plates are typically square in a square tile — contain vs cover is a no-op\n without a zoom. Scale the whole scene from the upper third so Face matches\n player fit (location + avatar crop together). */\n.liforma-et--fit-face {\n\t--liforma-et-avatar-scale: 1.85;\n\t--liforma-et-bg-scale: 1.85;\n\t--liforma-et-fg-scale: 1.85;\n}\n\n.liforma-et--fit-face .liforma-et__avatar,\n.liforma-et--fit-face .liforma-et__background,\n.liforma-et--fit-face .liforma-et__foreground {\n\ttransform-origin: 50% 18%;\n}\n\n.liforma-et--fit-face .liforma-et__avatar {\n\tobject-fit: cover;\n\tobject-position: 50% 18%;\n}\n\n/* Bust / medium: less zoom than face so upper chest stays in frame (player 3.75H window). */\n.liforma-et--fit-medium {\n\t--liforma-et-avatar-scale: 1.35;\n\t--liforma-et-bg-scale: 1.35;\n\t--liforma-et-fg-scale: 1.35;\n}\n\n.liforma-et--fit-medium .liforma-et__avatar,\n.liforma-et--fit-medium .liforma-et__background,\n.liforma-et--fit-medium .liforma-et__foreground {\n\ttransform-origin: 50% 28%;\n}\n\n.liforma-et--fit-medium .liforma-et__avatar {\n\tobject-fit: cover;\n\tobject-position: 50% 28%;\n}\n\n.liforma-et__foreground {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 3;\n\twidth: 100%;\n\theight: 100%;\n\tobject-fit: cover;\n\tobject-position: center center;\n\tpointer-events: none;\n\ttransform: translate(\n\t\t\tcalc(var(--liforma-et-parallax-x) * var(--liforma-et-fg-shift) * -1),\n\t\t\tcalc(var(--liforma-et-parallax-y) * var(--liforma-et-fg-shift) * -1)\n\t\t)\n\t\tscale(var(--liforma-et-fg-scale));\n\ttransform-origin: center center;\n\ttransition:\n\t\topacity var(--liforma-et-reveal-duration) ease,\n\t\ttransform 160ms ease;\n}\n\n.liforma-et--parallax {\n\t--liforma-et-bg-scale: 1.08;\n\t--liforma-et-fg-scale: 1.05;\n\t--liforma-et-avatar-scale: 1.08;\n\t--liforma-et-bg-shift: 10px;\n\t--liforma-et-fg-shift: 4px;\n\t--liforma-et-avatar-shift: 4px;\n}\n\n/* Promote layers only while parallax is active — avoids N compositor surfaces on galleries. */\n.liforma-et--parallax .liforma-et__background,\n.liforma-et--parallax .liforma-et__foreground,\n.liforma-et--parallax .liforma-et__avatar {\n\twill-change: transform;\n}\n\n.liforma-et--parallax.liforma-et--fit-face {\n\t--liforma-et-avatar-scale: 1.95;\n\t--liforma-et-bg-scale: 1.95;\n\t--liforma-et-fg-scale: 1.95;\n\t--liforma-et-avatar-shift: 0px;\n}\n\n.liforma-et--parallax.liforma-et--fit-medium {\n\t--liforma-et-avatar-scale: 1.42;\n\t--liforma-et-bg-scale: 1.42;\n\t--liforma-et-fg-scale: 1.42;\n\t--liforma-et-avatar-shift: 0px;\n}\n\n.liforma-et--scroll-parallax .liforma-et__background,\n.liforma-et--scroll-parallax .liforma-et__foreground,\n.liforma-et--scroll-parallax .liforma-et__avatar {\n\ttransition: opacity var(--liforma-et-reveal-duration) ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.liforma-et {\n\t\t--liforma-et-reveal-duration: 0ms;\n\t}\n\n\t.liforma-et--parallax {\n\t\t--liforma-et-bg-scale: 1;\n\t\t--liforma-et-fg-scale: 1;\n\t\t--liforma-et-avatar-scale: 1;\n\t\t--liforma-et-bg-shift: 0px;\n\t\t--liforma-et-fg-shift: 0px;\n\t\t--liforma-et-avatar-shift: 0px;\n\t}\n\n\t.liforma-et--parallax.liforma-et--fit-face {\n\t\t--liforma-et-avatar-scale: 1.85;\n\t\t--liforma-et-bg-scale: 1.85;\n\t\t--liforma-et-fg-scale: 1.85;\n\t}\n\n\t.liforma-et__background,\n\t.liforma-et__foreground,\n\t.liforma-et__avatar {\n\t\ttransition: none;\n\t}\n}\n`.trim();\n","let styleMounted = false;\n\n/** Inject shared thumbnail CSS once per document. */\nexport function ensureExperienceThumbnailStyles(css: string): void {\n\tif (typeof document === 'undefined' || styleMounted) return;\n\tif (document.querySelector('style[data-liforma-et]')) {\n\t\tstyleMounted = true;\n\t\treturn;\n\t}\n\tconst style = document.createElement('style');\n\tstyle.setAttribute('data-liforma-et', '');\n\tstyle.textContent = css;\n\tdocument.head.appendChild(style);\n\tstyleMounted = true;\n}\n","'use client';\n\nimport {\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n\ttype CSSProperties,\n\ttype MouseEvent as ReactMouseEvent,\n\ttype PointerEvent as ReactPointerEvent\n} from 'react';\n\nimport {\n\tattachLazyThumb,\n\tattachScrollLinkedParallax,\n\tensureExperienceThumbnailStyles,\n\tEXPERIENCE_THUMBNAIL_CSS,\n\thorizontalParallaxFromViewportY,\n\tresolveThumbnailHref,\n\tresolveThumbnailInteraction,\n\tresolveThumbnailLayers,\n\tthumbnailFitClass,\n\ttype GalleryThumb\n} from '../thumbnail/index';\n\nexport type ExperienceThumbnailProps = {\n\treadonly galleryThumb?: GalleryThumb;\n\treadonly avatarImage?: string;\n\treadonly backgroundImage?: string;\n\treadonly foregroundImage?: string;\n\treadonly alt: string;\n\treadonly experienceId?: string;\n\treadonly href?: string;\n\treadonly target?: string;\n\treadonly rel?: string;\n\treadonly onClick?: (event: ReactMouseEvent<HTMLElement>) => void;\n\treadonly returnUrl?: string;\n\treadonly playerBaseUrl?: string;\n\treadonly parallax?: boolean;\n\treadonly fit?: 'full' | 'face' | 'medium';\n\treadonly lazy?: boolean;\n\treadonly className?: string;\n\treadonly fallbackImage?: string;\n};\n\nfunction mediaClass(base: string, ready: boolean): string {\n\treturn `${base} liforma-et__media${ready ? ' liforma-et__media--ready' : ''}`;\n}\n\nexport function ExperienceThumbnail(props: ExperienceThumbnailProps) {\n\tconst {\n\t\tgalleryThumb,\n\t\tavatarImage,\n\t\tbackgroundImage,\n\t\tforegroundImage,\n\t\talt,\n\t\texperienceId,\n\t\thref,\n\t\ttarget,\n\t\trel,\n\t\tonClick,\n\t\treturnUrl,\n\t\tplayerBaseUrl,\n\t\tparallax = true,\n\t\tfit = 'full',\n\t\tlazy = true,\n\t\tclassName = '',\n\t\tfallbackImage\n\t} = props;\n\n\tconst layers = useMemo(\n\t\t() =>\n\t\t\tresolveThumbnailLayers({\n\t\t\t\tgalleryThumb,\n\t\t\t\tavatarImage,\n\t\t\t\tbackgroundImage,\n\t\t\t\tforegroundImage,\n\t\t\t\tfallbackImage\n\t\t\t}),\n\t\t[galleryThumb, avatarImage, backgroundImage, foregroundImage, fallbackImage]\n\t);\n\n\tconst interaction = resolveThumbnailInteraction({\n\t\thref,\n\t\thasClickHandler: typeof onClick === 'function',\n\t\texperienceId\n\t});\n\tconst isHostedLaunch =\n\t\tinteraction === 'anchor' && !href?.trim() && Boolean(experienceId?.trim());\n\tconst hasScene = Boolean(layers?.backgroundImage);\n\tconst parallaxEnabled = parallax !== false;\n\n\tconst rootRef = useRef<HTMLElement | null>(null);\n\tconst pointerDownRef = useRef(false);\n\tconst [shouldLoad, setShouldLoad] = useState(!lazy);\n\tconst [hovering, setHovering] = useState(false);\n\tconst [scrollParallax, setScrollParallax] = useState(false);\n\tconst [parallaxX, setParallaxX] = useState(0);\n\tconst [parallaxY, setParallaxY] = useState(0);\n\tconst [avatarLoadFailed, setAvatarLoadFailed] = useState(false);\n\tconst [backgroundReady, setBackgroundReady] = useState(false);\n\tconst [avatarReady, setAvatarReady] = useState(false);\n\tconst [foregroundReady, setForegroundReady] = useState(false);\n\tconst [resolvedHref, setResolvedHref] = useState<string | undefined>();\n\n\tconst resolvedAvatarImage = layers\n\t\t? avatarLoadFailed && layers.fallbackImage\n\t\t\t? layers.fallbackImage\n\t\t\t: layers.avatarImage\n\t\t: '';\n\n\tuseEffect(() => {\n\t\tensureExperienceThumbnailStyles(EXPERIENCE_THUMBNAIL_CSS);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tsetResolvedHref(\n\t\t\tresolveThumbnailHref({\n\t\t\t\thref,\n\t\t\t\texperienceId,\n\t\t\t\treturnUrl,\n\t\t\t\tplayerBaseUrl,\n\t\t\t\tuseCurrentPageAsReturnUrl: isHostedLaunch && !returnUrl?.trim()\n\t\t\t})\n\t\t);\n\t}, [href, experienceId, returnUrl, playerBaseUrl, isHostedLaunch]);\n\n\tuseEffect(() => {\n\t\tsetBackgroundReady(false);\n\t\tsetAvatarReady(false);\n\t\tsetForegroundReady(false);\n\t\tsetAvatarLoadFailed(false);\n\t}, [layers?.backgroundImage, layers?.foregroundImage, resolvedAvatarImage]);\n\n\tuseEffect(() => {\n\t\tconst el = rootRef.current;\n\t\tif (!el) return;\n\t\tif (!lazy) {\n\t\t\tsetShouldLoad(true);\n\t\t\treturn;\n\t\t}\n\t\treturn attachLazyThumb(el, {\n\t\t\tonVisibleChange: (visible) => {\n\t\t\t\tif (visible) setShouldLoad(true);\n\t\t\t}\n\t\t});\n\t}, [lazy, layers, interaction, resolvedHref]);\n\n\tuseEffect(() => {\n\t\tconst el = rootRef.current;\n\t\tif (!el || !parallaxEnabled) return;\n\t\treturn attachScrollLinkedParallax(el, {\n\t\t\tonParallax: (x) => {\n\t\t\t\tsetScrollParallax(true);\n\t\t\t\tif (!pointerDownRef.current) {\n\t\t\t\t\tsetParallaxX(x);\n\t\t\t\t\tsetParallaxY(0);\n\t\t\t\t}\n\t\t\t},\n\t\t\tpointerActive: () => pointerDownRef.current\n\t\t});\n\t}, [parallaxEnabled, layers, interaction, resolvedHref]);\n\n\tconst onPointerMove = (event: ReactPointerEvent<HTMLElement>) => {\n\t\tif (!parallaxEnabled || scrollParallax) return;\n\t\tconst rect = event.currentTarget.getBoundingClientRect();\n\t\tif (rect.width <= 0 || rect.height <= 0) return;\n\t\tsetParallaxX(((event.clientX - rect.left) / rect.width - 0.5) * 2);\n\t\tsetParallaxY(((event.clientY - rect.top) / rect.height - 0.5) * 2);\n\t};\n\n\tconst clearPointer = (thumb: HTMLElement) => {\n\t\tconst wasDown = pointerDownRef.current;\n\t\tpointerDownRef.current = false;\n\t\tsetHovering(false);\n\t\tif (scrollParallax && wasDown) {\n\t\t\tsetParallaxX(\n\t\t\t\thorizontalParallaxFromViewportY(thumb.getBoundingClientRect(), window.innerHeight)\n\t\t\t);\n\t\t\tsetParallaxY(0);\n\t\t} else if (!scrollParallax) {\n\t\t\tsetParallaxX(0);\n\t\t\tsetParallaxY(0);\n\t\t}\n\t};\n\n\tconst onPointerDown = (event: ReactPointerEvent<HTMLElement>) => {\n\t\tif (!parallaxEnabled) return;\n\t\tpointerDownRef.current = true;\n\t\tif (event.pointerType === 'mouse') setHovering(true);\n\t\tconst thumb = event.currentTarget;\n\t\tconst onGlobalEnd = () => {\n\t\t\tclearPointer(thumb);\n\t\t\twindow.removeEventListener('pointerup', onGlobalEnd);\n\t\t\twindow.removeEventListener('pointercancel', onGlobalEnd);\n\t\t};\n\t\twindow.addEventListener('pointerup', onGlobalEnd);\n\t\twindow.addEventListener('pointercancel', onGlobalEnd);\n\t};\n\n\tconst handleClick = (event: ReactMouseEvent<HTMLElement>) => {\n\t\tonClick?.(event);\n\t\tif (event.defaultPrevented) return;\n\t\tif (isHostedLaunch && !returnUrl?.trim()) {\n\t\t\tconst next = resolveThumbnailHref({\n\t\t\t\texperienceId,\n\t\t\t\tplayerBaseUrl,\n\t\t\t\tuseCurrentPageAsReturnUrl: true\n\t\t\t});\n\t\t\tif (\n\t\t\t\tnext &&\n\t\t\t\tevent.button === 0 &&\n\t\t\t\t!event.metaKey &&\n\t\t\t\t!event.ctrlKey &&\n\t\t\t\t!event.shiftKey\n\t\t\t) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\twindow.location.assign(next);\n\t\t\t}\n\t\t}\n\t};\n\n\tif (!layers) return null;\n\n\tconst parallaxLayersActive = parallaxEnabled && (hovering || scrollParallax);\n\t/** Fade placeholder as soon as any layer can paint — don't wait for the slowest plate. */\n\tconst revealThumb =\n\t\tshouldLoad && (avatarReady || backgroundReady || foregroundReady);\n\n\tconst rootClass = [\n\t\t'liforma-et',\n\t\thasScene ? 'liforma-et--scene' : '',\n\t\tthumbnailFitClass(fit),\n\t\tparallaxLayersActive ? 'liforma-et--parallax' : '',\n\t\tscrollParallax ? 'liforma-et--scroll-parallax' : '',\n\t\tshouldLoad && !revealThumb ? 'liforma-et--loading' : '',\n\t\trevealThumb ? 'liforma-et--revealed' : '',\n\t\tclassName\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' ');\n\n\tconst style = {\n\t\t['--liforma-et-parallax-x' as string]: parallaxX,\n\t\t['--liforma-et-parallax-y' as string]: parallaxY\n\t} as CSSProperties;\n\n\tconst markReady = (img: HTMLImageElement, setReady: (v: boolean) => void) => {\n\t\tif (img.complete) setReady(true);\n\t};\n\n\tconst media = (\n\t\t<>\n\t\t\t<span className=\"liforma-et__placeholder\" aria-hidden=\"true\" />\n\t\t\t{shouldLoad && layers.backgroundImage ? (\n\t\t\t\t<img\n\t\t\t\t\tclassName={mediaClass('liforma-et__background', backgroundReady)}\n\t\t\t\t\tsrc={layers.backgroundImage}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\tdecoding=\"async\"\n\t\t\t\t\tref={(node) => {\n\t\t\t\t\t\tif (node) markReady(node, setBackgroundReady);\n\t\t\t\t\t}}\n\t\t\t\t\tonLoad={() => setBackgroundReady(true)}\n\t\t\t\t\tonError={() => setBackgroundReady(true)}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t{shouldLoad && resolvedAvatarImage ? (\n\t\t\t\t<img\n\t\t\t\t\tclassName={mediaClass('liforma-et__avatar', avatarReady)}\n\t\t\t\t\tsrc={resolvedAvatarImage}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\tdecoding=\"async\"\n\t\t\t\t\tref={(node) => {\n\t\t\t\t\t\tif (node) markReady(node, setAvatarReady);\n\t\t\t\t\t}}\n\t\t\t\t\tonLoad={() => setAvatarReady(true)}\n\t\t\t\t\tonError={() => {\n\t\t\t\t\t\tif (layers.fallbackImage) setAvatarLoadFailed(true);\n\t\t\t\t\t\telse setAvatarReady(true);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t{shouldLoad && layers.foregroundImage ? (\n\t\t\t\t<img\n\t\t\t\t\tclassName={mediaClass('liforma-et__foreground', foregroundReady)}\n\t\t\t\t\tsrc={layers.foregroundImage}\n\t\t\t\t\talt=\"\"\n\t\t\t\t\tdecoding=\"async\"\n\t\t\t\t\tref={(node) => {\n\t\t\t\t\t\tif (node) markReady(node, setForegroundReady);\n\t\t\t\t\t}}\n\t\t\t\t\tonLoad={() => setForegroundReady(true)}\n\t\t\t\t\tonError={() => setForegroundReady(true)}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t</>\n\t);\n\n\tconst pointerProps = {\n\t\tonPointerDown,\n\t\tonPointerUp: (event: ReactPointerEvent<HTMLElement>) => clearPointer(event.currentTarget),\n\t\tonPointerCancel: (event: ReactPointerEvent<HTMLElement>) =>\n\t\t\tclearPointer(event.currentTarget),\n\t\tonPointerEnter: (event: ReactPointerEvent<HTMLElement>) => {\n\t\t\tif (parallaxEnabled && event.pointerType === 'mouse') setHovering(true);\n\t\t},\n\t\tonPointerMove,\n\t\tonPointerLeave: () => {\n\t\t\tif (!pointerDownRef.current) {\n\t\t\t\tsetHovering(false);\n\t\t\t\tif (!scrollParallax) {\n\t\t\t\t\tsetParallaxX(0);\n\t\t\t\t\tsetParallaxY(0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tconst setRootRef = (node: HTMLElement | null) => {\n\t\trootRef.current = node;\n\t};\n\n\tif (interaction === 'anchor' && resolvedHref) {\n\t\treturn (\n\t\t\t<a\n\t\t\t\tref={setRootRef}\n\t\t\t\tclassName={rootClass}\n\t\t\t\tstyle={style}\n\t\t\t\thref={resolvedHref}\n\t\t\t\ttarget={target}\n\t\t\t\trel={rel}\n\t\t\t\taria-label={alt}\n\t\t\t\tonClick={handleClick}\n\t\t\t\t{...pointerProps}\n\t\t\t>\n\t\t\t\t{media}\n\t\t\t</a>\n\t\t);\n\t}\n\n\tif (interaction === 'button') {\n\t\treturn (\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tref={setRootRef}\n\t\t\t\tclassName={rootClass}\n\t\t\t\tstyle={style}\n\t\t\t\taria-label={alt}\n\t\t\t\tonClick={handleClick}\n\t\t\t\t{...pointerProps}\n\t\t\t>\n\t\t\t\t{media}\n\t\t\t</button>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={setRootRef}\n\t\t\tclassName={rootClass}\n\t\t\tstyle={style}\n\t\t\trole={alt ? 'img' : undefined}\n\t\t\taria-label={alt || undefined}\n\t\t\taria-hidden={alt ? undefined : true}\n\t\t\t{...pointerProps}\n\t\t>\n\t\t\t{media}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;AA2CA,SAAgB,EAAkB,GAA0C;CAG3E,OAFI,MAAQ,SAAe,yBACvB,MAAQ,WAAiB,2BACtB;AACR;;;AC/CA,IAAM,IAAiB,kCACjB,IAAqB,gBACrB,IAAmB;AAOzB,SAAgB,EAAkB,GAAqB;CACtD,IAAM,IAAM,EAAI,KAAK;CACrB,IAAI,CAAC,GAAK,OAAO;CAEjB,IAAI,IAAO,EAAI,QAAQ,IAAiB,GAAQ,GAAgB,GAAc,MACzE,MAAS,QAAc,GAAG,IAAS,IAAO,MACvC,GAAG,EAAO,KAAK,GACtB;CAWD,OAVA,IAAO,EAAK,QAAQ,GAAoB,YAAY,GAEpD,IAAO,EAAK,QACX,IACC,GAAQ,GAAc,GAAc,GAAa,MAC7C,MAAS,YAAkB,GAAG,IAAO,IAAO,IAAM,MAC/C,GAAG,EAAK,SAAS,IAAM,GAEhC,GAEO;AACR;AAEA,SAAgB,GAAuB,GAe9B;CACR,IAAM,IACL,EAAM,aAAa,KAAK,KACxB,EAAM,cAAc,aAAa,KAAK,KACtC;CACD,IAAI,CAAC,GAAc,OAAO;CAE1B,IAAM,IACL,EAAM,iBAAiB,KAAK,KAAK,EAAM,cAAc,iBAAiB,KAAK,KAAK,IAC3E,IACL,EAAM,iBAAiB,KAAK,KAAK,EAAM,cAAc,iBAAiB,KAAK,KAAK,IAC3E,IAAiB,EAAM,eAAe,KAAK,KAAK;CAEtD,OAAO;EACN,aAAa,EAAkB,CAAY;EAC3C,GAAI,IAAmB,EAAE,iBAAiB,EAAkB,CAAgB,EAAE,IAAI,CAAC;EACnF,GAAI,IAAmB,EAAE,iBAAiB,EAAkB,CAAgB,EAAE,IAAI,CAAC;EACnF,GAAI,IAAiB,EAAE,eAAe,EAAkB,CAAc,EAAE,IAAI,CAAC;CAC9E;AACD;;;AC5DA,SAAgB,IAAiC;CAChD,IAAK,WAA4C,oBAAoB,SACpE,OAAO;CAGR,IAAI,OAAO,WAAa,KACvB,OAAO;CAGR,IAAI;EACH,OAAO,IAAI,gBAAgB,SAAS,MAAM,EAAE,IAAI,OAAO,MAAM;CAC9D,QAAQ;EACP,OAAO;CACR;AACD;;;ACfA,IAAM,IAA2B,6BAC3B,IAAsB;AAG5B,SAAgB,GACf,GAC2B;CAI3B,OAHI,EAAM,MAAM,KAAK,IAAU,WAC3B,EAAM,kBAAwB,WAC9B,EAAM,cAAc,KAAK,IAAU,WAChC;AACR;AAEA,SAAgB,EAAqB,GAAgC;CACpE,IAAM,IAAa,GAAe,KAAK;CAOvC,OANI,IAAmB,EAAW,QAAQ,OAAO,EAAE,IAE/C,EAAsB,IAClB,IAGD;AACR;AAMA,SAAgB,GAAqB,GAI1B;CACV,IAAM,IAAe,EAAQ,aAAa,KAAK,GACzC,IAAO,EAAqB,EAAQ,aAAa,GACjD,IAAM,IAAI,IAAI,GAAG,EAAK,GAAG,mBAAmB,CAAY,GAAG,GAC3D,IAAY,EAAQ,WAAW,KAAK;CAI1C,OAHI,KACH,EAAI,aAAa,IAAI,aAAa,CAAS,GAErC,EAAI,SAAS;AACrB;AAGA,SAAgB,GAAqB,GAOd;CACtB,IAAM,IAAO,EAAQ,MAAM,KAAK;CAChC,IAAI,GAAM,OAAO;CAEjB,IAAM,IAAe,EAAQ,cAAc,KAAK;CAChD,IAAI,CAAC,GAAc;CAEnB,IAAI,IAAY,EAAQ,WAAW,KAAK;CAKxC,OAJI,CAAC,KAAa,EAAQ,6BAA6B,OAAO,SAAW,QACxE,IAAY,OAAO,SAAS,OAGtB,GAAqB;EAC3B;EACA,GAAI,IAAY,EAAE,aAAU,IAAI,CAAC;EACjC,eAAe,EAAQ;CACxB,CAAC;AACF;AClEA,SAAgB,IAAgC;CAE/C,OADI,OAAO,SAAW,MAAoB,KACnC,OAAO,WAAW,kCAAkC,EAAE;AAC9D;AAOA,IAAI,IAAW,GACT,IAAwB,CAAC;AAE/B,SAAS,IAAwB;CAChC,OAAO,EAAqB,IAAA,IAAoC;AACjE;AAEA,SAAS,KAAoB;CAC5B,OAAO,EAAqB,IAAA,MAAmC;AAChE;AAEA,SAAS,IAAa;CACrB,IAAM,IAAQ,EAAc;CAC5B,OAAO,IAAW,KAAS,EAAQ,SAAS,IAAG;EAC9C,IAAM,IAAO,EAAQ,MAAM;EAC3B,IAAI,CAAC,KAAQ,EAAK,WAAW;EAE7B,AADA,KAAY,GACZ,EAAK,MAAM;EACX,IAAM,IAAQ,GAAU;EACxB,IAAI,KAAS,GAAG;GACf,IAAW,KAAK,IAAI,GAAG,IAAW,CAAC;GACnC;EACD;EACA,OAAO,iBAAiB;GAEvB,AADA,IAAW,KAAK,IAAI,GAAG,IAAW,CAAC,GACnC,EAAK;EACN,GAAG,CAAK;CACT;AACD;AAOA,SAAgB,EAAkB,GAA+B;CAChE,IAAI,CAAC,EAAqB,GAEzB,OADA,EAAM,SACO,CAAC;CAGf,IAAM,IAAmB;EAAE;EAAO,WAAW;CAAM;CAInD,OAHA,EAAQ,KAAK,CAAI,GACjB,EAAK,SAEQ;EACZ,EAAK,YAAY;CAClB;AACD;;;ACvDA,SAAgB,IAAmC;CAClD,OAAO,EAAqB,IAAI,aAAa;AAC9C;AAEA,SAAS,EAA0B,GAA4B;CAC9D,IAAM,IAAQ,EAAW,KAAK,EAAE,MAAM,KAAK,EAAE,MAAM,OAC7C,IAAQ,OAAO,WAAW,CAAK;CACrC,OAAO,OAAO,SAAS,CAAK,IAAI,KAAK,IAAI,CAAK,IAAI;AACnD;AAEA,SAAS,EAAe,GAAsB,GAA2B;CACxE,IAAI,OAAO,SAAW,KAAa,OAAO;CAC1C,IAAM,IAAO,EAAQ,sBAAsB;CAC3C,OAAO,EAAK,UAAU,CAAC,KAAY,EAAK,OAAO,OAAO,cAAc;AACrE;AAGA,SAAgB,GAAgB,GAAsB,GAAuC;CAC5F,IAAM,EAAE,uBAAoB,GACtB,IAAa,EAAQ,cAAc,EAAyB,GAC5D,IAAW,EAA0B,CAAU,GACjD,IAAU,IACV,IAAc,IACd,IAAuC,MAErC,UAAoB;EACrB,MACJ,IAAkB,GAClB,IAAkB,QAAwB;GAGzC,AAFA,IAAkB,MAClB,IAAc,IACd,EAAgB,EAAI;EACrB,CAAC;CACF,GAEM,KAAc,MAAkB;EACjC,UAAS,GAEb;OADA,IAAU,GACN,GAAM;IACT,EAAY;IACZ;GACD;GAIA,AAFA,IAAkB,GAClB,IAAkB,MAClB,EAAgB,EAAK;EAJrB;CAKD;CAEA,IAAI,OAAO,uBAAyB,KAEnC,OADA,EAAY,SACC;EAEZ,AADA,IAAkB,GAClB,IAAkB;CACnB;CAGD,IAAM,IAAW,IAAI,sBACnB,MAAY;EACZ,EAAW,EAAQ,MAAM,MAAU,EAAM,cAAc,CAAC;CACzD,GACA;EAAE,MAAM;EAAM;EAAY,WAAW;CAAE,CACxC;CAQA,OANA,EAAS,QAAQ,CAAO,GAEpB,EAAe,GAAS,CAAQ,KACnC,EAAW,EAAI,SAGH;EAGZ,AAFA,IAAkB,GAClB,IAAkB,MAClB,EAAS,WAAW;CACrB;AACD;;;ACjFA,SAAgB,IAAuC;CAGtD,OAFI,OAAO,SAAW,OAClB,OAAO,WAAW,kCAAkC,EAAE,UAAgB,KACnE,OAAO,WAAW,kCAAkC,EAAE;AAC9D;AAKA,SAAgB,EAAgC,GAAe,GAAgC;CAG9F,SAFgB,EAAK,MAAM,EAAK,SAAS,KACrB,KAAK,IAAI,GAAgB,CAAC,IAClC,MAAO;AACpB;AAaA,IAAM,oBAAc,IAAI,IAA8B,GAClD,IAAY,IACZ,IAAQ;AAEZ,SAAS,IAAgB;CAExB,IADA,IAAQ,GACJ,EAAY,SAAS,KAAK,OAAO,SAAW,KAAa;CAC7D,IAAM,IAAiB,OAAO;CAC9B,KAAK,IAAM,KAAS,GAAa;EAChC,IAAI,EAAM,gBAAgB,GAAG;EAC7B,IAAM,IAAO,EAAM,QAAQ,sBAAsB;EAE7C,EAAK,SAAS,OAAO,EAAK,MAAM,IAAiB,MACrD,EAAM,WAAW,EAAgC,GAAM,CAAc,CAAC;CACvE;AACD;AAEA,SAAS,IAAqB;CACzB,MAAU,MACd,IAAQ,sBAAsB,CAAO;AACtC;AAEA,SAAS,IAAwB;CAC5B,KAAa,OAAO,SAAW,QACnC,IAAY,IACZ,OAAO,iBAAiB,UAAU,GAAc,EAAE,SAAS,GAAK,CAAC,GACjE,OAAO,iBAAiB,UAAU,GAAc,EAAE,SAAS,GAAK,CAAC;AAClE;AAEA,SAAS,IAA4B;CAChC,EAAY,OAAO,KAAK,CAAC,KAAa,OAAO,SAAW,QAC5D,IAAY,IACR,MAAU,MACb,qBAAqB,CAAK,GAC1B,IAAQ,IAET,OAAO,oBAAoB,UAAU,CAAY,GACjD,OAAO,oBAAoB,UAAU,CAAY;AAClD;AAMA,SAAgB,GACf,GACA,GACa;CACb,IAAI,CAAC,EAA4B,GAAG,aAAa,CAAC;CAElD,IAAM,IAAkC;EACvC;EACA,YAAY,EAAQ;EACpB,eAAe,EAAQ;CACxB;CAUA,OATA,EAAY,IAAI,CAAK,GACrB,EAAgB,GAEX,EAAM,gBAAgB,KAC1B,EAAQ,WACP,EAAgC,EAAQ,sBAAsB,GAAG,OAAO,WAAW,CACpF,SAGY;EAEZ,AADA,EAAY,OAAO,CAAK,GACxB,EAAoB;CACrB;AACD;;;AC9FA,IAAa,KAA2B,4+KCDpC,IAAe;AAGnB,SAAgB,GAAgC,GAAmB;CAClE,IAAI,OAAO,WAAa,OAAe,GAAc;CACrD,IAAI,SAAS,cAAc,wBAAwB,GAAG;EACrD,IAAe;EACf;CACD;CACA,IAAM,IAAQ,SAAS,cAAc,OAAO;CAI5C,AAHA,EAAM,aAAa,mBAAmB,EAAE,GACxC,EAAM,cAAc,GACpB,SAAS,KAAK,YAAY,CAAK,GAC/B,IAAe;AAChB;;;AC+BA,SAAS,EAAW,GAAc,GAAwB;CACzD,OAAO,GAAG,EAAK,oBAAoB,IAAQ,8BAA8B;AAC1E;AAEA,SAAgB,EAAoB,GAAiC;CACpE,IAAM,EACL,iBACA,gBACA,oBACA,oBACA,QACA,iBACA,SACA,YACA,QACA,YACA,cACA,kBACA,eAAW,IACX,SAAM,QACN,UAAO,IACP,eAAY,IACZ,qBACG,GAEE,IAAS,QAEb,GAAuB;EACtB;EACA;EACA;EACA;EACA;CACD,CAAC,GACF;EAAC;EAAc;EAAa;EAAiB;EAAiB;CAAa,CAC5E,GAEM,IAAc,GAA4B;EAC/C;EACA,iBAAiB,OAAO,KAAY;EACpC;CACD,CAAC,GACK,IACL,MAAgB,YAAY,CAAC,GAAM,KAAK,KAAK,EAAQ,GAAc,KAAK,GACnE,IAAW,EAAQ,GAAQ,iBAC3B,IAAkB,OAAa,IAE/B,IAAU,EAA2B,IAAI,GACzC,IAAiB,EAAO,EAAK,GAC7B,CAAC,GAAY,KAAiB,EAAS,CAAC,CAAI,GAC5C,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,CAAC,GAAgB,MAAqB,EAAS,EAAK,GACpD,CAAC,IAAW,KAAgB,EAAS,CAAC,GACtC,CAAC,IAAW,KAAgB,EAAS,CAAC,GACtC,CAAC,IAAkB,KAAuB,EAAS,EAAK,GACxD,CAAC,GAAiB,KAAsB,EAAS,EAAK,GACtD,CAAC,IAAa,KAAkB,EAAS,EAAK,GAC9C,CAAC,IAAiB,KAAsB,EAAS,EAAK,GACtD,CAAC,GAAc,MAAmB,EAA6B,GAE/D,IAAsB,IACzB,MAAoB,EAAO,gBAC1B,EAAO,gBACP,EAAO,cACR;CAuCH,AArCA,QAAgB;EACf,GAAgC,EAAwB;CACzD,GAAG,CAAC,CAAC,GAEL,QAAgB;EACf,GACC,GAAqB;GACpB;GACA;GACA;GACA;GACA,2BAA2B,KAAkB,CAAC,GAAW,KAAK;EAC/D,CAAC,CACF;CACD,GAAG;EAAC;EAAM;EAAc;EAAW;EAAe;CAAc,CAAC,GAEjE,QAAgB;EAIf,AAHA,EAAmB,EAAK,GACxB,EAAe,EAAK,GACpB,EAAmB,EAAK,GACxB,EAAoB,EAAK;CAC1B,GAAG;EAAC,GAAQ;EAAiB,GAAQ;EAAiB;CAAmB,CAAC,GAE1E,QAAgB;EACf,IAAM,IAAK,EAAQ;EACd,OACL;OAAI,CAAC,GAAM;IACV,EAAc,EAAI;IAClB;GACD;GACA,OAAO,GAAgB,GAAI,EAC1B,kBAAkB,MAAY;IAC7B,AAAI,KAAS,EAAc,EAAI;GAChC,EACD,CAAC;EALD;CAMD,GAAG;EAAC;EAAM;EAAQ;EAAa;CAAY,CAAC,GAE5C,QAAgB;EACf,IAAM,IAAK,EAAQ;EACf,OAAC,KAAM,CAAC,IACZ,OAAO,GAA2B,GAAI;GACrC,aAAa,MAAM;IAElB,AADA,GAAkB,EAAI,GACjB,EAAe,YACnB,EAAa,CAAC,GACd,EAAa,CAAC;GAEhB;GACA,qBAAqB,EAAe;EACrC,CAAC;CACF,GAAG;EAAC;EAAiB;EAAQ;EAAa;CAAY,CAAC;CAEvD,IAAM,MAAiB,MAA0C;EAChE,IAAI,CAAC,KAAmB,GAAgB;EACxC,IAAM,IAAO,EAAM,cAAc,sBAAsB;EACnD,EAAK,SAAS,KAAK,EAAK,UAAU,MACtC,IAAe,EAAM,UAAU,EAAK,QAAQ,EAAK,QAAQ,MAAO,CAAC,GACjE,IAAe,EAAM,UAAU,EAAK,OAAO,EAAK,SAAS,MAAO,CAAC;CAClE,GAEM,KAAgB,MAAuB;EAC5C,IAAM,IAAU,EAAe;EAG/B,AAFA,EAAe,UAAU,IACzB,EAAY,EAAK,GACb,KAAkB,KACrB,EACC,EAAgC,EAAM,sBAAsB,GAAG,OAAO,WAAW,CAClF,GACA,EAAa,CAAC,KACH,MACX,EAAa,CAAC,GACd,EAAa,CAAC;CAEhB,GAEM,MAAiB,MAA0C;EAChE,IAAI,CAAC,GAAiB;EAEtB,AADA,EAAe,UAAU,IACrB,EAAM,gBAAgB,WAAS,EAAY,EAAI;EACnD,IAAM,IAAQ,EAAM,eACd,UAAoB;GAGzB,AAFA,EAAa,CAAK,GAClB,OAAO,oBAAoB,aAAa,CAAW,GACnD,OAAO,oBAAoB,iBAAiB,CAAW;EACxD;EAEA,AADA,OAAO,iBAAiB,aAAa,CAAW,GAChD,OAAO,iBAAiB,iBAAiB,CAAW;CACrD,GAEM,MAAe,MAAwC;EAC5D,QAAU,CAAK,GACX,GAAM,oBACN,KAAkB,CAAC,GAAW,KAAK,GAAG;GACzC,IAAM,IAAO,GAAqB;IACjC;IACA;IACA,2BAA2B;GAC5B,CAAC;GACD,AACC,KACA,EAAM,WAAW,KACjB,CAAC,EAAM,WACP,CAAC,EAAM,WACP,CAAC,EAAM,aAEP,EAAM,eAAe,GACrB,OAAO,SAAS,OAAO,CAAI;EAE7B;CACD;CAEA,IAAI,CAAC,GAAQ,OAAO;CAEpB,IAAM,KAAuB,MAAoB,KAAY,IAEvD,KACL,MAAe,MAAe,KAAmB,KAE5C,IAAY;EACjB;EACA,IAAW,sBAAsB;EACjC,EAAkB,CAAG;EACrB,KAAuB,yBAAyB;EAChD,IAAiB,gCAAgC;EACjD,KAAc,CAAC,KAAc,wBAAwB;EACrD,KAAc,yBAAyB;EACvC;CACD,EACE,OAAO,OAAO,EACd,KAAK,GAAG,GAEJ,IAAQ;EACZ,2BAAsC;EACtC,2BAAsC;CACxC,GAEM,KAAa,GAAuB,MAAmC;EAC5E,AAAI,EAAI,YAAU,EAAS,EAAI;CAChC,GAEM,IACL,kBAAA,GAAA,EAAA,UAAA;EACC,kBAAC,QAAD;GAAM,WAAU;GAA0B,eAAY;EAAQ,CAAA;EAC7D,KAAc,EAAO,kBACrB,kBAAC,OAAD;GACC,WAAW,EAAW,0BAA0B,CAAe;GAC/D,KAAK,EAAO;GACZ,KAAI;GACJ,UAAS;GACT,MAAM,MAAS;IACd,AAAI,KAAM,EAAU,GAAM,CAAkB;GAC7C;GACA,cAAc,EAAmB,EAAI;GACrC,eAAe,EAAmB,EAAI;EACtC,CAAA,IACE;EACH,KAAc,IACd,kBAAC,OAAD;GACC,WAAW,EAAW,sBAAsB,EAAW;GACvD,KAAK;GACL,KAAI;GACJ,UAAS;GACT,MAAM,MAAS;IACd,AAAI,KAAM,EAAU,GAAM,CAAc;GACzC;GACA,cAAc,EAAe,EAAI;GACjC,eAAe;IACd,AAAI,EAAO,gBAAe,EAAoB,EAAI,IAC7C,EAAe,EAAI;GACzB;EACA,CAAA,IACE;EACH,KAAc,EAAO,kBACrB,kBAAC,OAAD;GACC,WAAW,EAAW,0BAA0B,EAAe;GAC/D,KAAK,EAAO;GACZ,KAAI;GACJ,UAAS;GACT,MAAM,MAAS;IACd,AAAI,KAAM,EAAU,GAAM,CAAkB;GAC7C;GACA,cAAc,EAAmB,EAAI;GACrC,eAAe,EAAmB,EAAI;EACtC,CAAA,IACE;CACH,EAAA,CAAA,GAGG,IAAe;EACpB;EACA,cAAc,MAA0C,EAAa,EAAM,aAAa;EACxF,kBAAkB,MACjB,EAAa,EAAM,aAAa;EACjC,iBAAiB,MAA0C;GAC1D,AAAI,KAAmB,EAAM,gBAAgB,WAAS,EAAY,EAAI;EACvE;EACA;EACA,sBAAsB;GACrB,AAAK,EAAe,YACnB,EAAY,EAAK,GACZ,MACJ,EAAa,CAAC,GACd,EAAa,CAAC;EAGjB;CACD,GAEM,KAAc,MAA6B;EAChD,EAAQ,UAAU;CACnB;CAoCA,OAlCI,MAAgB,YAAY,IAE9B,kBAAC,KAAD;EACC,KAAK;EACL,WAAW;EACJ;EACP,MAAM;EACE;EACH;EACL,cAAY;EACZ,SAAS;EACT,GAAI;YAEH;CACC,CAAA,IAID,MAAgB,WAElB,kBAAC,UAAD;EACC,MAAK;EACL,KAAK;EACL,WAAW;EACJ;EACP,cAAY;EACZ,SAAS;EACT,GAAI;YAEH;CACM,CAAA,IAKT,kBAAC,OAAD;EACC,KAAK;EACL,WAAW;EACJ;EACP,MAAM,IAAM,QAAQ,KAAA;EACpB,cAAY,KAAO,KAAA;EACnB,eAAa,IAAM,KAAA,IAAY;EAC/B,GAAI;YAEH;CACG,CAAA;AAEP"}
|
|
@@ -2,7 +2,7 @@ import type { CloseEvent, EmbedState } from './protocol';
|
|
|
2
2
|
import { type WidgetChromeMode, type WidgetDragMoveEvent, type WidgetDragStartEvent } from './protocol';
|
|
3
3
|
import type { CharacterSpeechEvent, ConversationMessage, SpeakBehavior, SpeechResult as LegacySpeakResult, UserSpeechBoundaryEvent, UserTranscriptUpdate, UtteranceResult } from '../types/sessionInteraction';
|
|
4
4
|
import type { PlayerStatus, Session, SessionActivity } from '../types/sessionLaunch';
|
|
5
|
-
import type { StartButtonOptions } from '../types/sessionInteraction';
|
|
5
|
+
import type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';
|
|
6
6
|
import type { CompleteSpeechQueuePolicy, SpeechAudioFormat, SpeechInterruptOptions, SpeechPlayEmbedSource, SpeechResult, StreamingSpeechQueuePolicy } from '../speech/types';
|
|
7
7
|
export type IframeHostEventMap = {
|
|
8
8
|
close: CloseEvent;
|
|
@@ -84,6 +84,7 @@ export type IframeHost = {
|
|
|
84
84
|
postParentHello(): void;
|
|
85
85
|
postLaunch(launch: string, session?: Session | object, chrome?: {
|
|
86
86
|
readonly startButton?: StartButtonOptions;
|
|
87
|
+
readonly theme?: PlayerTheme;
|
|
87
88
|
readonly showFeedback?: boolean;
|
|
88
89
|
}): void;
|
|
89
90
|
/** @deprecated Prefer {@link IframeHost.postLaunch}. */
|
|
@@ -144,6 +145,7 @@ export type IframeHost = {
|
|
|
144
145
|
focusCharacter(characterId: string): Promise<void>;
|
|
145
146
|
setFit(fit: 'full' | 'face' | 'medium'): Promise<void>;
|
|
146
147
|
conversion(key: string): Promise<void>;
|
|
148
|
+
engage(): Promise<void>;
|
|
147
149
|
destroy(): void;
|
|
148
150
|
};
|
|
149
151
|
export declare function createIframeHost(options: IframeHostOptions): IframeHost;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iframeHost.d.ts","sourceRoot":"","sources":["../../../../src/v2/embed/iframeHost.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAA6C,UAAU,EAAE,MAAM,YAAY,CAAC;AACpG,OAAO,EAQN,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EACX,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,YAAY,IAAI,iBAAiB,EACjC,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"iframeHost.d.ts","sourceRoot":"","sources":["../../../../src/v2/embed/iframeHost.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CharacterSpeechEvent, ConversationMessage, SpeakBehavior, SessionModeChange, UserSpeechBoundaryEvent, UserTranscriptUpdate } from '../types/sessionInteraction';
|
|
2
2
|
import type { Session, SessionActivity } from '../types/sessionLaunch';
|
|
3
|
-
import type { StartButtonOptions } from '../types/sessionInteraction';
|
|
3
|
+
import type { StartButtonOptions, PlayerTheme } from '../types/sessionInteraction';
|
|
4
4
|
import type { CompleteSpeechQueuePolicy, SpeechAudioFormat, SpeechInterruptOptions, SpeechPlayEmbedSource, StreamingSpeechQueuePolicy } from '../speech/types';
|
|
5
5
|
export declare const EMBED_MESSAGE_SCHEMA_VERSION: 2;
|
|
6
6
|
/** Outbound postMessage versions accepted from the player embed. */
|
|
@@ -187,6 +187,8 @@ export type EmbedInboundMessage = {
|
|
|
187
187
|
readonly session?: Session | object;
|
|
188
188
|
/** Player chrome from attach — not part of the signed launch string. */
|
|
189
189
|
readonly startButton?: StartButtonOptions;
|
|
190
|
+
/** Global player chrome theme from attach. */
|
|
191
|
+
readonly theme?: PlayerTheme;
|
|
190
192
|
/**
|
|
191
193
|
* When false, player skips Feedback step-through UI (host renders scores).
|
|
192
194
|
* Default when omitted: true (player shows Feedback).
|
|
@@ -351,12 +353,19 @@ export type EmbedInboundMessage = {
|
|
|
351
353
|
readonly correlationId: string;
|
|
352
354
|
readonly key: string;
|
|
353
355
|
};
|
|
356
|
+
} | {
|
|
357
|
+
readonly type: 'engage';
|
|
358
|
+
readonly schemaVersion: typeof EMBED_MESSAGE_SCHEMA_VERSION;
|
|
359
|
+
readonly payload: {
|
|
360
|
+
readonly correlationId: string;
|
|
361
|
+
};
|
|
354
362
|
};
|
|
355
363
|
export type EmbedState = 'loading' | 'scene' | 'ready' | 'error';
|
|
356
364
|
export declare function parseOutboundMessage(data: unknown): EmbedOutboundMessage | null;
|
|
357
365
|
export declare function parseInboundMessage(data: unknown): EmbedInboundMessage | null;
|
|
358
366
|
export declare function createLaunchMessage(launch: string, session?: Session | object, chrome?: {
|
|
359
367
|
readonly startButton?: StartButtonOptions;
|
|
368
|
+
readonly theme?: PlayerTheme;
|
|
360
369
|
readonly showFeedback?: boolean;
|
|
361
370
|
}): EmbedInboundMessage;
|
|
362
371
|
/** @deprecated Prefer {@link createLaunchMessage}. */
|