@maas/vue-equipment 1.0.0-beta.27 → 1.0.0-beta.29

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment/nuxt",
3
3
  "configKey": "vueEquipment",
4
- "version": "1.0.0-beta.26",
4
+ "version": "1.0.0-beta.28",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
7
7
  "unbuild": "unknown"
@@ -2,6 +2,7 @@
2
2
  <div
3
3
  class="magic-player-audio-controls"
4
4
  :data-touched="touched"
5
+ :data-dragging="dragging"
5
6
  :data-started="started"
6
7
  :data-playing="playing"
7
8
  :data-paused="paused"
@@ -105,6 +106,7 @@ const {
105
106
  muted,
106
107
  waiting,
107
108
  touched,
109
+ dragging,
108
110
  controlsMouseEntered
109
111
  } = toRefs(state);
110
112
  const { idle } = useIdle(injectedOptions?.threshold?.idle);
@@ -46,42 +46,25 @@ const storyboard = shallowRef();
46
46
  let context = void 0;
47
47
  let image = void 0;
48
48
  const thumbWidth = computed(() => {
49
- if (!storyboard.value) return 0;
49
+ if (!storyboard.value) {
50
+ return 0;
51
+ }
50
52
  return storyboard.value.tile_width / pixelRatio.value;
51
53
  });
52
54
  const thumbHeight = computed(() => {
53
- if (!storyboard.value) return 0;
55
+ if (!storyboard.value) {
56
+ return 0;
57
+ }
54
58
  return storyboard.value.tile_height / pixelRatio.value;
55
59
  });
56
60
  function getMuxId(url) {
57
61
  const match = url?.match(/mux\.com\/([^\/]+)/);
58
62
  return match?.[1]?.replace(/\.(m3u8|mp4)$/, "");
59
63
  }
