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