@streamscloud/embeddable 16.0.7 → 16.1.0

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.
Files changed (160) hide show
  1. package/dist/ads/ad-card/types.d.ts +1 -1
  2. package/dist/ads/ad-card/types.js +1 -1
  3. package/dist/articles/article/article-layout.svelte +32 -0
  4. package/dist/articles/article/article-layout.svelte.d.ts +9 -0
  5. package/dist/articles/article/article-proxy.svelte +8 -0
  6. package/dist/articles/article/article-proxy.svelte.d.ts +12 -0
  7. package/dist/articles/article/article-section.svelte +52 -0
  8. package/dist/articles/article/article-section.svelte.d.ts +9 -0
  9. package/dist/articles/article/article-view.svelte +38 -0
  10. package/dist/articles/article/article-view.svelte.d.ts +8 -0
  11. package/dist/articles/article/cmp.article.svelte +36 -0
  12. package/dist/articles/article/cmp.article.svelte.d.ts +12 -0
  13. package/dist/articles/article/cmp.facts-container.svelte +27 -0
  14. package/dist/articles/article/cmp.facts-container.svelte.d.ts +7 -0
  15. package/dist/articles/article/fields/alt-text.svelte +15 -0
  16. package/dist/articles/article/fields/alt-text.svelte.d.ts +6 -0
  17. package/dist/articles/article/fields/article-field.svelte +45 -0
  18. package/dist/articles/article/fields/article-field.svelte.d.ts +8 -0
  19. package/dist/articles/article/fields/byline-field.svelte +23 -0
  20. package/dist/articles/article/fields/byline-field.svelte.d.ts +8 -0
  21. package/dist/articles/article/fields/image-field.svelte +8 -0
  22. package/dist/articles/article/fields/image-field.svelte.d.ts +7 -0
  23. package/dist/articles/article/fields/media-field.svelte +8 -0
  24. package/dist/articles/article/fields/media-field.svelte.d.ts +7 -0
  25. package/dist/articles/article/fields/media-gallery-field.svelte +8 -0
  26. package/dist/articles/article/fields/media-gallery-field.svelte.d.ts +7 -0
  27. package/dist/articles/article/fields/rich-text-field.svelte +19 -0
  28. package/dist/articles/article/fields/rich-text-field.svelte.d.ts +7 -0
  29. package/dist/articles/article/fields/text-field.svelte +24 -0
  30. package/dist/articles/article/fields/text-field.svelte.d.ts +7 -0
  31. package/dist/articles/article/fields/types.d.ts +72 -0
  32. package/dist/articles/article/fields/types.js +1 -0
  33. package/dist/articles/article/fields/video-field.svelte +8 -0
  34. package/dist/articles/article/fields/video-field.svelte.d.ts +7 -0
  35. package/dist/articles/article/helpers.d.ts +5 -0
  36. package/dist/articles/article/helpers.js +27 -0
  37. package/dist/articles/article/index.d.ts +8 -0
  38. package/dist/articles/article/index.js +5 -0
  39. package/dist/articles/article/styles-transformer.d.ts +47 -0
  40. package/dist/articles/article/styles-transformer.js +38 -0
  41. package/dist/articles/article/types.d.ts +32 -0
  42. package/dist/articles/article/types.js +1 -0
  43. package/dist/articles/article-dialog/article-dialog-localization.d.ts +3 -0
  44. package/dist/articles/article-dialog/article-dialog-localization.js +9 -0
  45. package/dist/articles/article-dialog/cmp.article-dialog.svelte +103 -0
  46. package/dist/articles/article-dialog/cmp.article-dialog.svelte.d.ts +9 -0
  47. package/dist/articles/article-dialog/index.d.ts +6 -0
  48. package/dist/articles/article-dialog/index.js +10 -0
  49. package/dist/articles/article-dialog/types.d.ts +6 -0
  50. package/dist/articles/data-providers/index.d.ts +1 -0
  51. package/dist/articles/data-providers/index.js +1 -0
  52. package/dist/articles/data-providers/types.d.ts +14 -0
  53. package/dist/articles/data-providers/types.js +1 -0
  54. package/dist/core/enums.d.ts +15 -50
  55. package/dist/core/enums.js +1 -61
  56. package/dist/core/graphql.d.ts +4 -1
  57. package/dist/core/graphql.js +3 -3
  58. package/dist/core/media/index.d.ts +0 -1
  59. package/dist/core/media/index.js +0 -1
  60. package/dist/core/media/media-item-url.service.d.ts +6 -2
  61. package/dist/core/media/media-item-url.service.js +1 -3
  62. package/dist/external-api/article/cmp.embed-article.svelte +98 -0
  63. package/dist/external-api/article/cmp.embed-article.svelte.d.ts +47 -0
  64. package/dist/external-api/article/index.d.ts +1 -0
  65. package/dist/external-api/article/index.js +1 -0
  66. package/dist/external-api/data-providers/article/article-data-provider.d.ts +4 -0
  67. package/dist/external-api/data-providers/article/article-data-provider.js +32 -0
  68. package/dist/external-api/data-providers/article/index.d.ts +1 -0
  69. package/dist/external-api/data-providers/article/index.js +1 -0
  70. package/dist/external-api/data-providers/article/operations.generated.d.ts +104 -0
  71. package/dist/external-api/data-providers/article/operations.generated.js +262 -0
  72. package/dist/external-api/data-providers/article/operations.graphql +99 -0
  73. package/dist/external-api/data-providers/internal-media-center-data-provider.svelte.js +6 -5
  74. package/dist/external-api/data-providers/internal-short-video-player-items-provider.d.ts +1 -1
  75. package/dist/external-api/data-providers/internal-short-video-player-items-provider.js +2 -4
  76. package/dist/external-api/data-providers/internal-streams-player-data-provider.js +1 -1
  77. package/dist/external-api/data-providers/mapper.d.ts +1 -1
  78. package/dist/external-api/data-providers/mapper.js +5 -6
  79. package/dist/external-api/data-providers/mocks/mock-content-management-handler.svelte.js +2 -3
  80. package/dist/external-api/data-providers/post-data-loaders/posts-loader.d.ts +1 -1
  81. package/dist/external-api/data-providers/post-data-loaders/posts-loader.js +0 -1
  82. package/dist/external-api/data-providers/stream-data-loaders/mapper.js +1 -2
  83. package/dist/external-api/data-providers/stream-data-loaders/stream-pages-loader.d.ts +1 -1
  84. package/dist/external-api/data-providers/stream-data-loaders/stream-pages-loader.js +1 -2
  85. package/dist/external-api/data-providers/stream-data-loaders/streams-loader.d.ts +1 -1
  86. package/dist/external-api/data-providers/stream-data-loaders/streams-loader.js +1 -2
  87. package/dist/external-api/index.d.ts +2 -1
  88. package/dist/external-api/index.js +2 -1
  89. package/dist/media-center/config/types.d.ts +4 -1
  90. package/dist/media-center/config/types.js +1 -1
  91. package/dist/media-center/media-center/cmp.media-center-proxy.svelte +9 -4
  92. package/dist/media-center/media-center/cmp.media-center-proxy.svelte.d.ts +2 -3
  93. package/dist/media-center/media-center/discover/data-loading.js +1 -2
  94. package/dist/media-center/media-center/discover/discover-view-handler.svelte.js +1 -2
  95. package/dist/media-center/media-center/index.d.ts +0 -1
  96. package/dist/media-center/media-center/index.js +0 -1
  97. package/dist/media-center/media-center/media-center-settings.svelte.d.ts +1 -1
  98. package/dist/media-center/media-center/media-center-settings.svelte.js +2 -2
  99. package/dist/media-center/media-center/moments/moments-feed-handler.svelte.d.ts +1 -1
  100. package/dist/media-center/media-center/moments/moments-feed-handler.svelte.js +2 -3
  101. package/dist/media-center/media-center/moments/moments-state.svelte.d.ts +1 -1
  102. package/dist/media-center/media-center/moments/moments-state.svelte.js +1 -3
  103. package/dist/media-center/media-center/posts-feed/feed-providers-generator.js +1 -2
  104. package/dist/media-center/media-center/posts-feed/posts-feed-handler.svelte.d.ts +1 -1
  105. package/dist/media-center/media-center/posts-feed/posts-feed-handler.svelte.js +2 -2
  106. package/dist/media-page/cmp.media-page.svelte +10 -9
  107. package/dist/media-page/index.js +4 -4
  108. package/dist/posts/attachments/cmp.attachments.svelte +2 -3
  109. package/dist/posts/model/post-model.d.ts +2 -1
  110. package/dist/posts/model/post-model.js +2 -1
  111. package/dist/posts/post-viewer/attachments-horizontal.svelte +1 -2
  112. package/dist/posts/post-viewer/cmp.post-viewer.svelte +12 -5
  113. package/dist/posts/post-viewer/cmp.post-viewer.svelte.d.ts +1 -0
  114. package/dist/posts/post-viewer/mapper.js +6 -7
  115. package/dist/posts/post-viewer/post-texts.svelte +8 -1
  116. package/dist/posts/post-viewer/post-texts.svelte.d.ts +3 -0
  117. package/dist/posts/posts-player/cmp.posts-player.svelte +23 -13
  118. package/dist/posts/posts-player/cmp.posts-player.svelte.d.ts +2 -0
  119. package/dist/posts/posts-player/index.d.ts +8 -1
  120. package/dist/posts/posts-player/index.js +7 -1
  121. package/dist/posts/posts-player/posts-player-proxy.svelte +3 -2
  122. package/dist/posts/posts-player/posts-player-proxy.svelte.d.ts +2 -0
  123. package/dist/posts/posts-player/posts-player-view.svelte +22 -9
  124. package/dist/posts/posts-player/types.d.ts +3 -0
  125. package/dist/products/price-helper.d.ts +1 -1
  126. package/dist/products/price-helper.js +3 -4
  127. package/dist/streams/layout/models/mapper.d.ts +1 -1
  128. package/dist/streams/layout/models/mapper.js +2 -6
  129. package/dist/streams/layout/models/stream-layout-media-item-model.d.ts +1 -1
  130. package/dist/streams/layout/models/stream-layout-media-item-model.js +1 -1
  131. package/dist/streams/layout/models/stream-layout-short-video-model.d.ts +1 -1
  132. package/dist/streams/layout/models/stream-layout-short-video-model.js +1 -1
  133. package/dist/streams/streams-player/cmp.streams-player.svelte +22 -13
  134. package/dist/streams/streams-player/streams-player-proxy.svelte +1 -1
  135. package/dist/ui/media-items/index.d.ts +3 -0
  136. package/dist/ui/media-items/index.js +3 -0
  137. package/dist/ui/{media-item-view → media-items/media-item-view}/cmp.media-item-view.svelte +23 -5
  138. package/dist/ui/{media-item-view → media-items/media-item-view}/cmp.media-item-view.svelte.d.ts +5 -3
  139. package/dist/ui/{media-items-gallery → media-items/media-items-gallery}/cmp.media-items-gallery.svelte +31 -31
  140. package/dist/ui/{media-items-gallery → media-items/media-items-gallery}/cmp.media-items-gallery.svelte.d.ts +5 -3
  141. package/dist/ui/{media-items-gallery/types.d.ts → media-items/media-items-gallery/gallery-layout.d.ts} +1 -1
  142. package/dist/ui/{media-items-gallery/types.js → media-items/media-items-gallery/gallery-layout.js} +1 -1
  143. package/dist/ui/media-items/types.d.ts +14 -0
  144. package/dist/ui/media-items/types.js +1 -0
  145. package/dist/ui/shadow-dom/cmp.shadow-root.svelte +3 -2
  146. package/dist/ui/shadow-dom/index.d.ts +1 -1
  147. package/dist/ui/shadow-dom/index.js +1 -1
  148. package/dist/ui/shadow-dom/shadow-root-service.d.ts +1 -0
  149. package/dist/ui/shadow-dom/shadow-root-service.js +8 -0
  150. package/package.json +11 -3
  151. package/dist/core/media/types.d.ts +0 -13
  152. package/dist/posts/posts-player/posts-player-host-settings.svelte.d.ts +0 -20
  153. package/dist/posts/posts-player/posts-player-host-settings.svelte.js +0 -15
  154. package/dist/streams/streams-player/streams-player-host-settings.svelte.d.ts +0 -20
  155. package/dist/streams/streams-player/streams-player-host-settings.svelte.js +0 -15
  156. /package/dist/{core/media → articles/article-dialog}/types.js +0 -0
  157. /package/dist/ui/{media-item-view → media-items/media-item-view}/index.d.ts +0 -0
  158. /package/dist/ui/{media-item-view → media-items/media-item-view}/index.js +0 -0
  159. /package/dist/ui/{media-items-gallery → media-items/media-items-gallery}/index.d.ts +0 -0
  160. /package/dist/ui/{media-items-gallery → media-items/media-items-gallery}/index.js +0 -0
