@nuxt/scripts 0.3.3 → 0.3.4

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 (62) hide show
  1. package/dist/client/200.html +5 -5
  2. package/dist/client/404.html +5 -5
  3. package/dist/client/_nuxt/{B-3dzucQ.js → B4lN06_-.js} +1 -1
  4. package/dist/client/_nuxt/{D-T6Aidr.js → Bcyt2NVQ.js} +1 -1
  5. package/dist/client/_nuxt/{CmaBlQfy.js → DaX43REz.js} +1 -1
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/d2381002-a578-4bfe-a659-00ae20f09aa2.json +1 -0
  8. package/dist/client/_nuxt/oEMCrPza.js +31 -0
  9. package/dist/client/index.html +5 -5
  10. package/dist/module.d.mts +2 -2
  11. package/dist/module.d.ts +2 -2
  12. package/dist/module.json +1 -1
  13. package/dist/module.mjs +60 -32
  14. package/dist/registry.d.mts +2 -2
  15. package/dist/registry.d.ts +2 -2
  16. package/dist/registry.mjs +16 -16
  17. package/dist/runtime/components/ScriptGoogleMaps.vue +264 -0
  18. package/dist/runtime/components/ScriptLemonSqueezyButton.vue +42 -0
  19. package/dist/runtime/components/ScriptLoadingIndicator.vue +15 -0
  20. package/dist/runtime/components/ScriptStripePricingTable.vue +47 -0
  21. package/dist/runtime/components/ScriptVimeoPlayer.vue +243 -0
  22. package/dist/runtime/components/ScriptYouTubePlayer.vue +160 -0
  23. package/dist/runtime/composables/useElementScriptTrigger.d.ts +3 -3
  24. package/dist/runtime/composables/useElementScriptTrigger.mjs +41 -5
  25. package/dist/runtime/composables/useScript.mjs +6 -4
  26. package/dist/runtime/registry/cloudflare-web-analytics.mjs +2 -2
  27. package/dist/runtime/registry/fathom-analytics.d.ts +2 -2
  28. package/dist/runtime/registry/fathom-analytics.mjs +2 -2
  29. package/dist/runtime/registry/google-analytics.d.ts +4 -2
  30. package/dist/runtime/registry/google-analytics.mjs +13 -8
  31. package/dist/runtime/registry/google-maps.mjs +2 -2
  32. package/dist/runtime/registry/google-tag-manager.mjs +2 -2
  33. package/dist/runtime/registry/hotjar.mjs +4 -4
  34. package/dist/runtime/registry/intercom.mjs +3 -8
  35. package/dist/runtime/registry/lemon-squeezy.d.ts +1 -2
  36. package/dist/runtime/registry/lemon-squeezy.mjs +3 -6
  37. package/dist/runtime/registry/matomo-analytics.mjs +11 -10
  38. package/dist/runtime/registry/{facebook-pixel.d.ts → meta-pixel.d.ts} +7 -7
  39. package/dist/runtime/registry/{facebook-pixel.mjs → meta-pixel.mjs} +9 -7
  40. package/dist/runtime/registry/npm.mjs +2 -2
  41. package/dist/runtime/registry/plausible-analytics.mjs +2 -2
  42. package/dist/runtime/registry/segment.d.ts +22 -9
  43. package/dist/runtime/registry/segment.mjs +43 -21
  44. package/dist/runtime/registry/stripe.mjs +4 -4
  45. package/dist/runtime/registry/vimeo-player.d.ts +6 -6
  46. package/dist/runtime/registry/vimeo-player.mjs +30 -34
  47. package/dist/runtime/registry/x-pixel.mjs +17 -13
  48. package/dist/runtime/registry/youtube-player.d.ts +14 -0
  49. package/dist/runtime/registry/{youtube-iframe.mjs → youtube-player.mjs} +22 -20
  50. package/dist/runtime/types.d.ts +33 -16
  51. package/dist/runtime/types.mjs +2 -0
  52. package/dist/runtime/utils.d.ts +3 -2
  53. package/dist/runtime/utils.mjs +15 -13
  54. package/package.json +6 -6
  55. package/dist/client/_nuxt/CMNIl2hT.js +0 -31
  56. package/dist/client/_nuxt/builds/meta/8b865286-abcf-4201-a2af-ee13e4478155.json +0 -1
  57. package/dist/runtime/components/GoogleMaps.vue +0 -130
  58. package/dist/runtime/components/LemonSqueezyButton.vue +0 -28
  59. package/dist/runtime/components/StripePricingTableEmbed.vue +0 -33
  60. package/dist/runtime/components/VimeoEmbed.vue +0 -161
  61. package/dist/runtime/components/YouTubeEmbed.vue +0 -79
  62. package/dist/runtime/registry/youtube-iframe.d.ts +0 -15
