@liquidcommercedev/rmn-sdk 1.4.5 → 1.4.6-beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. package/dist/index.cjs +1330 -734
  2. package/dist/index.esm.js +1331 -734
  3. package/dist/types/enums.d.ts +57 -1
  4. package/dist/types/index.umd.d.ts +2 -2
  5. package/dist/types/modules/element/component/carousel/carousel.component.d.ts +58 -0
  6. package/dist/types/modules/element/component/carousel/carousel.style.d.ts +1 -0
  7. package/dist/types/modules/element/component/carousel/index.d.ts +2 -0
  8. package/dist/types/modules/element/element.constant.d.ts +4 -0
  9. package/dist/types/modules/element/element.interface.d.ts +43 -0
  10. package/dist/types/modules/element/index.d.ts +3 -0
  11. package/dist/types/modules/element/spot.element.d.ts +2 -0
  12. package/dist/types/modules/element/spot.element.service.d.ts +28 -0
  13. package/dist/types/modules/element/template/helper.d.ts +2 -0
  14. package/dist/types/modules/element/template/index.d.ts +1 -0
  15. package/dist/types/modules/element/template/reservebar/collection-banner-without-text-block.template.d.ts +3 -0
  16. package/dist/types/modules/element/template/reservebar/homepage-hero-full-image.template.d.ts +3 -0
  17. package/dist/types/modules/element/template/reservebar/homepage-hero-three-tile.template.d.ts +3 -0
  18. package/dist/types/modules/element/template/reservebar/homepage-hero-two-tile.template.d.ts +3 -0
  19. package/dist/types/modules/element/template/reservebar/large-category-image-tout.template.d.ts +3 -0
  20. package/dist/types/modules/element/template/reservebar/navigation-banner.template.d.ts +3 -0
  21. package/dist/types/modules/element/template/reservebar/small-category-image-tout.template.d.ts +3 -0
  22. package/dist/types/modules/element/template/reservebar/small-discover-tout.template.d.ts +3 -0
  23. package/dist/types/modules/element/template/template.service.d.ts +10 -0
  24. package/dist/types/modules/element/template/template.type.d.ts +11 -0
  25. package/dist/types/modules/event/event.constant.d.ts +1 -0
  26. package/dist/types/modules/event/event.interface.d.ts +5 -0
  27. package/dist/types/modules/event/event.service.d.ts +5 -0
  28. package/dist/types/modules/event/helpers/index.d.ts +2 -0
  29. package/dist/types/modules/event/helpers/intersection.service.d.ts +8 -0
  30. package/dist/types/modules/event/helpers/resize.service.d.ts +30 -0
  31. package/dist/types/modules/event/index.d.ts +3 -0
  32. package/dist/types/modules/selection/index.d.ts +4 -0
  33. package/dist/types/modules/selection/selection.constant.d.ts +1 -0
  34. package/dist/types/modules/{spot/spot.interface.d.ts → selection/selection.interface.d.ts} +4 -13
  35. package/dist/types/modules/selection/selection.service.d.ts +16 -0
  36. package/dist/types/modules/{spot/spot.type.d.ts → selection/selection.type.d.ts} +1 -1
  37. package/dist/types/rmn-client.d.ts +39 -30
  38. package/dist/types/types.d.ts +7 -5
  39. package/package.json +1 -1
  40. package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
  41. package/dist/types/modules/spot/html/index.d.ts +0 -1
  42. package/dist/types/modules/spot/html/spot.element.service.d.ts +0 -7
  43. package/dist/types/modules/spot/html/spot.element.shadow-root.d.ts +0 -5
  44. package/dist/types/modules/spot/html/templates/iab/constants/fonts.constant.d.ts +0 -3
  45. package/dist/types/modules/spot/html/templates/index.d.ts +0 -1
  46. package/dist/types/modules/spot/html/templates/reservebar/collection-banner-without-text-block.template.d.ts +0 -2
  47. package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-full-image.template.d.ts +0 -2
  48. package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-three-tile.template.d.ts +0 -2
  49. package/dist/types/modules/spot/html/templates/reservebar/homepage-hero-two-tile.template.d.ts +0 -2
  50. package/dist/types/modules/spot/html/templates/reservebar/large-category-image-tout.template.d.ts +0 -2
  51. package/dist/types/modules/spot/html/templates/reservebar/navigation-banner.template.d.ts +0 -2
  52. package/dist/types/modules/spot/html/templates/reservebar/small-category-image-tout.template.d.ts +0 -2
  53. package/dist/types/modules/spot/html/templates/reservebar/small-discover-tout.template.d.ts +0 -2
  54. package/dist/types/modules/spot/html/templates/spot.template.d.ts +0 -21
  55. package/dist/types/modules/spot/index.d.ts +0 -6
  56. package/dist/types/modules/spot/spot.constant.d.ts +0 -4
  57. package/dist/types/modules/spot/spot.enum.d.ts +0 -57
  58. package/dist/types/modules/spot/spot.html.service.d.ts +0 -22
  59. package/dist/types/modules/spot/spot.selection.service.d.ts +0 -16
  60. /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v1.template.d.ts +0 -0
  61. /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v2.template.d.ts +0 -0
  62. /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/billboard-v3.template.d.ts +0 -0
  63. /package/dist/types/modules/{spot/html/templates → element/template}/iab/billboard/index.d.ts +0 -0
  64. /package/dist/types/modules/{spot/html/templates → element/template}/iab/in-text/in-text-v1.template.d.ts +0 -0
  65. /package/dist/types/modules/{spot/html/templates → element/template}/iab/in-text/index.d.ts +0 -0
  66. /package/dist/types/modules/{spot/html/templates → element/template}/iab/index.d.ts +0 -0
  67. /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/index.d.ts +0 -0
  68. /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/large-leaderboard-v1.template.d.ts +0 -0
  69. /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-leaderboard/large-leaderboard-v2.template.d.ts +0 -0
  70. /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-rectangle/index.d.ts +0 -0
  71. /package/dist/types/modules/{spot/html/templates → element/template}/iab/large-rectangle/large-rectangle-v1.template.d.ts +0 -0
  72. /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/index.d.ts +0 -0
  73. /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/square-v1.template.d.ts +0 -0
  74. /package/dist/types/modules/{spot/html/templates → element/template}/iab/square/square-v2.template.d.ts +0 -0
  75. /package/dist/types/modules/{spot/html/templates → element/template}/iab/vertical-rectangle/index.d.ts +0 -0
  76. /package/dist/types/modules/{spot/html/templates → element/template}/iab/vertical-rectangle/vertical-rectangle-v1.template.d.ts +0 -0
  77. /package/dist/types/modules/{spot/html/templates → element/template}/iab/wide-skyscraper/index.d.ts +0 -0
  78. /package/dist/types/modules/{spot/html/templates → element/template}/iab/wide-skyscraper/wide-skyscraper-v1.template.d.ts +0 -0
  79. /package/dist/types/modules/{spot/html/templates → element/template}/reservebar/index.d.ts +0 -0
package/dist/index.esm.js CHANGED
@@ -60,7 +60,6 @@ var RMN_SPOT_EVENT;
60
60
  RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
61
61
  RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
62
62
  })(RMN_SPOT_EVENT || (RMN_SPOT_EVENT = {}));
63
-
64
63
  var RMN_ENV;