@@ -1,30 +1,40 @@
1
1
  <script lang="ts">import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
2
2
  import { createShadowRoot } from '../../ui/shadow-dom';
3
- import { PostsPlayerHostSettings } from './posts-player-host-settings.svelte';
4
3
  import { default as PostsPlayerProxy } from './posts-player-proxy.svelte';
5
- import { mount, unmount, untrack } from 'svelte';
6
- let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, on } = $props();
7
- const settingsHolder = untrack(() => new PostsPlayerHostSettings(playerSettings));
8
- $effect(() => {
9
- settingsHolder.update(playerSettings);
10
- });
4
+ import { mount, unmount } from 'svelte';
5
+ let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, articleDataProvider, on } = $props();
11
6
  const initHost = (node) => {
12
7
  const shadowRoot = createShadowRoot(node);
13
8
  const mounted = mount(PostsPlayerProxy, {
14
9
  target: shadowRoot,
15
10
  props: {
16
- dataProvider,
17
- socialInteractionsHandler,
18
- sharingHandler,
19
- playerSettings: settingsHolder,
20
- analyticsHandler,
11
+ get dataProvider() {
12
+ return dataProvider;
13
+ },
14
+ get socialInteractionsHandler() {
15
+ return socialInteractionsHandler;
16
+ },
17
+ get sharingHandler() {
18
+ return sharingHandler;
19
+ },
20
+ get playerSettings() {
21
+ return playerSettings;
22
+ },
23
+ get analyticsHandler() {
24
+ return analyticsHandler;
25
+ },
26
+ get articleDataProvider() {
27
+ return articleDataProvider;
28
+ },
21
29
  closeOrchestrator: new CloseOrchestrator({
22
30
  closeFn: async () => {
23
31
  await unmount(mounted);
24
32
  },
25
33
  canClose: false
26
34
  }),
27
- on
35
+ get on() {
36
+ return on;
37
+ }
28
38
  }
29
39
  });
30
40
  return {
@@ -1,3 +1,4 @@
1
+ import type { ArticleDataProvider } from '../../articles/data-providers';
1
2
  import type { IPostSocialInteractionsHandler } from '..';
2
3
  import type { IPostSharingHandler } from '../sharing';
3
4
  import type { IPostAnalyticsHandler, PostPlayerModel } from './types';
@@ -8,6 +9,7 @@ type Props = {
8
9
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
9
10
  sharingHandler?: IPostSharingHandler;
10
11
  analyticsHandler?: IPostAnalyticsHandler;
12
+ articleDataProvider?: ArticleDataProvider;
11
13
  playerSettings?: {
12
14
  locale?: AppLocaleValue;
13
15
  showStreamsCloudWatermark?: boolean;
@@ -1,3 +1,4 @@
1
+ import type { ArticleDataProvider } from '../../articles/data-providers';
1
2
  import { type IMediaCenterDataProvider } from '../../media-center/config/types';
2
3
  import type { IPostSharingHandler } from '../sharing';
3
4
  import type { IPostSocialInteractionsHandler } from '../social-interactions';
@@ -5,7 +6,7 @@ import { default as PostsPlayer } from './cmp.posts-player.svelte';
5
6
  import type { IPostAnalyticsHandler, PostPlayerModel } from './types';
6
7
  import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
7
8
  export { PostsPlayer, type PostPlayerModel };
8
- export type { IMediaCenterDataProvider, IPostAnalyticsHandler };
9
+ export type { ArticleDataProvider, IMediaCenterDataProvider, IPostAnalyticsHandler };
9
10
  /**
10
11
  * Opens the posts player modal.
11
12
  *
@@ -23,6 +24,11 @@ export type { IMediaCenterDataProvider, IPostAnalyticsHandler };
23
24
  * @param {IPostSocialInteractionsHandler} [init.socialInteractionsHandler]
24
25
  * Handler for social interactions (like, share, etc.).
25
26
  *
27
+ * Article data provider (optional)
28
+ * @param {ArticleDataProvider} [init.articleDataProvider]
29
+ * Provider for fetching article content. When provided, article posts will show
30
+ * a "Read more" button that opens an article dialog instead of navigating to a URL.
31
+ *
26
32
  * Player settings (optional)
27
33
  * @param {object} [init.playerSettings]
28
34
  * Player UI and behavior settings.
@@ -87,6 +93,7 @@ export declare function openPostsPlayer(init: {
87
93
  analyticsHandler?: IPostAnalyticsHandler;
88
94
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
89
95
  sharingHandler?: IPostSharingHandler;
96
+ articleDataProvider?: ArticleDataProvider;
90
97
  playerSettings?: {
91
98
  disableBackground?: boolean;
92
99
  locale?: AppLocaleValue;
@@ -22,6 +22,11 @@ export { PostsPlayer };
22
22
  * @param {IPostSocialInteractionsHandler} [init.socialInteractionsHandler]
23
23
  * Handler for social interactions (like, share, etc.).
24
24
  *
25
+ * Article data provider (optional)
26
+ * @param {ArticleDataProvider} [init.articleDataProvider]
27
+ * Provider for fetching article content. When provided, article posts will show
28
+ * a "Read more" button that opens an article dialog instead of navigating to a URL.
29
+ *
25
30
  * Player settings (optional)
26
31
  * @param {object} [init.playerSettings]
27
32
  * Player UI and behavior settings.
@@ -82,7 +87,7 @@ export { PostsPlayer };
82
87
  * ```
83
88
  */
84
89
  export function openPostsPlayer(init) {
85
- const { postsProvider: dataProvider, analyticsHandler, socialInteractionsHandler, sharingHandler, playerSettings, on } = init;
90
+ const { postsProvider: dataProvider, analyticsHandler, socialInteractionsHandler, sharingHandler, articleDataProvider, playerSettings, on } = init;
86
91
  const shadowHost = new ModalShadowHost();
87
92
  let mounted = null;
88
93
  const makeCloseOrchestrator = () => new CloseOrchestrator({
@@ -102,6 +107,7 @@ export function openPostsPlayer(init) {
102
107
  socialInteractionsHandler,
103
108
  sharingHandler,
104
109
  analyticsHandler,
110
+ articleDataProvider,
105
111
  playerSettings,
106
112
  closeOrchestrator: makeCloseOrchestrator(),
107
113
  on: {
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">import {} from '../../ui/player/close-orchestrator';
2
2
  import { ShadowRoot } from '../../ui/shadow-dom';
3
3
  import { default as PostsPlayerView } from './posts-player-view.svelte';
4
- let { dataProvider, socialInteractionsHandler, sharingHandler, closeOrchestrator, playerSettings, analyticsHandler, on } = $props();
4
+ let { dataProvider, socialInteractionsHandler, sharingHandler, closeOrchestrator, playerSettings, analyticsHandler, articleDataProvider, on } = $props();
5
5
  let backgroundImageUrl = $state(null);
6
6
  const handleBackgroundImagedLoaded = (url) => {
7
7
  backgroundImageUrl = url;
@@ -10,7 +10,7 @@ const handleBackgroundImagedLoaded = (url) => {
10
10
 
11
11
  <ShadowRoot
12
12
  locale={playerSettings?.locale}
13
- theme={playerSettings?.theme ?? 'dark'}
13
+ theme={playerSettings?.theme}
14
14
  backgroundDisabled={playerSettings?.disableBackground === true}
15
15
  backgroundImageUrl={backgroundImageUrl}>
16
16
  <PostsPlayerView
@@ -19,6 +19,7 @@ const handleBackgroundImagedLoaded = (url) => {
19
19
  sharingHandler={sharingHandler}
20
20
  playerSettings={playerSettings}
21
21
  analyticsHandler={analyticsHandler}
22
+ articleDataProvider={articleDataProvider}
22
23
  closeOrchestrator={closeOrchestrator}
23
24
  on={{ postActivated: on?.postActivated, backgroundImageLoaded: playerSettings?.disableBackground === true ? undefined : handleBackgroundImagedLoaded }} />
24
25
  </ShadowRoot>
@@ -1,3 +1,4 @@
1
+ import type { ArticleDataProvider } from '../../articles/data-providers';
1
2
  import type { IPostSharingHandler } from '../sharing';
2
3
  import type { IPostSocialInteractionsHandler } from '../social-interactions';
3
4
  import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
@@ -9,6 +10,7 @@ type Props = {
9
10
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
10
11
  sharingHandler?: IPostSharingHandler;
11
12
  analyticsHandler?: IPostAnalyticsHandler;
13
+ articleDataProvider?: ArticleDataProvider;
12
14
  closeOrchestrator: ICloseOrchestrator;
13
15
  playerSettings?: {
14
16
  locale?: AppLocaleValue;
@@ -1,15 +1,27 @@
1
- <script lang="ts">import { PostType } from '../../core/enums';
1
+ <script lang="ts">import { openArticleDialog } from '../../articles/article-dialog';
2
2
  import { PostAttachments } from '../attachments';
3
3
  import { PostActionsGenerator } from '../controls';
4
4
  import { getPostCoverImage, PostModel } from '../model';
5
5
  import { PostViewer } from '../post-viewer';
6
6
  import { Player, PlayerConfig, PlayerSettings } from '../../ui/player';
7
+ import { getDialogAnchor } from '../../ui/shadow-dom';
7
8
  import IconDelete from '@fluentui/svg-icons/icons/delete_32_regular.svg?raw';
8
9
  import IconEdit from '@fluentui/svg-icons/icons/edit_32_regular.svg?raw';
9
10
  import { preloadImage } from '@streamscloud/kit/core/utils';
10
11
  import { initBufferFromProvider } from '@streamscloud/kit/ui/player/providers';
11
12
  import { untrack } from 'svelte';
12
- let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, managementActions, closeOrchestrator, on } = $props();
13
+ let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, managementActions, articleDataProvider, closeOrchestrator, on } = $props();
14
+ let playerHostElement = $state();
15
+ const handleArticleReadMore = (articleId) => {
16
+ if (!articleDataProvider || !playerHostElement) {
17
+ return;
18
+ }
19
+ const anchor = getDialogAnchor(playerHostElement);
20
+ if (!anchor) {
21
+ return;
22
+ }
23
+ openArticleDialog({ anchor, articleId, fetchArticle: articleDataProvider.fetchArticle });
24
+ };
13
25
  let buffer = $state.raw(null);
14
26
  let mappedPostsCache = {};
15
27
  $effect(() => {
@@ -57,7 +69,7 @@ const contentPlayerConfig = untrack(() => new PlayerConfig({
57
69
  if (on?.backgroundImageLoaded) {
58
70
  on.backgroundImageLoaded(getPostCoverImage(post));
59
71
  }
60
- if (post.postType === PostType.ShortVideo) {
72
+ if (post.postType === 'SHORT_VIDEO') {
61
73
  analyticsHandler?.trackShortVideoView(id);
62
74
  }
63
75
  else if (post.postType) {
@@ -73,12 +85,12 @@ const postActionsGenerator = untrack(() => new PostActionsGenerator({
73
85
  on: { attachmentClicked: () => (contentPlayerConfig.uiManager.attachmentsCollapsed = !contentPlayerConfig.uiManager.attachmentsCollapsed) }
74
86
  }));
75
87
  const onProductClick = (id, postId) => {
76
- if (getLoadedItemById(postId)?.postType === PostType.ShortVideo) {
88
+ if (getLoadedItemById(postId)?.postType === 'SHORT_VIDEO') {
77
89
  analyticsHandler?.trackShortVideoProductClick(id, postId);
78
90
  }
79
91
  };
80
92
  const onProductImpression = (id, postId) => {
81
- if (getLoadedItemById(postId)?.postType === PostType.ShortVideo) {
93
+ if (getLoadedItemById(postId)?.postType === 'SHORT_VIDEO') {
82
94
  analyticsHandler?.trackShortVideoProductImpression(id, postId);
83
95
  }
84
96
  };
@@ -104,7 +116,7 @@ const currentItemActions = $derived.by(() => {
104
116
  const postModel = itemAsPostModel(buffer.current);
105
117
  const handler = postActionsGenerator.getPostActionsHandler(postModel);
106
118
  result.push(...handler.actions);
107
- if (managementActions?.editPost && postModel.postType !== PostType.Article) {
119
+ if (managementActions?.editPost && postModel.postType !== 'ARTICLE') {
108
120
  result.push({
109
121
  icon: IconEdit,
110
122
  callback: async () => {
@@ -112,7 +124,7 @@ const currentItemActions = $derived.by(() => {
112
124
  }
113
125
  });
114
126
  }
115
- if (managementActions?.editArticle && postModel.postType === PostType.Article && buffer.current.articleId) {
127
+ if (managementActions?.editArticle && postModel.postType === 'ARTICLE' && buffer.current.articleId) {
116
128
  result.push({
117
129
  icon: IconEdit,
118
130
  callback: async () => {
@@ -146,7 +158,7 @@ const currentItemActions = $derived.by(() => {
146
158
  adImpression: (id) => onAdImpression(id)
147
159
  }} />
148
160
  {/snippet}
149
- <div class="player-host">
161
+ <div class="player-host" bind:this={playerHostElement}>
150
162
  <Player
151
163
  config={contentPlayerConfig}
152
164
  itemActions={currentItemActions}
@@ -165,7 +177,8 @@ const currentItemActions = $derived.by(() => {
165
177
  productClick: (productId) => onProductClick(productId, postModel.id),
166
178
  productImpression: (productId) => onProductImpression(productId, postModel.id),
167
179
  adClick: (adId) => onAdClick(adId),
168
- adImpression: (adId) => onAdImpression(adId)
180
+ adImpression: (adId) => onAdImpression(adId),
181
+ articleReadMore: articleDataProvider ? handleArticleReadMore : undefined
169
182
  }} />
170
183
  {/snippet}
171
184
  </Player>
@@ -1,3 +1,4 @@
1
+ import type { ArticleDataProvider } from '../../articles/data-providers';
1
2
  import type { PostType } from '../../core/enums';
2
3
  import type { IPostModel } from '..';
3
4
  import type { IPostSharingHandler } from '../sharing';
@@ -26,6 +27,8 @@ export type PostsPlayerProps = {
26
27
  sharingHandler?: IPostSharingHandler;
27
28
  analyticsHandler?: IPostAnalyticsHandler;
28
29
  managementActions?: PostManagementActions;
30
+ /** Provider for fetching article content. Enables "Read more" button that opens an article dialog. */
31
+ articleDataProvider?: ArticleDataProvider;
29
32
  playerSettings?: PostPlayerSettings;
30
33
  closeOrchestrator: ICloseOrchestrator;
31
34
  on?: {
@@ -1,4 +1,4 @@
1
- import { Currency } from '../core/enums';
1
+ import type { Currency } from '../core/enums';
2
2
  type CurrencyMode = 'none' | 'symbol' | 'code';
3
3
  export type PriceRepresentationOptions = {
4
4
  currencyMode?: CurrencyMode;
@@ -1,4 +1,3 @@
1
- import { Currency } from '../core/enums';
2
1
  import { Utils } from '@streamscloud/kit/core/utils';
3
2
  export const toPriceRepresentation = (data) => {
4
3
  const { amount, currency, options } = data;
@@ -52,9 +51,9 @@ export const toPriceRepresentation = (data) => {
52
51
  }
53
52
  };
54
53
  const currencyDefaults = {
55
- [Currency.Nok]: { symbol: 'kr', code: 'NOK', missingFractionPlaceholder: '-' },
56
- [Currency.Usd]: { symbol: '$', code: 'USD' },
57
- [Currency.Eur]: { symbol: '€', code: 'EUR' }
54
+ ['NOK']: { symbol: 'kr', code: 'NOK', missingFractionPlaceholder: '-' },
55
+ ['USD']: { symbol: '$', code: 'USD' },
56
+ ['EUR']: { symbol: '€', code: 'EUR' }
58
57
  };
59
58
  const getDecimalSeparator = (locale) => {
60
59
  const nf = new Intl.NumberFormat(locale);
@@ -1,3 +1,3 @@
1
- import { type IPostModel } from '../../../posts/model';
1
+ import type { IPostModel } from '../../../posts/model';
2
2
  import type { StreamLayoutShortVideoModel } from '../models/stream-layout-short-video-model';
3
3
  export declare const mapToPostModel: (model: StreamLayoutShortVideoModel) => IPostModel;
@@ -1,13 +1,9 @@
1
- import { MediaType, PostType } from '../../../core/enums';
2
- import {} from '../../../posts/model';
3
1
  export const mapToPostModel = (model) => {
4
2
  return {
5
3
  id: model.id,
6
- postType: PostType.ShortVideo,
4
+ postType: 'SHORT_VIDEO',
7
5
  media: [
8
- model.media.type === MediaType.Image
9
- ? { isImage: true, url: model.media.url }
10
- : { isImage: false, url: model.media.url, thumbnailUrl: model.media.thumbnailUrl }
6
+ model.media.type === 'IMAGE' ? { isImage: true, url: model.media.url } : { isImage: false, url: model.media.url, thumbnailUrl: model.media.thumbnailUrl }
11
7
  ],
12
8
  mediaFit: 'cover',
13
9
  kicker: null,
@@ -1,4 +1,4 @@
1
- import { MediaType } from '../../../core/enums';
1
+ import type { MediaType } from '../../../core/enums';
2
2
  export type StreamLayoutMediaItemModel = {
3
3
  url: string;
4
4
  thumbnailUrl: string | null;
@@ -1 +1 @@
1
- import { MediaType } from '../../../core/enums';
1
+ export {};
@@ -1,4 +1,4 @@
1
- import { AdType, type Currency } from '../../../core/enums';
1
+ import type { AdType, Currency } from '../../../core/enums';
2
2
  import type { StreamLayoutMediaItemModel } from './stream-layout-media-item-model';
3
3
  import type { StreamLayoutPostHeaderModel } from './stream-layout-post-header-model';
4
4
  export type StreamLayoutShortVideoModel = {
@@ -1 +1 @@
1
- import { AdType } from '../../../core/enums';
1
+ export {};
@@ -1,31 +1,40 @@
1
1
  <script lang="ts">import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
2
2
  import { createShadowRoot } from '../../ui/shadow-dom';
3
- import { StreamsPlayerHostSettings } from './streams-player-host-settings.svelte';
4
3
  import { default as StreamsPlayerProxy } from './streams-player-proxy.svelte';
5
- import { mount, unmount, untrack } from 'svelte';
4
+ import { mount, unmount } from 'svelte';
6
5
  let { dataProvider, postSocialInteractionsHandler, sharingHandler, amplificationParameters, playerSettings, analyticsHandler, on } = $props();
7
- const settingsHolder = untrack(() => new StreamsPlayerHostSettings(playerSettings));
8
- $effect(() => {
9
- settingsHolder.update(playerSettings);
10
- });
11
6
  const initHost = (node) => {
12
7
  const shadowRoot = createShadowRoot(node);
13
8
  const mounted = mount(StreamsPlayerProxy, {
14
9
  target: shadowRoot,
15
10
  props: {
16
- dataProvider,
17
- postSocialInteractionsHandler,
18
- sharingHandler,
19
- analyticsHandler,
20
- amplificationParameters,
21
- playerSettings: settingsHolder,
11
+ get dataProvider() {
12
+ return dataProvider;
13
+ },
14
+ get postSocialInteractionsHandler() {
15
+ return postSocialInteractionsHandler;
16
+ },
17
+ get sharingHandler() {
18
+ return sharingHandler;
19
+ },
20
+ get analyticsHandler() {
21
+ return analyticsHandler;
22
+ },
23
+ get amplificationParameters() {
24
+ return amplificationParameters;
25
+ },
26
+ get playerSettings() {
27
+ return playerSettings;
28
+ },
22
29
  closeOrchestrator: new CloseOrchestrator({
23
30
  closeFn: async () => {
24
31
  await unmount(mounted);
25
32
  },
26
33
  canClose: false
27
34
  }),
28
- on
35
+ get on() {
36
+ return on;
37
+ }
29
38
  }
30
39
  });
31
40
  return {
@@ -10,7 +10,7 @@ const handleBackgroundImagedLoaded = (url) => {
10
10
 
11
11
  <ShadowRoot
12
12
  locale={playerSettings?.locale}
13
- theme={playerSettings?.theme ?? 'dark'}
13
+ theme={playerSettings?.theme}
14
14
  backgroundDisabled={playerSettings?.disableBackground === true}
15
15
  backgroundImageUrl={backgroundImageUrl}>
16
16
  <StreamsPlayerView
@@ -0,0 +1,3 @@
1
+ export { MediaItemView } from './media-item-view';
2
+ export { MediaItemsGallery } from './media-items-gallery';
3
+ export { type MediaItem, type MediaItemMetadataModel, type MediaItemWithMetadataModel, getMediaItemImageUrl } from './types';
@@ -0,0 +1,3 @@
1
+ export { MediaItemView } from './media-item-view';
2
+ export { MediaItemsGallery } from './media-items-gallery';
3
+ export { getMediaItemImageUrl } from './types';
@@ -1,9 +1,21 @@
1
- <script lang="ts">import { MediaFormat, MediaType } from '../../core/enums';
2
- import { getMediaItemImageUrl } from '../../core/media';
1
+ <script lang="ts">import { getMediaItemImageUrl } from '../types';
2
+ import IconDelete from '@fluentui/svg-icons/icons/delete_20_regular.svg?raw';
3
+ import IconEdit from '@fluentui/svg-icons/icons/edit_20_regular.svg?raw';
4
+ import { cardActionContainer, CardActions } from '@streamscloud/kit/ui/card-actions';
3
5
  import { Image } from '@streamscloud/kit/ui/image';
4
6
  import { ProportionalContainer } from '@streamscloud/kit/ui/proportional-container';
5
7
  import { Video } from '@streamscloud/kit/ui/video';
6
8
  let { media, ratio = 0, inert = false, on } = $props();
9
+ const actions = $derived.by(() => {
10
+ const result = [];
11
+ if (on?.edit) {
12
+ result.push({ icon: IconEdit, iconColor: 'blue', callback: on.edit });
13
+ }
14
+ if (on?.remove) {
15
+ result.push({ icon: IconDelete, iconColor: 'red', callback: on.remove });
16
+ }
17
+ return result;
18
+ });
7
19
  const handleClick = (e) => {
8
20
  if (on?.click) {
9
21
  e.stopPropagation();
@@ -16,7 +28,7 @@ const parsedRatio = $derived.by(() => {
16
28
  }
17
29
  else {
18
30
  if (typeof ratio !== 'number') {
19
- return ratio === MediaFormat.W16H9 ? 16 / 9 : 4 / 3;
31
+ return ratio === 'W16H9' ? 16 / 9 : 4 / 3;
20
32
  }
21
33
  else {
22
34
  return ratio;
@@ -27,7 +39,7 @@ const parsedRatio = $derived.by(() => {
27
39
 
28
40
  {#if media}
29
41
  {#snippet mediaView()}
30
- {#if media.type === MediaType.Image}
42
+ {#if media.type === 'IMAGE'}
31
43
  <div class="media-item-view__image" onclick={handleClick} onkeydown={() => {}} role="none">
32
44
  <Image src={getMediaItemImageUrl(media)} />
33
45
  </div>
@@ -38,7 +50,12 @@ const parsedRatio = $derived.by(() => {
38
50
  {/if}
39
51
  {/snippet}
40
52
 
41
- <div class="media-item-view" class:media-item-view--clickable={on?.click} class:media-item-view--fit-parent={ratio === 'fit-parent'} inert={inert}>
53
+ <div
54
+ class="media-item-view"
55
+ class:media-item-view--clickable={on?.click}
56
+ class:media-item-view--fit-parent={ratio === 'fit-parent'}
57
+ use:cardActionContainer
58
+ inert={inert}>
42
59
  {#if parsedRatio}
43
60
  <ProportionalContainer ratio={parsedRatio}>
44
61
  {@render mediaView()}
@@ -46,6 +63,7 @@ const parsedRatio = $derived.by(() => {
46
63
  {:else}
47
64
  {@render mediaView()}
48
65
  {/if}
66
+ <CardActions actions={actions} />
49
67
  </div>
50
68
  {/if}
51
69
 
@@ -1,11 +1,13 @@
1
- import { MediaFormat } from '../../core/enums';
2
- import { type MediaItemModel } from '../../core/media';
1
+ import type { MediaFormat } from '../../../core/enums';
2
+ import { type MediaItem } from '../types';
3
3
  type Props = {
4
- media: MediaItemModel | null;
4
+ media: MediaItem | null;
5
5
  ratio?: number | MediaFormat | 'fit-parent';
6
6
  inert?: boolean;
7
7
  on?: {
8
8
  click?: () => void;
9
+ edit?: () => void;
10
+ remove?: () => void;
9
11
  };
10
12
  };
11
13
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -1,7 +1,7 @@
1
- <script lang="ts">import { MediaFormat } from '../../core/enums';
2
- import {} from '../../core/media';
3
- import { MediaItemView } from '../media-item-view';
4
- import { GalleryLayout } from './types';
1
+ <script lang="ts">import { MediaItemView } from '../media-item-view';
2
+ import {} from '../types';
3
+ import { GalleryLayout } from './gallery-layout';
4
+ import { openMediaViewer } from '@streamscloud/kit/ui/media-viewer-dialog';
5
5
  let { media, singleImageRatio = 0, inert = false, on } = $props();
6
6
  let layout = $state(null);
7
7
  const initLayout = async () => {
@@ -17,35 +17,31 @@ $effect(() => {
17
17
  });
18
18
  const upperTwoImages = $derived(media.length > 4 ? media.slice(0, 2) : []);
19
19
  const bottomThreeImages = $derived(media.length > 4 ? media.slice(2, 5) : []);
20
+ const toMediaViewerItemType = (type) => {
21
+ switch (type) {
22
+ case 'VIDEO':
23
+ case 'SHORT_VIDEO':
24
+ case 'AUDIO':
25
+ return 'video';
26
+ default:
27
+ return 'image';
28
+ }
29
+ };
20
30
  const handleGalleryItemClick = (index) => {
21
31
  if (on?.click) {
22
- on?.click(index);
32
+ on.click(index);
23
33
  return;
24
34
  }
25
- /*const toMediaViewerItemType = (type: MediaType) => {
26
- switch (type) {
27
- case MediaType.Image:
28
- return MediaViewerItemType.Image;
29
- case MediaType.Video:
30
- case MediaType.ShortVideo:
31
- return MediaViewerItemType.Video;
32
- case MediaType.Audio:
33
- return MediaViewerItemType.Audio;
34
- default:
35
- Utils.assertUnreachable(type);
36
- }
37
- };
38
35
  openMediaViewer({
39
- items: media.map((i) => ({
40
- id: randomNanoid(),
41
- url: i.url,
42
- thumbnailUrl: i.thumbnailUrl,
43
- type: toMediaViewerItemType(i.type),
44
- width: i.metadata.width,
45
- height: i.metadata.height
46
- })),
47
- index
48
- });*/
36
+ items: media.map((i) => ({
37
+ url: i.url,
38
+ thumbnailUrl: i.thumbnailUrl ?? null,
39
+ type: toMediaViewerItemType(i.type),
40
+ width: i.metadata.width,
41
+ height: i.metadata.height
42
+ })),
43
+ index
44
+ });
49
45
  };
50
46
  </script>
51
47
 
@@ -56,17 +52,21 @@ const handleGalleryItemClick = (index) => {
56
52
  ratio={singleImageRatio}
57
53
  inert={inert}
58
54
  on={{
59
- click: on?.click ? () => on?.click(0) : undefined
55
+ click: on?.click ? () => on?.click?.(0) : undefined,
56
+ edit: on?.edit ? () => on?.edit?.(0) : undefined,
57
+ remove: on?.remove ? () => on?.remove?.(0) : undefined
60
58
  }} />
61
59
  {:else}
62
60
  <div class="gallery-container" inert={inert}>
63
- {#snippet galleryItem(index: NumberType)}
61
+ {#snippet galleryItem(index: number)}
64
62
  <div class="gallery-item">
65
63
  <MediaItemView
66
64
  media={media[index]}
67
65
  ratio="fit-parent"
68
66
  on={{
69
- click: () => handleGalleryItemClick(index)
67
+ click: () => handleGalleryItemClick(index),
68
+ edit: on?.edit ? () => on?.edit?.(index) : undefined,
69
+ remove: on?.remove ? () => on?.remove?.(index) : undefined
70
70
  }} />
71
71
  </div>
72
72
  {/snippet}
@@ -1,11 +1,13 @@
1
- import { MediaFormat } from '../../core/enums';
2
- import { type MediaItemWithMetadataModel } from '../../core/media';
1
+ import type { MediaFormat } from '../../../core/enums';
2
+ import { type MediaItemWithMetadataModel } from '../types';
3
3
  type Props = {
4
4
  media: Array<MediaItemWithMetadataModel> | ReadonlyArray<MediaItemWithMetadataModel>;
5
5
  singleImageRatio?: number | MediaFormat;
6
6
  inert?: boolean;
7
7
  on?: {
8
- click: (index: number) => void;
8
+ click?: (index: number) => void;
9
+ edit?: (index: number) => void;
10
+ remove?: (index: number) => void;
9
11
  };
10
12
  };
11
13
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -1,4 +1,4 @@
1
- import { type MediaItemWithMetadataModel } from '../../core/media';
1
+ import { type MediaItemWithMetadataModel } from '../types';
2
2
  export declare class GalleryLayout {
3
3
  layoutClass: string;
4
4
  firstImage: MediaItemWithMetadataModel;
@@ -1,4 +1,4 @@
1
- import { getMediaItemImageUrl } from '../../core/media';
1
+ import { getMediaItemImageUrl } from '../types';
2
2
  import { ImageHelper } from '@streamscloud/kit/core/media';
3
3
  export class GalleryLayout {
4
4
  layoutClass;
@@ -0,0 +1,14 @@
1
+ import type { MediaType } from '../../core/enums';
2
+ export type MediaItem = {
3
+ type: MediaType;
4
+ url: string;
5
+ thumbnailUrl?: string | null;
6
+ };
7
+ export type MediaItemMetadataModel = {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ export type MediaItemWithMetadataModel = MediaItem & {
12
+ metadata: MediaItemMetadataModel;
13
+ };
14
+ export declare const getMediaItemImageUrl: (media: MediaItem) => string;
@@ -0,0 +1 @@
1
+ export const getMediaItemImageUrl = (media) => (media.type === 'IMAGE' ? media.url : (media.thumbnailUrl ?? ''));