@syntrologie/adapt-product 2.34.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn.js +2 -2
- package/dist/{chunk-FAKCB3BS.js → chunk-AAV4C3P4.js} +67 -30
- package/dist/chunk-AAV4C3P4.js.map +7 -0
- package/dist/{chunk-NH3CFDTZ.js → chunk-HV6QS4PQ.js} +1115 -483
- package/dist/chunk-HV6QS4PQ.js.map +7 -0
- package/dist/native/nativeSlotWatcher.d.ts.map +1 -1
- package/dist/runtime.d.ts +12 -10
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +6 -2
- package/dist/schema-primitives.d.ts +4 -4
- package/dist/schema.d.ts +143 -58
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +9 -1
- package/dist/takeover/engine.d.ts +45 -0
- package/dist/takeover/engine.d.ts.map +1 -0
- package/dist/takeover/fetchPlan.d.ts +61 -0
- package/dist/takeover/fetchPlan.d.ts.map +1 -0
- package/dist/takeover/ports.d.ts +29 -0
- package/dist/takeover/ports.d.ts.map +1 -0
- package/dist/takeover/regionCurtain.d.ts +17 -0
- package/dist/takeover/regionCurtain.d.ts.map +1 -0
- package/dist/takeover/renderModules.d.ts +48 -0
- package/dist/takeover/renderModules.d.ts.map +1 -0
- package/dist/takeover/resurrectionGuard.d.ts +28 -0
- package/dist/takeover/resurrectionGuard.d.ts.map +1 -0
- package/dist/takeover/schema.d.ts +163 -0
- package/dist/takeover/schema.d.ts.map +1 -0
- package/dist/takeover/sectionDetach.d.ts +13 -0
- package/dist/takeover/sectionDetach.d.ts.map +1 -0
- package/dist/widgets/SyntroPdpLit.d.ts +69 -0
- package/dist/widgets/SyntroPdpLit.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-FAKCB3BS.js.map +0 -7
- package/dist/chunk-NH3CFDTZ.js.map +0 -7
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
getProductPlatformAdapter,
|
|
10
10
|
gridSchema,
|
|
11
11
|
heroSchema,
|
|
12
|
-
recoSchema
|
|
13
|
-
|
|
12
|
+
recoSchema,
|
|
13
|
+
takeoverPlanSchema
|
|
14
|
+
} from "./chunk-AAV4C3P4.js";
|
|
14
15
|
|
|
15
16
|
// ../../../node_modules/@lit/context/lib/create-context.js
|
|
16
17
|
function n(n2) {
|
|
@@ -279,7 +280,7 @@ function selectPresetData(kind, data, decision) {
|
|
|
279
280
|
}
|
|
280
281
|
|
|
281
282
|
// src/widgets/SyntroPdpLit.ts
|
|
282
|
-
import { html as
|
|
283
|
+
import { html as html6, LitElement as LitElement6, render } from "lit";
|
|
283
284
|
|
|
284
285
|
// src/decision/pdp.ts
|
|
285
286
|
function createInitialPdpState(generation = 0) {
|
|
@@ -734,6 +735,319 @@ async function resolveScoredTemplate(opts) {
|
|
|
734
735
|
return { value, decisionValue, setSlots, unsetSlots };
|
|
735
736
|
}
|
|
736
737
|
|
|
738
|
+
// src/takeover/resurrectionGuard.ts
|
|
739
|
+
function startResurrectionGuard(opts) {
|
|
740
|
+
const maxRetries = opts.maxRetries ?? 3;
|
|
741
|
+
const debounceMs = opts.debounceMs ?? 50;
|
|
742
|
+
const watched = new Map(opts.anchors);
|
|
743
|
+
const counts = /* @__PURE__ */ new Map();
|
|
744
|
+
let timer = null;
|
|
745
|
+
let stopped = false;
|
|
746
|
+
const sweep = () => {
|
|
747
|
+
if (stopped) return;
|
|
748
|
+
const present = [];
|
|
749
|
+
for (const [sectionId, selector] of watched) {
|
|
750
|
+
let matches = [];
|
|
751
|
+
try {
|
|
752
|
+
matches = Array.from(opts.region.querySelectorAll(selector));
|
|
753
|
+
} catch {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
const el = matches.find((m) => !(opts.ignore?.(m) ?? false));
|
|
757
|
+
if (!el) continue;
|
|
758
|
+
present.push({ sectionId, el, n: (counts.get(sectionId) ?? 0) + 1 });
|
|
759
|
+
}
|
|
760
|
+
const exhausted = present.find((p) => p.n > maxRetries);
|
|
761
|
+
if (exhausted) {
|
|
762
|
+
for (const p of present) p.el.remove();
|
|
763
|
+
opts.onBudgetExhausted(exhausted.sectionId, exhausted.el);
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
for (const { sectionId, el, n: n2 } of present) {
|
|
767
|
+
counts.set(sectionId, n2);
|
|
768
|
+
opts.onResurrected(sectionId, el);
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
const observer2 = new MutationObserver(() => {
|
|
772
|
+
if (timer) clearTimeout(timer);
|
|
773
|
+
timer = setTimeout(sweep, debounceMs);
|
|
774
|
+
});
|
|
775
|
+
observer2.observe(opts.region, { childList: true, subtree: true });
|
|
776
|
+
return {
|
|
777
|
+
stop() {
|
|
778
|
+
stopped = true;
|
|
779
|
+
if (timer) clearTimeout(timer);
|
|
780
|
+
observer2.disconnect();
|
|
781
|
+
},
|
|
782
|
+
unwatch(sectionId) {
|
|
783
|
+
watched.delete(sectionId);
|
|
784
|
+
counts.delete(sectionId);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// src/takeover/sectionDetach.ts
|
|
790
|
+
var activeDetaches = /* @__PURE__ */ new WeakSet();
|
|
791
|
+
function detachSection(section) {
|
|
792
|
+
if (activeDetaches.has(section)) return null;
|
|
793
|
+
if (!section.parentNode) return null;
|
|
794
|
+
activeDetaches.add(section);
|
|
795
|
+
const anchor = document.createComment("syntro-takeover-section");
|
|
796
|
+
section.before(anchor);
|
|
797
|
+
section.remove();
|
|
798
|
+
let restored = false;
|
|
799
|
+
return {
|
|
800
|
+
section,
|
|
801
|
+
get restored() {
|
|
802
|
+
return restored;
|
|
803
|
+
},
|
|
804
|
+
restore() {
|
|
805
|
+
if (restored) return;
|
|
806
|
+
restored = true;
|
|
807
|
+
if (anchor.parentNode) anchor.after(section);
|
|
808
|
+
anchor.remove();
|
|
809
|
+
activeDetaches.delete(section);
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// src/takeover/engine.ts
|
|
815
|
+
var DEFAULT_COMMIT_TIMEOUT_MS = 500;
|
|
816
|
+
var NOOP_DISPOSE = () => {
|
|
817
|
+
};
|
|
818
|
+
async function runTakeover(config, ports, opts = {}) {
|
|
819
|
+
if (!ports.hasSignals()) {
|
|
820
|
+
void Promise.resolve().then(() => ports.fetchPlan()).then(
|
|
821
|
+
(response2) => ports.renderModules(
|
|
822
|
+
{
|
|
823
|
+
// Host-derived entries (kind:sectionId) are ALSO dropped here:
|
|
824
|
+
// their source sections stay attached on this path, and rendering
|
|
825
|
+
// our re-presentation next to the attached original duplicates
|
|
826
|
+
// host content — the exact class the spec forbids (review F2).
|
|
827
|
+
order: response2.plan.order.filter((entry) => !entry.includes(":")),
|
|
828
|
+
suppress: []
|
|
829
|
+
},
|
|
830
|
+
() => {
|
|
831
|
+
}
|
|
832
|
+
)
|
|
833
|
+
).catch(() => ports.telemetry("takeover.render_failed", { path: "progressive" }));
|
|
834
|
+
return { outcome: "progressive", dispose: NOOP_DISPOSE };
|
|
835
|
+
}
|
|
836
|
+
const commitTimeoutMs = opts.commitTimeoutMs ?? DEFAULT_COMMIT_TIMEOUT_MS;
|
|
837
|
+
const region = ports.region();
|
|
838
|
+
const lift = ports.curtain();
|
|
839
|
+
let timeoutId;
|
|
840
|
+
const timedOut = /* @__PURE__ */ Symbol("timeout");
|
|
841
|
+
const fetchFailed = /* @__PURE__ */ Symbol("fetch-failed");
|
|
842
|
+
const response = await Promise.race([
|
|
843
|
+
ports.fetchPlan().catch(() => fetchFailed),
|
|
844
|
+
new Promise((r) => {
|
|
845
|
+
timeoutId = setTimeout(() => r(timedOut), commitTimeoutMs);
|
|
846
|
+
})
|
|
847
|
+
]).finally(() => clearTimeout(timeoutId));
|
|
848
|
+
if (response === timedOut || response === fetchFailed) {
|
|
849
|
+
ports.deactivateRoot();
|
|
850
|
+
lift();
|
|
851
|
+
if (response === timedOut) {
|
|
852
|
+
ports.telemetry("takeover.precommit_timeout", { budgetMs: commitTimeoutMs });
|
|
853
|
+
} else {
|
|
854
|
+
ports.telemetry("takeover.plan_fetch_failed", { budgetMs: commitTimeoutMs });
|
|
855
|
+
}
|
|
856
|
+
return { outcome: "aborted-precommit", dispose: NOOP_DISPOSE };
|
|
857
|
+
}
|
|
858
|
+
const plan = response.plan;
|
|
859
|
+
const sectionsById = new Map(config.hostSections.map((s4) => [s4.id, s4]));
|
|
860
|
+
const toSuppress = [];
|
|
861
|
+
let reservedPx = 0;
|
|
862
|
+
for (const id of plan.suppress) {
|
|
863
|
+
const section = sectionsById.get(id);
|
|
864
|
+
if (!section) {
|
|
865
|
+
ports.telemetry("takeover.suppress_undeclared", { sectionId: id });
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
let el = null;
|
|
869
|
+
try {
|
|
870
|
+
el = ports.findSection(section.anchor);
|
|
871
|
+
} catch {
|
|
872
|
+
}
|
|
873
|
+
if (!el) {
|
|
874
|
+
ports.telemetry("takeover.section_anchor_missing", { sectionId: id });
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
reservedPx += ports.measureSection(el);
|
|
878
|
+
toSuppress.push({ id, el });
|
|
879
|
+
}
|
|
880
|
+
ports.reserve(reservedPx);
|
|
881
|
+
const handles = /* @__PURE__ */ new Map();
|
|
882
|
+
for (const { id, el } of toSuppress) {
|
|
883
|
+
const handle = detachSection(el);
|
|
884
|
+
if (handle) handles.set(id, handle);
|
|
885
|
+
}
|
|
886
|
+
let disposed = false;
|
|
887
|
+
let guard;
|
|
888
|
+
const dispose = () => {
|
|
889
|
+
if (disposed) return;
|
|
890
|
+
disposed = true;
|
|
891
|
+
guard?.stop();
|
|
892
|
+
for (const handle of handles.values()) handle.restore();
|
|
893
|
+
handles.clear();
|
|
894
|
+
ports.deactivateRoot();
|
|
895
|
+
lift();
|
|
896
|
+
};
|
|
897
|
+
guard = startResurrectionGuard({
|
|
898
|
+
region,
|
|
899
|
+
ignore: (el) => ports.ownsNode(el),
|
|
900
|
+
anchors: new Map(toSuppress.map(({ id }) => [id, sectionsById.get(id).anchor])),
|
|
901
|
+
onResurrected: (sectionId, el) => {
|
|
902
|
+
ports.telemetry("takeover.section_resurrected", { sectionId });
|
|
903
|
+
el.remove();
|
|
904
|
+
},
|
|
905
|
+
onBudgetExhausted: (sectionId, el) => {
|
|
906
|
+
ports.telemetry("takeover.resurrection_budget_exhausted", { sectionId });
|
|
907
|
+
el.remove();
|
|
908
|
+
dispose();
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
const onModuleFailed = (suppressedSectionId) => {
|
|
912
|
+
if (!suppressedSectionId) return;
|
|
913
|
+
const handle = handles.get(suppressedSectionId);
|
|
914
|
+
if (!handle) return;
|
|
915
|
+
guard?.unwatch(suppressedSectionId);
|
|
916
|
+
handle.restore();
|
|
917
|
+
handles.delete(suppressedSectionId);
|
|
918
|
+
ports.telemetry("takeover.module_failed_section_restored", {
|
|
919
|
+
sectionId: suppressedSectionId
|
|
920
|
+
});
|
|
921
|
+
};
|
|
922
|
+
void Promise.resolve().then(() => ports.renderModules(plan, onModuleFailed)).catch(() => {
|
|
923
|
+
ports.telemetry("takeover.render_failed", { path: "committed" });
|
|
924
|
+
dispose();
|
|
925
|
+
}).finally(() => ports.releaseReservation());
|
|
926
|
+
lift();
|
|
927
|
+
return { outcome: "committed", dispose };
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// src/takeover/fetchPlan.ts
|
|
931
|
+
import { z as z2 } from "zod";
|
|
932
|
+
var takeoverPlanResponseSchema = z2.object({
|
|
933
|
+
decisionArchetype: z2.string().min(1),
|
|
934
|
+
plan: takeoverPlanSchema
|
|
935
|
+
}).strict();
|
|
936
|
+
function createTakeoverPlanFetcher(deps) {
|
|
937
|
+
return async () => {
|
|
938
|
+
const resp = await deps.authedFetch("/api/pdp/plan", {
|
|
939
|
+
method: "POST",
|
|
940
|
+
// FROZEN SEAM SHAPE — field set AND order are pinned byte-for-byte by
|
|
941
|
+
// `src/__fixtures__/takeover-plan-request.json`; the runtime-backend PR
|
|
942
|
+
// commits the same fixture. Change both sides together or not at all.
|
|
943
|
+
// Deliberately NO client-scored archetype/decision slugs: the server
|
|
944
|
+
// scores (spec rev 3) — the client sends vocabulary + signals only.
|
|
945
|
+
body: JSON.stringify({
|
|
946
|
+
product_id: deps.productId,
|
|
947
|
+
product_name: deps.productName,
|
|
948
|
+
// Page anatomy: ids + roles only. Anchors are host DOM selectors —
|
|
949
|
+
// client-side facts the server has no business receiving.
|
|
950
|
+
host_sections: deps.config.hostSections.map(({ id, role }) => ({ id, role })),
|
|
951
|
+
decision_archetypes: deps.decisionArchetypes,
|
|
952
|
+
behavior_summary: deps.behaviorSummary,
|
|
953
|
+
signals: deps.signals,
|
|
954
|
+
ingest_snapshot: deps.config.ingestSnapshot
|
|
955
|
+
})
|
|
956
|
+
});
|
|
957
|
+
if (!resp.ok) {
|
|
958
|
+
throw new Error(`takeover plan fetch failed: HTTP ${resp.status}`);
|
|
959
|
+
}
|
|
960
|
+
const data = await resp.json();
|
|
961
|
+
return takeoverPlanResponseSchema.parse(data);
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// src/takeover/regionCurtain.ts
|
|
966
|
+
var CLASS = "syntro-takeover-curtain";
|
|
967
|
+
var STYLE_ATTR = "data-syntro-takeover-curtain";
|
|
968
|
+
var styleRefs = 0;
|
|
969
|
+
function acquireStyle() {
|
|
970
|
+
styleRefs += 1;
|
|
971
|
+
if (document.head.querySelector(`style[${STYLE_ATTR}]`)) return;
|
|
972
|
+
const styleEl = document.createElement("style");
|
|
973
|
+
styleEl.setAttribute(STYLE_ATTR, "");
|
|
974
|
+
styleEl.textContent = `.${CLASS} { opacity: 0 !important; }`;
|
|
975
|
+
document.head.appendChild(styleEl);
|
|
976
|
+
}
|
|
977
|
+
function releaseStyle() {
|
|
978
|
+
styleRefs = Math.max(0, styleRefs - 1);
|
|
979
|
+
if (styleRefs === 0) {
|
|
980
|
+
document.head.querySelector(`style[${STYLE_ATTR}]`)?.remove();
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function applyRegionCurtain(region, opts = {}) {
|
|
984
|
+
const timeoutMs = opts.timeoutMs ?? 3e3;
|
|
985
|
+
acquireStyle();
|
|
986
|
+
region.classList.add(CLASS);
|
|
987
|
+
let lifted = false;
|
|
988
|
+
const lift = () => {
|
|
989
|
+
if (lifted) return;
|
|
990
|
+
lifted = true;
|
|
991
|
+
clearTimeout(timeoutId);
|
|
992
|
+
region.classList.remove(CLASS);
|
|
993
|
+
releaseStyle();
|
|
994
|
+
};
|
|
995
|
+
const timeoutId = setTimeout(lift, timeoutMs);
|
|
996
|
+
return lift;
|
|
997
|
+
}
|
|
998
|
+
function applyCurtainToTargets(targets, opts = {}) {
|
|
999
|
+
const lifts = targets.map((t2) => applyRegionCurtain(t2, opts));
|
|
1000
|
+
return () => {
|
|
1001
|
+
for (const lift of lifts) lift();
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/takeover/ports.ts
|
|
1006
|
+
function createDomPorts(config, deps) {
|
|
1007
|
+
return {
|
|
1008
|
+
hasSignals: () => deps.signalCount > 0,
|
|
1009
|
+
findSection(anchor) {
|
|
1010
|
+
try {
|
|
1011
|
+
return document.querySelector(anchor);
|
|
1012
|
+
} catch {
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
measureSection: (el) => el.getBoundingClientRect().height,
|
|
1017
|
+
reserve(minHeightPx) {
|
|
1018
|
+
if (minHeightPx > 0) deps.root.style.minHeight = `${Math.round(minHeightPx)}px`;
|
|
1019
|
+
},
|
|
1020
|
+
releaseReservation() {
|
|
1021
|
+
deps.root.style.removeProperty("min-height");
|
|
1022
|
+
},
|
|
1023
|
+
region: () => deps.root.parentElement ?? deps.root,
|
|
1024
|
+
ownsNode: (el) => deps.root.contains(el),
|
|
1025
|
+
curtain() {
|
|
1026
|
+
const targets = [deps.root];
|
|
1027
|
+
for (const section of config.hostSections) {
|
|
1028
|
+
try {
|
|
1029
|
+
const el = document.querySelector(section.anchor);
|
|
1030
|
+
if (el) targets.push(el);
|
|
1031
|
+
} catch {
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return applyCurtainToTargets(targets);
|
|
1035
|
+
},
|
|
1036
|
+
deactivateRoot() {
|
|
1037
|
+
deps.root.replaceChildren();
|
|
1038
|
+
deps.root.style.display = "none";
|
|
1039
|
+
},
|
|
1040
|
+
fetchPlan: deps.fetchPlan,
|
|
1041
|
+
renderModules: deps.renderModules,
|
|
1042
|
+
telemetry: deps.telemetry
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
function attachLifecycleDispose(result) {
|
|
1046
|
+
const onHide = () => result.dispose();
|
|
1047
|
+
window.addEventListener("pagehide", onHide, { once: true });
|
|
1048
|
+
return () => window.removeEventListener("pagehide", onHide);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
737
1051
|
// src/widgets/PdpSectionHeaderLit.ts
|
|
738
1052
|
import { html, LitElement, nothing } from "lit";
|
|
739
1053
|
function ensureSectionHeaderStyles() {
|
|
@@ -898,11 +1212,298 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-sec
|
|
|
898
1212
|
customElements.define("syntro-pdp-section-header", PdpSectionHeaderLit);
|
|
899
1213
|
}
|
|
900
1214
|
|
|
1215
|
+
// src/widgets/PdpSlotLit.ts
|
|
1216
|
+
import { html as html2, LitElement as LitElement2, nothing as nothing2 } from "lit";
|
|
1217
|
+
function ensureSlotStyles() {
|
|
1218
|
+
if (typeof document === "undefined") return;
|
|
1219
|
+
if (document.getElementById("syntro-pdp-slot-style")) return;
|
|
1220
|
+
const s4 = document.createElement("style");
|
|
1221
|
+
s4.id = "syntro-pdp-slot-style";
|
|
1222
|
+
s4.textContent = SLOT_CSS;
|
|
1223
|
+
document.head.appendChild(s4);
|
|
1224
|
+
}
|
|
1225
|
+
var SLOT_CSS = `
|
|
1226
|
+
.syntro-pdp-slot {
|
|
1227
|
+
--sl-primary: var(--syntro-pdp-primary, hsl(150 32% 38%));
|
|
1228
|
+
--sl-fg: var(--syntro-pdp-fg, hsl(35 15% 92%));
|
|
1229
|
+
--sl-muted: var(--syntro-pdp-muted, hsl(30 8% 55%));
|
|
1230
|
+
--sl-border: var(--syntro-pdp-border, hsl(30 6% 18%));
|
|
1231
|
+
--sl-bg-a: var(--syntro-pdp-card-bg, hsl(25 10% 11%));
|
|
1232
|
+
--sl-bg-b: var(--syntro-pdp-card-bg-b, hsl(25 10% 9%));
|
|
1233
|
+
--sl-display: var(--syntro-pdp-display, inherit);
|
|
1234
|
+
|
|
1235
|
+
position: relative;
|
|
1236
|
+
display: grid;
|
|
1237
|
+
grid-template-areas: 'stack';
|
|
1238
|
+
font-family: var(--syntro-pdp-sans, inherit);
|
|
1239
|
+
}
|
|
1240
|
+
.syntro-pdp-slot > .syntro-pdp-slot-mount,
|
|
1241
|
+
.syntro-pdp-slot > .syntro-pdp-slot-pending,
|
|
1242
|
+
.syntro-pdp-slot > .syntro-pdp-slot-failed {
|
|
1243
|
+
grid-area: stack;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.syntro-pdp-slot-mount {
|
|
1247
|
+
min-height: 220px;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/* When mutation arrived, hide the pending layer */
|
|
1251
|
+
.syntro-pdp-slot[data-state='mounted'] .syntro-pdp-slot-pending,
|
|
1252
|
+
.syntro-pdp-slot[data-state='failed'] .syntro-pdp-slot-pending {
|
|
1253
|
+
display: none;
|
|
1254
|
+
}
|
|
1255
|
+
.syntro-pdp-slot[data-state='mounted'] .syntro-pdp-slot-failed,
|
|
1256
|
+
.syntro-pdp-slot[data-state='pending'] .syntro-pdp-slot-failed {
|
|
1257
|
+
display: none;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/* Pending \u2014 a quietly-animated waiting state. */
|
|
1261
|
+
.syntro-pdp-slot-pending {
|
|
1262
|
+
position: relative;
|
|
1263
|
+
border: 1px dashed var(--sl-border);
|
|
1264
|
+
border-radius: 22px;
|
|
1265
|
+
min-height: 220px;
|
|
1266
|
+
padding: 36px 28px;
|
|
1267
|
+
background: linear-gradient(180deg, var(--sl-bg-a), var(--sl-bg-b));
|
|
1268
|
+
overflow: hidden;
|
|
1269
|
+
display: flex;
|
|
1270
|
+
align-items: center;
|
|
1271
|
+
justify-content: flex-start;
|
|
1272
|
+
}
|
|
1273
|
+
.syntro-pdp-slot-pending-shimmer {
|
|
1274
|
+
position: absolute;
|
|
1275
|
+
inset: 0;
|
|
1276
|
+
background: linear-gradient(
|
|
1277
|
+
90deg,
|
|
1278
|
+
transparent,
|
|
1279
|
+
color-mix(in srgb, var(--sl-primary) 7%, transparent),
|
|
1280
|
+
transparent
|
|
1281
|
+
);
|
|
1282
|
+
transform: translateX(-100%);
|
|
1283
|
+
animation: syntro-pdp-slot-sweep 1800ms ease-in-out infinite;
|
|
1284
|
+
}
|
|
1285
|
+
.syntro-pdp-slot-pending-row {
|
|
1286
|
+
position: relative;
|
|
1287
|
+
z-index: 1;
|
|
1288
|
+
display: flex;
|
|
1289
|
+
align-items: center;
|
|
1290
|
+
gap: 12px;
|
|
1291
|
+
}
|
|
1292
|
+
.syntro-pdp-slot-pending-dot {
|
|
1293
|
+
flex: 0 0 auto;
|
|
1294
|
+
width: 8px;
|
|
1295
|
+
height: 8px;
|
|
1296
|
+
border-radius: 50%;
|
|
1297
|
+
background: var(--sl-primary);
|
|
1298
|
+
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-primary) 14%, transparent);
|
|
1299
|
+
animation: syntro-pdp-slot-pulse 1600ms ease-in-out infinite;
|
|
1300
|
+
}
|
|
1301
|
+
.syntro-pdp-slot-pending-label {
|
|
1302
|
+
font-family: var(--sl-display);
|
|
1303
|
+
font-style: italic;
|
|
1304
|
+
font-size: 18px;
|
|
1305
|
+
font-variation-settings: 'SOFT' 70;
|
|
1306
|
+
color: var(--sl-muted);
|
|
1307
|
+
margin: 0;
|
|
1308
|
+
line-height: 1.4;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/* Failed \u2014 the planner or sub-agent failed; the host page still works. */
|
|
1312
|
+
.syntro-pdp-slot-failed {
|
|
1313
|
+
border: 1px solid var(--sl-border);
|
|
1314
|
+
border-radius: 22px;
|
|
1315
|
+
min-height: 180px;
|
|
1316
|
+
padding: 24px 28px;
|
|
1317
|
+
background: linear-gradient(180deg, var(--sl-bg-a), var(--sl-bg-b));
|
|
1318
|
+
display: flex;
|
|
1319
|
+
flex-direction: column;
|
|
1320
|
+
justify-content: center;
|
|
1321
|
+
gap: 6px;
|
|
1322
|
+
}
|
|
1323
|
+
.syntro-pdp-slot-failed-title {
|
|
1324
|
+
font-family: var(--sl-display);
|
|
1325
|
+
font-style: italic;
|
|
1326
|
+
font-size: 17px;
|
|
1327
|
+
color: var(--sl-fg);
|
|
1328
|
+
margin: 0;
|
|
1329
|
+
font-variation-settings: 'SOFT' 70;
|
|
1330
|
+
}
|
|
1331
|
+
.syntro-pdp-slot-failed-body {
|
|
1332
|
+
color: var(--sl-muted);
|
|
1333
|
+
font-size: 13.5px;
|
|
1334
|
+
margin: 0;
|
|
1335
|
+
line-height: 1.5;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
@media (max-width: 640px) {
|
|
1339
|
+
.syntro-pdp-slot-pending,
|
|
1340
|
+
.syntro-pdp-slot-failed {
|
|
1341
|
+
border-radius: 18px;
|
|
1342
|
+
padding: 24px 18px;
|
|
1343
|
+
min-height: 180px;
|
|
1344
|
+
}
|
|
1345
|
+
.syntro-pdp-slot-pending-label {
|
|
1346
|
+
font-size: 15.5px;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
@keyframes syntro-pdp-slot-sweep {
|
|
1351
|
+
0% { transform: translateX(-100%); }
|
|
1352
|
+
100% { transform: translateX(100%); }
|
|
1353
|
+
}
|
|
1354
|
+
@keyframes syntro-pdp-slot-pulse {
|
|
1355
|
+
0%, 100% {
|
|
1356
|
+
opacity: 0.6;
|
|
1357
|
+
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-primary) 14%, transparent);
|
|
1358
|
+
}
|
|
1359
|
+
50% {
|
|
1360
|
+
opacity: 1;
|
|
1361
|
+
box-shadow: 0 0 0 8px color-mix(in srgb, var(--sl-primary) 26%, transparent);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
`;
|
|
1365
|
+
var PENDING_COPY = {
|
|
1366
|
+
"trending-news": "Composing this section\u2026",
|
|
1367
|
+
chart: "Drawing the comparison\u2026",
|
|
1368
|
+
qa: "Picking the questions worth answering\u2026",
|
|
1369
|
+
regional: "Locating you in time and place\u2026",
|
|
1370
|
+
"peer-feed": "Finding people like you\u2026"
|
|
1371
|
+
};
|
|
1372
|
+
var PENDING_FALLBACK = "Composing\u2026";
|
|
1373
|
+
var PdpSlotLit = class extends LitElement2 {
|
|
1374
|
+
constructor() {
|
|
1375
|
+
super(...arguments);
|
|
1376
|
+
/** DOM id the host's mutation runtime targets when appending the widget. */
|
|
1377
|
+
this.slotId = "";
|
|
1378
|
+
this.kind = "";
|
|
1379
|
+
this.state = "pending";
|
|
1380
|
+
}
|
|
1381
|
+
createRenderRoot() {
|
|
1382
|
+
return this;
|
|
1383
|
+
}
|
|
1384
|
+
connectedCallback() {
|
|
1385
|
+
super.connectedCallback();
|
|
1386
|
+
ensureSlotStyles();
|
|
1387
|
+
}
|
|
1388
|
+
willUpdate() {
|
|
1389
|
+
this.dataset.state = this.state;
|
|
1390
|
+
}
|
|
1391
|
+
render() {
|
|
1392
|
+
const pendingLabel = PENDING_COPY[this.kind] ?? PENDING_FALLBACK;
|
|
1393
|
+
return html2`
|
|
1394
|
+
<div class="syntro-pdp-slot" data-state=${this.state} data-kind=${this.kind}>
|
|
1395
|
+
<div
|
|
1396
|
+
class="syntro-pdp-slot-mount"
|
|
1397
|
+
id=${this.slotId || nothing2}
|
|
1398
|
+
data-pdp-slot=${this.kind}
|
|
1399
|
+
></div>
|
|
1400
|
+
<div class="syntro-pdp-slot-pending" aria-hidden=${this.state !== "pending"}>
|
|
1401
|
+
<div class="syntro-pdp-slot-pending-shimmer" aria-hidden="true"></div>
|
|
1402
|
+
<div class="syntro-pdp-slot-pending-row">
|
|
1403
|
+
<span class="syntro-pdp-slot-pending-dot" aria-hidden="true"></span>
|
|
1404
|
+
<p class="syntro-pdp-slot-pending-label">${pendingLabel}</p>
|
|
1405
|
+
</div>
|
|
1406
|
+
</div>
|
|
1407
|
+
<div class="syntro-pdp-slot-failed" aria-hidden=${this.state !== "failed"}>
|
|
1408
|
+
<p class="syntro-pdp-slot-failed-title">
|
|
1409
|
+
Personalized view couldn't load.
|
|
1410
|
+
</p>
|
|
1411
|
+
<p class="syntro-pdp-slot-failed-body">
|
|
1412
|
+
The standard page still has everything you need.
|
|
1413
|
+
</p>
|
|
1414
|
+
</div>
|
|
1415
|
+
</div>
|
|
1416
|
+
`;
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
PdpSlotLit.properties = {
|
|
1420
|
+
slotId: { type: String, attribute: "slot-id" },
|
|
1421
|
+
kind: { type: String },
|
|
1422
|
+
state: { type: String, reflect: true }
|
|
1423
|
+
};
|
|
1424
|
+
if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-slot")) {
|
|
1425
|
+
customElements.define("syntro-pdp-slot", PdpSlotLit);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// src/takeover/renderModules.ts
|
|
1429
|
+
function parsePlanEntry(entry) {
|
|
1430
|
+
const i2 = entry.indexOf(":");
|
|
1431
|
+
if (i2 === -1) return { kind: entry, hostSectionId: null };
|
|
1432
|
+
return { kind: entry.slice(0, i2), hostSectionId: entry.slice(i2 + 1) || null };
|
|
1433
|
+
}
|
|
1434
|
+
function createTakeoverModuleRenderer(deps) {
|
|
1435
|
+
return async (plan, onModuleFailed) => {
|
|
1436
|
+
const decisionArchetype = deps.getDecisionArchetype();
|
|
1437
|
+
const row = deps.getPresetRow(decisionArchetype) ?? {};
|
|
1438
|
+
const bakedWork = [];
|
|
1439
|
+
plan.order.forEach((entry, index) => {
|
|
1440
|
+
const { kind, hostSectionId } = parsePlanEntry(entry);
|
|
1441
|
+
const slotId = `pdp-slot-${kind}`;
|
|
1442
|
+
const preset = row[slotId];
|
|
1443
|
+
const tag = deps.resolveTag(kind, preset?.variant ?? null);
|
|
1444
|
+
if (!tag) {
|
|
1445
|
+
deps.telemetry("takeover.module_kind_unknown", { entry, kind });
|
|
1446
|
+
onModuleFailed(hostSectionId);
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
const envelope = buildPdpPlan([{ slot: slotId, preset }]);
|
|
1450
|
+
const task = envelope.tasks[0];
|
|
1451
|
+
const section = document.createElement("section");
|
|
1452
|
+
section.toggleAttribute("data-syntro-pdp-section", true);
|
|
1453
|
+
section.setAttribute("data-slot", slotId);
|
|
1454
|
+
section.setAttribute("data-syntro-takeover-entry", entry);
|
|
1455
|
+
const header = document.createElement("syntro-pdp-section-header");
|
|
1456
|
+
header.eyebrow = task.header.eyebrow ?? "";
|
|
1457
|
+
header.title = task.header.title ?? "";
|
|
1458
|
+
header.accent = task.header.accent ?? "";
|
|
1459
|
+
header.subtitle = task.header.subtitle ?? "";
|
|
1460
|
+
const inner = document.createElement("div");
|
|
1461
|
+
inner.toggleAttribute("data-syntro-pdp-section-inner", true);
|
|
1462
|
+
const slotEl = document.createElement("syntro-pdp-slot");
|
|
1463
|
+
slotEl.slotId = `syntro-takeover-${index}-${slotId}`;
|
|
1464
|
+
slotEl.kind = kind;
|
|
1465
|
+
slotEl.state = "pending";
|
|
1466
|
+
inner.appendChild(slotEl);
|
|
1467
|
+
section.append(header, inner);
|
|
1468
|
+
deps.root.appendChild(section);
|
|
1469
|
+
const fail = () => {
|
|
1470
|
+
if (hostSectionId) {
|
|
1471
|
+
section.remove();
|
|
1472
|
+
} else {
|
|
1473
|
+
slotEl.state = "failed";
|
|
1474
|
+
}
|
|
1475
|
+
deps.telemetry("takeover.module_failed", { entry, kind });
|
|
1476
|
+
onModuleFailed(hostSectionId);
|
|
1477
|
+
};
|
|
1478
|
+
const mountPayload = async (payload) => {
|
|
1479
|
+
await slotEl.updateComplete;
|
|
1480
|
+
const mount = slotEl.querySelector(".syntro-pdp-slot-mount");
|
|
1481
|
+
if (!mount) {
|
|
1482
|
+
fail();
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
mount.replaceChildren();
|
|
1486
|
+
const widget = document.createElement(tag);
|
|
1487
|
+
widget.data = payload;
|
|
1488
|
+
mount.appendChild(widget);
|
|
1489
|
+
slotEl.state = "mounted";
|
|
1490
|
+
};
|
|
1491
|
+
if (preset) {
|
|
1492
|
+
const data = selectPresetData(preset.kind, preset.data, decisionArchetype);
|
|
1493
|
+
bakedWork.push(mountPayload(data).catch(fail));
|
|
1494
|
+
} else {
|
|
1495
|
+
void deps.requestLiveModule(kind, decisionArchetype).then((payload) => payload ? mountPayload(payload) : fail()).catch(fail);
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
await Promise.all(bakedWork);
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
|
|
901
1502
|
// src/widgets/PdpOtherProductsCarouselLit.ts
|
|
902
|
-
import { html as
|
|
1503
|
+
import { html as html4, LitElement as LitElement4 } from "lit";
|
|
903
1504
|
|
|
904
1505
|
// src/widgets/OtherProductTileLit.ts
|
|
905
|
-
import { html as
|
|
1506
|
+
import { html as html3, LitElement as LitElement3 } from "lit";
|
|
906
1507
|
var RELATIONSHIP_LABELS = {
|
|
907
1508
|
discovery: "Recommended for you",
|
|
908
1509
|
complement: "Pairs with this",
|
|
@@ -1045,7 +1646,7 @@ var OTHER_PRODUCT_TILE_CSS = `
|
|
|
1045
1646
|
background: color-mix(in srgb, var(--opt-primary) 10%, transparent);
|
|
1046
1647
|
}
|
|
1047
1648
|
`;
|
|
1048
|
-
var OtherProductTileLit = class extends
|
|
1649
|
+
var OtherProductTileLit = class extends LitElement3 {
|
|
1049
1650
|
constructor() {
|
|
1050
1651
|
super(...arguments);
|
|
1051
1652
|
this.tile = null;
|
|
@@ -1060,24 +1661,24 @@ var OtherProductTileLit = class extends LitElement2 {
|
|
|
1060
1661
|
render() {
|
|
1061
1662
|
const t2 = this.tile;
|
|
1062
1663
|
if (!t2) {
|
|
1063
|
-
return
|
|
1664
|
+
return html3``;
|
|
1064
1665
|
}
|
|
1065
1666
|
const relationshipLabel = RELATIONSHIP_LABELS[t2.relationship];
|
|
1066
1667
|
const price = t2.price_cents == null ? "" : `$${(t2.price_cents / 100).toFixed(0)}`;
|
|
1067
|
-
return
|
|
1668
|
+
return html3`
|
|
1068
1669
|
<article class="opt-card" data-relationship="${t2.relationship}">
|
|
1069
|
-
${t2.image_url ?
|
|
1670
|
+
${t2.image_url ? html3`<div class="opt-image">
|
|
1070
1671
|
<img src="${t2.image_url}" alt="${t2.name}" loading="lazy" />
|
|
1071
1672
|
</div>` : null}
|
|
1072
1673
|
<div class="opt-relationship" data-relationship="${t2.relationship}">
|
|
1073
|
-
${relationshipLabel ?
|
|
1674
|
+
${relationshipLabel ? html3`${relationshipLabel}` : null}
|
|
1074
1675
|
<span class="opt-relationship-type">${t2.relationship}</span>
|
|
1075
1676
|
</div>
|
|
1076
1677
|
<h3 class="opt-name">${t2.name}</h3>
|
|
1077
|
-
${t2.tagline ?
|
|
1078
|
-
${t2.why_blurb ?
|
|
1079
|
-
${t2.evidence_chips.length ?
|
|
1080
|
-
${t2.evidence_chips.map((c2) =>
|
|
1678
|
+
${t2.tagline ? html3`<p class="opt-tagline">${t2.tagline}</p>` : null}
|
|
1679
|
+
${t2.why_blurb ? html3`<p class="opt-why">${t2.why_blurb}</p>` : null}
|
|
1680
|
+
${t2.evidence_chips.length ? html3`<div class="opt-chips">
|
|
1681
|
+
${t2.evidence_chips.map((c2) => html3`<span class="opt-chip">${c2.display}</span>`)}
|
|
1081
1682
|
</div>` : null}
|
|
1082
1683
|
<div class="opt-footer">
|
|
1083
1684
|
<span class="opt-price">${price}</span>
|
|
@@ -1160,7 +1761,7 @@ syntro-pdp-other-products-carousel {
|
|
|
1160
1761
|
}
|
|
1161
1762
|
}
|
|
1162
1763
|
`;
|
|
1163
|
-
var PdpOtherProductsCarouselLit = class extends
|
|
1764
|
+
var PdpOtherProductsCarouselLit = class extends LitElement4 {
|
|
1164
1765
|
constructor() {
|
|
1165
1766
|
super(...arguments);
|
|
1166
1767
|
this.data = null;
|
|
@@ -1173,12 +1774,12 @@ var PdpOtherProductsCarouselLit = class extends LitElement3 {
|
|
|
1173
1774
|
ensureCarouselStyles();
|
|
1174
1775
|
}
|
|
1175
1776
|
render() {
|
|
1176
|
-
if (!this.data) return
|
|
1177
|
-
return
|
|
1777
|
+
if (!this.data) return html4``;
|
|
1778
|
+
return html4`
|
|
1178
1779
|
<div class="opc-carousel">
|
|
1179
1780
|
<div class="carousel" role="list">
|
|
1180
1781
|
${this.data.tiles.map(
|
|
1181
|
-
(tile) =>
|
|
1782
|
+
(tile) => html4`
|
|
1182
1783
|
<div class="opc-item" role="listitem">
|
|
1183
1784
|
<syntro-pdp-other-product-tile .tile=${tile}></syntro-pdp-other-product-tile>
|
|
1184
1785
|
</div>
|
|
@@ -1197,7 +1798,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-oth
|
|
|
1197
1798
|
}
|
|
1198
1799
|
|
|
1199
1800
|
// src/widgets/PdpOtherProductsGridLit.ts
|
|
1200
|
-
import { html as
|
|
1801
|
+
import { html as html5, LitElement as LitElement5 } from "lit";
|
|
1201
1802
|
function ensureGridStyles() {
|
|
1202
1803
|
if (typeof document === "undefined") return;
|
|
1203
1804
|
if (document.getElementById("syntro-pdp-other-products-grid-style")) return;
|
|
@@ -1226,7 +1827,7 @@ syntro-pdp-other-products-grid {
|
|
|
1226
1827
|
}
|
|
1227
1828
|
}
|
|
1228
1829
|
`;
|
|
1229
|
-
var PdpOtherProductsGridLit = class extends
|
|
1830
|
+
var PdpOtherProductsGridLit = class extends LitElement5 {
|
|
1230
1831
|
constructor() {
|
|
1231
1832
|
super(...arguments);
|
|
1232
1833
|
this.data = null;
|
|
@@ -1239,11 +1840,11 @@ var PdpOtherProductsGridLit = class extends LitElement4 {
|
|
|
1239
1840
|
ensureGridStyles();
|
|
1240
1841
|
}
|
|
1241
1842
|
render() {
|
|
1242
|
-
if (!this.data) return
|
|
1243
|
-
return
|
|
1843
|
+
if (!this.data) return html5``;
|
|
1844
|
+
return html5`
|
|
1244
1845
|
<div class="grid" role="list">
|
|
1245
1846
|
${this.data.tiles.map(
|
|
1246
|
-
(tile) =>
|
|
1847
|
+
(tile) => html5`
|
|
1247
1848
|
<syntro-pdp-other-product-tile role="listitem" .tile=${tile}></syntro-pdp-other-product-tile>
|
|
1248
1849
|
`
|
|
1249
1850
|
)}
|
|
@@ -1750,6 +2351,9 @@ function gatherVisitorSignals() {
|
|
|
1750
2351
|
extras: gatherExtras(runtime2, context)
|
|
1751
2352
|
};
|
|
1752
2353
|
}
|
|
2354
|
+
function countTakeoverSignals(signals) {
|
|
2355
|
+
return _countSignals(signals.session_metrics) + (signals.chat_excerpt ? 1 : 0);
|
|
2356
|
+
}
|
|
1753
2357
|
var TEMPLATE_TO_TAG = {
|
|
1754
2358
|
// trending-news (TrendingNewsVariant)
|
|
1755
2359
|
"trending-news": "syntro-pdp-trending-news",
|
|
@@ -1794,12 +2398,21 @@ function resolveTagForMount(inst) {
|
|
|
1794
2398
|
}
|
|
1795
2399
|
return null;
|
|
1796
2400
|
}
|
|
1797
|
-
var _SyntroPdpLit = class _SyntroPdpLit extends
|
|
2401
|
+
var _SyntroPdpLit = class _SyntroPdpLit extends LitElement6 {
|
|
1798
2402
|
constructor() {
|
|
1799
2403
|
super(...arguments);
|
|
1800
2404
|
this.productId = "";
|
|
1801
2405
|
this.productName = "";
|
|
1802
2406
|
this.productBlurb = "";
|
|
2407
|
+
/**
|
|
2408
|
+
* Page-takeover anatomy (FEAT-1785977524), normally delivered through the
|
|
2409
|
+
* widget `props` below. Presence at CONNECT time latches the element into
|
|
2410
|
+
* takeover mode: the engine owns the root and the six-slot compose path
|
|
2411
|
+
* never starts. Setting it after a legacy connect is ignored (warned) —
|
|
2412
|
+
* flipping modes on a live element could leave both paths' DOM behind.
|
|
2413
|
+
*/
|
|
2414
|
+
this.takeover = void 0;
|
|
2415
|
+
this._propsValue = void 0;
|
|
1803
2416
|
/**
|
|
1804
2417
|
* SDK runtime. Null until the mountable wires it in. We only render
|
|
1805
2418
|
* the personalized surface once runtimeRef is present AND the
|
|
@@ -1840,6 +2453,48 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
1840
2453
|
*/
|
|
1841
2454
|
this._nativeSlots = /* @__PURE__ */ new Set();
|
|
1842
2455
|
this._nativeHandles = /* @__PURE__ */ new Map();
|
|
2456
|
+
/**
|
|
2457
|
+
* Takeover mode latch — decided ONCE, at the element's FIRST connect, from
|
|
2458
|
+
* the `takeover` prop, and kept for the element's whole lifetime. While
|
|
2459
|
+
* true, Lit never renders into this element (see shouldUpdate): the engine
|
|
2460
|
+
* renders imperatively and its deactivateRoot() calls replaceChildren() on
|
|
2461
|
+
* this root, which would destroy Lit's child parts. The latch is one-way in
|
|
2462
|
+
* BOTH directions — an element that ever rendered legacy has live Lit parts
|
|
2463
|
+
* (engaging the engine would render next to them, then destroy them), and
|
|
2464
|
+
* an element the engine ever owned has no parts left for Lit to resume.
|
|
2465
|
+
*/
|
|
2466
|
+
this._takeoverMode = false;
|
|
2467
|
+
this._takeoverModeLatched = false;
|
|
2468
|
+
/** The single in-flight/settled takeover run for this connected lifetime. */
|
|
2469
|
+
this._takeoverRun = null;
|
|
2470
|
+
/**
|
|
2471
|
+
* Settles when the previous run's dispose has fully completed. A re-run
|
|
2472
|
+
* (reconnect, or a synchronous move between parents) chains on this so a
|
|
2473
|
+
* LATE dispose from the torn-down run can never deactivate the root the
|
|
2474
|
+
* new run is rendering into.
|
|
2475
|
+
*/
|
|
2476
|
+
this._takeoverDisposal = Promise.resolve();
|
|
2477
|
+
/** A previous run deactivated the root (display:none + emptied); a re-run
|
|
2478
|
+
* after reconnect must undo that before the engine renders again. */
|
|
2479
|
+
this._takeoverRanBefore = false;
|
|
2480
|
+
this._takeoverLateWarned = false;
|
|
2481
|
+
/**
|
|
2482
|
+
* bfcache re-entry (review F4). pagehide disposes the run
|
|
2483
|
+
* (attachLifecycleDispose) but a bfcache restore does NOT re-fire
|
|
2484
|
+
* connectedCallback — without this listener the restored page would sit on
|
|
2485
|
+
* the native fallback forever. `persisted` is true only for bfcache
|
|
2486
|
+
* restores; the normal-load pageshow is owned by the connect path. Arrow
|
|
2487
|
+
* function per Lit event-handler convention (stable identity for
|
|
2488
|
+
* add/removeEventListener).
|
|
2489
|
+
*/
|
|
2490
|
+
this._onTakeoverPageShow = (event) => {
|
|
2491
|
+
if (!event.persisted) return;
|
|
2492
|
+
if (!this._takeoverMode || !this.isConnected) return;
|
|
2493
|
+
const config = this.takeover;
|
|
2494
|
+
if (!config) return;
|
|
2495
|
+
this._teardownTakeover();
|
|
2496
|
+
this._startTakeover(config);
|
|
2497
|
+
};
|
|
1843
2498
|
/**
|
|
1844
2499
|
* The scored axes from the current config pass — the SAME values
|
|
1845
2500
|
* `_fireFromConfig` resolved (sport-archetype preset key + decision archetype).
|
|
@@ -1860,6 +2515,23 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
1860
2515
|
this._dispatchDecision({ type: "dossier-toggled", open });
|
|
1861
2516
|
};
|
|
1862
2517
|
}
|
|
2518
|
+
/**
|
|
2519
|
+
* Widget props (the `adaptive-product:pdp` mountable sets `el.props` before
|
|
2520
|
+
* appending). Mapped IMMEDIATELY in the setter — not in willUpdate — so
|
|
2521
|
+
* `takeover` is already on the element when connectedCallback latches the
|
|
2522
|
+
* mode. Absent fields leave the element's current values untouched.
|
|
2523
|
+
*/
|
|
2524
|
+
get props() {
|
|
2525
|
+
return this._propsValue;
|
|
2526
|
+
}
|
|
2527
|
+
set props(value) {
|
|
2528
|
+
this._propsValue = value;
|
|
2529
|
+
if (!value) return;
|
|
2530
|
+
if (value.productId) this.productId = value.productId;
|
|
2531
|
+
if (value.productName) this.productName = value.productName;
|
|
2532
|
+
if (value.productBlurb) this.productBlurb = value.productBlurb;
|
|
2533
|
+
if (value.takeover) this.takeover = value.takeover;
|
|
2534
|
+
}
|
|
1863
2535
|
_dispatchDecision(event) {
|
|
1864
2536
|
const transition = transitionPdp(this._decisionState, event);
|
|
1865
2537
|
this._decisionState = transition.state;
|
|
@@ -1869,6 +2541,25 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
1869
2541
|
return this;
|
|
1870
2542
|
}
|
|
1871
2543
|
connectedCallback() {
|
|
2544
|
+
if (!this._takeoverModeLatched) {
|
|
2545
|
+
this._takeoverModeLatched = true;
|
|
2546
|
+
this._takeoverMode = Boolean(this.takeover);
|
|
2547
|
+
} else if (!this._takeoverMode && this.takeover && !this._takeoverLateWarned) {
|
|
2548
|
+
this._takeoverLateWarned = true;
|
|
2549
|
+
console.warn(
|
|
2550
|
+
"[syntro-pdp] takeover prop set on an element that already connected on the standard compose path \u2014 ignored (mode is latched per element). Mount a fresh element with `takeover` in its widget props."
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
if (this._takeoverMode) {
|
|
2554
|
+
super.connectedCallback();
|
|
2555
|
+
ensureSectionLayoutStyles();
|
|
2556
|
+
if (typeof window !== "undefined") {
|
|
2557
|
+
window.removeEventListener("pageshow", this._onTakeoverPageShow);
|
|
2558
|
+
window.addEventListener("pageshow", this._onTakeoverPageShow);
|
|
2559
|
+
}
|
|
2560
|
+
if (this.takeover) this._startTakeover(this.takeover);
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
1872
2563
|
const reconnecting = this._decisionState.connection === "disconnected";
|
|
1873
2564
|
super.connectedCallback();
|
|
1874
2565
|
ensureSectionLayoutStyles();
|
|
@@ -1885,6 +2576,14 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
1885
2576
|
}
|
|
1886
2577
|
}
|
|
1887
2578
|
disconnectedCallback() {
|
|
2579
|
+
if (this._takeoverMode) {
|
|
2580
|
+
super.disconnectedCallback();
|
|
2581
|
+
if (typeof window !== "undefined") {
|
|
2582
|
+
window.removeEventListener("pageshow", this._onTakeoverPageShow);
|
|
2583
|
+
}
|
|
2584
|
+
this._teardownTakeover();
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
1888
2587
|
super.disconnectedCallback();
|
|
1889
2588
|
this._navUnsub?.();
|
|
1890
2589
|
this._navUnsub = null;
|
|
@@ -1892,6 +2591,16 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
1892
2591
|
this._nativeHandles.clear();
|
|
1893
2592
|
this._dispatchDecision({ type: "disconnected" });
|
|
1894
2593
|
}
|
|
2594
|
+
shouldUpdate(changed) {
|
|
2595
|
+
if (this._takeoverMode) return false;
|
|
2596
|
+
if (changed.has("takeover") && this.takeover && !this._takeoverLateWarned) {
|
|
2597
|
+
this._takeoverLateWarned = true;
|
|
2598
|
+
console.warn(
|
|
2599
|
+
"[syntro-pdp] takeover prop set after the element already connected on the standard compose path \u2014 ignored. Provide `takeover` in the widget props before the element connects (or re-mount it)."
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
return true;
|
|
2603
|
+
}
|
|
1895
2604
|
willUpdate(changed) {
|
|
1896
2605
|
if (changed.has("runtimeRef")) {
|
|
1897
2606
|
this._syncDecisionRuntime(false);
|
|
@@ -2014,6 +2723,135 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2014
2723
|
_syncDecisionPortal() {
|
|
2015
2724
|
this._dispatchDecision({ type: "portal-updated", present: this._whyPortalEl() !== null });
|
|
2016
2725
|
}
|
|
2726
|
+
// ── Takeover wiring (FEAT-1785977524) ────────────────────────────────────
|
|
2727
|
+
/**
|
|
2728
|
+
* Run the takeover engine with real ports: this element as the root,
|
|
2729
|
+
* `SynOS.authedFetch` as the plan/module transport and the existing slot
|
|
2730
|
+
* machinery as the renderer. Activation is config delivery itself: the
|
|
2731
|
+
* served config either carries `takeover` or it doesn't. Runs at
|
|
2732
|
+
* most once per connected lifetime (`_takeoverRun` latch); disconnect tears
|
|
2733
|
+
* it down and a reconnect re-evaluates fresh.
|
|
2734
|
+
*/
|
|
2735
|
+
_startTakeover(config) {
|
|
2736
|
+
if (this._takeoverRun) return;
|
|
2737
|
+
if (!this.productId) {
|
|
2738
|
+
this._track("takeover.missing_product_id", {});
|
|
2739
|
+
console.warn(
|
|
2740
|
+
"[syntro-pdp] takeover requires a product id (widget props / product-id attr) \u2014 skipping takeover, native page untouched."
|
|
2741
|
+
);
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2744
|
+
const synos = _readSynOS();
|
|
2745
|
+
const authedFetch = synos?.authedFetch;
|
|
2746
|
+
const signals = { ...gatherVisitorSignals(), chat_excerpt: readChatExcerpt() };
|
|
2747
|
+
const decisionDescriptions = _readPdpDecisionArchetypes() ?? {};
|
|
2748
|
+
const telemetry2 = (event, props) => this._track(event, props);
|
|
2749
|
+
const scored = { decisionArchetype: "unknown" };
|
|
2750
|
+
const fetchPlan = authedFetch ? createTakeoverPlanFetcher({
|
|
2751
|
+
authedFetch,
|
|
2752
|
+
config,
|
|
2753
|
+
productId: this.productId,
|
|
2754
|
+
productName: this.productName,
|
|
2755
|
+
decisionArchetypes: decisionDescriptions,
|
|
2756
|
+
// No client-side summary exists on the takeover path (the server
|
|
2757
|
+
// scores); the field mirrors /api/pdp/module's for the scorer.
|
|
2758
|
+
behaviorSummary: "",
|
|
2759
|
+
signals
|
|
2760
|
+
}) : null;
|
|
2761
|
+
const run = {
|
|
2762
|
+
disposed: false,
|
|
2763
|
+
detach: null,
|
|
2764
|
+
result: Promise.resolve(null)
|
|
2765
|
+
};
|
|
2766
|
+
const renderModules = createTakeoverModuleRenderer({
|
|
2767
|
+
root: this,
|
|
2768
|
+
getPresetRow: (decisionArchetype) => {
|
|
2769
|
+
const table = _readPdpPresets()?.[this.productId];
|
|
2770
|
+
return table?.[decisionArchetype] ?? table?.unknown;
|
|
2771
|
+
},
|
|
2772
|
+
resolveTag: (kind, variant) => resolveTagForMount({
|
|
2773
|
+
slot: `pdp-slot-${kind}`,
|
|
2774
|
+
kind,
|
|
2775
|
+
variant,
|
|
2776
|
+
header: { eyebrow: "", title: "", accent: null, subtitle: null }
|
|
2777
|
+
}),
|
|
2778
|
+
requestLiveModule: async (kind, decisionArchetype) => {
|
|
2779
|
+
if (!authedFetch) return null;
|
|
2780
|
+
return composeModule(authedFetch, {
|
|
2781
|
+
productName: this.productName,
|
|
2782
|
+
// Guaranteed non-empty: _startTakeover gates on a missing product id.
|
|
2783
|
+
productId: this.productId,
|
|
2784
|
+
kind,
|
|
2785
|
+
variant: null,
|
|
2786
|
+
// The takeover round trip scores only the decision axis (the server
|
|
2787
|
+
// resolves the plan from it); the sport-archetype axis is unscored
|
|
2788
|
+
// on this path, so it is sent as an explicit 'unknown' — never a
|
|
2789
|
+
// silently-invented value.
|
|
2790
|
+
archetype: { slug: "unknown", description: "" },
|
|
2791
|
+
decisionArchetype: decisionArchetype === "unknown" ? null : {
|
|
2792
|
+
slug: decisionArchetype,
|
|
2793
|
+
description: decisionDescriptions[decisionArchetype] ?? ""
|
|
2794
|
+
},
|
|
2795
|
+
behaviorSummary: "",
|
|
2796
|
+
signals
|
|
2797
|
+
});
|
|
2798
|
+
},
|
|
2799
|
+
telemetry: telemetry2,
|
|
2800
|
+
getDecisionArchetype: () => scored.decisionArchetype
|
|
2801
|
+
});
|
|
2802
|
+
const ports = createDomPorts(config, {
|
|
2803
|
+
root: this,
|
|
2804
|
+
signalCount: countTakeoverSignals(signals),
|
|
2805
|
+
fetchPlan: fetchPlan ? async () => {
|
|
2806
|
+
const response = await fetchPlan();
|
|
2807
|
+
scored.decisionArchetype = response.decisionArchetype;
|
|
2808
|
+
return response;
|
|
2809
|
+
} : async () => {
|
|
2810
|
+
throw new Error("SynOS.authedFetch unavailable \u2014 cannot fetch takeover plan");
|
|
2811
|
+
},
|
|
2812
|
+
// Torn-down guard: the progressive path's dispose is a no-op (nothing
|
|
2813
|
+
// was detached), so its BACKGROUND render has no cancellation handle —
|
|
2814
|
+
// this gate is what stops a stale run from appending into a root a
|
|
2815
|
+
// newer run may own by then.
|
|
2816
|
+
renderModules: async (plan, onModuleFailed) => {
|
|
2817
|
+
if (run.disposed) return;
|
|
2818
|
+
return renderModules(plan, onModuleFailed);
|
|
2819
|
+
},
|
|
2820
|
+
telemetry: telemetry2
|
|
2821
|
+
});
|
|
2822
|
+
run.result = this._takeoverDisposal.then(() => {
|
|
2823
|
+
if (run.disposed) return null;
|
|
2824
|
+
if (this._takeoverRanBefore) {
|
|
2825
|
+
this.style.removeProperty("display");
|
|
2826
|
+
this.replaceChildren();
|
|
2827
|
+
}
|
|
2828
|
+
this._takeoverRanBefore = true;
|
|
2829
|
+
return runTakeover(config, ports);
|
|
2830
|
+
}).then((result) => {
|
|
2831
|
+
if (!result) return null;
|
|
2832
|
+
telemetry2("takeover.outcome", { outcome: result.outcome });
|
|
2833
|
+
if (run.disposed) {
|
|
2834
|
+
result.dispose();
|
|
2835
|
+
return result;
|
|
2836
|
+
}
|
|
2837
|
+
run.detach = attachLifecycleDispose(result);
|
|
2838
|
+
return result;
|
|
2839
|
+
}).catch((err) => {
|
|
2840
|
+
telemetry2("takeover.run_failed", { error: String(err).slice(0, 200) });
|
|
2841
|
+
return null;
|
|
2842
|
+
});
|
|
2843
|
+
this._takeoverRun = run;
|
|
2844
|
+
}
|
|
2845
|
+
/** Dispose the current takeover run (idempotent). */
|
|
2846
|
+
_teardownTakeover() {
|
|
2847
|
+
const run = this._takeoverRun;
|
|
2848
|
+
if (!run) return;
|
|
2849
|
+
this._takeoverRun = null;
|
|
2850
|
+
run.disposed = true;
|
|
2851
|
+
run.detach?.();
|
|
2852
|
+
run.detach = null;
|
|
2853
|
+
this._takeoverDisposal = run.result.then((result) => result?.dispose());
|
|
2854
|
+
}
|
|
2017
2855
|
/**
|
|
2018
2856
|
* Emit a telemetry event via the runtime's track API.
|
|
2019
2857
|
* Wrapped in try/catch so a broken telemetry integration never crashes the
|
|
@@ -2377,7 +3215,7 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2377
3215
|
if (view.status === "hidden") return "";
|
|
2378
3216
|
if (view.status === "loading") return this._renderWhyBoxLoading();
|
|
2379
3217
|
const e2 = view.explanation;
|
|
2380
|
-
return
|
|
3218
|
+
return html6`
|
|
2381
3219
|
<style>
|
|
2382
3220
|
/* Token bridge: every color resolves from a --syntro-pdp-* var the
|
|
2383
3221
|
* host (vela pages + SPA) publishes, falling back to a NEUTRAL host
|
|
@@ -2464,29 +3302,29 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2464
3302
|
Shown in demo mode only — a peek under the hood at the live personalization.
|
|
2465
3303
|
</div>
|
|
2466
3304
|
<div data-syntro-pdp-why-archetype>
|
|
2467
|
-
Shopping as: <strong>${e2.archetypeLabel}</strong>${e2.archetypeDesc ?
|
|
3305
|
+
Shopping as: <strong>${e2.archetypeLabel}</strong>${e2.archetypeDesc ? html6` — ${e2.archetypeDesc}` : ""}
|
|
2468
3306
|
</div>
|
|
2469
|
-
${e2.decisionLabel ?
|
|
2470
|
-
What they're weighing: <strong>${e2.decisionLabel}</strong>${e2.decisionDesc ?
|
|
3307
|
+
${e2.decisionLabel ? html6`<div data-syntro-pdp-why-archetype>
|
|
3308
|
+
What they're weighing: <strong>${e2.decisionLabel}</strong>${e2.decisionDesc ? html6` — “${e2.decisionDesc}”` : ""}
|
|
2471
3309
|
</div>` : ""}
|
|
2472
|
-
${e2.summary ?
|
|
3310
|
+
${e2.summary ? html6`<div data-syntro-pdp-why-summary>"${e2.summary}"</div>` : ""}
|
|
2473
3311
|
<div data-syntro-pdp-why-metrics>
|
|
2474
3312
|
${e2.metrics.map(
|
|
2475
|
-
(m) =>
|
|
3313
|
+
(m) => html6`<div data-syntro-pdp-why-metric>
|
|
2476
3314
|
<span data-syntro-pdp-why-metric-value>${m.value}</span>
|
|
2477
3315
|
<span data-syntro-pdp-why-metric-label>${m.label}</span>
|
|
2478
3316
|
</div>`
|
|
2479
3317
|
)}
|
|
2480
3318
|
</div>
|
|
2481
|
-
${view.dossier.length ?
|
|
3319
|
+
${view.dossier.length ? html6`<details data-syntro-pdp-why-dossier ?open=${view.dossierOpen} @toggle=${this._onDossierToggle}>
|
|
2482
3320
|
<summary>What was measured</summary>
|
|
2483
3321
|
<div data-syntro-pdp-why-dossier-list>
|
|
2484
3322
|
${view.dossier.map(
|
|
2485
|
-
(m) =>
|
|
3323
|
+
(m) => html6`<div data-syntro-pdp-why-dossier-row>
|
|
2486
3324
|
<span data-syntro-pdp-why-dossier-value>${m.value}</span>
|
|
2487
3325
|
<div data-syntro-pdp-why-dossier-text>
|
|
2488
3326
|
<span data-syntro-pdp-why-dossier-label>${m.label}</span>
|
|
2489
|
-
${m.hint ?
|
|
3327
|
+
${m.hint ? html6`<span data-syntro-pdp-why-dossier-hint>${m.hint}</span>` : ""}
|
|
2490
3328
|
</div>
|
|
2491
3329
|
</div>`
|
|
2492
3330
|
)}
|
|
@@ -2503,7 +3341,7 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2503
3341
|
* so the swap to the filled box is a state change, not a first appearance.
|
|
2504
3342
|
*/
|
|
2505
3343
|
_renderWhyBoxLoading() {
|
|
2506
|
-
return
|
|
3344
|
+
return html6`
|
|
2507
3345
|
<style>
|
|
2508
3346
|
[data-syntro-pdp-why] {
|
|
2509
3347
|
margin: 0; padding: 4px 0;
|
|
@@ -2543,18 +3381,18 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2543
3381
|
`;
|
|
2544
3382
|
}
|
|
2545
3383
|
render() {
|
|
2546
|
-
if (this._pageUnresolvable) return
|
|
3384
|
+
if (this._pageUnresolvable) return html6``;
|
|
2547
3385
|
if (this._presetsSettled && this._decisionState.stream.status === "idle" && this._decisionState.plan.status === "empty" && !_readPdpPresets()?.[this.productId]) {
|
|
2548
|
-
return
|
|
3386
|
+
return html6``;
|
|
2549
3387
|
}
|
|
2550
3388
|
const skeletonStyles = _SyntroPdpLit._skeletonStyles;
|
|
2551
3389
|
const view = selectPdpView(this._decisionState);
|
|
2552
3390
|
if (view.layout === "skeleton") {
|
|
2553
|
-
return
|
|
3391
|
+
return html6`
|
|
2554
3392
|
${skeletonStyles}
|
|
2555
3393
|
<div data-syntro-pdp-root data-state="pending" data-syntro-pdp-skeleton>
|
|
2556
3394
|
${[0, 1, 2].map(
|
|
2557
|
-
(i2) =>
|
|
3395
|
+
(i2) => html6`
|
|
2558
3396
|
<section
|
|
2559
3397
|
data-syntro-pdp-skeleton-section
|
|
2560
3398
|
style="animation-delay: ${i2 * 0.15}s"
|
|
@@ -2571,7 +3409,7 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2571
3409
|
</div>
|
|
2572
3410
|
`;
|
|
2573
3411
|
}
|
|
2574
|
-
return
|
|
3412
|
+
return html6`
|
|
2575
3413
|
${skeletonStyles}
|
|
2576
3414
|
<div data-syntro-pdp-root data-state=${view.rootState}>
|
|
2577
3415
|
${view.whyBox.destination === "inline" ? this._renderWhyBox(view.whyBox) : ""}
|
|
@@ -2579,7 +3417,7 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2579
3417
|
if (!slot.visible) return "";
|
|
2580
3418
|
const task = slot.task;
|
|
2581
3419
|
if (this._nativeSlots.has(task.slot)) return "";
|
|
2582
|
-
return
|
|
3420
|
+
return html6`
|
|
2583
3421
|
<section data-syntro-pdp-section data-slot=${task.slot}>
|
|
2584
3422
|
<syntro-pdp-section-header
|
|
2585
3423
|
.eyebrow=${task.header.eyebrow}
|
|
@@ -2603,7 +3441,7 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement5 {
|
|
|
2603
3441
|
* change) without ever touching the imperatively-managed
|
|
2604
3442
|
* slot subtree. See adversarial-review failure mode #2.
|
|
2605
3443
|
*/
|
|
2606
|
-
slot.showLoading ?
|
|
3444
|
+
slot.showLoading ? html6`<div data-syntro-pdp-slot-shimmer>
|
|
2607
3445
|
<div data-syntro-pdp-skeleton-body></div>
|
|
2608
3446
|
</div>` : ""}
|
|
2609
3447
|
</div>
|
|
@@ -2619,6 +3457,7 @@ _SyntroPdpLit.properties = {
|
|
|
2619
3457
|
productName: { type: String, attribute: "product-name" },
|
|
2620
3458
|
productBlurb: { type: String, attribute: "product-blurb" },
|
|
2621
3459
|
runtimeRef: { attribute: false },
|
|
3460
|
+
takeover: { attribute: false },
|
|
2622
3461
|
_decisionState: { state: true },
|
|
2623
3462
|
_pageUnresolvable: { state: true },
|
|
2624
3463
|
_presetsSettled: { state: true }
|
|
@@ -2630,7 +3469,7 @@ _SyntroPdpLit.properties = {
|
|
|
2630
3469
|
* (see `ensureSectionLayoutStyles`), not here, so they're emitted once
|
|
2631
3470
|
* per document rather than once per `<syntro-pdp>` instance.
|
|
2632
3471
|
*/
|
|
2633
|
-
_SyntroPdpLit._skeletonStyles =
|
|
3472
|
+
_SyntroPdpLit._skeletonStyles = html6`
|
|
2634
3473
|
<style>
|
|
2635
3474
|
[data-syntro-pdp-skeleton] {
|
|
2636
3475
|
display: flex;
|
|
@@ -3033,6 +3872,10 @@ async function flush() {
|
|
|
3033
3872
|
pending.clear();
|
|
3034
3873
|
return;
|
|
3035
3874
|
}
|
|
3875
|
+
if (typeof document !== "undefined" && document.querySelector("syntro-pdp")) {
|
|
3876
|
+
pending.clear();
|
|
3877
|
+
return;
|
|
3878
|
+
}
|
|
3036
3879
|
const ids = [...pending];
|
|
3037
3880
|
pending.clear();
|
|
3038
3881
|
for (const id of ids) await onProductAppeared(id);
|
|
@@ -3110,7 +3953,7 @@ function startNativeSlotWatcher() {
|
|
|
3110
3953
|
}
|
|
3111
3954
|
|
|
3112
3955
|
// src/widgets/ProductCardLit.ts
|
|
3113
|
-
import { html as
|
|
3956
|
+
import { html as html8, LitElement as LitElement8, nothing as nothing4 } from "lit";
|
|
3114
3957
|
import { styleMap } from "lit/directives/style-map.js";
|
|
3115
3958
|
|
|
3116
3959
|
// src/bind/dom-selector.ts
|
|
@@ -4138,7 +4981,7 @@ cancel_fn = function() {
|
|
|
4138
4981
|
};
|
|
4139
4982
|
|
|
4140
4983
|
// src/widgets/VariantPanelLit.ts
|
|
4141
|
-
import { html as
|
|
4984
|
+
import { html as html7, LitElement as LitElement7, nothing as nothing3 } from "lit";
|
|
4142
4985
|
var PANEL_CSS = `
|
|
4143
4986
|
syntro-variant-panel {
|
|
4144
4987
|
display: grid;
|
|
@@ -4370,7 +5213,7 @@ var PANEL_CSS = `
|
|
|
4370
5213
|
.svp-live { position: absolute; left: -9999px; top: 0; width: 1px; height: 1px; overflow: hidden; }
|
|
4371
5214
|
`;
|
|
4372
5215
|
var _VariantPanelLit_instances, healthProbe_fn;
|
|
4373
|
-
var _VariantPanelLit = class _VariantPanelLit extends
|
|
5216
|
+
var _VariantPanelLit = class _VariantPanelLit extends LitElement7 {
|
|
4374
5217
|
constructor() {
|
|
4375
5218
|
super();
|
|
4376
5219
|
__privateAdd(this, _VariantPanelLit_instances);
|
|
@@ -4472,7 +5315,7 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4472
5315
|
}
|
|
4473
5316
|
render() {
|
|
4474
5317
|
if (this.state === "error") {
|
|
4475
|
-
return
|
|
5318
|
+
return html7`
|
|
4476
5319
|
<div class="svp-error-block" data-error-block>
|
|
4477
5320
|
<div>Couldn't load options. ${this.error ?? ""}</div>
|
|
4478
5321
|
<button class="svp-retry-btn" data-retry-button @click=${this._onRetry}>Try again</button>
|
|
@@ -4480,7 +5323,7 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4480
5323
|
`;
|
|
4481
5324
|
}
|
|
4482
5325
|
if (this.state === "loading" || !this.payload) {
|
|
4483
|
-
return
|
|
5326
|
+
return html7`
|
|
4484
5327
|
<div data-loading-skeleton>
|
|
4485
5328
|
<div class="svp-skeleton"></div>
|
|
4486
5329
|
<div class="svp-skeleton"></div>
|
|
@@ -4493,26 +5336,26 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4493
5336
|
const compareAt = matching?.compare_at_price ?? null;
|
|
4494
5337
|
const singleVariant = this.payload.attributes.length === 0;
|
|
4495
5338
|
const heroSrc = this._heroSrc();
|
|
4496
|
-
const backBtn =
|
|
5339
|
+
const backBtn = html7`<button
|
|
4497
5340
|
class="svp-back-btn"
|
|
4498
5341
|
data-back-button
|
|
4499
5342
|
@click=${this._onBack}
|
|
4500
5343
|
aria-label="Back"
|
|
4501
5344
|
>‹ Back</button>`;
|
|
4502
|
-
return
|
|
5345
|
+
return html7`
|
|
4503
5346
|
<div class="svp-image-col" data-image-col>
|
|
4504
|
-
${heroSrc ?
|
|
5347
|
+
${heroSrc ? html7`<img
|
|
4505
5348
|
class="svp-image"
|
|
4506
5349
|
data-variant-image
|
|
4507
5350
|
src=${heroSrc}
|
|
4508
5351
|
alt=${this.productImage?.alt ?? ""}
|
|
4509
5352
|
loading="lazy"
|
|
4510
|
-
/>` :
|
|
5353
|
+
/>` : nothing3}
|
|
4511
5354
|
</div>
|
|
4512
5355
|
<div class="svp-body" data-panel-body>
|
|
4513
|
-
${this.productTitle ?
|
|
5356
|
+
${this.productTitle ? html7`<div class="svp-product-title" data-product-title data-critical-text>${this.productTitle}</div>` : nothing3}
|
|
4514
5357
|
<div class="svp-attributes-scroll" data-attributes-scroll data-clip-ok>
|
|
4515
|
-
${singleVariant ?
|
|
5358
|
+
${singleVariant ? html7`<div class="svp-single-variant-note" data-single-variant-note>
|
|
4516
5359
|
Just one option — ready to add.
|
|
4517
5360
|
</div>` : this.payload.attributes.map((attr) => this._renderAttributeRow(attr))}
|
|
4518
5361
|
</div>
|
|
@@ -4527,23 +5370,23 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4527
5370
|
${// Short label: "Add · $64" (the price commits HERE — the card's
|
|
4528
5371
|
// front face carries no price; round-3 feedback shortened this
|
|
4529
5372
|
// so Back fits beside it on the same row).
|
|
4530
|
-
ctaPrice != null ?
|
|
5373
|
+
ctaPrice != null ? html7`Add ${compareAt ? html7`<span class="svp-compare">$${compareAt.toFixed(2)}</span>` : nothing3}· $${ctaPrice.toFixed(2)}` : html7`Add to cart`}
|
|
4531
5374
|
</button>
|
|
4532
5375
|
${backBtn}
|
|
4533
5376
|
</div>
|
|
4534
5377
|
<div class="svp-live" data-live data-clip-ok aria-live="polite">
|
|
4535
|
-
${this.productTitle ? `Showing options for ${this.productTitle}` :
|
|
5378
|
+
${this.productTitle ? `Showing options for ${this.productTitle}` : nothing3}
|
|
4536
5379
|
</div>
|
|
4537
5380
|
</div>
|
|
4538
5381
|
`;
|
|
4539
5382
|
}
|
|
4540
5383
|
_renderAttributeRow(attr) {
|
|
4541
5384
|
const oosVisible = this._hasAnyOOSForAttribute(attr);
|
|
4542
|
-
return
|
|
5385
|
+
return html7`
|
|
4543
5386
|
<div class="svp-attribute-row" data-attribute-row data-attribute-key=${attr.key}>
|
|
4544
5387
|
<div class="svp-attribute-label" data-attribute-label id=${`attrlabel-${attr.key}`}>${attr.label}</div>
|
|
4545
5388
|
${attr.values.length >= _VariantPanelLit.COLLAPSE_MIN_OPTIONS ? this._renderCollapsedAxis(attr) : attr.kind === "swatch" ? this._renderSwatchRow(attr) : this._renderPillRow(attr)}
|
|
4546
|
-
${oosVisible ?
|
|
5389
|
+
${oosVisible ? html7`<div class="svp-oos-microcopy" data-out-of-stock-microcopy>Out of stock for one or more options</div>` : nothing3}
|
|
4547
5390
|
</div>
|
|
4548
5391
|
`;
|
|
4549
5392
|
}
|
|
@@ -4552,12 +5395,12 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4552
5395
|
}
|
|
4553
5396
|
_renderPillRow(attr) {
|
|
4554
5397
|
const segmented = attr.values.length <= _VariantPanelLit.SEGMENTED_MAX_OPTIONS;
|
|
4555
|
-
return
|
|
4556
|
-
<div class="svp-pill-row" data-segmented=${segmented ? "" :
|
|
5398
|
+
return html7`
|
|
5399
|
+
<div class="svp-pill-row" data-segmented=${segmented ? "" : nothing3} data-scroll=${this._isScrollTier(attr) ? "" : nothing3} role="radiogroup" aria-labelledby=${`attrlabel-${attr.key}`}>
|
|
4557
5400
|
${attr.values.map((v) => {
|
|
4558
5401
|
const disabled2 = this._isValueDisabled(attr.key, v.id);
|
|
4559
5402
|
const checked = this._selection[attr.key] === v.id;
|
|
4560
|
-
return
|
|
5403
|
+
return html7`<button
|
|
4561
5404
|
class="svp-pill"
|
|
4562
5405
|
data-pill
|
|
4563
5406
|
data-attribute-key=${attr.key}
|
|
@@ -4575,14 +5418,14 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4575
5418
|
_renderSwatchRow(attr) {
|
|
4576
5419
|
const selectedValueId = this._selection[attr.key];
|
|
4577
5420
|
const selectedLabel = attr.values.find((v) => v.id === selectedValueId)?.label ?? "";
|
|
4578
|
-
return
|
|
5421
|
+
return html7`
|
|
4579
5422
|
<div class="svp-swatch-label">${selectedLabel}</div>
|
|
4580
|
-
<div class="svp-swatch-row" data-scroll=${this._isScrollTier(attr) ? "" :
|
|
5423
|
+
<div class="svp-swatch-row" data-scroll=${this._isScrollTier(attr) ? "" : nothing3} role="radiogroup" aria-labelledby=${`attrlabel-${attr.key}`}>
|
|
4581
5424
|
${attr.values.map((v) => {
|
|
4582
5425
|
const disabled2 = this._isValueDisabled(attr.key, v.id);
|
|
4583
5426
|
const checked = this._selection[attr.key] === v.id;
|
|
4584
5427
|
const color = v.swatch?.kind === "color" ? v.swatch.value : "transparent";
|
|
4585
|
-
return
|
|
5428
|
+
return html7`<button
|
|
4586
5429
|
class="svp-swatch-pill"
|
|
4587
5430
|
data-pill
|
|
4588
5431
|
data-swatch-dot
|
|
@@ -4636,8 +5479,8 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4636
5479
|
const filter = (this._axisFilter[attr.key] ?? "").trim().toLowerCase();
|
|
4637
5480
|
const filtered = filter ? attr.values.filter((v) => v.label.toLowerCase().includes(filter)) : attr.values;
|
|
4638
5481
|
const showFilter = attr.values.length >= _VariantPanelLit.FILTER_MIN_OPTIONS;
|
|
4639
|
-
const dot = (v) => v?.swatch?.kind === "color" ?
|
|
4640
|
-
return
|
|
5482
|
+
const dot = (v) => v?.swatch?.kind === "color" ? html7`<span class="svp-swatch-dot" style="background-color: ${v.swatch.value}"></span>` : nothing3;
|
|
5483
|
+
return html7`
|
|
4641
5484
|
<div
|
|
4642
5485
|
class="svp-collapse"
|
|
4643
5486
|
data-collapsed-axis
|
|
@@ -4667,7 +5510,7 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4667
5510
|
<span class="svp-collapse-value">${selected ? selected.label : `Choose ${attr.label.toLowerCase()}`}</span>
|
|
4668
5511
|
<span class="svp-collapse-caret">${expanded ? "\u25B4" : "\u25BE"}</span>
|
|
4669
5512
|
</button>
|
|
4670
|
-
${expanded ?
|
|
5513
|
+
${expanded ? html7`
|
|
4671
5514
|
<div
|
|
4672
5515
|
class="svp-collapse-list"
|
|
4673
5516
|
data-clip-ok
|
|
@@ -4675,18 +5518,18 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4675
5518
|
role="listbox"
|
|
4676
5519
|
aria-labelledby=${`attrlabel-${attr.key}`}
|
|
4677
5520
|
>
|
|
4678
|
-
${showFilter ?
|
|
5521
|
+
${showFilter ? html7`<input
|
|
4679
5522
|
class="svp-collapse-filter"
|
|
4680
5523
|
data-collapse-filter
|
|
4681
5524
|
type="text"
|
|
4682
5525
|
placeholder=${`Filter ${attr.label.toLowerCase()}\u2026`}
|
|
4683
5526
|
.value=${this._axisFilter[attr.key] ?? ""}
|
|
4684
5527
|
@input=${(e2) => this._onAxisFilterInput(attr.key, e2)}
|
|
4685
|
-
/>` :
|
|
5528
|
+
/>` : nothing3}
|
|
4686
5529
|
${filtered.map((v) => {
|
|
4687
5530
|
const disabled2 = this._isValueDisabled(attr.key, v.id);
|
|
4688
5531
|
const isSelected = this._selection[attr.key] === v.id;
|
|
4689
|
-
return
|
|
5532
|
+
return html7`<button
|
|
4690
5533
|
class="svp-collapse-option"
|
|
4691
5534
|
data-collapse-option
|
|
4692
5535
|
data-value-id=${v.id}
|
|
@@ -4697,8 +5540,8 @@ var _VariantPanelLit = class _VariantPanelLit extends LitElement6 {
|
|
|
4697
5540
|
@click=${() => this._onCollapsedSelect(attr.key, v.id)}
|
|
4698
5541
|
>${dot(v)}<span class="svp-collapse-value">${v.label}</span></button>`;
|
|
4699
5542
|
})}
|
|
4700
|
-
${filtered.length === 0 ?
|
|
4701
|
-
</div>` :
|
|
5543
|
+
${filtered.length === 0 ? html7`<div class="svp-collapse-empty">No matches</div>` : nothing3}
|
|
5544
|
+
</div>` : nothing3}
|
|
4702
5545
|
</div>
|
|
4703
5546
|
`;
|
|
4704
5547
|
}
|
|
@@ -4823,7 +5666,7 @@ var CARD_FLIP_CSS = `
|
|
|
4823
5666
|
}
|
|
4824
5667
|
`;
|
|
4825
5668
|
var _effectExecutor, _controller, _unsubDevice, _lastFailureFingerprint, _reportedHealthStates, _healthRaf, _ProductCardLit_instances, scheduleHealthCheck_fn, measureAndReportHealth_fn, cleanupHostResources_fn, dispatchCard_fn, _onFlipAnimationEnd, startBind_fn, readProductObservation_fn, syncDecisionInputsBeforeIntent_fn;
|
|
4826
|
-
var ProductCardLit = class extends
|
|
5669
|
+
var ProductCardLit = class extends LitElement8 {
|
|
4827
5670
|
constructor() {
|
|
4828
5671
|
super(...arguments);
|
|
4829
5672
|
__privateAdd(this, _ProductCardLit_instances);
|
|
@@ -4925,9 +5768,9 @@ var ProductCardLit = class extends LitElement7 {
|
|
|
4925
5768
|
super.disconnectedCallback();
|
|
4926
5769
|
}
|
|
4927
5770
|
render() {
|
|
4928
|
-
if (this.validationError || !this.props) return
|
|
5771
|
+
if (this.validationError || !this.props) return html8``;
|
|
4929
5772
|
const parsed = cardSchema.safeParse(this.props);
|
|
4930
|
-
if (!parsed.success) return
|
|
5773
|
+
if (!parsed.success) return html8``;
|
|
4931
5774
|
const density = this._device === "mobile" ? "compact" : parsed.data.density;
|
|
4932
5775
|
const { product, visibleFacts } = parsed.data;
|
|
4933
5776
|
const resolved = this.resolved[product.id];
|
|
@@ -4954,7 +5797,7 @@ var ProductCardLit = class extends LitElement7 {
|
|
|
4954
5797
|
onPrimaryCtaClick,
|
|
4955
5798
|
!view.primaryCta.disabled
|
|
4956
5799
|
);
|
|
4957
|
-
const backFace =
|
|
5800
|
+
const backFace = html8`<syntro-variant-panel
|
|
4958
5801
|
.payload=${view.panel.payload}
|
|
4959
5802
|
.productTitle=${product.name ?? ""}
|
|
4960
5803
|
.productImage=${product.image ? { src: product.image.src, alt: product.image.alt } : null}
|
|
@@ -4965,27 +5808,27 @@ var ProductCardLit = class extends LitElement7 {
|
|
|
4965
5808
|
@variant-panel-retry=${this._onVariantRetry}
|
|
4966
5809
|
@variant-panel-selection-change=${this._onVariantSelectionChange}
|
|
4967
5810
|
></syntro-variant-panel>
|
|
4968
|
-
${view.addError ?
|
|
5811
|
+
${view.addError ? html8`<div data-add-to-cart-error>${view.addError}</div>` : nothing4}`;
|
|
4969
5812
|
const backView = view.face === "back" && view.flipAnimating ? (
|
|
4970
5813
|
// Mid-flip: both faces coexist inside a preserve-3d container. The
|
|
4971
5814
|
// front turns away (inert + aria-hidden) while the back turns in.
|
|
4972
|
-
|
|
5815
|
+
html8`<div data-card-flip @animationend=${__privateGet(this, _onFlipAnimationEnd)}>
|
|
4973
5816
|
<div data-face="front" aria-hidden="true" inert>${frontContent}</div>
|
|
4974
5817
|
<div data-face="back">${backFace}</div>
|
|
4975
5818
|
</div>`
|
|
4976
5819
|
) : view.face === "back" ? (
|
|
4977
5820
|
// Settled back: flat, untransformed — no flip container, no perspective.
|
|
4978
|
-
|
|
4979
|
-
) :
|
|
5821
|
+
html8`<div data-face="back">${backFace}</div>`
|
|
5822
|
+
) : html8`<div data-face="front">
|
|
4980
5823
|
${frontContent}
|
|
4981
|
-
${view.addError ?
|
|
5824
|
+
${view.addError ? html8`<div data-add-to-cart-error>${view.addError}</div>` : nothing4}
|
|
4982
5825
|
</div>`;
|
|
4983
|
-
return
|
|
5826
|
+
return html8`
|
|
4984
5827
|
<article
|
|
4985
5828
|
class="sc-product-card"
|
|
4986
5829
|
data-active-face=${view.face}
|
|
4987
5830
|
data-density=${density}
|
|
4988
|
-
data-labels=${product.labels ? JSON.stringify(product.labels) :
|
|
5831
|
+
data-labels=${product.labels ? JSON.stringify(product.labels) : nothing4}
|
|
4989
5832
|
style=${styleMap(articleStyles)}
|
|
4990
5833
|
>
|
|
4991
5834
|
${backView}
|
|
@@ -5515,7 +6358,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5515
6358
|
maxWidth: "100%",
|
|
5516
6359
|
flexShrink: "1"
|
|
5517
6360
|
};
|
|
5518
|
-
const ctaRow =
|
|
6361
|
+
const ctaRow = html8`<div class="sc-product-card__ctas" style=${styleMap(ctasStyles)}>
|
|
5519
6362
|
${ctas.map((c2, i2) => {
|
|
5520
6363
|
const disabled2 = c2.actionId === "add_to_cart" && !commerceAvailable;
|
|
5521
6364
|
const ctaStyles = {
|
|
@@ -5523,13 +6366,13 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5523
6366
|
...disabled2 ? { opacity: "0.5", "pointer-events": "none", cursor: "not-allowed" } : {}
|
|
5524
6367
|
};
|
|
5525
6368
|
const ctaLabel = c2.label;
|
|
5526
|
-
return
|
|
6369
|
+
return html8`<a
|
|
5527
6370
|
class="sc-product-card__cta"
|
|
5528
6371
|
data-product-cta=${i2 === 0 ? "primary" : "secondary"}
|
|
5529
6372
|
data-critical-text
|
|
5530
6373
|
data-variant=${c2.variant}
|
|
5531
|
-
data-disabled=${disabled2 ? "true" :
|
|
5532
|
-
aria-disabled=${disabled2 ? "true" :
|
|
6374
|
+
data-disabled=${disabled2 ? "true" : nothing4}
|
|
6375
|
+
aria-disabled=${disabled2 ? "true" : nothing4}
|
|
5533
6376
|
href=${c2.actionId === "add_to_cart" ? "#" : c2.href ?? "#"}
|
|
5534
6377
|
target=${c2.target}
|
|
5535
6378
|
rel=${c2.target === "_blank" ? "noopener noreferrer" : ""}
|
|
@@ -5546,7 +6389,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5546
6389
|
>`;
|
|
5547
6390
|
})}
|
|
5548
6391
|
</div>`;
|
|
5549
|
-
const ratingOverlay = overlay && product.rating && isVisible("rating") ?
|
|
6392
|
+
const ratingOverlay = overlay && product.rating && isVisible("rating") ? html8`<div
|
|
5550
6393
|
class="sc-product-card__rating sc-product-card__rating--overlay"
|
|
5551
6394
|
data-product-rating
|
|
5552
6395
|
data-rating-value=${product.rating.value}
|
|
@@ -5561,20 +6404,20 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5561
6404
|
style=${styleMap({ opacity: "0.8", marginLeft: "0.15rem", display: "var(--sc-card-rating-count-display, inline)" })}
|
|
5562
6405
|
>(${product.rating.count.toLocaleString()})</span
|
|
5563
6406
|
>
|
|
5564
|
-
</div>` :
|
|
5565
|
-
const priceOverlay = overlay && isVisible("price") && (product.price || product.salePrice) ?
|
|
6407
|
+
</div>` : nothing4;
|
|
6408
|
+
const priceOverlay = overlay && isVisible("price") && (product.price || product.salePrice) ? html8`<div
|
|
5566
6409
|
class="sc-product-card__price sc-product-card__price--overlay"
|
|
5567
6410
|
data-product-price
|
|
5568
6411
|
style=${styleMap(overlayPriceStyles)}
|
|
5569
6412
|
>
|
|
5570
6413
|
<span
|
|
5571
6414
|
class="sc-product-card__amount"
|
|
5572
|
-
data-product-price-sale=${hasSalePrice ? "true" :
|
|
6415
|
+
data-product-price-sale=${hasSalePrice ? "true" : nothing4}
|
|
5573
6416
|
data-critical-text
|
|
5574
6417
|
>${activePriceText}</span
|
|
5575
6418
|
>
|
|
5576
|
-
</div>` :
|
|
5577
|
-
const mediaBlock = overlay ?
|
|
6419
|
+
</div>` : nothing4;
|
|
6420
|
+
const mediaBlock = overlay ? html8`<div class="sc-product-card__media" style=${styleMap(mediaWrapperStyles)}>
|
|
5578
6421
|
<img
|
|
5579
6422
|
class="sc-product-card__image"
|
|
5580
6423
|
data-product-image
|
|
@@ -5585,7 +6428,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5585
6428
|
style=${styleMap(overlayImgStyles)}
|
|
5586
6429
|
/>
|
|
5587
6430
|
${ratingOverlay}${priceOverlay}
|
|
5588
|
-
</div>` :
|
|
6431
|
+
</div>` : html8`<img
|
|
5589
6432
|
class="sc-product-card__image"
|
|
5590
6433
|
data-product-image
|
|
5591
6434
|
src=${imgSrc}
|
|
@@ -5594,7 +6437,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5594
6437
|
@error=${onImageError}
|
|
5595
6438
|
style=${styleMap(imageStyles)}
|
|
5596
6439
|
/>`;
|
|
5597
|
-
return
|
|
6440
|
+
return html8`
|
|
5598
6441
|
<div class="sc-product-card__grid" data-product-card-grid style=${styleMap(rootGridStyles)}>
|
|
5599
6442
|
${mediaBlock}
|
|
5600
6443
|
<div class="sc-product-card__content" style=${styleMap(contentColStyles)}>
|
|
@@ -5658,7 +6501,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5658
6501
|
// the product page reachable.
|
|
5659
6502
|
(() => {
|
|
5660
6503
|
const navCta = ctas.find((c2) => c2.href);
|
|
5661
|
-
return navCta?.href ?
|
|
6504
|
+
return navCta?.href ? html8`<a
|
|
5662
6505
|
data-product-name-link
|
|
5663
6506
|
href=${navCta.href}
|
|
5664
6507
|
target=${navCta.target ?? "_self"}
|
|
@@ -5668,7 +6511,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5668
6511
|
})()}</h3>
|
|
5669
6512
|
${// On compact the rating renders as an image OVERLAY pill (item 2),
|
|
5670
6513
|
// so it is omitted from the header identity row here.
|
|
5671
|
-
!overlay && product.rating && isVisible("rating") ?
|
|
6514
|
+
!overlay && product.rating && isVisible("rating") ? html8`<div
|
|
5672
6515
|
class="sc-product-card__rating"
|
|
5673
6516
|
data-product-rating
|
|
5674
6517
|
data-rating-value=${product.rating.value}
|
|
@@ -5683,9 +6526,9 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5683
6526
|
<span class="sc-product-card__rating-stars" style="color: #f5a623;">★</span>
|
|
5684
6527
|
<span style=${styleMap({ marginLeft: "0.2rem", fontWeight: "600" })}>${product.rating.value}</span>
|
|
5685
6528
|
<span class="sc-product-card__rating-count" style=${styleMap({ opacity: "0.65", marginLeft: "0.2rem", display: "var(--sc-card-rating-count-display, inline)" })}>(${product.rating.count.toLocaleString()})</span>
|
|
5686
|
-
</div>` :
|
|
6529
|
+
</div>` : nothing4}
|
|
5687
6530
|
</div>
|
|
5688
|
-
${(product.tagline || product.framing) && isVisible("tagline") ?
|
|
6531
|
+
${(product.tagline || product.framing) && isVisible("tagline") ? html8`<p
|
|
5689
6532
|
class="sc-product-card__tagline"
|
|
5690
6533
|
data-product-tagline
|
|
5691
6534
|
style=${styleMap({
|
|
@@ -5719,7 +6562,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5719
6562
|
minWidth: "0",
|
|
5720
6563
|
overflowWrap: "anywhere"
|
|
5721
6564
|
})}
|
|
5722
|
-
>${product.tagline || product.framing}</p>` :
|
|
6565
|
+
>${product.tagline || product.framing}</p>` : nothing4}
|
|
5723
6566
|
</header>
|
|
5724
6567
|
<div
|
|
5725
6568
|
class="sc-product-card__body"
|
|
@@ -5733,36 +6576,36 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5733
6576
|
>
|
|
5734
6577
|
${factOrder.map((key) => {
|
|
5735
6578
|
if (key === "price") {
|
|
5736
|
-
if (overlay) return
|
|
5737
|
-
if (!isVisible("price") || !product.price && !product.salePrice) return
|
|
5738
|
-
return
|
|
6579
|
+
if (overlay) return nothing4;
|
|
6580
|
+
if (!isVisible("price") || !product.price && !product.salePrice) return nothing4;
|
|
6581
|
+
return html8`<div
|
|
5739
6582
|
class="sc-product-card__price"
|
|
5740
6583
|
data-product-price
|
|
5741
6584
|
style=${styleMap(priceBlockStyles)}
|
|
5742
6585
|
>
|
|
5743
|
-
${hasSalePrice && product.price ?
|
|
6586
|
+
${hasSalePrice && product.price ? html8`<span
|
|
5744
6587
|
class="sc-product-card__amount-original"
|
|
5745
6588
|
data-product-price-original
|
|
5746
6589
|
style=${styleMap(priceOriginalStyles)}
|
|
5747
6590
|
>${product.price.amount}</span
|
|
5748
|
-
>` :
|
|
6591
|
+
>` : nothing4}
|
|
5749
6592
|
<span
|
|
5750
6593
|
class="sc-product-card__amount"
|
|
5751
|
-
data-product-price-sale=${hasSalePrice ? "true" :
|
|
6594
|
+
data-product-price-sale=${hasSalePrice ? "true" : nothing4}
|
|
5752
6595
|
data-critical-text
|
|
5753
6596
|
style=${styleMap(priceSaleStyles)}
|
|
5754
6597
|
>${activePriceText}</span
|
|
5755
6598
|
>
|
|
5756
|
-
${activeCadence ?
|
|
6599
|
+
${activeCadence ? html8`<span
|
|
5757
6600
|
class="sc-product-card__cadence"
|
|
5758
6601
|
style=${styleMap(priceCadenceStyles)}
|
|
5759
6602
|
>${activeCadence}</span
|
|
5760
|
-
>` :
|
|
6603
|
+
>` : nothing4}
|
|
5761
6604
|
</div>`;
|
|
5762
6605
|
}
|
|
5763
6606
|
if (key === "availability") {
|
|
5764
|
-
if (!isVisible("availability") || !product.availability) return
|
|
5765
|
-
return
|
|
6607
|
+
if (!isVisible("availability") || !product.availability) return nothing4;
|
|
6608
|
+
return html8`<span
|
|
5766
6609
|
class="sc-product-card__availability"
|
|
5767
6610
|
data-product-availability
|
|
5768
6611
|
data-availability=${product.availability}
|
|
@@ -5771,8 +6614,8 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5771
6614
|
>`;
|
|
5772
6615
|
}
|
|
5773
6616
|
if (key === "badge") {
|
|
5774
|
-
if (!isVisible("badge") || !product.badge) return
|
|
5775
|
-
return
|
|
6617
|
+
if (!isVisible("badge") || !product.badge) return nothing4;
|
|
6618
|
+
return html8`<span
|
|
5776
6619
|
class="sc-product-card__badge"
|
|
5777
6620
|
data-product-badge
|
|
5778
6621
|
data-tone=${product.badge.tone}
|
|
@@ -5788,12 +6631,12 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5788
6631
|
>`;
|
|
5789
6632
|
}
|
|
5790
6633
|
if (key === "specs") {
|
|
5791
|
-
if (!isVisible("specs") || specGroups.length === 0) return
|
|
6634
|
+
if (!isVisible("specs") || specGroups.length === 0) return nothing4;
|
|
5792
6635
|
if (density === "compact") {
|
|
5793
6636
|
const allRows = specGroups.flatMap((g) => g.rows);
|
|
5794
6637
|
const highlights = allRows.slice(0, 4);
|
|
5795
|
-
if (highlights.length === 0) return
|
|
5796
|
-
return
|
|
6638
|
+
if (highlights.length === 0) return nothing4;
|
|
6639
|
+
return html8`<div
|
|
5797
6640
|
class="sc-product-card__specs"
|
|
5798
6641
|
data-density="compact"
|
|
5799
6642
|
data-clip-ok
|
|
@@ -5803,7 +6646,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5803
6646
|
style=${styleMap(specChipRowStyles)}
|
|
5804
6647
|
>
|
|
5805
6648
|
${highlights.map(
|
|
5806
|
-
(r) =>
|
|
6649
|
+
(r) => html8`<span
|
|
5807
6650
|
data-spec-chip
|
|
5808
6651
|
style=${styleMap(specChipStyles)}
|
|
5809
6652
|
><span style="font-weight: 600;">${r.name}</span
|
|
@@ -5812,9 +6655,9 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5812
6655
|
)}
|
|
5813
6656
|
</div>`;
|
|
5814
6657
|
}
|
|
5815
|
-
return
|
|
6658
|
+
return html8`<div class="sc-product-card__specs" style=${styleMap(specsContainerStyles)}>
|
|
5816
6659
|
${specGroups.map(
|
|
5817
|
-
(g) =>
|
|
6660
|
+
(g) => html8`<section
|
|
5818
6661
|
class="sc-product-card__spec-section"
|
|
5819
6662
|
data-spec-section=${g.section}
|
|
5820
6663
|
style=${styleMap(specGroupStyles)}
|
|
@@ -5832,7 +6675,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5832
6675
|
style=${styleMap(specRowsStyles)}
|
|
5833
6676
|
>
|
|
5834
6677
|
${g.rows.map(
|
|
5835
|
-
(r) =>
|
|
6678
|
+
(r) => html8`<li
|
|
5836
6679
|
data-spec-row
|
|
5837
6680
|
data-spec-chip
|
|
5838
6681
|
data-attribute-emphasis=${r.emphasis ? "true" : "false"}
|
|
@@ -5857,12 +6700,12 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5857
6700
|
style=${styleMap(specValueStyles)}
|
|
5858
6701
|
>${r.value}</span
|
|
5859
6702
|
>
|
|
5860
|
-
${r.unit ?
|
|
6703
|
+
${r.unit ? html8`<span
|
|
5861
6704
|
class="sc-product-card__spec-unit"
|
|
5862
6705
|
data-spec-unit
|
|
5863
6706
|
style="opacity: 0.72;"
|
|
5864
6707
|
>${r.unit}</span
|
|
5865
|
-
>` :
|
|
6708
|
+
>` : nothing4}
|
|
5866
6709
|
</li>`
|
|
5867
6710
|
)}
|
|
5868
6711
|
</ul>
|
|
@@ -5871,8 +6714,8 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5871
6714
|
</div>`;
|
|
5872
6715
|
}
|
|
5873
6716
|
if (key === "framing") {
|
|
5874
|
-
if (!isVisible("framing") || !showFraming) return
|
|
5875
|
-
return
|
|
6717
|
+
if (!isVisible("framing") || !showFraming) return nothing4;
|
|
6718
|
+
return html8`<p
|
|
5876
6719
|
class="sc-product-card__framing"
|
|
5877
6720
|
style=${styleMap({
|
|
5878
6721
|
margin: "0",
|
|
@@ -5885,7 +6728,7 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5885
6728
|
.innerHTML=${sanitizeHtml(product.framing ?? "")}
|
|
5886
6729
|
></p>`;
|
|
5887
6730
|
}
|
|
5888
|
-
return
|
|
6731
|
+
return nothing4;
|
|
5889
6732
|
})}
|
|
5890
6733
|
</div>
|
|
5891
6734
|
</div>
|
|
@@ -5895,11 +6738,11 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
|
|
|
5895
6738
|
}
|
|
5896
6739
|
function renderProductCard(product, density, resolved, visibleFacts) {
|
|
5897
6740
|
const articleStyles = _buildArticleStyles(density);
|
|
5898
|
-
return
|
|
6741
|
+
return html8`
|
|
5899
6742
|
<article
|
|
5900
6743
|
class="sc-product-card"
|
|
5901
6744
|
data-density=${density}
|
|
5902
|
-
data-labels=${product.labels ? JSON.stringify(product.labels) :
|
|
6745
|
+
data-labels=${product.labels ? JSON.stringify(product.labels) : nothing4}
|
|
5903
6746
|
style=${styleMap(articleStyles)}
|
|
5904
6747
|
>
|
|
5905
6748
|
${renderProductCardInner(product, density, resolved, visibleFacts, product.ctas, void 0)}
|
|
@@ -5913,9 +6756,9 @@ function onImageError(e2) {
|
|
|
5913
6756
|
}
|
|
5914
6757
|
|
|
5915
6758
|
// src/widgets/ProductComparisonLit.ts
|
|
5916
|
-
import { html as
|
|
6759
|
+
import { html as html9, LitElement as LitElement9, nothing as nothing5 } from "lit";
|
|
5917
6760
|
var _controller2, _parsed, _ProductComparisonLit_instances, healthProbe_fn2, _scrollListenerEl, _onBodyScroll, syncScrollCue_fn, startBind_fn2, renderDiveDeeper_fn, onDiveDeeper_fn, visibleRows_fn, rowComplete_fn, maxFields_fn, synthesizeRows_fn, renderMatrix_fn;
|
|
5918
|
-
var ProductComparisonLit = class extends
|
|
6761
|
+
var ProductComparisonLit = class extends LitElement9 {
|
|
5919
6762
|
constructor() {
|
|
5920
6763
|
super();
|
|
5921
6764
|
__privateAdd(this, _ProductComparisonLit_instances);
|
|
@@ -5957,7 +6800,7 @@ var ProductComparisonLit = class extends LitElement8 {
|
|
|
5957
6800
|
__privateGet(this, _controller2)?.destroy();
|
|
5958
6801
|
}
|
|
5959
6802
|
render() {
|
|
5960
|
-
if (this.validationError || !__privateGet(this, _parsed)) return
|
|
6803
|
+
if (this.validationError || !__privateGet(this, _parsed)) return html9``;
|
|
5961
6804
|
const parsed = __privateGet(this, _parsed);
|
|
5962
6805
|
const bodyStyle = (
|
|
5963
6806
|
// touch-action:pan-y is REQUIRED for the deck swipe-to-cycle to work over a
|
|
@@ -5971,7 +6814,7 @@ var ProductComparisonLit = class extends LitElement8 {
|
|
|
5971
6814
|
// rows and hands horizontal drags back to the deck's swipe handler.
|
|
5972
6815
|
"flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;touch-action:pan-y;scrollbar-width:none;-ms-overflow-style:none;overscroll-behavior:contain;" + (this.scrollFade ? "mask-image:linear-gradient(to bottom,#000 calc(100% - 18px),transparent);-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 18px),transparent);" : "")
|
|
5973
6816
|
);
|
|
5974
|
-
return
|
|
6817
|
+
return html9`
|
|
5975
6818
|
<section
|
|
5976
6819
|
class="sc-product-comparison"
|
|
5977
6820
|
style="display:flex;flex-direction:column;flex:1 1 auto;padding:2px var(--sc-comparison-inset,12px) var(--sc-comparison-inset,12px);box-sizing:border-box;max-width:100%;min-width:0;min-height:0;max-height:100%;overflow:hidden;"
|
|
@@ -6006,11 +6849,11 @@ var ProductComparisonLit = class extends LitElement8 {
|
|
|
6006
6849
|
}
|
|
6007
6850
|
}
|
|
6008
6851
|
</style>
|
|
6009
|
-
${parsed.heading ?
|
|
6852
|
+
${parsed.heading ? html9`<h2
|
|
6010
6853
|
class="sc-product-comparison__heading"
|
|
6011
6854
|
data-comparison-heading
|
|
6012
6855
|
style="flex:0 0 auto;margin:0 0 4px;font:600 14px/1.3 var(--sc-font-family,inherit);color:var(--sc-tile-title-color,inherit);min-width:0;overflow-wrap:break-word;"
|
|
6013
|
-
>${parsed.heading}</h2>` :
|
|
6856
|
+
>${parsed.heading}</h2>` : nothing5}
|
|
6014
6857
|
<div
|
|
6015
6858
|
class="sc-product-comparison__scroll-wrap"
|
|
6016
6859
|
style="position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;"
|
|
@@ -6031,7 +6874,7 @@ var ProductComparisonLit = class extends LitElement8 {
|
|
|
6031
6874
|
// it's in-theme; pointer-events:none so it never blocks scroll/taps;
|
|
6032
6875
|
// gated on scrollFade (content below the current scroll) so it hides
|
|
6033
6876
|
// at the end. Bounce is dropped under prefers-reduced-motion (style).
|
|
6034
|
-
this.scrollFade ?
|
|
6877
|
+
this.scrollFade ? html9`<span class="sc-product-comparison__scroll-cue" aria-hidden="true"></span>` : nothing5}
|
|
6035
6878
|
</div>
|
|
6036
6879
|
${__privateMethod(this, _ProductComparisonLit_instances, renderDiveDeeper_fn).call(this, parsed)}
|
|
6037
6880
|
</section>
|
|
@@ -6116,9 +6959,9 @@ startBind_fn2 = function() {
|
|
|
6116
6959
|
* chat-bar mountable turns it into a user turn.
|
|
6117
6960
|
*/
|
|
6118
6961
|
renderDiveDeeper_fn = function(parsed) {
|
|
6119
|
-
if (parsed.products.length < 2) return
|
|
6962
|
+
if (parsed.products.length < 2) return nothing5;
|
|
6120
6963
|
const chipStyle = "flex:0 0 auto;align-self:flex-end;margin-top:6px;padding:4px 10px;border-radius:9999px;border:1px solid var(--sc-color-border,rgba(0,0,0,0.14));background:transparent;cursor:pointer;font:600 12px/1.2 var(--sc-font-family,inherit);color:var(--sc-color-primary,#3d8a5e);white-space:nowrap;";
|
|
6121
|
-
return
|
|
6964
|
+
return html9`<button
|
|
6122
6965
|
type="button"
|
|
6123
6966
|
class="sc-product-comparison__dive-deeper"
|
|
6124
6967
|
data-dive-deeper
|
|
@@ -6197,7 +7040,7 @@ renderMatrix_fn = function(products, rows) {
|
|
|
6197
7040
|
const colHeadStyle = "display:block;padding:6px 3px;text-align:left;font-weight:600;min-width:0;";
|
|
6198
7041
|
const labelStyle = "padding:8px 4px 8px 2px;font-weight:600;font-size:0.75rem;opacity:0.75;border-top:1px solid var(--sc-tile-border-color,rgba(0,0,0,0.08));align-self:stretch;min-width:0;overflow-wrap:break-word;hyphens:auto;";
|
|
6199
7042
|
const cellStyle = "padding:8px 6px;border-top:1px solid var(--sc-tile-border-color,rgba(0,0,0,0.08));align-self:stretch;min-width:0;overflow-wrap:anywhere;";
|
|
6200
|
-
return
|
|
7043
|
+
return html9`
|
|
6201
7044
|
<div
|
|
6202
7045
|
class="sc-product-comparison__matrix"
|
|
6203
7046
|
data-comparison-matrix
|
|
@@ -6231,7 +7074,7 @@ renderMatrix_fn = function(products, rows) {
|
|
|
6231
7074
|
const showRatingPill = !compactHeaders && p.rating;
|
|
6232
7075
|
const nameOverlayStyle = compactHeaders ? "display:block;font-weight:600;font-size:0.66rem;line-height:1.2;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.55);white-space:normal;overflow-wrap:break-word;min-width:0;" : "display:block;font-weight:600;font-size:0.76rem;line-height:1.25;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.55);white-space:normal;overflow-wrap:break-word;min-width:0;";
|
|
6233
7076
|
const mediaStyle = "position:relative;display:block;width:100%;aspect-ratio:var(--sc-comparison-image-aspect, 19 / 10);border-radius:10px;overflow:hidden;background:#e5e7eb;text-decoration:none;";
|
|
6234
|
-
const cardInner =
|
|
7077
|
+
const cardInner = html9`
|
|
6235
7078
|
<img
|
|
6236
7079
|
class="sc-product-comparison__thumb"
|
|
6237
7080
|
src=${imgSrc}
|
|
@@ -6240,33 +7083,33 @@ renderMatrix_fn = function(products, rows) {
|
|
|
6240
7083
|
style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;"
|
|
6241
7084
|
/>
|
|
6242
7085
|
<span aria-hidden="true" style="position:absolute;inset:auto 0 0 0;height:62%;background:linear-gradient(transparent,rgba(0,0,0,.62));"></span>
|
|
6243
|
-
${showRatingPill && p.rating ?
|
|
7086
|
+
${showRatingPill && p.rating ? html9`<span
|
|
6244
7087
|
class="sc-product-comparison__rating-pill"
|
|
6245
7088
|
data-product-rating
|
|
6246
7089
|
data-rating-value=${p.rating.value}
|
|
6247
7090
|
aria-label=${`${p.rating.value} out of ${p.rating.max ?? 5}, ${p.rating.count} reviews`}
|
|
6248
7091
|
style=${`${pillBase}left:4px;`}
|
|
6249
7092
|
><span style="color:#f5a623;">★</span><span style="margin-left:0.12rem;">${p.rating.value}</span></span
|
|
6250
|
-
>` :
|
|
6251
|
-
${priceText ?
|
|
7093
|
+
>` : nothing5}
|
|
7094
|
+
${priceText ? html9`<span
|
|
6252
7095
|
class="sc-product-comparison__price"
|
|
6253
7096
|
data-critical-text
|
|
6254
7097
|
style=${`${pillBase}right:4px;`}
|
|
6255
7098
|
>${priceText}</span
|
|
6256
|
-
>` :
|
|
7099
|
+
>` : nothing5}
|
|
6257
7100
|
<span
|
|
6258
7101
|
class="sc-product-comparison__name"
|
|
6259
7102
|
data-critical-text
|
|
6260
7103
|
style=${`position:absolute;left:8px;right:8px;bottom:6px;${nameOverlayStyle}`}
|
|
6261
7104
|
>${p.name}</span
|
|
6262
7105
|
>`;
|
|
6263
|
-
return
|
|
7106
|
+
return html9`<div
|
|
6264
7107
|
class="sc-product-comparison__matrix-col"
|
|
6265
7108
|
role="columnheader"
|
|
6266
7109
|
data-product-id=${p.id}
|
|
6267
7110
|
style=${colHeadStyle}
|
|
6268
7111
|
>
|
|
6269
|
-
${pdpHref ?
|
|
7112
|
+
${pdpHref ? html9`<a
|
|
6270
7113
|
class="sc-product-comparison__media"
|
|
6271
7114
|
data-comparison-media
|
|
6272
7115
|
data-product-cta="primary"
|
|
@@ -6277,19 +7120,19 @@ renderMatrix_fn = function(products, rows) {
|
|
|
6277
7120
|
data-action-id=${navCta?.actionId ?? ""}
|
|
6278
7121
|
data-variant=${navCta?.variant ?? ""}
|
|
6279
7122
|
style=${mediaStyle}
|
|
6280
|
-
>${cardInner}</a>` :
|
|
7123
|
+
>${cardInner}</a>` : html9`<div class="sc-product-comparison__media" data-comparison-media style=${mediaStyle}>${cardInner}</div>`}
|
|
6281
7124
|
</div>`;
|
|
6282
7125
|
})}
|
|
6283
7126
|
</div>
|
|
6284
7127
|
${rows.map((row) => {
|
|
6285
7128
|
const cells = [row.valueA, row.valueB, row.valueC, row.valueD];
|
|
6286
|
-
return
|
|
7129
|
+
return html9`
|
|
6287
7130
|
<div role="row" style="display:contents;">
|
|
6288
7131
|
<span class="sc-product-comparison__matrix-label" role="rowheader" style=${labelStyle}
|
|
6289
7132
|
>${row.label}</span
|
|
6290
7133
|
>
|
|
6291
7134
|
${products.map(
|
|
6292
|
-
(_p, i2) =>
|
|
7135
|
+
(_p, i2) => html9`<span class="sc-product-comparison__matrix-cell" role="cell" style=${cellStyle}
|
|
6293
7136
|
>${cells[i2] ?? "\u2014"}</span
|
|
6294
7137
|
>`
|
|
6295
7138
|
)}
|
|
@@ -6307,9 +7150,9 @@ ProductComparisonLit.properties = {
|
|
|
6307
7150
|
};
|
|
6308
7151
|
|
|
6309
7152
|
// src/widgets/ProductGridLit.ts
|
|
6310
|
-
import { html as
|
|
7153
|
+
import { html as html10, LitElement as LitElement10, nothing as nothing6 } from "lit";
|
|
6311
7154
|
var _controller3, _ProductGridLit_instances, startBind_fn3;
|
|
6312
|
-
var ProductGridLit = class extends
|
|
7155
|
+
var ProductGridLit = class extends LitElement10 {
|
|
6313
7156
|
constructor() {
|
|
6314
7157
|
super(...arguments);
|
|
6315
7158
|
__privateAdd(this, _ProductGridLit_instances);
|
|
@@ -6335,20 +7178,20 @@ var ProductGridLit = class extends LitElement9 {
|
|
|
6335
7178
|
__privateGet(this, _controller3)?.destroy();
|
|
6336
7179
|
}
|
|
6337
7180
|
render() {
|
|
6338
|
-
if (this.validationError || !this.props) return
|
|
7181
|
+
if (this.validationError || !this.props) return html10``;
|
|
6339
7182
|
const parsed = gridSchema.safeParse(this.props);
|
|
6340
|
-
if (!parsed.success) return
|
|
7183
|
+
if (!parsed.success) return html10``;
|
|
6341
7184
|
const { products, desktopColumns, heading } = parsed.data;
|
|
6342
|
-
return
|
|
7185
|
+
return html10`
|
|
6343
7186
|
<section class="sc-product-grid">
|
|
6344
|
-
${heading ?
|
|
7187
|
+
${heading ? html10`<h2 data-grid-heading class="sc-product-grid__heading">${heading}</h2>` : nothing6}
|
|
6345
7188
|
<div
|
|
6346
7189
|
data-grid-root
|
|
6347
7190
|
class="sc-product-grid__cells"
|
|
6348
7191
|
style=${`--sc-product-grid-cols:${desktopColumns}`}
|
|
6349
7192
|
>
|
|
6350
7193
|
${products.map(
|
|
6351
|
-
(p) =>
|
|
7194
|
+
(p) => html10`<div data-grid-cell class="sc-product-grid__cell">
|
|
6352
7195
|
${renderProductCard(p, "standard", this.resolved[p.id])}
|
|
6353
7196
|
</div>`
|
|
6354
7197
|
)}
|
|
@@ -6389,9 +7232,9 @@ ProductGridLit.properties = {
|
|
|
6389
7232
|
};
|
|
6390
7233
|
|
|
6391
7234
|
// src/widgets/ProductHeroLit.ts
|
|
6392
|
-
import { html as
|
|
7235
|
+
import { html as html11, LitElement as LitElement11, nothing as nothing7 } from "lit";
|
|
6393
7236
|
var _controller4, _ProductHeroLit_instances, startBind_fn4;
|
|
6394
|
-
var ProductHeroLit = class extends
|
|
7237
|
+
var ProductHeroLit = class extends LitElement11 {
|
|
6395
7238
|
constructor() {
|
|
6396
7239
|
super(...arguments);
|
|
6397
7240
|
__privateAdd(this, _ProductHeroLit_instances);
|
|
@@ -6417,9 +7260,9 @@ var ProductHeroLit = class extends LitElement10 {
|
|
|
6417
7260
|
__privateGet(this, _controller4)?.destroy();
|
|
6418
7261
|
}
|
|
6419
7262
|
render() {
|
|
6420
|
-
if (this.validationError || !this.props) return
|
|
7263
|
+
if (this.validationError || !this.props) return html11``;
|
|
6421
7264
|
const parsed = heroSchema.safeParse(this.props);
|
|
6422
|
-
if (!parsed.success) return
|
|
7265
|
+
if (!parsed.success) return html11``;
|
|
6423
7266
|
const { product, layout, longCopy } = parsed.data;
|
|
6424
7267
|
const resolved = this.resolved[product.id];
|
|
6425
7268
|
const imgSrc = resolved?.image ?? product.image.src;
|
|
@@ -6428,7 +7271,7 @@ var ProductHeroLit = class extends LitElement10 {
|
|
|
6428
7271
|
const sectionStyles = isTopLayout ? "display:block;" : `display:flex;flex-direction:${layout === "image-right" ? "row-reverse" : "row"};gap:1rem;align-items:flex-start;`;
|
|
6429
7272
|
const imageStyles = isTopLayout ? "width:100%;max-height:160px;object-fit:cover;border-radius:8px;display:block;margin-bottom:0.75rem;" : "width:128px;height:128px;object-fit:cover;border-radius:8px;flex-shrink:0;";
|
|
6430
7273
|
const contentStyles = isTopLayout ? "" : "flex:1;min-width:0;";
|
|
6431
|
-
return
|
|
7274
|
+
return html11`
|
|
6432
7275
|
<section class="sc-product-hero" data-hero-layout=${layout} style=${sectionStyles}>
|
|
6433
7276
|
<img
|
|
6434
7277
|
class="sc-product-hero__image"
|
|
@@ -6439,18 +7282,18 @@ var ProductHeroLit = class extends LitElement10 {
|
|
|
6439
7282
|
/>
|
|
6440
7283
|
<div class="sc-product-hero__content" style=${contentStyles}>
|
|
6441
7284
|
<h2 class="sc-product-hero__name">${product.name}</h2>
|
|
6442
|
-
${product.tagline ?
|
|
6443
|
-
${product.price ?
|
|
6444
|
-
${priceText}${product.price.cadence ?
|
|
6445
|
-
</p>` :
|
|
6446
|
-
${longCopy ?
|
|
7285
|
+
${product.tagline ? html11`<p class="sc-product-hero__tagline">${product.tagline}</p>` : nothing7}
|
|
7286
|
+
${product.price ? html11`<p class="sc-product-hero__price">
|
|
7287
|
+
${priceText}${product.price.cadence ? html11` <small>${product.price.cadence}</small>` : nothing7}
|
|
7288
|
+
</p>` : nothing7}
|
|
7289
|
+
${longCopy ? html11`<div
|
|
6447
7290
|
data-hero-longcopy
|
|
6448
7291
|
class="sc-product-hero__longcopy"
|
|
6449
7292
|
.innerHTML=${sanitizeHtml(longCopy)}
|
|
6450
|
-
></div>` :
|
|
7293
|
+
></div>` : nothing7}
|
|
6451
7294
|
<div class="sc-product-hero__ctas">
|
|
6452
7295
|
${product.ctas.map(
|
|
6453
|
-
(c2, i2) =>
|
|
7296
|
+
(c2, i2) => html11`<a
|
|
6454
7297
|
class="sc-product-hero__cta"
|
|
6455
7298
|
data-product-cta=${i2 === 0 ? "primary" : "secondary"}
|
|
6456
7299
|
data-variant=${c2.variant}
|
|
@@ -6498,10 +7341,10 @@ ProductHeroLit.properties = {
|
|
|
6498
7341
|
};
|
|
6499
7342
|
|
|
6500
7343
|
// src/widgets/ProductRecoCarouselLit.ts
|
|
6501
|
-
import { html as
|
|
7344
|
+
import { html as html12, LitElement as LitElement12, nothing as nothing8 } from "lit";
|
|
6502
7345
|
import { styleMap as styleMap2 } from "lit/directives/style-map.js";
|
|
6503
7346
|
var _ProductRecoCarouselLit_instances, healthProbe_fn3;
|
|
6504
|
-
var ProductRecoCarouselLit = class extends
|
|
7347
|
+
var ProductRecoCarouselLit = class extends LitElement12 {
|
|
6505
7348
|
constructor() {
|
|
6506
7349
|
super();
|
|
6507
7350
|
__privateAdd(this, _ProductRecoCarouselLit_instances);
|
|
@@ -6520,20 +7363,20 @@ var ProductRecoCarouselLit = class extends LitElement11 {
|
|
|
6520
7363
|
}
|
|
6521
7364
|
render() {
|
|
6522
7365
|
const items = this._parsed?.items ?? [];
|
|
6523
|
-
if (items.length === 0) return
|
|
6524
|
-
return
|
|
7366
|
+
if (items.length === 0) return html12``;
|
|
7367
|
+
return html12`
|
|
6525
7368
|
<section class="sc-reco" style="box-sizing:border-box;display:flex;flex-direction:column;height:100%;padding:2px var(--sc-reco-inset,12px) var(--sc-reco-inset,12px);">
|
|
6526
7369
|
<div class="sc-reco__carousel" role="list" style="display:flex;align-items:stretch;gap:8px;flex:1 1 auto;min-height:0;overflow-x:auto;scroll-snap-type:x mandatory;">
|
|
6527
7370
|
${items.map(
|
|
6528
|
-
(it) =>
|
|
7371
|
+
(it) => html12`
|
|
6529
7372
|
<div role="listitem" style="display:contents;">
|
|
6530
7373
|
<a data-reco-item data-product-cta="primary" href=${it.pdp_href}
|
|
6531
7374
|
style=${styleMap2({ position: "relative", flex: "0 0 auto", aspectRatio: "4 / 5", minHeight: "var(--sc-reco-item-min-h, 162px)", maxHeight: "var(--sc-reco-item-max-h, 340px)", borderRadius: "12px", overflow: "hidden", scrollSnapAlign: "start", textDecoration: "none", display: "block", background: "#e5e7eb" })}>
|
|
6532
|
-
${it.image_url ?
|
|
7375
|
+
${it.image_url ? html12`<img src=${it.image_url} alt=${it.hook ?? "Recommended product"} loading="lazy" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;">` : nothing8}
|
|
6533
7376
|
<span style="position:absolute;inset:auto 0 0 0;height:60%;background:linear-gradient(transparent,rgba(0,0,0,.62));"></span>
|
|
6534
7377
|
<span style="position:absolute;left:8px;right:8px;bottom:8px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.5);">
|
|
6535
|
-
${it.price ?
|
|
6536
|
-
${it.hook ?
|
|
7378
|
+
${it.price ? html12`<span style="display:block;font-weight:700;font-size:0.9rem;">${it.price}</span>` : nothing8}
|
|
7379
|
+
${it.hook ? html12`<span style="display:block;font-size:0.72rem;line-height:1.2;opacity:.95;">${it.hook}</span>` : nothing8}
|
|
6537
7380
|
</span>
|
|
6538
7381
|
</a>
|
|
6539
7382
|
</div>`
|
|
@@ -6568,7 +7411,7 @@ if (!customElements.get("syntro-product-reco-carousel"))
|
|
|
6568
7411
|
customElements.define("syntro-product-reco-carousel", ProductRecoCarouselLit);
|
|
6569
7412
|
|
|
6570
7413
|
// src/widgets/PdpTrendingNewsLit.ts
|
|
6571
|
-
import { html as
|
|
7414
|
+
import { html as html13, LitElement as LitElement13 } from "lit";
|
|
6572
7415
|
|
|
6573
7416
|
// src/widgets/entrance.ts
|
|
6574
7417
|
function armEntranceSettle(onSettle, container, settleMs, fastPath = false) {
|
|
@@ -6915,7 +7758,7 @@ var TRENDING_NEWS_CSS = `
|
|
|
6915
7758
|
}
|
|
6916
7759
|
}
|
|
6917
7760
|
`;
|
|
6918
|
-
var PdpTrendingNewsLit = class extends
|
|
7761
|
+
var PdpTrendingNewsLit = class extends LitElement13 {
|
|
6919
7762
|
constructor() {
|
|
6920
7763
|
super(...arguments);
|
|
6921
7764
|
this.data = void 0;
|
|
@@ -6951,7 +7794,7 @@ var PdpTrendingNewsLit = class extends LitElement12 {
|
|
|
6951
7794
|
}
|
|
6952
7795
|
render() {
|
|
6953
7796
|
if (!this.data) {
|
|
6954
|
-
return
|
|
7797
|
+
return html13`<div data-skeleton class="pdp-trending-news-skeleton">
|
|
6955
7798
|
<div class="pdp-skeleton-bar" style="width:60%"></div>
|
|
6956
7799
|
<div class="pdp-skeleton-bar" style="width:90%"></div>
|
|
6957
7800
|
<div class="pdp-skeleton-bar" style="width:80%"></div>
|
|
@@ -6961,7 +7804,7 @@ var PdpTrendingNewsLit = class extends LitElement12 {
|
|
|
6961
7804
|
const items = this.data.items;
|
|
6962
7805
|
const featured = items[0];
|
|
6963
7806
|
const rest = items.slice(1);
|
|
6964
|
-
return
|
|
7807
|
+
return html13`
|
|
6965
7808
|
<section
|
|
6966
7809
|
class="${this._entering ? "pdp-trending-news is-entering" : "pdp-trending-news"}"
|
|
6967
7810
|
aria-label="Trending news"
|
|
@@ -6978,7 +7821,7 @@ var PdpTrendingNewsLit = class extends LitElement12 {
|
|
|
6978
7821
|
<p class="pdp-tn-blurb">${featured.blurb}</p>
|
|
6979
7822
|
</article>
|
|
6980
7823
|
${rest.map(
|
|
6981
|
-
(item) =>
|
|
7824
|
+
(item) => html13`
|
|
6982
7825
|
<article class="pdp-tn-card">
|
|
6983
7826
|
<div class="pdp-tn-meta">
|
|
6984
7827
|
<span class="pdp-tn-dot" aria-hidden="true"></span>
|
|
@@ -7000,8 +7843,8 @@ PdpTrendingNewsLit.properties = {
|
|
|
7000
7843
|
_entering: { state: true }
|
|
7001
7844
|
};
|
|
7002
7845
|
function renderHeadlineLink(item) {
|
|
7003
|
-
if (!item.url) return
|
|
7004
|
-
return
|
|
7846
|
+
if (!item.url) return html13`${item.headline}`;
|
|
7847
|
+
return html13`<a
|
|
7005
7848
|
class="pdp-tn-headline-link"
|
|
7006
7849
|
href=${item.url}
|
|
7007
7850
|
target="_blank"
|
|
@@ -7014,7 +7857,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-tre
|
|
|
7014
7857
|
}
|
|
7015
7858
|
|
|
7016
7859
|
// src/widgets/PdpTrendingNewsMagazineLit.ts
|
|
7017
|
-
import { html as
|
|
7860
|
+
import { html as html14, LitElement as LitElement14 } from "lit";
|
|
7018
7861
|
function ensureMagazineStyles() {
|
|
7019
7862
|
if (typeof document === "undefined") return;
|
|
7020
7863
|
if (document.getElementById("syntro-pdp-trending-news-magazine-style")) return;
|
|
@@ -7194,7 +8037,7 @@ var MAGAZINE_CSS = `
|
|
|
7194
8037
|
}
|
|
7195
8038
|
}
|
|
7196
8039
|
`;
|
|
7197
|
-
var PdpTrendingNewsMagazineLit = class extends
|
|
8040
|
+
var PdpTrendingNewsMagazineLit = class extends LitElement14 {
|
|
7198
8041
|
constructor() {
|
|
7199
8042
|
super(...arguments);
|
|
7200
8043
|
this.data = void 0;
|
|
@@ -7208,13 +8051,13 @@ var PdpTrendingNewsMagazineLit = class extends LitElement13 {
|
|
|
7208
8051
|
}
|
|
7209
8052
|
render() {
|
|
7210
8053
|
if (!this.data) {
|
|
7211
|
-
return
|
|
8054
|
+
return html14`<div aria-busy="true" class="pdp-tn-mag" style="opacity:0.5;">…</div>`;
|
|
7212
8055
|
}
|
|
7213
8056
|
const items = this.data.items;
|
|
7214
8057
|
const [lead, ...rest] = items;
|
|
7215
|
-
return
|
|
8058
|
+
return html14`
|
|
7216
8059
|
<section class="pdp-tn-mag" aria-label="Trending news">
|
|
7217
|
-
${lead ?
|
|
8060
|
+
${lead ? html14`<article class="pdp-tn-mag__lead">
|
|
7218
8061
|
<div class="pdp-tn-mag__meta">
|
|
7219
8062
|
<span class="pdp-tn-mag__meta-source">${lead.source}</span>
|
|
7220
8063
|
· ${lead.published_relative}
|
|
@@ -7223,7 +8066,7 @@ var PdpTrendingNewsMagazineLit = class extends LitElement13 {
|
|
|
7223
8066
|
<p class="pdp-tn-mag__blurb">${lead.blurb}</p>
|
|
7224
8067
|
</article>` : ""}
|
|
7225
8068
|
${rest.map(
|
|
7226
|
-
(it) =>
|
|
8069
|
+
(it) => html14`<article class="pdp-tn-mag__item">
|
|
7227
8070
|
<div class="pdp-tn-mag__meta">
|
|
7228
8071
|
<span class="pdp-tn-mag__meta-source">${it.source}</span>
|
|
7229
8072
|
· ${it.published_relative}
|
|
@@ -7240,8 +8083,8 @@ PdpTrendingNewsMagazineLit.properties = {
|
|
|
7240
8083
|
data: { attribute: false }
|
|
7241
8084
|
};
|
|
7242
8085
|
function renderHeadlineLink2(item) {
|
|
7243
|
-
if (!item.url) return
|
|
7244
|
-
return
|
|
8086
|
+
if (!item.url) return html14`${item.headline}`;
|
|
8087
|
+
return html14`<a
|
|
7245
8088
|
class="pdp-tn-mag__headline-link"
|
|
7246
8089
|
href=${item.url}
|
|
7247
8090
|
target="_blank"
|
|
@@ -7254,7 +8097,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-tre
|
|
|
7254
8097
|
}
|
|
7255
8098
|
|
|
7256
8099
|
// src/widgets/PdpTrendingNewsHeroLit.ts
|
|
7257
|
-
import { html as
|
|
8100
|
+
import { html as html15, LitElement as LitElement15 } from "lit";
|
|
7258
8101
|
function ensureHeroStyles() {
|
|
7259
8102
|
if (typeof document === "undefined") return;
|
|
7260
8103
|
if (document.getElementById("syntro-pdp-trending-news-hero-style")) return;
|
|
@@ -7445,7 +8288,7 @@ var HERO_CSS = `
|
|
|
7445
8288
|
}
|
|
7446
8289
|
}
|
|
7447
8290
|
`;
|
|
7448
|
-
var PdpTrendingNewsHeroLit = class extends
|
|
8291
|
+
var PdpTrendingNewsHeroLit = class extends LitElement15 {
|
|
7449
8292
|
constructor() {
|
|
7450
8293
|
super(...arguments);
|
|
7451
8294
|
this.data = void 0;
|
|
@@ -7459,11 +8302,11 @@ var PdpTrendingNewsHeroLit = class extends LitElement14 {
|
|
|
7459
8302
|
}
|
|
7460
8303
|
render() {
|
|
7461
8304
|
if (!this.data) {
|
|
7462
|
-
return
|
|
8305
|
+
return html15`<div aria-busy="true" class="pdp-tn-hero" style="opacity:0.5;">…</div>`;
|
|
7463
8306
|
}
|
|
7464
8307
|
const [lead, ...rest] = this.data.items;
|
|
7465
|
-
if (!lead) return
|
|
7466
|
-
return
|
|
8308
|
+
if (!lead) return html15``;
|
|
8309
|
+
return html15`
|
|
7467
8310
|
<section class="pdp-tn-hero" aria-label="Trending news">
|
|
7468
8311
|
<article class="pdp-tn-hero__panel">
|
|
7469
8312
|
<blockquote class="pdp-tn-hero__quote">${lead.blurb}</blockquote>
|
|
@@ -7474,9 +8317,9 @@ var PdpTrendingNewsHeroLit = class extends LitElement14 {
|
|
|
7474
8317
|
</footer>
|
|
7475
8318
|
<p class="pdp-tn-hero__headline">${renderHeadlineLink3(lead)}</p>
|
|
7476
8319
|
</article>
|
|
7477
|
-
${rest.length ?
|
|
8320
|
+
${rest.length ? html15`<div class="pdp-tn-hero__followon">
|
|
7478
8321
|
${rest.map(
|
|
7479
|
-
(it) =>
|
|
8322
|
+
(it) => html15`<div class="pdp-tn-hero__row">
|
|
7480
8323
|
<p class="pdp-tn-hero__row-headline">${renderHeadlineLink3(it)}</p>
|
|
7481
8324
|
<span class="pdp-tn-hero__row-meta">${it.source}</span>
|
|
7482
8325
|
</div>`
|
|
@@ -7490,8 +8333,8 @@ PdpTrendingNewsHeroLit.properties = {
|
|
|
7490
8333
|
data: { attribute: false }
|
|
7491
8334
|
};
|
|
7492
8335
|
function renderHeadlineLink3(item) {
|
|
7493
|
-
if (!item.url) return
|
|
7494
|
-
return
|
|
8336
|
+
if (!item.url) return html15`${item.headline}`;
|
|
8337
|
+
return html15`<a
|
|
7495
8338
|
class="pdp-tn-hero__headline-link"
|
|
7496
8339
|
href=${item.url}
|
|
7497
8340
|
target="_blank"
|
|
@@ -7504,7 +8347,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-tre
|
|
|
7504
8347
|
}
|
|
7505
8348
|
|
|
7506
8349
|
// src/widgets/PdpPeerFeedMasonryLit.ts
|
|
7507
|
-
import { html as
|
|
8350
|
+
import { html as html16, LitElement as LitElement16 } from "lit";
|
|
7508
8351
|
function ensureMasonryStyles() {
|
|
7509
8352
|
if (typeof document === "undefined") return;
|
|
7510
8353
|
if (document.getElementById("syntro-pdp-peer-feed-masonry-style")) return;
|
|
@@ -7648,7 +8491,7 @@ function personaHue(s4) {
|
|
|
7648
8491
|
for (let i2 = 0; i2 < s4.length; i2++) h = h * 31 + s4.charCodeAt(i2) | 0;
|
|
7649
8492
|
return Math.abs(h) % 360;
|
|
7650
8493
|
}
|
|
7651
|
-
var PdpPeerFeedMasonryLit = class extends
|
|
8494
|
+
var PdpPeerFeedMasonryLit = class extends LitElement16 {
|
|
7652
8495
|
constructor() {
|
|
7653
8496
|
super(...arguments);
|
|
7654
8497
|
this.data = void 0;
|
|
@@ -7662,13 +8505,13 @@ var PdpPeerFeedMasonryLit = class extends LitElement15 {
|
|
|
7662
8505
|
}
|
|
7663
8506
|
render() {
|
|
7664
8507
|
if (!this.data) {
|
|
7665
|
-
return
|
|
8508
|
+
return html16`<div aria-busy="true" class="pdp-pf-mas" style="opacity:0.5;">…</div>`;
|
|
7666
8509
|
}
|
|
7667
|
-
return
|
|
8510
|
+
return html16`
|
|
7668
8511
|
<section class="pdp-pf-mas" aria-label="Peer voices">
|
|
7669
8512
|
<div class="pdp-pf-mas__grid">
|
|
7670
8513
|
${this.data.peers.map(
|
|
7671
|
-
(p) =>
|
|
8514
|
+
(p) => html16`<article
|
|
7672
8515
|
class="pdp-pf-mas__card"
|
|
7673
8516
|
style=${`--pf-avatar-hue: ${personaHue(p.persona)};`}
|
|
7674
8517
|
>
|
|
@@ -7696,7 +8539,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-pee
|
|
|
7696
8539
|
}
|
|
7697
8540
|
|
|
7698
8541
|
// src/widgets/PdpPeerFeedCarouselLit.ts
|
|
7699
|
-
import { html as
|
|
8542
|
+
import { html as html17, LitElement as LitElement17, svg } from "lit";
|
|
7700
8543
|
function ensureCarouselStyles2() {
|
|
7701
8544
|
if (typeof document === "undefined") return;
|
|
7702
8545
|
if (document.getElementById("syntro-pdp-peer-feed-carousel-style")) return;
|
|
@@ -7912,7 +8755,7 @@ function renderGlyph(kind) {
|
|
|
7912
8755
|
<path d="M30 6 L34 26 L54 30 L34 34 L30 54 L26 34 L6 30 L26 26 Z" stroke="currentColor" stroke-width="1.6" fill="none" stroke-linejoin="round"/>
|
|
7913
8756
|
</svg>`;
|
|
7914
8757
|
}
|
|
7915
|
-
var PdpPeerFeedCarouselLit = class extends
|
|
8758
|
+
var PdpPeerFeedCarouselLit = class extends LitElement17 {
|
|
7916
8759
|
constructor() {
|
|
7917
8760
|
super(...arguments);
|
|
7918
8761
|
this.data = void 0;
|
|
@@ -7926,15 +8769,15 @@ var PdpPeerFeedCarouselLit = class extends LitElement16 {
|
|
|
7926
8769
|
}
|
|
7927
8770
|
render() {
|
|
7928
8771
|
if (!this.data) {
|
|
7929
|
-
return
|
|
8772
|
+
return html17`<div aria-busy="true" class="pdp-pf-car" style="opacity:0.5;">…</div>`;
|
|
7930
8773
|
}
|
|
7931
|
-
return
|
|
8774
|
+
return html17`
|
|
7932
8775
|
<section class="pdp-pf-car" aria-label="Peer voices">
|
|
7933
8776
|
<div class="pdp-pf-car__track">
|
|
7934
8777
|
${this.data.peers.map((p) => {
|
|
7935
8778
|
const kind = glyphFor(p.persona);
|
|
7936
8779
|
const hue = glyphHue(p.persona);
|
|
7937
|
-
return
|
|
8780
|
+
return html17`<article class="pdp-pf-car__card" style=${`--pf-glyph-hue: ${hue};`}>
|
|
7938
8781
|
<span class="pdp-pf-car__glyph" aria-hidden="true">${renderGlyph(kind)}</span>
|
|
7939
8782
|
<span class="pdp-pf-car__persona">${p.persona}</span>
|
|
7940
8783
|
<blockquote class="pdp-pf-car__quote">${p.quote}</blockquote>
|
|
@@ -7959,7 +8802,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-pee
|
|
|
7959
8802
|
}
|
|
7960
8803
|
|
|
7961
8804
|
// src/widgets/PdpChartLit.ts
|
|
7962
|
-
import { html as
|
|
8805
|
+
import { html as html18, LitElement as LitElement18, nothing as nothing9, svg as svg2 } from "lit";
|
|
7963
8806
|
function formatNum(v) {
|
|
7964
8807
|
if (v === void 0 || !Number.isFinite(v)) return "\u2014";
|
|
7965
8808
|
if (Number.isInteger(v)) return v.toLocaleString("en-US");
|
|
@@ -8582,7 +9425,7 @@ function colorVar(seriesIdx) {
|
|
|
8582
9425
|
return `var(--pc-color-${seriesIdx % PALETTE_SIZE})`;
|
|
8583
9426
|
}
|
|
8584
9427
|
var _PdpChartLit_instances, renderLegend_fn, renderTable_fn, renderBars_fn, renderLine_fn;
|
|
8585
|
-
var PdpChartLit = class extends
|
|
9428
|
+
var PdpChartLit = class extends LitElement18 {
|
|
8586
9429
|
constructor() {
|
|
8587
9430
|
super(...arguments);
|
|
8588
9431
|
__privateAdd(this, _PdpChartLit_instances);
|
|
@@ -8618,7 +9461,7 @@ var PdpChartLit = class extends LitElement17 {
|
|
|
8618
9461
|
}
|
|
8619
9462
|
render() {
|
|
8620
9463
|
if (!this.data) {
|
|
8621
|
-
return
|
|
9464
|
+
return html18`<div data-skeleton class="pdp-chart-skeleton">
|
|
8622
9465
|
<div class="pdp-skeleton-bar" style="width:50%"></div>
|
|
8623
9466
|
<div class="pdp-skeleton-rect" style="height:200px"></div>
|
|
8624
9467
|
</div>`;
|
|
@@ -8627,7 +9470,7 @@ var PdpChartLit = class extends LitElement17 {
|
|
|
8627
9470
|
const allSeriesOnePoint = this.data.series.every((s4) => s4.points.length <= 1);
|
|
8628
9471
|
const effectiveKind = isTable ? "table" : this.data.viz_kind === "line" && !allSeriesOnePoint ? "line" : "bar";
|
|
8629
9472
|
const isMultiSeries = this.data.series.length > 1;
|
|
8630
|
-
return
|
|
9473
|
+
return html18`
|
|
8631
9474
|
<section
|
|
8632
9475
|
class="${this._entering ? "pdp-chart pdp-chart-frame is-entering" : "pdp-chart pdp-chart-frame"}"
|
|
8633
9476
|
aria-label="${this.data.title}"
|
|
@@ -8638,11 +9481,11 @@ var PdpChartLit = class extends LitElement17 {
|
|
|
8638
9481
|
</div>
|
|
8639
9482
|
<h3 class="pdp-chart-title">${this.data.title}</h3>
|
|
8640
9483
|
|
|
8641
|
-
${effectiveKind === "table" ? __privateMethod(this, _PdpChartLit_instances, renderTable_fn).call(this) :
|
|
8642
|
-
${effectiveKind === "bar" ? __privateMethod(this, _PdpChartLit_instances, renderBars_fn).call(this) :
|
|
8643
|
-
${effectiveKind === "line" ? __privateMethod(this, _PdpChartLit_instances, renderLine_fn).call(this) :
|
|
8644
|
-
${effectiveKind !== "table" && isMultiSeries ? __privateMethod(this, _PdpChartLit_instances, renderLegend_fn).call(this) :
|
|
8645
|
-
${this.data.rationale ?
|
|
9484
|
+
${effectiveKind === "table" ? __privateMethod(this, _PdpChartLit_instances, renderTable_fn).call(this) : nothing9}
|
|
9485
|
+
${effectiveKind === "bar" ? __privateMethod(this, _PdpChartLit_instances, renderBars_fn).call(this) : nothing9}
|
|
9486
|
+
${effectiveKind === "line" ? __privateMethod(this, _PdpChartLit_instances, renderLine_fn).call(this) : nothing9}
|
|
9487
|
+
${effectiveKind !== "table" && isMultiSeries ? __privateMethod(this, _PdpChartLit_instances, renderLegend_fn).call(this) : nothing9}
|
|
9488
|
+
${this.data.rationale ? html18`<p class="pdp-chart-rationale">${this.data.rationale}</p>` : nothing9}
|
|
8646
9489
|
</section>
|
|
8647
9490
|
`;
|
|
8648
9491
|
}
|
|
@@ -8650,10 +9493,10 @@ var PdpChartLit = class extends LitElement17 {
|
|
|
8650
9493
|
_PdpChartLit_instances = new WeakSet();
|
|
8651
9494
|
renderLegend_fn = function() {
|
|
8652
9495
|
const data = this.data;
|
|
8653
|
-
return
|
|
9496
|
+
return html18`
|
|
8654
9497
|
<ol class="pdp-chart-legend" aria-label="Legend">
|
|
8655
9498
|
${data.series.map(
|
|
8656
|
-
(s4, idx) =>
|
|
9499
|
+
(s4, idx) => html18`
|
|
8657
9500
|
<li class="pdp-chart-legend-item">
|
|
8658
9501
|
<span
|
|
8659
9502
|
class="pdp-chart-legend-swatch"
|
|
@@ -8669,22 +9512,22 @@ renderLegend_fn = function() {
|
|
|
8669
9512
|
};
|
|
8670
9513
|
renderTable_fn = function() {
|
|
8671
9514
|
const matrix = buildComparisonMatrix(this.data);
|
|
8672
|
-
return
|
|
9515
|
+
return html18`
|
|
8673
9516
|
<div class="pdp-chart-table-wrap">
|
|
8674
9517
|
<table class="pdp-chart-table">
|
|
8675
9518
|
<thead>
|
|
8676
9519
|
<tr>
|
|
8677
9520
|
<th></th>
|
|
8678
|
-
${matrix.colLabels.map((label) =>
|
|
9521
|
+
${matrix.colLabels.map((label) => html18`<th>${label}</th>`)}
|
|
8679
9522
|
</tr>
|
|
8680
9523
|
</thead>
|
|
8681
9524
|
<tbody>
|
|
8682
9525
|
${matrix.rowLabels.map(
|
|
8683
|
-
(row, rowIdx) =>
|
|
9526
|
+
(row, rowIdx) => html18`
|
|
8684
9527
|
<tr class=${rowIdx === matrix.winningRow ? "is-winning" : ""}>
|
|
8685
9528
|
<td>${row}</td>
|
|
8686
9529
|
${matrix.cells[rowIdx].map(
|
|
8687
|
-
(cell) =>
|
|
9530
|
+
(cell) => html18`<td class="pdp-chart-numeric-cell">${formatNum(cell)}</td>`
|
|
8688
9531
|
)}
|
|
8689
9532
|
</tr>
|
|
8690
9533
|
`
|
|
@@ -8699,7 +9542,7 @@ renderBars_fn = function() {
|
|
|
8699
9542
|
const { buckets, yMax } = buildBarBuckets(data);
|
|
8700
9543
|
const ticks = niceTicks(yMax);
|
|
8701
9544
|
const scaleMax = Math.max(yMax, ticks[ticks.length - 1]);
|
|
8702
|
-
return
|
|
9545
|
+
return html18`
|
|
8703
9546
|
<div
|
|
8704
9547
|
class="pdp-chart-bars"
|
|
8705
9548
|
role="figure"
|
|
@@ -8708,7 +9551,7 @@ renderBars_fn = function() {
|
|
|
8708
9551
|
>
|
|
8709
9552
|
<div class="pdp-chart-yaxis" aria-hidden="true">
|
|
8710
9553
|
${ticks.map(
|
|
8711
|
-
(t2) =>
|
|
9554
|
+
(t2) => html18`
|
|
8712
9555
|
<span
|
|
8713
9556
|
class="pdp-chart-yaxis-tick"
|
|
8714
9557
|
style="bottom:${t2 / scaleMax * 100}%"
|
|
@@ -8720,7 +9563,7 @@ renderBars_fn = function() {
|
|
|
8720
9563
|
</div>
|
|
8721
9564
|
<div class="pdp-chart-bars-area">
|
|
8722
9565
|
${ticks.map(
|
|
8723
|
-
(t2) =>
|
|
9566
|
+
(t2) => html18`
|
|
8724
9567
|
<div
|
|
8725
9568
|
class="pdp-chart-bars-gridline"
|
|
8726
9569
|
style="bottom:${t2 / scaleMax * 100}%"
|
|
@@ -8730,11 +9573,11 @@ renderBars_fn = function() {
|
|
|
8730
9573
|
)}
|
|
8731
9574
|
<div class="pdp-chart-bars-baseline" aria-hidden="true"></div>
|
|
8732
9575
|
${buckets.map(
|
|
8733
|
-
(bucket, bIdx) =>
|
|
9576
|
+
(bucket, bIdx) => html18`
|
|
8734
9577
|
<div class="pdp-chart-bars-bucket">
|
|
8735
9578
|
<div class="pdp-chart-bars-stack">
|
|
8736
9579
|
${bucket.bars.map(
|
|
8737
|
-
(bar, barIdxInBucket) =>
|
|
9580
|
+
(bar, barIdxInBucket) => html18`
|
|
8738
9581
|
<div
|
|
8739
9582
|
class="pdp-chart-bar"
|
|
8740
9583
|
style="
|
|
@@ -8745,9 +9588,9 @@ renderBars_fn = function() {
|
|
|
8745
9588
|
role="img"
|
|
8746
9589
|
aria-label="${bucket.label} — ${bar.seriesName}: ${formatNum(bar.value)}"
|
|
8747
9590
|
>
|
|
8748
|
-
${bucket.bars.length === 1 ?
|
|
9591
|
+
${bucket.bars.length === 1 ? html18`<span class="pdp-chart-bar-value"
|
|
8749
9592
|
>${formatNum(bar.value)}</span
|
|
8750
|
-
>` :
|
|
9593
|
+
>` : nothing9}
|
|
8751
9594
|
</div>
|
|
8752
9595
|
`
|
|
8753
9596
|
)}
|
|
@@ -8765,7 +9608,7 @@ renderLine_fn = function() {
|
|
|
8765
9608
|
const { series, xLabels, yMax } = buildLinePaths(data);
|
|
8766
9609
|
const ticks = niceTicks(yMax);
|
|
8767
9610
|
const scaleMax = Math.max(yMax, ticks[ticks.length - 1]);
|
|
8768
|
-
return
|
|
9611
|
+
return html18`
|
|
8769
9612
|
<div
|
|
8770
9613
|
class="pdp-chart-line"
|
|
8771
9614
|
role="figure"
|
|
@@ -8775,7 +9618,7 @@ renderLine_fn = function() {
|
|
|
8775
9618
|
>
|
|
8776
9619
|
<div class="pdp-chart-line-yaxis" aria-hidden="true">
|
|
8777
9620
|
${ticks.map(
|
|
8778
|
-
(t2) =>
|
|
9621
|
+
(t2) => html18`
|
|
8779
9622
|
<span
|
|
8780
9623
|
class="pdp-chart-yaxis-tick"
|
|
8781
9624
|
style="bottom:${t2 / scaleMax * 100}%"
|
|
@@ -8824,7 +9667,7 @@ renderLine_fn = function() {
|
|
|
8824
9667
|
style="--col-count:${xLabels.length}"
|
|
8825
9668
|
aria-hidden="true"
|
|
8826
9669
|
>
|
|
8827
|
-
${xLabels.map((label) =>
|
|
9670
|
+
${xLabels.map((label) => html18`<span>${label}</span>`)}
|
|
8828
9671
|
</div>
|
|
8829
9672
|
`;
|
|
8830
9673
|
};
|
|
@@ -8837,7 +9680,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-cha
|
|
|
8837
9680
|
}
|
|
8838
9681
|
|
|
8839
9682
|
// src/widgets/PdpChartBarStackedLit.ts
|
|
8840
|
-
import { html as
|
|
9683
|
+
import { html as html19, LitElement as LitElement19 } from "lit";
|
|
8841
9684
|
function ensureStyles() {
|
|
8842
9685
|
if (typeof document === "undefined") return;
|
|
8843
9686
|
if (document.getElementById("syntro-pdp-chart-bar-style")) return;
|
|
@@ -8925,7 +9768,7 @@ var CSS = `
|
|
|
8925
9768
|
}
|
|
8926
9769
|
`;
|
|
8927
9770
|
var PALETTE = ["hsl(150 32% 50%)", "hsl(40 75% 60%)", "hsl(208 50% 55%)", "hsl(320 38% 60%)"];
|
|
8928
|
-
var PdpChartBarStackedLit = class extends
|
|
9771
|
+
var PdpChartBarStackedLit = class extends LitElement19 {
|
|
8929
9772
|
constructor() {
|
|
8930
9773
|
super(...arguments);
|
|
8931
9774
|
this.data = void 0;
|
|
@@ -8938,16 +9781,16 @@ var PdpChartBarStackedLit = class extends LitElement18 {
|
|
|
8938
9781
|
ensureStyles();
|
|
8939
9782
|
}
|
|
8940
9783
|
render() {
|
|
8941
|
-
if (!this.data) return
|
|
9784
|
+
if (!this.data) return html19`<div class="pdp-chart-bar" style="opacity:0.5;">…</div>`;
|
|
8942
9785
|
const { title, series } = this.data;
|
|
8943
9786
|
const allX = Array.from(new Set(series.flatMap((s4) => s4.points.map((p) => p.x))));
|
|
8944
9787
|
const max = Math.max(...series.flatMap((s4) => s4.points.map((p) => p.y)), 1);
|
|
8945
|
-
return
|
|
9788
|
+
return html19`
|
|
8946
9789
|
<section class="pdp-chart-bar" aria-label=${title}>
|
|
8947
9790
|
<h3 class="pdp-chart-bar__title">${title}</h3>
|
|
8948
|
-
${series.length > 1 ?
|
|
9791
|
+
${series.length > 1 ? html19`<div class="pdp-chart-bar__legend">
|
|
8949
9792
|
${series.map(
|
|
8950
|
-
(s4, i2) =>
|
|
9793
|
+
(s4, i2) => html19`<span
|
|
8951
9794
|
><span
|
|
8952
9795
|
class="pdp-chart-bar__legend-dot"
|
|
8953
9796
|
style=${`background: ${PALETTE[i2 % PALETTE.length]};`}
|
|
@@ -8957,14 +9800,14 @@ var PdpChartBarStackedLit = class extends LitElement18 {
|
|
|
8957
9800
|
)}
|
|
8958
9801
|
</div>` : ""}
|
|
8959
9802
|
${allX.map(
|
|
8960
|
-
(x) =>
|
|
9803
|
+
(x) => html19`<div class="pdp-chart-bar__row">
|
|
8961
9804
|
<div class="pdp-chart-bar__row-label">${x}</div>
|
|
8962
9805
|
<div class="pdp-chart-bar__row-bars">
|
|
8963
9806
|
${series.map((s4, i2) => {
|
|
8964
9807
|
const point = s4.points.find((p) => p.x === x);
|
|
8965
9808
|
if (!point) return "";
|
|
8966
9809
|
const pct = point.y / max * 100;
|
|
8967
|
-
return
|
|
9810
|
+
return html19`<div class="pdp-chart-bar__bar-track">
|
|
8968
9811
|
<div
|
|
8969
9812
|
class="pdp-chart-bar__bar-fill"
|
|
8970
9813
|
style=${`width: ${pct.toFixed(1)}%; background: ${PALETTE[i2 % PALETTE.length]};`}
|
|
@@ -8987,7 +9830,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-cha
|
|
|
8987
9830
|
}
|
|
8988
9831
|
|
|
8989
9832
|
// src/widgets/PdpChartMetricPullLit.ts
|
|
8990
|
-
import { html as
|
|
9833
|
+
import { html as html20, LitElement as LitElement20, svg as svg3 } from "lit";
|
|
8991
9834
|
function ensureStyles2() {
|
|
8992
9835
|
if (typeof document === "undefined") return;
|
|
8993
9836
|
if (document.getElementById("syntro-pdp-chart-metric-style")) return;
|
|
@@ -9099,7 +9942,7 @@ function buildSparkline(points) {
|
|
|
9099
9942
|
const peakIndex = points.reduce((best, p, i2) => p.y > points[best].y ? i2 : best, 0);
|
|
9100
9943
|
return { linePath: line, areaPath: area, peakIndex };
|
|
9101
9944
|
}
|
|
9102
|
-
var PdpChartMetricPullLit = class extends
|
|
9945
|
+
var PdpChartMetricPullLit = class extends LitElement20 {
|
|
9103
9946
|
constructor() {
|
|
9104
9947
|
super(...arguments);
|
|
9105
9948
|
this.data = void 0;
|
|
@@ -9112,10 +9955,10 @@ var PdpChartMetricPullLit = class extends LitElement19 {
|
|
|
9112
9955
|
ensureStyles2();
|
|
9113
9956
|
}
|
|
9114
9957
|
render() {
|
|
9115
|
-
if (!this.data) return
|
|
9958
|
+
if (!this.data) return html20`<div class="pdp-chart-met" style="opacity:0.5;">…</div>`;
|
|
9116
9959
|
const { title, series } = this.data;
|
|
9117
9960
|
const first = series[0];
|
|
9118
|
-
if (!first || first.points.length === 0) return
|
|
9961
|
+
if (!first || first.points.length === 0) return html20``;
|
|
9119
9962
|
const points = first.points;
|
|
9120
9963
|
const peak = points.reduce((b, p) => p.y > b.y ? p : b, points[0]);
|
|
9121
9964
|
const mean = points.reduce((s4, p) => s4 + p.y, 0) / points.length;
|
|
@@ -9128,7 +9971,7 @@ var PdpChartMetricPullLit = class extends LitElement19 {
|
|
|
9128
9971
|
const max = Math.max(...points.map((p) => p.y));
|
|
9129
9972
|
const range = max - min || 1;
|
|
9130
9973
|
const py = h - 4 - (peak.y - min) / range * (h - 8);
|
|
9131
|
-
return
|
|
9974
|
+
return html20`
|
|
9132
9975
|
<section class="pdp-chart-met" aria-label=${title}>
|
|
9133
9976
|
<div class="pdp-chart-met__metric">
|
|
9134
9977
|
<span class="pdp-chart-met__big">${peak.y}</span>
|
|
@@ -9160,7 +10003,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-cha
|
|
|
9160
10003
|
}
|
|
9161
10004
|
|
|
9162
10005
|
// src/widgets/PdpQaAccordionLit.ts
|
|
9163
|
-
import { html as
|
|
10006
|
+
import { html as html21, LitElement as LitElement21 } from "lit";
|
|
9164
10007
|
function ensureStyles3() {
|
|
9165
10008
|
if (typeof document === "undefined") return;
|
|
9166
10009
|
if (document.getElementById("syntro-pdp-qa-accordion-style")) return;
|
|
@@ -9242,7 +10085,7 @@ var CSS3 = `
|
|
|
9242
10085
|
max-width: 56ch;
|
|
9243
10086
|
}
|
|
9244
10087
|
`;
|
|
9245
|
-
var PdpQaAccordionLit = class extends
|
|
10088
|
+
var PdpQaAccordionLit = class extends LitElement21 {
|
|
9246
10089
|
constructor() {
|
|
9247
10090
|
super(...arguments);
|
|
9248
10091
|
this.data = void 0;
|
|
@@ -9255,11 +10098,11 @@ var PdpQaAccordionLit = class extends LitElement20 {
|
|
|
9255
10098
|
ensureStyles3();
|
|
9256
10099
|
}
|
|
9257
10100
|
render() {
|
|
9258
|
-
if (!this.data) return
|
|
9259
|
-
return
|
|
10101
|
+
if (!this.data) return html21`<div class="pdp-qa-acc" style="opacity:0.5;">…</div>`;
|
|
10102
|
+
return html21`
|
|
9260
10103
|
<section class="pdp-qa-acc" aria-label="Frequently asked questions">
|
|
9261
10104
|
${this.data.items.map(
|
|
9262
|
-
(it) =>
|
|
10105
|
+
(it) => html21`<details class="pdp-qa-acc__item">
|
|
9263
10106
|
<summary>
|
|
9264
10107
|
<span class="pdp-qa-acc__chev" aria-hidden="true"></span>
|
|
9265
10108
|
<span>${it.question}</span>
|
|
@@ -9279,7 +10122,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-qa-
|
|
|
9279
10122
|
}
|
|
9280
10123
|
|
|
9281
10124
|
// src/widgets/PdpQaSideBySideLit.ts
|
|
9282
|
-
import { html as
|
|
10125
|
+
import { html as html22, LitElement as LitElement22 } from "lit";
|
|
9283
10126
|
function ensureStyles4() {
|
|
9284
10127
|
if (typeof document === "undefined") return;
|
|
9285
10128
|
if (document.getElementById("syntro-pdp-qa-side-style")) return;
|
|
@@ -9353,7 +10196,7 @@ var CSS4 = `
|
|
|
9353
10196
|
margin: 0;
|
|
9354
10197
|
}
|
|
9355
10198
|
`;
|
|
9356
|
-
var PdpQaSideBySideLit = class extends
|
|
10199
|
+
var PdpQaSideBySideLit = class extends LitElement22 {
|
|
9357
10200
|
constructor() {
|
|
9358
10201
|
super(...arguments);
|
|
9359
10202
|
this.data = void 0;
|
|
@@ -9366,11 +10209,11 @@ var PdpQaSideBySideLit = class extends LitElement21 {
|
|
|
9366
10209
|
ensureStyles4();
|
|
9367
10210
|
}
|
|
9368
10211
|
render() {
|
|
9369
|
-
if (!this.data) return
|
|
9370
|
-
return
|
|
10212
|
+
if (!this.data) return html22`<div class="pdp-qa-side" style="opacity:0.5;">…</div>`;
|
|
10213
|
+
return html22`
|
|
9371
10214
|
<section class="pdp-qa-side" aria-label="Q&A">
|
|
9372
10215
|
${this.data.items.map(
|
|
9373
|
-
(it) =>
|
|
10216
|
+
(it) => html22`<div class="pdp-qa-side__item">
|
|
9374
10217
|
<h4 class="pdp-qa-side__q">${it.question}</h4>
|
|
9375
10218
|
<p class="pdp-qa-side__a">${it.answer}</p>
|
|
9376
10219
|
</div>`
|
|
@@ -9387,7 +10230,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-qa-
|
|
|
9387
10230
|
}
|
|
9388
10231
|
|
|
9389
10232
|
// src/widgets/PdpRegionalFullBleedLit.ts
|
|
9390
|
-
import { html as
|
|
10233
|
+
import { html as html23, LitElement as LitElement23 } from "lit";
|
|
9391
10234
|
function ensureStyles5() {
|
|
9392
10235
|
if (typeof document === "undefined") return;
|
|
9393
10236
|
if (document.getElementById("syntro-pdp-regional-fullbleed-style")) return;
|
|
@@ -9478,7 +10321,7 @@ var CSS5 = `
|
|
|
9478
10321
|
font-style: italic;
|
|
9479
10322
|
}
|
|
9480
10323
|
`;
|
|
9481
|
-
var PdpRegionalFullBleedLit = class extends
|
|
10324
|
+
var PdpRegionalFullBleedLit = class extends LitElement23 {
|
|
9482
10325
|
constructor() {
|
|
9483
10326
|
super(...arguments);
|
|
9484
10327
|
this.data = void 0;
|
|
@@ -9491,9 +10334,9 @@ var PdpRegionalFullBleedLit = class extends LitElement22 {
|
|
|
9491
10334
|
ensureStyles5();
|
|
9492
10335
|
}
|
|
9493
10336
|
render() {
|
|
9494
|
-
if (!this.data) return
|
|
10337
|
+
if (!this.data) return html23`<div class="pdp-reg-fb" style="opacity:0.5;">…</div>`;
|
|
9495
10338
|
const d = this.data;
|
|
9496
|
-
return
|
|
10339
|
+
return html23`
|
|
9497
10340
|
<section class="pdp-reg-fb" aria-label="Where you are">
|
|
9498
10341
|
<article class="pdp-reg-fb__panel">
|
|
9499
10342
|
<svg class="pdp-reg-fb__glyph" viewBox="0 0 56 56" aria-hidden="true">
|
|
@@ -9536,7 +10379,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-reg
|
|
|
9536
10379
|
}
|
|
9537
10380
|
|
|
9538
10381
|
// src/widgets/PdpRegionalInlineNoteLit.ts
|
|
9539
|
-
import { html as
|
|
10382
|
+
import { html as html24, LitElement as LitElement24 } from "lit";
|
|
9540
10383
|
function ensureStyles6() {
|
|
9541
10384
|
if (typeof document === "undefined") return;
|
|
9542
10385
|
if (document.getElementById("syntro-pdp-regional-inline-style")) return;
|
|
@@ -9597,7 +10440,7 @@ var CSS6 = `
|
|
|
9597
10440
|
font-style: italic;
|
|
9598
10441
|
}
|
|
9599
10442
|
`;
|
|
9600
|
-
var PdpRegionalInlineNoteLit = class extends
|
|
10443
|
+
var PdpRegionalInlineNoteLit = class extends LitElement24 {
|
|
9601
10444
|
constructor() {
|
|
9602
10445
|
super(...arguments);
|
|
9603
10446
|
this.data = void 0;
|
|
@@ -9610,9 +10453,9 @@ var PdpRegionalInlineNoteLit = class extends LitElement23 {
|
|
|
9610
10453
|
ensureStyles6();
|
|
9611
10454
|
}
|
|
9612
10455
|
render() {
|
|
9613
|
-
if (!this.data) return
|
|
10456
|
+
if (!this.data) return html24`<div class="pdp-reg-in" style="opacity:0.5;">…</div>`;
|
|
9614
10457
|
const d = this.data;
|
|
9615
|
-
return
|
|
10458
|
+
return html24`
|
|
9616
10459
|
<aside class="pdp-reg-in" aria-label="Regional note">
|
|
9617
10460
|
<svg class="pdp-reg-in__icon" viewBox="0 0 22 22" aria-hidden="true">
|
|
9618
10461
|
<circle cx="11" cy="11" r="9" fill="none" stroke="currentColor" stroke-width="1.6"/>
|
|
@@ -9640,8 +10483,8 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-reg
|
|
|
9640
10483
|
}
|
|
9641
10484
|
|
|
9642
10485
|
// src/widgets/PdpSlotPlaceholderLit.ts
|
|
9643
|
-
import { html as
|
|
9644
|
-
var PdpSlotPlaceholderLit = class extends
|
|
10486
|
+
import { html as html25, LitElement as LitElement25 } from "lit";
|
|
10487
|
+
var PdpSlotPlaceholderLit = class extends LitElement25 {
|
|
9645
10488
|
constructor() {
|
|
9646
10489
|
super(...arguments);
|
|
9647
10490
|
this.label = "More personalized content coming soon";
|
|
@@ -9650,7 +10493,7 @@ var PdpSlotPlaceholderLit = class extends LitElement24 {
|
|
|
9650
10493
|
return this;
|
|
9651
10494
|
}
|
|
9652
10495
|
render() {
|
|
9653
|
-
return
|
|
10496
|
+
return html25`
|
|
9654
10497
|
<div class="pdp-slot-placeholder" data-placeholder>
|
|
9655
10498
|
<p>${this.label}</p>
|
|
9656
10499
|
<small>Ask in chat to explore this product further.</small>
|
|
@@ -9666,7 +10509,7 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-slo
|
|
|
9666
10509
|
}
|
|
9667
10510
|
|
|
9668
10511
|
// src/widgets/PdpRibbonLit.ts
|
|
9669
|
-
import { html as
|
|
10512
|
+
import { html as html26, LitElement as LitElement26, nothing as nothing10 } from "lit";
|
|
9670
10513
|
function ensureRibbonStyles() {
|
|
9671
10514
|
if (typeof document === "undefined") return;
|
|
9672
10515
|
if (document.getElementById("syntro-pdp-ribbon-style")) return;
|
|
@@ -9795,7 +10638,7 @@ var RIBBON_CSS = `
|
|
|
9795
10638
|
100% { transform: translateX(110%); }
|
|
9796
10639
|
}
|
|
9797
10640
|
`;
|
|
9798
|
-
var PdpRibbonLit = class extends
|
|
10641
|
+
var PdpRibbonLit = class extends LitElement26 {
|
|
9799
10642
|
constructor() {
|
|
9800
10643
|
super(...arguments);
|
|
9801
10644
|
this.topic = "";
|
|
@@ -9833,7 +10676,7 @@ var PdpRibbonLit = class extends LitElement25 {
|
|
|
9833
10676
|
}
|
|
9834
10677
|
render() {
|
|
9835
10678
|
const cls = this._entering ? "syntro-pdp-ribbon is-entering" : "syntro-pdp-ribbon";
|
|
9836
|
-
return
|
|
10679
|
+
return html26`
|
|
9837
10680
|
<div class="${cls}" role="status" aria-live="polite">
|
|
9838
10681
|
<span class="syntro-pdp-ribbon-sweep" aria-hidden="true"></span>
|
|
9839
10682
|
<svg
|
|
@@ -9853,7 +10696,7 @@ var PdpRibbonLit = class extends LitElement25 {
|
|
|
9853
10696
|
</svg>
|
|
9854
10697
|
<p class="syntro-pdp-ribbon-copy">
|
|
9855
10698
|
Tailored to your conversation about
|
|
9856
|
-
${this.topic ?
|
|
10699
|
+
${this.topic ? html26` <span class="syntro-pdp-ribbon-topic">${this.topic}</span>.` : nothing10}
|
|
9857
10700
|
<span class="syntro-pdp-ribbon-trail"> ${this.subtitle}</span>
|
|
9858
10701
|
</p>
|
|
9859
10702
|
</div>
|
|
@@ -9869,219 +10712,6 @@ if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-rib
|
|
|
9869
10712
|
customElements.define("syntro-pdp-ribbon", PdpRibbonLit);
|
|
9870
10713
|
}
|
|
9871
10714
|
|
|
9872
|
-
// src/widgets/PdpSlotLit.ts
|
|
9873
|
-
import { html as html26, LitElement as LitElement26, nothing as nothing10 } from "lit";
|
|
9874
|
-
function ensureSlotStyles() {
|
|
9875
|
-
if (typeof document === "undefined") return;
|
|
9876
|
-
if (document.getElementById("syntro-pdp-slot-style")) return;
|
|
9877
|
-
const s4 = document.createElement("style");
|
|
9878
|
-
s4.id = "syntro-pdp-slot-style";
|
|
9879
|
-
s4.textContent = SLOT_CSS;
|
|
9880
|
-
document.head.appendChild(s4);
|
|
9881
|
-
}
|
|
9882
|
-
var SLOT_CSS = `
|
|
9883
|
-
.syntro-pdp-slot {
|
|
9884
|
-
--sl-primary: var(--syntro-pdp-primary, hsl(150 32% 38%));
|
|
9885
|
-
--sl-fg: var(--syntro-pdp-fg, hsl(35 15% 92%));
|
|
9886
|
-
--sl-muted: var(--syntro-pdp-muted, hsl(30 8% 55%));
|
|
9887
|
-
--sl-border: var(--syntro-pdp-border, hsl(30 6% 18%));
|
|
9888
|
-
--sl-bg-a: var(--syntro-pdp-card-bg, hsl(25 10% 11%));
|
|
9889
|
-
--sl-bg-b: var(--syntro-pdp-card-bg-b, hsl(25 10% 9%));
|
|
9890
|
-
--sl-display: var(--syntro-pdp-display, inherit);
|
|
9891
|
-
|
|
9892
|
-
position: relative;
|
|
9893
|
-
display: grid;
|
|
9894
|
-
grid-template-areas: 'stack';
|
|
9895
|
-
font-family: var(--syntro-pdp-sans, inherit);
|
|
9896
|
-
}
|
|
9897
|
-
.syntro-pdp-slot > .syntro-pdp-slot-mount,
|
|
9898
|
-
.syntro-pdp-slot > .syntro-pdp-slot-pending,
|
|
9899
|
-
.syntro-pdp-slot > .syntro-pdp-slot-failed {
|
|
9900
|
-
grid-area: stack;
|
|
9901
|
-
}
|
|
9902
|
-
|
|
9903
|
-
.syntro-pdp-slot-mount {
|
|
9904
|
-
min-height: 220px;
|
|
9905
|
-
}
|
|
9906
|
-
|
|
9907
|
-
/* When mutation arrived, hide the pending layer */
|
|
9908
|
-
.syntro-pdp-slot[data-state='mounted'] .syntro-pdp-slot-pending,
|
|
9909
|
-
.syntro-pdp-slot[data-state='failed'] .syntro-pdp-slot-pending {
|
|
9910
|
-
display: none;
|
|
9911
|
-
}
|
|
9912
|
-
.syntro-pdp-slot[data-state='mounted'] .syntro-pdp-slot-failed,
|
|
9913
|
-
.syntro-pdp-slot[data-state='pending'] .syntro-pdp-slot-failed {
|
|
9914
|
-
display: none;
|
|
9915
|
-
}
|
|
9916
|
-
|
|
9917
|
-
/* Pending \u2014 a quietly-animated waiting state. */
|
|
9918
|
-
.syntro-pdp-slot-pending {
|
|
9919
|
-
position: relative;
|
|
9920
|
-
border: 1px dashed var(--sl-border);
|
|
9921
|
-
border-radius: 22px;
|
|
9922
|
-
min-height: 220px;
|
|
9923
|
-
padding: 36px 28px;
|
|
9924
|
-
background: linear-gradient(180deg, var(--sl-bg-a), var(--sl-bg-b));
|
|
9925
|
-
overflow: hidden;
|
|
9926
|
-
display: flex;
|
|
9927
|
-
align-items: center;
|
|
9928
|
-
justify-content: flex-start;
|
|
9929
|
-
}
|
|
9930
|
-
.syntro-pdp-slot-pending-shimmer {
|
|
9931
|
-
position: absolute;
|
|
9932
|
-
inset: 0;
|
|
9933
|
-
background: linear-gradient(
|
|
9934
|
-
90deg,
|
|
9935
|
-
transparent,
|
|
9936
|
-
color-mix(in srgb, var(--sl-primary) 7%, transparent),
|
|
9937
|
-
transparent
|
|
9938
|
-
);
|
|
9939
|
-
transform: translateX(-100%);
|
|
9940
|
-
animation: syntro-pdp-slot-sweep 1800ms ease-in-out infinite;
|
|
9941
|
-
}
|
|
9942
|
-
.syntro-pdp-slot-pending-row {
|
|
9943
|
-
position: relative;
|
|
9944
|
-
z-index: 1;
|
|
9945
|
-
display: flex;
|
|
9946
|
-
align-items: center;
|
|
9947
|
-
gap: 12px;
|
|
9948
|
-
}
|
|
9949
|
-
.syntro-pdp-slot-pending-dot {
|
|
9950
|
-
flex: 0 0 auto;
|
|
9951
|
-
width: 8px;
|
|
9952
|
-
height: 8px;
|
|
9953
|
-
border-radius: 50%;
|
|
9954
|
-
background: var(--sl-primary);
|
|
9955
|
-
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-primary) 14%, transparent);
|
|
9956
|
-
animation: syntro-pdp-slot-pulse 1600ms ease-in-out infinite;
|
|
9957
|
-
}
|
|
9958
|
-
.syntro-pdp-slot-pending-label {
|
|
9959
|
-
font-family: var(--sl-display);
|
|
9960
|
-
font-style: italic;
|
|
9961
|
-
font-size: 18px;
|
|
9962
|
-
font-variation-settings: 'SOFT' 70;
|
|
9963
|
-
color: var(--sl-muted);
|
|
9964
|
-
margin: 0;
|
|
9965
|
-
line-height: 1.4;
|
|
9966
|
-
}
|
|
9967
|
-
|
|
9968
|
-
/* Failed \u2014 the planner or sub-agent failed; the host page still works. */
|
|
9969
|
-
.syntro-pdp-slot-failed {
|
|
9970
|
-
border: 1px solid var(--sl-border);
|
|
9971
|
-
border-radius: 22px;
|
|
9972
|
-
min-height: 180px;
|
|
9973
|
-
padding: 24px 28px;
|
|
9974
|
-
background: linear-gradient(180deg, var(--sl-bg-a), var(--sl-bg-b));
|
|
9975
|
-
display: flex;
|
|
9976
|
-
flex-direction: column;
|
|
9977
|
-
justify-content: center;
|
|
9978
|
-
gap: 6px;
|
|
9979
|
-
}
|
|
9980
|
-
.syntro-pdp-slot-failed-title {
|
|
9981
|
-
font-family: var(--sl-display);
|
|
9982
|
-
font-style: italic;
|
|
9983
|
-
font-size: 17px;
|
|
9984
|
-
color: var(--sl-fg);
|
|
9985
|
-
margin: 0;
|
|
9986
|
-
font-variation-settings: 'SOFT' 70;
|
|
9987
|
-
}
|
|
9988
|
-
.syntro-pdp-slot-failed-body {
|
|
9989
|
-
color: var(--sl-muted);
|
|
9990
|
-
font-size: 13.5px;
|
|
9991
|
-
margin: 0;
|
|
9992
|
-
line-height: 1.5;
|
|
9993
|
-
}
|
|
9994
|
-
|
|
9995
|
-
@media (max-width: 640px) {
|
|
9996
|
-
.syntro-pdp-slot-pending,
|
|
9997
|
-
.syntro-pdp-slot-failed {
|
|
9998
|
-
border-radius: 18px;
|
|
9999
|
-
padding: 24px 18px;
|
|
10000
|
-
min-height: 180px;
|
|
10001
|
-
}
|
|
10002
|
-
.syntro-pdp-slot-pending-label {
|
|
10003
|
-
font-size: 15.5px;
|
|
10004
|
-
}
|
|
10005
|
-
}
|
|
10006
|
-
|
|
10007
|
-
@keyframes syntro-pdp-slot-sweep {
|
|
10008
|
-
0% { transform: translateX(-100%); }
|
|
10009
|
-
100% { transform: translateX(100%); }
|
|
10010
|
-
}
|
|
10011
|
-
@keyframes syntro-pdp-slot-pulse {
|
|
10012
|
-
0%, 100% {
|
|
10013
|
-
opacity: 0.6;
|
|
10014
|
-
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-primary) 14%, transparent);
|
|
10015
|
-
}
|
|
10016
|
-
50% {
|
|
10017
|
-
opacity: 1;
|
|
10018
|
-
box-shadow: 0 0 0 8px color-mix(in srgb, var(--sl-primary) 26%, transparent);
|
|
10019
|
-
}
|
|
10020
|
-
}
|
|
10021
|
-
`;
|
|
10022
|
-
var PENDING_COPY = {
|
|
10023
|
-
"trending-news": "Composing this section\u2026",
|
|
10024
|
-
chart: "Drawing the comparison\u2026",
|
|
10025
|
-
qa: "Picking the questions worth answering\u2026",
|
|
10026
|
-
regional: "Locating you in time and place\u2026",
|
|
10027
|
-
"peer-feed": "Finding people like you\u2026"
|
|
10028
|
-
};
|
|
10029
|
-
var PENDING_FALLBACK = "Composing\u2026";
|
|
10030
|
-
var PdpSlotLit = class extends LitElement26 {
|
|
10031
|
-
constructor() {
|
|
10032
|
-
super(...arguments);
|
|
10033
|
-
/** DOM id the host's mutation runtime targets when appending the widget. */
|
|
10034
|
-
this.slotId = "";
|
|
10035
|
-
this.kind = "";
|
|
10036
|
-
this.state = "pending";
|
|
10037
|
-
}
|
|
10038
|
-
createRenderRoot() {
|
|
10039
|
-
return this;
|
|
10040
|
-
}
|
|
10041
|
-
connectedCallback() {
|
|
10042
|
-
super.connectedCallback();
|
|
10043
|
-
ensureSlotStyles();
|
|
10044
|
-
}
|
|
10045
|
-
willUpdate() {
|
|
10046
|
-
this.dataset.state = this.state;
|
|
10047
|
-
}
|
|
10048
|
-
render() {
|
|
10049
|
-
const pendingLabel = PENDING_COPY[this.kind] ?? PENDING_FALLBACK;
|
|
10050
|
-
return html26`
|
|
10051
|
-
<div class="syntro-pdp-slot" data-state=${this.state} data-kind=${this.kind}>
|
|
10052
|
-
<div
|
|
10053
|
-
class="syntro-pdp-slot-mount"
|
|
10054
|
-
id=${this.slotId || nothing10}
|
|
10055
|
-
data-pdp-slot=${this.kind}
|
|
10056
|
-
></div>
|
|
10057
|
-
<div class="syntro-pdp-slot-pending" aria-hidden=${this.state !== "pending"}>
|
|
10058
|
-
<div class="syntro-pdp-slot-pending-shimmer" aria-hidden="true"></div>
|
|
10059
|
-
<div class="syntro-pdp-slot-pending-row">
|
|
10060
|
-
<span class="syntro-pdp-slot-pending-dot" aria-hidden="true"></span>
|
|
10061
|
-
<p class="syntro-pdp-slot-pending-label">${pendingLabel}</p>
|
|
10062
|
-
</div>
|
|
10063
|
-
</div>
|
|
10064
|
-
<div class="syntro-pdp-slot-failed" aria-hidden=${this.state !== "failed"}>
|
|
10065
|
-
<p class="syntro-pdp-slot-failed-title">
|
|
10066
|
-
Personalized view couldn't load.
|
|
10067
|
-
</p>
|
|
10068
|
-
<p class="syntro-pdp-slot-failed-body">
|
|
10069
|
-
The standard page still has everything you need.
|
|
10070
|
-
</p>
|
|
10071
|
-
</div>
|
|
10072
|
-
</div>
|
|
10073
|
-
`;
|
|
10074
|
-
}
|
|
10075
|
-
};
|
|
10076
|
-
PdpSlotLit.properties = {
|
|
10077
|
-
slotId: { type: String, attribute: "slot-id" },
|
|
10078
|
-
kind: { type: String },
|
|
10079
|
-
state: { type: String, reflect: true }
|
|
10080
|
-
};
|
|
10081
|
-
if (typeof customElements !== "undefined" && !customElements.get("syntro-pdp-slot")) {
|
|
10082
|
-
customElements.define("syntro-pdp-slot", PdpSlotLit);
|
|
10083
|
-
}
|
|
10084
|
-
|
|
10085
10715
|
// src/widgets/PdpQaLit.ts
|
|
10086
10716
|
import { html as html27, LitElement as LitElement27, nothing as nothing11 } from "lit";
|
|
10087
10717
|
function ensureQaStyles() {
|
|
@@ -11050,6 +11680,8 @@ var runtime = {
|
|
|
11050
11680
|
var runtime_default = runtime;
|
|
11051
11681
|
|
|
11052
11682
|
export {
|
|
11683
|
+
detachSection,
|
|
11684
|
+
runTakeover,
|
|
11053
11685
|
_testing,
|
|
11054
11686
|
onActivate,
|
|
11055
11687
|
ProductCardMountable,
|
|
@@ -11089,4 +11721,4 @@ export {
|
|
|
11089
11721
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
11090
11722
|
*)
|
|
11091
11723
|
*/
|
|
11092
|
-
//# sourceMappingURL=chunk-
|
|
11724
|
+
//# sourceMappingURL=chunk-HV6QS4PQ.js.map
|