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

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