@liquidcommercedev/rmn-sdk 1.5.0-beta.18 → 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 +681 -205
- package/dist/index.esm.js +681 -205
- package/dist/types/modules/element/template/helper.d.ts +2 -1
- package/dist/types/modules/event/event.interface.d.ts +5 -0
- package/dist/types/modules/event/event.service.d.ts +4 -3
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
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 =
|
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.
|
16309
|
-
|
16310
|
-
|
16311
|
-
|
16312
|
-
|
16313
|
-
|
16314
|
-
|
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.
|
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.
|
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
|
-
|
16372
|
-
|
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
|
16382
|
-
|
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
|
16402
|
-
|
16403
|
-
|
16404
|
-
|
16405
|
-
|
16406
|
-
|
16407
|
-
|
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.
|
16411
|
-
|
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.
|
16484
|
+
this.shadowRoot.appendChild(carouselContainer);
|
16485
|
+
this.cacheElements();
|
16422
16486
|
}
|
16423
|
-
|
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
|
-
|
16427
|
-
|
16428
|
-
|
16429
|
-
|
16430
|
-
|
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
|
-
|
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 ${
|
16439
|
-
dotsContainer.style.
|
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 =
|
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
|
-
|
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 =
|
16451
|
-
|
16452
|
-
|
16453
|
-
|
16454
|
-
|
16455
|
-
|
16456
|
-
|
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 =
|
16466
|
-
button.style.backgroundColor =
|
16467
|
-
button.style.borderRadius =
|
16572
|
+
button.style.color = textColor;
|
16573
|
+
button.style.backgroundColor = backgroundColor;
|
16574
|
+
button.style.borderRadius = borderRadius;
|
16468
16575
|
return button;
|
16469
16576
|
}
|
16470
|
-
|
16471
|
-
|
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.
|
16474
|
-
this.
|
16475
|
-
|
16476
|
-
|
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
|
-
|
16482
|
-
|
16483
|
-
|
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
|
-
|
16486
|
-
|
16487
|
-
|
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
|
-
|
16490
|
-
|
16491
|
-
|
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;
|
16664
|
+
}
|
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();
|
16676
|
+
}
|
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();
|
16493
16703
|
}
|
16494
|
-
|
16495
|
-
|
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);
|
16496
16727
|
}
|
16497
|
-
|
16498
|
-
|
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';
|
16499
16800
|
}
|
16801
|
+
/**
|
16802
|
+
* Navigates to a specific slide
|
16803
|
+
* Used primarily by dot navigation
|
16804
|
+
*/
|
16500
16805
|
goToSlide(index) {
|
16501
|
-
this.
|
16502
|
-
|
16806
|
+
if (this.state.isTransitioning)
|
16807
|
+
return;
|
16808
|
+
this.state.currentSlide = index;
|
16809
|
+
this.updateCarousel(true);
|
16503
16810
|
}
|
16504
|
-
|
16505
|
-
|
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
|
-
|
16508
|
-
|
16509
|
-
this.
|
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.
|
16516
|
-
const isActive = index === this.
|
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.
|
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
|
-
|
16539
|
-
|
16540
|
-
|
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
|
-
|
16543
|
-
|
16544
|
-
|
16545
|
-
|
16546
|
-
|
16547
|
-
|
16548
|
-
|
16549
|
-
|
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
|
-
|
16556
|
-
|
16557
|
-
|
16558
|
-
|
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
|
-
|
16566
|
-
CustomCarouselElement.
|
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
|
-
|
16732
|
-
|
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
|
16743
|
-
|
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(
|
18879
|
-
//
|
18880
|
-
this.
|
18881
|
-
// Handle
|
18882
|
-
|
18883
|
-
|
18884
|
-
|
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
|
18889
|
-
|
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(
|
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(
|
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
|
-
|
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 : [
|
19444
|
+
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [],
|
18991
19445
|
});
|
18992
19446
|
}
|
18993
|
-
|
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';
|
@@ -19792,6 +20266,8 @@ class LiquidCommerceRmnClient {
|
|
19792
20266
|
this.eventService.handleSpotState(item.placementId, {
|
19793
20267
|
state: {
|
19794
20268
|
error: `Placement not found for id "${item.placementId}".`,
|
20269
|
+
mounted: false,
|
20270
|
+
loading: false,
|
19795
20271
|
},
|
19796
20272
|
});
|
19797
20273
|
continue;
|