@streamscloud/embeddable 6.5.1 → 6.5.2

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.
@@ -2,10 +2,36 @@
2
2
  import { Button, ButtonSize } from '../../ui/button';
3
3
  import { Image } from '../../ui/image';
4
4
  import { LineClamp } from '../../ui/line-clamp';
5
- let { ad, inert = false } = $props();
5
+ import { onMount } from 'svelte';
6
+ let { ad, inert = false, on } = $props();
7
+ let adElement;
8
+ onMount(() => {
9
+ if (adElement && (on === null || on === void 0 ? void 0 : on.impression)) {
10
+ const observer = new IntersectionObserver((entries) => {
11
+ entries.forEach((entry) => {
12
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
13
+ on.impression(ad.id);
14
+ observer.unobserve(entry.target);
15
+ }
16
+ });
17
+ }, { threshold: 0.5 });
18
+ observer.observe(adElement);
19
+ return () => {
20
+ observer.disconnect();
21
+ };
22
+ }
23
+ });
24
+ const handleAdClick = () => {
25
+ if (on === null || on === void 0 ? void 0 : on.adClick) {
26
+ on.adClick(ad.id);
27
+ }
28
+ if (ad.ctaButton) {
29
+ window.open(ad.ctaButton.url, '_blank');
30
+ }
31
+ };
6
32
  </script>
7
33
 
8
- <div class="ad-card" inert={inert}>
34
+ <div class="ad-card" inert={inert} bind:this={adElement}>
9
35
  <div class="ad-card__image">
10
36
  <Image src={ad.image} alt={ad.title} />
11
37
  </div>
@@ -37,7 +63,7 @@ let { ad, inert = false } = $props();
37
63
  <div class="ad-card__button">
38
64
  <Button
39
65
  size={ButtonSize.Standard}
40
- on={{ click: () => ad.ctaButton && window.open(ad.ctaButton.url, '_blank') }}
66
+ on={{ click: handleAdClick }}
41
67
  --button--font--size="1em"
42
68
  --button--font--color={ad.ctaButton.textColor}
43
69
  --button--background={ad.ctaButton.background}
@@ -2,6 +2,10 @@ import type { AdCardModel } from './types';
2
2
  type Props = {
3
3
  ad: AdCardModel;
4
4
  inert?: boolean;
5
+ on?: {
6
+ adClick?: (adId: string) => void;
7
+ impression?: (adId: string) => void;
8
+ };
5
9
  };
6
10
  declare const Cmp: import("svelte").Component<Props, {}, "">;
7
11
  type Cmp = ReturnType<typeof Cmp>;
