@vio-live/web-sdk 0.23.0 → 0.23.1

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.
@@ -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, autoSlotDisplayName, autoSlotId, normalizeScope } from './chunk-AMDI7KH3.js';
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, normalizeSlotId, autoSlotDisplayName, autoSlotId, normalizeScope } from './chunk-BRJMT7P4.js';
2
2
  import { LitElement, css, html } from 'lit';
3
3
  import { property, state, query } from 'lit/decorators.js';
4
4
 
@@ -171,61 +171,77 @@ var SCOPE_ATTR = "vio-scope";
171
171
  var SCOPE_NAME_ATTR = "vio-scope-name";
172
172
  var SCOPE_DATA_ATTR = "data-vio-scope";
173
173
  var SCOPE_NAME_DATA_ATTR = "data-vio-scope-name";
174
+ var liveAutoIds = (() => {
175
+ const g = globalThis;
176
+ return g.__VIO_LIVE_SLOT_IDS__ ?? (g.__VIO_LIVE_SLOT_IDS__ = /* @__PURE__ */ new Map());
177
+ })();
174
178
  var SlotRegistration = class {
175
179
  constructor(host, kind) {
176
180
  this.host = host;
177
181
  this.kind = kind;
178
182
  this.identity = null;
179
183
  this.release = null;
180
- /** The element's position-based identity, fixed at connect time. */
181
- this.position = null;
184
+ /** The auto identity held (its number is kept while the element lives). */
185
+ this.auto = null;
186
+ /** Set by connect(); the scope label is read then too. */
187
+ this.connected = false;
188
+ this.scope = "";
189
+ this.scopeName = "";
182
190
  }
183
191
  /** The effective slot id ('' before connect / after disconnect). */
184
192
  get effective() {
185
193
  return this.identity?.id ?? "";
186
194
  }
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. */
195
+ /** On connect: read the scope from the DOM, then register. */
192
196
  connect(attrs) {
193
- this.position = positionOf(this.host, attrs);
197
+ this.connected = true;
198
+ this.scope = scopeOf(this.host, attrs);
199
+ this.scopeName = scopeNameOf(this.host, attrs);
194
200
  this.sync(attrs);
195
201
  }
196
202
  /** (Re)register when the attributes changed the identity. */
197
203
  sync(attrs) {
198
- if (this.position && scopeOf(this.host, attrs) !== this.position.scope) {
199
- this.position = positionOf(this.host, attrs);
204
+ if (!this.connected) return;
205
+ const scope = scopeOf(this.host, attrs);
206
+ if (scope !== this.scope) {
207
+ this.scope = scope;
208
+ this.scopeName = scopeNameOf(this.host, attrs);
209
+ this.releaseAuto();
210
+ } else {
211
+ const scopeName = scopeNameOf(this.host, attrs);
212
+ if (scopeName !== this.scopeName) this.scopeName = scopeName;
200
213
  }
201
214
  const next = this.resolve(attrs);
202
215
  if (sameIdentity(next, this.identity)) return;
203
- this.clear();
216
+ this.unregister();
204
217
  if (!next) return;
205
218
  try {
206
- this.release = Vio.registerSlot(next.id, next.displayName);
219
+ this.release = typeof Vio.registerSlot === "function" ? Vio.registerSlot(next.id, next.displayName) : null;
207
220
  this.identity = next;
208
221
  } catch {
209
222
  this.release = null;
210
223
  this.identity = null;
211
224
  }
212
225
  }
213
- /** What the identity would be for these attributes (null before connect without a host id). */
226
+ /** What the identity is for these attributes (null before connect without a host id). */
214
227
  resolve(attrs) {
215
- const explicit = typeof attrs.vioSlot === "string" ? attrs.vioSlot.trim() : "";
228
+ const explicit = normalizeSlotId(attrs.vioSlot);
216
229
  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
- };
230
+ if (explicit) {
231
+ this.releaseAuto();
232
+ return { id: explicit, displayName: name };
233
+ }
234
+ if (!this.connected) return null;
235
+ const auto = this.claimAuto();
236
+ return { id: auto.id, displayName: name ?? autoSlotDisplayName(this.kind, auto.number - 1, this.scopeName) };
226
237
  }
227
- /** Unregister whatever is registered. */
238
+ /** Unregister whatever is registered and free the auto number. */
228
239
  clear() {
240
+ this.unregister();
241
+ this.releaseAuto();
242
+ this.connected = false;
243
+ }
244
+ unregister() {
229
245
  try {
230
246
  this.release?.();
231
247
  } catch {
@@ -233,6 +249,29 @@ var SlotRegistration = class {
233
249
  this.release = null;
234
250
  this.identity = null;
235
251
  }
252
+ /** The element's auto id: the one it already holds, else the first free number. */
253
+ claimAuto() {
254
+ if (this.auto && this.auto.scope === this.scope) return this.auto;
255
+ this.releaseAuto();
256
+ for (let number = 1; ; number++) {
257
+ const id = autoSlotId(this.kind, number - 1, this.scope);
258
+ const holders = liveAutoIds.get(id);
259
+ if (!holders || holders.size === 0 || holders.size === 1 && holders.has(this.host)) {
260
+ const set = holders ?? /* @__PURE__ */ new Set();
261
+ set.add(this.host);
262
+ liveAutoIds.set(id, set);
263
+ this.auto = { id, scope: this.scope, number };
264
+ return this.auto;
265
+ }
266
+ }
267
+ }
268
+ releaseAuto() {
269
+ if (!this.auto) return;
270
+ const holders = liveAutoIds.get(this.auto.id);
271
+ holders?.delete(this.host);
272
+ if (holders && holders.size === 0) liveAutoIds.delete(this.auto.id);
273
+ this.auto = null;
274
+ }
236
275
  };
237
276
  function sameIdentity(a, b) {
238
277
  if (!a || !b) return a === b;
@@ -240,33 +279,11 @@ function sameIdentity(a, b) {
240
279
  }
241
280
  function scopeOf(el, attrs) {
242
281
  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;
282
+ return normalizeScope(own) || normalizeScope(closestAcrossShadow(el, `[${SCOPE_DATA_ATTR}]`)?.getAttribute(SCOPE_DATA_ATTR));
245
283
  }
246
284
  function scopeNameOf(el, attrs) {
247
285
  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 };
286
+ return own.trim() || (closestAcrossShadow(el, `[${SCOPE_NAME_DATA_ATTR}]`)?.getAttribute(SCOPE_NAME_DATA_ATTR) ?? "").trim();
270
287
  }
271
288
  function closestAcrossShadow(start, selector) {
272
289
  try {
@@ -315,7 +332,7 @@ var VioProduct = class extends LitElement {
315
332
  }
316
333
  /** The slot campaign's sponsor as the string the attributes use ('' when unknown). */
317
334
  sponsorFromAttribution() {
318
- const id = Vio.attribution(this.effectiveSlot).sponsorId;
335
+ const id = typeof Vio.attribution === "function" ? Vio.attribution(this.effectiveSlot).sponsorId : void 0;
319
336
  return id !== void 0 ? String(id) : "";
320
337
  }
321
338
  slotAttributes() {
@@ -332,7 +349,7 @@ var VioProduct = class extends LitElement {
332
349
  * set `vio-content-id` / `vio-content-title` on this card.
333
350
  */
334
351
  attribution() {
335
- const base = Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId || void 0 });
352
+ const base = typeof Vio.attribution === "function" ? Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId || void 0 }) : { slot: this.effectiveSlot || void 0 };
336
353
  return {
337
354
  ...base,
338
355
  ...this.vioContentId ? { contentId: this.vioContentId } : {},
@@ -690,7 +707,7 @@ var VioProductCarousel = class extends LitElement {
690
707
  }
691
708
  /** Attribution every analytics event of this carousel carries (`Vio.attribution` + the content overrides). */
692
709
  attribution() {
693
- const base = Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0 });
710
+ const base = typeof Vio.attribution === "function" ? Vio.attribution(this.effectiveSlot, { sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0 }) : { slot: this.effectiveSlot || void 0 };
694
711
  return {
695
712
  ...base,
696
713
  ...this.vioContentId ? { contentId: this.vioContentId } : {},
@@ -872,7 +889,7 @@ var VioProductCarousel = class extends LitElement {
872
889
  */
873
890
  effectiveSponsorId() {
874
891
  if (this.sponsorId > 0) return this.sponsorId;
875
- const fromSlot = Number(Vio.campaignForSlot(this.effectiveSlot || null)?.primarySponsor?.id);
892
+ const fromSlot = typeof Vio.campaignForSlot === "function" ? Number(Vio.campaignForSlot(this.effectiveSlot || null)?.primarySponsor?.id) : NaN;
876
893
  return Number.isFinite(fromSlot) && fromSlot > 0 ? fromSlot : 0;
877
894
  }
878
895
  async autoFetch() {
@@ -1355,10 +1372,11 @@ var VioProductDetail = class extends LitElement {
1355
1372
  this.vioContentId = "";
1356
1373
  this.vioContentTitle = "";
1357
1374
  this.slotRegistration = new SlotRegistration(this, "detail");
1358
- /** What the click that opened the detail carried ('' when nothing). */
1375
+ /** What the click that opened the detail carried ('' when nothing), and for which product. */
1359
1376
  this.eventSlot = "";
1360
1377
  this.eventContentId = "";
1361
1378
  this.eventContentTitle = "";
1379
+ this.eventProductId = "";
1362
1380
  this.product = null;
1363
1381
  this.sellerName = null;
1364
1382
  this.sellerSettled = false;
@@ -1392,11 +1410,12 @@ var VioProductDetail = class extends LitElement {
1392
1410
  const slot = typeof ev.detail.slot === "string" ? ev.detail.slot.trim() : "";
1393
1411
  let sponsorIdNum = parseInt(ev.detail.sponsorId, 10);
1394
1412
  if (Number.isNaN(sponsorIdNum) || sponsorIdNum <= 0) {
1395
- const fromSlot = Number(Vio.campaignForSlot(slot || this.effectiveSlot || null)?.primarySponsor?.id);
1413
+ const fromSlot = typeof Vio.campaignForSlot === "function" ? Number(Vio.campaignForSlot(slot || this.effectiveSlot || null)?.primarySponsor?.id) : NaN;
1396
1414
  if (!Number.isFinite(fromSlot) || fromSlot <= 0) return;
1397
1415
  sponsorIdNum = fromSlot;
1398
1416
  }
1399
1417
  this.eventSlot = slot;
1418
+ this.eventProductId = String(ev.detail.productId);
1400
1419
  this.eventContentId = ev.detail.contentId !== void 0 && ev.detail.contentId !== null ? String(ev.detail.contentId).trim() : "";
1401
1420
  this.eventContentTitle = typeof ev.detail.contentTitle === "string" ? ev.detail.contentTitle.trim() : "";
1402
1421
  this.productId = ev.detail.productId;
@@ -1406,13 +1425,17 @@ var VioProductDetail = class extends LitElement {
1406
1425
  void this.fetchProduct();
1407
1426
  };
1408
1427
  }
1428
+ /** The card's context applies to the product it opened — not to one the host opened by hand later. */
1429
+ get fromCard() {
1430
+ return this.eventProductId !== "" && this.eventProductId === String(this.productId);
1431
+ }
1409
1432
  /** The slot id in effect for this element: `vio-slot`, else the auto id (`detail-N`). Read-only. */
1410
1433
  get effectiveSlot() {
1411
1434
  return this.slotRegistration.effective;
1412
1435
  }
1413
1436
  /** The slot the open product is attributed to: the opening card's, else this element's. */
1414
1437
  get activeSlot() {
1415
- return this.eventSlot || this.effectiveSlot;
1438
+ return this.fromCard && this.eventSlot || this.effectiveSlot;
1416
1439
  }
1417
1440
  slotAttributes() {
1418
1441
  return {
@@ -1424,9 +1447,9 @@ var VioProductDetail = class extends LitElement {
1424
1447
  }
1425
1448
  /** Attribution every event of the open product carries (`Vio.attribution` of the opening card's slot, else this element's). */
1426
1449
  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;
1450
+ const base = typeof Vio.attribution === "function" ? Vio.attribution(this.activeSlot, { sponsorId: this.sponsorId > 0 ? this.sponsorId : void 0 }) : { slot: this.activeSlot || void 0 };
1451
+ const contentId = this.fromCard && this.eventContentId || this.vioContentId;
1452
+ const contentTitle = this.fromCard && this.eventContentTitle || this.vioContentTitle;
1430
1453
  return {
1431
1454
  ...base,
1432
1455
  ...contentId ? { contentId } : {},
@@ -1902,6 +1925,10 @@ var VioProductDetail = class extends LitElement {
1902
1925
  this.open = false;
1903
1926
  setTimeout(() => {
1904
1927
  if (!this.open) {
1928
+ this.eventSlot = "";
1929
+ this.eventContentId = "";
1930
+ this.eventContentTitle = "";
1931
+ this.eventProductId = "";
1905
1932
  this.product = null;
1906
1933
  this.sellerName = null;
1907
1934
  this.sellerSettled = false;
@@ -2001,7 +2028,7 @@ var VioProductDetail = class extends LitElement {
2001
2028
  }
2002
2029
  /** Which buy buttons to render — backend-configured per sponsor. */
2003
2030
  async loadAvailablePaymentMethods() {
2004
- const spId = this.sponsorId || Number(Vio.campaignForSlot(this.activeSlot || null)?.primarySponsor?.id) || globalThis.__VIO_SPONSOR_ID__;
2031
+ const spId = this.sponsorId || (typeof Vio.campaignForSlot === "function" ? Number(Vio.campaignForSlot(this.activeSlot || null)?.primarySponsor?.id) : 0) || globalThis.__VIO_SPONSOR_ID__;
2005
2032
  if (!spId) return;
2006
2033
  try {
2007
2034
  const methods = await Vio.checkout.getAvailablePaymentMethods(spId);
@@ -7007,5 +7034,5 @@ function registerVioElements() {
7007
7034
  }
7008
7035
 
7009
7036
  export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
7010
- //# sourceMappingURL=chunk-COCHGJ2K.js.map
7011
- //# sourceMappingURL=chunk-COCHGJ2K.js.map
7037
+ //# sourceMappingURL=chunk-UVDOKFGD.js.map
7038
+ //# sourceMappingURL=chunk-UVDOKFGD.js.map