@streamscloud/kit 0.2.27 → 0.2.28

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.
@@ -8,7 +8,7 @@ import IconSpeaker from '@fluentui/svg-icons/icons/speaker_2_20_regular.svg?raw'
8
8
  import IconSpeakerMute from '@fluentui/svg-icons/icons/speaker_mute_20_regular.svg?raw';
9
9
  import { untrack } from 'svelte';
10
10
  import { fade } from 'svelte/transition';
11
- let { src, poster, id = randomNanoid(), controls = false, autoplay = false, loop = false, inert = false, allowPreloading = false, hideSpeaker = false, hidePlayButton = false, intersectionContainer, scrubberPosition = 'bottom', on } = $props();
11
+ let { src, poster, id = randomNanoid(), autoplay = false, loop = false, inert = false, allowPreloading = false, hideSpeaker = false, hidePlayButton = false, intersectionContainer, scrubberPosition = 'bottom', on } = $props();
12
12
  let video = $state(null);
13
13
  let videoContainerRef = $state(null);
14
14
  let showControlsOnHover = $state(false);
@@ -72,19 +72,24 @@ $effect(() => {
72
72
  }
73
73
  const [entry] = entries;
74
74
  latestEntry = entry;
75
- if ((entry.isIntersecting || allowPreloading) && !video.src) {
75
+ if ((entry.isIntersecting || allowPreloading || !poster) && !video.src) {
76
76
  video.src = src;
77
77
  video.load();
78
- if (autoplayState === true) {
79
- const handleCanPlay = () => {
80
- if (latestEntry?.isIntersecting) {
81
- void play();
82
- autoplayState = false;
83
- }
84
- };
85
- video.addEventListener('canplay', handleCanPlay, { once: true });
86
- return;
78
+ }
79
+ if (autoplayState === true && entry.isIntersecting) {
80
+ const attemptPlay = () => {
81
+ if (autoplayState === true && latestEntry?.isIntersecting) {
82
+ void play();
83
+ autoplayState = false;
84
+ }
85
+ };
86
+ if (video.readyState >= 3) {
87
+ attemptPlay();
88
+ }
89
+ else {
90
+ video.addEventListener('canplay', attemptPlay, { once: true });
87
91
  }
92
+ return;
88
93
  }
89
94
  if (autoplayState !== 'on-appearance') {
90
95
  return;
@@ -229,12 +234,11 @@ const handleSeek = (percent) => {
229
234
  <div class="video" role="none" inert={inert} bind:this={videoContainerRef}>
230
235
  <video
231
236
  class="video__video"
232
- class:video__video--not-activated={!everActivated}
237
+ class:video__video--not-activated={!everActivated && !!poster}
233
238
  width="100%"
234
- controls={controls && everActivated}
235
239
  poster={poster}
236
240
  loop={loop}
237
- preload="metadata"
241
+ preload={poster ? 'metadata' : 'auto'}
238
242
  onvolumechange={onVolumeChange}
239
243
  ontimeupdate={onTimeUpdate}
240
244
  onloadeddata={onLoaded}
@@ -248,56 +252,54 @@ const handleSeek = (percent) => {
248
252
  {#if !everActivated && poster}
249
253
  <img class="video__poster" src={poster} alt="" />
250
254
  {/if}
251
- {#if !controls || !everActivated}
252
- <div
253
- class="video__overlay"
254
- onclick={togglePlay}
255
- onkeydown={() => ({})}
256
- onmouseenter={() => (showControlsOnHover = true)}
257
- onmouseleave={() => (showControlsOnHover = false)}
258
- role="none">
259
- {#if isVideoPaused && !hidePlayButton}
260
- <button type="button" aria-label="play" class="video__playback-button" onclick={togglePlay} onkeydown={() => ({})}>
261
- <Icon src={IconPlay} color="white" />
262
- </button>
263
- {:else if showControlsOnHover && !hidePlayButton}
264
- <button type="button" aria-label="pause" class="video__playback-button video__playback-button--pause" onclick={togglePlay} onkeydown={() => ({})}>
265
- <Icon src={IconPause} color="white" />
266
- </button>
267
- {/if}
255
+ <div
256
+ class="video__overlay"
257
+ onclick={togglePlay}
258
+ onkeydown={() => ({})}
259
+ onmouseenter={() => (showControlsOnHover = true)}
260
+ onmouseleave={() => (showControlsOnHover = false)}
261
+ role="none">
262
+ {#if isVideoPaused && !hidePlayButton}
263
+ <button type="button" aria-label="play" class="video__playback-button" onclick={togglePlay} onkeydown={() => ({})}>
264
+ <Icon src={IconPlay} color="white" />
265
+ </button>
266
+ {:else if showControlsOnHover && !hidePlayButton}
267
+ <button type="button" aria-label="pause" class="video__playback-button video__playback-button--pause" onclick={togglePlay} onkeydown={() => ({})}>
268
+ <Icon src={IconPause} color="white" />
269
+ </button>
270
+ {/if}
268
271
 
269
- {#if (showControlsOnHover || MediaVolumeManager.isMuted) && !hideSpeaker}
270
- <button type="button" aria-label={MediaVolumeManager.isMuted ? 'mute' : 'unmute'} class="video__mute-button" onclick={toggleMute}>
271
- {#if MediaVolumeManager.isMuted}
272
- <Icon src={IconSpeakerMute} color="white" />
273
- {:else}
274
- <Icon src={IconSpeaker} color="white" />
275
- {/if}
276
- </button>
277
- {/if}
272
+ {#if (showControlsOnHover || MediaVolumeManager.isMuted) && !hideSpeaker}
273
+ <button type="button" aria-label={MediaVolumeManager.isMuted ? 'mute' : 'unmute'} class="video__mute-button" onclick={toggleMute}>
274
+ {#if MediaVolumeManager.isMuted}
275
+ <Icon src={IconSpeakerMute} color="white" />
276
+ {:else}
277
+ <Icon src={IconSpeaker} color="white" />
278
+ {/if}
279
+ </button>
280
+ {/if}
278
281
 
279
- {#if everActivated}
280
- <div
281
- class="video__progress-container"
282
- class:video__progress-container--top={scrubberPosition === 'top'}
283
- class:video__progress-container--bottom={scrubberPosition === 'bottom'}
284
- onmouseenter={() => (showProgressOnHover = true)}
285
- onmouseleave={() => (showProgressOnHover = false)}
286
- role="none">
287
- {#if showProgressOnHover || (!showProgressOnHover && isVideoPaused)}
288
- <div
289
- class="video__seek-bar"
290
- transition:fade={{ duration: isVideoPaused ? 0 : 300 }}
291
- onclick={(e) => e.stopPropagation()}
292
- onkeydown={() => ({})}
293
- role="none">
294
- <SeekBar value={percentageCompleted} on={{ seek: handleSeek }} />
295
- </div>
296
- {/if}
297
- </div>
298
- {/if}
299
- </div>
300
- {/if}
282
+ {#if everActivated}
283
+ <div
284
+ class="video__progress-container"
285
+ class:video__progress-container--top={scrubberPosition === 'top'}
286
+ class:video__progress-container--bottom={scrubberPosition === 'bottom'}
287
+ onmouseenter={() => (showProgressOnHover = true)}
288
+ onmouseleave={() => (showProgressOnHover = false)}
289
+ role="none">
290
+ {#if showProgressOnHover || (!showProgressOnHover && isVideoPaused)}
291
+ <div
292
+ class="video__seek-bar"
293
+ transition:fade={{ duration: isVideoPaused ? 0 : 300 }}
294
+ onclick={(e) => e.stopPropagation()}
295
+ onkeydown={() => ({})}
296
+ role="none">
297
+ <SeekBar value={percentageCompleted} on={{ seek: handleSeek }} />
298
+ </div>
299
+ {/if}
300
+ </div>
301
+ {/if}
302
+ </div>
301
303
  </div>
302
304
 
303
305
  <!--
@@ -6,8 +6,6 @@ type Props = {
6
6
  poster: string | null | undefined;
7
7
  /** Unique player ID for the global PlaybackManager @default nanoid() */
8
8
  id?: string;
9
- /** Show native browser controls once playback starts */
10
- controls?: boolean;
11
9
  /** Autoplay strategy: `true` plays immediately, `'on-appearance'` plays when scrolled into view */
12
10
  autoplay?: true | false | 'on-appearance';
13
11
  loop?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",