@liquidcommercedev/rmn-sdk 1.5.0-beta.13 → 1.5.0-beta.14

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.esm.js CHANGED
@@ -16143,6 +16143,7 @@ class AuthService extends BaseApi {
16143
16143
 
16144
16144
  const SPOT_ELEMENT_TAG = 'spot-element';
16145
16145
  const CAROUSEL_ELEMENT_TAG = 'spot-carousel-element';
16146
+ const SKELETON_ELEMENT_TAG = 'spot-skeleton-element';
16146
16147
  const GFONT_PRECONNECT = `
16147
16148
  <link rel="preconnect" href="https://fonts.googleapis.com">
16148
16149
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -16153,6 +16154,45 @@ const GFONT_SOURCE_SANS_3 = `
16153
16154
  const GFONT_CORMORANT = `
16154
16155
  <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">
16155
16156
  `;
16157
+ const SPOT_DIMENSIONS = {
16158
+ [RMN_SPOT_TYPE.RB_HOMEPAGE_HERO]: { width: 1140, height: 640 },
16159
+ [RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE]: { width: 1140, height: 640 },
16160
+ [RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE]: { width: 1140, height: 640 },
16161
+ [RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE]: { width: 1140, height: 640 },
16162
+ [RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT]: { width: 468, height: 410 },
16163
+ [RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT]: { width: 224, height: 378 },
16164
+ [RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT]: { width: 224, height: 410 },
16165
+ [RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK]: { width: 887, height: 344 },
16166
+ [RMN_SPOT_TYPE.RB_PRODUCT_UPCS]: { width: 1, height: 1 },
16167
+ [RMN_SPOT_TYPE.RB_NAVIGATION_BANNER]: { width: 440, height: 220 },
16168
+ [RMN_SPOT_TYPE.SMALL_RECTANGLE]: { width: 180, height: 150 },
16169
+ [RMN_SPOT_TYPE.MEDIUM_RECTANGLE]: { width: 300, height: 250 },
16170
+ [RMN_SPOT_TYPE.LARGE_RECTANGLE]: { width: 336, height: 280 },
16171
+ [RMN_SPOT_TYPE.VERTICAL_RECTANGLE]: { width: 240, height: 400 },
16172
+ [RMN_SPOT_TYPE.BANNER]: { width: 468, height: 60 },
16173
+ [RMN_SPOT_TYPE.LEADERBOARD]: { width: 728, height: 90 },
16174
+ [RMN_SPOT_TYPE.LARGE_LEADERBOARD]: { width: 970, height: 90 },
16175
+ [RMN_SPOT_TYPE.BILLBOARD]: { width: 970, height: 250 },
16176
+ [RMN_SPOT_TYPE.SKYSCRAPER]: { width: 120, height: 600 },
16177
+ [RMN_SPOT_TYPE.WIDE_SKYSCRAPER]: { width: 160, height: 600 },
16178
+ [RMN_SPOT_TYPE.HALF_PAGE]: { width: 300, height: 600 },
16179
+ [RMN_SPOT_TYPE.SMALL_SQUARE]: { width: 200, height: 200 },
16180
+ [RMN_SPOT_TYPE.SQUARE]: { width: 250, height: 250 },
16181
+ [RMN_SPOT_TYPE.VERTICAL_BANNER]: { width: 120, height: 240 },
16182
+ [RMN_SPOT_TYPE.BUTTON_2]: { width: 120, height: 60 },
16183
+ [RMN_SPOT_TYPE.MICRO_BAR]: { width: 88, height: 31 },
16184
+ [RMN_SPOT_TYPE.POP_UP]: { width: 550, height: 480 },
16185
+ [RMN_SPOT_TYPE.PORTRAIT]: { width: 300, height: 1050 },
16186
+ [RMN_SPOT_TYPE.SMARTPHONE_BANNER_1]: { width: 300, height: 50 },
16187
+ [RMN_SPOT_TYPE.SMARTPHONE_BANNER_2]: { width: 320, height: 50 },
16188
+ [RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_1]: { width: 640, height: 1136 },
16189
+ [RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_2]: { width: 750, height: 1334 },
16190
+ [RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_3]: { width: 1080, height: 1920 },
16191
+ [RMN_SPOT_TYPE.FEATURE_PHONE_SMALL_BANNER]: { width: 120, height: 20 },
16192
+ [RMN_SPOT_TYPE.FEATURE_PHONE_MEDIUM_BANNER]: { width: 168, height: 28 },
16193
+ [RMN_SPOT_TYPE.FEATURE_PHONE_LARGE_BANNER]: { width: 216, height: 36 },
16194
+ [RMN_SPOT_TYPE.IN_TEXT]: { width: 1, height: 1 },
16195
+ };
16156
16196
 
16157
16197
  class IntersectionObserverService {
16158
16198
  constructor(defaultOptions = {}) {
@@ -16991,6 +17031,118 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
16991
17031
  CarouselElement = CustomCarouselElement;
16992
17032
  }
16993
17033
 
17034
+ function SkeletonTemplate({ fluid, width, height }) {
17035
+ return `
17036
+ <style>
17037
+ :host {
17038
+ display: block;
17039
+ position: relative;
17040
+ box-sizing: border-box;
17041
+ overflow: hidden;
17042
+ width: ${fluid ? '100%' : `${width}px`};
17043
+ height: ${fluid ? '100%' : `${height}px`};
17044
+ background: #ffffff;
17045
+ padding: 20px;
17046
+ border-radius: 5px;
17047
+ }
17048
+
17049
+ .content {
17050
+ height: 100%;
17051
+ display: flex;
17052
+ flex-direction: column;
17053
+ gap: 20px;
17054
+ }
17055
+
17056
+ .image-placeholder {
17057
+ width: 100%;
17058
+ height: 100%;
17059
+ background: #f0f0f0;
17060
+ border-radius: 4px;
17061
+ position: relative;
17062
+ overflow: hidden;
17063
+ }
17064
+
17065
+ .lines-container {
17066
+ display: flex;
17067
+ flex-direction: column;
17068
+ justify-content: flex-end;
17069
+ }
17070
+
17071
+ .line {
17072
+ height: 20px;
17073
+ background: #f0f0f0;
17074
+ border-radius: 4px;
17075
+ margin-bottom: 15px;
17076
+ position: relative;
17077
+ overflow: hidden;
17078
+ }
17079
+
17080
+ .image-placeholder::after,
17081
+ .line::after {
17082
+ content: "";
17083
+ position: absolute;
17084
+ top: 0;
17085
+ left: 0;
17086
+ width: 100%;
17087
+ height: 100%;
17088
+ background: linear-gradient(
17089
+ 90deg,
17090
+ rgba(255, 255, 255, 0) 0%,
17091
+ rgba(255, 255, 255, 0.5) 50%,
17092
+ rgba(255, 255, 255, 0) 100%
17093
+ );
17094
+ animation: shimmer 1.5s infinite;
17095
+ }
17096
+
17097
+ .line.header {
17098
+ width: 25%;
17099
+ }
17100
+
17101
+ .line.description {
17102
+ width: 65%;
17103
+ }
17104
+
17105
+ .line.button {
17106
+ width: 40%;
17107
+ }
17108
+
17109
+ @keyframes shimmer {
17110
+ 0% {
17111
+ transform: translateX(-100%);
17112
+ }
17113
+ 100% {
17114
+ transform: translateX(100%);
17115
+ }
17116
+ }
17117
+ </style>
17118
+
17119
+ <div class="content">
17120
+ <div class="image-placeholder"></div>
17121
+ <div class="lines-container">
17122
+ <div class="line header"></div>
17123
+ <div class="line description"></div>
17124
+ <div class="line button"></div>
17125
+ </div>
17126
+ </div>
17127
+ `;
17128
+ }
17129
+
17130
+ let SkeletonElement;
17131
+ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
17132
+ class CustomSkeletonElement extends HTMLElement {
17133
+ constructor() {
17134
+ super();
17135
+ this.attachShadow({ mode: 'open' });
17136
+ }
17137
+ connectedCallback() {
17138
+ if (!this.shadowRoot || !this.data)
17139
+ return;
17140
+ this.shadowRoot.innerHTML = SkeletonTemplate(this.data);
17141
+ }
17142
+ }
17143
+ SkeletonElement = CustomSkeletonElement;
17144
+ }
17145
+
16994
17146
  let SpotElement;
16995
17147
  if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
16996
17148
  class CustomSpotElement extends HTMLElement {
@@ -17098,15 +17250,14 @@ class ElementService {
17098
17250
  * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
17099
17251
  */
17100
17252
  createSpotElement({ content, config }) {
17101
- var _a, _b;
17253
+ var _a;
17102
17254
  if (!this.ensureBrowserEnvironmentAndDefineElement()) {
17103
17255
  return null;
17104
17256
  }
17105
17257
  const spot = document.createElement(SPOT_ELEMENT_TAG);
17106
- spot.setAttribute('type', (_a = config === null || config === void 0 ? void 0 : config.spot) !== null && _a !== void 0 ? _a : '');
17107
17258
  spot.data = {
17108
17259
  spot: config === null || config === void 0 ? void 0 : config.spot,
17109
- fluid: (_b = config === null || config === void 0 ? void 0 : config.fluid) !== null && _b !== void 0 ? _b : false,
17260
+ fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
17110
17261
  ...config,
17111
17262
  };
17112
17263
  spot.content = content;
@@ -17134,6 +17285,27 @@ class ElementService {
17134
17285
  carousel.slides = slides;
17135
17286
  return carousel;
17136
17287
  }
17288
+ /**
17289
+ * Creates the skeleton html element based on the provided data using shadow dom.
17290
+ *
17291
+ * This method is only available in browser environments.
17292
+ *
17293
+ * @param {ICreateSkeletonElementParams} params - The parameters to create the final element.
17294
+ *
17295
+ * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
17296
+ */
17297
+ createSkeletonElement(params) {
17298
+ if (!this.ensureBrowserEnvironmentAndDefineElement()) {
17299
+ return null;
17300
+ }
17301
+ const skeleton = document.createElement(SKELETON_ELEMENT_TAG);
17302
+ const dimensions = SPOT_DIMENSIONS[params.spotType];
17303
+ skeleton.data = {
17304
+ fluid: params.fluid,
17305
+ ...dimensions,
17306
+ };
17307
+ return skeleton;
17308
+ }
17137
17309
  /**
17138
17310
  * Overrides the spot colors with the provided colors.
17139
17311
  *
@@ -17168,6 +17340,9 @@ class ElementService {
17168
17340
  if (!window.customElements.get(CAROUSEL_ELEMENT_TAG)) {
17169
17341
  window.customElements.define(CAROUSEL_ELEMENT_TAG, CarouselElement);
17170
17342
  }
17343
+ if (!window.customElements.get(SKELETON_ELEMENT_TAG)) {
17344
+ window.customElements.define(SKELETON_ELEMENT_TAG, SkeletonElement);
17345
+ }
17171
17346
  return true;
17172
17347
  }
17173
17348
  }
@@ -19313,6 +19488,7 @@ class LiquidCommerceRmnClient {
19313
19488
  this.selectionService = SelectionService.getInstance(auth);
19314
19489
  this.elementService = ElementService.getInstance();
19315
19490
  this.eventService = EventService.getInstance();
19491
+ this.intersectionObserver = new IntersectionObserverService();
19316
19492
  }
19317
19493
  /**
19318
19494
  * Makes a selection request on our server based on the provided data.
@@ -19336,24 +19512,29 @@ class LiquidCommerceRmnClient {
19336
19512
  async injectSpotElement(params) {
19337
19513
  var _a;
19338
19514
  if (typeof window === 'undefined' || typeof document === 'undefined') {
19339
- console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
19515
+ console.warn('LiquidCommerce Rmn Sdk: injectSpotElement method is only available in the browser environment.');
19340
19516
  return;
19341
19517
  }
19342
19518
  const config = params.config;
19343
19519
  let inject = params.inject;
19520
+ // Handle no spots error state
19344
19521
  if (!inject.length) {
19345
- // Handle no spots error state
19346
19522
  this.eventService.handleSpotState('all', {
19347
19523
  state: {
19348
19524
  error: 'No spot elements provided for injection.',
19349
- loading: false,
19350
- mounted: false,
19351
19525
  },
19352
19526
  });
19353
19527
  return;
19354
19528
  }
19355
- // Update the state of the spots to loading
19356
- this.updateSpotsState(inject);
19529
+ // Identify the spot elements
19530
+ for (const item of inject) {
19531
+ this.eventService.handleSpotState(item.placementId, {
19532
+ identifier: {
19533
+ placementId: item.placementId,
19534
+ spotType: item.spotType,
19535
+ },
19536
+ }, false);
19537
+ }
19357
19538
  // Prevent duplicate placement ids
19358
19539
  const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
19359
19540
  if (!hasDuplicatePlacementIds) {
@@ -19361,35 +19542,9 @@ class LiquidCommerceRmnClient {
19361
19542
  }
19362
19543
  // Prevent non-existent spot types
19363
19544
  inject = this.preventNonExistentSpotTypes(inject);
19364
- // Make the spot selection request
19365
- const response = await this.spotSelectionRequest({ ...params, inject });
19366
- // const response = await this.useSpotSelectionExample(inject);
19367
- // Handle the response
19368
- if (typeof response === 'object' && 'error' in response) {
19369
- // Handle request error state
19370
- this.eventService.handleSpotState('all', {
19371
- state: {
19372
- error: response.error,
19373
- mounted: false,
19374
- loading: false,
19375
- },
19376
- });
19377
- return;
19378
- }
19545
+ // Add Intersection Observer to the spot elements to track visibility
19546
+ // This is useful for lazy loading the spot elements
19379
19547
  for (const item of inject) {
19380
- const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
19381
- const spots = response[item.placementId];
19382
- if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
19383
- // Handle no spots found error state
19384
- this.eventService.handleSpotState(item.placementId, {
19385
- state: {
19386
- error: `No spots found for type "${item.spotType}".`,
19387
- mounted: false,
19388
- loading: false,
19389
- },
19390
- });
19391
- continue;
19392
- }
19393
19548
  const placementId = item.placementId.replace('#', '');
19394
19549
  const placement = document.getElementById(placementId);
19395
19550
  if (!placement) {
@@ -19397,8 +19552,6 @@ class LiquidCommerceRmnClient {
19397
19552
  this.eventService.handleSpotState(item.placementId, {
19398
19553
  state: {
19399
19554
  error: `Placement not found for id "${placementId}".`,
19400
- mounted: false,
19401
- loading: false,
19402
19555
  },
19403
19556
  });
19404
19557
  continue;
@@ -19412,43 +19565,73 @@ class LiquidCommerceRmnClient {
19412
19565
  display: 'flex',
19413
19566
  justifyContent: 'center',
19414
19567
  });
19415
- // Handle single spot
19416
- if (spots.length === 1) {
19417
- const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
19418
- if (!isInjected) {
19419
- continue;
19420
- }
19568
+ const skeletonElement = this.elementService.createSkeletonElement({
19569
+ fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
19570
+ spotType: item.spotType,
19571
+ });
19572
+ if (!skeletonElement) {
19573
+ this.eventService.handleSpotState(item.placementId, {
19574
+ state: {
19575
+ error: `Failed to create skeleton loader element.`,
19576
+ mounted: false,
19577
+ loading: true,
19578
+ },
19579
+ });
19580
+ continue;
19421
19581
  }
19422
- // Handle multiple spots (carousel)
19423
- if (spots.length > 1) {
19424
- const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
19425
- if (!isInjected) {
19426
- continue;
19582
+ placement.replaceChildren(skeletonElement);
19583
+ const spotPlacementIsNear = async () => {
19584
+ var _a;
19585
+ // Set the spot element to loading state
19586
+ this.eventService.handleSpotState(item.placementId, {
19587
+ state: {
19588
+ loading: true,
19589
+ },
19590
+ });
19591
+ // Stop observing the placement
19592
+ this.intersectionObserver.unobserve(placement);
19593
+ // Make the spot selection request
19594
+ const response = await this.spotSelectionRequest({ ...params, inject: [item] });
19595
+ // const response = await this.useSpotSelectionExample(inject);
19596
+ // Handle request error state
19597
+ if (typeof response === 'object' && 'error' in response) {
19598
+ this.eventService.handleSpotState(item.placementId, {
19599
+ state: {
19600
+ error: response.error,
19601
+ mounted: false,
19602
+ loading: false,
19603
+ },
19604
+ });
19605
+ this.clearPlacement(item.placementId);
19606
+ return;
19427
19607
  }
19428
- }
19608
+ const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
19609
+ const spots = response[item.placementId];
19610
+ if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
19611
+ // Handle no spots found error state
19612
+ this.eventService.handleSpotState(item.placementId, {
19613
+ state: {
19614
+ error: `No spots found for type "${item.spotType}".`,
19615
+ mounted: false,
19616
+ loading: false,
19617
+ },
19618
+ });
19619
+ this.clearPlacement(item.placementId);
19620
+ return;
19621
+ }
19622
+ // Handle single spot
19623
+ if (spots.length === 1) {
19624
+ this.injectOneSpotElement(item, placement, spots[0], itemConfig);
19625
+ }
19626
+ // Handle multiple spots (carousel)
19627
+ if (spots.length > 1) {
19628
+ this.injectCarouselSpotElement(placement, spots, itemConfig);
19629
+ }
19630
+ };
19631
+ this.intersectionObserver.observe(placement, spotPlacementIsNear, { rootMargin: '500px' });
19429
19632
  }
19430
19633
  }
19431
- /**
19432
- * Makes a selection request on our server based on the provided data.
19433
- *
19434
- * @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
19435
- *
19436
- * @return {Promise<ISpots | {error: string}>} - The spots response object.
19437
- */
19438
- async spotSelectionRequest(params) {
19439
- const { inject, filter, config } = params;
19440
- const request = {
19441
- url: config === null || config === void 0 ? void 0 : config.url,
19442
- filter,
19443
- spots: inject.map((item) => ({
19444
- placementId: item.placementId,
19445
- spot: item.spotType,
19446
- count: item === null || item === void 0 ? void 0 : item.count,
19447
- ...item === null || item === void 0 ? void 0 : item.filter,
19448
- })),
19449
- };
19450
- return this.spotSelection(request);
19451
- }
19634
+ /** ========================= HELPER METHODS ========================= **/
19452
19635
  /**
19453
19636
  * Injects a carousel element with the provided spots into the placement.
19454
19637
  *
@@ -19517,7 +19700,8 @@ class LiquidCommerceRmnClient {
19517
19700
  loading: false,
19518
19701
  },
19519
19702
  });
19520
- return false;
19703
+ this.clearPlacement(placement.id);
19704
+ return;
19521
19705
  }
19522
19706
  placement.replaceChildren(carouselElement);
19523
19707
  this.eventService.handleSpotState(placement.id, {
@@ -19531,7 +19715,6 @@ class LiquidCommerceRmnClient {
19531
19715
  error: undefined,
19532
19716
  },
19533
19717
  });
19534
- return true;
19535
19718
  }
19536
19719
  /**
19537
19720
  * Injects a single spot element into the provided placement.
@@ -19567,7 +19750,8 @@ class LiquidCommerceRmnClient {
19567
19750
  loading: false,
19568
19751
  },
19569
19752
  });
19570
- return false;
19753
+ this.clearPlacement(injectItem.placementId);
19754
+ return;
19571
19755
  }
19572
19756
  // Create the spot element
19573
19757
  const spotElement = this.elementService.createSpotElement({
@@ -19588,7 +19772,8 @@ class LiquidCommerceRmnClient {
19588
19772
  loading: false,
19589
19773
  },
19590
19774
  });
19591
- return false;
19775
+ this.clearPlacement(injectItem.placementId);
19776
+ return;
19592
19777
  }
19593
19778
  this.eventService.registerSpot({
19594
19779
  spot: spotData,
@@ -19607,7 +19792,38 @@ class LiquidCommerceRmnClient {
19607
19792
  error: undefined,
19608
19793
  },
19609
19794
  });
19610
- return true;
19795
+ }
19796
+ /**
19797
+ * Clears the placement element by removing all its children.
19798
+ *
19799
+ * @param {string} placementId - The placement id.
19800
+ *
19801
+ * @return {void}
19802
+ */
19803
+ clearPlacement(placementId) {
19804
+ var _a;
19805
+ (_a = document.getElementById(placementId)) === null || _a === void 0 ? void 0 : _a.replaceChildren();
19806
+ }
19807
+ /**
19808
+ * Makes a selection request on our server based on the provided data.
19809
+ *
19810
+ * @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
19811
+ *
19812
+ * @return {Promise<ISpots | {error: string}>} - The spots response object.
19813
+ */
19814
+ async spotSelectionRequest(params) {
19815
+ const { inject, filter, config } = params;
19816
+ const request = {
19817
+ url: config === null || config === void 0 ? void 0 : config.url,
19818
+ filter,
19819
+ spots: inject.map((item) => ({
19820
+ placementId: item.placementId,
19821
+ spot: item.spotType,
19822
+ count: item === null || item === void 0 ? void 0 : item.count,
19823
+ ...item === null || item === void 0 ? void 0 : item.filter,
19824
+ })),
19825
+ };
19826
+ return this.spotSelection(request);
19611
19827
  }
19612
19828
  /**
19613
19829
  * Prevents duplicate placement ids in the inject data.
@@ -19625,8 +19841,6 @@ class LiquidCommerceRmnClient {
19625
19841
  this.eventService.handleSpotState(item.placementId, {
19626
19842
  state: {
19627
19843
  error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
19628
- mounted: false,
19629
- loading: false,
19630
19844
  },
19631
19845
  });
19632
19846
  return false;
@@ -19635,6 +19849,12 @@ class LiquidCommerceRmnClient {
19635
19849
  }
19636
19850
  return true;
19637
19851
  }
19852
+ /**
19853
+ * Prevents non-existent spot types in the inject data.
19854
+ *
19855
+ * @param {IInjectSpotElement[]} inject - The inject data.
19856
+ * @return {IInjectSpotElement[]} - The filtered inject data.
19857
+ */
19638
19858
  preventNonExistentSpotTypes(inject) {
19639
19859
  const newInject = [];
19640
19860
  for (const item of inject) {
@@ -19642,8 +19862,6 @@ class LiquidCommerceRmnClient {
19642
19862
  this.eventService.handleSpotState(item.placementId, {
19643
19863
  state: {
19644
19864
  error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
19645
- mounted: false,
19646
- loading: false,
19647
19865
  },
19648
19866
  });
19649
19867
  continue;
@@ -19652,22 +19870,7 @@ class LiquidCommerceRmnClient {
19652
19870
  }
19653
19871
  return newInject;
19654
19872
  }
19655
- // Initialize spots with loading state and identifiers
19656
- updateSpotsState(inject) {
19657
- for (const item of inject) {
19658
- this.eventService.handleSpotState(item.placementId, {
19659
- identifier: {
19660
- placementId: item.placementId,
19661
- spotType: item.spotType,
19662
- },
19663
- state: {
19664
- loading: true,
19665
- mounted: false,
19666
- error: undefined,
19667
- },
19668
- });
19669
- }
19670
- }
19873
+ // Use spot selection example data for private testing
19671
19874
  useSpotSelectionExample(inject) {
19672
19875
  const examples = { ...RB_SPOTS_SELECTION_EXAMPLE, ...IAB_SPOTS_SELECTION_EXAMPLE };
19673
19876
  const data = {};
@@ -0,0 +1,2 @@
1
+ export * from './skeleton.component';
2
+ export * from './skeleton.interface';
@@ -0,0 +1,3 @@
1
+ import type { ICustomSkeletonElement } from './skeleton.interface';
2
+ declare let SkeletonElement: new () => ICustomSkeletonElement;
3
+ export { SkeletonElement };
@@ -0,0 +1,13 @@
1
+ import type { RMN_SPOT_TYPE } from 'enums';
2
+ export interface ICustomSkeletonElementData {
3
+ fluid: boolean;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface ICustomSkeletonElement extends HTMLElement {
8
+ data: ICustomSkeletonElementData;
9
+ }
10
+ export interface ICreateSkeletonElementParams {
11
+ fluid: boolean;
12
+ spotType: RMN_SPOT_TYPE;
13
+ }
@@ -0,0 +1,2 @@
1
+ import type { ICustomSkeletonElementData } from './skeleton.interface';
2
+ export declare function SkeletonTemplate({ fluid, width, height }: ICustomSkeletonElementData): string;
@@ -1,5 +1,8 @@
1
+ import type { SpotDimensionsType } from 'modules/selection';
1
2
  export declare const SPOT_ELEMENT_TAG = "spot-element";
2
3
  export declare const CAROUSEL_ELEMENT_TAG = "spot-carousel-element";
4
+ export declare const SKELETON_ELEMENT_TAG = "spot-skeleton-element";
3
5
  export declare const GFONT_PRECONNECT = "\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n";
4
6
  export declare const GFONT_SOURCE_SANS_3 = "\n <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap\">\n";
5
7
  export declare const GFONT_CORMORANT = "\n <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\">\n";
8
+ export declare const SPOT_DIMENSIONS: SpotDimensionsType;
@@ -1,5 +1,6 @@
1
1
  import type { ISpot } from 'modules/selection';
2
2
  import type { ICreateCarouselElementParams } from './component/carousel';
3
+ import type { ICreateSkeletonElementParams } from './component/skeleton';
3
4
  import type { ICreateSpotElementParams } from './component/spot';
4
5
  import type { IElementService, ISpotColors } from './element.interface';
5
6
  export declare class ElementService implements IElementService {
@@ -24,6 +25,16 @@ export declare class ElementService implements IElementService {
24
25
  * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
25
26
  */
26
27
  createCarouselElement({ slides, config, }: ICreateCarouselElementParams): HTMLElement | null;
28
+ /**
29
+ * Creates the skeleton html element based on the provided data using shadow dom.
30
+ *
31
+ * This method is only available in browser environments.
32
+ *
33
+ * @param {ICreateSkeletonElementParams} params - The parameters to create the final element.
34
+ *
35
+ * @return {HTMLElement | null} - The html element or null if the browser environment is not available.
36
+ */
37
+ createSkeletonElement(params: ICreateSkeletonElementParams): HTMLElement | null;
27
38
  /**
28
39
  * Overrides the spot colors with the provided colors.
29
40
  *
@@ -6,6 +6,7 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
6
6
  private readonly selectionService;
7
7
  private readonly elementService;
8
8
  private readonly eventService;
9
+ private intersectionObserver;
9
10
  constructor(auth: IAuthCredentials);
10
11
  /**
11
12
  * Makes a selection request on our server based on the provided data.
@@ -27,14 +28,7 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
27
28
  * @return {Promise<void>} - A promise that resolves when the spot elements are injected.
28
29
  */
29
30
  injectSpotElement(params: IInjectSpotElementParams): Promise<void>;
30
- /**
31
- * Makes a selection request on our server based on the provided data.
32
- *
33
- * @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
34
- *
35
- * @return {Promise<ISpots | {error: string}>} - The spots response object.
36
- */
37
- private spotSelectionRequest;
31
+ /** ========================= HELPER METHODS ========================= **/
38
32
  /**
39
33
  * Injects a carousel element with the provided spots into the placement.
40
34
  *
@@ -56,6 +50,22 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
56
50
  * @return {void}
57
51
  */
58
52
  private injectOneSpotElement;
53
+ /**
54
+ * Clears the placement element by removing all its children.
55
+ *
56
+ * @param {string} placementId - The placement id.
57
+ *
58
+ * @return {void}
59
+ */
60
+ private clearPlacement;
61
+ /**
62
+ * Makes a selection request on our server based on the provided data.
63
+ *
64
+ * @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
65
+ *
66
+ * @return {Promise<ISpots | {error: string}>} - The spots response object.
67
+ */
68
+ private spotSelectionRequest;
59
69
  /**
60
70
  * Prevents duplicate placement ids in the inject data.
61
71
  *
@@ -66,8 +76,13 @@ export declare class LiquidCommerceRmnClient implements IRmnClient {
66
76
  * @return {void}
67
77
  */
68
78
  private preventDuplicateSpotPlacementIds;
79
+ /**
80
+ * Prevents non-existent spot types in the inject data.
81
+ *
82
+ * @param {IInjectSpotElement[]} inject - The inject data.
83
+ * @return {IInjectSpotElement[]} - The filtered inject data.
84
+ */
69
85
  private preventNonExistentSpotTypes;
70
- private updateSpotsState;
71
86
  private useSpotSelectionExample;
72
87
  }
73
88
  /**