@vio-live/web-sdk 0.21.0 → 0.23.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/README.md +144 -0
- package/dist/chunk-25QECQDS.js +3 -0
- package/dist/{chunk-PZUOMOLF.js.map → chunk-25QECQDS.js.map} +1 -1
- package/dist/{chunk-WTVGVDZX.js → chunk-AMDI7KH3.js} +842 -75
- package/dist/chunk-AMDI7KH3.js.map +1 -0
- package/dist/{chunk-MRJR6DG5.js → chunk-COCHGJ2K.js} +376 -34
- package/dist/chunk-COCHGJ2K.js.map +1 -0
- package/dist/core/index.d.ts +358 -15
- package/dist/core/index.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/react/index.js.map +1 -1
- package/dist/{tokens-Dkbfcd1L.d.ts → tokens-DSYvrBsB.d.ts} +105 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-MRJR6DG5.js.map +0 -1
- package/dist/chunk-PZUOMOLF.js +0 -3
- package/dist/chunk-WTVGVDZX.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vio, __decorateClass, primaryImageUrl, displayPrice, getGlobalCurrency, ensureVippsButton, formatPrice, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, AdyenOriginError } from './chunk-
|
|
1
|
+
import { Vio, __decorateClass, primaryImageUrl, displayPrice, getGlobalCurrency, ensureVippsButton, formatPrice, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, AdyenOriginError, autoSlotDisplayName, autoSlotId, normalizeScope } from './chunk-AMDI7KH3.js';
|
|
2
2
|
import { LitElement, css, html } from 'lit';
|
|
3
3
|
import { property, state, query } from 'lit/decorators.js';
|
|
4
4
|
|
|
@@ -165,6 +165,124 @@ function applyVioTheme(overrides, target = typeof document !== "undefined" ? doc
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
+
|
|
169
|
+
// src/ui/slot-registration.ts
|
|
170
|
+
var SCOPE_ATTR = "vio-scope";
|
|
171
|
+
var SCOPE_NAME_ATTR = "vio-scope-name";
|
|
172
|
+
var SCOPE_DATA_ATTR = "data-vio-scope";
|
|
173
|
+
var SCOPE_NAME_DATA_ATTR = "data-vio-scope-name";
|
|
174
|
+
var SlotRegistration = class {
|
|
175
|
+
constructor(host, kind) {
|
|
176
|
+
this.host = host;
|
|
177
|
+
this.kind = kind;
|
|
178
|
+
this.identity = null;
|
|
179
|
+
this.release = null;
|
|
180
|
+
/** The element's position-based identity, fixed at connect time. */
|
|
181
|
+
this.position = null;
|
|
182
|
+
}
|
|
183
|
+
/** The effective slot id ('' before connect / after disconnect). */
|
|
184
|
+
get effective() {
|
|
185
|
+
return this.identity?.id ?? "";
|
|
186
|
+
}
|
|
187
|
+
/** The identity in effect, or null. */
|
|
188
|
+
get current() {
|
|
189
|
+
return this.identity;
|
|
190
|
+
}
|
|
191
|
+
/** On connect: fix scope + ordinal from the element's position, then register. */
|
|
192
|
+
connect(attrs) {
|
|
193
|
+
this.position = positionOf(this.host, attrs);
|
|
194
|
+
this.sync(attrs);
|
|
195
|
+
}
|
|
196
|
+
/** (Re)register when the attributes changed the identity. */
|
|
197
|
+
sync(attrs) {
|
|
198
|
+
if (this.position && scopeOf(this.host, attrs) !== this.position.scope) {
|
|
199
|
+
this.position = positionOf(this.host, attrs);
|
|
200
|
+
}
|
|
201
|
+
const next = this.resolve(attrs);
|
|
202
|
+
if (sameIdentity(next, this.identity)) return;
|
|
203
|
+
this.clear();
|
|
204
|
+
if (!next) return;
|
|
205
|
+
try {
|
|
206
|
+
this.release = Vio.registerSlot(next.id, next.displayName);
|
|
207
|
+
this.identity = next;
|
|
208
|
+
} catch {
|
|
209
|
+
this.release = null;
|
|
210
|
+
this.identity = null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** What the identity would be for these attributes (null before connect without a host id). */
|
|
214
|
+
resolve(attrs) {
|
|
215
|
+
const explicit = typeof attrs.vioSlot === "string" ? attrs.vioSlot.trim() : "";
|
|
216
|
+
const name = typeof attrs.vioSlotName === "string" && attrs.vioSlotName.trim() ? attrs.vioSlotName.trim() : void 0;
|
|
217
|
+
if (explicit) return { id: explicit, displayName: name, auto: false, scope: this.position?.scope ?? "" };
|
|
218
|
+
if (!this.position) return null;
|
|
219
|
+
const { scope, scopeName, ordinal } = this.position;
|
|
220
|
+
return {
|
|
221
|
+
id: autoSlotId(this.kind, ordinal, scope),
|
|
222
|
+
displayName: name ?? autoSlotDisplayName(this.kind, ordinal, scopeName),
|
|
223
|
+
auto: true,
|
|
224
|
+
scope
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** Unregister whatever is registered. */
|
|
228
|
+
clear() {
|
|
229
|
+
try {
|
|
230
|
+
this.release?.();
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
this.release = null;
|
|
234
|
+
this.identity = null;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
function sameIdentity(a, b) {
|
|
238
|
+
if (!a || !b) return a === b;
|
|
239
|
+
return a.id === b.id && a.displayName === b.displayName;
|
|
240
|
+
}
|
|
241
|
+
function scopeOf(el, attrs) {
|
|
242
|
+
const own = attrs && typeof attrs.vioScope === "string" ? attrs.vioScope : typeof el.vioScope === "string" ? el.vioScope ?? "" : el.getAttribute(SCOPE_ATTR) ?? "";
|
|
243
|
+
const value = normalizeScope(own) || normalizeScope(closestAcrossShadow(el, `[${SCOPE_DATA_ATTR}]`)?.getAttribute(SCOPE_DATA_ATTR));
|
|
244
|
+
return value;
|
|
245
|
+
}
|
|
246
|
+
function scopeNameOf(el, attrs) {
|
|
247
|
+
const own = attrs && typeof attrs.vioScopeName === "string" ? attrs.vioScopeName : typeof el.vioScopeName === "string" ? el.vioScopeName ?? "" : el.getAttribute(SCOPE_NAME_ATTR) ?? "";
|
|
248
|
+
const value = own.trim() || (closestAcrossShadow(el, `[${SCOPE_NAME_DATA_ATTR}]`)?.getAttribute(SCOPE_NAME_DATA_ATTR) ?? "").trim();
|
|
249
|
+
return value;
|
|
250
|
+
}
|
|
251
|
+
function positionOf(host, attrs) {
|
|
252
|
+
const scope = scopeOf(host, attrs);
|
|
253
|
+
const scopeName = scopeNameOf(host, attrs);
|
|
254
|
+
let ordinal = 0;
|
|
255
|
+
try {
|
|
256
|
+
const tag = host.tagName.toLowerCase();
|
|
257
|
+
const root = host.getRootNode();
|
|
258
|
+
const scopeRoot = root && typeof root.querySelectorAll === "function" ? root : typeof document !== "undefined" ? document : null;
|
|
259
|
+
if (scopeRoot) {
|
|
260
|
+
const peers = Array.from(scopeRoot.querySelectorAll(tag)).filter(
|
|
261
|
+
(el) => el === host || scopeOf(el) === scope
|
|
262
|
+
);
|
|
263
|
+
const index = peers.indexOf(host);
|
|
264
|
+
ordinal = index >= 0 ? index : 0;
|
|
265
|
+
}
|
|
266
|
+
} catch {
|
|
267
|
+
ordinal = 0;
|
|
268
|
+
}
|
|
269
|
+
return { scope, scopeName, ordinal };
|
|
270
|
+
}
|
|
271
|
+
function closestAcrossShadow(start, selector) {
|
|
272
|
+
try {
|
|
273
|
+
let node = start;
|
|
274
|
+
while (node) {
|
|
275
|
+
const found = typeof node.closest === "function" ? node.closest(selector) : null;
|
|
276
|
+
if (found) return found;
|
|
277
|
+
const root = node.getRootNode();
|
|
278
|
+
node = root && root !== node && typeof root.host === "object" ? root.host ?? null : null;
|
|
279
|
+
}
|
|
280
|
+
} catch {
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/ui/components/vio-product.ts
|
|
168
286
|
var VioProduct = class extends LitElement {
|
|
169
287
|
constructor() {
|
|
170
288
|
super(...arguments);
|
|
@@ -175,6 +293,13 @@ var VioProduct = class extends LitElement {
|
|
|
175
293
|
this.imageUrl = "";
|
|
176
294
|
this.productId = "";
|
|
177
295
|
this.sponsorId = "";
|
|
296
|
+
this.vioSlot = "";
|
|
297
|
+
this.vioSlotName = "";
|
|
298
|
+
this.vioScope = "";
|
|
299
|
+
this.vioScopeName = "";
|
|
300
|
+
this.vioContentId = "";
|
|
301
|
+
this.vioContentTitle = "";
|
|
302
|
+
this.slotRegistration = new SlotRegistration(this, "card");
|
|
178
303
|
this.hasVariants = false;
|
|
179
304
|
this.variants = void 0;
|
|
180
305
|
this.options = void 0;
|
|
@@ -184,6 +309,36 @@ var VioProduct = class extends LitElement {
|
|
|
184
309
|
this.justAdded = false;
|
|
185
310
|
this.boundCartChange = () => this.updateInCart();
|
|
186
311
|
}
|
|
312
|
+
/** The slot id in effect: `vio-slot`, else the auto id (`card-N`). Read-only. */
|
|
313
|
+
get effectiveSlot() {
|
|
314
|
+
return this.slotRegistration.effective;
|
|
315
|
+
}
|
|
316
|
+
/** The slot campaign's sponsor as the string the attributes use ('' when unknown). */
|
|
317
|
+
sponsorFromAttribution() {
|
|
318
|
+
const id = Vio.attribution(this.effectiveSlot).sponsorId;
|
|
319
|
+
return id !== void 0 ? String(id) : "";
|
|
320
|
+
}
|
|
321
|
+
slotAttributes() {
|
|
322
|
+
return {
|
|
323
|
+
vioSlot: this.vioSlot,
|
|
324
|
+
vioSlotName: this.vioSlotName,
|
|
325
|
+
vioScope: this.vioScope,
|
|
326
|
+
vioScopeName: this.vioScopeName
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* What every event carries for attribution (`Vio.attribution`): the place,
|
|
331
|
+
* its campaign and sponsor, and the content — overridden here when the host
|
|
332
|
+
* set `vio-content-id` / `vio-content-title` on this card.
|
|
333
|
+
*/
|
|
334
|
+
attribution() {
|
|
335
|
+
const base = Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId || void 0 });
|
|
336
|
+
return {
|
|
337
|
+
...base,
|
|
338
|
+
...this.vioContentId ? { contentId: this.vioContentId } : {},
|
|
339
|
+
...this.vioContentTitle ? { contentTitle: this.vioContentTitle } : {}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
187
342
|
static {
|
|
188
343
|
this.styles = css`
|
|
189
344
|
:host {
|
|
@@ -297,14 +452,19 @@ var VioProduct = class extends LitElement {
|
|
|
297
452
|
connectedCallback() {
|
|
298
453
|
super.connectedCallback();
|
|
299
454
|
this.updateInCart();
|
|
455
|
+
this.slotRegistration.connect(this.slotAttributes());
|
|
300
456
|
Vio.cart.addEventListener("change", this.boundCartChange);
|
|
301
457
|
}
|
|
302
458
|
disconnectedCallback() {
|
|
303
459
|
Vio.cart.removeEventListener("change", this.boundCartChange);
|
|
460
|
+
this.slotRegistration.clear();
|
|
304
461
|
super.disconnectedCallback();
|
|
305
462
|
}
|
|
306
463
|
updated(changed) {
|
|
307
464
|
if (changed.has("productId") || changed.has("sponsorId")) this.updateInCart();
|
|
465
|
+
if (changed.has("vioSlot") || changed.has("vioSlotName") || changed.has("vioScope") || changed.has("vioScopeName")) {
|
|
466
|
+
this.slotRegistration.sync(this.slotAttributes());
|
|
467
|
+
}
|
|
308
468
|
}
|
|
309
469
|
/** Reflect whether (and how many units of) this product sit in the cart. */
|
|
310
470
|
updateInCart() {
|
|
@@ -330,12 +490,14 @@ var VioProduct = class extends LitElement {
|
|
|
330
490
|
composed: true,
|
|
331
491
|
detail: {
|
|
332
492
|
productId: this.productId,
|
|
333
|
-
sponsorId: this.sponsorId,
|
|
334
493
|
brand: this.brand,
|
|
335
494
|
name: this.name,
|
|
336
495
|
price: this.price,
|
|
337
496
|
retailer: this.retailer,
|
|
338
|
-
imageUrl: this.imageUrl
|
|
497
|
+
imageUrl: this.imageUrl,
|
|
498
|
+
...this.attribution(),
|
|
499
|
+
// The host's sponsor-id wins; without one, the slot's campaign sponsor.
|
|
500
|
+
sponsorId: this.sponsorId || this.sponsorFromAttribution()
|
|
339
501
|
}
|
|
340
502
|
})
|
|
341
503
|
);
|
|
@@ -355,18 +517,28 @@ var VioProduct = class extends LitElement {
|
|
|
355
517
|
this.onClick();
|
|
356
518
|
return;
|
|
357
519
|
}
|
|
520
|
+
const attribution = this.attribution();
|
|
358
521
|
this.dispatchEvent(
|
|
359
522
|
new CustomEvent("vio:product-add", {
|
|
360
523
|
bubbles: true,
|
|
361
524
|
composed: true,
|
|
362
525
|
detail: {
|
|
363
526
|
productId: this.productId,
|
|
364
|
-
sponsorId: this.sponsorId,
|
|
365
527
|
brand: this.brand,
|
|
366
528
|
name: this.name,
|
|
367
529
|
price: this.price,
|
|
368
530
|
retailer: this.retailer,
|
|
369
|
-
imageUrl: this.imageUrl
|
|
531
|
+
imageUrl: this.imageUrl,
|
|
532
|
+
...attribution,
|
|
533
|
+
// The host's sponsor-id wins; without one, the slot's campaign sponsor.
|
|
534
|
+
sponsorId: this.sponsorId || this.sponsorFromAttribution(),
|
|
535
|
+
// The host adds to the cart: pass this through as `origin` so the
|
|
536
|
+
// purchase is attributed to this place and campaign.
|
|
537
|
+
origin: {
|
|
538
|
+
campaignId: attribution.campaignId,
|
|
539
|
+
slot: attribution.slot,
|
|
540
|
+
contentId: attribution.contentId
|
|
541
|
+
}
|
|
370
542
|
}
|
|
371
543
|
})
|
|
372
544
|
);
|
|
@@ -434,6 +606,24 @@ __decorateClass([
|
|
|
434
606
|
__decorateClass([
|
|
435
607
|
property({ type: String, attribute: "sponsor-id" })
|
|
436
608
|
], VioProduct.prototype, "sponsorId", 2);
|
|
609
|
+
__decorateClass([
|
|
610
|
+
property({ type: String, attribute: "vio-slot" })
|
|
611
|
+
], VioProduct.prototype, "vioSlot", 2);
|
|
612
|
+
__decorateClass([
|
|
613
|
+
property({ type: String, attribute: "vio-slot-name" })
|
|
614
|
+
], VioProduct.prototype, "vioSlotName", 2);
|
|
615
|
+
__decorateClass([
|
|
616
|
+
property({ type: String, attribute: "vio-scope" })
|
|
617
|
+
], VioProduct.prototype, "vioScope", 2);
|
|
618
|
+
__decorateClass([
|
|
619
|
+
property({ type: String, attribute: "vio-scope-name" })
|
|
620
|
+
], VioProduct.prototype, "vioScopeName", 2);
|
|
621
|
+
__decorateClass([
|
|
622
|
+
property({ type: String, attribute: "vio-content-id" })
|
|
623
|
+
], VioProduct.prototype, "vioContentId", 2);
|
|
624
|
+
__decorateClass([
|
|
625
|
+
property({ type: String, attribute: "vio-content-title" })
|
|
626
|
+
], VioProduct.prototype, "vioContentTitle", 2);
|
|
437
627
|
__decorateClass([
|
|
438
628
|
property({ type: Boolean, attribute: "has-variants" })
|
|
439
629
|
], VioProduct.prototype, "hasVariants", 2);
|
|
@@ -468,6 +658,13 @@ var VioProductCarousel = class extends LitElement {
|
|
|
468
658
|
this.sponsorId = 0;
|
|
469
659
|
this.productRefs = "";
|
|
470
660
|
this.currency = "NOK";
|
|
661
|
+
this.vioSlot = "";
|
|
662
|
+
this.vioSlotName = "";
|
|
663
|
+
this.vioScope = "";
|
|
664
|
+
this.vioScopeName = "";
|
|
665
|
+
this.vioContentId = "";
|
|
666
|
+
this.vioContentTitle = "";
|
|
667
|
+
this.slotRegistration = new SlotRegistration(this, "carousel");
|
|
471
668
|
this.fetched = null;
|
|
472
669
|
this.isLoading = false;
|
|
473
670
|
this.fetchError = "";
|
|
@@ -479,6 +676,27 @@ var VioProductCarousel = class extends LitElement {
|
|
|
479
676
|
this.impressed = false;
|
|
480
677
|
this.listTracked = false;
|
|
481
678
|
}
|
|
679
|
+
/** The slot id in effect: `vio-slot`, else the auto id (`carousel-N`). Read-only. */
|
|
680
|
+
get effectiveSlot() {
|
|
681
|
+
return this.slotRegistration.effective;
|
|
682
|
+
}
|
|
683
|
+
slotAttributes() {
|
|
684
|
+
return {
|
|
685
|
+
vioSlot: this.vioSlot,
|
|
686
|
+
vioSlotName: this.vioSlotName,
|
|
687
|
+
vioScope: this.vioScope,
|
|
688
|
+
vioScopeName: this.vioScopeName
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
/** Attribution every analytics event of this carousel carries (`Vio.attribution` + the content overrides). */
|
|
692
|
+
attribution() {
|
|
693
|
+
const base = Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0 });
|
|
694
|
+
return {
|
|
695
|
+
...base,
|
|
696
|
+
...this.vioContentId ? { contentId: this.vioContentId } : {},
|
|
697
|
+
...this.vioContentTitle ? { contentTitle: this.vioContentTitle } : {}
|
|
698
|
+
};
|
|
699
|
+
}
|
|
482
700
|
static {
|
|
483
701
|
this.styles = css`
|
|
484
702
|
:host {
|
|
@@ -626,6 +844,7 @@ var VioProductCarousel = class extends LitElement {
|
|
|
626
844
|
}
|
|
627
845
|
connectedCallback() {
|
|
628
846
|
super.connectedCallback();
|
|
847
|
+
this.slotRegistration.connect(this.slotAttributes());
|
|
629
848
|
this.observeForAnalytics();
|
|
630
849
|
if (this.productRefs.trim() || this.productIds.trim()) {
|
|
631
850
|
void this.autoFetch();
|
|
@@ -634,14 +853,28 @@ var VioProductCarousel = class extends LitElement {
|
|
|
634
853
|
disconnectedCallback() {
|
|
635
854
|
this.unobserveImpression?.();
|
|
636
855
|
this.unobserveImpression = null;
|
|
856
|
+
this.slotRegistration.clear();
|
|
637
857
|
super.disconnectedCallback();
|
|
638
858
|
}
|
|
639
859
|
updated(changed) {
|
|
640
|
-
|
|
860
|
+
if (changed.has("vioSlot") || changed.has("vioSlotName") || changed.has("vioScope") || changed.has("vioScopeName")) {
|
|
861
|
+
this.slotRegistration.sync(this.slotAttributes());
|
|
862
|
+
}
|
|
863
|
+
const propChanged = changed.has("productRefs") || changed.has("productIds") || changed.has("commerceKey") || changed.has("sponsorId") || changed.has("vioSlot");
|
|
641
864
|
if (propChanged && (this.productRefs.trim() || this.productIds.trim())) {
|
|
642
865
|
void this.autoFetch();
|
|
643
866
|
}
|
|
644
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* The sponsor of this carousel: the host's `sponsor-id`, else the primary
|
|
870
|
+
* sponsor of the campaign the slot shows (ADR-0034 — "the campaign of the
|
|
871
|
+
* block is its sponsor"), else 0 (unknown).
|
|
872
|
+
*/
|
|
873
|
+
effectiveSponsorId() {
|
|
874
|
+
if (this.sponsorId > 0) return this.sponsorId;
|
|
875
|
+
const fromSlot = Number(Vio.campaignForSlot(this.effectiveSlot || null)?.primarySponsor?.id);
|
|
876
|
+
return Number.isFinite(fromSlot) && fromSlot > 0 ? fromSlot : 0;
|
|
877
|
+
}
|
|
645
878
|
async autoFetch() {
|
|
646
879
|
if (!Vio.isInitialized) {
|
|
647
880
|
this.fetchError = "Vio not initialized \u2014 call Vio.init({ apiKey }) first";
|
|
@@ -650,7 +883,14 @@ var VioProductCarousel = class extends LitElement {
|
|
|
650
883
|
this.isLoading = true;
|
|
651
884
|
this.fetchError = "";
|
|
652
885
|
try {
|
|
653
|
-
|
|
886
|
+
if (this.productRefs.trim() === "" && !this.commerceKey && this.sponsorId <= 0 && !Vio.bootstrapCache) {
|
|
887
|
+
try {
|
|
888
|
+
await Vio.bootstrap();
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const sponsorId = this.effectiveSponsorId();
|
|
893
|
+
const refs = this.productRefs.trim() ? this.parseRefs(this.productRefs) : this.productIds.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !Number.isNaN(n)).map((id) => ({ sponsorId, productId: id }));
|
|
654
894
|
if (refs.length === 0) {
|
|
655
895
|
this.fetched = [];
|
|
656
896
|
return;
|
|
@@ -662,23 +902,23 @@ var VioProductCarousel = class extends LitElement {
|
|
|
662
902
|
bySponsor.set(r.sponsorId, arr);
|
|
663
903
|
}
|
|
664
904
|
const fetched = await Promise.all(
|
|
665
|
-
Array.from(bySponsor.entries()).map(async ([
|
|
666
|
-
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(
|
|
905
|
+
Array.from(bySponsor.entries()).map(async ([sponsorId2, ids]) => {
|
|
906
|
+
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(sponsorId2);
|
|
667
907
|
const products = await commerce.channel.product.getByIds({
|
|
668
908
|
product_ids: ids,
|
|
669
909
|
currency: this.currency,
|
|
670
910
|
image_size: "large"
|
|
671
911
|
});
|
|
672
|
-
return { sponsorId, products };
|
|
912
|
+
return { sponsorId: sponsorId2, products };
|
|
673
913
|
})
|
|
674
914
|
);
|
|
675
915
|
const lookup = /* @__PURE__ */ new Map();
|
|
676
|
-
for (const { sponsorId, products } of fetched) {
|
|
677
|
-
for (const p of products) lookup.set(`${
|
|
916
|
+
for (const { sponsorId: sponsorId2, products } of fetched) {
|
|
917
|
+
for (const p of products) lookup.set(`${sponsorId2}:${p.id}`, p);
|
|
678
918
|
}
|
|
679
|
-
this.fetched = refs.map(({ sponsorId, productId }) => {
|
|
680
|
-
const product = lookup.get(`${
|
|
681
|
-
return product ? { product, sponsorId } : null;
|
|
919
|
+
this.fetched = refs.map(({ sponsorId: sponsorId2, productId }) => {
|
|
920
|
+
const product = lookup.get(`${sponsorId2}:${productId}`);
|
|
921
|
+
return product ? { product, sponsorId: sponsorId2 } : null;
|
|
682
922
|
}).filter((x) => x !== null);
|
|
683
923
|
this.maybeTrackList();
|
|
684
924
|
} catch (err) {
|
|
@@ -695,10 +935,12 @@ var VioProductCarousel = class extends LitElement {
|
|
|
695
935
|
{
|
|
696
936
|
sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0,
|
|
697
937
|
componentTemplateId: "product-carousel",
|
|
698
|
-
|
|
938
|
+
// The slot is the real location id; the label only stands in for it.
|
|
939
|
+
locationId: this.effectiveSlot || this.label || void 0,
|
|
940
|
+
...this.attribution()
|
|
699
941
|
},
|
|
700
942
|
{
|
|
701
|
-
key: `carousel:${this.label || this.productIds || this.productRefs || "default"}`,
|
|
943
|
+
key: `carousel:${this.effectiveSlot || this.label || this.productIds || this.productRefs || "default"}`,
|
|
702
944
|
onImpression: () => {
|
|
703
945
|
this.impressed = true;
|
|
704
946
|
this.maybeTrackList();
|
|
@@ -716,14 +958,16 @@ var VioProductCarousel = class extends LitElement {
|
|
|
716
958
|
if (entries.length === 0) return;
|
|
717
959
|
this.listTracked = true;
|
|
718
960
|
try {
|
|
961
|
+
const sponsorId = this.effectiveSponsorId();
|
|
719
962
|
Vio.analytics.track("view_item_list", {
|
|
720
963
|
context: {
|
|
721
|
-
sponsorId:
|
|
964
|
+
sponsorId: sponsorId > 0 ? sponsorId : void 0,
|
|
722
965
|
componentTemplateId: "product-carousel",
|
|
723
|
-
locationId: this.label || void 0
|
|
966
|
+
locationId: this.effectiveSlot || this.label || void 0,
|
|
967
|
+
...this.attribution()
|
|
724
968
|
},
|
|
725
969
|
commerce: {
|
|
726
|
-
items: entries.map(({ product, sponsorId }) => ({
|
|
970
|
+
items: entries.map(({ product, sponsorId: sponsorId2 }) => ({
|
|
727
971
|
productId: product.id,
|
|
728
972
|
name: product.title,
|
|
729
973
|
price: Number(product.price?.amount_incl_taxes ?? product.price?.amount) || void 0
|
|
@@ -776,6 +1020,9 @@ var VioProductCarousel = class extends LitElement {
|
|
|
776
1020
|
retailer=${retailer}
|
|
777
1021
|
image-url=${img}
|
|
778
1022
|
?has-variants=${(p.variants?.length ?? 0) > 1}
|
|
1023
|
+
.vioSlot=${this.effectiveSlot}
|
|
1024
|
+
.vioContentId=${this.vioContentId}
|
|
1025
|
+
.vioContentTitle=${this.vioContentTitle}
|
|
779
1026
|
></vio-product>
|
|
780
1027
|
`;
|
|
781
1028
|
})}`;
|
|
@@ -845,6 +1092,24 @@ __decorateClass([
|
|
|
845
1092
|
__decorateClass([
|
|
846
1093
|
property({ type: String })
|
|
847
1094
|
], VioProductCarousel.prototype, "currency", 2);
|
|
1095
|
+
__decorateClass([
|
|
1096
|
+
property({ type: String, attribute: "vio-slot" })
|
|
1097
|
+
], VioProductCarousel.prototype, "vioSlot", 2);
|
|
1098
|
+
__decorateClass([
|
|
1099
|
+
property({ type: String, attribute: "vio-slot-name" })
|
|
1100
|
+
], VioProductCarousel.prototype, "vioSlotName", 2);
|
|
1101
|
+
__decorateClass([
|
|
1102
|
+
property({ type: String, attribute: "vio-scope" })
|
|
1103
|
+
], VioProductCarousel.prototype, "vioScope", 2);
|
|
1104
|
+
__decorateClass([
|
|
1105
|
+
property({ type: String, attribute: "vio-scope-name" })
|
|
1106
|
+
], VioProductCarousel.prototype, "vioScopeName", 2);
|
|
1107
|
+
__decorateClass([
|
|
1108
|
+
property({ type: String, attribute: "vio-content-id" })
|
|
1109
|
+
], VioProductCarousel.prototype, "vioContentId", 2);
|
|
1110
|
+
__decorateClass([
|
|
1111
|
+
property({ type: String, attribute: "vio-content-title" })
|
|
1112
|
+
], VioProductCarousel.prototype, "vioContentTitle", 2);
|
|
848
1113
|
__decorateClass([
|
|
849
1114
|
query(".scroller")
|
|
850
1115
|
], VioProductCarousel.prototype, "scroller", 2);
|
|
@@ -1083,6 +1348,17 @@ var VioProductDetail = class extends LitElement {
|
|
|
1083
1348
|
this.sponsorId = 0;
|
|
1084
1349
|
this.autoOpen = true;
|
|
1085
1350
|
this.currency = "NOK";
|
|
1351
|
+
this.vioSlot = "";
|
|
1352
|
+
this.vioSlotName = "";
|
|
1353
|
+
this.vioScope = "";
|
|
1354
|
+
this.vioScopeName = "";
|
|
1355
|
+
this.vioContentId = "";
|
|
1356
|
+
this.vioContentTitle = "";
|
|
1357
|
+
this.slotRegistration = new SlotRegistration(this, "detail");
|
|
1358
|
+
/** What the click that opened the detail carried ('' when nothing). */
|
|
1359
|
+
this.eventSlot = "";
|
|
1360
|
+
this.eventContentId = "";
|
|
1361
|
+
this.eventContentTitle = "";
|
|
1086
1362
|
this.product = null;
|
|
1087
1363
|
this.sellerName = null;
|
|
1088
1364
|
this.sellerSettled = false;
|
|
@@ -1113,8 +1389,16 @@ var VioProductDetail = class extends LitElement {
|
|
|
1113
1389
|
const ev = e;
|
|
1114
1390
|
const productIdNum = parseInt(ev.detail.productId, 10);
|
|
1115
1391
|
if (Number.isNaN(productIdNum)) return;
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1392
|
+
const slot = typeof ev.detail.slot === "string" ? ev.detail.slot.trim() : "";
|
|
1393
|
+
let sponsorIdNum = parseInt(ev.detail.sponsorId, 10);
|
|
1394
|
+
if (Number.isNaN(sponsorIdNum) || sponsorIdNum <= 0) {
|
|
1395
|
+
const fromSlot = Number(Vio.campaignForSlot(slot || this.effectiveSlot || null)?.primarySponsor?.id);
|
|
1396
|
+
if (!Number.isFinite(fromSlot) || fromSlot <= 0) return;
|
|
1397
|
+
sponsorIdNum = fromSlot;
|
|
1398
|
+
}
|
|
1399
|
+
this.eventSlot = slot;
|
|
1400
|
+
this.eventContentId = ev.detail.contentId !== void 0 && ev.detail.contentId !== null ? String(ev.detail.contentId).trim() : "";
|
|
1401
|
+
this.eventContentTitle = typeof ev.detail.contentTitle === "string" ? ev.detail.contentTitle.trim() : "";
|
|
1118
1402
|
this.productId = ev.detail.productId;
|
|
1119
1403
|
this.sponsorId = sponsorIdNum;
|
|
1120
1404
|
this.currency = ev.detail.currency || getGlobalCurrency();
|
|
@@ -1122,6 +1406,33 @@ var VioProductDetail = class extends LitElement {
|
|
|
1122
1406
|
void this.fetchProduct();
|
|
1123
1407
|
};
|
|
1124
1408
|
}
|
|
1409
|
+
/** The slot id in effect for this element: `vio-slot`, else the auto id (`detail-N`). Read-only. */
|
|
1410
|
+
get effectiveSlot() {
|
|
1411
|
+
return this.slotRegistration.effective;
|
|
1412
|
+
}
|
|
1413
|
+
/** The slot the open product is attributed to: the opening card's, else this element's. */
|
|
1414
|
+
get activeSlot() {
|
|
1415
|
+
return this.eventSlot || this.effectiveSlot;
|
|
1416
|
+
}
|
|
1417
|
+
slotAttributes() {
|
|
1418
|
+
return {
|
|
1419
|
+
vioSlot: this.vioSlot,
|
|
1420
|
+
vioSlotName: this.vioSlotName,
|
|
1421
|
+
vioScope: this.vioScope,
|
|
1422
|
+
vioScopeName: this.vioScopeName
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
/** Attribution every event of the open product carries (`Vio.attribution` of the opening card's slot, else this element's). */
|
|
1426
|
+
attribution() {
|
|
1427
|
+
const base = Vio.attribution(this.activeSlot, { sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0 });
|
|
1428
|
+
const contentId = this.eventContentId || this.vioContentId;
|
|
1429
|
+
const contentTitle = this.eventContentTitle || this.vioContentTitle;
|
|
1430
|
+
return {
|
|
1431
|
+
...base,
|
|
1432
|
+
...contentId ? { contentId } : {},
|
|
1433
|
+
...contentTitle ? { contentTitle } : {}
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1125
1436
|
static {
|
|
1126
1437
|
this.styles = css`
|
|
1127
1438
|
:host { display: contents; }
|
|
@@ -1569,15 +1880,20 @@ var VioProductDetail = class extends LitElement {
|
|
|
1569
1880
|
}
|
|
1570
1881
|
connectedCallback() {
|
|
1571
1882
|
super.connectedCallback();
|
|
1883
|
+
this.slotRegistration.connect(this.slotAttributes());
|
|
1572
1884
|
void this.loadVippsButton();
|
|
1573
1885
|
document.addEventListener("vio:product-click", this.boundProductClick);
|
|
1574
1886
|
}
|
|
1575
1887
|
disconnectedCallback() {
|
|
1576
1888
|
document.removeEventListener("vio:product-click", this.boundProductClick);
|
|
1889
|
+
this.slotRegistration.clear();
|
|
1577
1890
|
super.disconnectedCallback();
|
|
1578
1891
|
}
|
|
1579
1892
|
updated(changed) {
|
|
1580
1893
|
if (changed.has("open")) this.dialogFocus.update(this.open);
|
|
1894
|
+
if (changed.has("vioSlot") || changed.has("vioSlotName") || changed.has("vioScope") || changed.has("vioScopeName")) {
|
|
1895
|
+
this.slotRegistration.sync(this.slotAttributes());
|
|
1896
|
+
}
|
|
1581
1897
|
}
|
|
1582
1898
|
show() {
|
|
1583
1899
|
this.open = true;
|
|
@@ -1644,7 +1960,8 @@ var VioProductDetail = class extends LitElement {
|
|
|
1644
1960
|
Vio.analytics.track("view_item", {
|
|
1645
1961
|
context: {
|
|
1646
1962
|
sponsorId: this.sponsorId > 0 ? Number(this.sponsorId) : void 0,
|
|
1647
|
-
componentTemplateId: "product-detail"
|
|
1963
|
+
componentTemplateId: "product-detail",
|
|
1964
|
+
...this.attribution()
|
|
1648
1965
|
},
|
|
1649
1966
|
commerce: {
|
|
1650
1967
|
items: [
|
|
@@ -1684,7 +2001,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
1684
2001
|
}
|
|
1685
2002
|
/** Which buy buttons to render — backend-configured per sponsor. */
|
|
1686
2003
|
async loadAvailablePaymentMethods() {
|
|
1687
|
-
const spId = this.sponsorId || globalThis.__VIO_SPONSOR_ID__;
|
|
2004
|
+
const spId = this.sponsorId || Number(Vio.campaignForSlot(this.activeSlot || null)?.primarySponsor?.id) || globalThis.__VIO_SPONSOR_ID__;
|
|
1688
2005
|
if (!spId) return;
|
|
1689
2006
|
try {
|
|
1690
2007
|
const methods = await Vio.checkout.getAvailablePaymentMethods(spId);
|
|
@@ -1966,12 +2283,14 @@ var VioProductDetail = class extends LitElement {
|
|
|
1966
2283
|
const sponsor = Vio.bootstrapCache?.primarySponsor;
|
|
1967
2284
|
const secondaries = Vio.bootstrapCache?.secondarySponsors ?? [];
|
|
1968
2285
|
const sponsorName = sponsor?.id === this.sponsorId ? sponsor.name : secondaries.find((s) => s.id === this.sponsorId)?.name;
|
|
2286
|
+
const { campaignId, slot, contentId } = this.attribution();
|
|
1969
2287
|
Vio.cart.addProduct({
|
|
1970
2288
|
product: this.product,
|
|
1971
2289
|
sponsorId: this.sponsorId,
|
|
1972
2290
|
sponsorName,
|
|
1973
2291
|
quantity: this.quantity,
|
|
1974
|
-
variantId: variant?.id
|
|
2292
|
+
variantId: variant?.id,
|
|
2293
|
+
origin: { campaignId, slot, contentId }
|
|
1975
2294
|
});
|
|
1976
2295
|
return variant?.id;
|
|
1977
2296
|
}
|
|
@@ -1988,7 +2307,8 @@ var VioProductDetail = class extends LitElement {
|
|
|
1988
2307
|
productId: this.product.id,
|
|
1989
2308
|
sponsorId: this.sponsorId,
|
|
1990
2309
|
quantity: this.quantity,
|
|
1991
|
-
variantId
|
|
2310
|
+
variantId,
|
|
2311
|
+
...this.attribution()
|
|
1992
2312
|
}
|
|
1993
2313
|
})
|
|
1994
2314
|
);
|
|
@@ -2013,7 +2333,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
2013
2333
|
new CustomEvent("vio:checkout-open", {
|
|
2014
2334
|
bubbles: true,
|
|
2015
2335
|
composed: true,
|
|
2016
|
-
detail: { sponsorId: this.sponsorId, paymentMethod: "klarna", express: true }
|
|
2336
|
+
detail: { sponsorId: this.sponsorId, paymentMethod: "klarna", express: true, ...this.attribution() }
|
|
2017
2337
|
})
|
|
2018
2338
|
);
|
|
2019
2339
|
} finally {
|
|
@@ -2043,7 +2363,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
2043
2363
|
new CustomEvent("vio:checkout-open", {
|
|
2044
2364
|
bubbles: true,
|
|
2045
2365
|
composed: true,
|
|
2046
|
-
detail: { sponsorId: this.sponsorId, express: false }
|
|
2366
|
+
detail: { sponsorId: this.sponsorId, express: false, ...this.attribution() }
|
|
2047
2367
|
})
|
|
2048
2368
|
);
|
|
2049
2369
|
}
|
|
@@ -2079,7 +2399,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
2079
2399
|
new CustomEvent("vio:checkout-open", {
|
|
2080
2400
|
bubbles: true,
|
|
2081
2401
|
composed: true,
|
|
2082
|
-
detail: { sponsorId: this.sponsorId, paymentMethod: "vipps", express: false }
|
|
2402
|
+
detail: { sponsorId: this.sponsorId, paymentMethod: "vipps", express: false, ...this.attribution() }
|
|
2083
2403
|
})
|
|
2084
2404
|
);
|
|
2085
2405
|
}
|
|
@@ -2092,7 +2412,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
2092
2412
|
new CustomEvent("vio:checkout-open", {
|
|
2093
2413
|
bubbles: true,
|
|
2094
2414
|
composed: true,
|
|
2095
|
-
detail: { sponsorId: this.sponsorId, paymentMethod: "stripe", express: false }
|
|
2415
|
+
detail: { sponsorId: this.sponsorId, paymentMethod: "stripe", express: false, ...this.attribution() }
|
|
2096
2416
|
})
|
|
2097
2417
|
);
|
|
2098
2418
|
}
|
|
@@ -2375,6 +2695,24 @@ __decorateClass([
|
|
|
2375
2695
|
__decorateClass([
|
|
2376
2696
|
property({ type: String })
|
|
2377
2697
|
], VioProductDetail.prototype, "currency", 2);
|
|
2698
|
+
__decorateClass([
|
|
2699
|
+
property({ type: String, attribute: "vio-slot" })
|
|
2700
|
+
], VioProductDetail.prototype, "vioSlot", 2);
|
|
2701
|
+
__decorateClass([
|
|
2702
|
+
property({ type: String, attribute: "vio-slot-name" })
|
|
2703
|
+
], VioProductDetail.prototype, "vioSlotName", 2);
|
|
2704
|
+
__decorateClass([
|
|
2705
|
+
property({ type: String, attribute: "vio-scope" })
|
|
2706
|
+
], VioProductDetail.prototype, "vioScope", 2);
|
|
2707
|
+
__decorateClass([
|
|
2708
|
+
property({ type: String, attribute: "vio-scope-name" })
|
|
2709
|
+
], VioProductDetail.prototype, "vioScopeName", 2);
|
|
2710
|
+
__decorateClass([
|
|
2711
|
+
property({ type: String, attribute: "vio-content-id" })
|
|
2712
|
+
], VioProductDetail.prototype, "vioContentId", 2);
|
|
2713
|
+
__decorateClass([
|
|
2714
|
+
property({ type: String, attribute: "vio-content-title" })
|
|
2715
|
+
], VioProductDetail.prototype, "vioContentTitle", 2);
|
|
2378
2716
|
__decorateClass([
|
|
2379
2717
|
state()
|
|
2380
2718
|
], VioProductDetail.prototype, "product", 2);
|
|
@@ -3001,6 +3339,7 @@ var VioCart = class extends LitElement {
|
|
|
3001
3339
|
async startVippsExpressOrCheckout(sponsorId) {
|
|
3002
3340
|
let fallback = true;
|
|
3003
3341
|
try {
|
|
3342
|
+
await Vio.cart.waitForCartMutations(sponsorId);
|
|
3004
3343
|
if (!await Vio.checkout.getVippsExpressEnabled(sponsorId)) throw new Error("express off");
|
|
3005
3344
|
const res = await Vio.checkout.startVippsExpress(sponsorId);
|
|
3006
3345
|
fallback = !res?.payment_url;
|
|
@@ -3042,11 +3381,14 @@ var VioCart = class extends LitElement {
|
|
|
3042
3381
|
for (const cart of this.carts.values()) return cart.currency;
|
|
3043
3382
|
return "NOK";
|
|
3044
3383
|
}
|
|
3384
|
+
// A delta on the manager's live quantity, not a target computed from this
|
|
3385
|
+
// render's snapshot: two clicks before Lit re-renders used to ask for the
|
|
3386
|
+
// same quantity twice (Alan, 2026-10-15).
|
|
3045
3387
|
onIncrement(item) {
|
|
3046
|
-
Vio.cart.
|
|
3388
|
+
Vio.cart.adjustQuantity(item.id, item.sponsorId, 1);
|
|
3047
3389
|
}
|
|
3048
3390
|
onDecrement(item) {
|
|
3049
|
-
Vio.cart.
|
|
3391
|
+
Vio.cart.adjustQuantity(item.id, item.sponsorId, -1);
|
|
3050
3392
|
}
|
|
3051
3393
|
onRemove(item) {
|
|
3052
3394
|
Vio.cart.removeItem(item.id, item.sponsorId);
|
|
@@ -6665,5 +7007,5 @@ function registerVioElements() {
|
|
|
6665
7007
|
}
|
|
6666
7008
|
|
|
6667
7009
|
export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
|
|
6668
|
-
//# sourceMappingURL=chunk-
|
|
6669
|
-
//# sourceMappingURL=chunk-
|
|
7010
|
+
//# sourceMappingURL=chunk-COCHGJ2K.js.map
|
|
7011
|
+
//# sourceMappingURL=chunk-COCHGJ2K.js.map
|