@@ -13,6 +13,7 @@ const attachmentsToShow = $derived.by(() => {
13
13
  image: p.image,
14
14
  link: p.link,
15
15
  productId: p.id,
16
+ adId: null,
16
17
  price: {
17
18
  amount: p.salePrice || p.price,
18
19
  currency: p.currency
@@ -29,6 +30,7 @@ const attachmentsToShow = $derived.by(() => {
29
30
  image: a.image,
30
31
  link: ((_a = a.ctaButton) === null || _a === void 0 ? void 0 : _a.url) || null,
31
32
  productId: null,
33
+ adId: a.id,
32
34
  price: a.price && a.currency
33
35
  ? {
34
36
  amount: a.price,
@@ -47,6 +49,9 @@ const handleAttachmentClick = (attachment) => {
47
49
  if (attachment.productId && (on === null || on === void 0 ? void 0 : on.productClick)) {
48
50
  on.productClick(attachment.productId);
49
51
  }
52
+ if (attachment.adId && (on === null || on === void 0 ? void 0 : on.adClick)) {
53
+ on.adClick(attachment.adId);
54
+ }
50
55
  if (attachment.link) {
51
56
  window.open(attachment.link, '_blank');
52
57
  }
@@ -54,7 +59,7 @@ const handleAttachmentClick = (attachment) => {
54
59
  let attachmentElements = $state({});
55
60
  let observer = null;
56
61
  $effect(() => {
57
- if ((on === null || on === void 0 ? void 0 : on.productImpression) && Object.keys(attachmentElements).length > 0) {
62
+ if (((on === null || on === void 0 ? void 0 : on.productImpression) || (on === null || on === void 0 ? void 0 : on.adImpression)) && Object.keys(attachmentElements).length > 0) {
58
63
  if (observer) {
59
64
  observer.disconnect();
60
65
  }
@@ -62,15 +67,19 @@ $effect(() => {
62
67
  entries.forEach((entry) => {
63
68
  if (entry.isIntersecting && entry.intersectionRatio >= 0.1) {
64
69
  const productId = entry.target.getAttribute('data-product-id');
65
- if (productId) {
70
+ const adId = entry.target.getAttribute('data-ad-id');
71
+ if (productId && (on === null || on === void 0 ? void 0 : on.productImpression)) {
66
72
  on.productImpression(productId, model.id);
67
- observer === null || observer === void 0 ? void 0 : observer.unobserve(entry.target); // Only track once per session
68
73
  }
74
+ else if (adId && (on === null || on === void 0 ? void 0 : on.adImpression)) {
75
+ on.adImpression(adId);
76
+ }
77
+ observer === null || observer === void 0 ? void 0 : observer.unobserve(entry.target); // Only track once per session
69
78
  }
70
79
  });
71
80
  }, { threshold: 0.1 });
72
81
  Object.entries(attachmentElements).forEach(([key, element]) => {
73
- if (element && key.startsWith('product-')) {
82
+ if (element && (key.startsWith('product-') || key.startsWith('ad-'))) {
74
83
  observer === null || observer === void 0 ? void 0 : observer.observe(element);
75
84
  }
76
85
  });
@@ -93,8 +102,9 @@ $effect(() => {
93
102
  onclick={() => handleAttachmentClick(attachment)}
94
103
  onkeydown={() => {}}
95
104
  role="none"
96
- bind:this={attachmentElements[attachment.productId ? `product-${attachment.productId}` : `ad-${index}`]}
97
- data-product-id={attachment.productId || undefined}>
105
+ bind:this={attachmentElements[attachment.productId ? `product-${attachment.productId}` : `ad-${attachment.adId}`]}
106
+ data-product-id={attachment.productId || undefined}
107
+ data-ad-id={attachment.adId || undefined}>
98
108
  <div class="attachments-card" class:attachments-card--single={attachmentsToShow.length === 1}>
99
109
  <div class="attachments-card__thumb">
100
110
  <ImageRounded src={attachment.image} alt="" noBorders={true} />
@@ -4,6 +4,8 @@ type Props = {
4
4
  on?: {
5
5
  productClick?: (productId: string) => void;
6
6
  productImpression?: (productId: string, videoId: string) => void;
7
+ adClick?: (adId: string) => void;
8
+ adImpression?: (adId: string) => void;
7
9
  };
8
10
  };
9
11
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -9,7 +9,12 @@ const localization = $derived(new ShortVideoAttachmentsLocalization(localization
9
9
  {#if shortVideo.hasAttachments}
10
10
  <div class="short-video-attachments">
11
11
  {#if shortVideo.ad}
12
- <AdCard ad={shortVideo.ad} />
12
+ <AdCard
13
+ ad={shortVideo.ad}
14
+ on={{
15
+ adClick: on?.adClick,
16
+ impression: on?.adImpression
17
+ }} />
13
18
  {/if}
14
19
 
15
20
  {#if shortVideo.products.length}
@@ -7,6 +7,8 @@ type Props = {
7
7
  on?: {
8
8
  productClick?: (productId: string) => void;
9
9
  productImpression?: (productId: string, videoId: string) => void;
10
+ adClick?: (adId: string) => void;
11
+ adImpression?: (adId: string) => void;
10
12
  };
11
13
  };
12
14
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -60,7 +60,9 @@ const trackControlsPanelSize = (node) => {
60
60
  model={model}
61
61
  on={{
62
62
  productClick: on?.productClick,
63
- productImpression: on?.productImpression
63
+ productImpression: on?.productImpression,
64
+ adClick: on?.adClick,
65
+ adImpression: on?.adImpression
64
66
  }} />
65
67
  </div>
66
68
  {/if}
@@ -12,6 +12,8 @@ type Props = {
12
12
  progress?: (progress: number) => void;
13
13
  productClick?: (productId: string) => void;
14
14
  productImpression?: (productId: string, videoId: string) => void;
15
+ adClick?: (adId: string) => void;
16
+ adImpression?: (adId: string) => void;
15
17
  };
16
18
  };
17
19
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -74,7 +74,9 @@ const trackNavigationButtonsSize = (node) => {
74
74
  localization={localization.shortVideoAttachmentsLocalization}
75
75
  on={{
76
76
  productClick: on.productClick,
77
- productImpression: on.productImpression
77
+ productImpression: on.productImpression,
78
+ adClick: on.adClick,
79
+ adImpression: on.adImpression
78
80
  }} />
79
81
  </div>
80
82
  {/if}
@@ -13,6 +13,8 @@ type Props = {
13
13
  closePlayer?: () => void;
14
14
  productClick?: (productId: string) => void;
15
15
  productImpression?: (productId: string, videoId: string) => void;
16
+ adClick?: (adId: string) => void;
17
+ adImpression?: (adId: string) => void;
16
18
  };
17
19
  };
18
20
  declare const Controls: import("svelte").Component<Props, {}, "">;
@@ -5,4 +5,6 @@ export declare class InternalShortVideoAnalyticsHandler implements IShortVideoAn
5
5
  trackShortVideoView: (videoId: string) => void;
6
6
  trackShortVideoProductImpression: (productId: string, videoId: string) => void;
7
7
  trackShortVideoProductClick: (productId: string, videoId: string) => void;
8
+ trackAdImpression: (adId: string) => void;
9
+ trackAdClick: (adId: string) => void;
8
10
  }
@@ -10,4 +10,6 @@ export class InternalShortVideoAnalyticsHandler {
10
10
  trackShortVideoView = (videoId) => AppEventsTracker.trackShortVideoView(videoId);
11
11
  trackShortVideoProductImpression = (productId, videoId) => AppEventsTracker.trackShortVideoProductImpression(productId, videoId);
12
12
  trackShortVideoProductClick = (productId, videoId) => AppEventsTracker.trackShortVideoProductClick(productId, videoId);
13
+ trackAdImpression = (adId) => AppEventsTracker.trackAdImpression(adId);
14
+ trackAdClick = (adId) => AppEventsTracker.trackAdClick(adId);
13
15
  }
@@ -97,6 +97,12 @@ const onShortVideoProductClick = (productId, videoId) => {
97
97
  const onShortVideoProductImpression = (productId, videoId) => {
98
98
  analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackShortVideoProductImpression(productId, videoId);
99
99
  };
100
+ const onShortVideoAdClick = (adId) => {
101
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackAdClick(adId);
102
+ };
103
+ const onShortVideoAdImpression = (adId) => {
104
+ analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.trackAdImpression(adId);
105
+ };
100
106
  </script>
101
107
 
102
108
  <svelte:document onkeydown={(e) => handleEsc(e, onPlayerClose)} />
@@ -140,7 +146,9 @@ const onShortVideoProductImpression = (productId, videoId) => {
140
146
  localization={localization.shortVideoViewerLocalization}
141
147
  on={{
142
148
  productClick: (productId) => onShortVideoProductClick(productId, item.id),
143
- productImpression: (productId, videoId) => onShortVideoProductImpression(productId, videoId)
149
+ productImpression: (productId, videoId) => onShortVideoProductImpression(productId, videoId),
150
+ adClick: onShortVideoAdClick,
151
+ adImpression: onShortVideoAdImpression
144
152
  }} />
145
153
  {/snippet}
146
154
  </PlayerSlider>
@@ -158,7 +166,9 @@ const onShortVideoProductImpression = (productId, videoId) => {
158
166
  on={{
159
167
  closePlayer: on?.playerClosed,
160
168
  productClick: (productId) => onShortVideoProductClick(productId, buffer?.current?.id || ''),
161
- productImpression: onShortVideoProductImpression
169
+ productImpression: onShortVideoProductImpression,
170
+ adClick: onShortVideoAdClick,
171
+ adImpression: onShortVideoAdImpression
162
172
  }} />
163
173
  {:else}
164
174
  <Loading positionFixedCenter={true} timeout={1000} />
@@ -7,6 +7,8 @@ export interface IShortVideoAnalyticsHandler {
7
7
  trackShortVideoView: (videoId: string) => void;
8
8
  trackShortVideoProductImpression: (productId: string, videoId: string) => void;
9
9
  trackShortVideoProductClick: (productId: string, videoId: string) => void;
10
+ trackAdImpression: (adId: string) => void;
11
+ trackAdClick: (adId: string) => void;
10
12
  }
11
13
  export type ShortVideoPlayerModel = ShortVideoViewerModel & {
12
14
  analyticsOrganizationId: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/embeddable",
3
- "version": "6.5.1",
3
+ "version": "6.5.2",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",