@liquidcommercedev/rmn-sdk 1.4.6-beta.4 → 1.4.6-beta.5
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 +301 -8
- package/dist/index.esm.js +301 -8
- package/dist/types/enums.d.ts +3 -0
- package/dist/types/modules/element/component/carousel/carousel.interface.d.ts +3 -3
- 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 +1 -0
- package/dist/types/rmn-client.d.ts +9 -0
- package/dist/types/types.d.ts +4 -1
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.cjs
CHANGED
@@ -56,6 +56,9 @@ exports.RMN_FILTER_PROPERTIES = void 0;
|
|
56
56
|
})(exports.RMN_FILTER_PROPERTIES || (exports.RMN_FILTER_PROPERTIES = {}));
|
57
57
|
exports.RMN_SPOT_EVENT = void 0;
|
58
58
|
(function (RMN_SPOT_EVENT) {
|
59
|
+
RMN_SPOT_EVENT["MOUNTED"] = "MOUNTED";
|
60
|
+
RMN_SPOT_EVENT["UNMOUNTED"] = "UNMOUNTED";
|
61
|
+
RMN_SPOT_EVENT["RESIZED"] = "RESIZED";
|
59
62
|
RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
|
60
63
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
61
64
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
@@ -15164,6 +15167,46 @@ const GFONT_CORMORANT = `
|
|
15164
15167
|
<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">
|
15165
15168
|
`;
|
15166
15169
|
|
15170
|
+
class IntersectionObserverService {
|
15171
|
+
constructor(defaultOptions = {}) {
|
15172
|
+
this.observers = new Map();
|
15173
|
+
this.defaultOptions = {
|
15174
|
+
root: null,
|
15175
|
+
rootMargin: '0px',
|
15176
|
+
threshold: 0.5,
|
15177
|
+
...defaultOptions,
|
15178
|
+
};
|
15179
|
+
}
|
15180
|
+
observe(element, callback, options = {}) {
|
15181
|
+
const mergedOptions = { ...this.defaultOptions, ...options };
|
15182
|
+
const ioCallback = (entries) => {
|
15183
|
+
entries.forEach((entry) => {
|
15184
|
+
if (entry.isIntersecting) {
|
15185
|
+
callback(entry);
|
15186
|
+
}
|
15187
|
+
});
|
15188
|
+
};
|
15189
|
+
const observer = new IntersectionObserver(ioCallback, mergedOptions);
|
15190
|
+
this.observers.set(element, observer);
|
15191
|
+
observer.observe(element);
|
15192
|
+
}
|
15193
|
+
unobserve(element) {
|
15194
|
+
const observer = this.observers.get(element);
|
15195
|
+
if (observer) {
|
15196
|
+
observer.unobserve(element);
|
15197
|
+
observer.disconnect();
|
15198
|
+
this.observers.delete(element);
|
15199
|
+
}
|
15200
|
+
}
|
15201
|
+
unobserveAll() {
|
15202
|
+
this.observers.forEach((observer, element) => {
|
15203
|
+
observer.unobserve(element);
|
15204
|
+
observer.disconnect();
|
15205
|
+
});
|
15206
|
+
this.observers.clear();
|
15207
|
+
}
|
15208
|
+
}
|
15209
|
+
|
15167
15210
|
class ResizeObserverService {
|
15168
15211
|
constructor({ element, maxSize, minScale }) {
|
15169
15212
|
this.element = element;
|
@@ -15469,8 +15512,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15469
15512
|
this.addEventListener('spotSizeChanged', this.handleCarouselSizeChanged.bind(this));
|
15470
15513
|
}
|
15471
15514
|
}
|
15472
|
-
|
15473
|
-
|
15515
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
15516
|
+
handleCarouselSizeChanged(_event) {
|
15517
|
+
// console.info('Carousel Size Changed', event);
|
15474
15518
|
}
|
15475
15519
|
render() {
|
15476
15520
|
var _a;
|
@@ -15696,7 +15740,7 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15696
15740
|
* #########################################################
|
15697
15741
|
*/
|
15698
15742
|
handleSpotSizeChanged(event) {
|
15699
|
-
console.info('Spot Size Changed', event);
|
15743
|
+
// console.info('Spot Size Changed', event);
|
15700
15744
|
// Adjust text elements font size based on the scale factor
|
15701
15745
|
this.adjustFontSize(event.detail.scale);
|
15702
15746
|
}
|
@@ -15708,8 +15752,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15708
15752
|
elements === null || elements === void 0 ? void 0 : elements.forEach((element) => {
|
15709
15753
|
if (element instanceof HTMLElement) {
|
15710
15754
|
if (!this.originalFontSizes.has(element)) {
|
15711
|
-
const
|
15712
|
-
this.originalFontSizes.set(element,
|
15755
|
+
const originalSize = parseFloat(window.getComputedStyle(element).fontSize);
|
15756
|
+
this.originalFontSizes.set(element, originalSize);
|
15713
15757
|
}
|
15714
15758
|
const originalSize = this.originalFontSizes.get(element);
|
15715
15759
|
const newFontSize = originalSize * scaleFactor;
|
@@ -17540,11 +17584,12 @@ function rbSmallDiscoverToutTemplate(spot, config) {
|
|
17540
17584
|
}
|
17541
17585
|
|
17542
17586
|
/**
|
17543
|
-
*
|
17587
|
+
* Returns the HTML element for the given spot.
|
17544
17588
|
*
|
17545
|
-
* @param {ISpot} spot - The spot
|
17589
|
+
* @param {ISpot} spot - The spot object.
|
17590
|
+
* @param {ISpotTemplateConfig} config - The spot template configuration.
|
17546
17591
|
*
|
17547
|
-
* @return {
|
17592
|
+
* @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
|
17548
17593
|
*/
|
17549
17594
|
const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
17550
17595
|
const templates = {
|
@@ -17617,6 +17662,228 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
17617
17662
|
return spotHtmlStringToElement(spotHtmlString);
|
17618
17663
|
};
|
17619
17664
|
|
17665
|
+
/**
|
17666
|
+
* PubSub class
|
17667
|
+
* Manages event subscriptions and publications
|
17668
|
+
* @template IEventMap A record type defining the structure of events and their data
|
17669
|
+
*/
|
17670
|
+
class PubSub {
|
17671
|
+
constructor() {
|
17672
|
+
/**
|
17673
|
+
* Object to store subscribers for each event type
|
17674
|
+
*/
|
17675
|
+
this.subscribers = {};
|
17676
|
+
}
|
17677
|
+
/**
|
17678
|
+
* Subscribe to an event
|
17679
|
+
* @param eventType - The type of event to subscribe to
|
17680
|
+
* @param callback - The function to be called when the event is published
|
17681
|
+
* @returns A function to unsubscribe from the event
|
17682
|
+
*
|
17683
|
+
* @Example:
|
17684
|
+
* const unsubscribe = pubSub.subscribe('userLogin', (data) => {
|
17685
|
+
* console.log(`User ${data.username} logged in`);
|
17686
|
+
* });
|
17687
|
+
*/
|
17688
|
+
subscribe(eventType, callback) {
|
17689
|
+
if (!this.subscribers[eventType]) {
|
17690
|
+
this.subscribers[eventType] = [];
|
17691
|
+
}
|
17692
|
+
this.subscribers[eventType].push(callback);
|
17693
|
+
// Return an unsubscribe function
|
17694
|
+
return () => {
|
17695
|
+
this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
|
17696
|
+
};
|
17697
|
+
}
|
17698
|
+
/**
|
17699
|
+
* Publish an event
|
17700
|
+
* @param eventType - The type of event to publish
|
17701
|
+
* @param data - The data to be passed to the event subscribers
|
17702
|
+
*
|
17703
|
+
* @Example:
|
17704
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
17705
|
+
*/
|
17706
|
+
publish(eventType, data) {
|
17707
|
+
if (!this.subscribers[eventType]) {
|
17708
|
+
return;
|
17709
|
+
}
|
17710
|
+
this.subscribers[eventType].forEach((callback) => callback(data));
|
17711
|
+
}
|
17712
|
+
}
|
17713
|
+
/**
|
17714
|
+
* Usage Example:
|
17715
|
+
*
|
17716
|
+
* interface IEventMap {
|
17717
|
+
* userLogin: { username: string; timestamp: number };
|
17718
|
+
* pageView: { url: string; timestamp: number };
|
17719
|
+
* }
|
17720
|
+
*
|
17721
|
+
* const pubSub = new PubSub<IEventMap>();
|
17722
|
+
*
|
17723
|
+
* // Subscribe to events
|
17724
|
+
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
17725
|
+
* console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
|
17726
|
+
* });
|
17727
|
+
*
|
17728
|
+
* pubSub.subscribe('pageView', (data) => {
|
17729
|
+
* console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
|
17730
|
+
* });
|
17731
|
+
*
|
17732
|
+
* // Publish events
|
17733
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
17734
|
+
* pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
|
17735
|
+
*
|
17736
|
+
* // Unsubscribe from an event
|
17737
|
+
* unsubscribeLogin();
|
17738
|
+
*/
|
17739
|
+
|
17740
|
+
class EventService {
|
17741
|
+
constructor() {
|
17742
|
+
this.pubSub = new PubSub();
|
17743
|
+
this.activeSpots = new Map();
|
17744
|
+
this.intersectionObserver = new IntersectionObserverService();
|
17745
|
+
}
|
17746
|
+
static getInstance() {
|
17747
|
+
if (!EventService.instance) {
|
17748
|
+
EventService.instance = new EventService();
|
17749
|
+
}
|
17750
|
+
return EventService.instance;
|
17751
|
+
}
|
17752
|
+
registerSpot({ placementId, element, spot }) {
|
17753
|
+
this.activeSpots.set(spot.id, {
|
17754
|
+
placementId,
|
17755
|
+
element,
|
17756
|
+
impressionTracked: false,
|
17757
|
+
});
|
17758
|
+
// Handle resize observer
|
17759
|
+
// this.handleResizeObserver(placementId, spot, element);
|
17760
|
+
// Handle intersection observer
|
17761
|
+
this.handleIntersectionObserver(placementId, spot, element);
|
17762
|
+
// Attach click event listener
|
17763
|
+
element.addEventListener('click', async () => {
|
17764
|
+
var _a, _b;
|
17765
|
+
this.pubSub.publish(exports.RMN_SPOT_EVENT.CLICK, {
|
17766
|
+
placementId,
|
17767
|
+
spotId: spot.id,
|
17768
|
+
element,
|
17769
|
+
});
|
17770
|
+
// Fire click event
|
17771
|
+
await this.fireEvent({
|
17772
|
+
event: exports.RMN_SPOT_EVENT.CLICK,
|
17773
|
+
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 : '',
|
17774
|
+
});
|
17775
|
+
});
|
17776
|
+
// Publish spot created event
|
17777
|
+
this.pubSub.publish(exports.RMN_SPOT_EVENT.MOUNTED, {
|
17778
|
+
placementId,
|
17779
|
+
spotId: spot.id,
|
17780
|
+
spotType: spot.spot,
|
17781
|
+
spotVariant: spot.variant,
|
17782
|
+
element,
|
17783
|
+
});
|
17784
|
+
}
|
17785
|
+
unregisterSpot(spotId) {
|
17786
|
+
const spotData = this.activeSpots.get(spotId);
|
17787
|
+
if (spotData) {
|
17788
|
+
this.intersectionObserver.unobserve(spotData.element);
|
17789
|
+
// this.resizeObserver?.disconnect();
|
17790
|
+
this.pubSub.publish(exports.RMN_SPOT_EVENT.UNMOUNTED, {
|
17791
|
+
placementId: spotData.placementId,
|
17792
|
+
spotId,
|
17793
|
+
});
|
17794
|
+
this.activeSpots.delete(spotId);
|
17795
|
+
}
|
17796
|
+
}
|
17797
|
+
// private handleResizeObserver(placementId: string, spot: ISpot, element: HTMLElement): void {
|
17798
|
+
// // this.resizeObserver = new ResizeObserverService({
|
17799
|
+
// // element,
|
17800
|
+
// // maxSize: {
|
17801
|
+
// // width: spot.width,
|
17802
|
+
// // height: spot.height,
|
17803
|
+
// // },
|
17804
|
+
// // minScale: 0.25,
|
17805
|
+
// // });
|
17806
|
+
//
|
17807
|
+
// const sizeChangedCb = (event: ISizeChangedEvent) => {
|
17808
|
+
// // Publish spot resized event
|
17809
|
+
// this.pubSub.publish(RMN_SPOT_EVENT.RESIZED, {
|
17810
|
+
// placementId,
|
17811
|
+
// spotId: spot.id,
|
17812
|
+
// scale: event.detail.scale,
|
17813
|
+
// previousDimensions: {
|
17814
|
+
// width: event.detail.width,
|
17815
|
+
// height: event.detail.height,
|
17816
|
+
// },
|
17817
|
+
// currentDimensions: {
|
17818
|
+
// width: event.detail.newWidth,
|
17819
|
+
// height: event.detail.newHeight,
|
17820
|
+
// },
|
17821
|
+
// });
|
17822
|
+
// };
|
17823
|
+
//
|
17824
|
+
// element.addEventListener('spotSizeChanged', sizeChangedCb as EventListener);
|
17825
|
+
// }
|
17826
|
+
handleIntersectionObserver(placementId, spot, element) {
|
17827
|
+
const spotIsVisibleCb = async () => {
|
17828
|
+
var _a, _b;
|
17829
|
+
this.pubSub.publish(exports.RMN_SPOT_EVENT.IMPRESSION, {
|
17830
|
+
placementId,
|
17831
|
+
spotId: spot.id,
|
17832
|
+
element,
|
17833
|
+
});
|
17834
|
+
this.intersectionObserver.unobserve(element);
|
17835
|
+
this.activeSpots.set(spot.id, {
|
17836
|
+
placementId,
|
17837
|
+
element,
|
17838
|
+
impressionTracked: true,
|
17839
|
+
});
|
17840
|
+
// Fire impression event
|
17841
|
+
await this.fireEvent({
|
17842
|
+
event: exports.RMN_SPOT_EVENT.IMPRESSION,
|
17843
|
+
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 : '',
|
17844
|
+
});
|
17845
|
+
};
|
17846
|
+
this.intersectionObserver.observe(element, spotIsVisibleCb);
|
17847
|
+
}
|
17848
|
+
subscribe(eventType, callback) {
|
17849
|
+
return this.pubSub.subscribe(eventType, callback);
|
17850
|
+
}
|
17851
|
+
publish(eventType, data) {
|
17852
|
+
this.pubSub.publish(eventType, data);
|
17853
|
+
}
|
17854
|
+
/**
|
17855
|
+
* Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
|
17856
|
+
*
|
17857
|
+
* @param {IFireEventParams} params - The parameters for firing the event.
|
17858
|
+
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
17859
|
+
* @param {string} params.eventUrl - The URL to which the event is sent.
|
17860
|
+
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
17861
|
+
*/
|
17862
|
+
async fireEvent({ event, eventUrl }) {
|
17863
|
+
const didFireEvent = navigator.sendBeacon(eventUrl);
|
17864
|
+
if (didFireEvent && event === exports.RMN_SPOT_EVENT.CLICK) {
|
17865
|
+
window.location.href = this.getRedirectUrlFromPayload(eventUrl);
|
17866
|
+
}
|
17867
|
+
}
|
17868
|
+
/**
|
17869
|
+
* Extracts and decodes a URL from a base64-encoded query parameter.
|
17870
|
+
*
|
17871
|
+
* @param {string} url - The URL containing the base64-encoded query parameter.
|
17872
|
+
* @returns {string} - The decoded URL or an empty string if decoding fails.
|
17873
|
+
*/
|
17874
|
+
getRedirectUrlFromPayload(url) {
|
17875
|
+
var _a, _b;
|
17876
|
+
const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
|
17877
|
+
try {
|
17878
|
+
const data = JSON.parse(atob(base64String));
|
17879
|
+
return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
|
17880
|
+
}
|
17881
|
+
catch (_c) {
|
17882
|
+
return '';
|
17883
|
+
}
|
17884
|
+
}
|
17885
|
+
}
|
17886
|
+
|
17620
17887
|
const SELECTION_API_PATH = '/spots/selection';
|
17621
17888
|
|
17622
17889
|
class SelectionService extends BaseApi {
|
@@ -17651,6 +17918,7 @@ class LiquidCommerceRmnClient {
|
|
17651
17918
|
constructor(auth) {
|
17652
17919
|
this.selectionService = SelectionService.getInstance(auth);
|
17653
17920
|
this.elementService = ElementService.getInstance();
|
17921
|
+
this.eventService = EventService.getInstance();
|
17654
17922
|
}
|
17655
17923
|
/**
|
17656
17924
|
* Makes a selection request on our server based on the provided data.
|
@@ -17701,6 +17969,14 @@ class LiquidCommerceRmnClient {
|
|
17701
17969
|
}
|
17702
17970
|
}
|
17703
17971
|
}
|
17972
|
+
/**
|
17973
|
+
* Returns the event manager instance.
|
17974
|
+
*
|
17975
|
+
* @return {EventService} - The event manager instance.
|
17976
|
+
*/
|
17977
|
+
eventManager() {
|
17978
|
+
return this.eventService;
|
17979
|
+
}
|
17704
17980
|
/**
|
17705
17981
|
* Makes a selection request on our server based on the provided data.
|
17706
17982
|
*
|
@@ -17741,6 +18017,11 @@ class LiquidCommerceRmnClient {
|
|
17741
18017
|
console.warn(`RmnSdk: Failed to inject carousel spot element. Could not create element for type "${spot.spot}".`);
|
17742
18018
|
return;
|
17743
18019
|
}
|
18020
|
+
this.eventSpotElement({
|
18021
|
+
spot,
|
18022
|
+
placementId: placement.id,
|
18023
|
+
element: content,
|
18024
|
+
});
|
17744
18025
|
carouselSlides.push(content);
|
17745
18026
|
}
|
17746
18027
|
const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
|
@@ -17792,8 +18073,20 @@ class LiquidCommerceRmnClient {
|
|
17792
18073
|
console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
|
17793
18074
|
return;
|
17794
18075
|
}
|
18076
|
+
this.eventSpotElement({
|
18077
|
+
spot,
|
18078
|
+
placementId: injectItem.placementId,
|
18079
|
+
element: spotElement,
|
18080
|
+
});
|
17795
18081
|
placement.replaceChildren(spotElement);
|
17796
18082
|
}
|
18083
|
+
eventSpotElement({ spot, placementId, element, }) {
|
18084
|
+
this.eventService.registerSpot({
|
18085
|
+
placementId,
|
18086
|
+
element,
|
18087
|
+
spot,
|
18088
|
+
});
|
18089
|
+
}
|
17797
18090
|
/**
|
17798
18091
|
* Prevents duplicate placement ids in the inject data.
|
17799
18092
|
*
|