@maas/vue-equipment 0.23.2 → 0.24.1

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,5 +1,5 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment/nuxt",
3
3
  "configKey": "vueEquipment",
4
- "version": "0.23.1"
4
+ "version": "0.24.0"
5
5
  }
@@ -46,7 +46,7 @@ const functions$1 = [
46
46
  {
47
47
  name: "MagicPlayer",
48
48
  "package": "plugins",
49
- lastUpdated: 1707404937000,
49
+ lastUpdated: 1709136225000,
50
50
  docs: "https://maas.egineering/vue-equipment/plugins/MagicPlayer/",
51
51
  description: "player"
52
52
  },
@@ -114,5 +114,5 @@ const {
114
114
  </script>
115
115
 
116
116
  <style>
117
- :root{--magic-cookie-max-width:480px;--magic-cookie-max-height:calc(100vh - 2rem);--magic-cookie-background-color:rgba(75,75,75,.5);--magic-cookie-backdrop-filter:blur(32px);--magic-cookie-color:#fff;--magic-cookie-border-radius:0;--magic-cookie-box-shadow:none;--magic-cookie-preferences-mask:linear-gradient(0deg,hsla(0,0%,100%,0),#fff 1.5rem);--magic-cookie-checkbox-size:0.875rem;--magic-cookie-checkbox-border-width:1px;--magic-cookie-checkbox-border-color:currentColor;--magic-cookie-checkbox-border-radius:0;--magic-cookie-button-width:auto;--magic-cookie-button-height:2.5rem;--magic-cookie-button-spacing:1rem;--magic-cookie-button-border-width:1px;--magic-cookie-button-border-radius:0.25rem;--magic-cookie-button-backdrop-filter:none;--magic-cookie-button-primary-color:#000;--magic-cookie-button-primary-background-color:#fff;--magic-cookie-button-primary-border-color:transparent;--magic-cookie-button-secondary-color:#fff;--magic-cookie-button-secondary-background-color:transparent;--magic-cookie-button-secondary-border-color:transparent}.magic-cookie{backdrop-filter:var(--magic-cookie-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-backdrop-filter);background-color:var(--magic-cookie-background-color);border-radius:var(--magic-cookie-border-radius);box-shadow:var(--magic-cookie-box-shadow);color:var(--magic-cookie-color);max-width:var(--magic-cookie-max-width);overflow:hidden}.magic-cookie,.magic-cookie__container{display:flex;flex-direction:column;width:100%}.magic-cookie__container{max-height:var(--magic-cookie-max-height)}.magic-cookie__body{display:flex;flex-direction:column;gap:1rem;height:100%;mask:var(--magic-cookie-preferences-mask);-webkit-mask:var(--magic-cookie-preferences-mask);overflow-y:scroll;padding:1rem;width:100%;-webkit-overflow-scrolling:touch;scroll-behavior:smooth;-ms-overflow-style:none;scrollbar-width:none}.magic-cookie__body::-webkit-scrollbar{display:none}.magic-cookie__footer{padding:1rem;width:100%}.magic-cookie__preferences{flex-direction:column;height:100%}.magic-cookie__actions,.magic-cookie__preferences{display:flex;gap:1rem;width:100%}ul.magic-cookie__cookies{display:flex;flex-direction:column;gap:1rem;list-style:none;margin:0;padding:0}li.magic-cookie__cookie{align-items:flex-start;display:flex;gap:1rem;margin:0;padding:0}.magic-cookie__cookie__content{align-items:flex-start;display:flex;flex-direction:column;gap:.25rem}.magic-cookie__cookie__title{display:inline-flex}.magic-cookie__cookie__text{white-space:pre-line}.magic-cookie-checkbox{align-items:center;display:flex;gap:.625rem}.magic-cookie-checkbox input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:var(--magic-cookie-checkbox-border-width) var(--magic-cookie-checkbox-border-color) solid;border-radius:var(--magic-cookie-checkbox-border-radius);cursor:pointer;flex-shrink:0;height:var(--magic-cookie-checkbox-size);position:relative;vertical-align:middle;width:var(--magic-cookie-checkbox-size)}.magic-cookie-checkbox input[type=checkbox]:checked:after{background-color:var(--magic-cookie-checkbox-border-color);border-radius:var(--magic-cookie-checkbox-border-radius);content:"";display:block;height:calc(var(--magic-cookie-checkbox-size)/2);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:calc(var(--magic-cookie-checkbox-size)/2)}.magic-cookie-checkbox:disabled{cursor:not-allowed}.magic-cookie-button{align-items:center;backdrop-filter:var(--magic-cookie-button-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-button-backdrop-filter);border:var(--magic-cookie-button-border-width) solid;border-radius:var(--magic-cookie-button-border-radius);display:inline-flex;gap:var(--magic-cookie-button-spacing);height:var(--magic-cookie-button-height);justify-content:center;padding:0 var(--magic-cookie-button-spacing);width:var(--magic-cookie-button-width)}.magic-cookie-button.-primary{background-color:var(--magic-cookie-button-primary-background-color);border-color:var(--magic-cookie-button-primary-border-color);color:var(--magic-cookie-button-primary-color)}.magic-cookie-button.-secondary{background-color:var(--magic-cookie-button-secondary-background-color);border-color:var(--magic-cookie-button-secondary-border-color);color:var(--magic-cookie-button-secondary-color)}
117
+ :root{--magic-cookie-max-width:480px;--magic-cookie-max-height:calc(100vh - 2rem);--magic-cookie-background:rgba(75,75,75,.5);--magic-cookie-backdrop-filter:blur(32px);--magic-cookie-color:#fff;--magic-cookie-border-radius:0;--magic-cookie-box-shadow:none;--magic-cookie-preferences-mask:linear-gradient(0deg,hsla(0,0%,100%,0),#fff 1.5rem);--magic-cookie-checkbox-size:0.875rem;--magic-cookie-checkbox-border-width:1px;--magic-cookie-checkbox-border-color:currentColor;--magic-cookie-checkbox-border-radius:0;--magic-cookie-button-width:auto;--magic-cookie-button-height:2.5rem;--magic-cookie-button-spacing:1rem;--magic-cookie-button-border-width:1px;--magic-cookie-button-border-radius:0.25rem;--magic-cookie-button-backdrop-filter:none;--magic-cookie-button-primary-color:#000;--magic-cookie-button-primary-background:#fff;--magic-cookie-button-primary-border-color:transparent;--magic-cookie-button-secondary-color:#fff;--magic-cookie-button-secondary-background:transparent;--magic-cookie-button-secondary-border-color:transparent}.magic-cookie{backdrop-filter:var(--magic-cookie-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-backdrop-filter);background-color:var(--magic-cookie-background);border-radius:var(--magic-cookie-border-radius);box-shadow:var(--magic-cookie-box-shadow);color:var(--magic-cookie-color);max-width:var(--magic-cookie-max-width);overflow:hidden}.magic-cookie,.magic-cookie__container{display:flex;flex-direction:column;width:100%}.magic-cookie__container{max-height:var(--magic-cookie-max-height)}.magic-cookie__body{display:flex;flex-direction:column;gap:1rem;height:100%;mask:var(--magic-cookie-preferences-mask);-webkit-mask:var(--magic-cookie-preferences-mask);overflow-y:scroll;padding:1rem;width:100%;-webkit-overflow-scrolling:touch;scroll-behavior:smooth;-ms-overflow-style:none;scrollbar-width:none}.magic-cookie__body::-webkit-scrollbar{display:none}.magic-cookie__footer{padding:1rem;width:100%}.magic-cookie__preferences{flex-direction:column;height:100%}.magic-cookie__actions,.magic-cookie__preferences{display:flex;gap:1rem;width:100%}ul.magic-cookie__cookies{display:flex;flex-direction:column;gap:1rem;list-style:none;margin:0;padding:0}li.magic-cookie__cookie{align-items:flex-start;display:flex;gap:1rem;margin:0;padding:0}.magic-cookie__cookie__content{align-items:flex-start;display:flex;flex-direction:column;gap:.25rem}.magic-cookie__cookie__title{display:inline-flex}.magic-cookie__cookie__text{white-space:pre-line}.magic-cookie-checkbox{align-items:center;display:flex;gap:.625rem}.magic-cookie-checkbox input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:var(--magic-cookie-checkbox-border-width) var(--magic-cookie-checkbox-border-color) solid;border-radius:var(--magic-cookie-checkbox-border-radius);cursor:pointer;flex-shrink:0;height:var(--magic-cookie-checkbox-size);position:relative;vertical-align:middle;width:var(--magic-cookie-checkbox-size)}.magic-cookie-checkbox input[type=checkbox]:checked:after{background-color:var(--magic-cookie-checkbox-border-color);border-radius:var(--magic-cookie-checkbox-border-radius);content:"";display:block;height:calc(var(--magic-cookie-checkbox-size)/2);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:calc(var(--magic-cookie-checkbox-size)/2)}.magic-cookie-checkbox:disabled{cursor:not-allowed}.magic-cookie-button{align-items:center;backdrop-filter:var(--magic-cookie-button-backdrop-filter);-webkit-backdrop-filter:var(--magic-cookie-button-backdrop-filter);border:var(--magic-cookie-button-border-width) solid;border-radius:var(--magic-cookie-button-border-radius);display:inline-flex;gap:var(--magic-cookie-button-spacing);height:var(--magic-cookie-button-height);justify-content:center;padding:0 var(--magic-cookie-button-spacing);width:var(--magic-cookie-button-width)}.magic-cookie-button.-primary{background-color:var(--magic-cookie-button-primary-background);border-color:var(--magic-cookie-button-primary-border-color);color:var(--magic-cookie-button-primary-color)}.magic-cookie-button.-secondary{background-color:var(--magic-cookie-button-secondary-background);border-color:var(--magic-cookie-button-secondary-border-color);color:var(--magic-cookie-button-secondary-color)}
118
118
  </style>
@@ -1,5 +1,7 @@
1
+ import MagicAudioPlayer from "./src/components/MagicAudioPlayer.vue";
1
2
  import MagicPlayer from "./src/components/MagicPlayer.vue";
2
3
  import MagicPlayerControls from "./src/components/MagicPlayerControls.vue";
4
+ import MagicPlayerCurrentTime from "./src/components/MagicPlayerCurrentTime.vue";
3
5
  import MagicPlayerMuxPopover from "./src/components/MagicPlayerMuxPopover.vue";
4
6
  import MagicPlayerOverlay from "./src/components/MagicPlayerOverlay.vue";
5
7
  import MagicPlayerPoster from "./src/components/MagicPlayerPoster.vue";
@@ -7,8 +9,10 @@ import MagicPlayerTimeline from "./src/components/MagicPlayerTimeline.vue";
7
9
  import { usePlayerApi } from "./src/composables/usePlayerApi.mjs";
8
10
  const MagicPlayerPlugin = {
9
11
  install: (app) => {
12
+ app.component("MagicAudioPlayer", MagicAudioPlayer);
10
13
  app.component("MagicPlayer", MagicPlayer);
11
14
  app.component("MagicPlayerControls", MagicPlayerControls);
15
+ app.component("MagicPlayerCurrentTime", MagicPlayerCurrentTime);
12
16
  app.component("MagicPlayerMuxPopover", MagicPlayerMuxPopover);
13
17
  app.component("MagicPlayerOverlay", MagicPlayerOverlay);
14
18
  app.component("MagicPlayerPoster", MagicPlayerPoster);
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <div
3
+ ref="playerRef"
4
+ class="magic-audio-player"
5
+ :class="{ '-slot': $slots.default }"
6
+ >
7
+ <div class="magic-audio-player__container">
8
+ <div v-if="$slots.default" class="magic-audio-player__slot">
9
+ <slot />
10
+ </div>
11
+ <magic-audio-player-controls :id="id" />
12
+ </div>
13
+ <audio ref="audioRef" class="magic-audio-player__audio" />
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import MagicAudioPlayerControls from './MagicAudioPlayerControls.vue'
19
+ import { ref, onMounted, onBeforeUnmount } from 'vue'
20
+ import { useIntersectionObserver } from '@vueuse/core'
21
+ import { usePlayerAudioApi } from '../composables/private/usePlayerAudioApi'
22
+ import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
23
+ import { usePlayerRuntime } from '../composables/private/usePlayerRuntime'
24
+
25
+ interface Props {
26
+ id: string
27
+ src: string
28
+ loop?: boolean
29
+ }
30
+
31
+ const props = withDefaults(defineProps<Props>(), {
32
+ src: '',
33
+ loop: false,
34
+ })
35
+
36
+ const playerRef = ref<HTMLDivElement | undefined>(undefined)
37
+ const audioRef = ref<HTMLVideoElement | undefined>(undefined)
38
+
39
+ const pausedByIntersection = ref(false)
40
+
41
+ const { playing } = usePlayerMediaApi({
42
+ id: props.id,
43
+ mediaRef: audioRef,
44
+ })
45
+
46
+ const { initialize, destroy } = usePlayerRuntime({
47
+ id: props.id,
48
+ mediaRef: audioRef,
49
+ src: props.src,
50
+ srcType: 'native',
51
+ })
52
+
53
+ const { play, pause } = usePlayerAudioApi({
54
+ id: props.id,
55
+ })
56
+
57
+ useIntersectionObserver(
58
+ playerRef,
59
+ ([{ isIntersecting }]) => {
60
+ if (!isIntersecting && playing.value) {
61
+ pause()
62
+ pausedByIntersection.value = true
63
+ } else if (isIntersecting && !playing.value && pausedByIntersection.value) {
64
+ pausedByIntersection.value = false
65
+
66
+ play()
67
+ }
68
+ },
69
+ {
70
+ immediate: true,
71
+ }
72
+ )
73
+
74
+ onMounted(() => {
75
+ initialize()
76
+ })
77
+
78
+ onBeforeUnmount(() => {
79
+ destroy()
80
+ })
81
+ </script>
82
+
83
+ <style>
84
+ :root{--magic-audio-player-color:#fff;--magic-audio-player-background:rgba(32,32,32,.8);--magic-audio-player-background-slot:hsla(0,0%,98%,.15);--magic-audio-player-backdrop-filter:blur(80px);--magic-audio-player-border-radius:1.25rem;--magic-audio-player-padding:0.25rem;--magic-audio-player-gap:0.25rem;--magic-audio-player-slot-padding:0.75rem 1rem;--magic-audio-player-slot-radius:calc(var(--magic-audio-player-border-radius) - var(--magic-audio-player-padding));--magic-audio-player-slot-background:rgba(32,32,32,.8)}.magic-audio-player{-webkit-backdrop-filter:var(--magic-audio-player-backdrop-filter);backdrop-filter:var(--magic-audio-player-backdrop-filter);background:var(--magic-audio-player-background);border-radius:var(--magic-audio-player-border-radius);color:var(--magic-audio-player-color);padding:var(--magic-audio-player-padding);position:relative;width:100%}.magic-audio-player.-slot{background:var(--magic-audio-player-background-slot)}.magic-audio-player__container{display:flex;flex-direction:column;gap:var(--magic-audio-player-gap);height:100%;position:relative;width:100%}.magic-audio-player__slot{background-color:var(--magic-audio-player-background);border-radius:var(--magic-audio-player-slot-radius);color:inherit;padding:var(--magic-audio-player-slot-padding)}.magic-audio-player__audio{width:100%}
85
+ </style>
@@ -0,0 +1,40 @@
1
+ interface Props {
2
+ id: string;
3
+ src: string;
4
+ loop?: boolean;
5
+ }
6
+ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
7
+ src: string;
8
+ loop: boolean;
9
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
10
+ src: string;
11
+ loop: boolean;
12
+ }>>>, {
13
+ src: string;
14
+ loop: boolean;
15
+ }, {}>, {
16
+ default?(_: {}): any;
17
+ }>;
18
+ export default _default;
19
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
20
+ type __VLS_TypePropsToRuntimeProps<T> = {
21
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
22
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
23
+ } : {
24
+ type: import('vue').PropType<T[K]>;
25
+ required: true;
26
+ };
27
+ };
28
+ type __VLS_WithDefaults<P, D> = {
29
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
30
+ default: D[K];
31
+ }> : P[K];
32
+ };
33
+ type __VLS_Prettify<T> = {
34
+ [K in keyof T]: T[K];
35
+ } & {};
36
+ type __VLS_WithTemplateSlots<T, S> = T & {
37
+ new (): {
38
+ $slots: S;
39
+ };
40
+ };
@@ -0,0 +1,94 @@
1
+ <template>
2
+ <div
3
+ class="magic-audio-player-controls"
4
+ :class="{
5
+ '-touched': touched,
6
+ '-untouched': !touched,
7
+ '-playing': playing,
8
+ '-paused': !playing,
9
+ '-waiting': waiting,
10
+ '-idle': idle,
11
+ '-not-idle': !idle,
12
+ '-hover': mouseEntered,
13
+ '-not-hover': !mouseEntered,
14
+ }"
15
+ >
16
+ <div class="magic-audio-player-controls__bar">
17
+ <div class="magic-audio-player-controls__bar--inner" ref="barRef">
18
+ <div class="magic-audio-player-controls__item -shrink-0">
19
+ <button v-if="!playing" @click="play">
20
+ <slot name="playIcon">
21
+ <icon-play />
22
+ </slot>
23
+ </button>
24
+ <button v-else @click="pause">
25
+ <slot name="pauseIcon">
26
+ <icon-pause />
27
+ </slot>
28
+ </button>
29
+ </div>
30
+ <div class="magic-audio-player-controls__item -shrink-0">
31
+ <magic-player-current-time :id="id" />
32
+ </div>
33
+ <div class="magic-audio-player-controls__item -grow">
34
+ <div class="magic-audio-player-controls__timeline" ref="trackRef">
35
+ <magic-player-timeline :id="id" />
36
+ </div>
37
+ </div>
38
+ <div class="magic-audio-player-controls__item -shrink-0">
39
+ <button v-if="muted" @click="unmute">
40
+ <slot name="volumeOffIcon">
41
+ <icon-volume-off />
42
+ </slot>
43
+ </button>
44
+ <button v-else @click="mute">
45
+ <slot name="volumeOnIcon">
46
+ <icon-volume-on />
47
+ </slot>
48
+ </button>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { ref } from 'vue'
57
+ import { useIdle } from '@vueuse/core'
58
+ import IconPlay from './icons/Play.vue'
59
+ import IconPause from './icons/Pause.vue'
60
+ import IconVolumeOn from './icons/VolumeOn.vue'
61
+ import IconVolumeOff from './icons/VolumeOff.vue'
62
+ import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
63
+ import { usePlayerAudioApi } from '../composables/private/usePlayerAudioApi'
64
+ import { usePlayerControlsApi } from '../composables/private/usePlayerControlsApi'
65
+
66
+ interface Props {
67
+ id: string
68
+ }
69
+
70
+ const props = defineProps<Props>()
71
+
72
+ const barRef = ref<HTMLDivElement | undefined>(undefined)
73
+ const trackRef = ref<HTMLDivElement | undefined>(undefined)
74
+
75
+ const { playing, waiting, muted } = usePlayerMediaApi({
76
+ id: props.id,
77
+ })
78
+
79
+ const { play, pause, mute, unmute, touched, mouseEntered } = usePlayerAudioApi({
80
+ id: props.id,
81
+ })
82
+
83
+ usePlayerControlsApi({
84
+ id: props.id,
85
+ barRef: barRef,
86
+ trackRef: trackRef,
87
+ })
88
+
89
+ const { idle } = useIdle(3000)
90
+ </script>
91
+
92
+ <style>
93
+ :root{--magic-audio-player-controls-height:3rem;--magic-audio-player-controls-padding:0rem;--magic-audio-player-controls-color:inherit;--magic-audio-player-controls-icon-width:1.25rem;--magic-audio-player-controls-button-width:4rem}.magic-audio-player-controls{pointer-events:none;width:100%}.magic-audio-player-controls__bar{align-items:flex-start;display:flex;flex-direction:column;margin:0 auto;pointer-events:auto;width:100%}.magic-audio-player-controls__bar--inner{align-items:center;box-sizing:border-box;color:var(--magic-audio-player-controls-color);display:flex;height:var(--magic-audio-player-controls-height);padding:0 var(--magic-audio-player-controls-padding);width:100%}.magic-audio-player-controls__item{align-items:center;display:inline-flex;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-audio-player-controls__item.-shrink-0{flex-shrink:0}.magic-audio-player-controls__item.-grow{flex-grow:1}.magic-audio-player-controls__item button{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;display:flex;height:var(--magic-audio-player-controls-height);justify-content:center;outline:none;padding:0;width:var(--magic-audio-player-controls-button-width)}.magic-audio-player-controls__item button svg{display:block;height:auto;width:var(--magic-audio-player-controls-icon-width)}.magic-audio-player-controls__timeline{width:100%}
94
+ </style>
@@ -0,0 +1,24 @@
1
+ interface Props {
2
+ id: string;
3
+ }
4
+ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>>, {}, {}>, {
5
+ playIcon?(_: {}): any;
6
+ pauseIcon?(_: {}): any;
7
+ volumeOffIcon?(_: {}): any;
8
+ volumeOnIcon?(_: {}): any;
9
+ }>;
10
+ export default _default;
11
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
12
+ type __VLS_TypePropsToRuntimeProps<T> = {
13
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
14
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
15
+ } : {
16
+ type: import('vue').PropType<T[K]>;
17
+ required: true;
18
+ };
19
+ };
20
+ type __VLS_WithTemplateSlots<T, S> = T & {
21
+ new (): {
22
+ $slots: S;
23
+ };
24
+ };
@@ -8,7 +8,7 @@
8
8
  >
9
9
  <video
10
10
  ref="videoRef"
11
- class="magic-player-video"
11
+ class="magic-player__video"
12
12
  preload="auto"
13
13
  playsinline
14
14
  disablePictureInPicture
@@ -112,5 +112,5 @@ onBeforeUnmount(() => {
112
112
  </script>
113
113
 
114
114
  <style>
115
- :root{--magic-player-aspect-ratio:16/9}.magic-player{aspect-ratio:var(--magic-player-aspect-ratio);overflow:hidden;position:relative;width:100%}.magic-player-video{height:100%;left:0;-o-object-fit:cover;object-fit:cover;position:absolute;top:0;width:100%}
115
+ :root{--magic-player-aspect-ratio:16/9}.magic-player{aspect-ratio:var(--magic-player-aspect-ratio);overflow:hidden;position:relative;width:100%}.magic-player__video{height:100%;left:0;-o-object-fit:cover;object-fit:cover;position:absolute;top:0;width:100%}
116
116
  </style>
@@ -121,7 +121,7 @@ const { idle } = useIdle(3000)
121
121
  </script>
122
122
 
123
123
  <style>
124
- :root{--magic-player-controls-height:3rem;--magic-player-controls-padding:0.75rem;--magic-player-controls-bottom:1.5rem;--magic-player-controls-left:1.5rem;--magic-player-controls-width:calc(100% - var(--magic-player-controls-left)*2);--magic-player-controls-gap:1rem;--magic-player-controls-border-radius:50rem;--magic-player-controls-background-color:rgba(32,32,32,.8);--magic-player-controls-backdrop-filter:blur(80px);--magic-player-controls-color:#fff;--magic-player-controls-icon-width:1.25rem;--magic-player-controls-transition-duration:300ms;--magic-player-controls-transition-timing-function:ease}@media (max-width:640px){:root{--magic-player-controls-height:2.5rem;--magic-player-controls-bottom:0.75rem;--magic-player-controls-padding:0.5rem}}.magic-player-controls{inset:0;pointer-events:none;position:absolute;width:100%}.magic-player-controls__bar{align-items:flex-start;bottom:var(--magic-player-controls-bottom);display:flex;flex-direction:column;gap:var(--magic-player-controls-gap);left:var(--magic-player-controls-left);margin:0 auto;pointer-events:auto;position:absolute;transition-duration:var(--magic-player-controls-transition-duration);transition-property:opacity,transform;transition-timing-function:var(
124
+ :root{--magic-player-controls-height:3rem;--magic-player-controls-padding:0.75rem;--magic-player-controls-bottom:1.5rem;--magic-player-controls-left:1.5rem;--magic-player-controls-width:calc(100% - var(--magic-player-controls-left)*2);--magic-player-controls-gap:1rem;--magic-player-controls-border-radius:50rem;--magic-player-controls-background:rgba(32,32,32,.8);--magic-player-controls-backdrop-filter:blur(80px);--magic-player-controls-color:#fff;--magic-player-controls-button-width:3rem;--magic-player-controls-icon-width:1.25rem;--magic-player-controls-transition-duration:300ms;--magic-player-controls-transition-timing-function:ease}@media (max-width:640px){:root{--magic-player-controls-height:2.5rem;--magic-player-controls-bottom:0.75rem;--magic-player-controls-padding:0.5rem}}.magic-player-controls{inset:0;pointer-events:none;position:absolute;width:100%}.magic-player-controls__bar{align-items:flex-start;bottom:var(--magic-player-controls-bottom);display:flex;flex-direction:column;gap:var(--magic-player-controls-gap);left:var(--magic-player-controls-left);margin:0 auto;pointer-events:auto;position:absolute;transition-duration:var(--magic-player-controls-transition-duration);transition-property:opacity,transform;transition-timing-function:var(
125
125
  --magic-player-controls-transition-timing-function
126
- );width:var(--magic-player-controls-width)}.magic-player-controls__bar--inner{align-items:center;-webkit-backdrop-filter:var(--magic-player-controls-backdrop-filter);backdrop-filter:var(--magic-player-controls-backdrop-filter);background-color:var(--magic-player-controls-background-color);border-radius:var(--magic-player-controls-border-radius);box-sizing:border-box;color:var(--magic-player-controls-color);display:flex;height:var(--magic-player-controls-height);padding:0 var(--magic-player-controls-padding);width:100%}.magic-player-controls__item{align-items:center;display:inline-flex;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-player-controls__item.-shrink-0{flex-shrink:0}.magic-player-controls__item.-grow{flex-grow:1}.magic-player-controls__item button{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;display:flex;height:var(--magic-player-controls-height);justify-content:center;outline:none;padding:0;width:var(--magic-player-controls-height)}.magic-player-controls__item button svg{display:block;height:auto;width:var(--magic-player-controls-icon-width)}.magic-player-controls__timeline{width:100%}.magic-player-controls:not(.-standalone).-playing.-idle .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-playing.-not-hover .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-untouched .magic-player-controls__bar{opacity:0;transform:translateY(25%)}.magic-player-controls.-standalone{inset:unset;position:relative;--magic-player-controls-width:100%;--magic-player-controls-bottom:0;--magic-player-controls-left:0;--magic-player-controls-padding:0;--magic-player-controls-background-color:unset;--magic-player-controls-border-radius:unset;--magic-player-controls-background-color:transparent;--magic-player-controls-backdrop-filter:none;--magic-player-controls-transition-duration:unset;--magic-player-controls-transition-timing-function:unset}.magic-player-controls.-standalone .magic-player-controls__bar{position:relative}
126
+ );width:var(--magic-player-controls-width)}.magic-player-controls__bar--inner{align-items:center;-webkit-backdrop-filter:var(--magic-player-controls-backdrop-filter);backdrop-filter:var(--magic-player-controls-backdrop-filter);background-color:var(--magic-player-controls-background);border-radius:var(--magic-player-controls-border-radius);box-sizing:border-box;color:var(--magic-player-controls-color);display:flex;height:var(--magic-player-controls-height);padding:0 var(--magic-player-controls-padding);width:100%}.magic-player-controls__item{align-items:center;display:inline-flex;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-player-controls__item.-shrink-0{flex-shrink:0}.magic-player-controls__item.-grow{flex-grow:1}.magic-player-controls__item button{align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;display:flex;height:var(--magic-player-controls-height);justify-content:center;outline:none;padding:0;width:var(--magic-player-controls-button-width)}.magic-player-controls__item button svg{display:block;height:auto;width:var(--magic-player-controls-icon-width)}.magic-player-controls__timeline{width:100%}.magic-player-controls:not(.-standalone).-playing.-idle .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-playing.-not-hover .magic-player-controls__bar,.magic-player-controls:not(.-standalone).-untouched .magic-player-controls__bar{opacity:0;transform:translateY(25%)}.magic-player-controls.-standalone{inset:unset;position:relative;--magic-player-controls-width:100%;--magic-player-controls-bottom:0;--magic-player-controls-left:0;--magic-player-controls-padding:0;--magic-player-controls-background:unset;--magic-player-controls-border-radius:unset;--magic-player-controls-background:transparent;--magic-player-controls-backdrop-filter:none;--magic-player-controls-transition-duration:unset;--magic-player-controls-transition-timing-function:unset}.magic-player-controls.-standalone .magic-player-controls__bar{position:relative}
127
127
  </style>
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <div class="magic-player-current-time">
3
+ {{ stringifiedTime }}
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { computed } from 'vue'
9
+ import { usePlayerMediaApi } from '../composables/private/usePlayerMediaApi'
10
+
11
+ interface Props {
12
+ id: string
13
+ }
14
+
15
+ const props = defineProps<Props>()
16
+
17
+ const { currentTime } = usePlayerMediaApi({
18
+ id: props.id,
19
+ })
20
+
21
+ function toNumber(value: string | number): number {
22
+ return typeof value === 'string' ? parseFloat(value) : Number(value)
23
+ }
24
+
25
+ const formatTime = function (seconds: number, guide: number) {
26
+ seconds = seconds < 0 ? 0 : seconds
27
+ let s: string | number = Math.floor(seconds % 60)
28
+ let m: string | number = Math.floor((seconds / 60) % 60)
29
+ let h: string | number = Math.floor(seconds / 3600)
30
+ const gm = Math.floor((guide / 60) % 60)
31
+ const gh = Math.floor(guide / 3600)
32
+
33
+ // handle invalid times
34
+ if (isNaN(seconds) || seconds === Infinity) {
35
+ // '-' is false for all relational operators (e.g. <, >=) so this setting
36
+ // will add the minimum number of fields specified by the guide
37
+ h = m = s = '-'
38
+ }
39
+
40
+ // Check if we need to show hours
41
+ h = toNumber(h) > 0 || gh > 0 ? h + ':' : ''
42
+
43
+ // If hours are showing, we may need to add a leading zero.
44
+ // Always show at least one digit of minutes.
45
+ m = ((h || gm >= 10) && toNumber(m) < 10 ? '0' + m : m) + ':'
46
+
47
+ // Check if leading zero is need for seconds
48
+ s = toNumber(s) < 10 ? '0' + s : s
49
+
50
+ return h + m + s
51
+ }
52
+
53
+ const stringifiedTime = computed(() => formatTime(currentTime.value, 60))
54
+ </script>
55
+
56
+ <style>
57
+ :root{--magic-player-current-time-font-size:0.875rem;--magic-player-current-time-color:inherit;--magic-player-current-time-width:3.25rem;--magic-player-current-time-justify-content:flex-start}.magic-player-current-time{align-items:center;color:var(--magic-player-current-time-color);display:flex;font-size:var(--magic-player-current-time-font-size);height:100%;justify-content:var(--magic-player-current-time-justify-content);width:var(--magic-player-current-time-width)}
58
+ </style>
@@ -0,0 +1,14 @@
1
+ interface Props {
2
+ id: string;
3
+ }
4
+ declare const _default: import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>>, {}, {}>;
5
+ export default _default;
6
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
7
+ type __VLS_TypePropsToRuntimeProps<T> = {
8
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
9
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
10
+ } : {
11
+ type: import('vue').PropType<T[K]>;
12
+ required: true;
13
+ };
14
+ };
@@ -60,5 +60,5 @@ const { idle } = useIdle(3000)
60
60
  </script>
61
61
 
62
62
  <style>
63
- :root{--magic-player-overlay-background-color:rgba(0,0,0,.3);--magic-player-overlay-color:#fff;--magic-player-overlay-button-size:2.5rem}.magic-player-overlay{align-items:center;background-color:var(--magic-player-overlay-background-color);color:var(--magic-player-overlay-color);cursor:pointer;display:flex;inset:0;justify-content:center;position:absolute;transition-duration:.3s;transition-property:opacity;transition-timing-function:ease}.magic-player-overlay__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;height:var(--magic-player-overlay-button-size);outline:none;padding:0;width:var(--magic-player-overlay-button-size)}.magic-player-overlay.-playing.-idle,.magic-player-overlay.-playing.-not-hover{opacity:0}
63
+ :root{--magic-player-overlay-background:rgba(0,0,0,.3);--magic-player-overlay-color:#fff;--magic-player-overlay-button-size:2.5rem}.magic-player-overlay{align-items:center;background-color:var(--magic-player-overlay-background);color:var(--magic-player-overlay-color);cursor:pointer;display:flex;inset:0;justify-content:center;position:absolute;transition-duration:.3s;transition-property:opacity;transition-timing-function:ease}.magic-player-overlay__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0;border-radius:0;color:inherit;cursor:pointer;height:var(--magic-player-overlay-button-size);outline:none;padding:0;width:var(--magic-player-overlay-button-size)}.magic-player-overlay.-playing.-idle,.magic-player-overlay.-playing.-not-hover{opacity:0}
64
64
  </style>
@@ -36,7 +36,6 @@
36
36
  </template>
37
37
 
38
38
  <script setup lang="ts">
39
- import { computed } from 'vue'
40
39
  import { usePlayerControlsApi } from '../composables/private/usePlayerControlsApi'
41
40
 
42
41
  interface Props {
@@ -59,12 +58,8 @@ const {
59
58
  } = usePlayerControlsApi({
60
59
  id: props.id,
61
60
  })
62
-
63
- const height = computed(() => {
64
- return trackRect.value?.height
65
- })
66
61
  </script>
67
62
 
68
63
  <style>
69
- :root{--magic-player-target-height:56px;--magic-player-track-height:4px;--magic-player-track-bg-color:hsla(0,0%,98%,.15);--magic-player-thumb-size:1rem;--magic-player-thumb-bg-color:#fafafa}.magic-player-timeline{height:var(--magic-player-track-height)}.magic-player-timeline,.magic-player-timeline__target{align-items:center;display:flex;position:relative;width:100%}.magic-player-timeline__target{cursor:pointer;height:var(--magic-player-target-height)}.magic-player-timeline__slider-track{background:var(--magic-player-track-bg-color);border-radius:50rem;height:var(--magic-player-track-height);position:relative;width:100%}.magic-player-timeline__slider-inner-track{border-radius:50rem;height:100%;left:0;overflow:hidden;position:relative;top:0;width:100%;z-index:1}.magic-player-timeline__slider-thumb{height:var(--magic-player-track-height);position:absolute;width:var(--magic-player-track-height);z-index:10}.magic-player-timeline__slider-thumb-handle{background-color:var(--magic-player-thumb-bg-color);border-radius:50rem;height:var(--magic-player-thumb-size);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:transform .3s ease;width:var(--magic-player-thumb-size);z-index:10}.magic-player-timeline__slider-buffered,.magic-player-timeline__slider-scrubbed,.magic-player-timeline__slider-seeked{background:currentColor;border-radius:50rem;height:100%;left:0;margin-left:calc(-100% + var(--magic-player-track-height));position:absolute;width:100%}.magic-player-timeline__slider-scrubbed{display:flex;min-width:var(--magic-player-track-height);z-index:1}.magic-player-timeline__slider-seeked{opacity:.25}.magic-player-timeline__slider-buffered{opacity:.15}.magic-player-timeline:hover .magic-player-timeline__slider-thumb-handle{transform:translate(-50%,-50%) scale(1)}.magic-player-timeline__seek-popover{bottom:100%;left:0;position:absolute;transform:translateX(-50%)}
64
+ :root{--magic-player-target-height:56px;--magic-player-track-height:4px;--magic-player-track-background:hsla(0,0%,98%,.15);--magic-player-thumb-size:1rem;--magic-player-thumb-background:#fafafa}.magic-player-timeline{height:var(--magic-player-track-height)}.magic-player-timeline,.magic-player-timeline__target{align-items:center;display:flex;position:relative;width:100%}.magic-player-timeline__target{cursor:pointer;height:var(--magic-player-target-height)}.magic-player-timeline__slider-track{background:var(--magic-player-track-background);border-radius:50rem;height:var(--magic-player-track-height);position:relative;width:100%}.magic-player-timeline__slider-inner-track{border-radius:50rem;height:100%;left:0;overflow:hidden;position:relative;top:0;width:100%;z-index:1}.magic-player-timeline__slider-thumb{height:var(--magic-player-track-height);position:absolute;width:var(--magic-player-track-height);z-index:10}.magic-player-timeline__slider-thumb-handle{background-color:var(--magic-player-thumb-background);border-radius:50rem;height:var(--magic-player-thumb-size);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:transform .3s ease;width:var(--magic-player-thumb-size);z-index:10}.magic-player-timeline__slider-buffered,.magic-player-timeline__slider-scrubbed,.magic-player-timeline__slider-seeked{background:currentColor;border-radius:50rem;height:100%;left:0;margin-left:calc(-100% + var(--magic-player-track-height));position:absolute;width:100%}.magic-player-timeline__slider-scrubbed{display:flex;min-width:var(--magic-player-track-height);z-index:1}.magic-player-timeline__slider-seeked{opacity:.25}.magic-player-timeline__slider-buffered{opacity:.15}.magic-player-timeline:hover .magic-player-timeline__slider-thumb-handle{transform:translate(-50%,-50%) scale(1)}.magic-player-timeline__seek-popover{bottom:100%;left:0;position:absolute;transform:translateX(-50%)}
70
65
  </style>
@@ -0,0 +1,17 @@
1
+ import { type MaybeRef } from 'vue';
2
+ export type UsePlayerAudioApiArgs = {
3
+ id: MaybeRef<string>;
4
+ };
5
+ export declare function usePlayerAudioApi(args: UsePlayerAudioApiArgs): {
6
+ mouseEntered: import("vue").Ref<boolean>;
7
+ touched: import("vue").Ref<boolean>;
8
+ play: () => void;
9
+ pause: () => void;
10
+ togglePlay: () => void;
11
+ seek: (time: number) => void;
12
+ mute: () => void;
13
+ unmute: () => void;
14
+ onMouseenter: () => void;
15
+ onMouseleave: () => void;
16
+ };
17
+ export type UsePlayerAudioApiReturn = ReturnType<typeof usePlayerAudioApi>;
@@ -0,0 +1,82 @@
1
+ import { ref, watch, toValue } from "vue";
2
+ import { usePlayerStateEmitter } from "./usePlayerStateEmitter.mjs";
3
+ import { usePlayerMediaApi } from "./usePlayerMediaApi.mjs";
4
+ export function usePlayerAudioApi(args) {
5
+ const { playing, currentTime, muted } = usePlayerMediaApi({
6
+ id: args.id
7
+ });
8
+ const touched = ref(false);
9
+ const mouseEntered = ref(false);
10
+ function play() {
11
+ playing.value = true;
12
+ }
13
+ function pause() {
14
+ playing.value = false;
15
+ }
16
+ function togglePlay() {
17
+ playing.value = !playing.value;
18
+ }
19
+ function seek(time) {
20
+ currentTime.value = time;
21
+ }
22
+ function mute() {
23
+ muted.value = true;
24
+ }
25
+ function unmute() {
26
+ muted.value = false;
27
+ }
28
+ function onMouseenter() {
29
+ mouseEntered.value = true;
30
+ }
31
+ function onMouseleave() {
32
+ mouseEntered.value = false;
33
+ }
34
+ watch(playing, (value) => {
35
+ if (!touched.value && value) {
36
+ touched.value = true;
37
+ }
38
+ });
39
+ const emitter = usePlayerStateEmitter();
40
+ emitter.on("update", (payload) => {
41
+ if (payload.id !== toValue(args.id))
42
+ return;
43
+ if (payload.api === "player") {
44
+ switch (payload.key) {
45
+ case "mouseEntered":
46
+ mouseEntered.value = payload.value;
47
+ break;
48
+ case "touched":
49
+ touched.value = payload.value;
50
+ break;
51
+ }
52
+ }
53
+ });
54
+ watch(mouseEntered, (value) => {
55
+ emitter.emit("update", {
56
+ id: toValue(args.id),
57
+ api: "player",
58
+ key: "mouseEntered",
59
+ value
60
+ });
61
+ });
62
+ watch(touched, (value) => {
63
+ emitter.emit("update", {
64
+ id: toValue(args.id),
65
+ api: "player",
66
+ key: "touched",
67
+ value
68
+ });
69
+ });
70
+ return {
71
+ mouseEntered,
72
+ touched,
73
+ play,
74
+ pause,
75
+ togglePlay,
76
+ seek,
77
+ mute,
78
+ unmute,
79
+ onMouseenter,
80
+ onMouseleave
81
+ };
82
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment",
3
3
  "description": "A magic collection of Vue composables, plugins, components and directives",
4
- "version": "0.23.2",
4
+ "version": "0.24.1",
5
5
  "author": "Robin Scholz <https://github.com/robinscholz>, Christoph Jeworutzki <https://github.com/ChristophJeworutzki>",
6
6
  "devDependencies": {
7
7
  "@antfu/ni": "^0.21.12",
@@ -50,7 +50,7 @@
50
50
  "mitt": "^3.0.1",
51
51
  "motion": "^10.16.2",
52
52
  "nuxt": "^3.5.1",
53
- "universal-cookie": "^7.0.2"
53
+ "universal-cookie": "^7.1.0"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "@maas/magic-timer": {