@@ -0,0 +1,264 @@
1
+ <script lang="ts" setup>
2
+ /// <reference types="google.maps" />
3
+ import {
4
+ type HTMLAttributes,
5
+ type ImgHTMLAttributes,
6
+ type Ref,
7
+ type ReservedProps,
8
+ computed,
9
+ onBeforeUnmount,
10
+ onMounted,
11
+ ref,
12
+ watch,
13
+ } from 'vue'
14
+ import { type QueryObject, withQuery } from 'ufo'
15
+ import { defu } from 'defu'
16
+ import type { ElementScriptTrigger } from '../composables/useElementScriptTrigger'
17
+ import { scriptRuntimeConfig } from '../utils'
18
+ import { resolveComponent, useElementScriptTrigger, useHead, useScriptGoogleMaps } from '#imports'
19
+
20
+ interface PlaceholderOptions {
21
+ width?: string | number
22
+ height?: string | number
23
+ center?: string
24
+ zoom?: number
25
+ size?: string
26
+ scale?: number
27
+ format?: 'png' | 'jpg' | 'gif' | 'png8' | 'png32' | 'jpg-baseline'
28
+ maptype?: 'roadmap' | 'satellite' | 'terrain' | 'hybrid'
29
+ language?: string
30
+ region?: string
31
+ markers?: string
32
+ path?: string
33
+ visible?: string
34
+ style?: string
35
+ map_id?: string
36
+ key?: string
37
+ signature?: string
38
+ }
39
+
40
+ const props = withDefaults(defineProps<{
41
+ /**
42
+ * Defines the trigger event to load the script.
43
+ */
44
+ trigger?: ElementScriptTrigger
45
+ /**
46
+ * Is Google Maps being rendered above the fold?
47
+ * This will load the placeholder image with higher priority.
48
+ */
49
+ aboveTheFold?: boolean
50
+ /**
51
+ * Defines the Google Maps API key. Must have access to the Static Maps API as well.
52
+ */
53
+ apiKey: string
54
+ /**
55
+ * Defines map marker location.
56
+ */
57
+ query?: string
58
+ /**
59
+ * Options for the map.
60
+ */
61
+ options?: google.maps.MapOptions
62
+ /**
63
+ * Defines the width of the map.
64
+ */
65
+ width?: number | string
66
+ /**
67
+ * Defines the height of the map
68
+ */
69
+ height?: number | string
70
+ /**
71
+ * Customize the placeholder image attributes.
72
+ *
73
+ * @see https://developers.google.com/maps/documentation/maps-static/start.
74
+ */
75
+ placeholderOptions?: PlaceholderOptions
76
+ /**
77
+ * Customize the placeholder image attributes.
78
+ */
79
+ placeholderAttrs?: ImgHTMLAttributes & ReservedProps & Record<string, unknown>
80
+ /**
81
+ * Customize the root element attributes.
82
+ */
83
+ rootAttrs?: HTMLAttributes & ReservedProps & Record<string, unknown>
84
+ }>(), {
85
+ // @ts-expect-error untyped
86
+ trigger: ['mouseenter', 'mouseover', 'mousedown'],
87
+ width: 600,
88
+ height: 400,
89
+ })
90
+
91
+ const emits = defineEmits<{
92
+ // our emit
93
+ ready: [e: Ref<google.maps.Map | undefined>]
94
+ }>()
95
+
96
+ const apiKey = props.apiKey || scriptRuntimeConfig('googleMaps')?.apiKey
97
+
98
+ if (!apiKey)
99
+ throw new Error('GoogleMaps requires an API key. Please provide `apiKey` on the <ScriptGoogleMaps> or globally via `runtimeConfig.public.scripts.googleMaps.apiKey`.')
100
+ if (!props.query && !props.options?.center)
101
+ throw new Error('GoogleMaps requires either a query or center prop to be set.')
102
+
103
+ const rootEl = ref<HTMLElement>()
104
+ const mapEl = ref<HTMLElement>()
105
+
106
+ const { $script } = useScriptGoogleMaps({
107
+ apiKey: props.apiKey,
108
+ scriptOptions: {
109
+ trigger: useElementScriptTrigger({ trigger: props.trigger, el: rootEl }),
110
+ },
111
+ })
112
+
113
+ const options = computed(() => {
114
+ return defu(props.options, {
115
+ zoom: 15,
116
+ mapId: 'map',
117
+ })
118
+ })
119
+ const ready = ref(false)
120
+
121
+ function queryToLocation(service: google.maps.places.PlacesService, query: string) {
122
+ return new Promise<google.maps.LatLng>((resolve, reject) => {
123
+ service.findPlaceFromQuery({
124
+ query,
125
+ fields: ['name', 'geometry'],
126
+ }, (results, status) => {
127
+ if (status === 'OK' && results?.[0]?.geometry?.location)
128
+ return resolve(results[0].geometry.location)
129
+ return reject(new Error(`No location found for ${query}`))
130
+ })
131
+ })
132
+ }
133
+
134
+ const map: Ref<google.maps.Map | undefined> = ref()
135
+ const markers: Ref<google.maps.marker.AdvancedMarkerElement[]> = ref([])
136
+ defineExpose({
137
+ map,
138
+ markers,
139
+ })
140
+
141
+ onMounted(() => {
142
+ watch(ready, (v) => {
143
+ v && emits('ready', map)
144
+ })
145
+ // create the map
146
+ $script.then(async (instance) => {
147
+ const maps = await instance.maps as typeof google.maps
148
+ const _map = new maps.Map(mapEl.value!, options.value)
149
+ const placesService = new maps.places.PlacesService(_map)
150
+
151
+ watch(options, () => _map.setOptions(options.value))
152
+ watch(() => props.query, async (query) => {
153
+ // always clear old markers
154
+ markers.value.forEach(marker => marker.remove())
155
+ markers.value = []
156
+ if (query) {
157
+ const marker = await maps.importLibrary('marker') as google.maps.MarkerLibrary
158
+ const location = await queryToLocation(placesService, query).catch((err) => {
159
+ console.warn(err)
160
+ return {
161
+ lat: 0,
162
+ lng: 0,
163
+ }
164
+ })
165
+ _map.setCenter(location)
166
+ markers.value.push(new marker.AdvancedMarkerElement({
167
+ map: _map,
168
+ position: location,
169
+ }))
170
+ ready.value = true
171
+ }
172
+ }, {
173
+ immediate: !!props.query,
174
+ })
175
+ if (!props.query)
176
+ ready.value = true
177
+ map.value = _map
178
+ })
179
+ })
180
+
181
+ if (import.meta.server) {
182
+ useHead({
183
+ link: [
184
+ {
185
+ rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
186
+ href: 'https://maps.googleapis.com',
187
+ },
188
+ ],
189
+ })
190
+ }
191
+
192
+ const placeholder = computed(() => {
193
+ const placeholderOptions: PlaceholderOptions = defu(props.placeholderOptions, {
194
+ // only map option values
195
+ zoom: options.value.zoom,
196
+ center: options.value.center?.toString() || '',
197
+ }, {
198
+ size: `${props.width}x${props.height}`,
199
+ key: apiKey,
200
+ scale: 2, // we assume a high DPI to avoid hydration issues
201
+ markers: `color:red|${props.query}`,
202
+ })
203
+ return withQuery('https://maps.googleapis.com/maps/api/staticmap', placeholderOptions as QueryObject)
204
+ })
205
+
206
+ const placeholderAttrs = computed(() => {
207
+ return defu(props.placeholderAttrs, {
208
+ src: placeholder.value,
209
+ alt: props.query || '',
210
+ loading: props.aboveTheFold ? 'eager' : 'lazy',
211
+ style: {
212
+ cursor: 'pointer',
213
+ width: '100%',
214
+ objectFit: 'cover',
215
+ height: '100%',
216
+ },
217
+ } satisfies ImgHTMLAttributes)
218
+ })
219
+
220
+ const rootAttrs = computed(() => {
221
+ return defu(props.rootAttrs, {
222
+ 'aria-busy': $script.status.value === 'loading',
223
+ 'aria-label': $script.status.value === 'awaitingLoad'
224
+ ? 'Google Maps Static Map'
225
+ : $script.status.value === 'loading'
226
+ ? 'Google Maps Map Embed Loading'
227
+ : 'Google Maps Embed',
228
+ 'aria-live': 'polite',
229
+ 'role': 'application',
230
+ 'style': {
231
+ cursor: 'pointer',
232
+ position: 'relative',
233
+ maxWidth: '100%',
234
+ width: `${props.width}px`,
235
+ height: `'auto'`,
236
+ aspectRatio: `${props.width}/${props.height}`,
237
+ },
238
+ }) as HTMLAttributes
239
+ })
240
+
241
+ const ScriptLoadingIndicator = resolveComponent('ScriptLoadingIndicator')
242
+
243
+ onBeforeUnmount(() => {
244
+ markers.value.forEach(marker => marker.remove())
245
+ markers.value = []
246
+ map.value?.unbindAll()
247
+ map.value = undefined
248
+ mapEl.value?.firstChild?.remove()
249
+ })
250
+ </script>
251
+
252
+ <template>
253
+ <div ref="rootEl" v-bind="rootAttrs">
254
+ <div v-show="ready" ref="mapEl" class="script-google-maps__map" :style="{ width: '100%', height: '100%', maxWidth: '100%' }" />
255
+ <slot v-if="!ready" :placeholder="placeholder" name="placeholder">
256
+ <img v-bind="placeholderAttrs">
257
+ </slot>
258
+ <slot v-if="$script.status.value === 'loading'" name="loading">
259
+ <ScriptLoadingIndicator color="black" />
260
+ </slot>
261
+ <slot v-if="$script.status.value === 'awaitingLoad'" name="awaitingLoad" />
262
+ <slot />
263
+ </div>
264
+ </template>
@@ -0,0 +1,42 @@
1
+ <script lang="ts" setup>
2
+ import { type ElementScriptTrigger, onMounted, ref, useElementScriptTrigger, useScriptLemonSqueezy } from '#imports'
3
+
4
+ const props = withDefaults(defineProps<{
5
+ trigger?: ElementScriptTrigger
6
+ href: string
7
+ }>(), {
8
+ trigger: 'visible',
9
+ })
10
+
11
+ const emits = defineEmits<{
12
+ event: [{ event: string, data?: Record<string, any> }]
13
+ }>()
14
+
15
+ const rootEl = ref<HTMLElement | null>(null)
16
+ const { $script } = useScriptLemonSqueezy({
17
+ scriptOptions: {
18
+ trigger: useElementScriptTrigger({ trigger: props.trigger, el: rootEl }),
19
+ },
20
+ })
21
+ onMounted(() => {
22
+ // @ts-expect-error untyped
23
+ $script.then(({ Setup }) => {
24
+ Setup({
25
+ // @ts-expect-error untyped
26
+ eventHandler(event) {
27
+ emits('event', event)
28
+ },
29
+ })
30
+ })
31
+ })
32
+ </script>
33
+
34
+ <template>
35
+ <div ref="rootEl">
36
+ <slot v-bind="{ class: 'lemonsqueezy-button', href }">
37
+ <a :href="href" class="lemonsqueezy-button">
38
+ Buy me
39
+ </a>
40
+ </slot>
41
+ </div>
42
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ withDefaults(defineProps<{
3
+ color?: string
4
+ }>(), {
5
+ color: 'currentColor',
6
+ })
7
+ </script>
8
+
9
+ <template>
10
+ <div class="loader" aria-label="Loading..." role="status" />
11
+ </template>
12
+
13
+ <style scoped>
14
+ .loader{animation:rotation 1s linear infinite;border:5px solid v-bind(color);border-bottom-color:transparent;border-radius:50%;bottom:12px;box-sizing:border-box;display:inline-block;height:30px;left:12px;opacity:.5;position:absolute;width:30px}@keyframes rotation{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
15
+ </style>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import type { ElementScriptTrigger } from '../composables/useElementScriptTrigger'
4
+ import { useElementScriptTrigger, useScript } from '#imports'
5
+
6
+ const props = withDefaults(defineProps<{
7
+ trigger?: ElementScriptTrigger
8
+ publishableKey: string
9
+ pricingTableId: string
10
+ clientReferenceId?: string
11
+ customerEmail?: string
12
+ customerSessionClientSecret?: string
13
+ }>(), {
14
+ trigger: 'visible',
15
+ })
16
+
17
+ const emit = defineEmits<{
18
+ ready: []
19
+ }>()
20
+
21
+ const rootEl = ref()
22
+ const { $script } = useScript(`https://js.stripe.com/v3/pricing-table.js`, {
23
+ trigger: useElementScriptTrigger({ trigger: props.trigger, el: rootEl }),
24
+ })
25
+
26
+ $script.then(() => {
27
+ emit('ready')
28
+ })
29
+ </script>
30
+
31
+ <template>
32
+ <div ref="rootEl">
33
+ <ClientOnly>
34
+ <stripe-pricing-table
35
+ v-bind="$attrs"
36
+ :publishable-key="publishableKey"
37
+ :pricing-table-id="pricingTableId"
38
+ :client-reference-id="clientReferenceId"
39
+ :customer-email="customerEmail"
40
+ :customer-session-client-secret="customerSessionClientSecret"
41
+ />
42
+ </ClientOnly>
43
+ <slot v-if="$script.status.value === 'loading'" name="loading" />
44
+ <slot v-if="$script.status.value === 'awaitingLoad'" name="awaitingLoad" />
45
+ <slot />
46
+ </div>
47
+ </template>
@@ -0,0 +1,243 @@
1
+ <script setup lang="ts">
2
+ import { type HTMLAttributes, type ImgHTMLAttributes, computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
3
+ import type Player from 'vimeo__player'
4
+ import type { EventMap, VimeoVideoQuality } from 'vimeo__player'
5
+ import { defu } from 'defu'
6
+ import type { ElementScriptTrigger } from '../composables/useElementScriptTrigger'
7
+ import { useAsyncData, useElementScriptTrigger, useHead, useScriptVimeoPlayer } from '#imports'
8
+
9
+ const props = withDefaults(defineProps<{
10
+ // custom
11
+ trigger?: ElementScriptTrigger
12
+ placeholderAttrs?: ImgHTMLAttributes
13
+ rootAttrs?: HTMLAttributes
14
+ aboveTheFold?: boolean
15
+ // copied from @types/vimeo__player
16
+ id: string | number | undefined
17
+ url?: string | undefined
18
+ autopause?: boolean | undefined
19
+ autoplay?: boolean | undefined
20
+ background?: boolean | undefined
21
+ byline?: boolean | undefined
22
+ color?: string | undefined
23
+ controls?: boolean | undefined
24
+ dnt?: boolean | undefined
25
+ height?: number | undefined
26
+ // eslint-disable-next-line vue/prop-name-casing
27
+ interactive_params?: string | undefined
28
+ keyboard?: boolean | undefined
29
+ loop?: boolean | undefined
30
+ maxheight?: number | undefined
31
+ maxwidth?: number | undefined
32
+ muted?: boolean | undefined
33
+ pip?: boolean | undefined
34
+ playsinline?: boolean | undefined
35
+ portrait?: boolean | undefined
36
+ responsive?: boolean | undefined
37
+ speed?: boolean | undefined
38
+ quality?: VimeoVideoQuality | undefined
39
+ texttrack?: string | undefined
40
+ title?: boolean | undefined
41
+ transparent?: boolean | undefined
42
+ width?: number | undefined
43
+ }>(), {
44
+ trigger: 'mousedown',
45
+ width: 640,
46
+ height: 480,
47
+ loop: false,
48
+ controls: true,
49
+ })
50
+
51
+ const emits = defineEmits<{
52
+ play: [e: EventMap['play'], player: Player]
53
+ playing: [e: EventMap['playing'], player: Player]
54
+ pause: [e: EventMap['pause'], player: Player]
55
+ ended: [e: EventMap['ended'], player: Player]
56
+ timeupdate: [e: EventMap['timeupdate'], player: Player]
57
+ progress: [e: EventMap['progress'], player: Player]
58
+ seeking: [e: EventMap['seeking'], player: Player]
59
+ seeked: [e: EventMap['seeked'], player: Player]
60
+ texttrackchange: [e: EventMap['texttrackchange'], player: Player]
61
+ chapterchange: [e: EventMap['chapterchange'], player: Player]
62
+ cuechange: [e: EventMap['cuechange'], player: Player]
63
+ cuepoint: [e: EventMap['cuepoint'], player: Player]
64
+ volumechange: [e: EventMap['volumechange'], player: Player]
65
+ playbackratechange: [e: EventMap['playbackratechange'], player: Player]
66
+ bufferstart: [e: EventMap['bufferstart'], player: Player]
67
+ bufferend: [e: EventMap['bufferend'], player: Player]
68
+ error: [e: EventMap['error'], player: Player]
69
+ loaded: [e: EventMap['loaded'], player: Player]
70
+ durationchange: [e: EventMap['durationchange'], player: Player]
71
+ fullscreenchange: [e: EventMap['fullscreenchange'], player: Player]
72
+ qualitychange: [e: EventMap['qualitychange'], player: Player]
73
+ camerachange: [e: EventMap['camerachange'], player: Player]
74
+ resize: [e: EventMap['resize'], player: Player]
75
+ enterpictureinpicture: [e: EventMap['enterpictureinpicture'], player: Player]
76
+ leavepictureinpicture: [e: EventMap['leavepictureinpicture'], player: Player]
77
+ }>()
78
+
79
+ const events = [
80
+ 'play',
81
+ 'playing',
82
+ 'pause',
83
+ 'ended',
84
+ 'timeupdate',
85
+ 'progress',
86
+ 'seeking',
87
+ 'seeked',
88
+ 'texttrackchange',
89
+ 'chapterchange',
90
+ 'cuechange',
91
+ 'cuepoint',
92
+ 'volumechange',
93
+ 'playbackratechange',
94
+ 'bufferstart',
95
+ 'bufferend',
96
+ 'error',
97
+ 'loaded',
98
+ 'durationchange',
99
+ 'fullscreenchange',
100
+ 'qualitychange',
101
+ 'camerachange',
102
+ 'resize',
103
+ ]
104
+
105
+ const elVimeo = ref()
106
+ const rootEl = ref()
107
+
108
+ const trigger = useElementScriptTrigger({ trigger: props.trigger, el: rootEl })
109
+ let clickTriggered = false
110
+ if (props.trigger === 'mousedown') {
111
+ trigger.then(() => {
112
+ clickTriggered = true
113
+ })
114
+ }
115
+ const ready = ref(false)
116
+ const { $script } = useScriptVimeoPlayer({
117
+ scriptOptions: {
118
+ trigger,
119
+ },
120
+ })
121
+
122
+ if (import.meta.server) {
123
+ // dns-prefetch https://i.vimeocdn.com
124
+ useHead({
125
+ link: [
126
+ {
127
+ rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
128
+ href: 'https://i.vimeocdn.com',
129
+ },
130
+ ],
131
+ })
132
+ }
133
+
134
+ const { data: payload } = useAsyncData(
135
+ `vimeo-embed:${props.id}`,
136
+ // TODO ideally we cache this
137
+ () => $fetch(`https://vimeo.com/api/v2/video/${props.id}.json`).then(res => res[0]),
138
+ {
139
+ watch: [() => props.id],
140
+ },
141
+ )
142
+
143
+ const placeholder = computed(() => payload.value?.thumbnail_large)
144
+
145
+ let player: Player | undefined
146
+ // we can't directly expose the player as vue will break the proxy
147
+ defineExpose({
148
+ play: () => player?.play(),
149
+ pause: () => player?.pause(),
150
+ getDuration: () => player?.getDuration(),
151
+ getCurrentTime: () => player?.getCurrentTime(),
152
+ setCurrentTime: (time: number) => player?.setCurrentTime(time),
153
+ getVolume: () => player?.getVolume(),
154
+ setVolume: (volume: number) => player?.setVolume(volume),
155
+ getPaused: () => player?.getPaused(),
156
+ getEnded: () => player?.getEnded(),
157
+ getLoop: () => player?.getLoop(),
158
+ setLoop: (loop: boolean) => player?.setLoop(loop),
159
+ getPlaybackRate: () => player?.getPlaybackRate(),
160
+ setPlaybackRate: (rate: number) => player?.setPlaybackRate(rate),
161
+ })
162
+ onMounted(() => {
163
+ $script.then(async ({ Vimeo }) => {
164
+ // filter props for false values
165
+ player = new Vimeo.Player(elVimeo.value, {
166
+ ...props,
167
+ url: encodeURI(`https://vimeo.com/${props.id}`),
168
+ })
169
+ if (clickTriggered) {
170
+ player!.play()
171
+ clickTriggered = false
172
+ }
173
+ for (const event of events) {
174
+ player!.on(event, (e) => {
175
+ emits(event, e, player)
176
+ if (event === 'loaded')
177
+ ready.value = true
178
+ })
179
+ }
180
+ })
181
+
182
+ watch(() => props.id, (v) => {
183
+ v && player?.loadVideo(Number(v))
184
+ })
185
+ })
186
+
187
+ const rootAttrs = computed(() => {
188
+ return defu(props.rootAttrs, {
189
+ 'aria-busy': $script.status.value === 'loading',
190
+ 'aria-label': $script.status.value === 'awaitingLoad'
191
+ ? 'Vimeo Player - Placeholder'
192
+ : $script.status.value === 'loading'
193
+ ? 'Vimeo Player - Loading'
194
+ : 'Vimeo Player - Loaded',
195
+ 'aria-live': 'polite',
196
+ 'role': 'application',
197
+ 'style': {
198
+ maxWidth: '100%',
199
+ width: `${props.width}px`,
200
+ height: `'auto'`,
201
+ aspectRatio: `${props.width}/${props.height}`,
202
+ position: 'relative',
203
+ backgroundColor: 'black',
204
+ },
205
+ }) as HTMLAttributes
206
+ })
207
+
208
+ const placeholderAttrs = computed(() => {
209
+ return defu(props.placeholderAttrs, {
210
+ src: placeholder.value,
211
+ alt: '',
212
+ loading: props.aboveTheFold ? 'eager' : 'lazy',
213
+ // @ts-expect-error untyped
214
+ fetchpriority: props.aboveTheFold ? 'high' : undefined,
215
+ style: {
216
+ cursor: 'pointer',
217
+ width: '100%',
218
+ objectFit: 'contain',
219
+ height: '100%',
220
+ },
221
+ } satisfies ImgHTMLAttributes)
222
+ })
223
+
224
+ onBeforeUnmount(() => player?.unload())
225
+ </script>
226
+
227
+ <template>
228
+ <div ref="rootEl" v-bind="rootAttrs">
229
+ <div v-show="ready" ref="elVimeo" class="vimeo-player" style="width: 100%; height: 100%; max-width: 100%;" />
230
+ <slot v-if="!ready" v-bind="payload" :placeholder="placeholder" name="placeholder">
231
+ <img v-if="placeholder" v-bind="placeholderAttrs">
232
+ </slot>
233
+ <slot v-if="$script.status.value === 'loading'" name="loading">
234
+ <ScriptLoadingIndicator color="white" />
235
+ </slot>
236
+ <slot v-if="$script.status.value === 'awaitingLoad'" name="awaitingLoad" />
237
+ <slot />
238
+ </div>
239
+ </template>
240
+
241
+ <style>
242
+ .vimeo-player iframe{max-width:100%!important}
243
+ </style>