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

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.
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;