@liquidcommercedev/rmn-sdk 1.5.0-beta.18 → 1.5.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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;
|