@liquidcommercedev/rmn-sdk 1.4.6-beta.8 → 1.5.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.cjs CHANGED
@@ -15000,7 +15000,7 @@ class BaseApi extends BaseApiAbstract {
15000
15000
  */
15001
15001
  async post(path, data, configOverrides) {
15002
15002
  let requestData = data;
15003
- if (this.authInfo.env !== exports.RMN_ENV.LOCAL) {
15003
+ if (![exports.RMN_ENV.LOCAL, exports.RMN_ENV.DEVELOPMENT].includes(this.authInfo.env)) {
15004
15004
  const timestamp = new Date().getTime();
15005
15005
  configOverrides = {
15006
15006
  ...configOverrides,
@@ -15205,6 +15205,78 @@ class IntersectionObserverService {
15205
15205
  }
15206
15206
  }
15207
15207
 
15208
+ class LocalStorage {
15209
+ constructor() {
15210
+ this.spots = new Map();
15211
+ // Sync local storage with the current state
15212
+ this.syncLocalStorage();
15213
+ // Remove expired spots
15214
+ this.removeExpiredSpots();
15215
+ }
15216
+ static getInstance() {
15217
+ if (!LocalStorage.instance) {
15218
+ LocalStorage.instance = new LocalStorage();
15219
+ }
15220
+ return LocalStorage.instance;
15221
+ }
15222
+ syncLocalStorage() {
15223
+ const localStorageData = localStorage.getItem(LocalStorage.localStorageKey);
15224
+ // TODO: Encrypt the data before storing it in the local storage
15225
+ if (localStorageData) {
15226
+ try {
15227
+ const parsedData = JSON.parse(localStorageData);
15228
+ if (parsedData && typeof parsedData === 'object') {
15229
+ this.spots = this.objToMap(parsedData);
15230
+ }
15231
+ else {
15232
+ this.clearLocalStorage();
15233
+ }
15234
+ }
15235
+ catch (_a) {
15236
+ // If there is an error parsing the data, clear the local storage to prevent any issues
15237
+ this.clearLocalStorage();
15238
+ }
15239
+ }
15240
+ }
15241
+ setSpot(spotId, data) {
15242
+ data.createdAt = Date.now();
15243
+ this.spots.set(spotId, data);
15244
+ this.updateLocalStorage();
15245
+ }
15246
+ getSpot(spotId) {
15247
+ return this.spots.get(spotId);
15248
+ }
15249
+ removeSpot(spotId) {
15250
+ this.spots.delete(spotId);
15251
+ this.updateLocalStorage();
15252
+ }
15253
+ updateLocalStorage() {
15254
+ const data = this.mapToObj(this.spots);
15255
+ localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(data));
15256
+ }
15257
+ clearLocalStorage() {
15258
+ localStorage.removeItem(LocalStorage.localStorageKey);
15259
+ }
15260
+ removeExpiredSpots() {
15261
+ const currentTime = Date.now();
15262
+ this.spots.forEach((spot, spotId) => {
15263
+ var _a;
15264
+ if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorage.spotExpirationTime) {
15265
+ this.spots.delete(spotId);
15266
+ }
15267
+ });
15268
+ this.updateLocalStorage();
15269
+ }
15270
+ mapToObj(map) {
15271
+ return Object.fromEntries(map);
15272
+ }
15273
+ objToMap(obj) {
15274
+ return new Map(Object.entries(obj));
15275
+ }
15276
+ }
15277
+ LocalStorage.localStorageKey = 'lc_rmn';
15278
+ LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
15279
+
15208
15280
  class ResizeObserverService {
15209
15281
  constructor({ element, maxSize, minScale }) {
15210
15282
  this.element = element;
@@ -15337,11 +15409,25 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15337
15409
  display: flex;
15338
15410
  align-items: center;
15339
15411
  gap: 8px;
15412
+ opacity: var(--opacity, 1);
15340
15413
  }
15341
15414
 
15342
- .dots .dot {
15415
+ .dots.small .dot {
15416
+ width: 8px;
15417
+ height: 8px;
15418
+ }
15419
+
15420
+ .dots.base .dot {
15343
15421
  width: 12px;
15344
15422
  height: 12px;
15423
+ }
15424
+
15425
+ .dots.large .dot {
15426
+ width: 16px;
15427
+ height: 16px;
15428
+ }
15429
+
15430
+ .dots .dot {
15345
15431
  border-radius: 50%;
15346
15432
  cursor: pointer;
15347
15433
  transition: all 0.3s ease;
@@ -15389,6 +15475,10 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15389
15475
  flex-direction: column;
15390
15476
  }
15391
15477
 
15478
+ .buttons {
15479
+ opacity: var(--opacity, 1);
15480
+ }
15481
+
15392
15482
  .buttons button {
15393
15483
  background-color: #00000080;
15394
15484
  color: #fff;
@@ -15398,6 +15488,18 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15398
15488
  transition: background-color 0.3s ease;
15399
15489
  }
15400
15490
 
15491
+ .buttons.small button {
15492
+ padding: 6px;
15493
+ }
15494
+
15495
+ .buttons.base button {
15496
+ padding: 10px;
15497
+ }
15498
+
15499
+ .buttons.large button {
15500
+ padding: 14px;
15501
+ }
15502
+
15401
15503
  .buttons button:hover {
15402
15504
  background-color: #000000b3;
15403
15505
  }
@@ -15470,11 +15572,6 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15470
15572
  padding: 8px 12px;
15471
15573
  font-size: 14px;
15472
15574
  }
15473
-
15474
- .dots .dot {
15475
- width: 8px;
15476
- height: 8px;
15477
- }
15478
15575
  }
15479
15576
  `;
15480
15577
 
@@ -15514,6 +15611,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15514
15611
  position: 'bottom-center',
15515
15612
  color: '#d9d9d9',
15516
15613
  activeColor: '#b5914a',
15614
+ size: 'base',
15615
+ opacity: 1,
15517
15616
  ...(typeof ((_j = this.data) === null || _j === void 0 ? void 0 : _j.useDots) === 'object' ? this.data.useDots : {}),
15518
15617
  };
15519
15618
  this.buttonsOptions = {
@@ -15524,6 +15623,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15524
15623
  borderRadius: '50%',
15525
15624
  prev: 'Prev',
15526
15625
  next: 'Next',
15626
+ size: 'base',
15627
+ opacity: 1,
15527
15628
  ...(typeof ((_k = this.data) === null || _k === void 0 ? void 0 : _k.useButtons) === 'object' ? this.data.useButtons : {}),
15528
15629
  };
15529
15630
  this.validateOptions();
@@ -15609,7 +15710,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15609
15710
  }
15610
15711
  renderDots() {
15611
15712
  const dotsContainer = document.createElement('div');
15612
- dotsContainer.className = `dots ${this.dotsOptions.position}`;
15713
+ dotsContainer.className = `dots ${this.dotsOptions.position} ${this.dotsOptions.size}`;
15714
+ dotsContainer.style.cssText = `--opacity: ${this.dotsOptions.opacity}`;
15613
15715
  this.slides.forEach((_, index) => {
15614
15716
  const dot = document.createElement('span');
15615
15717
  dot.className = `dot ${index === this.currentSlide ? 'active' : ''}`;
@@ -15623,7 +15725,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15623
15725
  const buttonsClass = this.buttonsOptions.together
15624
15726
  ? `buttons-together ${this.buttonsOptions.position}`
15625
15727
  : 'buttons-separate';
15626
- buttonsContainer.className = `buttons ${buttonsClass}`;
15728
+ buttonsContainer.className = `buttons ${buttonsClass} ${this.buttonsOptions.size}`;
15729
+ buttonsContainer.style.cssText = `--opacity: ${this.buttonsOptions.opacity}`;
15627
15730
  this.prevButton = this.createButton('prev-button', this.buttonsOptions.prev);
15628
15731
  this.nextButton = this.createButton('next-button', this.buttonsOptions.next);
15629
15732
  buttonsContainer.appendChild(this.prevButton);
@@ -15857,14 +15960,15 @@ class ElementService {
15857
15960
  * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
15858
15961
  */
15859
15962
  createSpotElement({ content, config }) {
15860
- var _a;
15963
+ var _a, _b;
15861
15964
  if (!this.ensureBrowserEnvironmentAndDefineElement()) {
15862
15965
  return null;
15863
15966
  }
15864
15967
  const spot = document.createElement(SPOT_ELEMENT_TAG);
15968
+ spot.setAttribute('type', (_a = config === null || config === void 0 ? void 0 : config.spot) !== null && _a !== void 0 ? _a : '');
15865
15969
  spot.data = {
15866
15970
  spot: config === null || config === void 0 ? void 0 : config.spot,
15867
- fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
15971
+ fluid: (_b = config === null || config === void 0 ? void 0 : config.fluid) !== null && _b !== void 0 ? _b : false,
15868
15972
  ...config,
15869
15973
  };
15870
15974
  spot.content = content;
@@ -15930,11 +16034,172 @@ class ElementService {
15930
16034
  }
15931
16035
  }
15932
16036
 
15933
- function linearGradientColorStop(overlay, fallback) {
15934
- if (!overlay || overlay.length === 0) {
16037
+ class UniqueIdGenerator {
16038
+ /**
16039
+ * Initialize the generator with a node ID
16040
+ * @param nodeId Number between 0-1023 to identify this instance
16041
+ */
16042
+ static initialize(nodeId = Math.floor(Math.random() * 1024)) {
16043
+ if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
16044
+ throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
16045
+ }
16046
+ this.nodeId = nodeId;
16047
+ }
16048
+ /**
16049
+ * Convert a number to base32 string with specified length
16050
+ */
16051
+ static toBase32(num, length) {
16052
+ let result = '';
16053
+ while (num > 0) {
16054
+ result = this.base32Chars[Number(num % BigInt(32))] + result;
16055
+ // @ts-expect-error - TS doesn't support bigint division
16056
+ num = num / 32n;
16057
+ }
16058
+ return result.padStart(length, '0');
16059
+ }
16060
+ /**
16061
+ * Generate a cryptographically secure random number
16062
+ */
16063
+ static getSecureRandom() {
16064
+ if (typeof crypto !== 'undefined') {
16065
+ const buffer = new Uint32Array(1);
16066
+ crypto.getRandomValues(buffer);
16067
+ return buffer[0];
16068
+ }
16069
+ return Math.floor(Math.random() * 0xffffffff);
16070
+ }
16071
+ /**
16072
+ * Wait until next millisecond
16073
+ */
16074
+ static waitNextMillis(lastTimestamp) {
16075
+ let timestamp = Date.now();
16076
+ while (timestamp <= lastTimestamp) {
16077
+ timestamp = Date.now();
16078
+ }
16079
+ return timestamp;
16080
+ }
16081
+ /**
16082
+ * Generates a highly unique ID with the following format:
16083
+ * TTTTTTTTTTCCCCNNNNNRRRR
16084
+ * T: Timestamp (10 chars)
16085
+ * C: Counter (4 chars)
16086
+ * N: Node ID (5 chars)
16087
+ * R: Random (4 chars)
16088
+ *
16089
+ * Total length: 23 characters, always uppercase alphanumeric
16090
+ */
16091
+ static generate() {
16092
+ if (this.nodeId === undefined) {
16093
+ this.initialize();
16094
+ }
16095
+ let timestamp = Date.now() - this.epoch;
16096
+ // Handle clock moving backwards or same millisecond
16097
+ if (timestamp < this.lastTimestamp) {
16098
+ throw new Error('Clock moved backwards. Refusing to generate ID.');
16099
+ }
16100
+ if (timestamp === this.lastTimestamp) {
16101
+ this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
16102
+ if (this.sequence === 0) {
16103
+ timestamp = this.waitNextMillis(this.lastTimestamp);
16104
+ }
16105
+ }
16106
+ else {
16107
+ this.sequence = 0;
16108
+ }
16109
+ this.lastTimestamp = timestamp;
16110
+ // Generate random component
16111
+ const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
16112
+ // Combine all components into a BigInt
16113
+ // const id =
16114
+ // (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
16115
+ // (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
16116
+ // (BigInt(this.sequence) << BigInt(16)) |
16117
+ // BigInt(random);
16118
+ // Convert to base32 representation
16119
+ const timeComponent = this.toBase32(BigInt(timestamp), 10);
16120
+ const counterComponent = this.toBase32(BigInt(this.sequence), 4);
16121
+ const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
16122
+ const randomComponent = this.toBase32(BigInt(random), 4);
16123
+ return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
16124
+ }
16125
+ /**
16126
+ * Validates if a string matches the expected ID format
16127
+ */
16128
+ static isValid(id) {
16129
+ if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
16130
+ return false;
16131
+ try {
16132
+ const timeComponent = id.slice(0, 10);
16133
+ const timestamp = this.decodeBase32(timeComponent);
16134
+ const now = Date.now() - this.epoch;
16135
+ return timestamp >= 0 && timestamp <= now;
16136
+ }
16137
+ catch (_a) {
16138
+ return false;
16139
+ }
16140
+ }
16141
+ /**
16142
+ * Decode base32 string to number
16143
+ */
16144
+ static decodeBase32(str) {
16145
+ let result = 0;
16146
+ for (const char of str) {
16147
+ result = result * 32 + this.base32Chars.indexOf(char);
16148
+ }
16149
+ return result;
16150
+ }
16151
+ /**
16152
+ * Extract timestamp from ID
16153
+ */
16154
+ static getTimestamp(id) {
16155
+ if (!this.isValid(id))
16156
+ throw new Error('Invalid ID format');
16157
+ const timeComponent = id.slice(0, 10);
16158
+ const timestamp = this.decodeBase32(timeComponent);
16159
+ return new Date(timestamp + this.epoch);
16160
+ }
16161
+ }
16162
+ // Constants for bit manipulation
16163
+ UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
16164
+ UniqueIdGenerator.nodeBits = 10;
16165
+ UniqueIdGenerator.sequenceBits = 12;
16166
+ // Instance variables
16167
+ UniqueIdGenerator.lastTimestamp = -1;
16168
+ UniqueIdGenerator.sequence = 0;
16169
+ // Character set for base32 encoding (excluding similar looking characters)
16170
+ UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
16171
+
16172
+ function convertHexToRgba(hex, opacity = 1) {
16173
+ // Remove # if present
16174
+ const cleanHex = hex.replace('#', '');
16175
+ // Convert hex to RGB
16176
+ const r = parseInt(cleanHex.substring(0, 2), 16);
16177
+ const g = parseInt(cleanHex.substring(2, 4), 16);
16178
+ const b = parseInt(cleanHex.substring(4, 6), 16);
16179
+ // Return rgba string
16180
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
16181
+ }
16182
+ function generateGradientColor(overlay, fallback = '') {
16183
+ if (!overlay) {
15935
16184
  return fallback;
15936
16185
  }
15937
- return overlay.map(({ color, colorStop }) => `${color} ${colorStop}`).join(', ');
16186
+ const OVERLAY_SIZE = {
16187
+ small: 10,
16188
+ base: 30,
16189
+ large: 50,
16190
+ };
16191
+ const OVERLAY_OPACITY = {
16192
+ light: 0.1,
16193
+ medium: 0.4,
16194
+ dark: 0.6,
16195
+ };
16196
+ const { size, opacity, color } = overlay;
16197
+ const goTo = OVERLAY_SIZE[size];
16198
+ const overlayOpacity = OVERLAY_OPACITY[opacity];
16199
+ const fullColor = convertHexToRgba(color, 1);
16200
+ const transparentColor = convertHexToRgba(color, 0);
16201
+ const gradientColor = convertHexToRgba(color, overlayOpacity);
16202
+ return `${fullColor} 0%, ${gradientColor} ${goTo}%, ${transparentColor} 100%`;
15938
16203
  }
15939
16204
  function spotHtmlStringToElement(htmlString) {
15940
16205
  const spot = document.createElement('div');
@@ -16798,7 +17063,7 @@ function rbCollectionBannerWithoutTextBlockTemplate(spot, config) {
16798
17063
  }
16799
17064
 
16800
17065
  const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
16801
- const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 40%');
17066
+ const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 40%');
16802
17067
  return `
16803
17068
  <style>
16804
17069
  .${prefix} {
@@ -17289,7 +17554,7 @@ function rbHomepageHeroTwoTileTemplate(spot, config) {
17289
17554
  }
17290
17555
 
17291
17556
  const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
17292
- const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17557
+ const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17293
17558
  return `
17294
17559
  <style>
17295
17560
  .${prefix} {
@@ -17426,7 +17691,7 @@ function rbLargeCategoryImageToutTemplate(spot, config) {
17426
17691
  }
17427
17692
 
17428
17693
  const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
17429
- const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17694
+ const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17430
17695
  return `
17431
17696
  <style>
17432
17697
  .${prefix} {
@@ -17443,11 +17708,7 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
17443
17708
  background-position: center;
17444
17709
  background-repeat: no-repeat;
17445
17710
  container-type: inline-size;
17446
- }
17447
-
17448
- .${prefix}__text {
17449
- padding: 15px 10%;
17450
- width: fit-content;
17711
+ position: relative;
17451
17712
  }
17452
17713
 
17453
17714
  .${prefix}__header {
@@ -17458,6 +17719,7 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
17458
17719
  font-family: "Source Sans 3", system-ui;
17459
17720
  font-style: normal;
17460
17721
  margin: 0;
17722
+ padding: 15px 10%;
17461
17723
  }
17462
17724
 
17463
17725
  @container (min-width: 640px) {
@@ -17493,15 +17755,13 @@ function rbNavigationBannerTemplate(spot, config) {
17493
17755
  ${GFONT_SOURCE_SANS_3}
17494
17756
  ${STYLES$2(spot, config)}
17495
17757
  <div class="${prefix}">
17496
- <div class="${prefix}__text">
17497
17758
  ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17498
- </div>
17499
17759
  </div>
17500
17760
  `;
17501
17761
  }
17502
17762
 
17503
17763
  const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
17504
- const linearGradient = linearGradientColorStop(overlay || [], 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17764
+ const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
17505
17765
  return `
17506
17766
  <style>
17507
17767
  .${prefix} {
@@ -17697,8 +17957,8 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
17697
17957
  if (!variantTemplate) {
17698
17958
  return null;
17699
17959
  }
17700
- // Generate a random prefix to avoid conflicts with other elements.
17701
- const prefix = 's' + Math.random().toString(36).substring(6);
17960
+ // Generate a highly unique prefix to avoid conflicts with other elements.
17961
+ const prefix = 's' + UniqueIdGenerator.generate().toLowerCase();
17702
17962
  const spotHtmlString = variantTemplate(spot, { ...config, prefix });
17703
17963
  return spotHtmlStringToElement(spotHtmlString);
17704
17964
  };
@@ -17715,6 +17975,12 @@ class PubSub {
17715
17975
  */
17716
17976
  this.subscribers = {};
17717
17977
  }
17978
+ static getInstance() {
17979
+ if (!PubSub.instance) {
17980
+ PubSub.instance = new PubSub();
17981
+ }
17982
+ return PubSub.instance;
17983
+ }
17718
17984
  /**
17719
17985
  * Subscribe to an event
17720
17986
  * @param eventType - The type of event to subscribe to
@@ -17780,7 +18046,8 @@ class PubSub {
17780
18046
 
17781
18047
  class EventService {
17782
18048
  constructor() {
17783
- this.pubSub = new PubSub();
18049
+ this.pubSub = PubSub.getInstance();
18050
+ this.localStorage = LocalStorage.getInstance();
17784
18051
  this.activeSpots = new Map();
17785
18052
  this.spotStates = new Map();
17786
18053
  this.intersectionObserver = new IntersectionObserverService();
@@ -17797,6 +18064,59 @@ class EventService {
17797
18064
  publish(eventType, data) {
17798
18065
  this.pubSub.publish(eventType, data);
17799
18066
  }
18067
+ registerSpot(params) {
18068
+ const { placementId, spot, spotElement } = params;
18069
+ this.activeSpots.set(placementId, { spotElement });
18070
+ // Fire impression event
18071
+ this.fireImpressionEvent(placementId, spot, spotElement);
18072
+ // Handle intersection observer
18073
+ this.handleIntersectionObserver(placementId, spot, spotElement);
18074
+ // Attach click event listener
18075
+ spotElement.addEventListener('click', async () => await this.handleClick(params));
18076
+ }
18077
+ unregisterSpot(placementId) {
18078
+ const placementIdClean = placementId.replace('#', '');
18079
+ const spotData = this.activeSpots.get(placementIdClean);
18080
+ if (!spotData) {
18081
+ this.handleSpotState(placementIdClean, {
18082
+ state: {
18083
+ error: `Active spot with placementId ${placementIdClean} not found.`,
18084
+ },
18085
+ });
18086
+ return;
18087
+ }
18088
+ this.intersectionObserver.unobserve(spotData.spotElement);
18089
+ this.handleSpotState(placementIdClean, {
18090
+ dom: {
18091
+ spotElement: undefined,
18092
+ visibleOnViewport: false,
18093
+ },
18094
+ state: {
18095
+ unmounted: true,
18096
+ mounted: false,
18097
+ },
18098
+ });
18099
+ this.activeSpots.delete(placementIdClean);
18100
+ const placementElement = document.getElementById(placementIdClean);
18101
+ if (!placementElement) {
18102
+ this.handleSpotState(placementIdClean, {
18103
+ state: {
18104
+ error: `Placement element with id ${placementIdClean} not found.`,
18105
+ },
18106
+ });
18107
+ return;
18108
+ }
18109
+ placementElement.innerHTML = '';
18110
+ }
18111
+ /**
18112
+ * Updates the state of a spot.
18113
+ *
18114
+ * @param {string} placementId - The placement ID of the spot.
18115
+ * @param {Partial<ILifecycleState>} updates - The updates to apply to the spot state.
18116
+ * @param {boolean} publish - Whether to publish the updated state.
18117
+ *
18118
+ * @returns {void}
18119
+ */
17800
18120
  handleSpotState(placementId, updates, publish = true) {
17801
18121
  let currentState = this.spotStates.get(placementId);
17802
18122
  if (!currentState) {
@@ -17807,8 +18127,8 @@ class EventService {
17807
18127
  spotType: '',
17808
18128
  },
17809
18129
  dom: {
17810
- element: undefined,
17811
- visible: false,
18130
+ spotElement: undefined,
18131
+ visibleOnViewport: false,
17812
18132
  },
17813
18133
  state: {
17814
18134
  mounted: false,
@@ -17823,81 +18143,57 @@ class EventService {
17823
18143
  },
17824
18144
  };
17825
18145
  }
17826
- this.spotStates.set(placementId, {
17827
- ...currentState,
17828
- ...updates,
17829
- });
18146
+ this.spotStates.set(placementId, { ...currentState, ...updates });
17830
18147
  if (publish) {
17831
18148
  this.pubSub.publish(exports.RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
17832
18149
  }
17833
18150
  }
17834
- registerSpot({ placementId, element, spot }) {
17835
- this.activeSpots.set(spot.id, {
18151
+ async handleClick({ placementId, spot, spotElement, }) {
18152
+ var _a, _b, _c;
18153
+ // Publish click event
18154
+ this.pubSub.publish(exports.RMN_SPOT_EVENT.CLICK, {
17836
18155
  placementId,
17837
- element,
17838
- impressionTracked: false,
18156
+ spotId: spot.id,
18157
+ spotElement,
17839
18158
  });
17840
- // Handle intersection observer
17841
- this.handleIntersectionObserver(placementId, spot, element);
17842
- // Attach click event listener
17843
- element.addEventListener('click', async () => {
17844
- var _a, _b;
17845
- this.pubSub.publish(exports.RMN_SPOT_EVENT.CLICK, {
17846
- placementId,
17847
- spotId: spot.id,
17848
- element,
17849
- });
17850
- // Fire click event
17851
- await this.fireEvent({
17852
- event: exports.RMN_SPOT_EVENT.CLICK,
17853
- eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
17854
- });
18159
+ // Fire click event
18160
+ await this.fireEvent({
18161
+ event: exports.RMN_SPOT_EVENT.CLICK,
18162
+ eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
18163
+ });
18164
+ // Save spot to local storage for event tracking
18165
+ this.localStorage.setSpot(spot.id, {
18166
+ spotId: spot.id,
18167
+ spotType: spot.spot,
18168
+ events: spot.events,
18169
+ productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 'GROUPING-12345', 'DAN-12345', 131398103],
17855
18170
  });
17856
18171
  }
17857
- unregisterSpot(spotId) {
17858
- const spotData = this.activeSpots.get(spotId);
17859
- if (spotData) {
17860
- this.intersectionObserver.unobserve(spotData.element);
17861
- this.handleSpotState(spotData.placementId, {
18172
+ handleIntersectionObserver(placementId, _spot, spotElement) {
18173
+ const spotIsVisibleCallback = async () => {
18174
+ this.intersectionObserver.unobserve(spotElement);
18175
+ this.handleSpotState(placementId, {
17862
18176
  dom: {
17863
- element: undefined,
17864
- visible: false,
17865
- },
17866
- state: {
17867
- unmounted: true,
17868
- mounted: false,
18177
+ spotElement,
18178
+ visibleOnViewport: true,
17869
18179
  },
17870
18180
  });
17871
- this.activeSpots.delete(spotId);
17872
- }
18181
+ };
18182
+ this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
17873
18183
  }
17874
- handleIntersectionObserver(placementId, spot, element) {
17875
- const spotIsVisibleCb = async () => {
18184
+ fireImpressionEvent(placementId, spot, spotElement) {
18185
+ this.pubSub.publish(exports.RMN_SPOT_EVENT.IMPRESSION, {
18186
+ placementId,
18187
+ spotId: spot.id,
18188
+ spotElement,
18189
+ });
18190
+ (async () => {
17876
18191
  var _a, _b;
17877
- this.pubSub.publish(exports.RMN_SPOT_EVENT.IMPRESSION, {
17878
- placementId,
17879
- spotId: spot.id,
17880
- element,
17881
- });
17882
- this.intersectionObserver.unobserve(element);
17883
- this.activeSpots.set(spot.id, {
17884
- placementId,
17885
- element,
17886
- impressionTracked: true,
17887
- });
17888
- this.handleSpotState(placementId, {
17889
- dom: {
17890
- element,
17891
- visible: true,
17892
- },
17893
- });
17894
- // Fire impression event
17895
18192
  await this.fireEvent({
17896
18193
  event: exports.RMN_SPOT_EVENT.IMPRESSION,
17897
18194
  eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
17898
18195
  });
17899
- };
17900
- this.intersectionObserver.observe(element, spotIsVisibleCb);
18196
+ })();
17901
18197
  }
17902
18198
  /**
17903
18199
  * Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
@@ -17962,23 +18258,178 @@ class SelectionService extends BaseApi {
17962
18258
  }
17963
18259
  }
17964
18260
 
18261
+ const SPOT_EVENTS_EXAMPLE = [
18262
+ {
18263
+ event: exports.RMN_SPOT_EVENT.CLICK,
18264
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
18265
+ },
18266
+ {
18267
+ event: exports.RMN_SPOT_EVENT.IMPRESSION,
18268
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
18269
+ },
18270
+ {
18271
+ event: exports.RMN_SPOT_EVENT.PURCHASE,
18272
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
18273
+ },
18274
+ {
18275
+ event: exports.RMN_SPOT_EVENT.ADD_TO_CART,
18276
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
18277
+ },
18278
+ {
18279
+ event: exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST,
18280
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
18281
+ },
18282
+ {
18283
+ event: exports.RMN_SPOT_EVENT.BUY_NOW,
18284
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
18285
+ },
18286
+ ];
18287
+ const RB_SPOTS_SELECTION_EXAMPLE = {
18288
+ rbHomepageHeroFullImage: [
18289
+ {
18290
+ id: '111111_111111',
18291
+ spot: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18292
+ variant: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18293
+ width: 1140,
18294
+ height: 640,
18295
+ header: 'Artisanal Craft Beer Collection',
18296
+ description: 'Discover our curated selection of small-batch, flavor-packed craft beers.',
18297
+ ctaText: 'Explore the Collection',
18298
+ textColor: '#ffffff',
18299
+ ctaTextColor: '#ffffff',
18300
+ primaryImage: 'https://placehold.co/1140x640/png?text=Craft+Beer+Collection',
18301
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Craft+Beer',
18302
+ events: SPOT_EVENTS_EXAMPLE,
18303
+ },
18304
+ {
18305
+ id: '222222_222222',
18306
+ spot: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18307
+ variant: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18308
+ width: 1140,
18309
+ height: 640,
18310
+ header: 'Summer Wine Spectacular',
18311
+ description: 'Refresh your palate with our handpicked selection of crisp, summer wines.',
18312
+ ctaText: 'Shop Summer Wines',
18313
+ textColor: '#000000',
18314
+ ctaTextColor: '#ffffff',
18315
+ primaryImage: 'https://placehold.co/1140x640/png?text=Summer+Wines',
18316
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Summer+Wines',
18317
+ events: SPOT_EVENTS_EXAMPLE,
18318
+ },
18319
+ ],
18320
+ rbHomepageHeroTwoTile: [
18321
+ {
18322
+ id: '333333_333333',
18323
+ spot: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
18324
+ variant: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
18325
+ width: 1140,
18326
+ height: 640,
18327
+ header: 'Whiskey Wonderland',
18328
+ description: 'Embark on a journey through our premium whiskey selection.',
18329
+ ctaText: 'Discover Whiskeys',
18330
+ textColor: '#ffffff',
18331
+ backgroundColor: '#2c1a05',
18332
+ ctaTextColor: '#2c1a05',
18333
+ primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey+Collection',
18334
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
18335
+ events: SPOT_EVENTS_EXAMPLE,
18336
+ },
18337
+ ],
18338
+ rbHomepageHeroThreeTile: [
18339
+ {
18340
+ id: '444444_444444',
18341
+ spot: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
18342
+ variant: exports.RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
18343
+ width: 1140,
18344
+ height: 640,
18345
+ header: 'Cocktail Essentials',
18346
+ description: 'Stock your bar with premium spirits and mixers for the perfect cocktail.',
18347
+ ctaText: 'Build Your Bar',
18348
+ textColor: '#ffffff',
18349
+ backgroundColor: '#1a3c4d',
18350
+ ctaTextColor: '#1a3c4d',
18351
+ primaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Spirits',
18352
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Mixers',
18353
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktail+Kit',
18354
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Cocktail+Mixers',
18355
+ events: SPOT_EVENTS_EXAMPLE,
18356
+ },
18357
+ ],
18358
+ rbLargeCategoryImageTout: [
18359
+ {
18360
+ id: '555555_555555',
18361
+ spot: exports.RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
18362
+ variant: exports.RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
18363
+ width: 468,
18364
+ height: 410,
18365
+ header: 'Rare & Limited Edition',
18366
+ description: 'Discover our collection of hard-to-find and limited release spirits.',
18367
+ textColor: '#ffffff',
18368
+ ctaTextColor: '#ffffff',
18369
+ primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
18370
+ mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
18371
+ ctaText: 'Shop Rare Spirits',
18372
+ events: SPOT_EVENTS_EXAMPLE,
18373
+ },
18374
+ ],
18375
+ rbSmallDiscoverTout: [
18376
+ {
18377
+ id: '666666_666666',
18378
+ spot: exports.RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
18379
+ variant: exports.RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
18380
+ width: 224,
18381
+ height: 378,
18382
+ header: 'Château Margaux 2015 Bordeaux',
18383
+ textColor: '#ffffff',
18384
+ primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
18385
+ mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
18386
+ events: SPOT_EVENTS_EXAMPLE,
18387
+ },
18388
+ ],
18389
+ rbSmallCategoryImageTout: [
18390
+ {
18391
+ id: '777777_777777',
18392
+ spot: exports.RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
18393
+ variant: exports.RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
18394
+ width: 224,
18395
+ height: 410,
18396
+ header: 'Japanese Sake',
18397
+ textColor: '#ffffff',
18398
+ primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
18399
+ mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
18400
+ events: SPOT_EVENTS_EXAMPLE,
18401
+ },
18402
+ ],
18403
+ rbCollectionBannerWithoutTextBlock: [
18404
+ {
18405
+ id: '888888_888888',
18406
+ spot: exports.RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
18407
+ variant: exports.RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
18408
+ width: 887,
18409
+ height: 344,
18410
+ primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
18411
+ mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
18412
+ events: SPOT_EVENTS_EXAMPLE,
18413
+ },
18414
+ ],
18415
+ rbNavigationBanner: [
18416
+ {
18417
+ id: '999999_999999',
18418
+ spot: exports.RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
18419
+ variant: exports.RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
18420
+ width: 440,
18421
+ height: 220,
18422
+ header: 'Explore Tequilas',
18423
+ textColor: '#ffffff',
18424
+ primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
18425
+ mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
18426
+ events: SPOT_EVENTS_EXAMPLE,
18427
+ },
18428
+ ],
18429
+ };
18430
+
17965
18431
  class LiquidCommerceRmnClient {
17966
18432
  constructor(auth) {
17967
- /**
17968
- * Returns the event manager instance.
17969
- *
17970
- * @return {EventService} - The event manager instance.
17971
- */
17972
- this.eventManager = {
17973
- subscribe: (eventType, callback
17974
- /* eslint-disable arrow-body-style */
17975
- ) => {
17976
- return this.eventService.subscribe(eventType, callback);
17977
- },
17978
- publish: (eventType, data) => {
17979
- this.eventService.publish(eventType, data);
17980
- },
17981
- };
17982
18433
  this.selectionService = SelectionService.getInstance(auth);
17983
18434
  this.elementService = ElementService.getInstance();
17984
18435
  this.eventService = EventService.getInstance();
@@ -18026,6 +18477,7 @@ class LiquidCommerceRmnClient {
18026
18477
  inject = this.preventNonExistentSpotTypes(inject);
18027
18478
  // Make the spot selection request
18028
18479
  const response = await this.spotSelectionRequest({ ...params, inject });
18480
+ // const response = await this.useSpotSelectionExample(inject);
18029
18481
  // Handle the response
18030
18482
  if (typeof response === 'object' && 'error' in response) {
18031
18483
  this.eventService.handleSpotState('all', {
@@ -18058,6 +18510,15 @@ class LiquidCommerceRmnClient {
18058
18510
  });
18059
18511
  continue;
18060
18512
  }
18513
+ // Take over placement styles
18514
+ placement.removeAttribute('style');
18515
+ placement.removeAttribute('class');
18516
+ Object.assign(placement.style, {
18517
+ width: '100%',
18518
+ height: 'auto',
18519
+ display: 'flex',
18520
+ justifyContent: 'center',
18521
+ });
18061
18522
  if (spots.length === 1) {
18062
18523
  const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
18063
18524
  if (!isInjected) {
@@ -18084,14 +18545,12 @@ class LiquidCommerceRmnClient {
18084
18545
  const request = {
18085
18546
  url: config === null || config === void 0 ? void 0 : config.url,
18086
18547
  filter,
18087
- spots: inject.map((item) => {
18088
- return {
18089
- placementId: item.placementId,
18090
- spot: item.spotType,
18091
- count: item === null || item === void 0 ? void 0 : item.count,
18092
- ...item === null || item === void 0 ? void 0 : item.filter,
18093
- };
18094
- }),
18548
+ spots: inject.map((item) => ({
18549
+ placementId: item.placementId,
18550
+ spot: item.spotType,
18551
+ count: item === null || item === void 0 ? void 0 : item.count,
18552
+ ...item === null || item === void 0 ? void 0 : item.filter,
18553
+ })),
18095
18554
  };
18096
18555
  return this.spotSelection(request);
18097
18556
  }
@@ -18129,17 +18588,15 @@ class LiquidCommerceRmnClient {
18129
18588
  this.eventService.registerSpot({
18130
18589
  spot,
18131
18590
  placementId: placement.id,
18132
- element: content,
18591
+ spotElement: content,
18133
18592
  });
18134
18593
  carouselSlides.push(content);
18135
18594
  }
18136
18595
  // Get the max width and height of the spots
18137
- const { maxWidth, maxHeight } = spots.reduce((max, spot) => {
18138
- return {
18139
- maxWidth: Math.max(max.maxWidth, spot.width),
18140
- maxHeight: Math.max(max.maxHeight, spot.height),
18141
- };
18142
- }, { maxWidth: 0, maxHeight: 0 });
18596
+ const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
18597
+ maxWidth: Math.max(max.maxWidth, spot.width),
18598
+ maxHeight: Math.max(max.maxHeight, spot.height),
18599
+ }), { maxWidth: 0, maxHeight: 0 });
18143
18600
  // Create the carousel element
18144
18601
  const carouselElement = this.elementService.createCarouselElement({
18145
18602
  slides: carouselSlides,
@@ -18163,7 +18620,7 @@ class LiquidCommerceRmnClient {
18163
18620
  placement.replaceChildren(carouselElement);
18164
18621
  this.eventService.handleSpotState(placement.id, {
18165
18622
  dom: {
18166
- element: carouselElement,
18623
+ spotElement: carouselElement,
18167
18624
  },
18168
18625
  state: {
18169
18626
  mounted: true,
@@ -18224,12 +18681,12 @@ class LiquidCommerceRmnClient {
18224
18681
  this.eventService.registerSpot({
18225
18682
  spot: spotData,
18226
18683
  placementId: injectItem.placementId,
18227
- element: spotElement,
18684
+ spotElement,
18228
18685
  });
18229
18686
  placement.replaceChildren(spotElement);
18230
18687
  this.eventService.handleSpotState(injectItem.placementId, {
18231
18688
  dom: {
18232
- element: spotElement,
18689
+ spotElement,
18233
18690
  },
18234
18691
  state: {
18235
18692
  mounted: true,
@@ -18290,6 +18747,17 @@ class LiquidCommerceRmnClient {
18290
18747
  });
18291
18748
  }
18292
18749
  }
18750
+ useSpotSelectionExample(inject) {
18751
+ const examples = RB_SPOTS_SELECTION_EXAMPLE;
18752
+ const data = {};
18753
+ inject.map((item) => {
18754
+ var _a, _b, _c;
18755
+ data[item.placementId] = (_c = (_a = examples[item.spotType]) === null || _a === void 0 ? void 0 : _a.slice(0, (_b = item.count) !== null && _b !== void 0 ? _b : 1)) !== null && _c !== void 0 ? _c : [];
18756
+ });
18757
+ return new Promise((resolve) => {
18758
+ resolve(data);
18759
+ });
18760
+ }
18293
18761
  }
18294
18762
  /**
18295
18763
  * Creates a new instance of the RmnClient.
@@ -18304,6 +18772,36 @@ async function RmnClient(apiKey, config) {
18304
18772
  const credentials = await authService.initialize();
18305
18773
  return new LiquidCommerceRmnClient(credentials);
18306
18774
  }
18775
+ /**
18776
+ * Creates a new instance of the RmnEventManager.
18777
+ *
18778
+ * @return {IRmnEventManager} - The RmnEventManager instance.
18779
+ */
18780
+ function RmnEventManager() {
18781
+ const eventService = EventService.getInstance();
18782
+ return {
18783
+ /**
18784
+ * Subscribes to an event type.
18785
+ */
18786
+ subscribe: (eventType, callback
18787
+ /* eslint-disable arrow-body-style */
18788
+ ) => {
18789
+ return eventService.subscribe(eventType, callback);
18790
+ },
18791
+ /**
18792
+ * Publishes an event type.
18793
+ */
18794
+ publish: (eventType, data) => {
18795
+ eventService.publish(eventType, data);
18796
+ },
18797
+ /**
18798
+ * Destroys a spot element
18799
+ */
18800
+ destroySpot: (placementId) => {
18801
+ eventService.unregisterSpot(placementId);
18802
+ },
18803
+ };
18804
+ }
18307
18805
  /**
18308
18806
  * Creates the spot html element based on the provided data using shadow dom.
18309
18807
  *
@@ -18339,3 +18837,4 @@ function RmnCreateSpotElement(spot, config) {
18339
18837
  exports.LiquidCommerceRmnClient = LiquidCommerceRmnClient;
18340
18838
  exports.RmnClient = RmnClient;
18341
18839
  exports.RmnCreateSpotElement = RmnCreateSpotElement;
18840
+ exports.RmnEventManager = RmnEventManager;