65
64
  (function (RMN_ENV) {
66
65
  RMN_ENV["LOCAL"] = "local";
@@ -14997,7 +14996,7 @@ class BaseApi extends BaseApiAbstract {
14997
14996
  */
14998
14997
  async post(path, data, configOverrides) {
14999
14998
  let requestData = data;
15000
- if (this.authInfo.env !== RMN_ENV.DEVELOPMENT) {
14999
+ if (this.authInfo.env !== RMN_ENV.LOCAL) {
15001
15000
  const timestamp = new Date().getTime();
15002
15001
  configOverrides = {
15003
15002
  ...configOverrides,
@@ -15149,63 +15148,696 @@ class AuthService extends BaseApi {
15149
15148
  }
15150
15149
  }
15151
15150
 
15152
- const SPOT_ELEMENT_TAG = 'spot-element';
15153
- const SPOT_ELEMENT_SLOT_NAME = `${SPOT_ELEMENT_TAG}-custom-content`;
15154
- const SPOTS_SELECTION_API_PATH = '/spots/selection';
15155
- const SPOT_EVENT_API_PATH = '/spots/event';
15151
+ const ELEMENT_TAG = 'spot-element';
15152
+ const GFONT_PRECONNECT = `
15153
+ <link rel="preconnect" href="https://fonts.googleapis.com">
15154
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15155
+ `;
15156
+ const GFONT_SOURCE_SANS_3 = `
15157
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
15158
+ `;
15159
+ const GFONT_CORMORANT = `
15160
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
15161
+ `;
15156
15162
 
15157
- const SPOT_ELEMENT_SHADOW_ROOT = (width, height, hasCustomContent) => {
15158
- const style = document.createElement('style');
15159
- style.textContent = `
15160
- :host {
15161
- display: block;
15162
- position: relative;
15163
- container-type: inline-size;
15164
- overflow: hidden;
15163
+ class ResizeObserverService {
15164
+ constructor({ element, maxSize, minScale = 0.275 }) {
15165
+ this.element = element;
15166
+ if (!element.parentElement) {
15167
+ throw new Error('RmnSdk: Spot element must have a parent container.');
15168
+ }
15169
+ this.container = element.parentElement;
15170
+ this.setDimensions(maxSize, minScale);
15171
+ this.resizeObserver = new ResizeObserver(() => this.updateElementSize());
15172
+ this.resizeObserver.observe(this.container);
15173
+ // Initial size update
15174
+ this.updateElementSize();
15175
+ }
15176
+ setDimensions(maxSize, minScale) {
15177
+ if (minScale <= 0 || minScale > 1) {
15178
+ throw new Error('RmnSdk: Invalid minScale value');
15179
+ }
15180
+ const minSize = {
15181
+ width: maxSize.width * minScale,
15182
+ height: maxSize.height * minScale,
15183
+ };
15184
+ if (maxSize.width <= 0 || maxSize.height <= 0 || minSize.width <= 0 || minSize.height <= 0) {
15185
+ throw new Error('RmnSdk: Invalid dimensions');
15186
+ }
15187
+ if (minSize.width > maxSize.width || minSize.height > maxSize.height) {
15188
+ throw new Error('RmnSdk: Minimum size cannot be greater than maximum size');
15189
+ }
15190
+ this.maxSize = maxSize;
15191
+ this.minSize = minSize;
15192
+ this.aspectRatio = this.maxSize.width / this.maxSize.height;
15193
+ }
15194
+ updateElementSize() {
15195
+ const { clientWidth: containerWidth, clientHeight: containerHeight } = this.container;
15196
+ let newWidth;
15197
+ let newHeight;
15198
+ // First, try to fit the maximum width
15199
+ newWidth = Math.min(containerWidth, this.maxSize.width);
15200
+ newHeight = newWidth / this.aspectRatio;
15201
+ // If the height exceeds the container, adjust based on height
15202
+ if (newHeight > containerHeight) {
15203
+ newHeight = containerHeight;
15204
+ newWidth = newHeight * this.aspectRatio;
15205
+ }
15206
+ // Ensure we're not going below minimum dimensions
15207
+ newWidth = Math.max(newWidth, this.minSize.width);
15208
+ newHeight = Math.max(newHeight, this.minSize.height);
15209
+ this.element.style.width = `${newWidth}px`;
15210
+ this.element.style.height = `${newHeight}px`;
15211
+ // Calculate the scale percentage
15212
+ const scaleWidth = newWidth / this.maxSize.width;
15213
+ const scaleHeight = newHeight / this.maxSize.height;
15214
+ const scale = Math.min(scaleWidth, scaleHeight);
15215
+ // Dispatch a custom event
15216
+ this.element.dispatchEvent(new CustomEvent('spotSizeChanged', {
15217
+ detail: {
15218
+ width: this.maxSize.width,
15219
+ height: this.maxSize.height,
15220
+ newWidth,
15221
+ newHeight,
15222
+ scale,
15223
+ },
15224
+ }));
15165
15225
  }
15166
- :host([fluid="true"]) {
15167
- width: 100%;
15168
- height: 100%;
15226
+ disconnect() {
15227
+ this.resizeObserver.disconnect();
15228
+ }
15229
+ }
15230
+
15231
+ let SpotElement;
15232
+ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
15233
+ class CustomSpotElement extends HTMLElement {
15234
+ constructor() {
15235
+ super();
15236
+ this.originalFontSizes = new Map();
15237
+ this.attachShadow({ mode: 'open' });
15238
+ }
15239
+ connectedCallback() {
15240
+ this.setupResizeObserver();
15241
+ this.render();
15242
+ }
15243
+ disconnectedCallback() {
15244
+ var _a;
15245
+ this.removeEventListener('spotSizeChanged', this.handleSpotSizeChanged);
15246
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
15247
+ }
15248
+ /**
15249
+ * Setup observers for the spot element
15250
+ * #########################################################
15251
+ */
15252
+ setupResizeObserver() {
15253
+ if (this.data) {
15254
+ this.resizeObserver = new ResizeObserverService({
15255
+ element: this,
15256
+ maxSize: {
15257
+ width: this.data.width,
15258
+ height: this.data.height,
15259
+ },
15260
+ minScale: this.data.minScale,
15261
+ });
15262
+ this.addEventListener('spotSizeChanged', this.handleSpotSizeChanged.bind(this));
15263
+ }
15264
+ }
15265
+ /**
15266
+ * Observer additional event handlers
15267
+ * #########################################################
15268
+ */
15269
+ handleSpotSizeChanged(event) {
15270
+ // Adjust text elements font size based on the scale factor
15271
+ this.adjustFontSize(event.detail.scale);
15272
+ }
15273
+ adjustFontSize(elementScale) {
15274
+ var _a;
15275
+ const scaleFactor = this.calculateScaleFactor(elementScale);
15276
+ // Find all text elements within the shadow root
15277
+ const elements = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('h1, h2, h3, h4, p, span');
15278
+ elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
15279
+ if (element instanceof HTMLElement) {
15280
+ if (!this.originalFontSizes.has(element)) {
15281
+ const orignalSize = parseFloat(window.getComputedStyle(element).fontSize);
15282
+ this.originalFontSizes.set(element, orignalSize);
15283
+ }
15284
+ const originalSize = this.originalFontSizes.get(element);
15285
+ const newFontSize = originalSize * scaleFactor;
15286
+ element.style.fontSize = `${newFontSize}px`;
15287
+ }
15288
+ });
15289
+ }
15290
+ calculateScaleFactor(elementScale) {
15291
+ // Step 1: Apply square root for non-linear scaling
15292
+ // This creates a more gradual scaling effect, especially for larger changes
15293
+ // For example:
15294
+ // - elementScale of 0.25 (1/4 size) becomes 0.5
15295
+ // - elementScale of 1 (unchanged) remains 1
15296
+ // - elementScale of 4 (4x size) becomes 2
15297
+ const baseFactor = Math.sqrt(elementScale);
15298
+ // Step 2: Apply additional dampening to further soften the scaling effect
15299
+ // The dampening factor (0.5) can be adjusted:
15300
+ // - Lower values (closer to 0) make scaling more subtle
15301
+ // - Higher values (closer to 1) make scaling more pronounced
15302
+ const dampening = 0.5;
15303
+ // Calculate the scaleFactor:
15304
+ // 1. (baseFactor - 1) represents the change from the original size
15305
+ // 2. Multiply by dampening to reduce the effect
15306
+ // 3. Add 1 to center the scaling around the original size
15307
+ // For example, if baseFactor is 2:
15308
+ // scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
15309
+ const scaleFactor = 1 + (baseFactor - 1) * dampening;
15310
+ // Step 3: Define the allowed range for the scale factor
15311
+ // This ensures that the font size never changes too drastically
15312
+ const minScale = 0.9; // Font will never be smaller than 90% of original
15313
+ const maxScale = 1.1; // Font will never be larger than 110% of original
15314
+ // Step 4: Clamp the scale factor to the defined range
15315
+ // Math.min ensures the value doesn't exceed maxScale
15316
+ // Math.max ensures the value isn't less than minScale
15317
+ return Math.max(minScale, Math.min(maxScale, scaleFactor));
15318
+ }
15319
+ /**
15320
+ * Spot element rendering
15321
+ * #########################################################
15322
+ */
15323
+ render() {
15324
+ if (!this.shadowRoot || !this.data || !this.content)
15325
+ return;
15326
+ const style = this.getTemplateStyle(this.data.width, this.data.height);
15327
+ const spot = document.createElement('div');
15328
+ spot.className = 'spot';
15329
+ if (typeof this.content === 'string') {
15330
+ spot.innerHTML = this.content;
15331
+ }
15332
+ if (this.content instanceof HTMLElement) {
15333
+ spot.replaceChildren(this.content);
15334
+ }
15335
+ this.shadowRoot.replaceChildren(style, spot);
15336
+ }
15337
+ getTemplateStyle(width, height) {
15338
+ const style = document.createElement('style');
15339
+ style.textContent = `
15340
+ :host {
15341
+ display: block;
15342
+ position: relative;
15343
+ box-sizing: border-box;
15344
+ overflow: hidden;
15345
+ width: ${this.data.fluid ? '100%' : `${width}px`};
15346
+ height: ${this.data.fluid ? '100%' : `${height}px`};
15347
+ }
15348
+
15349
+ :host .spot {
15350
+ width: 100%;
15351
+ height: 100%;
15352
+ display: block;
15353
+ }
15354
+ `;
15355
+ return style;
15356
+ }
15169
15357
  }
15170
- :host([fluid="false"]) {
15171
- width: ${width}px;
15172
- height: ${height}px;
15358
+ SpotElement = CustomSpotElement;
15359
+ }
15360
+
15361
+ class ElementService {
15362
+ static getInstance() {
15363
+ return SingletonManager.getInstance('ElementService', () => new ElementService());
15173
15364
  }
15174
- `;
15175
- const wrapper = document.createElement('div');
15176
- wrapper.className = 'wrapper';
15177
- const slot = document.createElement('slot');
15178
- slot.name = SPOT_ELEMENT_SLOT_NAME;
15179
- if (!hasCustomContent) {
15180
- style.textContent += `
15181
- :host .wrapper {
15182
- position: absolute;
15183
- top: 0;
15184
- left: 0;
15365
+ /**
15366
+ * Creates the html element based on the provided data, content and configs using shadow dom.
15367
+ *
15368
+ * This method is only available in browser environments.
15369
+ *
15370
+ * @param {ICreateFinalElementParams} params - The parameters to create the final element.
15371
+ *
15372
+ * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
15373
+ */
15374
+ createFinalElement({ content, config }) {
15375
+ var _a;
15376
+ if (!this.ensureBrowserEnvironmentAndDefineElement()) {
15377
+ return null;
15378
+ }
15379
+ const element = document.createElement(ELEMENT_TAG);
15380
+ element.data = {
15381
+ width: config.width,
15382
+ height: config.height,
15383
+ minScale: config === null || config === void 0 ? void 0 : config.minScale,
15384
+ fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
15385
+ };
15386
+ element.content = content;
15387
+ return element;
15388
+ }
15389
+ /**
15390
+ * Overrides the spot colors with the provided colors.
15391
+ *
15392
+ * @param {ISpot} spot - The spot data.
15393
+ * @param {ISpotColors} colors - The colors to override.
15394
+ *
15395
+ * @return {ISpot} - The spot data with the colors overridden.
15396
+ */
15397
+ overrideSpotColors(spot, colors) {
15398
+ if (!colors)
15399
+ return spot;
15400
+ const { textColor, backgroundColor, ctaTextColor, ctaBorderColor } = colors;
15401
+ return {
15402
+ ...spot,
15403
+ textColor: textColor !== null && textColor !== void 0 ? textColor : spot.textColor,
15404
+ backgroundColor: backgroundColor !== null && backgroundColor !== void 0 ? backgroundColor : spot.backgroundColor,
15405
+ ctaTextColor: ctaTextColor !== null && ctaTextColor !== void 0 ? ctaTextColor : spot.ctaTextColor,
15406
+ ctaBorderColor: ctaBorderColor !== null && ctaBorderColor !== void 0 ? ctaBorderColor : spot.ctaBorderColor,
15407
+ };
15408
+ }
15409
+ /**
15410
+ * @returns {boolean} - True if the browser environment is available and the element is defined.
15411
+ */
15412
+ ensureBrowserEnvironmentAndDefineElement() {
15413
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
15414
+ console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
15415
+ return false;
15416
+ }
15417
+ if (!window.customElements.get(ELEMENT_TAG)) {
15418
+ window.customElements.define(ELEMENT_TAG, SpotElement);
15419
+ }
15420
+ return true;
15421
+ }
15422
+ }
15423
+
15424
+ const CAROUSEL_COMPONENT_STYLE = `
15425
+ :host {
15426
+ position: relative;
15427
+ display: inline-block;
15428
+ margin: 0;
15429
+ overflow: hidden;
15430
+ height: 100%;
15431
+ width: 100%;
15432
+ }
15433
+
15434
+ .carousel-slides {
15435
+ position: relative;
15436
+ height: 100%;
15185
15437
  width: 100%;
15438
+ }
15439
+
15440
+ .carousel-slide {
15441
+ display: none;
15442
+
15443
+ justify-content: center;
15444
+ align-items: center;
15186
15445
  height: 100%;
15187
- overflow: hidden;
15188
- }
15189
- `;
15446
+ width: 100%;
15190
15447
  }
15191
- return { style, wrapper, slot };
15192
- };
15193
15448
 
15194
- const GFONT_PRECONNECT = () => `
15195
- <link rel="preconnect" href="https://fonts.googleapis.com">
15196
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15197
- `;
15198
- const GFONT_SOURCE_SANS_3 = () => `
15199
- <link rel="stylesheet"
15200
- href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
15201
- >
15202
- `;
15203
- const GFONT_CORMORANT = () => `
15204
- <link rel="stylesheet"
15205
- href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
15206
- >
15449
+ .carousel-slide.active {
15450
+ display: flex;
15451
+ }
15452
+
15453
+ .carousel-dots {
15454
+ position: absolute;
15455
+ display: flex;
15456
+ align-items: center;
15457
+ gap: 8px;
15458
+ }
15459
+
15460
+ .carousel-dots .dot {
15461
+ width: 12px;
15462
+ height: 12px;
15463
+ border-radius: 50%;
15464
+ cursor: pointer;
15465
+ transition: all 0.3s ease;
15466
+ }
15467
+
15468
+ .carousel-dots.top-left,
15469
+ .carousel-dots.bottom-left {
15470
+ left: 10px;
15471
+ }
15472
+
15473
+ .carousel-dots.top-center,
15474
+ .carousel-dots.bottom-center {
15475
+ left: 50%;
15476
+ transform: translateX(-50%);
15477
+ }
15478
+
15479
+ .carousel-dots.top-right,
15480
+ .carousel-dots.bottom-right {
15481
+ right: 10px;
15482
+ }
15483
+
15484
+ .carousel-dots.top-left,
15485
+ .carousel-dots.top-center,
15486
+ .carousel-dots.top-right {
15487
+ top: 10px;
15488
+ }
15489
+
15490
+ .carousel-dots.bottom-left,
15491
+ .carousel-dots.bottom-center,
15492
+ .carousel-dots.bottom-right {
15493
+ bottom: 10px;
15494
+ }
15495
+
15496
+ .carousel-dots.middle-left {
15497
+ left: 10px;
15498
+ top: 50%;
15499
+ transform: translateY(-50%);
15500
+ flex-direction: column;
15501
+ }
15502
+
15503
+ .carousel-dots.middle-right {
15504
+ right: 10px;
15505
+ top: 50%;
15506
+ transform: translateY(-50%);
15507
+ flex-direction: column;
15508
+ }
15509
+
15510
+ .carousel-buttons button {
15511
+ background-color: #00000080;
15512
+ color: #fff;
15513
+ border: none;
15514
+ padding: 10px;
15515
+ cursor: pointer;
15516
+ transition: background-color 0.3s ease;
15517
+ }
15518
+
15519
+ .carousel-buttons button:hover {
15520
+ background-color: #000000b3;
15521
+ }
15522
+
15523
+ .carousel-buttons.buttons-separate button {
15524
+ position: absolute;
15525
+ top: 50%;
15526
+ transform: translateY(-50%);
15527
+ }
15528
+
15529
+ .carousel-buttons.buttons-separate .prev-button {
15530
+ left: 10px;
15531
+ }
15532
+
15533
+ .carousel-buttons.buttons-separate .next-button {
15534
+ right: 10px;
15535
+ }
15536
+
15537
+ .carousel-buttons.buttons-together {
15538
+ position: absolute;
15539
+ display: flex;
15540
+ gap: 10px;
15541
+ }
15542
+
15543
+ .carousel-buttons.buttons-together.top-left,
15544
+ .carousel-buttons.buttons-together.bottom-left {
15545
+ left: 10px;
15546
+ }
15547
+
15548
+ .carousel-buttons.buttons-together.top-center,
15549
+ .carousel-buttons.buttons-together.bottom-center {
15550
+ left: 50%;
15551
+ transform: translateX(-50%);
15552
+ }
15553
+
15554
+ .carousel-buttons.buttons-together.top-right,
15555
+ .carousel-buttons.buttons-together.bottom-right {
15556
+ right: 10px;
15557
+ }
15558
+
15559
+ .carousel-buttons.buttons-together.top-left,
15560
+ .carousel-buttons.buttons-together.top-center,
15561
+ .carousel-buttons.buttons-together.top-right {
15562
+ top: 10px;
15563
+ }
15564
+
15565
+ .carousel-buttons.buttons-together.bottom-left,
15566
+ .carousel-buttons.buttons-together.bottom-center,
15567
+ .carousel-buttons.buttons-together.bottom-right {
15568
+ bottom: 10px;
15569
+ }
15570
+
15571
+ .carousel-buttons.buttons-together.middle-left,
15572
+ .carousel-buttons.buttons-together.middle-right {
15573
+ top: 50%;
15574
+ transform: translateY(-50%);
15575
+ flex-direction: column;
15576
+ }
15577
+
15578
+ .carousel-buttons.buttons-together.middle-left {
15579
+ left: 10px;
15580
+ }
15581
+
15582
+ .carousel-buttons.buttons-together.middle-right {
15583
+ right: 10px;
15584
+ }
15585
+
15586
+ @media (max-width: 768px) {
15587
+ .carousel-buttons button {
15588
+ padding: 8px 12px;
15589
+ font-size: 14px;
15590
+ }
15591
+
15592
+ .carousel-dots .dot {
15593
+ width: 8px;
15594
+ height: 8px;
15595
+ }
15596
+ }
15207
15597
  `;
15208
15598
 
15599
+ class CarouselComponent {
15600
+ constructor(slides, options = {}) {
15601
+ var _a, _b;
15602
+ this.currentSlide = 0;
15603
+ this.dotElements = [];
15604
+ this.prevButton = null;
15605
+ this.nextButton = null;
15606
+ this.autoplayInterval = null;
15607
+ this.slides = slides;
15608
+ this.autoplay = (_a = options.autoplay) !== null && _a !== void 0 ? _a : true;
15609
+ this.interval = (_b = options.interval) !== null && _b !== void 0 ? _b : 10000;
15610
+ this.dotsOptions = this.initializeDotOptions(options.useDots);
15611
+ this.buttonsOptions = this.initializeButtonOptions(options.useButtons);
15612
+ this.validateOptions();
15613
+ this.carousel = document.createElement('div');
15614
+ this.carousel.className = 'carousel';
15615
+ this.shadowRoot = this.carousel.attachShadow({ mode: 'open' });
15616
+ this.render();
15617
+ this.slidesContainer = this.shadowRoot.querySelector('.carousel-slides');
15618
+ this.setupCarousel();
15619
+ }
15620
+ // Public method to get the carousel element
15621
+ getElement() {
15622
+ return this.carousel;
15623
+ }
15624
+ // Main setup methods
15625
+ render() {
15626
+ const style = document.createElement('style');
15627
+ style.textContent = CAROUSEL_COMPONENT_STYLE;
15628
+ this.shadowRoot.appendChild(style);
15629
+ this.shadowRoot.appendChild(this.renderSlides());
15630
+ if (this.dotsOptions) {
15631
+ const dots = this.renderDots();
15632
+ if (dots)
15633
+ this.shadowRoot.appendChild(dots);
15634
+ }
15635
+ if (this.buttonsOptions) {
15636
+ const buttons = this.renderButtons();
15637
+ if (buttons)
15638
+ this.shadowRoot.appendChild(buttons);
15639
+ }
15640
+ }
15641
+ setupCarousel() {
15642
+ this.setupDots();
15643
+ this.setupButtons();
15644
+ if (this.autoplay) {
15645
+ this.startAutoplay();
15646
+ }
15647
+ this.updateCarousel();
15648
+ }
15649
+ // Rendering methods
15650
+ renderSlides() {
15651
+ const slidesContainer = document.createElement('div');
15652
+ slidesContainer.className = 'carousel-slides';
15653
+ this.slides.forEach((slide, index) => {
15654
+ const slideElement = document.createElement('div');
15655
+ slideElement.className = `carousel-slide ${index === this.currentSlide ? 'active' : ''}`;
15656
+ if (typeof slide === 'string') {
15657
+ slideElement.innerHTML = slide;
15658
+ }
15659
+ else if (slide instanceof HTMLElement) {
15660
+ slideElement.appendChild(slide);
15661
+ }
15662
+ slidesContainer.appendChild(slideElement);
15663
+ });
15664
+ return slidesContainer;
15665
+ }
15666
+ renderDots() {
15667
+ if (!this.dotsOptions)
15668
+ return null;
15669
+ const dotsContainer = document.createElement('div');
15670
+ dotsContainer.className = `carousel-dots ${this.dotsOptions.position}`;
15671
+ this.slides.forEach((_, index) => {
15672
+ if (!this.dotsOptions)
15673
+ return;
15674
+ const dot = document.createElement('span');
15675
+ dot.className = `dot ${index === this.currentSlide ? 'active' : ''}`;
15676
+ dot.style.backgroundColor = this.dotsOptions.color;
15677
+ dotsContainer.appendChild(dot);
15678
+ });
15679
+ return dotsContainer;
15680
+ }
15681
+ renderButtons() {
15682
+ if (!this.buttonsOptions)
15683
+ return null;
15684
+ const buttonsContainer = document.createElement('div');
15685
+ const buttonsClass = this.buttonsOptions.together
15686
+ ? `buttons-together ${this.buttonsOptions.position}`
15687
+ : 'buttons-separate';
15688
+ buttonsContainer.className = `carousel-buttons ${buttonsClass}`;
15689
+ this.prevButton = document.createElement('button');
15690
+ this.prevButton.className = 'prev-button';
15691
+ this.prevButton.textContent = this.buttonsOptions.prev;
15692
+ this.prevButton.style.color = this.buttonsOptions.textColor;
15693
+ this.prevButton.style.backgroundColor = this.buttonsOptions.backgroundColor;
15694
+ this.prevButton.style.borderRadius = this.buttonsOptions.borderRadius;
15695
+ buttonsContainer.appendChild(this.prevButton);
15696
+ this.nextButton = document.createElement('button');
15697
+ this.nextButton.className = 'next-button';
15698
+ this.nextButton.textContent = this.buttonsOptions.next;
15699
+ this.nextButton.style.color = this.buttonsOptions.textColor;
15700
+ this.nextButton.style.backgroundColor = this.buttonsOptions.backgroundColor;
15701
+ this.nextButton.style.borderRadius = this.buttonsOptions.borderRadius;
15702
+ buttonsContainer.appendChild(this.nextButton);
15703
+ return buttonsContainer;
15704
+ }
15705
+ // Setup methods
15706
+ setupDots() {
15707
+ if (this.dotsOptions) {
15708
+ this.dotElements = Array.from(this.shadowRoot.querySelectorAll('.dot'));
15709
+ this.dotElements.forEach((dot, index) => {
15710
+ dot.addEventListener('click', () => {
15711
+ this.goToSlide(index);
15712
+ this.resetAutoplay();
15713
+ });
15714
+ });
15715
+ }
15716
+ }
15717
+ setupButtons() {
15718
+ var _a, _b;
15719
+ if (this.buttonsOptions) {
15720
+ (_a = this.prevButton) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
15721
+ this.prevSlide();
15722
+ this.resetAutoplay();
15723
+ });
15724
+ (_b = this.nextButton) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
15725
+ this.nextSlide();
15726
+ this.resetAutoplay();
15727
+ });
15728
+ }
15729
+ }
15730
+ // Navigation methods
15731
+ nextSlide() {
15732
+ this.goToSlide((this.currentSlide + 1) % this.slides.length);
15733
+ }
15734
+ prevSlide() {
15735
+ this.goToSlide((this.currentSlide - 1 + this.slides.length) % this.slides.length);
15736
+ }
15737
+ goToSlide(index) {
15738
+ this.currentSlide = index;
15739
+ this.updateCarousel();
15740
+ }
15741
+ // Update methods
15742
+ updateCarousel() {
15743
+ const slides = Array.from(this.slidesContainer.children);
15744
+ slides.forEach((slide, index) => {
15745
+ if (index === this.currentSlide) {
15746
+ slide.classList.add('active');
15747
+ }
15748
+ else {
15749
+ slide.classList.remove('active');
15750
+ }
15751
+ });
15752
+ this.updateDots();
15753
+ }
15754
+ updateDots() {
15755
+ this.dotElements.forEach((dot, index) => {
15756
+ const isActive = index === this.currentSlide;
15757
+ dot.classList.toggle('active', isActive);
15758
+ if (!this.dotsOptions)
15759
+ return;
15760
+ dot.style.backgroundColor = isActive ? this.dotsOptions.activeColor : this.dotsOptions.color;
15761
+ });
15762
+ }
15763
+ // Autoplay methods
15764
+ startAutoplay() {
15765
+ this.autoplayInterval = window.setInterval(() => this.nextSlide(), this.interval);
15766
+ }
15767
+ stopAutoplay() {
15768
+ if (this.autoplayInterval !== null) {
15769
+ window.clearInterval(this.autoplayInterval);
15770
+ this.autoplayInterval = null;
15771
+ }
15772
+ }
15773
+ resetAutoplay() {
15774
+ if (this.autoplay) {
15775
+ this.stopAutoplay();
15776
+ this.startAutoplay();
15777
+ }
15778
+ }
15779
+ // Initialization and validation methods
15780
+ initializeDotOptions(useDots) {
15781
+ var _a, _b, _c;
15782
+ return !useDots
15783
+ ? false
15784
+ : {
15785
+ position: (_a = useDots === null || useDots === void 0 ? void 0 : useDots.position) !== null && _a !== void 0 ? _a : 'bottom-center',
15786
+ color: (_b = useDots === null || useDots === void 0 ? void 0 : useDots.color) !== null && _b !== void 0 ? _b : '#d9d9d9',
15787
+ activeColor: (_c = useDots === null || useDots === void 0 ? void 0 : useDots.activeColor) !== null && _c !== void 0 ? _c : '#b5914a',
15788
+ };
15789
+ }
15790
+ initializeButtonOptions(useButtons) {
15791
+ var _a, _b, _c, _d, _e, _f, _g;
15792
+ return !useButtons
15793
+ ? false
15794
+ : {
15795
+ position: (_a = useButtons === null || useButtons === void 0 ? void 0 : useButtons.position) !== null && _a !== void 0 ? _a : 'middle-sides',
15796
+ together: (_b = useButtons === null || useButtons === void 0 ? void 0 : useButtons.together) !== null && _b !== void 0 ? _b : false,
15797
+ textColor: (_c = useButtons === null || useButtons === void 0 ? void 0 : useButtons.textColor) !== null && _c !== void 0 ? _c : '#000000',
15798
+ backgroundColor: (_d = useButtons === null || useButtons === void 0 ? void 0 : useButtons.backgroundColor) !== null && _d !== void 0 ? _d : '#ffffff',
15799
+ borderRadius: (_e = useButtons === null || useButtons === void 0 ? void 0 : useButtons.borderRadius) !== null && _e !== void 0 ? _e : '50%',
15800
+ prev: (_f = useButtons === null || useButtons === void 0 ? void 0 : useButtons.prev) !== null && _f !== void 0 ? _f : 'Prev',
15801
+ next: (_g = useButtons === null || useButtons === void 0 ? void 0 : useButtons.next) !== null && _g !== void 0 ? _g : 'Next',
15802
+ };
15803
+ }
15804
+ validateOptions() {
15805
+ const validPositions = [
15806
+ 'top-left',
15807
+ 'top-center',
15808
+ 'top-right',
15809
+ 'bottom-left',
15810
+ 'bottom-center',
15811
+ 'bottom-right',
15812
+ 'middle-left',
15813
+ 'middle-right',
15814
+ 'middle-sides',
15815
+ ];
15816
+ this.validateDotsPosition(validPositions);
15817
+ this.validateButtonsPosition(validPositions);
15818
+ }
15819
+ validateDotsPosition(validPositions) {
15820
+ if (this.dotsOptions && !validPositions.includes(this.dotsOptions.position)) {
15821
+ console.warn(`Invalid dotsPosition: ${this.dotsOptions.position}. Defaulting to 'bottom-center'.`);
15822
+ this.dotsOptions.position = 'bottom-center';
15823
+ }
15824
+ }
15825
+ validateButtonsPosition(validPositions) {
15826
+ if (this.buttonsOptions) {
15827
+ if (this.buttonsOptions.together) {
15828
+ if (!validPositions.includes(this.buttonsOptions.position)) {
15829
+ console.warn(`Invalid buttonsPosition: ${this.buttonsOptions.position}. Defaulting to 'bottom-center'.`);
15830
+ this.buttonsOptions.position = 'bottom-center';
15831
+ }
15832
+ }
15833
+ else if (this.buttonsOptions.position !== 'middle-sides') {
15834
+ console.warn(`Invalid buttonsPosition: ${this.buttonsOptions.position}. When buttons are not together, only 'middle-sides' is allowed. Defaulting to 'middle-sides'.`);
15835
+ this.buttonsOptions.position = 'middle-sides';
15836
+ }
15837
+ }
15838
+ }
15839
+ }
15840
+
15209
15841
  const STYLES$i = ({ primaryImage, secondaryImage }) => `
15210
15842
  <style>
15211
15843
  .content {
@@ -15301,9 +15933,9 @@ const STYLES$i = ({ primaryImage, secondaryImage }) => `
15301
15933
  `;
15302
15934
  function billboardV1Template(spot) {
15303
15935
  return `
15304
- ${GFONT_PRECONNECT()}
15305
- ${GFONT_SOURCE_SANS_3()}
15306
- ${GFONT_CORMORANT()}
15936
+ ${GFONT_PRECONNECT}
15937
+ ${GFONT_SOURCE_SANS_3}
15938
+ ${GFONT_CORMORANT}
15307
15939
  ${STYLES$i(spot)}
15308
15940
  <div class="content">
15309
15941
  <div class="big-image"></div>
@@ -15390,9 +16022,9 @@ const STYLES$h = ({ primaryImage }) => `
15390
16022
  `;
15391
16023
  function billboardV2Template(spot) {
15392
16024
  return `
15393
- ${GFONT_PRECONNECT()}
15394
- ${GFONT_SOURCE_SANS_3()}
15395
- ${GFONT_CORMORANT()}
16025
+ ${GFONT_PRECONNECT}
16026
+ ${GFONT_SOURCE_SANS_3}
16027
+ ${GFONT_CORMORANT}
15396
16028
  ${STYLES$h(spot)}
15397
16029
  <div class="content">
15398
16030
  <div class="text-container">
@@ -15491,9 +16123,9 @@ const STYLES$g = ({ primaryImage }) => `
15491
16123
  `;
15492
16124
  function billboardV3Template(spot) {
15493
16125
  return `
15494
- ${GFONT_PRECONNECT()}
15495
- ${GFONT_SOURCE_SANS_3()}
15496
- ${GFONT_CORMORANT()}
16126
+ ${GFONT_PRECONNECT}
16127
+ ${GFONT_SOURCE_SANS_3}
16128
+ ${GFONT_CORMORANT}
15497
16129
  ${STYLES$g(spot)}
15498
16130
  <div class="content">
15499
16131
  <div class="text">
@@ -15535,9 +16167,9 @@ const STYLES$f = () => `
15535
16167
  `;
15536
16168
  function inTextV1Template(spot) {
15537
16169
  return `
15538
- ${GFONT_PRECONNECT()}
15539
- ${GFONT_SOURCE_SANS_3()}
15540
- ${GFONT_CORMORANT()}
16170
+ ${GFONT_PRECONNECT}
16171
+ ${GFONT_SOURCE_SANS_3}
16172
+ ${GFONT_CORMORANT}
15541
16173
  ${STYLES$f()}
15542
16174
  <div class="content">
15543
16175
  <span class="header">${spot.header}</span>
@@ -15625,9 +16257,9 @@ const STYLES$e = ({ primaryImage }) => `
15625
16257
  `;
15626
16258
  function largeLeaderboardV1Template(spot) {
15627
16259
  return `
15628
- ${GFONT_PRECONNECT()}
15629
- ${GFONT_SOURCE_SANS_3()}
15630
- ${GFONT_CORMORANT()}
16260
+ ${GFONT_PRECONNECT}
16261
+ ${GFONT_SOURCE_SANS_3}
16262
+ ${GFONT_CORMORANT}
15631
16263
  ${STYLES$e(spot)}
15632
16264
  <div class="content">
15633
16265
  <div class="text">
@@ -15712,9 +16344,9 @@ const STYLES$d = ({ primaryImage }) => `
15712
16344
  `;
15713
16345
  function largeLeaderboardV2Template(spot) {
15714
16346
  return `
15715
- ${GFONT_PRECONNECT()}
15716
- ${GFONT_SOURCE_SANS_3()}
15717
- ${GFONT_CORMORANT()}
16347
+ ${GFONT_PRECONNECT}
16348
+ ${GFONT_SOURCE_SANS_3}
16349
+ ${GFONT_CORMORANT}
15718
16350
  ${STYLES$d(spot)}
15719
16351
  <div class="content">
15720
16352
  <div class="text">
@@ -15771,9 +16403,9 @@ const STYLES$c = ({ primaryImage }) => `
15771
16403
  `;
15772
16404
  function largeRectangleV1Template(spot) {
15773
16405
  return `
15774
- ${GFONT_PRECONNECT()}
15775
- ${GFONT_SOURCE_SANS_3()}
15776
- ${GFONT_CORMORANT()}
16406
+ ${GFONT_PRECONNECT}
16407
+ ${GFONT_SOURCE_SANS_3}
16408
+ ${GFONT_CORMORANT}
15777
16409
  ${STYLES$c(spot)}
15778
16410
  <div class="content">
15779
16411
  <div class="image"></div>
@@ -15869,9 +16501,9 @@ const STYLES$b = ({ primaryImage }) => `
15869
16501
  `;
15870
16502
  function squareV1Template(spot) {
15871
16503
  return `
15872
- ${GFONT_PRECONNECT()}
15873
- ${GFONT_SOURCE_SANS_3()}
15874
- ${GFONT_CORMORANT()}
16504
+ ${GFONT_PRECONNECT}
16505
+ ${GFONT_SOURCE_SANS_3}
16506
+ ${GFONT_CORMORANT}
15875
16507
  ${STYLES$b(spot)}
15876
16508
  <div class="content">
15877
16509
  <div class="text">
@@ -15924,9 +16556,9 @@ const STYLES$a = ({ primaryImage }) => `
15924
16556
  `;
15925
16557
  function squareV2Template(spot) {
15926
16558
  return `
15927
- ${GFONT_PRECONNECT()}
15928
- ${GFONT_SOURCE_SANS_3()}
15929
- ${GFONT_CORMORANT()}
16559
+ ${GFONT_PRECONNECT}
16560
+ ${GFONT_SOURCE_SANS_3}
16561
+ ${GFONT_CORMORANT}
15930
16562
  ${STYLES$a(spot)}
15931
16563
  <div class="content">
15932
16564
  <span class="header">${spot.header}</span>
@@ -15989,9 +16621,9 @@ const STYLES$9 = ({ primaryImage }) => `
15989
16621
  `;
15990
16622
  function verticalRectangleV1Template(spot) {
15991
16623
  return `
15992
- ${GFONT_PRECONNECT()}
15993
- ${GFONT_SOURCE_SANS_3()}
15994
- ${GFONT_CORMORANT()}
16624
+ ${GFONT_PRECONNECT}
16625
+ ${GFONT_SOURCE_SANS_3}
16626
+ ${GFONT_CORMORANT}
15995
16627
  ${STYLES$9(spot)}
15996
16628
  <div class="content">
15997
16629
  <div class="text">
@@ -16023,175 +16655,221 @@ function wideSkyscraperV1Template(spot) {
16023
16655
  `;
16024
16656
  }
16025
16657
 
16026
- const STYLES$7 = ({ primaryImage, mobilePrimaryImage = primaryImage }) => `
16027
- <style>
16028
- :host {
16029
- min-width: 320px;
16030
- min-height: 223px;
16031
- }
16032
- .content {
16033
- display: block;
16034
- width: 100%;
16035
- height: 100%;
16036
- background-image: url("${mobilePrimaryImage}");
16037
- background-size: cover;
16038
- background-repeat: no-repeat;
16039
- background-position: center;
16040
- cursor: pointer;
16041
- }
16042
- @media (min-width: 640px) {
16043
- .content {
16044
- background-image: url("${primaryImage}");
16045
- }
16658
+ const STYLES$7 = ({ primaryImage, mobilePrimaryImage = primaryImage }, { prefix }) => `
16659
+ <style>
16660
+ :host {
16661
+ min-width: 320px;
16662
+ min-height: 223px;
16663
+ }
16664
+
16665
+ .${prefix}__content {
16666
+ display: block;
16667
+ width: 100%;
16668
+ height: 100%;
16669
+ background-image: url("${mobilePrimaryImage}");
16670
+ background-size: cover;
16671
+ background-repeat: no-repeat;
16672
+ background-position: center;
16673
+ cursor: pointer;
16674
+ }
16675
+
16676
+ @media (min-width: 640px) {
16677
+ .${prefix}__content {
16678
+ background-image: url("${primaryImage}");
16046
16679
  }
16047
- </style>
16680
+ }
16681
+ </style>
16048
16682
  `;
16049
- function rbCollectionBannerWithoutTextBlockTemplate(spot) {
16683
+ function rbCollectionBannerWithoutTextBlockTemplate(spot, config) {
16684
+ const { prefix = '' } = config;
16050
16685
  return `
16051
- ${STYLES$7(spot)}
16052
- <div class="content"></div>
16686
+ ${STYLES$7(spot, config)}
16687
+ <div class="${prefix}__content"></div>
16053
16688
  `;
16054
16689
  }
16055
16690
 
16056
- const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }) => `
16057
- <style>
16058
- :host {
16059
- min-width: 320px;
16060
- min-height: 388px;
16061
- }
16062
- .content {
16063
- display: flex;
16064
- flex-direction: column;
16065
- justify-content: flex-end;
16066
- align-items: flex-start;
16067
- width: 100%;
16068
- height: 100%;
16069
- background-image: url("${mobilePrimaryImage}");
16070
- background-size: cover;
16071
- background-repeat: no-repeat;
16072
- background-position: center;
16073
- padding: 3%;
16074
- box-sizing: border-box;
16075
- color: ${textColor};
16076
- cursor: pointer;
16077
- }
16078
- .text {
16079
- display: flex;
16080
- flex-direction: column;
16081
- justify-content: flex-start;
16082
- align-items: flex-start;
16083
- width: 100%;
16084
- height: fit-content;
16085
- gap: 5px;
16086
- }
16087
- .header {
16088
- font-size: 18px;
16089
- margin: 0;
16090
- font-family: "Cormorant";
16091
- font-style: normal;
16092
- font-weight: 300;
16093
- line-height: normal;
16094
- }
16095
- .description {
16096
- font-size: 10px;
16097
- font-family: "Source Sans 3", system-ui;
16098
- font-style: normal;
16099
- font-weight: 400;
16100
- line-height: 20px;
16101
- margin: 0;
16102
- }
16103
- .cta-button {
16104
- font-size: 8px;
16105
- font-family: "Source Sans 3", system-ui;
16106
- font-style: normal;
16107
- font-weight: 400;
16108
- line-height: 18px;
16109
- border-radius: 5px;
16110
- border: 0.5px solid ${ctaBorderColor};
16111
- display: inline-block;
16112
- padding: 7px 20px;
16113
- color: ${ctaTextColor};
16114
- transition: background-color 0.3s ease;
16115
- }
16116
- .content:hover .cta-button {
16117
- background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
16118
- }
16119
- @media (min-width: 640px) {
16120
- .content {
16121
- background-image: url("${primaryImage}");
16122
- }
16123
- }
16124
- @media (min-width: 768px) {
16125
- .primary-image {
16126
- width: 66.66666%;
16691
+ function linearGradientColorStop(overlay, fallback) {
16692
+ if (!overlay || overlay.length === 0) {
16693
+ return fallback;
16694
+ }
16695
+ return overlay.map(({ color, colorStop }) => `${color} ${colorStop}`).join(', ');
16696
+ }
16697
+
16698
+ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
16699
+ const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 40%');
16700
+ return `
16701
+ <style>
16702
+ .${prefix} {
16703
+ min-width: 320px;
16704
+ min-height: 388px;
16705
+ width: 100%;
16127
16706
  height: 100%;
16707
+ display: block;
16708
+ position: relative;
16709
+ container-type: inline-size;
16128
16710
  }
16129
- .main {
16711
+
16712
+ .${prefix}__content {
16713
+ display: flex;
16130
16714
  flex-direction: column;
16715
+ justify-content: flex-end;
16716
+ align-items: flex-start;
16717
+ width: 100%;
16131
16718
  height: 100%;
16132
- width: 33.33333%;
16719
+ background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
16720
+ background-size: cover;
16721
+ background-repeat: no-repeat;
16722
+ background-position: center;
16723
+ padding: 3%;
16724
+ box-sizing: border-box;
16725
+ color: ${textColor};
16726
+ cursor: pointer;
16133
16727
  }
16134
- .secondary-image {
16728
+
16729
+ .${prefix}__text {
16730
+ display: flex;
16731
+ flex-direction: column;
16732
+ justify-content: flex-start;
16733
+ align-items: flex-start;
16135
16734
  width: 100%;
16136
- height: 50%;
16137
- }
16138
- .header {
16139
- font-size: 22px;
16735
+ height: fit-content;
16736
+ gap: 5px;
16140
16737
  }
16141
- .description {
16142
- font-size: 12px;
16738
+
16739
+ .${prefix}__header {
16740
+ font-size: 18px;
16741
+ margin: 0;
16742
+ font-family: "Cormorant";
16743
+ font-style: normal;
16744
+ font-weight: 300;
16745
+ line-height: normal;
16143
16746
  }
16144
- .cta-button {
16145
- font-size: 12px;
16747
+
16748
+ .${prefix}__description {
16749
+ font-size: 10px;
16750
+ font-family: "Source Sans 3", system-ui;
16751
+ font-style: normal;
16752
+ font-weight: 400;
16753
+ line-height: 20px;
16754
+ margin: 0;
16146
16755
  }
16147
- }
16148
- @media (min-width: 1024px) {
16149
- .header {
16150
- font-size: 24px;
16756
+
16757
+ .${prefix}__cta-button {
16758
+ font-size: 8px;
16759
+ font-family: "Source Sans 3", system-ui;
16760
+ font-style: normal;
16761
+ font-weight: 400;
16762
+ line-height: 18px;
16763
+ border-radius: 5px;
16764
+ border: 0.5px solid ${ctaBorderColor};
16765
+ display: inline-block;
16766
+ padding: 7px 20px;
16767
+ color: ${ctaTextColor};
16768
+ transition: background-color 0.3s ease;
16151
16769
  }
16152
- .description {
16153
- font-size: 13px;
16770
+
16771
+ .${prefix}__content:hover .cta-button {
16772
+ background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
16154
16773
  }
16155
- .cta-button {
16156
- font-size: 13px;
16774
+
16775
+ @media (min-width: 640px) {
16776
+ .${prefix}__content {
16777
+ background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
16778
+ }
16157
16779
  }
16158
- }
16159
- @media (min-width: 1280px) {
16160
- .header {
16161
- font-size: 28px;
16780
+
16781
+ @media (min-width: 768px) {
16782
+ .${prefix}__primary-image {
16783
+ width: 66.66666%;
16784
+ height: 100%;
16785
+ }
16786
+
16787
+ .${prefix}__main {
16788
+ flex-direction: column;
16789
+ height: 100%;
16790
+ width: 33.33333%;
16791
+ }
16792
+
16793
+ .${prefix}__secondary-image {
16794
+ width: 100%;
16795
+ height: 50%;
16796
+ }
16797
+
16798
+ .${prefix}__header {
16799
+ font-size: 22px;
16800
+ }
16801
+
16802
+ .${prefix}__description {
16803
+ font-size: 12px;
16804
+ }
16805
+
16806
+ .${prefix}__cta-button {
16807
+ font-size: 12px;
16808
+ }
16162
16809
  }
16163
- .description {
16164
- font-size: 14px;
16810
+
16811
+ @media (min-width: 1024px) {
16812
+ .${prefix}__header {
16813
+ font-size: 24px;
16814
+ }
16815
+
16816
+ .${prefix}__description {
16817
+ font-size: 13px;
16818
+ }
16819
+
16820
+ .${prefix}__cta-button {
16821
+ font-size: 13px;
16822
+ }
16165
16823
  }
16166
- .cta-button {
16167
- font-size: 14px;
16824
+
16825
+ @media (min-width: 1280px) {
16826
+ .${prefix}__header {
16827
+ font-size: 28px;
16828
+ }
16829
+
16830
+ .${prefix}__description {
16831
+ font-size: 14px;
16832
+ }
16833
+
16834
+ .${prefix}__cta-button {
16835
+ font-size: 14px;
16836
+ }
16168
16837
  }
16169
- }
16170
- </style>
16171
- `;
16172
- function rbHomepageHeroFullImageTemplate(spot) {
16838
+ </style>
16839
+ `;
16840
+ };
16841
+ function rbHomepageHeroFullImageTemplate(spot, config) {
16842
+ const { prefix = '' } = config;
16173
16843
  return `
16174
- ${GFONT_PRECONNECT()}
16175
- ${GFONT_SOURCE_SANS_3()}
16176
- ${GFONT_CORMORANT()}
16177
- ${STYLES$6(spot)}
16178
- <div class="content">
16179
- <div class="text">
16180
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
16181
- ${spot.description ? `<p class="description">${spot.description}</p>` : ''}
16182
- ${spot.ctaText ? `<span class="cta-button">${spot.ctaText}</span>` : ''}
16844
+ ${GFONT_PRECONNECT}
16845
+ ${GFONT_SOURCE_SANS_3}
16846
+ ${GFONT_CORMORANT}
16847
+ ${STYLES$6(spot, config)}
16848
+ <div class="${prefix}">
16849
+ <div class="${prefix}__content">
16850
+ <div class="${prefix}__text">
16851
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
16852
+ ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
16853
+ ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
16854
+ </div>
16183
16855
  </div>
16184
16856
  </div>
16185
16857
  `;
16186
16858
  }
16187
16859
 
16188
- const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, secondaryImage, mobileSecondaryImage = secondaryImage, }) => `
16189
- <style>
16190
- :host {
16860
+ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, secondaryImage, mobileSecondaryImage = secondaryImage, }, { prefix }) => `
16861
+ <style>
16862
+ .${prefix} {
16191
16863
  min-width: 320px;
16192
16864
  min-height: 388px;
16865
+ width: 100%;
16866
+ height: 100%;
16867
+ display: block;
16868
+ position: relative;
16869
+ container-type: inline-size;
16193
16870
  }
16194
- .content {
16871
+
16872
+ .${prefix}__content {
16195
16873
  width: 100%;
16196
16874
  height: 100%;
16197
16875
  display: flex;
@@ -16201,7 +16879,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16201
16879
  color: inherit;
16202
16880
  cursor: pointer;
16203
16881
  }
16204
- .primary-image {
16882
+
16883
+ .${prefix}__primary-image {
16205
16884
  width: 100%;
16206
16885
  height: 60%;
16207
16886
  background-image: url("${mobilePrimaryImage}");
@@ -16209,14 +16888,16 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16209
16888
  background-repeat: no-repeat;
16210
16889
  background-size: cover;
16211
16890
  }
16212
- .main {
16891
+
16892
+ .${prefix}__main {
16213
16893
  width: 100%;
16214
16894
  height: 40%;
16215
16895
  display: flex;
16216
16896
  flex-direction: row;
16217
16897
  gap: 5px;
16218
16898
  }
16219
- .secondary-image {
16899
+
16900
+ .${prefix}__secondary-image {
16220
16901
  width: 50%;
16221
16902
  height: 100%;
16222
16903
  background-image: url("${mobileSecondaryImage}");
@@ -16224,7 +16905,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16224
16905
  background-repeat: no-repeat;
16225
16906
  background-size: cover;
16226
16907
  }
16227
- .text {
16908
+
16909
+ .${prefix}__text {
16228
16910
  color: ${textColor};
16229
16911
  background-color: ${backgroundColor};
16230
16912
  text-align: center;
@@ -16238,7 +16920,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16238
16920
  padding: 0 10px;
16239
16921
  box-sizing: border-box;
16240
16922
  }
16241
- .header {
16923
+
16924
+ .${prefix}__header {
16242
16925
  color: inherit;
16243
16926
  margin: 0;
16244
16927
  font-size: 18px;
@@ -16247,7 +16930,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16247
16930
  font-weight: 700;
16248
16931
  line-height: normal;
16249
16932
  }
16250
- .description {
16933
+
16934
+ .${prefix}__description {
16251
16935
  color: inherit;
16252
16936
  margin: 0;
16253
16937
  font-size: 10px;
@@ -16255,7 +16939,8 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16255
16939
  font-style: normal;
16256
16940
  font-weight: 400;
16257
16941
  }
16258
- .cta-button {
16942
+
16943
+ .${prefix}__cta-button {
16259
16944
  color: ${ctaTextColor};
16260
16945
  background-color: transparent;
16261
16946
  font-size: 8px;
@@ -16270,99 +16955,85 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16270
16955
  padding: 0;
16271
16956
  transition: opacity 0.3s ease;
16272
16957
  }
16273
- .content:hover .cta-button {
16958
+
16959
+ .${prefix}__content:hover .${prefix}__cta-button {
16274
16960
  opacity: 0.8;
16275
16961
  }
16962
+
16276
16963
  @media (min-width: 640px) {
16277
- .primary-image {
16964
+ .${prefix}__primary-image {
16278
16965
  background-image: url("${primaryImage}");
16279
16966
  }
16280
- .secondary-image {
16967
+
16968
+ .${prefix}__secondary-image {
16281
16969
  background-image: url("${secondaryImage}");
16282
16970
  }
16283
16971
  }
16972
+
16284
16973
  @media (min-width: 768px) {
16285
- .content {
16974
+ .${prefix}__content {
16286
16975
  flex-direction: row;
16287
16976
  }
16288
- .primary-image {
16977
+
16978
+ .${prefix}__primary-image {
16289
16979
  width: 66.66666%;
16290
16980
  height: 100%;
16291
16981
  }
16292
- .main {
16982
+
16983
+ .${prefix}__main {
16293
16984
  flex-direction: column;
16294
16985
  height: 100%;
16295
16986
  width: 33.33333%;
16296
16987
  }
16297
- .secondary-image {
16988
+
16989
+ .${prefix}__secondary-image {
16298
16990
  width: 100%;
16299
16991
  height: 50%;
16300
16992
  }
16301
- .text {
16993
+
16994
+ .${prefix}__text {
16302
16995
  width: 100%;
16303
16996
  height: 50%;
16304
16997
  }
16305
- .header {
16306
- font-size: 22px;
16307
- }
16308
- .description {
16309
- font-size: 12px;
16310
- }
16311
- .cta-button {
16312
- font-size: 12px;
16313
- }
16314
- }
16315
- @media (min-width: 1024px) {
16316
- .header {
16317
- font-size: 24px;
16318
- }
16319
- .description {
16320
- font-size: 13px;
16321
- }
16322
- .cta-button {
16323
- font-size: 13px;
16324
- }
16325
16998
  }
16326
- @media (min-width: 1280px) {
16327
- .header {
16328
- font-size: 28px;
16329
- }
16330
- .description {
16331
- font-size: 14px;
16332
- }
16333
- .cta-button {
16334
- font-size: 14px;
16335
- }
16336
- }
16337
- </style>
16999
+ </style>
16338
17000
  `;
16339
- function rbHomepageHeroThreeTileTemplate(spot) {
17001
+ function rbHomepageHeroThreeTileTemplate(spot, config) {
17002
+ const { prefix = '' } = config;
16340
17003
  return `
16341
- ${GFONT_PRECONNECT()}
16342
- ${GFONT_SOURCE_SANS_3()}
16343
- ${GFONT_CORMORANT()}
16344
- ${STYLES$5(spot)}
16345
- <div class="content">
16346
- <div class="primary-image"></div>
16347
- <div class="main">
16348
- <div class="secondary-image"></div>
16349
- <div class="text">
16350
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
16351
- ${spot.description ? `<p class="description">${spot.description}</p>` : ''}
16352
- ${spot.ctaText ? `<span class="cta-button">${spot.ctaText}</span>` : ''}
17004
+ ${GFONT_PRECONNECT}
17005
+ ${GFONT_SOURCE_SANS_3}
17006
+ ${GFONT_CORMORANT}
17007
+ ${STYLES$5(spot, config)}
17008
+ <div class="${prefix}">
17009
+ <div class="${prefix}__content">
17010
+ <div class="${prefix}__primary-image"></div>
17011
+ <div class="${prefix}__main">
17012
+ <div class="${prefix}__secondary-image"></div>
17013
+ <div class="${prefix}__text">
17014
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17015
+ ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
17016
+ ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
17017
+ </div>
16353
17018
  </div>
16354
17019
  </div>
16355
17020
  </div>
16356
17021
  `;
16357
17022
  }
16358
17023
 
16359
- const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }) => `
17024
+ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
16360
17025
  <style>
16361
- :host {
17026
+ .${prefix} {
16362
17027
  min-width: 320px;
16363
17028
  min-height: 388px;
17029
+ width: 100%;
17030
+ height: 100%;
17031
+ display: block;
17032
+ position: relative;
17033
+ container-type: inline-size;
16364
17034
  }
16365
- .content {
17035
+
17036
+ .${prefix}__content {
16366
17037
  width: 100%;
16367
17038
  height: 100%;
16368
17039
  display: flex;
@@ -16371,7 +17042,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16371
17042
  gap: 5px;
16372
17043
  cursor: pointer;
16373
17044
  }
16374
- .image {
17045
+
17046
+ .${prefix}__image {
16375
17047
  width: 100%;
16376
17048
  height: 100%;
16377
17049
  background-image: url("${mobilePrimaryImage}");
@@ -16379,7 +17051,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16379
17051
  background-repeat: no-repeat;
16380
17052
  background-size: cover;
16381
17053
  }
16382
- .text {
17054
+
17055
+ .${prefix}__text {
16383
17056
  color: ${textColor};
16384
17057
  background-color: ${backgroundColor};
16385
17058
  text-align: center;
@@ -16393,7 +17066,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16393
17066
  padding: 0 10px;
16394
17067
  box-sizing: border-box;
16395
17068
  }
16396
- .header {
17069
+
17070
+ .${prefix}__header {
16397
17071
  font-size: 18px;
16398
17072
  margin: 0;
16399
17073
  color: inherit;
@@ -16402,7 +17076,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16402
17076
  font-weight: 700;
16403
17077
  line-height: normal;
16404
17078
  }
16405
- .description {
17079
+
17080
+ .${prefix}__description {
16406
17081
  color: inherit;
16407
17082
  margin: 0;
16408
17083
  font-size: 10px;
@@ -16410,7 +17085,8 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16410
17085
  font-style: normal;
16411
17086
  font-weight: 400;
16412
17087
  }
16413
- .cta-button {
17088
+
17089
+ .${prefix}__cta-button {
16414
17090
  color: ${ctaTextColor};
16415
17091
  background-color: transparent;
16416
17092
  font-size: 8px;
@@ -16425,205 +17101,202 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16425
17101
  padding: 0;
16426
17102
  transition: opacity 0.3s ease;
16427
17103
  }
16428
- .content:hover .cta-button {
17104
+
17105
+ .${prefix}__content:hover .${prefix}__cta-button {
16429
17106
  opacity: 0.8;
16430
17107
  }
17108
+
16431
17109
  @media (min-width: 640px) {
16432
- .image {
17110
+ .${prefix}__image {
16433
17111
  background-image: url("${primaryImage}");
16434
17112
  }
16435
17113
  }
16436
17114
  @media (min-width: 768px) {
16437
- .content {
17115
+ .${prefix}__content {
16438
17116
  flex-direction: row;
16439
17117
  }
16440
- .image {
17118
+
17119
+ .${prefix}__image {
16441
17120
  width: 66.66666%;
16442
17121
  height: 100%;
16443
17122
  }
16444
- .text {
16445
- width: 33.333%;
17123
+
17124
+ .${prefix}__text {
17125
+ width: 33.33333%;
16446
17126
  height: 100%;
16447
17127
  }
16448
- .header {
16449
- font-size: 22px;
16450
- }
16451
- .description {
16452
- font-size: 12px;
16453
- }
16454
- .cta-button {
16455
- font-size: 12px;
16456
- }
16457
- }
16458
- @media (min-width: 1024px) {
16459
- .header {
16460
- font-size: 24px;
16461
- }
16462
- .description {
16463
- font-size: 13px;
16464
- }
16465
- .cta-button {
16466
- font-size: 13px;
16467
- }
16468
- }
16469
- @media (min-width: 1280px) {
16470
- .header {
16471
- font-size: 28px;
16472
- }
16473
- .description {
16474
- font-size: 14px;
16475
- }
16476
- .cta-button {
16477
- font-size: 14px;
16478
- }
16479
17128
  }
16480
17129
  </style>
16481
17130
  `;
16482
- function rbHomepageHeroTwoTileTemplate(spot) {
17131
+ function rbHomepageHeroTwoTileTemplate(spot, config) {
17132
+ const { prefix = '' } = config;
16483
17133
  return `
16484
- ${GFONT_PRECONNECT()}
16485
- ${GFONT_SOURCE_SANS_3()}
16486
- ${GFONT_CORMORANT()}
16487
- ${STYLES$4(spot)}
16488
- <div class="content">
16489
- <div class="text">
16490
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
16491
- ${spot.description ? `<p class="description">${spot.description}</p>` : ''}
16492
- ${spot.ctaText ? `<span class="cta-button">${spot.ctaText}</span>` : ''}
17134
+ ${GFONT_PRECONNECT}
17135
+ ${GFONT_SOURCE_SANS_3}
17136
+ ${GFONT_CORMORANT}
17137
+ ${STYLES$4(spot, config)}
17138
+ <div class="${prefix}">
17139
+ <div class="${prefix}__content">
17140
+ <div class="${prefix}__text">
17141
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17142
+ ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
17143
+ ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
17144
+ </div>
17145
+ <div class="${prefix}__image"></div>
16493
17146
  </div>
16494
- <div class="image"></div>
16495
17147
  </div>
16496
17148
  `;
16497
17149
  }
16498
17150
 
16499
- const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }) => `
16500
- <style>
16501
- :host {
16502
- min-width: 320px;
16503
- min-height: 334px;
16504
- }
16505
- .content {
16506
- width: 100%;
16507
- height: 100%;
16508
- display: flex;
16509
- flex-direction: column;
16510
- justify-content: flex-end;
16511
- background-image: url("${mobilePrimaryImage}");
16512
- background-size: cover;
16513
- background-repeat: no-repeat;
16514
- background-position: center;
16515
- border-radius: 5px;
16516
- overflow: hidden;
16517
- cursor: pointer;
16518
- color: ${textColor};
16519
- }
16520
- .text {
16521
- padding: 20px;
16522
- width: 70%;
16523
- display: flex;
16524
- flex-direction: column;
16525
- justify-content: center;
16526
- align-items: flex-start;
16527
- gap: 10px;
16528
- }
16529
- .header {
16530
- color: inherit;
16531
- margin: 0;
16532
- font-size: 20px;
16533
- font-family: "Cormorant";
16534
- font-style: normal;
16535
- font-weight: 300;
16536
- line-height: normal;
16537
- }
16538
- .description {
16539
- color: inherit;
16540
- font-size: 12px;
16541
- line-height: 16px;
16542
- font-family: "Source Sans 3", system-ui;
16543
- font-style: normal;
16544
- font-weight: 400;
16545
- margin: 0;
16546
- }
16547
- .cta-button {
16548
- width: fit-content;
16549
- display: inline-block;
16550
- padding: 7px 20px;
16551
- border: 0.5px solid ${ctaBorderColor};
16552
- border-radius: 5px;
16553
- color: ${ctaTextColor};
16554
- font-size: 8px;
16555
- transition: background-color 0.3s ease;
16556
- font-family: "Source Sans 3", system-ui;
16557
- font-style: normal;
16558
- font-weight: 400;
16559
- }
16560
- .content:hover .cta-button {
16561
- background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
16562
- }
16563
- @media (min-width: 640px) {
16564
- .content {
16565
- background-image: url("${primaryImage}");
17151
+ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
17152
+ const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17153
+ return `
17154
+ <style>
17155
+ :host {
17156
+ min-width: 320px;
17157
+ min-height: 334px;
16566
17158
  }
16567
- }
16568
- @media (min-width: 768px) {
16569
- .text {
16570
- padding: 25px;
17159
+
17160
+ .${prefix}__content {
17161
+ width: 100%;
17162
+ height: 100%;
17163
+ display: flex;
17164
+ flex-direction: column;
17165
+ justify-content: flex-end;
17166
+ background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
17167
+ background-size: cover;
17168
+ background-repeat: no-repeat;
17169
+ background-position: center;
17170
+ border-radius: 5px;
17171
+ overflow: hidden;
17172
+ cursor: pointer;
17173
+ color: ${textColor};
16571
17174
  }
16572
- .header {
16573
- font-size: 24px;
17175
+
17176
+ .${prefix}__text {
17177
+ padding: 20px;
17178
+ width: 70%;
17179
+ display: flex;
17180
+ flex-direction: column;
17181
+ justify-content: center;
17182
+ align-items: flex-start;
17183
+ gap: 10px;
16574
17184
  }
16575
- .description {
16576
- font-size: 13px;
16577
- line-height: 18px;
17185
+
17186
+ .${prefix}__header {
17187
+ color: inherit;
17188
+ margin: 0;
17189
+ font-size: 20px;
17190
+ font-family: "Cormorant";
17191
+ font-style: normal;
17192
+ font-weight: 300;
17193
+ line-height: normal;
16578
17194
  }
16579
- .cta-button {
17195
+
17196
+ .${prefix}__description {
17197
+ color: inherit;
16580
17198
  font-size: 12px;
17199
+ line-height: 16px;
17200
+ font-family: "Source Sans 3", system-ui;
17201
+ font-style: normal;
17202
+ font-weight: 400;
17203
+ margin: 0;
16581
17204
  }
16582
- }
16583
- @media (min-width: 1024px) {
16584
- .text {
16585
- padding: 30px;
17205
+
17206
+ .${prefix}__cta-button {
17207
+ width: fit-content;
17208
+ display: inline-block;
17209
+ padding: 7px 20px;
17210
+ border: 0.5px solid ${ctaBorderColor};
17211
+ border-radius: 5px;
17212
+ color: ${ctaTextColor};
17213
+ font-size: 8px;
17214
+ transition: background-color 0.3s ease;
17215
+ font-family: "Source Sans 3", system-ui;
17216
+ font-style: normal;
17217
+ font-weight: 400;
16586
17218
  }
16587
- .header {
16588
- font-size: 28px;
17219
+
17220
+ .${prefix}__content:hover .${prefix}__cta-button {
17221
+ background-color: ${ctaBorderColor.length === 7 ? `${ctaBorderColor}15` : `${ctaBorderColor}`};
16589
17222
  }
16590
- .description {
16591
- font-size: 14px;
17223
+
17224
+ @media (min-width: 640px) {
17225
+ .${prefix}__content {
17226
+ background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
17227
+ }
16592
17228
  }
16593
- .cta-button {
16594
- font-size: 13px;
17229
+
17230
+ @media (min-width: 768px) {
17231
+ .${prefix}__text {
17232
+ padding: 25px;
17233
+ }
17234
+
17235
+ .${prefix}__header {
17236
+ font-size: 24px;
17237
+ }
17238
+
17239
+ .${prefix}__description {
17240
+ font-size: 13px;
17241
+ line-height: 18px;
17242
+ }
17243
+
17244
+ .${prefix}__cta-button {
17245
+ font-size: 12px;
17246
+ }
16595
17247
  }
16596
- }
16597
- @media (min-width: 1280px) {
16598
- .cta-button {
16599
- font-size: 14px;
17248
+
17249
+ @media (min-width: 1024px) {
17250
+ .${prefix}__text {
17251
+ padding: 30px;
17252
+ }
17253
+
17254
+ .${prefix}__header {
17255
+ font-size: 28px;
17256
+ }
17257
+
17258
+ .${prefix}__description {
17259
+ font-size: 14px;
17260
+ }
17261
+
17262
+ .${prefix}__cta-button {
17263
+ font-size: 13px;
17264
+ }
16600
17265
  }
16601
- }
16602
- </style>
16603
- `;
16604
- function rbLargeCategoryImageToutTemplate(spot) {
17266
+
17267
+ @media (min-width: 1280px) {
17268
+ .${prefix}__cta-button {
17269
+ font-size: 14px;
17270
+ }
17271
+ }
17272
+ </style>
17273
+ `;
17274
+ };
17275
+ function rbLargeCategoryImageToutTemplate(spot, config) {
17276
+ const { prefix = '' } = config;
16605
17277
  return `
16606
- ${GFONT_PRECONNECT()}
16607
- ${GFONT_SOURCE_SANS_3()}
16608
- ${GFONT_CORMORANT()}
16609
- ${STYLES$3(spot)}
16610
- <div class="content">
16611
- <div class="text">
16612
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
16613
- ${spot.description ? `<p class="description">${spot.description}</p>` : ''}
16614
- ${spot.ctaText ? `<span class="cta-button">${spot.ctaText}</span>` : ''}
17278
+ ${GFONT_PRECONNECT}
17279
+ ${GFONT_SOURCE_SANS_3}
17280
+ ${GFONT_CORMORANT}
17281
+ ${STYLES$3(spot, config)}
17282
+ <div class="${prefix}__content">
17283
+ <div class="${prefix}__text">
17284
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17285
+ ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
17286
+ ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
16615
17287
  </div>
16616
17288
  </div>
16617
17289
  `;
16618
17290
  }
16619
17291
 
16620
- const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage, }) => `
17292
+ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix }) => `
16621
17293
  <style>
16622
17294
  :host {
16623
17295
  min-width: 320px;
16624
17296
  min-height: 150px;
16625
17297
  }
16626
- .content {
17298
+
17299
+ .${prefix}__content {
16627
17300
  width: 100%;
16628
17301
  height: 100%;
16629
17302
  display: flex;
@@ -16638,11 +17311,13 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
16638
17311
  background-blend-mode: overlay;
16639
17312
  background-repeat: no-repeat;
16640
17313
  }
16641
- .text {
17314
+
17315
+ .${prefix}__text {
16642
17316
  padding: 15px 10%;
16643
17317
  width: fit-content;
16644
17318
  }
16645
- .header {
17319
+
17320
+ .${prefix}__header {
16646
17321
  font-size: 16px;
16647
17322
  color: ${textColor};
16648
17323
  line-height: 20px;
@@ -16651,101 +17326,116 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
16651
17326
  font-style: normal;
16652
17327
  margin: 0;
16653
17328
  }
17329
+
16654
17330
  @media (min-width: 640px) {
16655
- .content {
17331
+ .${prefix}__content {
16656
17332
  background-image: url("${primaryImage}");
16657
17333
  }
16658
17334
  }
17335
+
16659
17336
  @media (min-width: 768px) {
16660
- .header {
17337
+ .${prefix}__header {
16661
17338
  font-size: 22px;
16662
17339
  }
16663
17340
  }
17341
+
16664
17342
  @media (min-width: 1024px) {
16665
- .header {
17343
+ .${prefix}__header {
16666
17344
  font-size: 24px;
16667
17345
  }
16668
17346
  }
17347
+
16669
17348
  @media (min-width: 1280px) {
16670
- .header {
17349
+ .${prefix}__header {
16671
17350
  font-size: 28px;
16672
17351
  }
16673
17352
  }
16674
17353
  </style>
16675
17354
  `;
16676
- function rbNavigationBannerTemplate(spot) {
17355
+ function rbNavigationBannerTemplate(spot, config) {
17356
+ const { prefix = '' } = config;
16677
17357
  return `
16678
- ${GFONT_PRECONNECT()}
16679
- ${GFONT_SOURCE_SANS_3()}
16680
- ${STYLES$2(spot)}
16681
- <div class="content">
16682
- <div class="text">
16683
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
17358
+ ${GFONT_PRECONNECT}
17359
+ ${GFONT_SOURCE_SANS_3}
17360
+ ${STYLES$2(spot, config)}
17361
+ <div class="${prefix}__content">
17362
+ <div class="${prefix}__text">
17363
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
16684
17364
  </div>
16685
17365
  </div>
16686
17366
  `;
16687
17367
  }
16688
17368
 
16689
- const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage, }) => `
16690
- <style>
16691
- :host {
16692
- min-width: 165px;
16693
- min-height: 300px;
16694
- }
16695
- .content {
16696
- width: 100%;
16697
- height: 100%;
16698
- display: flex;
16699
- flex-direction: column;
16700
- justify-content: flex-end;
16701
- background-image: url("${mobilePrimaryImage}");
16702
- background-size: cover;
16703
- background-repeat: no-repeat;
16704
- background-position: center;
16705
- border-radius: 5px;
16706
- overflow: hidden;
16707
- cursor: pointer;
16708
- }
16709
- .text {
16710
- padding: 10px;
16711
- width: 70%;
16712
- }
16713
- .header {
16714
- font-size: 12px;
16715
- color: ${textColor};
16716
- line-height: 16px;
16717
- font-family: "Source Sans 3", system-ui;
16718
- font-style: normal;
16719
- font-weight: 400;
16720
- line-height: normal;
16721
- }
16722
- @media (min-width: 640px) {
16723
- .content {
16724
- background-image: url("${primaryImage}");
17369
+ const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
17370
+ const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17371
+ return `
17372
+ <style>
17373
+ :host {
17374
+ min-width: 165px;
17375
+ min-height: 300px;
16725
17376
  }
16726
- }
16727
- </style>
16728
- `;
16729
- function rbSmallCategoryImageToutTemplate(spot) {
17377
+
17378
+ .${prefix}__content {
17379
+ width: 100%;
17380
+ height: 100%;
17381
+ display: flex;
17382
+ flex-direction: column;
17383
+ justify-content: flex-end;
17384
+ background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
17385
+ background-size: cover;
17386
+ background-repeat: no-repeat;
17387
+ background-position: center;
17388
+ border-radius: 5px;
17389
+ overflow: hidden;
17390
+ cursor: pointer;
17391
+ }
17392
+
17393
+ .${prefix}__text {
17394
+ padding: 10px;
17395
+ width: 70%;
17396
+ }
17397
+
17398
+ .${prefix}__header {
17399
+ font-size: 12px;
17400
+ color: ${textColor};
17401
+ line-height: 16px;
17402
+ font-family: "Source Sans 3", system-ui;
17403
+ font-style: normal;
17404
+ font-weight: 400;
17405
+ line-height: normal;
17406
+ margin: 0;
17407
+ }
17408
+
17409
+ @media (min-width: 640px) {
17410
+ .${prefix}__content {
17411
+ background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
17412
+ }
17413
+ }
17414
+ </style>
17415
+ `;
17416
+ };
17417
+ function rbSmallCategoryImageToutTemplate(spot, config) {
17418
+ const { prefix = '' } = config;
16730
17419
  return `
16731
- ${GFONT_PRECONNECT()}
16732
- ${GFONT_CORMORANT()}
16733
- ${STYLES$1(spot)}
16734
- <div class="content">
16735
- <div class="text">
16736
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
17420
+ ${GFONT_PRECONNECT}
17421
+ ${GFONT_CORMORANT}
17422
+ ${STYLES$1(spot, config)}
17423
+ <div class="${prefix}__content">
17424
+ <div class="${prefix}__text">
17425
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
16737
17426
  </div>
16738
17427
  </div>
16739
17428
  `;
16740
17429
  }
16741
17430
 
16742
- const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primaryImage, mobilePrimaryImage = primaryImage, }) => `
17431
+ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
16743
17432
  <style>
16744
17433
  :host {
16745
17434
  min-width: 165px;
16746
17435
  min-height: 250px;
16747
17436
  }
16748
- .content {
17437
+
17438
+ .${prefix}__content {
16749
17439
  width: 100%;
16750
17440
  height: 100%;
16751
17441
  background-color: ${backgroundColor};
@@ -16754,7 +17444,8 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
16754
17444
  flex-direction: column;
16755
17445
  border-radius: 5px;
16756
17446
  }
16757
- .image {
17447
+
17448
+ .${prefix}__image {
16758
17449
  width: 100%;
16759
17450
  height: 100%;
16760
17451
  background-image: url("${mobilePrimaryImage}");
@@ -16763,7 +17454,8 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
16763
17454
  background-position: center;
16764
17455
  border-radius: 5px;
16765
17456
  }
16766
- .text {
17457
+
17458
+ .${prefix}__text {
16767
17459
  text-align: left;
16768
17460
  display: flex;
16769
17461
  flex-direction: row;
@@ -16773,7 +17465,8 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
16773
17465
  height: fit-content;
16774
17466
  position: relative;
16775
17467
  }
16776
- .header {
17468
+
17469
+ .${prefix}__header {
16777
17470
  font-size: 12px;
16778
17471
  color: ${textColor};
16779
17472
  padding-top: 5px;
@@ -16782,44 +17475,41 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
16782
17475
  font-style: normal;
16783
17476
  font-weight: 400;
16784
17477
  line-height: normal;
17478
+ margin: 0;
16785
17479
  }
17480
+
16786
17481
  @media (min-width: 640px) {
16787
- .image {
17482
+ .${prefix}__image {
16788
17483
  background-image: url("${primaryImage}");
16789
17484
  }
16790
17485
  }
16791
17486
  </style>
16792
17487
  `;
16793
- function rbSmallDiscoverToutTemplate(spot) {
17488
+ function rbSmallDiscoverToutTemplate(spot, config) {
17489
+ const { prefix = '' } = config;
16794
17490
  return `
16795
- ${GFONT_PRECONNECT()}
16796
- ${GFONT_CORMORANT()}
16797
- ${STYLES(spot)}
16798
- <div class="content">
16799
- <div class="image"></div>
16800
- <div class="text">
16801
- ${spot.header ? `<h2 class="header">${spot.header}</h2>` : ''}
17491
+ ${GFONT_PRECONNECT}
17492
+ ${GFONT_CORMORANT}
17493
+ ${STYLES(spot, config)}
17494
+ <div class="${prefix}__content">
17495
+ <div class="${prefix}__image"></div>
17496
+ <div class="${prefix}__text">
17497
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
16802
17498
  </div>
16803
17499
  </div>
16804
17500
  `;
16805
17501
  }
16806
17502
 
16807
- var ENUM_SPOT_ELEMENT_ATTRIBUTE;
16808
- (function (ENUM_SPOT_ELEMENT_ATTRIBUTE) {
16809
- ENUM_SPOT_ELEMENT_ATTRIBUTE["WIDTH"] = "width";
16810
- ENUM_SPOT_ELEMENT_ATTRIBUTE["HEIGHT"] = "height";
16811
- ENUM_SPOT_ELEMENT_ATTRIBUTE["FLUID"] = "fluid";
16812
- ENUM_SPOT_ELEMENT_ATTRIBUTE["REDIRECT_ON_CLICK"] = "redirect-on-click";
16813
- })(ENUM_SPOT_ELEMENT_ATTRIBUTE || (ENUM_SPOT_ELEMENT_ATTRIBUTE = {}));
16814
17503
  /**
16815
17504
  * Creates the spot html string based on the provided spot data.
16816
17505
  *
16817
- * @param {ISpot} data - The spot data.
17506
+ * @param {ISpot} spot - The spot data.
16818
17507
  *
16819
17508
  * @return {string} - The spot html string.
16820
17509
  */
16821
- const GET_SPOT_TEMPLATE_HTML_STRING = (data) => {
17510
+ const GET_SPOT_TEMPLATE_HTML_STRING = (spot, config) => {
16822
17511
  const templates = {
17512
+ // Reserve Bar Spot Templates
16823
17513
  [RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE]: {
16824
17514
  rbHomepageHeroThreeTile: rbHomepageHeroThreeTileTemplate,
16825
17515
  },
@@ -16847,6 +17537,7 @@ const GET_SPOT_TEMPLATE_HTML_STRING = (data) => {
16847
17537
  [RMN_SPOT_TYPE.RB_PRODUCT_UPCS]: {
16848
17538
  rbProductUpcs: () => '', // No template for this spot type, it will be handled by ReserveBar App.
16849
17539
  },
17540
+ // IAB Standard Spot Templates
16850
17541
  [RMN_SPOT_TYPE.BILLBOARD]: {
16851
17542
  billboardV1: billboardV1Template,
16852
17543
  billboardV2: billboardV2Template,
@@ -16873,185 +17564,27 @@ const GET_SPOT_TEMPLATE_HTML_STRING = (data) => {
16873
17564
  inTextV1: inTextV1Template,
16874
17565
  },
16875
17566
  };
16876
- const spotVariants = templates[data.spot];
17567
+ const spotVariants = templates[spot.spot];
16877
17568
  if (!spotVariants) {
16878
17569
  return '';
16879
17570
  }
16880
- const variantTemplate = spotVariants[data.variant];
17571
+ const variantTemplate = spotVariants[spot.variant];
16881
17572
  if (!variantTemplate) {
16882
17573
  return '';
16883
17574
  }
16884
- return variantTemplate(data);
17575
+ // Generate a random prefix to avoid conflicts with other elements.
17576
+ const prefix = 's' + Math.random().toString(36).substring(6);
17577
+ return variantTemplate(spot, { ...config, prefix });
16885
17578
  };
16886
17579
 
16887
- let SpotElement;
16888
- if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
16889
- class CustomSpotElement extends HTMLElement {
16890
- constructor() {
16891
- super();
16892
- this.hasCustomContent = false;
16893
- this.handleClick = this.handleClick.bind(this);
16894
- this.attachShadow({ mode: 'open' });
16895
- }
16896
- connectedCallback() {
16897
- this.hasCustomContent = Boolean(this.customContent);
16898
- this.addEventListener('click', this.handleClick);
16899
- this.setupIntersectionObserver();
16900
- this.render();
16901
- }
16902
- disconnectedCallback() {
16903
- var _a;
16904
- (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
16905
- this.removeEventListener('click', this.handleClick);
16906
- }
16907
- attributeChangedCallback(_name, oldValue, newValue) {
16908
- if (oldValue !== newValue) {
16909
- this.render();
16910
- }
16911
- }
16912
- render() {
16913
- if (!this.shadowRoot || !this.data)
16914
- return;
16915
- const { style, wrapper, slot } = SPOT_ELEMENT_SHADOW_ROOT(this.data.width, this.data.height, this.hasCustomContent);
16916
- this.shadowRoot.replaceChildren(style, slot);
16917
- if (this.hasCustomContent) {
16918
- this.setCustomContent();
16919
- }
16920
- if (!this.hasCustomContent) {
16921
- wrapper.innerHTML = GET_SPOT_TEMPLATE_HTML_STRING(this.data);
16922
- this.shadowRoot.appendChild(wrapper);
16923
- }
16924
- }
16925
- setCustomContent() {
16926
- const wrapper = document.createElement('div');
16927
- wrapper.setAttribute('slot', SPOT_ELEMENT_SLOT_NAME);
16928
- if (typeof this.customContent === 'string') {
16929
- wrapper.innerHTML = this.customContent;
16930
- }
16931
- if (this.customContent instanceof HTMLElement) {
16932
- wrapper.appendChild(this.customContent);
16933
- }
16934
- this.appendChild(wrapper);
16935
- }
16936
- setupIntersectionObserver() {
16937
- const options = {
16938
- root: null,
16939
- rootMargin: '0px',
16940
- threshold: 0.5, // The element is considered visible when 50% of it is visible
16941
- };
16942
- this.observer = new IntersectionObserver((entries) => {
16943
- var _a;
16944
- if (entries[0].isIntersecting) {
16945
- this.registerEvent(RMN_SPOT_EVENT.IMPRESSION);
16946
- (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
16947
- }
16948
- }, options);
16949
- this.observer.observe(this);
16950
- }
16951
- handleClick() {
16952
- this.registerEvent(RMN_SPOT_EVENT.CLICK);
16953
- }
16954
- async registerEvent(event) {
16955
- var _a, _b;
16956
- if (!this.data)
16957
- return;
16958
- const shouldRedirectOnClick = this.getAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.REDIRECT_ON_CLICK) === 'true';
16959
- const eventUrl = (_b = (_a = this.data.events.find((e) => e.event === event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '';
16960
- try {
16961
- const options = {
16962
- method: 'POST',
16963
- redirect: event === RMN_SPOT_EVENT.CLICK && shouldRedirectOnClick ? 'follow' : 'manual',
16964
- };
16965
- const normalizedUrl = this.normalizeUrl(eventUrl);
16966
- const response = await fetch(normalizedUrl, options);
16967
- if (response.ok && event === RMN_SPOT_EVENT.CLICK && shouldRedirectOnClick) {
16968
- window.location.href = this.getRedirectUrlFromPayload(normalizedUrl);
16969
- }
16970
- }
16971
- catch (error) {
16972
- console.error(`Rmn error sending ${event} event:`, error);
16973
- }
16974
- }
16975
- normalizeUrl(url) {
16976
- if (!this.data)
16977
- return url;
16978
- const rmnUrl = `${SDK_CONFIG.url[this.data.env]}/api${SPOT_EVENT_API_PATH}`;
16979
- return url.replace(/https?:\/\/[^/]+\/[^?]+/, `${rmnUrl}`);
16980
- }
16981
- getRedirectUrlFromPayload(url) {
16982
- var _a, _b;
16983
- const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
16984
- try {
16985
- const data = JSON.parse(atob(base64String));
16986
- return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
16987
- }
16988
- catch (_c) {
16989
- return '';
16990
- }
16991
- }
16992
- }
16993
- CustomSpotElement.observedAttributes = Object.values(ENUM_SPOT_ELEMENT_ATTRIBUTE);
16994
- SpotElement = CustomSpotElement;
16995
- }
16996
-
16997
- class SpotHtmlService {
16998
- static getInstance() {
16999
- return SingletonManager.getInstance('SpotHtmlService', () => new SpotHtmlService());
17000
- }
17001
- /**
17002
- * Creates the html element based on the provided spot data using shadow dom.
17003
- *
17004
- * This method is only available in browser environments.
17005
- *
17006
- * @param {ISpot} spot - The spot data.
17007
- * @param {ICreateSpotElementConfig} config - The configuration object.
17008
- * @param {ICreateSpotElementConfig.fluid} config.fluid - If the spot should be fluid or not.
17009
- * @param {ICreateSpotElementConfig.customContent} config.customContent - Use a custom html element/string.
17010
- * @param {ICreateSpotElementConfig.redirectOnClick} config.redirectOnClick - If the spot should redirect on click.
17011
- *
17012
- * @return {HTMLElement | null} - The spot html element or null if the browser environment is not available.
17013
- */
17014
- createSpotHtmlElement(spot, config) {
17015
- var _a, _b;
17016
- if (!this.ensureBrowserEnvironmentAndDefineElement()) {
17017
- return null;
17018
- }
17019
- const isFluid = (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false;
17020
- const shouldRedirectOnClick = (_b = config === null || config === void 0 ? void 0 : config.redirectOnClick) !== null && _b !== void 0 ? _b : true;
17021
- const element = document.createElement(SPOT_ELEMENT_TAG);
17022
- element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.WIDTH, spot.width.toString());
17023
- element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.HEIGHT, spot.height.toString());
17024
- element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.FLUID, isFluid.toString());
17025
- element.setAttribute(ENUM_SPOT_ELEMENT_ATTRIBUTE.REDIRECT_ON_CLICK, shouldRedirectOnClick.toString());
17026
- // Share the spot data with the element
17027
- element.data = spot;
17028
- // Set custom content
17029
- if (config === null || config === void 0 ? void 0 : config.customContent) {
17030
- element.customContent = config.customContent;
17031
- }
17032
- return element;
17033
- }
17034
- /**
17035
- * @returns {boolean} - True if the browser environment is available and the element is defined.
17036
- */
17037
- ensureBrowserEnvironmentAndDefineElement() {
17038
- if (typeof window === 'undefined' || typeof document === 'undefined') {
17039
- console.warn('LiquidCommerce Rmn Sdk: createSpotElement is only available in browser environments!!!');
17040
- return false;
17041
- }
17042
- if (!customElements.get(SPOT_ELEMENT_TAG)) {
17043
- customElements.define(SPOT_ELEMENT_TAG, SpotElement);
17044
- }
17045
- return true;
17046
- }
17047
- }
17580
+ const SELECTION_API_PATH = '/spots/selection';
17048
17581
 
17049
- class SpotSelectionService extends BaseApi {
17582
+ class SelectionService extends BaseApi {
17050
17583
  constructor(auth) {
17051
17584
  super(auth);
17052
17585
  }
17053
17586
  static getInstance(auth) {
17054
- return SingletonManager.getInstance('SpotSelectionService', () => new SpotSelectionService(auth));
17587
+ return SingletonManager.getInstance('SelectionService', () => new SelectionService(auth));
17055
17588
  }
17056
17589
  /**
17057
17590
  * Makes a selection request on our server based on the provided data.
@@ -17061,35 +17594,23 @@ class SpotSelectionService extends BaseApi {
17061
17594
  * @return {Promise<ISpots>} - The spots response object.
17062
17595
  */
17063
17596
  async spotSelection(data) {
17064
- const { isOk, val, isErr } = await this.post(SPOTS_SELECTION_API_PATH, data, {});
17597
+ const { isOk, val, isErr } = await this.post(SELECTION_API_PATH, data, {});
17065
17598
  if (isErr) {
17066
17599
  throw new Error(`There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})`);
17067
17600
  }
17068
17601
  if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
17069
17602
  this.authInfo.authenticated = true;
17070
17603
  this.authInfo.token = val.refresh.token;
17071
- let spots = val.data.spots;
17072
- spots = this.addEnvToSpotData(spots, this.authInfo.env);
17073
- return spots;
17604
+ return val.data.spots;
17074
17605
  }
17075
17606
  throw new Error('Spot selection response was not successful');
17076
17607
  }
17077
- addEnvToSpotData(spots, env) {
17078
- for (const key in spots) {
17079
- if (spots[key]) {
17080
- spots[key].forEach((spot) => {
17081
- spot.env = env;
17082
- });
17083
- }
17084
- }
17085
- return spots;
17086
- }
17087
17608
  }
17088
17609
 
17089
17610
  class LiquidCommerceRmnClient {
17090
17611
  constructor(auth) {
17091
- this.spotSelectionService = SpotSelectionService.getInstance(auth);
17092
- this.spotHtmlService = SpotHtmlService.getInstance();
17612
+ this.selectionService = SelectionService.getInstance(auth);
17613
+ this.elementService = ElementService.getInstance();
17093
17614
  }
17094
17615
  /**
17095
17616
  * Makes a selection request on our server based on the provided data.
@@ -17101,23 +17622,118 @@ class LiquidCommerceRmnClient {
17101
17622
  * @return {Promise<ISpots>} - The spots response object.
17102
17623
  */
17103
17624
  async spotSelection(data) {
17104
- return this.spotSelectionService.spotSelection(data);
17625
+ return this.selectionService.spotSelection(data);
17626
+ }
17627
+ /**
17628
+ * Injects the spot elements into their provided placement.
17629
+ *
17630
+ * @param {IInjectSpotElement[]} data - The spot elements data.
17631
+ * @param {IInjectSpotsConfig} config - The configuration object.
17632
+ *
17633
+ * @return {Promise<void>} - A promise that resolves when the spot elements are injected.
17634
+ */
17635
+ async injectSpotElement(data, config) {
17636
+ if (!data.length) {
17637
+ console.warn('RmnSdk: Failed to request spot selection. No spot elements provided.');
17638
+ return;
17639
+ }
17640
+ const spotSelectionRequest = data.map((item) => {
17641
+ var _a;
17642
+ return ({
17643
+ spot: item.spotType,
17644
+ count: (_a = item === null || item === void 0 ? void 0 : item.count) !== null && _a !== void 0 ? _a : 1,
17645
+ });
17646
+ });
17647
+ const response = await this.spotSelection({ spots: spotSelectionRequest });
17648
+ const normalizedData = this.normalizeDataSpotType(data);
17649
+ for (const item of normalizedData) {
17650
+ const spots = response[item.spotType];
17651
+ if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
17652
+ console.warn(`RmnSdk: Failed to inject spot element. No spots found for type "${item.spotType}".`);
17653
+ continue;
17654
+ }
17655
+ const placementId = item.placementId.replace('#', '');
17656
+ const placement = document.getElementById(placementId);
17657
+ if (!placement) {
17658
+ console.warn(`RmnSdk: Failed to inject spot element. Placement not found for id "#${placementId}".`);
17659
+ continue;
17660
+ }
17661
+ if (spots.length === 1) {
17662
+ this.injectOneSpotElement(item, placement, spots[0], config);
17663
+ }
17664
+ if (spots.length > 1) {
17665
+ this.injectCarouselSpotElement(placement, spots, config);
17666
+ }
17667
+ }
17105
17668
  }
17106
17669
  /**
17107
- * Creates the spot html element based on the provided data using shadow dom.
17670
+ * Injects a carousel element with the provided spots into the placement.
17108
17671
  *
17109
- * This method is useful when you are initializing the client in a browser environment, so you can create the spot html element directly from the RmnClient instance.
17672
+ * @param {HTMLElement} placement - The placement element.
17673
+ * @param {ISpot[]} spots - The spot data.
17674
+ * @param {IInjectSpotsConfig} config - The configuration object.
17110
17675
  *
17676
+ * @return {void}
17677
+ */
17678
+ injectCarouselSpotElement(placement, spots, config) {
17679
+ const carouselSlides = [];
17680
+ for (const spotItem of spots) {
17681
+ const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
17682
+ const content = GET_SPOT_TEMPLATE_HTML_STRING(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
17683
+ carouselSlides.push(content);
17684
+ }
17685
+ const carousel = new CarouselComponent(carouselSlides, config === null || config === void 0 ? void 0 : config.carousel);
17686
+ const carouselElement = carousel.getElement();
17687
+ placement.appendChild(carouselElement);
17688
+ }
17689
+ /**
17690
+ * Injects a single spot element into the provided placement.
17691
+ *
17692
+ * @param {IInjectSpotElement} injectItem - The inject item data.
17693
+ * @param {HTMLElement} placement - The placement element.
17111
17694
  * @param {ISpot} spot - The spot data.
17112
- * @param {ICreateSpotElementConfig} config - The configuration object.
17113
- * @param {ICreateSpotElementConfig.fluid} config.fluid - If the spot should be fluid or not.
17114
- * @param {ICreateSpotElementConfig.customContent} config.customContent - Use a custom html element/string.
17115
- * @param {ICreateSpotElementConfig.redirectOnClick} config.redirectOnClick - If the spot should redirect on click.
17695
+ * @param {IInjectSpotsConfig} config - The configuration object.
17696
+ *
17697
+ * @return {void}
17698
+ */
17699
+ injectOneSpotElement(injectItem, placement, spot, config) {
17700
+ const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
17701
+ const content = GET_SPOT_TEMPLATE_HTML_STRING(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
17702
+ const spotElement = this.elementService.createFinalElement({
17703
+ content,
17704
+ config: {
17705
+ fluid: true,
17706
+ width: spot.width,
17707
+ height: spot.height,
17708
+ minScale: config === null || config === void 0 ? void 0 : config.minScale,
17709
+ },
17710
+ });
17711
+ if (!spotElement) {
17712
+ console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
17713
+ return;
17714
+ }
17715
+ placement.appendChild(spotElement);
17716
+ }
17717
+ /**
17718
+ * Normalizes the spot type data by adding a number suffix to the spot type.
17116
17719
  *
17117
- * @return {HTMLElement | null} - The spot html element or null if the browser environment is not available.
17720
+ * @param {IInjectSpotElement[]} spots - The spot type data.
17721
+ *
17722
+ * @return {IInjectSpotElement[]} - The normalized spot type data.
17118
17723
  */
17119
- createSpotElement(spot, config) {
17120
- return this.spotHtmlService.createSpotHtmlElement(spot, config);
17724
+ normalizeDataSpotType(spots) {
17725
+ const spotTypeCounts = {};
17726
+ return spots.map((spot) => {
17727
+ const { spotType } = spot;
17728
+ spotTypeCounts[spotType] = (spotTypeCounts[spotType] || 0) + 1;
17729
+ if (spotTypeCounts[spotType] === 1) {
17730
+ return spot;
17731
+ }
17732
+ return {
17733
+ ...spot,
17734
+ spotType: `${spotType}${spotTypeCounts[spotType]}`,
17735
+ };
17736
+ });
17121
17737
  }
17122
17738
  }
17123
17739
  /**
@@ -17133,24 +17749,5 @@ async function RmnClient(apiKey, config) {
17133
17749
  const credentials = await authService.initialize();
17134
17750
  return new LiquidCommerceRmnClient(credentials);
17135
17751
  }
17136
- /**
17137
- * Creates the spot html element based on the provided data using shadow dom.
17138
- *
17139
- * This method is useful when you are initializing the client in a non-browser environment.
17140
- * When you request a spot selection, you will receive the spot data in server-side and return them back to the client.
17141
- * Then you can use this function to create the spot html element based on the provided data without the need of the RmnClient instance.
17142
- *
17143
- * @param {ISpot} spot - The spot data.
17144
- * @param {ICreateSpotElementConfig} config - The configuration object.
17145
- * @param {ICreateSpotElementConfig.fluid} config.fluid - If the spot should be fluid or not.
17146
- * @param {ICreateSpotElementConfig.customContent} config.customContent - Use a custom html element/string.
17147
- * @param {ICreateSpotElementConfig.redirectOnClick} config.redirectOnClick - If the spot should redirect on click.
17148
- *
17149
- * @return {HTMLElement | null} - The spot html element or null if the browser environment is not available.
17150
- */
17151
- function RmnCreateSpotElement(spot, config) {
17152
- const spotHtmlService = SpotHtmlService.getInstance();
17153
- return spotHtmlService.createSpotHtmlElement(spot, config);
17154
- }
17155
17752
 
17156
- export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement };
17753
+ export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient };