@liquidcommercedev/rmn-sdk 1.4.6-beta.3 → 1.4.6-beta.5
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +351 -47
- package/dist/index.esm.js +351 -47
- package/dist/types/enums.d.ts +4 -0
- package/dist/types/modules/element/component/carousel/carousel.interface.d.ts +3 -3
- package/dist/types/modules/element/element.interface.d.ts +17 -9
- package/dist/types/modules/element/template/template.service.d.ts +4 -3
- package/dist/types/modules/event/event.interface.d.ts +67 -0
- package/dist/types/modules/event/event.service.d.ts +27 -2
- package/dist/types/modules/event/pubsub.d.ts +67 -0
- package/dist/types/modules/selection/selection.interface.d.ts +3 -2
- package/dist/types/modules/selection/selection.type.d.ts +3 -2
- package/dist/types/rmn-client.d.ts +28 -10
- package/dist/types/types.d.ts +7 -4
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -42,6 +42,7 @@ var RMN_SPOT_TYPE;
|
|
42
42
|
var RMN_FILTER_PROPERTIES;
|
43
43
|
(function (RMN_FILTER_PROPERTIES) {
|
44
44
|
RMN_FILTER_PROPERTIES["KEYWORDS"] = "keywords";
|
45
|
+
RMN_FILTER_PROPERTIES["PAGE_LOCATION"] = "pageLocation";
|
45
46
|
RMN_FILTER_PROPERTIES["PARENTCO"] = "parentCo";
|
46
47
|
RMN_FILTER_PROPERTIES["BRAND"] = "brand";
|
47
48
|
RMN_FILTER_PROPERTIES["CATEGORY"] = "category";
|
@@ -53,6 +54,9 @@ var RMN_FILTER_PROPERTIES;
|
|
53
54
|
})(RMN_FILTER_PROPERTIES || (RMN_FILTER_PROPERTIES = {}));
|
54
55
|
var RMN_SPOT_EVENT;
|
55
56
|
(function (RMN_SPOT_EVENT) {
|
57
|
+
RMN_SPOT_EVENT["MOUNTED"] = "MOUNTED";
|
58
|
+
RMN_SPOT_EVENT["UNMOUNTED"] = "UNMOUNTED";
|
59
|
+
RMN_SPOT_EVENT["RESIZED"] = "RESIZED";
|
56
60
|
RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
|
57
61
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
58
62
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
@@ -15161,6 +15165,46 @@ const GFONT_CORMORANT = `
|
|
15161
15165
|
<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">
|
15162
15166
|
`;
|
15163
15167
|
|
15168
|
+
class IntersectionObserverService {
|
15169
|
+
constructor(defaultOptions = {}) {
|
15170
|
+
this.observers = new Map();
|
15171
|
+
this.defaultOptions = {
|
15172
|
+
root: null,
|
15173
|
+
rootMargin: '0px',
|
15174
|
+
threshold: 0.5,
|
15175
|
+
...defaultOptions,
|
15176
|
+
};
|
15177
|
+
}
|
15178
|
+
observe(element, callback, options = {}) {
|
15179
|
+
const mergedOptions = { ...this.defaultOptions, ...options };
|
15180
|
+
const ioCallback = (entries) => {
|
15181
|
+
entries.forEach((entry) => {
|
15182
|
+
if (entry.isIntersecting) {
|
15183
|
+
callback(entry);
|
15184
|
+
}
|
15185
|
+
});
|
15186
|
+
};
|
15187
|
+
const observer = new IntersectionObserver(ioCallback, mergedOptions);
|
15188
|
+
this.observers.set(element, observer);
|
15189
|
+
observer.observe(element);
|
15190
|
+
}
|
15191
|
+
unobserve(element) {
|
15192
|
+
const observer = this.observers.get(element);
|
15193
|
+
if (observer) {
|
15194
|
+
observer.unobserve(element);
|
15195
|
+
observer.disconnect();
|
15196
|
+
this.observers.delete(element);
|
15197
|
+
}
|
15198
|
+
}
|
15199
|
+
unobserveAll() {
|
15200
|
+
this.observers.forEach((observer, element) => {
|
15201
|
+
observer.unobserve(element);
|
15202
|
+
observer.disconnect();
|
15203
|
+
});
|
15204
|
+
this.observers.clear();
|
15205
|
+
}
|
15206
|
+
}
|
15207
|
+
|
15164
15208
|
class ResizeObserverService {
|
15165
15209
|
constructor({ element, maxSize, minScale }) {
|
15166
15210
|
this.element = element;
|
@@ -15466,8 +15510,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15466
15510
|
this.addEventListener('spotSizeChanged', this.handleCarouselSizeChanged.bind(this));
|
15467
15511
|
}
|
15468
15512
|
}
|
15469
|
-
|
15470
|
-
|
15513
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
15514
|
+
handleCarouselSizeChanged(_event) {
|
15515
|
+
// console.info('Carousel Size Changed', event);
|
15471
15516
|
}
|
15472
15517
|
render() {
|
15473
15518
|
var _a;
|
@@ -15693,7 +15738,7 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15693
15738
|
* #########################################################
|
15694
15739
|
*/
|
15695
15740
|
handleSpotSizeChanged(event) {
|
15696
|
-
console.info('Spot Size Changed', event);
|
15741
|
+
// console.info('Spot Size Changed', event);
|
15697
15742
|
// Adjust text elements font size based on the scale factor
|
15698
15743
|
this.adjustFontSize(event.detail.scale);
|
15699
15744
|
}
|
@@ -15705,8 +15750,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15705
15750
|
elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
|
15706
15751
|
if (element instanceof HTMLElement) {
|
15707
15752
|
if (!this.originalFontSizes.has(element)) {
|
15708
|
-
const
|
15709
|
-
this.originalFontSizes.set(element,
|
15753
|
+
const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
|
15754
|
+
this.originalFontSizes.set(element, originalSize);
|
15710
15755
|
}
|
15711
15756
|
const originalSize = this.originalFontSizes.get(element);
|
15712
15757
|
const newFontSize = originalSize * scaleFactor;
|
@@ -17537,11 +17582,12 @@ function rbSmallDiscoverToutTemplate(spot, config) {
|
|
17537
17582
|
}
|
17538
17583
|
|
17539
17584
|
/**
|
17540
|
-
*
|
17585
|
+
* Returns the HTML element for the given spot.
|
17541
17586
|
*
|
17542
|
-
* @param {ISpot} spot - The spot
|
17587
|
+
* @param {ISpot} spot - The spot object.
|
17588
|
+
* @param {ISpotTemplateConfig} config - The spot template configuration.
|
17543
17589
|
*
|
17544
|
-
* @return {
|
17590
|
+
* @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
|
17545
17591
|
*/
|
17546
17592
|
const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
17547
17593
|
const templates = {
|
@@ -17614,6 +17660,228 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
17614
17660
|
return spotHtmlStringToElement(spotHtmlString);
|
17615
17661
|
};
|
17616
17662
|
|
17663
|
+
/**
|
17664
|
+
* PubSub class
|
17665
|
+
* Manages event subscriptions and publications
|
17666
|
+
* @template IEventMap A record type defining the structure of events and their data
|
17667
|
+
*/
|
17668
|
+
class PubSub {
|
17669
|
+
constructor() {
|
17670
|
+
/**
|
17671
|
+
* Object to store subscribers for each event type
|
17672
|
+
*/
|
17673
|
+
this.subscribers = {};
|
17674
|
+
}
|
17675
|
+
/**
|
17676
|
+
* Subscribe to an event
|
17677
|
+
* @param eventType - The type of event to subscribe to
|
17678
|
+
* @param callback - The function to be called when the event is published
|
17679
|
+
* @returns A function to unsubscribe from the event
|
17680
|
+
*
|
17681
|
+
* @Example:
|
17682
|
+
* const unsubscribe = pubSub.subscribe('userLogin', (data) => {
|
17683
|
+
* console.log(`User ${data.username} logged in`);
|
17684
|
+
* });
|
17685
|
+
*/
|
17686
|
+
subscribe(eventType, callback) {
|
17687
|
+
if (!this.subscribers[eventType]) {
|
17688
|
+
this.subscribers[eventType] = [];
|
17689
|
+
}
|
17690
|
+
this.subscribers[eventType].push(callback);
|
17691
|
+
// Return an unsubscribe function
|
17692
|
+
return () => {
|
17693
|
+
this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
|
17694
|
+
};
|
17695
|
+
}
|
17696
|
+
/**
|
17697
|
+
* Publish an event
|
17698
|
+
* @param eventType - The type of event to publish
|
17699
|
+
* @param data - The data to be passed to the event subscribers
|
17700
|
+
*
|
17701
|
+
* @Example:
|
17702
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
17703
|
+
*/
|
17704
|
+
publish(eventType, data) {
|
17705
|
+
if (!this.subscribers[eventType]) {
|
17706
|
+
return;
|
17707
|
+
}
|
17708
|
+
this.subscribers[eventType].forEach((callback) => callback(data));
|
17709
|
+
}
|
17710
|
+
}
|
17711
|
+
/**
|
17712
|
+
* Usage Example:
|
17713
|
+
*
|
17714
|
+
* interface IEventMap {
|
17715
|
+
* userLogin: { username: string; timestamp: number };
|
17716
|
+
* pageView: { url: string; timestamp: number };
|
17717
|
+
* }
|
17718
|
+
*
|
17719
|
+
* const pubSub = new PubSub<IEventMap>();
|
17720
|
+
*
|
17721
|
+
* // Subscribe to events
|
17722
|
+
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
17723
|
+
* console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
|
17724
|
+
* });
|
17725
|
+
*
|
17726
|
+
* pubSub.subscribe('pageView', (data) => {
|
17727
|
+
* console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
|
17728
|
+
* });
|
17729
|
+
*
|
17730
|
+
* // Publish events
|
17731
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
17732
|
+
* pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
|
17733
|
+
*
|
17734
|
+
* // Unsubscribe from an event
|
17735
|
+
* unsubscribeLogin();
|
17736
|
+
*/
|
17737
|
+
|
17738
|
+
class EventService {
|
17739
|
+
constructor() {
|
17740
|
+
this.pubSub = new PubSub();
|
17741
|
+
this.activeSpots = new Map();
|
17742
|
+
this.intersectionObserver = new IntersectionObserverService();
|
17743
|
+
}
|
17744
|
+
static getInstance() {
|
17745
|
+
if (!EventService.instance) {
|
17746
|
+
EventService.instance = new EventService();
|
17747
|
+
}
|
17748
|
+
return EventService.instance;
|
17749
|
+
}
|
17750
|
+
registerSpot({ placementId, element, spot }) {
|
17751
|
+
this.activeSpots.set(spot.id, {
|
17752
|
+
placementId,
|
17753
|
+
element,
|
17754
|
+
impressionTracked: false,
|
17755
|
+
});
|
17756
|
+
// Handle resize observer
|
17757
|
+
// this.handleResizeObserver(placementId, spot, element);
|
17758
|
+
// Handle intersection observer
|
17759
|
+
this.handleIntersectionObserver(placementId, spot, element);
|
17760
|
+
// Attach click event listener
|
17761
|
+
element.addEventListener('click', async () => {
|
17762
|
+
var _a, _b;
|
17763
|
+
this.pubSub.publish(RMN_SPOT_EVENT.CLICK, {
|
17764
|
+
placementId,
|
17765
|
+
spotId: spot.id,
|
17766
|
+
element,
|
17767
|
+
});
|
17768
|
+
// Fire click event
|
17769
|
+
await this.fireEvent({
|
17770
|
+
event: RMN_SPOT_EVENT.CLICK,
|
17771
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
17772
|
+
});
|
17773
|
+
});
|
17774
|
+
// Publish spot created event
|
17775
|
+
this.pubSub.publish(RMN_SPOT_EVENT.MOUNTED, {
|
17776
|
+
placementId,
|
17777
|
+
spotId: spot.id,
|
17778
|
+
spotType: spot.spot,
|
17779
|
+
spotVariant: spot.variant,
|
17780
|
+
element,
|
17781
|
+
});
|
17782
|
+
}
|
17783
|
+
unregisterSpot(spotId) {
|
17784
|
+
const spotData = this.activeSpots.get(spotId);
|
17785
|
+
if (spotData) {
|
17786
|
+
this.intersectionObserver.unobserve(spotData.element);
|
17787
|
+
// this.resizeObserver?.disconnect();
|
17788
|
+
this.pubSub.publish(RMN_SPOT_EVENT.UNMOUNTED, {
|
17789
|
+
placementId: spotData.placementId,
|
17790
|
+
spotId,
|
17791
|
+
});
|
17792
|
+
this.activeSpots.delete(spotId);
|
17793
|
+
}
|
17794
|
+
}
|
17795
|
+
// private handleResizeObserver(placementId: string, spot: ISpot, element: HTMLElement): void {
|
17796
|
+
// // this.resizeObserver = new ResizeObserverService({
|
17797
|
+
// // element,
|
17798
|
+
// // maxSize: {
|
17799
|
+
// // width: spot.width,
|
17800
|
+
// // height: spot.height,
|
17801
|
+
// // },
|
17802
|
+
// // minScale: 0.25,
|
17803
|
+
// // });
|
17804
|
+
//
|
17805
|
+
// const sizeChangedCb = (event: ISizeChangedEvent) => {
|
17806
|
+
// // Publish spot resized event
|
17807
|
+
// this.pubSub.publish(RMN_SPOT_EVENT.RESIZED, {
|
17808
|
+
// placementId,
|
17809
|
+
// spotId: spot.id,
|
17810
|
+
// scale: event.detail.scale,
|
17811
|
+
// previousDimensions: {
|
17812
|
+
// width: event.detail.width,
|
17813
|
+
// height: event.detail.height,
|
17814
|
+
// },
|
17815
|
+
// currentDimensions: {
|
17816
|
+
// width: event.detail.newWidth,
|
17817
|
+
// height: event.detail.newHeight,
|
17818
|
+
// },
|
17819
|
+
// });
|
17820
|
+
// };
|
17821
|
+
//
|
17822
|
+
// element.addEventListener('spotSizeChanged', sizeChangedCb as EventListener);
|
17823
|
+
// }
|
17824
|
+
handleIntersectionObserver(placementId, spot, element) {
|
17825
|
+
const spotIsVisibleCb = async () => {
|
17826
|
+
var _a, _b;
|
17827
|
+
this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
|
17828
|
+
placementId,
|
17829
|
+
spotId: spot.id,
|
17830
|
+
element,
|
17831
|
+
});
|
17832
|
+
this.intersectionObserver.unobserve(element);
|
17833
|
+
this.activeSpots.set(spot.id, {
|
17834
|
+
placementId,
|
17835
|
+
element,
|
17836
|
+
impressionTracked: true,
|
17837
|
+
});
|
17838
|
+
// Fire impression event
|
17839
|
+
await this.fireEvent({
|
17840
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
17841
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
17842
|
+
});
|
17843
|
+
};
|
17844
|
+
this.intersectionObserver.observe(element, spotIsVisibleCb);
|
17845
|
+
}
|
17846
|
+
subscribe(eventType, callback) {
|
17847
|
+
return this.pubSub.subscribe(eventType, callback);
|
17848
|
+
}
|
17849
|
+
publish(eventType, data) {
|
17850
|
+
this.pubSub.publish(eventType, data);
|
17851
|
+
}
|
17852
|
+
/**
|
17853
|
+
* Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
|
17854
|
+
*
|
17855
|
+
* @param {IFireEventParams} params - The parameters for firing the event.
|
17856
|
+
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
17857
|
+
* @param {string} params.eventUrl - The URL to which the event is sent.
|
17858
|
+
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
17859
|
+
*/
|
17860
|
+
async fireEvent({ event, eventUrl }) {
|
17861
|
+
const didFireEvent = navigator.sendBeacon(eventUrl);
|
17862
|
+
if (didFireEvent && event === RMN_SPOT_EVENT.CLICK) {
|
17863
|
+
window.location.href = this.getRedirectUrlFromPayload(eventUrl);
|
17864
|
+
}
|
17865
|
+
}
|
17866
|
+
/**
|
17867
|
+
* Extracts and decodes a URL from a base64-encoded query parameter.
|
17868
|
+
*
|
17869
|
+
* @param {string} url - The URL containing the base64-encoded query parameter.
|
17870
|
+
* @returns {string} - The decoded URL or an empty string if decoding fails.
|
17871
|
+
*/
|
17872
|
+
getRedirectUrlFromPayload(url) {
|
17873
|
+
var _a, _b;
|
17874
|
+
const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
|
17875
|
+
try {
|
17876
|
+
const data = JSON.parse(atob(base64String));
|
17877
|
+
return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
|
17878
|
+
}
|
17879
|
+
catch (_c) {
|
17880
|
+
return '';
|
17881
|
+
}
|
17882
|
+
}
|
17883
|
+
}
|
17884
|
+
|
17617
17885
|
const SELECTION_API_PATH = '/spots/selection';
|
17618
17886
|
|
17619
17887
|
class SelectionService extends BaseApi {
|
@@ -17648,46 +17916,39 @@ class LiquidCommerceRmnClient {
|
|
17648
17916
|
constructor(auth) {
|
17649
17917
|
this.selectionService = SelectionService.getInstance(auth);
|
17650
17918
|
this.elementService = ElementService.getInstance();
|
17919
|
+
this.eventService = EventService.getInstance();
|
17651
17920
|
}
|
17652
17921
|
/**
|
17653
17922
|
* Makes a selection request on our server based on the provided data.
|
17654
17923
|
*
|
17655
17924
|
* To create a spot html element, use the RmnCreateSpotElement function.
|
17656
17925
|
*
|
17657
|
-
* @param {ISpotSelectionParams}
|
17926
|
+
* @param {ISpotSelectionParams} params - Spots selection parameters.
|
17658
17927
|
*
|
17659
17928
|
* @return {Promise<ISpots>} - The spots response object.
|
17660
17929
|
*/
|
17661
|
-
async spotSelection(
|
17662
|
-
return this.selectionService.spotSelection(
|
17930
|
+
async spotSelection(params) {
|
17931
|
+
return this.selectionService.spotSelection(params);
|
17663
17932
|
}
|
17664
17933
|
/**
|
17665
17934
|
* Injects the spot elements into their provided placement.
|
17666
17935
|
*
|
17667
|
-
* @param {
|
17668
|
-
* @param {IInjectSpotElementConfig} config - The configuration object.
|
17936
|
+
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
17669
17937
|
*
|
17670
17938
|
* @return {Promise<void>} - A promise that resolves when the spot elements are injected.
|
17671
17939
|
*/
|
17672
|
-
async injectSpotElement(
|
17673
|
-
|
17674
|
-
|
17940
|
+
async injectSpotElement(params) {
|
17941
|
+
var _a;
|
17942
|
+
const { inject, config } = params;
|
17943
|
+
if (!inject.length) {
|
17944
|
+
console.warn('RmnSdk: Failed to inject spot element. Please provide at least one spot element to inject.');
|
17675
17945
|
return;
|
17676
17946
|
}
|
17677
|
-
|
17678
|
-
|
17679
|
-
|
17680
|
-
|
17681
|
-
|
17682
|
-
});
|
17683
|
-
});
|
17684
|
-
const response = await this.spotSelection({
|
17685
|
-
spots: spotSelectionRequest,
|
17686
|
-
url: config === null || config === void 0 ? void 0 : config.url,
|
17687
|
-
});
|
17688
|
-
const normalizedData = this.normalizeDataSpotType(data);
|
17689
|
-
for (const item of normalizedData) {
|
17690
|
-
const spots = response[item.spotType];
|
17947
|
+
this.preventDuplicateSpotPlacementIds(inject);
|
17948
|
+
const response = await this.spotSelectionRequest(params);
|
17949
|
+
for (const item of inject) {
|
17950
|
+
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
17951
|
+
const spots = response[item.placementId];
|
17691
17952
|
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
17692
17953
|
console.warn(`RmnSdk: Failed to inject spot element. No spots found for type "${item.spotType}".`);
|
17693
17954
|
continue;
|
@@ -17699,13 +17960,42 @@ class LiquidCommerceRmnClient {
|
|
17699
17960
|
continue;
|
17700
17961
|
}
|
17701
17962
|
if (spots.length === 1) {
|
17702
|
-
this.injectOneSpotElement(item, placement, spots[0],
|
17963
|
+
this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
17703
17964
|
}
|
17704
17965
|
if (spots.length > 1) {
|
17705
|
-
this.injectCarouselSpotElement(placement, spots,
|
17966
|
+
this.injectCarouselSpotElement(placement, spots, itemConfig);
|
17706
17967
|
}
|
17707
17968
|
}
|
17708
17969
|
}
|
17970
|
+
/**
|
17971
|
+
* Returns the event manager instance.
|
17972
|
+
*
|
17973
|
+
* @return {EventService} - The event manager instance.
|
17974
|
+
*/
|
17975
|
+
eventManager() {
|
17976
|
+
return this.eventService;
|
17977
|
+
}
|
17978
|
+
/**
|
17979
|
+
* Makes a selection request on our server based on the provided data.
|
17980
|
+
*
|
17981
|
+
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
17982
|
+
*
|
17983
|
+
* @return {Promise<ISpots>} - The spots response object.
|
17984
|
+
*/
|
17985
|
+
async spotSelectionRequest(params) {
|
17986
|
+
const { inject, filter, config } = params;
|
17987
|
+
const request = {
|
17988
|
+
url: config === null || config === void 0 ? void 0 : config.url,
|
17989
|
+
filter,
|
17990
|
+
spots: inject.map((item) => ({
|
17991
|
+
placementId: item.placementId,
|
17992
|
+
spot: item.spotType,
|
17993
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
17994
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
17995
|
+
})),
|
17996
|
+
};
|
17997
|
+
return this.spotSelection(request);
|
17998
|
+
}
|
17709
17999
|
/**
|
17710
18000
|
* Injects a carousel element with the provided spots into the placement.
|
17711
18001
|
*
|
@@ -17725,6 +18015,11 @@ class LiquidCommerceRmnClient {
|
|
17725
18015
|
console.warn(`RmnSdk: Failed to inject carousel spot element. Could not create element for type "${spot.spot}".`);
|
17726
18016
|
return;
|
17727
18017
|
}
|
18018
|
+
this.eventSpotElement({
|
18019
|
+
spot,
|
18020
|
+
placementId: placement.id,
|
18021
|
+
element: content,
|
18022
|
+
});
|
17728
18023
|
carouselSlides.push(content);
|
17729
18024
|
}
|
17730
18025
|
const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
|
@@ -17776,28 +18071,37 @@ class LiquidCommerceRmnClient {
|
|
17776
18071
|
console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
|
17777
18072
|
return;
|
17778
18073
|
}
|
18074
|
+
this.eventSpotElement({
|
18075
|
+
spot,
|
18076
|
+
placementId: injectItem.placementId,
|
18077
|
+
element: spotElement,
|
18078
|
+
});
|
17779
18079
|
placement.replaceChildren(spotElement);
|
17780
18080
|
}
|
18081
|
+
eventSpotElement({ spot, placementId, element, }) {
|
18082
|
+
this.eventService.registerSpot({
|
18083
|
+
placementId,
|
18084
|
+
element,
|
18085
|
+
spot,
|
18086
|
+
});
|
18087
|
+
}
|
17781
18088
|
/**
|
17782
|
-
*
|
18089
|
+
* Prevents duplicate placement ids in the inject data.
|
18090
|
+
*
|
18091
|
+
* @param {IInjectSpotElement[]} inject - The inject data.
|
17783
18092
|
*
|
17784
|
-
* @
|
18093
|
+
* @throws {Error} - If a duplicate placement id is found.
|
17785
18094
|
*
|
17786
|
-
* @return {
|
18095
|
+
* @return {void}
|
17787
18096
|
*/
|
17788
|
-
|
17789
|
-
const
|
17790
|
-
|
17791
|
-
|
17792
|
-
|
17793
|
-
if (spotTypeCounts[spotType] === 1) {
|
17794
|
-
return spot;
|
18097
|
+
preventDuplicateSpotPlacementIds(inject) {
|
18098
|
+
const placementIds = new Set();
|
18099
|
+
for (const item of inject) {
|
18100
|
+
if (placementIds.has(item.placementId)) {
|
18101
|
+
throw new Error(`RmnSdk: Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`);
|
17795
18102
|
}
|
17796
|
-
|
17797
|
-
|
17798
|
-
spotType: `${spotType}${spotTypeCounts[spotType]}`,
|
17799
|
-
};
|
17800
|
-
});
|
18103
|
+
placementIds.add(item.placementId);
|
18104
|
+
}
|
17801
18105
|
}
|
17802
18106
|
}
|
17803
18107
|
/**
|
package/dist/types/enums.d.ts
CHANGED
@@ -38,6 +38,7 @@ export declare enum RMN_SPOT_TYPE {
|
|
38
38
|
}
|
39
39
|
export declare enum RMN_FILTER_PROPERTIES {
|
40
40
|
KEYWORDS = "keywords",
|
41
|
+
PAGE_LOCATION = "pageLocation",
|
41
42
|
PARENTCO = "parentCo",
|
42
43
|
BRAND = "brand",
|
43
44
|
CATEGORY = "category",
|
@@ -48,6 +49,9 @@ export declare enum RMN_FILTER_PROPERTIES {
|
|
48
49
|
SECTION = "section"
|
49
50
|
}
|
50
51
|
export declare enum RMN_SPOT_EVENT {
|
52
|
+
MOUNTED = "MOUNTED",
|
53
|
+
UNMOUNTED = "UNMOUNTED",
|
54
|
+
RESIZED = "RESIZED",
|
51
55
|
IMPRESSION = "IMPRESSION",
|
52
56
|
CLICK = "CLICK",
|
53
57
|
PURCHASE = "PURCHASE",
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import type { ICreateElementConfig } from 'modules/element';
|
2
|
-
export type
|
2
|
+
export type CarouselNavPositionType = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'middle-left' | 'middle-right' | 'middle-sides';
|
3
3
|
export interface ICarouselDotOptions {
|
4
|
-
position:
|
4
|
+
position: CarouselNavPositionType;
|
5
5
|
color: string;
|
6
6
|
activeColor: string;
|
7
7
|
}
|
8
8
|
export interface ICarouselButtonOptions {
|
9
|
-
position:
|
9
|
+
position: CarouselNavPositionType;
|
10
10
|
together: boolean;
|
11
11
|
textColor: string;
|
12
12
|
backgroundColor: string;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import type { RMN_SPOT_TYPE } from 'enums';
|
2
|
-
import type { ICarouselOptions, ICreateCarouselElementParams } from '
|
3
|
-
import type { ICreateSpotElementParams } from '
|
2
|
+
import type { ICarouselOptions, ICreateCarouselElementParams } from 'modules/element/component/carousel';
|
3
|
+
import type { ICreateSpotElementParams } from 'modules/element/component/spot';
|
4
|
+
import type { RmnFilterType } from 'modules/selection';
|
4
5
|
export interface ISpotColors {
|
5
6
|
textColor?: string;
|
6
7
|
backgroundColor?: string;
|
@@ -11,11 +12,6 @@ export interface ISpotOverlay {
|
|
11
12
|
color: string;
|
12
13
|
colorStop: string;
|
13
14
|
}
|
14
|
-
export interface IInjectSpotElement {
|
15
|
-
placementId: string;
|
16
|
-
spotType: RMN_SPOT_TYPE | string;
|
17
|
-
count?: number;
|
18
|
-
}
|
19
15
|
export interface IInjectSpotElementConfig {
|
20
16
|
url?: string;
|
21
17
|
colors?: ISpotColors;
|
@@ -23,15 +19,27 @@ export interface IInjectSpotElementConfig {
|
|
23
19
|
overlay?: ISpotOverlay[];
|
24
20
|
carousel?: ICarouselOptions;
|
25
21
|
}
|
22
|
+
export interface IInjectSpotElement {
|
23
|
+
placementId: string;
|
24
|
+
spotType: RMN_SPOT_TYPE | string;
|
25
|
+
count?: number;
|
26
|
+
config?: Omit<IInjectSpotElementConfig, 'url'>;
|
27
|
+
filter?: Partial<RmnFilterType>;
|
28
|
+
}
|
26
29
|
export interface ICreateElementConfig {
|
27
30
|
width: number;
|
28
31
|
height: number;
|
29
32
|
fluid?: boolean;
|
30
33
|
minScale: number;
|
31
34
|
}
|
35
|
+
export interface IInjectSpotElementParams {
|
36
|
+
inject: IInjectSpotElement[];
|
37
|
+
config?: IInjectSpotElementConfig;
|
38
|
+
filter?: Partial<RmnFilterType>;
|
39
|
+
}
|
32
40
|
export interface IElementService {
|
33
|
-
createSpotElement(
|
34
|
-
createCarouselElement(
|
41
|
+
createSpotElement(params: ICreateSpotElementParams): HTMLElement | null;
|
42
|
+
createCarouselElement(params: ICreateCarouselElementParams): HTMLElement | null;
|
35
43
|
}
|
36
44
|
export interface IRmnCreateSpotElementConfig {
|
37
45
|
fluid?: boolean;
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import type { ISpot } from 'types';
|
2
2
|
import type { ISpotTemplateConfig } from './template.type';
|
3
3
|
/**
|
4
|
-
*
|
4
|
+
* Returns the HTML element for the given spot.
|
5
5
|
*
|
6
|
-
* @param {ISpot} spot - The spot
|
6
|
+
* @param {ISpot} spot - The spot object.
|
7
|
+
* @param {ISpotTemplateConfig} config - The spot template configuration.
|
7
8
|
*
|
8
|
-
* @return {
|
9
|
+
* @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
|
9
10
|
*/
|
10
11
|
export declare const SPOT_TEMPLATE_HTML_ELEMENT: (spot: ISpot, config?: ISpotTemplateConfig) => HTMLElement | null;
|
@@ -1,5 +1,72 @@
|
|
1
1
|
import type { RMN_SPOT_EVENT } from 'enums';
|
2
|
+
import type { ISpot } from '../selection';
|
2
3
|
export interface IFireEventParams {
|
3
4
|
event: RMN_SPOT_EVENT;
|
4
5
|
eventUrl: string;
|
5
6
|
}
|
7
|
+
export interface IMountedEvent {
|
8
|
+
placementId: string;
|
9
|
+
spotId: string;
|
10
|
+
spotType: string;
|
11
|
+
spotVariant: string;
|
12
|
+
element: HTMLElement;
|
13
|
+
}
|
14
|
+
export interface IUnMountedEvent {
|
15
|
+
placementId: string;
|
16
|
+
spotId: string;
|
17
|
+
}
|
18
|
+
export interface IResizedEvent {
|
19
|
+
placementId: string;
|
20
|
+
spotId: string;
|
21
|
+
scale: number;
|
22
|
+
previousDimensions: {
|
23
|
+
width: number;
|
24
|
+
height: number;
|
25
|
+
};
|
26
|
+
currentDimensions: {
|
27
|
+
width: number;
|
28
|
+
height: number;
|
29
|
+
};
|
30
|
+
}
|
31
|
+
export interface IClickEvent {
|
32
|
+
placementId: string;
|
33
|
+
spotId: string;
|
34
|
+
element: HTMLElement;
|
35
|
+
}
|
36
|
+
export interface IImpressionEvent {
|
37
|
+
placementId: string;
|
38
|
+
spotId: string;
|
39
|
+
element: HTMLElement;
|
40
|
+
}
|
41
|
+
export interface IAddToCartEvent {
|
42
|
+
placementId: string;
|
43
|
+
spotId: string;
|
44
|
+
}
|
45
|
+
export interface IAddToWishlistEvent {
|
46
|
+
placementId: string;
|
47
|
+
spotId: string;
|
48
|
+
}
|
49
|
+
export interface IPurchaseEvent {
|
50
|
+
placementId: string;
|
51
|
+
spotId: string;
|
52
|
+
}
|
53
|
+
export interface IBuyNowEvent {
|
54
|
+
placementId: string;
|
55
|
+
spotId: string;
|
56
|
+
}
|
57
|
+
export interface IEventMap {
|
58
|
+
[RMN_SPOT_EVENT.MOUNTED]: IMountedEvent;
|
59
|
+
[RMN_SPOT_EVENT.UNMOUNTED]: IUnMountedEvent;
|
60
|
+
[RMN_SPOT_EVENT.RESIZED]: IResizedEvent;
|
61
|
+
[RMN_SPOT_EVENT.CLICK]: IClickEvent;
|
62
|
+
[RMN_SPOT_EVENT.IMPRESSION]: IImpressionEvent;
|
63
|
+
[RMN_SPOT_EVENT.ADD_TO_CART]: IAddToCartEvent;
|
64
|
+
[RMN_SPOT_EVENT.ADD_TO_WISHLIST]: IAddToWishlistEvent;
|
65
|
+
[RMN_SPOT_EVENT.PURCHASE]: IPurchaseEvent;
|
66
|
+
[RMN_SPOT_EVENT.BUY_NOW]: IBuyNowEvent;
|
67
|
+
}
|
68
|
+
export interface IRegisterSpotParams {
|
69
|
+
placementId: string;
|
70
|
+
element: HTMLElement;
|
71
|
+
spot: ISpot;
|
72
|
+
}
|