60
- async function init() {
61
- const parsedPlaybackId = getMuxId(injectedOptions?.src);
62
- const mappedPlaybackId = playbackId ?? parsedPlaybackId;
63
- if (!mappedPlaybackId) {
64
- console.error(
65
- "MagicPlayerMuxPopover must be nested inside MagicPlayerProvider or a playbackId must be provided"
66
- );
64
+ function drawFrame(time) {
65
+ if (!storyboard.value || !context || !image || !time) {
67
66
  return;
68
67
  }
69
- try {
70
- storyboard.value = await fetch(
71
- `https://image.mux.com/${mappedPlaybackId}/storyboard.json`
72
- ).then((res) => res.json());
73
- if (!storyboard.value) throw new Error();
74
- image = new Image();
75
- image.src = storyboard.value.url;
76
- await image.decode();
77
- context = canvasRef.value?.getContext("2d");
78
- context?.drawImage(image, 0, 0);
79
- } catch (e) {
80
- console.error("Can not initialize timeine preview.", e);
81
- }
82
- }
83
- function drawFrame(time) {
84
- if (!storyboard.value || !context || !image) return;
85
68
  const { tile_height, tile_width, tiles } = storyboard.value;
86
69
  let closestIndex = -1;
87
70
  let minDifference = Infinity;
@@ -106,8 +89,38 @@ function drawFrame(time) {
106
89
  tile_height
107
90
  );
108
91
  }
109
- onMounted(init);
110
- watch(() => seekedTime?.value, drawFrame);
92
+ async function initialize() {
93
+ const parsedPlaybackId = getMuxId(injectedOptions?.src);
94
+ const mappedPlaybackId = playbackId ?? parsedPlaybackId;
95
+ if (!mappedPlaybackId) {
96
+ console.error(
97
+ "MagicPlayerMuxPopover must be nested inside MagicPlayerProvider or a playbackId must be provided"
98
+ );
99
+ return;
100
+ }
101
+ try {
102
+ storyboard.value = await fetch(
103
+ `https://image.mux.com/${mappedPlaybackId}/storyboard.json`
104
+ ).then((res) => res.json());
105
+ if (!storyboard.value) {
106
+ throw new Error();
107
+ }
108
+ image = new Image();
109
+ image.src = storyboard.value.url;
110
+ await image.decode();
111
+ context = canvasRef.value?.getContext("2d");
112
+ drawFrame(seekedTime.value);
113
+ } catch (e) {
114
+ console.error("Can not initialize timeline preview", e);
115
+ }
116
+ }
117
+ onMounted(() => {
118
+ initialize();
119
+ });
120
+ watch(
121
+ () => seekedTime?.value,
122
+ (value) => drawFrame(value)
123
+ );
111
124
  </script>
112
125
 
113
126
  <style>
@@ -12,7 +12,6 @@
12
12
  :data-waiting="waiting"
13
13
  :data-loaded="loaded"
14
14
  :data-muted="muted"
15
- @touchstart="onTouchstart"
16
15
  @mouseenter="onMouseenter"
17
16
  @mouseleave="onMouseleave"
18
17
  @pointerdown="onPointerdown"
@@ -54,10 +53,9 @@ const {
54
53
  muted,
55
54
  loaded,
56
55
  fullscreen,
57
- touched,
58
- hasOverlay
56
+ touched
59
57
  } = toRefs(state);
60
- const { onTouchstart, onMouseenter, onMouseleave, onPointerdown } = usePlayerProvider(id);
58
+ const { onMouseenter, onMouseleave, onPointerdown } = usePlayerProvider(id);
61
59
  const playerRef = useTemplateRef("player");
62
60
  const { initializeEmitter } = usePlayerEmitter({ id });
63
61
  onMounted(() => {
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
  <div
3
- ref="el"
4
3
  class="magic-player-video-controls"
5
4
  :data-fullscreen="fullscreen"
6
5
  :data-touched="touched"
6
+ :data-dragging="dragging"
7
7
  :data-started="started"
8
8
  :data-playing="playing"
9
9
  :data-paused="paused"
@@ -18,13 +18,16 @@
18
18
  <transition :name="mappedTransition">
19
19
  <div v-show="visible" class="magic-player-video-controls__bar">
20
20
  <div
21
- v-if="$slots.popover"
22
- v-show="!!seekedTime && touched"
21
+ v-if="$slots.popover && seekedTime !== null && seekedTime >= 0"
23
22
  ref="popover"
24
23
  class="magic-player-video-controls__popover"
25
- :style="{ marginLeft: `${popoverOffsetX}%` }"
24
+ :style="{
25
+ marginLeft: `${popoverOffsetX}%`
26
+ }"
26
27
  >
27
- <slot name="popover" />
28
+ <div v-show="popoverOffsetX !== null">
29
+ <slot name="popover" />
30
+ </div>
28
31
  </div>
29
32
  <div ref="bar" class="magic-player-video-controls__bar--inner">
30
33
  <div class="magic-player-video-controls__item -shrink-0">
@@ -85,7 +88,7 @@ import {
85
88
  useTemplateRef,
86
89
  onBeforeUnmount
87
90
  } from "vue";
88
- import { useElementVisibility, useIdle } from "@vueuse/core";
91
+ import { useIdle } from "@vueuse/core";
89
92
  import IconPlay from "./icons/Play.vue";
90
93
  import IconPause from "./icons/Pause.vue";
91
94
  import IconVolumeOn from "./icons/VolumeOn.vue";
@@ -141,7 +144,8 @@ const {
141
144
  fullscreen,
142
145
  popoverOffsetX,
143
146
  hasOverlay,
144
- seekedTime
147
+ seekedTime,
148
+ dragging
145
149
  } = toRefs(state);
146
150
  const { play, pause, mute, unmute, enterFullscreen, exitFullscreen } = usePlayerVideoApi({ id: mappedInstanceId.value });
147
151
  const { initialize, destroy, onMouseenter, onMouseleave } = usePlayerControlsApi({
@@ -150,18 +154,17 @@ const { initialize, destroy, onMouseenter, onMouseleave } = usePlayerControlsApi
150
154
  trackRef,
151
155
  popoverRef
152
156
  });
153
- const elRef = useTemplateRef("el");
154
- const isVisible = useElementVisibility(elRef);
155
157
  const { idle } = useIdle(injectedOptions?.threshold?.idle);
156
158
  const visible = computed(() => {
157
159
  switch (true) {
158
160
  case standalone:
159
161
  return true;
160
- case !isVisible.value:
161
162
  case (hasOverlay.value && !started.value):
162
163
  case (playing.value && idle.value):
163
164
  case (playing.value && !mouseEntered.value && !controlsMouseEntered.value):
164
- case (injectedOptions?.autoplay && (!started.value || !mouseEntered.value)):
165
+ case (injectedOptions?.autoplay && !started.value):
166
+ case (injectedOptions?.autoplay && !mouseEntered.value):
167
+ case (injectedOptions?.autoplay && !mouseEntered.value && !touched.value):
165
168
  return false;
166
169
  default:
167
170
  return true;
@@ -101,6 +101,7 @@ export function usePlayerControlsApi(args) {
101
101
  }
102
102
  function resetStateAndListeners() {
103
103
  dragging.value = false;
104
+ touched.value = false;
104
105
  cancelTouchend?.();
105
106
  cancelPointerup?.();
106
107
  cancelPointermove?.();
@@ -149,7 +150,11 @@ export function usePlayerControlsApi(args) {
149
150
  function onMouseleave() {
150
151
  controlsMouseEntered.value = false;
151
152
  if (!dragging.value) {
152
- seekedTime.value = 0;
153
+ seekedTime.value = null;
154
+ popoverOffsetX.value = null;
155
+ seekedPercentage.value = 0;
156
+ scrubbedPercentage.value = 0;
157
+ thumbPercentage.value = 0;
153
158
  }
154
159
  }
155
160
  let watchTrack = null;
@@ -1,6 +1,5 @@
1
1
  import { type MaybeRef } from 'vue';
2
2
  export declare function usePlayerProvider(id: MaybeRef<string>): {
3
- onTouchstart: () => void;
4
3
  onMouseenter: () => void;
5
4
  onMouseleave: () => void;
6
5
  onPointerdown: () => void;
@@ -1,21 +1,19 @@
1
1
  import { toRefs } from "vue";
2
2
  import { useEventListener } from "@vueuse/core";
3
+ import { isIOS } from "@maas/vue-equipment/utils";
3
4
  import { usePlayerState } from "./usePlayerState.mjs";
4
5
  export function usePlayerProvider(id) {
5
6
  const { initializeState } = usePlayerState(id);
6
7
  const state = initializeState();
7
8
  const { mouseEntered, touched } = toRefs(state);
9
+ let cancelPointerup = void 0;
8
10
  let cancelTouchend = void 0;
9
- function onTouchend() {
11
+ function onPointerup() {
12
+ touched.value = false;
13
+ cancelPointerup?.();
10
14
  cancelTouchend?.();
15
+ cancelPointerup = void 0;
11
16
  cancelTouchend = void 0;
12
- mouseEntered.value = false;
13
- }
14
- function onTouchstart() {
15
- mouseEntered.value = true;
16
- cancelTouchend = useEventListener(document, "touchend", onTouchend, {
17
- passive: true
18
- });
19
17
  }
20
18
  function onMouseenter() {
21
19
  mouseEntered.value = true;
@@ -25,9 +23,10 @@ export function usePlayerProvider(id) {
25
23
  }
26
24
  function onPointerdown() {
27
25
  touched.value = true;
26
+ cancelPointerup = useEventListener(document, "pointerup", onPointerup);
27
+ cancelTouchend = isIOS() ? useEventListener(document, "touchend", onPointerup) : void 0;
28
28
  }
29
29
  return {
30
- onTouchstart,
31
30
  onMouseenter,
32
31
  onMouseleave,
33
32
  onPointerdown
@@ -24,11 +24,11 @@ export function usePlayerState(id) {
24
24
  fullscreenTarget: null,
25
25
  mouseEntered: false,
26
26
  controlsMouseEntered: false,
27
- seekedTime: 0,
27
+ seekedTime: null,
28
28
  seekedPercentage: 0,
29
29
  scrubbedPercentage: 0,
30
30
  thumbPercentage: 0,
31
- popoverOffsetX: 0,
31
+ popoverOffsetX: null,
32
32
  hasOverlay: false,
33
33
  hasControls: false,
34
34
  controlsBarRect: void 0,
@@ -17,11 +17,11 @@ export declare function useMagicPlayer(id: MaybeRef<string>): {
17
17
  dragging: import("vue").Ref<boolean, boolean>;
18
18
  fullscreen: import("vue").Ref<boolean, boolean>;
19
19
  currentTime: import("vue").Ref<number, number>;
20
- seekedTime: import("vue").Ref<number, number>;
20
+ seekedTime: import("vue").Ref<number | null, number | null>;
21
21
  seekedPercentage: import("vue").Ref<number, number>;
22
22
  scrubbedPercentage: import("vue").Ref<number, number>;
23
23
  thumbPercentage: import("vue").Ref<number, number>;
24
- popoverOffsetX: import("vue").Ref<number, number>;
24
+ popoverOffsetX: import("vue").Ref<number | null, number | null>;
25
25
  audioApi: {
26
26
  play: () => void;
27
27
  pause: () => void;
@@ -1,7 +1,6 @@
1
1
  @import './magic-player-timeline.css';
2
2
  @import './magic-player-display-time.css';
3
3
 
4
- /* We keep this variable since it's used in multiple places */
5
4
  :root {
6
5
  --magic-player-audio-controls-height: 3rem;
7
6
  }
@@ -20,6 +20,10 @@
20
20
  cursor: pointer;
21
21
  }
22
22
 
23
+ [data-dragging='true'] .magic-player-timeline__target {
24
+ cursor: grabbing;
25
+ }
26
+
23
27
  .magic-player-timeline__track {
24
28
  position: relative;
25
29
  width: 100%;
@@ -55,11 +55,11 @@ export interface PlayerState {
55
55
  fullscreenTarget: HTMLElement | null;
56
56
  mouseEntered: boolean;
57
57
  controlsMouseEntered: boolean;
58
- seekedTime: number;
58
+ seekedTime: number | null;
59
59
  seekedPercentage: number;
60
60
  scrubbedPercentage: number;
61
61
  thumbPercentage: number;
62
- popoverOffsetX: number;
62
+ popoverOffsetX: number | null;
63
63
  hasOverlay: boolean;
64
64
  hasControls: boolean;
65
65
  controlsBarRect: DOMRect | undefined;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment",
3
3
  "description": "Our Frontend Toolkit, Free and Open Source",
4
- "version": "1.0.0-beta.27",
4
+ "version": "1.0.0-beta.29",
5
5
  "contributors": [
6
6
  {
7
7
  "name": "Robin Scholz",