@liquidcommercedev/rmn-sdk 1.5.0-beta.17 → 1.5.0-beta.19

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.cjs CHANGED
@@ -15947,7 +15947,7 @@ class LocalStorageService {
15947
15947
  LocalStorageService.localStorageKeyPrefix = 'lc_rmn';
15948
15948
  LocalStorageService.localStorageKey = '';
15949
15949
  LocalStorageService.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
15950
- LocalStorageService.encryptData = true;
15950
+ LocalStorageService.encryptData = false;
15951
15951
 
15952
15952
  /**
15953
15953
  * PubsubService class
@@ -16108,6 +16108,12 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
16108
16108
  height: ${fluid ? '100%' : `${height}px`};
16109
16109
  }
16110
16110
 
16111
+ .container {
16112
+ position: relative;
16113
+ width: 100%;
16114
+ height: 100%;
16115
+ }
16116
+
16111
16117
  .slides {
16112
16118
  position: relative;
16113
16119
  height: 100%;
@@ -16303,57 +16309,74 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
16303
16309
  let CarouselElement;
16304
16310
  if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
16305
16311
  class CustomCarouselElement extends HTMLElement {
16312
+ /**
16313
+ * Initializes the web component and attaches shadow DOM
16314
+ * Binds all event handlers to maintain proper 'this' context
16315
+ */
16306
16316
  constructor() {
16307
16317
  super();
16308
- this.currentSlide = 0;
16309
- this.dotElements = [];
16310
- this.prevButton = null;
16311
- this.nextButton = null;
16312
- this.autoplayInterval = null;
16313
- this.useDots = false;
16314
- this.useButtons = false;
16318
+ this.state = {
16319
+ currentSlide: 0,
16320
+ autoplayInterval: null,
16321
+ isAutoplayPaused: false,
16322
+ useDots: false,
16323
+ useButtons: false,
16324
+ autoplay: true,
16325
+ interval: CustomCarouselElement.defaultConfigs.interval,
16326
+ dots: { ...CustomCarouselElement.defaultConfigs.dots },
16327
+ buttons: { ...CustomCarouselElement.defaultConfigs.buttons },
16328
+ isDragging: false,
16329
+ startX: 0,
16330
+ currentX: 0,
16331
+ dragStartTime: 0,
16332
+ dragDistance: 0,
16333
+ containerWidth: 0,
16334
+ isTransitioning: false,
16335
+ realIndex: 0, // Track the actual slide index
16336
+ virtualIndex: 1, // Track the virtual slide position (start at 1 to show clone)
16337
+ isVirtualizing: false, // Flag for handling virtual slide transitions
16338
+ };
16339
+ this.elements = {
16340
+ slidesContainer: null,
16341
+ dots: [],
16342
+ prevButton: null,
16343
+ nextButton: null,
16344
+ };
16315
16345
  this.originalFontSizes = new Map();
16346
+ this.cloneToOriginalMap = new WeakMap();
16316
16347
  this.attachShadow({ mode: 'open' });
16348
+ this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
16349
+ this.handleTouchStart = this.handleTouchStart.bind(this);
16350
+ this.handleTouchMove = this.handleTouchMove.bind(this);
16351
+ this.handleTouchEnd = this.handleTouchEnd.bind(this);
16352
+ this.handleDragStart = this.handleDragStart.bind(this);
16353
+ this.handleDrag = this.handleDrag.bind(this);
16354
+ this.handleDragEnd = this.handleDragEnd.bind(this);
16355
+ this.updateContainerWidth = this.updateContainerWidth.bind(this);
16317
16356
  }
16357
+ /**
16358
+ * Web component lifecycle method called when element is added to DOM
16359
+ * Initializes state, renders UI, sets up events and starts autoplay
16360
+ */
16318
16361
  connectedCallback() {
16319
- this.initializeOptions();
16320
- this.setupResizeObserver();
16362
+ this.initializeState();
16321
16363
  this.render();
16322
16364
  this.setupCarousel();
16365
+ this.setupTouchEvents();
16366
+ this.startAutoplayIfEnabled();
16367
+ this.updateContainerWidth();
16368
+ window.addEventListener('resize', this.updateContainerWidth.bind(this));
16369
+ this.setupResizeObserver();
16323
16370
  }
16371
+ /**
16372
+ * Web component lifecycle method called when element is removed from DOM
16373
+ * Cleans up all event listeners and intervals
16374
+ */
16324
16375
  disconnectedCallback() {
16325
16376
  var _a;
16326
- this.stopAutoplay();
16377
+ this.cleanupEventListeners();
16327
16378
  (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
16328
16379
  }
16329
- initializeOptions() {
16330
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
16331
- this.useDots = ((_a = this.data) === null || _a === void 0 ? void 0 : _a.useDots) === true || typeof ((_b = this.data) === null || _b === void 0 ? void 0 : _b.useDots) === 'object';
16332
- this.useButtons = ((_c = this.data) === null || _c === void 0 ? void 0 : _c.useButtons) === true || typeof ((_d = this.data) === null || _d === void 0 ? void 0 : _d.useButtons) === 'object';
16333
- this.autoplay = (_f = (_e = this.data) === null || _e === void 0 ? void 0 : _e.autoplay) !== null && _f !== void 0 ? _f : true;
16334
- this.interval = (_h = (_g = this.data) === null || _g === void 0 ? void 0 : _g.interval) !== null && _h !== void 0 ? _h : CustomCarouselElement.defaultInterval;
16335
- this.dotsOptions = {
16336
- position: 'bottom-center',
16337
- color: '#d9d9d9',
16338
- activeColor: '#b5914a',
16339
- size: 'base',
16340
- opacity: 1,
16341
- ...(typeof ((_j = this.data) === null || _j === void 0 ? void 0 : _j.useDots) === 'object' ? this.data.useDots : {}),
16342
- };
16343
- this.buttonsOptions = {
16344
- together: false,
16345
- position: 'middle-sides',
16346
- textColor: '#000000',
16347
- backgroundColor: '#ffffff',
16348
- borderRadius: '50%',
16349
- prev: 'Prev',
16350
- next: 'Next',
16351
- size: 'base',
16352
- opacity: 1,
16353
- ...(typeof ((_k = this.data) === null || _k === void 0 ? void 0 : _k.useButtons) === 'object' ? this.data.useButtons : {}),
16354
- };
16355
- this.validateOptions();
16356
- }
16357
16380
  setupResizeObserver() {
16358
16381
  if (this.data && !this.data.fluid) {
16359
16382
  this.resizeObserver = new ResizeObserverService({
@@ -16368,18 +16391,20 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
16368
16391
  }
16369
16392
  }
16370
16393
  handleCarouselSizeChanged(event) {
16371
- const isRBSpot = 'rbHeroadaksda'.startsWith('rb');
16372
- if (!isRBSpot) {
16373
- // Adjust text elements font size based on the scale factor
16374
- this.adjustFontSize(event.detail.scale);
16375
- }
16394
+ // Adjust text elements font size based on the scale factor
16395
+ this.adjustFontSize(event.detail.scale);
16376
16396
  }
16377
16397
  adjustFontSize(elementScale) {
16378
16398
  var _a;
16379
- const scaleFactor = calculateScaleFactor(elementScale);
16380
16399
  // Find all text elements within the shadow root
16381
- const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('h1, h2, h3, h4, p, span');
16382
- elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
16400
+ const selectors = ['h1', 'h2', 'h3', 'h4', 'p', 'span']
16401
+ .map((tag) => `[data-spot="iab"] ${tag}`)
16402
+ .join(', ');
16403
+ const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors);
16404
+ if (!elements)
16405
+ return;
16406
+ const scaleFactor = calculateScaleFactor(elementScale);
16407
+ elements.forEach((element) => {
16383
16408
  if (element instanceof HTMLElement) {
16384
16409
  if (!this.originalFontSizes.has(element)) {
16385
16410
  const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
@@ -16391,179 +16416,610 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
16391
16416
  }
16392
16417
  });
16393
16418
  }
16419
+ /** State and Configuration Management */
16420
+ /**
16421
+ * Initializes all state values from provided configuration
16422
+ * Sets up dots, buttons, autoplay and other feature flags
16423
+ */
16424
+ initializeState() {
16425
+ var _a, _b, _c, _d, _e, _f, _g, _h;
16426
+ this.state.useDots = Boolean((_a = this.data) === null || _a === void 0 ? void 0 : _a.useDots);
16427
+ this.state.useButtons = Boolean((_b = this.data) === null || _b === void 0 ? void 0 : _b.useButtons);
16428
+ this.state.autoplay = (_d = (_c = this.data) === null || _c === void 0 ? void 0 : _c.autoplay) !== null && _d !== void 0 ? _d : true;
16429
+ this.state.interval = (_f = (_e = this.data) === null || _e === void 0 ? void 0 : _e.interval) !== null && _f !== void 0 ? _f : CustomCarouselElement.defaultConfigs.interval;
16430
+ if (typeof ((_g = this.data) === null || _g === void 0 ? void 0 : _g.useDots) === 'object') {
16431
+ this.state.dots = { ...this.state.dots, ...this.data.useDots };
16432
+ }
16433
+ if (typeof ((_h = this.data) === null || _h === void 0 ? void 0 : _h.useButtons) === 'object') {
16434
+ this.state.buttons = { ...this.state.buttons, ...this.data.useButtons };
16435
+ }
16436
+ this.validateConfiguration();
16437
+ }
16438
+ /**
16439
+ * Validates all configuration options
16440
+ * Ensures positions and other settings are valid
16441
+ */
16442
+ validateConfiguration() {
16443
+ this.validatePosition(this.state.dots.position, 'dotsPosition', 'bottom-center');
16444
+ this.validateButtonsPosition();
16445
+ }
16446
+ /**
16447
+ * Validates navigation element positions
16448
+ * Ensures dots and buttons are placed in valid locations
16449
+ */
16450
+ validatePosition(position, optionName, defaultValue) {
16451
+ if (!CustomCarouselElement.validPositions.has(position)) {
16452
+ console.warn(`Invalid ${optionName}: ${position}. Defaulting to '${defaultValue}'.`);
16453
+ if (optionName === 'dotsPosition') {
16454
+ this.state.dots.position = defaultValue;
16455
+ }
16456
+ else if (optionName === 'buttonsPosition') {
16457
+ this.state.buttons.position = defaultValue;
16458
+ }
16459
+ }
16460
+ }
16461
+ /** Rendering and DOM Management */
16462
+ /**
16463
+ * Main rendering function that builds the carousel structure
16464
+ * Creates slides, dots, and navigation buttons
16465
+ */
16394
16466
  render() {
16395
- var _a;
16396
16467
  if (!this.shadowRoot)
16397
16468
  return;
16398
16469
  const style = document.createElement('style');
16399
16470
  style.textContent = CAROUSEL_COMPONENT_STYLE(this.data);
16400
16471
  this.shadowRoot.appendChild(style);
16401
- const slides = this.renderSlides();
16402
- this.shadowRoot.appendChild(slides);
16403
- this.slidesContainer = (_a = this.shadowRoot.querySelector('.slides')) !== null && _a !== void 0 ? _a : undefined;
16404
- if (this.useDots) {
16405
- const dots = this.renderDots();
16406
- if (dots)
16407
- this.shadowRoot.appendChild(dots);
16472
+ const carouselContainer = document.createElement('div');
16473
+ carouselContainer.className = 'container';
16474
+ const slides = this.createSlides();
16475
+ carouselContainer.appendChild(slides);
16476
+ if (this.state.useDots) {
16477
+ const dots = this.createDots();
16478
+ carouselContainer.appendChild(dots);
16408
16479
  }
16409
- if (this.useButtons) {
16410
- const buttons = this.renderButtons();
16411
- if (buttons)
16412
- this.shadowRoot.appendChild(buttons);
16413
- }
16414
- }
16415
- setupCarousel() {
16416
- this.setupDots();
16417
- this.setupButtons();
16418
- if (this.autoplay) {
16419
- this.startAutoplay();
16480
+ if (this.state.useButtons) {
16481
+ const buttons = this.createButtons();
16482
+ carouselContainer.appendChild(buttons);
16420
16483
  }
16421
- this.updateCarousel();
16484
+ this.shadowRoot.appendChild(carouselContainer);
16485
+ this.cacheElements();
16422
16486
  }
16423
- renderSlides() {
16487
+ /**
16488
+ * Creates the slides container with infinite scroll support
16489
+ * Adds cloned slides at start and end for seamless scrolling
16490
+ */
16491
+ createSlides() {
16424
16492
  const slidesContainer = document.createElement('div');
16425
16493
  slidesContainer.className = 'slides';
16426
- this.slides.forEach((slide) => {
16427
- const slideElement = document.createElement('div');
16428
- slideElement.className = 'slide';
16429
- if (slide instanceof HTMLElement) {
16430
- slideElement.appendChild(slide);
16431
- }
16432
- slidesContainer.appendChild(slideElement);
16494
+ // Add the last slide at the beginning for seamless backward transition
16495
+ this.appendSlide(slidesContainer, this.slides.length - 1);
16496
+ // Add all slides
16497
+ this.slides.forEach((_, index) => {
16498
+ this.appendSlide(slidesContainer, index);
16433
16499
  });
16500
+ // Add the first slide at the end for seamless forward transition
16501
+ this.appendSlide(slidesContainer, 0);
16502
+ // Set initial position to show first real slide
16503
+ slidesContainer.style.transform = 'translateX(-100%)';
16434
16504
  return slidesContainer;
16435
16505
  }
16436
- renderDots() {
16506
+ /**
16507
+ * Appends a single slide to the container
16508
+ * Handles cloning of slide elements
16509
+ */
16510
+ appendSlide(container, index) {
16511
+ const slideElement = document.createElement('div');
16512
+ slideElement.className = 'slide';
16513
+ if (this.slides[index] instanceof HTMLElement) {
16514
+ // Clone the slide
16515
+ const clonedSlide = this.slides[index].cloneNode(true);
16516
+ // Map clone to original for event handling
16517
+ this.cloneToOriginalMap.set(clonedSlide, this.slides[index]);
16518
+ // Add event delegation to the slide container
16519
+ slideElement.addEventListener('click', (e) => {
16520
+ const original = this.slides[index];
16521
+ // Dispatch a new event on the original element
16522
+ const cloneEvent = new Event(e.type, { bubbles: true, cancelable: true });
16523
+ original.dispatchEvent(cloneEvent);
16524
+ });
16525
+ slideElement.appendChild(clonedSlide);
16526
+ }
16527
+ container.appendChild(slideElement);
16528
+ }
16529
+ /**
16530
+ * Creates navigation dots based on number of slides
16531
+ * Sets up initial active state and styling
16532
+ */
16533
+ createDots() {
16534
+ const { position, size, opacity, color } = this.state.dots;
16437
16535
  const dotsContainer = document.createElement('div');
16438
- dotsContainer.className = `dots ${this.dotsOptions.position} ${this.dotsOptions.size}`;
16439
- dotsContainer.style.cssText = `--opacity: ${this.dotsOptions.opacity}`;
16536
+ dotsContainer.className = `dots ${position} ${size}`;
16537
+ dotsContainer.style.setProperty('--opacity', opacity.toString());
16440
16538
  this.slides.forEach((_, index) => {
16441
16539
  const dot = document.createElement('span');
16442
- dot.className = `dot ${index === this.currentSlide ? 'active' : ''}`;
16443
- dot.style.backgroundColor = this.dotsOptions.color;
16540
+ dot.className = `dot ${index === this.state.currentSlide ? 'active' : ''}`;
16541
+ dot.style.backgroundColor = color;
16444
16542
  dotsContainer.appendChild(dot);
16445
16543
  });
16446
16544
  return dotsContainer;
16447
16545
  }
16448
- renderButtons() {
16546
+ /**
16547
+ * Creates navigation buttons (prev/next)
16548
+ * Applies styling and position configuration
16549
+ */
16550
+ createButtons() {
16551
+ // eslint-disable-next-line @typescript-eslint/naming-convention
16552
+ const { together, position, size, opacity } = this.state.buttons;
16449
16553
  const buttonsContainer = document.createElement('div');
16450
- const buttonsClass = this.buttonsOptions.together
16451
- ? `buttons-together ${this.buttonsOptions.position}`
16452
- : 'buttons-separate';
16453
- buttonsContainer.className = `buttons ${buttonsClass} ${this.buttonsOptions.size}`;
16454
- buttonsContainer.style.cssText = `--opacity: ${this.buttonsOptions.opacity}`;
16455
- this.prevButton = this.createButton('prev-button', this.buttonsOptions.prev);
16456
- this.nextButton = this.createButton('next-button', this.buttonsOptions.next);
16457
- buttonsContainer.appendChild(this.prevButton);
16458
- buttonsContainer.appendChild(this.nextButton);
16554
+ const buttonsClass = together ? `buttons-together ${position}` : 'buttons-separate';
16555
+ buttonsContainer.className = `buttons ${buttonsClass} ${size}`;
16556
+ buttonsContainer.style.setProperty('--opacity', opacity.toString());
16557
+ this.elements.prevButton = this.createButton('prev-button', this.state.buttons.prev);
16558
+ this.elements.nextButton = this.createButton('next-button', this.state.buttons.next);
16559
+ buttonsContainer.appendChild(this.elements.prevButton);
16560
+ buttonsContainer.appendChild(this.elements.nextButton);
16459
16561
  return buttonsContainer;
16460
16562
  }
16563
+ /**
16564
+ * Creates a single button element with specified properties
16565
+ * Used for both prev and next buttons
16566
+ */
16461
16567
  createButton(className, text) {
16568
+ const { textColor, backgroundColor, borderRadius } = this.state.buttons;
16462
16569
  const button = document.createElement('button');
16463
16570
  button.className = className;
16464
16571
  button.textContent = text;
16465
- button.style.color = this.buttonsOptions.textColor;
16466
- button.style.backgroundColor = this.buttonsOptions.backgroundColor;
16467
- button.style.borderRadius = this.buttonsOptions.borderRadius;
16572
+ button.style.color = textColor;
16573
+ button.style.backgroundColor = backgroundColor;
16574
+ button.style.borderRadius = borderRadius;
16468
16575
  return button;
16469
16576
  }
16470
- setupDots() {
16471
- if (!this.shadowRoot || !this.useDots)
16577
+ /**
16578
+ * Caches references to important DOM elements
16579
+ * Stores references to slides container, dots, and buttons
16580
+ */
16581
+ cacheElements() {
16582
+ if (!this.shadowRoot)
16472
16583
  return;
16473
- this.dotElements = Array.from(this.shadowRoot.querySelectorAll('.dot'));
16474
- this.dotElements.forEach((dot, index) => {
16475
- dot.addEventListener('click', () => {
16476
- this.goToSlide(index);
16477
- this.resetAutoplay();
16478
- });
16479
- });
16584
+ this.elements.slidesContainer = this.shadowRoot.querySelector('.slides');
16585
+ this.elements.dots = Array.from(this.shadowRoot.querySelectorAll('.dot'));
16586
+ this.elements.prevButton = this.shadowRoot.querySelector('.prev-button');
16587
+ this.elements.nextButton = this.shadowRoot.querySelector('.next-button');
16480
16588
  }
16481
- setupButtons() {
16482
- var _a, _b;
16483
- if (!this.useButtons)
16589
+ /** Event Management */
16590
+ /**
16591
+ * Sets up all carousel event listeners
16592
+ * Includes dots, buttons, and transition events
16593
+ */
16594
+ setupCarousel() {
16595
+ this.setupEventListeners();
16596
+ // Add transition event listener with bound method
16597
+ if (this.elements.slidesContainer) {
16598
+ this.elements.slidesContainer.addEventListener('transitionend', this.handleTransitionEnd);
16599
+ }
16600
+ this.updateCarousel(false);
16601
+ }
16602
+ /**
16603
+ * Sets up touch and drag event listeners
16604
+ * Handles both mobile touch and desktop mouse events
16605
+ */
16606
+ setupTouchEvents() {
16607
+ if (!this.elements.slidesContainer)
16484
16608
  return;
16485
- (_a = this.prevButton) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
16486
- this.prevSlide();
16487
- this.resetAutoplay();
16609
+ // Touch events
16610
+ this.elements.slidesContainer.addEventListener('touchstart', this.handleTouchStart, {
16611
+ passive: true,
16612
+ });
16613
+ this.elements.slidesContainer.addEventListener('touchmove', this.handleTouchMove, {
16614
+ passive: false,
16488
16615
  });
16489
- (_b = this.nextButton) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
16490
- this.nextSlide();
16491
- this.resetAutoplay();
16616
+ this.elements.slidesContainer.addEventListener('touchend', this.handleTouchEnd);
16617
+ // Mouse drag events
16618
+ this.elements.slidesContainer.addEventListener('mousedown', this.handleDragStart);
16619
+ document.addEventListener('mousemove', this.handleDrag);
16620
+ document.addEventListener('mouseup', this.handleDragEnd);
16621
+ }
16622
+ /**
16623
+ * Removes all event listeners
16624
+ * Called during cleanup and before re-adding listeners
16625
+ */
16626
+ removeEventListeners() {
16627
+ this.elements.dots.forEach((dot) => {
16628
+ dot.replaceWith(dot.cloneNode(true));
16492
16629
  });
16630
+ if (this.elements.prevButton) {
16631
+ this.elements.prevButton.replaceWith(this.elements.prevButton.cloneNode(true));
16632
+ }
16633
+ if (this.elements.nextButton) {
16634
+ this.elements.nextButton.replaceWith(this.elements.nextButton.cloneNode(true));
16635
+ }
16636
+ }
16637
+ /**
16638
+ * Removes touch and drag event listeners
16639
+ * Separate from other event listeners for better management
16640
+ */
16641
+ removeTouchEvents() {
16642
+ if (!this.elements.slidesContainer)
16643
+ return;
16644
+ this.elements.slidesContainer.removeEventListener('touchstart', this.handleTouchStart);
16645
+ this.elements.slidesContainer.removeEventListener('touchmove', this.handleTouchMove);
16646
+ this.elements.slidesContainer.removeEventListener('touchend', this.handleTouchEnd);
16647
+ this.elements.slidesContainer.removeEventListener('mousedown', this.handleDragStart);
16648
+ document.removeEventListener('mousemove', this.handleDrag);
16649
+ document.removeEventListener('mouseup', this.handleDragEnd);
16650
+ }
16651
+ /** Touch and Drag Event Handlers */
16652
+ /**
16653
+ * Handles start of touch interaction
16654
+ * Initializes drag tracking and pauses autoplay
16655
+ */
16656
+ handleTouchStart(e) {
16657
+ if (this.state.isTransitioning)
16658
+ return;
16659
+ this.pauseAutoplay();
16660
+ this.state.startX = e.touches[0].clientX;
16661
+ this.state.dragStartTime = Date.now();
16662
+ this.state.isDragging = true;
16663
+ this.state.dragDistance = 0;
16493
16664
  }
16494
- nextSlide() {
16495
- this.goToSlide((this.currentSlide + 1) % this.slides.length);
16665
+ /**
16666
+ * Handles touch movement
16667
+ * Calculates drag distance and updates carousel position
16668
+ */
16669
+ handleTouchMove(e) {
16670
+ if (!this.state.isDragging || this.state.isTransitioning)
16671
+ return;
16672
+ e.preventDefault();
16673
+ const currentX = e.touches[0].clientX;
16674
+ this.state.dragDistance = this.state.startX - currentX;
16675
+ this.updateDragPosition();
16496
16676
  }
16497
- prevSlide() {
16498
- this.goToSlide((this.currentSlide - 1 + this.slides.length) % this.slides.length);
16677
+ /**
16678
+ * Handles end of touch interaction
16679
+ * Determines if slide should change based on drag distance
16680
+ */
16681
+ handleTouchEnd() {
16682
+ if (!this.state.isDragging)
16683
+ return;
16684
+ const dragDuration = Date.now() - this.state.dragStartTime;
16685
+ const velocity = Math.abs(this.state.dragDistance) / dragDuration;
16686
+ const isQuickSwipe = velocity > 0.5;
16687
+ this.handleDragComplete(isQuickSwipe);
16688
+ setTimeout(() => this.resumeAutoplay(), 100);
16689
+ }
16690
+ /**
16691
+ * Handles start of mouse drag
16692
+ * Similar to touch start but for desktop interaction
16693
+ */
16694
+ handleDragStart(e) {
16695
+ if (this.state.isTransitioning)
16696
+ return;
16697
+ this.pauseAutoplay();
16698
+ this.state.startX = e.clientX;
16699
+ this.state.dragStartTime = Date.now();
16700
+ this.state.isDragging = true;
16701
+ this.state.dragDistance = 0;
16702
+ e.preventDefault();
16499
16703
  }
16704
+ /**
16705
+ * Handles mouse movement during drag
16706
+ * Updates carousel position during drag
16707
+ */
16708
+ handleDrag(e) {
16709
+ if (!this.state.isDragging || this.state.isTransitioning)
16710
+ return;
16711
+ const currentX = e.clientX;
16712
+ this.state.dragDistance = this.state.startX - currentX;
16713
+ this.updateDragPosition();
16714
+ }
16715
+ /**
16716
+ * Handles end of mouse drag
16717
+ * Determines final slide position based on drag
16718
+ */
16719
+ handleDragEnd() {
16720
+ if (!this.state.isDragging)
16721
+ return;
16722
+ const dragDuration = Date.now() - this.state.dragStartTime;
16723
+ const velocity = Math.abs(this.state.dragDistance) / dragDuration;
16724
+ const isQuickSwipe = velocity > 0.5;
16725
+ this.handleDragComplete(isQuickSwipe);
16726
+ setTimeout(() => this.resumeAutoplay(), 100);
16727
+ }
16728
+ /** Navigation and Position Management */
16729
+ /**
16730
+ * Handles navigation button clicks and programmatic navigation
16731
+ * Updates both real and virtual indices
16732
+ */
16733
+ handleNavigation(direction) {
16734
+ if (this.state.isTransitioning)
16735
+ return;
16736
+ const totalSlides = this.slides.length;
16737
+ if (direction === 'next') {
16738
+ this.state.realIndex = (this.state.realIndex + 1) % totalSlides;
16739
+ this.state.virtualIndex++;
16740
+ }
16741
+ else {
16742
+ this.state.realIndex = (this.state.realIndex - 1 + totalSlides) % totalSlides;
16743
+ this.state.virtualIndex--;
16744
+ }
16745
+ this.updateCarousel(true);
16746
+ }
16747
+ /**
16748
+ * Handles dot navigation clicks
16749
+ * Calculates shortest path to target slide
16750
+ */
16751
+ handleDotClick(index) {
16752
+ const currentRealIndex = this.state.realIndex;
16753
+ const totalSlides = this.slides.length;
16754
+ // Calculate the shortest path to the target slide
16755
+ let diff = index - currentRealIndex;
16756
+ // Adjust for shortest path when crossing the boundary
16757
+ if (Math.abs(diff) > totalSlides / 2) {
16758
+ diff = diff > 0 ? diff - totalSlides : diff + totalSlides;
16759
+ }
16760
+ // Update both real and virtual indices
16761
+ this.state.realIndex = index;
16762
+ this.state.virtualIndex += diff;
16763
+ this.updateCarousel(true);
16764
+ this.resetAutoplay();
16765
+ }
16766
+ /**
16767
+ * Completes a drag interaction
16768
+ * Determines whether to change slides based on drag distance
16769
+ */
16770
+ handleDragComplete(isQuickSwipe) {
16771
+ this.state.isDragging = false;
16772
+ if (!this.elements.slidesContainer)
16773
+ return;
16774
+ const dragPercentage = this.state.dragDistance / this.state.containerWidth;
16775
+ const threshold = isQuickSwipe ? 0.1 : CustomCarouselElement.defaultConfigs.dragThreshold;
16776
+ if (Math.abs(dragPercentage) > threshold) {
16777
+ if (this.state.dragDistance > 0) {
16778
+ this.handleNavigation('next');
16779
+ }
16780
+ else {
16781
+ this.handleNavigation('prev');
16782
+ }
16783
+ }
16784
+ else {
16785
+ this.updateCarousel(true);
16786
+ }
16787
+ this.state.dragDistance = 0;
16788
+ }
16789
+ /**
16790
+ * Updates carousel position during drag
16791
+ * Applies transform without transition
16792
+ */
16793
+ updateDragPosition() {
16794
+ if (!this.elements.slidesContainer || this.state.isTransitioning)
16795
+ return;
16796
+ const translateX = -this.state.virtualIndex * 100 -
16797
+ (this.state.dragDistance / this.state.containerWidth) * 100;
16798
+ this.elements.slidesContainer.style.transform = `translateX(${translateX}%)`;
16799
+ this.elements.slidesContainer.style.transition = 'none';
16800
+ }
16801
+ /**
16802
+ * Navigates to a specific slide
16803
+ * Used primarily by dot navigation
16804
+ */
16500
16805
  goToSlide(index) {
16501
- this.currentSlide = index;
16502
- this.updateCarousel();
16806
+ if (this.state.isTransitioning)
16807
+ return;
16808
+ this.state.currentSlide = index;
16809
+ this.updateCarousel(true);
16503
16810
  }
16504
- updateCarousel() {
16505
- if (!this.slidesContainer)
16811
+ /** Transition and Animation Management */
16812
+ /**
16813
+ * Updates carousel position and state
16814
+ * Handles both animated and immediate updates
16815
+ */
16816
+ updateCarousel(animated = true) {
16817
+ if (!this.elements.slidesContainer)
16506
16818
  return;
16507
- // Calculate the translation distance based on current slide
16508
- const translateX = -this.currentSlide * 100;
16509
- this.slidesContainer.style.transform = `translateX(${translateX}%)`;
16819
+ const totalSlides = this.slides.length;
16820
+ // Calculate the translation for the current virtual position
16821
+ const translateX = -this.state.virtualIndex * 100;
16822
+ if (animated) {
16823
+ this.state.isTransitioning = true;
16824
+ this.elements.slidesContainer.style.transition = 'transform 0.3s ease-out';
16825
+ }
16826
+ else {
16827
+ this.elements.slidesContainer.style.transition = 'none';
16828
+ }
16829
+ this.elements.slidesContainer.style.transform = `translateX(${translateX}%)`;
16510
16830
  this.updateDots();
16831
+ // Check if we need to reset virtual position
16832
+ if (this.state.virtualIndex <= 0 || this.state.virtualIndex >= totalSlides + 1) {
16833
+ this.state.isVirtualizing = true;
16834
+ }
16835
+ }
16836
+ /**
16837
+ * Handles the end of slide transitions
16838
+ * Manages infinite scroll position reset
16839
+ */
16840
+ handleTransitionEnd(event) {
16841
+ if (event.target !== this.elements.slidesContainer || event.propertyName !== 'transform')
16842
+ return;
16843
+ this.state.isTransitioning = false;
16844
+ if (this.state.isVirtualizing) {
16845
+ this.resetVirtualPosition();
16846
+ }
16847
+ if (this.elements.slidesContainer) {
16848
+ this.elements.slidesContainer.style.transition = 'none';
16849
+ }
16850
+ }
16851
+ /**
16852
+ * Resets virtual position for infinite scroll
16853
+ * Called after hitting first or last clone
16854
+ */
16855
+ resetVirtualPosition() {
16856
+ var _a;
16857
+ const totalSlides = this.slides.length;
16858
+ if (this.state.virtualIndex <= 0) {
16859
+ // If we've moved before the first clone, jump to the last real slide
16860
+ this.state.virtualIndex = totalSlides;
16861
+ }
16862
+ else if (this.state.virtualIndex >= totalSlides + 1) {
16863
+ // If we've moved after the last clone, jump to the first real slide
16864
+ this.state.virtualIndex = 1;
16865
+ }
16866
+ if (this.elements.slidesContainer) {
16867
+ this.elements.slidesContainer.style.transition = 'none';
16868
+ this.elements.slidesContainer.style.transform = `translateX(${-this.state.virtualIndex * 100}%)`;
16869
+ }
16870
+ this.state.isVirtualizing = false;
16871
+ // Force reflow to ensure the style change takes effect immediately
16872
+ void ((_a = this.elements.slidesContainer) === null || _a === void 0 ? void 0 : _a.offsetHeight);
16511
16873
  }
16874
+ /**
16875
+ * Updates dot active states
16876
+ * Reflects current slide position in navigation
16877
+ */
16512
16878
  updateDots() {
16513
- if (!this.useDots)
16879
+ if (!this.state.useDots)
16514
16880
  return;
16515
- this.dotElements.forEach((dot, index) => {
16516
- const isActive = index === this.currentSlide;
16881
+ this.elements.dots.forEach((dot, index) => {
16882
+ const isActive = index === this.state.realIndex;
16517
16883
  dot.classList.toggle('active', isActive);
16518
- dot.style.backgroundColor = isActive
16519
- ? this.dotsOptions.activeColor
16520
- : this.dotsOptions.color;
16884
+ dot.style.backgroundColor = isActive ? this.state.dots.activeColor : this.state.dots.color;
16521
16885
  });
16522
16886
  }
16887
+ /** Autoplay Management */
16888
+ /**
16889
+ * Starts autoplay if enabled
16890
+ * Called during initialization
16891
+ */
16892
+ startAutoplayIfEnabled() {
16893
+ if (this.state.autoplay && !this.state.isAutoplayPaused) {
16894
+ this.startAutoplay();
16895
+ }
16896
+ }
16897
+ /**
16898
+ * Starts the autoplay interval
16899
+ * Ensures only one interval is running
16900
+ */
16523
16901
  startAutoplay() {
16524
- this.autoplayInterval = window.setInterval(() => this.nextSlide(), this.interval);
16902
+ this.stopAutoplay(); // Ensure any existing interval is cleared first
16903
+ if (!this.state.isAutoplayPaused && this.state.autoplay) {
16904
+ this.state.autoplayInterval = window.setInterval(() => this.handleNavigation('next'), this.state.interval);
16905
+ }
16525
16906
  }
16907
+ /**
16908
+ * Pauses autoplay
16909
+ * Used during user interaction
16910
+ */
16911
+ pauseAutoplay() {
16912
+ this.state.isAutoplayPaused = true;
16913
+ this.stopAutoplay();
16914
+ }
16915
+ /**
16916
+ * Resumes autoplay after pause
16917
+ * Used after user interaction ends
16918
+ */
16919
+ resumeAutoplay() {
16920
+ this.state.isAutoplayPaused = false;
16921
+ if (this.state.autoplay) {
16922
+ this.startAutoplay();
16923
+ }
16924
+ }
16925
+ /**
16926
+ * Stops autoplay completely
16927
+ * Cleans up interval
16928
+ */
16526
16929
  stopAutoplay() {
16527
- if (this.autoplayInterval !== null) {
16528
- window.clearInterval(this.autoplayInterval);
16529
- this.autoplayInterval = null;
16930
+ if (this.state.autoplayInterval !== null) {
16931
+ window.clearInterval(this.state.autoplayInterval);
16932
+ this.state.autoplayInterval = null;
16530
16933
  }
16531
16934
  }
16935
+ /**
16936
+ * Resets autoplay interval
16937
+ * Used after user interactions
16938
+ */
16532
16939
  resetAutoplay() {
16533
- if (this.autoplay) {
16940
+ if (!this.state.isDragging && this.state.autoplay) {
16534
16941
  this.stopAutoplay();
16535
16942
  this.startAutoplay();
16536
16943
  }
16537
16944
  }
16538
- validateOptions() {
16539
- this.validatePosition(this.dotsOptions.position, 'dotsPosition', 'bottom-center');
16540
- this.validateButtonsPosition();
16945
+ /** Utility Methods */
16946
+ /**
16947
+ * Updates container width on resize
16948
+ * Used for drag distance calculations
16949
+ */
16950
+ updateContainerWidth() {
16951
+ if (this.elements.slidesContainer) {
16952
+ this.state.containerWidth = this.elements.slidesContainer.offsetWidth;
16953
+ }
16541
16954
  }
16542
- validatePosition(position, optionName, defaultValue) {
16543
- if (!CustomCarouselElement.validPositions.includes(position)) {
16544
- console.warn(`Invalid ${optionName}: ${position}. Defaulting to '${defaultValue}'.`);
16545
- if (optionName === 'dotsPosition') {
16546
- this.dotsOptions.position = defaultValue;
16547
- }
16548
- else if (optionName === 'buttonsPosition') {
16549
- this.buttonsOptions.position = defaultValue;
16550
- }
16955
+ /**
16956
+ * Cleans up all event listeners
16957
+ * Called during component cleanup
16958
+ */
16959
+ cleanupEventListeners() {
16960
+ this.stopAutoplay();
16961
+ this.removeEventListeners();
16962
+ this.removeTouchEvents();
16963
+ // Remove transition listener
16964
+ if (this.elements.slidesContainer) {
16965
+ this.elements.slidesContainer.removeEventListener('transitionend', this.handleTransitionEnd);
16966
+ }
16967
+ window.removeEventListener('resize', this.updateContainerWidth);
16968
+ }
16969
+ /**
16970
+ * Sets up all event listeners
16971
+ * Includes dots, buttons, and transition events
16972
+ */
16973
+ setupEventListeners() {
16974
+ var _a, _b;
16975
+ if (this.state.useDots) {
16976
+ this.elements.dots.forEach((dot, index) => {
16977
+ dot.addEventListener('click', () => this.handleDotClick(index));
16978
+ });
16979
+ }
16980
+ if (this.state.useButtons) {
16981
+ (_a = this.elements.prevButton) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => this.handleNavigation('prev'));
16982
+ (_b = this.elements.nextButton) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => this.handleNavigation('next'));
16551
16983
  }
16552
16984
  }
16985
+ /**
16986
+ * Validates button position configuration
16987
+ * Ensures only valid positions are used
16988
+ */
16553
16989
  validateButtonsPosition() {
16554
- if (this.useButtons) {
16555
- if (this.buttonsOptions.together) {
16556
- this.validatePosition(this.buttonsOptions.position, 'buttonsPosition', 'bottom-center');
16557
- }
16558
- else if (this.buttonsOptions.position !== 'middle-sides') {
16559
- console.warn(`Invalid buttonsPosition: ${this.buttonsOptions.position}. When buttons are not together, only 'middle-sides' is allowed. Defaulting to 'middle-sides'.`);
16560
- this.buttonsOptions.position = 'middle-sides';
16561
- }
16990
+ if (this.state.useButtons &&
16991
+ !this.state.buttons.together &&
16992
+ this.state.buttons.position !== 'middle-sides') {
16993
+ console.warn('When buttons are not together, only "middle-sides" is allowed. Defaulting to "middle-sides".');
16994
+ this.state.buttons.position = 'middle-sides';
16562
16995
  }
16563
16996
  }
16564
16997
  }
16565
- CustomCarouselElement.defaultInterval = 5000;
16566
- CustomCarouselElement.validPositions = [
16998
+ /** Core initialization and lifecycle methods */
16999
+ CustomCarouselElement.defaultConfigs = {
17000
+ interval: 5000,
17001
+ touchThreshold: 50, // minimum swipe distance in pixels
17002
+ dragThreshold: 0.2, // minimum drag percentage of carousel width
17003
+ dots: {
17004
+ position: 'bottom-center',
17005
+ color: '#d9d9d9',
17006
+ activeColor: '#b5914a',
17007
+ size: 'base',
17008
+ opacity: 1,
17009
+ },
17010
+ buttons: {
17011
+ together: false,
17012
+ position: 'middle-sides',
17013
+ textColor: '#000000',
17014
+ backgroundColor: '#ffffff',
17015
+ borderRadius: '50%',
17016
+ prev: 'Prev',
17017
+ next: 'Next',
17018
+ size: 'base',
17019
+ opacity: 1,
17020
+ },
17021
+ };
17022
+ CustomCarouselElement.validPositions = new Set([
16567
17023
  'top-left',
16568
17024
  'top-center',
16569
17025
  'top-right',
@@ -16573,7 +17029,7 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
16573
17029
  'middle-left',
16574
17030
  'middle-right',
16575
17031
  'middle-sides',
16576
- ];
17032
+ ]);
16577
17033
  CarouselElement = CustomCarouselElement;
16578
17034
  }
16579
17035
 
@@ -16728,19 +17184,20 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
16728
17184
  * #########################################################
16729
17185
  */
16730
17186
  handleSpotSizeChanged(event) {
16731
- var _a, _b, _c;
16732
- const isRBSpot = (_c = (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.spot) === null || _b === void 0 ? void 0 : _b.startsWith('rb')) !== null && _c !== void 0 ? _c : false;
16733
- if (!isRBSpot) {
16734
- // Adjust text elements font size based on the scale factor
16735
- this.adjustFontSize(event.detail.scale);
16736
- }
17187
+ // Adjust text elements font size based on the scale factor
17188
+ this.adjustFontSize(event.detail.scale);
16737
17189
  }
16738
17190
  adjustFontSize(elementScale) {
16739
17191
  var _a;
16740
- const scaleFactor = calculateScaleFactor(elementScale);
16741
17192
  // Find all text elements within the shadow root
16742
- const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('h1, h2, h3, h4, p, span');
16743
- elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
17193
+ const selectors = ['h1', 'h2', 'h3', 'h4', 'p', 'span']
17194
+ .map((tag) => `[data-spot="iab"] ${tag}`)
17195
+ .join(', ');
17196
+ const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors);
17197
+ if (!elements)
17198
+ return;
17199
+ const scaleFactor = calculateScaleFactor(elementScale);
17200
+ elements.forEach((element) => {
16744
17201
  if (element instanceof HTMLElement) {
16745
17202
  if (!this.originalFontSizes.has(element)) {
16746
17203
  const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
@@ -16925,8 +17382,9 @@ function generateGradientColor(overlay, fallback = '') {
16925
17382
  const gradientColor = convertHexToRgba(color, overlayOpacity);
16926
17383
  return `${fullColor} 0%, ${gradientColor} ${goTo}%, ${transparentColor} 100%`;
16927
17384
  }
16928
- function spotHtmlStringToElement(htmlString) {
17385
+ function spotHtmlStringToElement(htmlString, spotType) {
16929
17386
  const spot = document.createElement('div');
17387
+ spot.setAttribute('data-spot', spotType.startsWith('rb') ? 'rb' : 'iab');
16930
17388
  spot.className = 'spot';
16931
17389
  spot.innerHTML = htmlString;
16932
17390
  Object.assign(spot.style, {
@@ -17858,6 +18316,10 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
17858
18316
  .${prefix} {
17859
18317
  background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
17860
18318
  }
18319
+
18320
+ .${prefix}__text {
18321
+ width: 70%;
18322
+ }
17861
18323
  }
17862
18324
 
17863
18325
  @container (min-width: 768px) {
@@ -18680,7 +19142,7 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
18680
19142
  // Generate a highly unique prefix to avoid conflicts with other elements.
18681
19143
  const prefix = 's' + UniqueIdGenerator.generate().toLowerCase();
18682
19144
  const spotHtmlString = variantTemplate(spot, { ...config, prefix });
18683
- return spotHtmlStringToElement(spotHtmlString);
19145
+ return spotHtmlStringToElement(spotHtmlString, spot.spot);
18684
19146
  };
18685
19147
 
18686
19148
  // For the moment, we will only focus on sites that use Google Analytics,
@@ -18875,18 +19337,21 @@ class EventService {
18875
19337
  }
18876
19338
  registerSpot(params) {
18877
19339
  const { placementId, spot, spotElement } = params;
18878
- this.activeSpots.set(placementId, { spotElement });
18879
- // Fire impression event
18880
- this.fireImpressionEvent(placementId, spot);
18881
- // Handle intersection observer
18882
- this.handleIntersectionObserver(placementId, spot, spotElement);
18883
- // Attach click event listener
18884
- spotElement.addEventListener('click', async () => await this.handleClick(params));
19340
+ this.activeSpots.set(spot.id, { placementId, spotElement });
19341
+ // Handle Impression Event
19342
+ this.handleImpressionEvent(placementId, spot);
19343
+ // Handle Click Event
19344
+ spotElement.addEventListener('click', async () => {
19345
+ await this.handleClickEvent(params);
19346
+ });
19347
+ // Handle Intersection Observer
19348
+ this.handleIntersectionObserver(placementId, spotElement);
18885
19349
  }
18886
19350
  unregisterSpot(placementId) {
18887
19351
  const placementIdClean = placementId.replace('#', '');
18888
- const spotData = this.activeSpots.get(placementIdClean);
18889
- if (!spotData) {
19352
+ const spotId = this.getSpotIdByPlacementId(this.activeSpots, placementIdClean);
19353
+ const data = this.activeSpots.get(placementIdClean !== null && placementIdClean !== void 0 ? placementIdClean : '');
19354
+ if (!spotId || !data) {
18890
19355
  this.handleSpotState(placementIdClean, {
18891
19356
  state: {
18892
19357
  error: `Active spot with placementId ${placementIdClean} not found.`,
@@ -18894,7 +19359,7 @@ class EventService {
18894
19359
  });
18895
19360
  return;
18896
19361
  }
18897
- this.intersectionObserver.unobserve(spotData.spotElement);
19362
+ this.intersectionObserver.unobserve(data.spotElement);
18898
19363
  this.handleSpotState(placementIdClean, {
18899
19364
  dom: {
18900
19365
  spotElement: undefined,
@@ -18903,9 +19368,10 @@ class EventService {
18903
19368
  state: {
18904
19369
  unmounted: true,
18905
19370
  mounted: false,
19371
+ loading: false,
18906
19372
  },
18907
19373
  });
18908
- this.activeSpots.delete(placementIdClean);
19374
+ this.activeSpots.delete(spotId);
18909
19375
  const placementElement = document.getElementById(placementIdClean);
18910
19376
  if (!placementElement) {
18911
19377
  this.handleSpotState(placementIdClean, {
@@ -18958,19 +19424,7 @@ class EventService {
18958
19424
  this.pubSubService.publish(exports.RMN_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
18959
19425
  }
18960
19426
  }
18961
- deepMerge(current, updates) {
18962
- return {
18963
- identifier: updates.identifier
18964
- ? { ...current.identifier, ...updates.identifier }
18965
- : current.identifier,
18966
- dom: updates.dom ? { ...current.dom, ...updates.dom } : current.dom,
18967
- state: updates.state ? { ...current.state, ...updates.state } : current.state,
18968
- displayConfig: updates.displayConfig
18969
- ? { ...current.displayConfig, ...updates.displayConfig }
18970
- : current.displayConfig,
18971
- };
18972
- }
18973
- async handleClick({ placementId, spot }) {
19427
+ async handleClickEvent({ placementId, spot }) {
18974
19428
  var _a, _b, _c;
18975
19429
  this.pubSubService.publish(exports.RMN_EVENT.SPOT_EVENT, {
18976
19430
  eventType: exports.RMN_SPOT_EVENT.CLICK,
@@ -18987,22 +19441,10 @@ class EventService {
18987
19441
  spotId: spot.id,
18988
19442
  spotType: spot.spot,
18989
19443
  events: spot.events,
18990
- productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 2, 3],
19444
+ productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [],
18991
19445
  });
18992
19446
  }
18993
- handleIntersectionObserver(placementId, _spot, spotElement) {
18994
- const spotIsVisibleCallback = async () => {
18995
- this.intersectionObserver.unobserve(spotElement);
18996
- this.handleSpotState(placementId, {
18997
- dom: {
18998
- spotElement,
18999
- visibleOnViewport: true,
19000
- },
19001
- });
19002
- };
19003
- this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
19004
- }
19005
- fireImpressionEvent(placementId, spot) {
19447
+ handleImpressionEvent(placementId, spot) {
19006
19448
  this.pubSubService.publish(exports.RMN_EVENT.SPOT_EVENT, {
19007
19449
  eventType: exports.RMN_SPOT_EVENT.IMPRESSION,
19008
19450
  placementId,
@@ -19016,6 +19458,38 @@ class EventService {
19016
19458
  });
19017
19459
  })();
19018
19460
  }
19461
+ getSpotIdByPlacementId(activeSpots, searchPlacementId) {
19462
+ for (const [spotId, spotData] of activeSpots) {
19463
+ if (spotData.placementId === searchPlacementId) {
19464
+ return spotId;
19465
+ }
19466
+ }
19467
+ return null;
19468
+ }
19469
+ deepMerge(current, updates) {
19470
+ return {
19471
+ identifier: updates.identifier
19472
+ ? { ...current.identifier, ...updates.identifier }
19473
+ : current.identifier,
19474
+ dom: updates.dom ? { ...current.dom, ...updates.dom } : current.dom,
19475
+ state: updates.state ? { ...current.state, ...updates.state } : current.state,
19476
+ displayConfig: updates.displayConfig
19477
+ ? { ...current.displayConfig, ...updates.displayConfig }
19478
+ : current.displayConfig,
19479
+ };
19480
+ }
19481
+ handleIntersectionObserver(placementId, spotElement) {
19482
+ const spotIsVisibleCallback = async () => {
19483
+ this.intersectionObserver.unobserve(spotElement);
19484
+ this.handleSpotState(placementId, {
19485
+ dom: {
19486
+ spotElement,
19487
+ visibleOnViewport: true,
19488
+ },
19489
+ });
19490
+ };
19491
+ this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
19492
+ }
19019
19493
  }
19020
19494
 
19021
19495
  const SELECTION_API_PATH = '/spots/selection';
@@ -19733,6 +20207,7 @@ function setUserId() {
19733
20207
 
19734
20208
  /**
19735
20209
  * LiquidCommerce Rmn Client
20210
+ *
19736
20211
  * @class
19737
20212
  */
19738
20213
  class LiquidCommerceRmnClient {
@@ -19791,6 +20266,8 @@ class LiquidCommerceRmnClient {
19791
20266
  this.eventService.handleSpotState(item.placementId, {
19792
20267
  state: {
19793
20268
  error: `Placement not found for id "${item.placementId}".`,
20269
+ mounted: false,
20270
+ loading: false,
19794
20271
  },
19795
20272
  });
19796
20273
  continue;