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