@nuxt/scripts 0.10.4 → 0.11.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.
- package/README.md +71 -71
- package/dist/client/200.html +10 -13
- package/dist/client/404.html +10 -13
- package/dist/client/_nuxt/{BP_4hZ94.js → BFM-Ncmx.js} +1 -1
- package/dist/client/_nuxt/{CHw4dS8l.js → BSA2bgdb.js} +1 -1
- package/dist/client/_nuxt/CtQNcfGE.js +1 -0
- package/dist/client/_nuxt/DuCkB5R-.js +21 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/e03354ab-f2ce-4d6b-8542-7b38262b3671.json +1 -0
- package/dist/client/_nuxt/{entry.OK28jpwG.css → entry.ipQkUTQD.css} +1 -1
- package/dist/client/_nuxt/error-404.BdjopNsg.css +1 -0
- package/dist/client/_nuxt/error-500.Bd7Z7Q7I.css +1 -0
- package/dist/client/index.html +10 -13
- package/dist/module.json +2 -2
- package/dist/module.mjs +7 -13
- package/dist/runtime/components/ScriptAriaLoadingIndicator.vue +5 -5
- package/dist/runtime/components/ScriptCarbonAds.vue +83 -83
- package/dist/runtime/components/ScriptCrisp.vue +94 -94
- package/dist/runtime/components/ScriptGoogleAdsense.vue +93 -92
- package/dist/runtime/components/ScriptGoogleMaps.vue +469 -469
- package/dist/runtime/components/ScriptIntercom.vue +103 -103
- package/dist/runtime/components/ScriptLemonSqueezy.vue +52 -52
- package/dist/runtime/components/ScriptLoadingIndicator.vue +22 -22
- package/dist/runtime/components/ScriptStripePricingTable.vue +74 -74
- package/dist/runtime/components/ScriptVimeoPlayer.vue +289 -289
- package/dist/runtime/components/ScriptYouTubePlayer.vue +215 -215
- package/dist/runtime/composables/useScript.d.ts +8 -4
- package/dist/runtime/composables/useScript.js +10 -59
- package/dist/runtime/composables/useScriptTriggerConsent.js +18 -8
- package/dist/runtime/registry/google-analytics.js +0 -3
- package/dist/runtime/registry/google-maps.d.ts +4 -10
- package/dist/runtime/registry/google-tag-manager.js +0 -3
- package/dist/runtime/registry/matomo-analytics.js +0 -4
- package/dist/runtime/registry/segment.js +0 -18
- package/dist/runtime/types.d.ts +4 -3
- package/dist/runtime/utils.js +1 -1
- package/package.json +32 -35
- package/dist/client/_nuxt/CVO1_9PV.js +0 -1
- package/dist/client/_nuxt/D0r3Knsf.js +0 -1
- package/dist/client/_nuxt/DH2VihVY.js +0 -1
- package/dist/client/_nuxt/builds/meta/bdb8796b-4a60-4f87-8abb-1f993f2e6be1.json +0 -1
- package/dist/client/_nuxt/eRX7aRp1.js +0 -168
- package/dist/client/_nuxt/error-404.uksU7Oj7.css +0 -1
- package/dist/client/_nuxt/error-500.V_etBug4.css +0 -1
- package/dist/client/_nuxt/ySlJ1b_l.js +0 -1
|
@@ -1,215 +1,215 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
-
// @ts-nocheck
|
|
4
|
-
|
|
5
|
-
/// <reference types="youtube" />
|
|
6
|
-
import { computed, onMounted, ref, watch } from 'vue'
|
|
7
|
-
import type { HTMLAttributes, ImgHTMLAttributes, Ref } from 'vue'
|
|
8
|
-
import { defu } from 'defu'
|
|
9
|
-
import { useHead } from '@unhead/vue'
|
|
10
|
-
import type { ElementScriptTrigger } from '../types'
|
|
11
|
-
import { useScriptTriggerElement } from '../composables/useScriptTriggerElement'
|
|
12
|
-
import { useScriptYouTubePlayer } from '../registry/youtube-player'
|
|
13
|
-
import ScriptAriaLoadingIndicator from './ScriptAriaLoadingIndicator.vue'
|
|
14
|
-
|
|
15
|
-
export type YoutubeThumbnailSize =
|
|
16
|
-
// 120x90
|
|
17
|
-
'1' | '2' | '3' | 'default' |
|
|
18
|
-
// 320x180
|
|
19
|
-
'mq1' | 'mq2' | 'mq3' | 'mqdefault' |
|
|
20
|
-
// 480x360
|
|
21
|
-
'0' | 'hq1' | 'hq2' | 'hq3' | 'hqdefault' |
|
|
22
|
-
// 640x480
|
|
23
|
-
'sd1' | 'sd2' | 'sd3' | 'sddefault' |
|
|
24
|
-
// 1280x720
|
|
25
|
-
'hq720' |
|
|
26
|
-
// 1920x1080
|
|
27
|
-
'maxresdefault'
|
|
28
|
-
|
|
29
|
-
const props = withDefaults(defineProps<{
|
|
30
|
-
placeholderAttrs?: ImgHTMLAttributes
|
|
31
|
-
rootAttrs?: HTMLAttributes
|
|
32
|
-
aboveTheFold?: boolean
|
|
33
|
-
trigger?: ElementScriptTrigger
|
|
34
|
-
videoId: string
|
|
35
|
-
playerVars?: YT.PlayerVars
|
|
36
|
-
width?: number
|
|
37
|
-
height?: number
|
|
38
|
-
/**
|
|
39
|
-
* Whether to use youtube-nocookie.com for embedding.
|
|
40
|
-
*
|
|
41
|
-
* @default false
|
|
42
|
-
*/
|
|
43
|
-
cookies?: boolean
|
|
44
|
-
playerOptions?: YT.PlayerOptions
|
|
45
|
-
thumbnailSize?: YoutubeThumbnailSize
|
|
46
|
-
webp?: boolean
|
|
47
|
-
}>(), {
|
|
48
|
-
cookies: false,
|
|
49
|
-
trigger: 'mousedown',
|
|
50
|
-
thumbnailSize: 'hq720',
|
|
51
|
-
webp: true,
|
|
52
|
-
// @ts-expect-error untyped
|
|
53
|
-
playerVars: { autoplay: 0, playsinline: 1 },
|
|
54
|
-
width: 640,
|
|
55
|
-
height: 360,
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const emits = defineEmits<{
|
|
59
|
-
'ready': [e: YT.PlayerEvent]
|
|
60
|
-
'state-change': [e: YT.OnStateChangeEvent, target: YT.Player]
|
|
61
|
-
'playback-quality-change': [e: YT.OnPlaybackQualityChangeEvent, target: YT.Player]
|
|
62
|
-
'playback-rate-change': [e: YT.OnPlaybackRateChangeEvent, target: YT.Player]
|
|
63
|
-
'error': [e: YT.OnErrorEvent, target: YT.Player]
|
|
64
|
-
}>()
|
|
65
|
-
const events: (keyof YT.Events)[] = [
|
|
66
|
-
'onReady',
|
|
67
|
-
'onStateChange',
|
|
68
|
-
'onPlaybackQualityChange',
|
|
69
|
-
'onPlaybackRateChange',
|
|
70
|
-
'onError',
|
|
71
|
-
'onApiChange',
|
|
72
|
-
]
|
|
73
|
-
const rootEl = ref()
|
|
74
|
-
const youtubeEl = ref()
|
|
75
|
-
const ready = ref(false)
|
|
76
|
-
const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl })
|
|
77
|
-
const script = useScriptYouTubePlayer({
|
|
78
|
-
scriptOptions: {
|
|
79
|
-
trigger,
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
const { onLoaded, status } = script
|
|
83
|
-
|
|
84
|
-
const player: Ref<YT.Player | undefined> = ref()
|
|
85
|
-
let clickTriggered = false
|
|
86
|
-
if (props.trigger === 'mousedown' && trigger instanceof Promise) {
|
|
87
|
-
trigger.then((triggered) => {
|
|
88
|
-
if (triggered) {
|
|
89
|
-
clickTriggered = true
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
onMounted(() => {
|
|
94
|
-
onLoaded(async (instance) => {
|
|
95
|
-
const YouTube = instance.YT instanceof Promise ? await instance.YT : instance.YT
|
|
96
|
-
await new Promise<void>((resolve) => {
|
|
97
|
-
if (typeof YT.Player === 'undefined')
|
|
98
|
-
YouTube.ready(resolve)
|
|
99
|
-
else
|
|
100
|
-
resolve()
|
|
101
|
-
})
|
|
102
|
-
player.value = new YT.Player(youtubeEl.value, {
|
|
103
|
-
host: !props.cookies ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
|
|
104
|
-
...props,
|
|
105
|
-
...props.playerOptions,
|
|
106
|
-
events: Object.fromEntries(events.map(event => [event, (e: any) => {
|
|
107
|
-
const emitEventName = event.replace(/([A-Z])/g, '-$1').replace('on-', '').toLowerCase()
|
|
108
|
-
// @ts-expect-error untyped
|
|
109
|
-
emits(emitEventName, e)
|
|
110
|
-
if (event === 'onReady') {
|
|
111
|
-
ready.value = true
|
|
112
|
-
if (clickTriggered) {
|
|
113
|
-
player.value?.playVideo()
|
|
114
|
-
clickTriggered = false
|
|
115
|
-
}
|
|
116
|
-
watch(() => props.videoId, () => {
|
|
117
|
-
player.value?.loadVideoById(props.videoId)
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
}])),
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
watch(status, (status) => {
|
|
124
|
-
if (status === 'error') {
|
|
125
|
-
// @ts-expect-error untyped
|
|
126
|
-
emits('error')
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
defineExpose({
|
|
132
|
-
player,
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
const rootAttrs = computed(() => {
|
|
136
|
-
return defu(props.rootAttrs, {
|
|
137
|
-
'aria-busy': status.value === 'loading',
|
|
138
|
-
'aria-label': status.value === 'awaitingLoad'
|
|
139
|
-
? 'YouTube Player - Placeholder'
|
|
140
|
-
: status.value === 'loading'
|
|
141
|
-
? 'YouTube Player - Loading'
|
|
142
|
-
: 'YouTube Player - Loaded',
|
|
143
|
-
'aria-live': 'polite',
|
|
144
|
-
'role': 'application',
|
|
145
|
-
'style': {
|
|
146
|
-
cursor: 'pointer',
|
|
147
|
-
position: 'relative',
|
|
148
|
-
backgroundColor: 'black',
|
|
149
|
-
width: '100%',
|
|
150
|
-
aspectRatio: `${props.width}/${props.height}`,
|
|
151
|
-
},
|
|
152
|
-
...(trigger instanceof Promise ? trigger.ssrAttrs || {} : {}),
|
|
153
|
-
}) as HTMLAttributes
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
const fallbackPlaceHolder = computed(() => `https://i.ytimg.com/vi/${props.videoId}/hqdefault.jpg`)
|
|
157
|
-
const placeholder = computed(() => `https://i.ytimg.com/${props.webp ? 'vi_webp' : 'vi'}/${props.videoId}/${props.thumbnailSize}.${props.webp ? 'webp' : 'jpg'}`)
|
|
158
|
-
const isFallbackPlaceHolder = ref(false)
|
|
159
|
-
|
|
160
|
-
if (import.meta.server) {
|
|
161
|
-
// dns-prefetch https://i.vimeocdn.com
|
|
162
|
-
useHead({
|
|
163
|
-
link: [
|
|
164
|
-
{
|
|
165
|
-
key: `nuxt-script-youtube-img`,
|
|
166
|
-
rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
|
|
167
|
-
href: 'https://i.ytimg.com',
|
|
168
|
-
},
|
|
169
|
-
props.aboveTheFold
|
|
170
|
-
// we can preload the placeholder image
|
|
171
|
-
? {
|
|
172
|
-
key: `nuxt-script-youtube-img`,
|
|
173
|
-
rel: 'preload',
|
|
174
|
-
as: 'image',
|
|
175
|
-
href: placeholder.value,
|
|
176
|
-
}
|
|
177
|
-
: {},
|
|
178
|
-
],
|
|
179
|
-
})
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const placeholderAttrs = computed(() => {
|
|
183
|
-
return defu(props.placeholderAttrs, {
|
|
184
|
-
src: isFallbackPlaceHolder.value ? fallbackPlaceHolder.value : placeholder.value,
|
|
185
|
-
alt: '',
|
|
186
|
-
loading: props.aboveTheFold ? 'eager' : 'lazy',
|
|
187
|
-
style: {
|
|
188
|
-
width: '100%',
|
|
189
|
-
objectFit: 'contain',
|
|
190
|
-
height: '100%',
|
|
191
|
-
},
|
|
192
|
-
onLoad(payload) {
|
|
193
|
-
const img = payload.target as HTMLImageElement
|
|
194
|
-
if (img.naturalWidth === 120 && img.naturalHeight === 90) {
|
|
195
|
-
isFallbackPlaceHolder.value = true
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
} satisfies ImgHTMLAttributes)
|
|
199
|
-
})
|
|
200
|
-
</script>
|
|
201
|
-
|
|
202
|
-
<template>
|
|
203
|
-
<div ref="rootEl" v-bind="rootAttrs">
|
|
204
|
-
<div ref="youtubeEl" style="width: 100%; height: 100%; position: absolute; top: 0; left: 0;" />
|
|
205
|
-
<slot v-if="!ready" :placeholder="placeholder" name="placeholder">
|
|
206
|
-
<img v-bind="placeholderAttrs">
|
|
207
|
-
</slot>
|
|
208
|
-
<slot v-if="status === 'loading'" name="loading">
|
|
209
|
-
<ScriptAriaLoadingIndicator />
|
|
210
|
-
</slot>
|
|
211
|
-
<slot v-if="status === 'awaitingLoad'" name="awaitingLoad" />
|
|
212
|
-
<slot v-else-if="status === 'error'" name="error" />
|
|
213
|
-
<slot />
|
|
214
|
-
</div>
|
|
215
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
/// <reference types="youtube" />
|
|
6
|
+
import { computed, onMounted, ref, watch } from 'vue'
|
|
7
|
+
import type { HTMLAttributes, ImgHTMLAttributes, Ref } from 'vue'
|
|
8
|
+
import { defu } from 'defu'
|
|
9
|
+
import { useHead } from '@unhead/vue'
|
|
10
|
+
import type { ElementScriptTrigger } from '../types'
|
|
11
|
+
import { useScriptTriggerElement } from '../composables/useScriptTriggerElement'
|
|
12
|
+
import { useScriptYouTubePlayer } from '../registry/youtube-player'
|
|
13
|
+
import ScriptAriaLoadingIndicator from './ScriptAriaLoadingIndicator.vue'
|
|
14
|
+
|
|
15
|
+
export type YoutubeThumbnailSize =
|
|
16
|
+
// 120x90
|
|
17
|
+
'1' | '2' | '3' | 'default' |
|
|
18
|
+
// 320x180
|
|
19
|
+
'mq1' | 'mq2' | 'mq3' | 'mqdefault' |
|
|
20
|
+
// 480x360
|
|
21
|
+
'0' | 'hq1' | 'hq2' | 'hq3' | 'hqdefault' |
|
|
22
|
+
// 640x480
|
|
23
|
+
'sd1' | 'sd2' | 'sd3' | 'sddefault' |
|
|
24
|
+
// 1280x720
|
|
25
|
+
'hq720' |
|
|
26
|
+
// 1920x1080
|
|
27
|
+
'maxresdefault'
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<{
|
|
30
|
+
placeholderAttrs?: ImgHTMLAttributes
|
|
31
|
+
rootAttrs?: HTMLAttributes
|
|
32
|
+
aboveTheFold?: boolean
|
|
33
|
+
trigger?: ElementScriptTrigger
|
|
34
|
+
videoId: string
|
|
35
|
+
playerVars?: YT.PlayerVars
|
|
36
|
+
width?: number
|
|
37
|
+
height?: number
|
|
38
|
+
/**
|
|
39
|
+
* Whether to use youtube-nocookie.com for embedding.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
cookies?: boolean
|
|
44
|
+
playerOptions?: YT.PlayerOptions
|
|
45
|
+
thumbnailSize?: YoutubeThumbnailSize
|
|
46
|
+
webp?: boolean
|
|
47
|
+
}>(), {
|
|
48
|
+
cookies: false,
|
|
49
|
+
trigger: 'mousedown',
|
|
50
|
+
thumbnailSize: 'hq720',
|
|
51
|
+
webp: true,
|
|
52
|
+
// @ts-expect-error untyped
|
|
53
|
+
playerVars: { autoplay: 0, playsinline: 1 },
|
|
54
|
+
width: 640,
|
|
55
|
+
height: 360,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const emits = defineEmits<{
|
|
59
|
+
'ready': [e: YT.PlayerEvent]
|
|
60
|
+
'state-change': [e: YT.OnStateChangeEvent, target: YT.Player]
|
|
61
|
+
'playback-quality-change': [e: YT.OnPlaybackQualityChangeEvent, target: YT.Player]
|
|
62
|
+
'playback-rate-change': [e: YT.OnPlaybackRateChangeEvent, target: YT.Player]
|
|
63
|
+
'error': [e: YT.OnErrorEvent, target: YT.Player]
|
|
64
|
+
}>()
|
|
65
|
+
const events: (keyof YT.Events)[] = [
|
|
66
|
+
'onReady',
|
|
67
|
+
'onStateChange',
|
|
68
|
+
'onPlaybackQualityChange',
|
|
69
|
+
'onPlaybackRateChange',
|
|
70
|
+
'onError',
|
|
71
|
+
'onApiChange',
|
|
72
|
+
]
|
|
73
|
+
const rootEl = ref()
|
|
74
|
+
const youtubeEl = ref()
|
|
75
|
+
const ready = ref(false)
|
|
76
|
+
const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl })
|
|
77
|
+
const script = useScriptYouTubePlayer({
|
|
78
|
+
scriptOptions: {
|
|
79
|
+
trigger,
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
const { onLoaded, status } = script
|
|
83
|
+
|
|
84
|
+
const player: Ref<YT.Player | undefined> = ref()
|
|
85
|
+
let clickTriggered = false
|
|
86
|
+
if (props.trigger === 'mousedown' && trigger instanceof Promise) {
|
|
87
|
+
trigger.then((triggered) => {
|
|
88
|
+
if (triggered) {
|
|
89
|
+
clickTriggered = true
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
onMounted(() => {
|
|
94
|
+
onLoaded(async (instance) => {
|
|
95
|
+
const YouTube = instance.YT instanceof Promise ? await instance.YT : instance.YT
|
|
96
|
+
await new Promise<void>((resolve) => {
|
|
97
|
+
if (typeof YT.Player === 'undefined')
|
|
98
|
+
YouTube.ready(resolve)
|
|
99
|
+
else
|
|
100
|
+
resolve()
|
|
101
|
+
})
|
|
102
|
+
player.value = new YT.Player(youtubeEl.value, {
|
|
103
|
+
host: !props.cookies ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
|
|
104
|
+
...props,
|
|
105
|
+
...props.playerOptions,
|
|
106
|
+
events: Object.fromEntries(events.map(event => [event, (e: any) => {
|
|
107
|
+
const emitEventName = event.replace(/([A-Z])/g, '-$1').replace('on-', '').toLowerCase()
|
|
108
|
+
// @ts-expect-error untyped
|
|
109
|
+
emits(emitEventName, e)
|
|
110
|
+
if (event === 'onReady') {
|
|
111
|
+
ready.value = true
|
|
112
|
+
if (clickTriggered) {
|
|
113
|
+
player.value?.playVideo()
|
|
114
|
+
clickTriggered = false
|
|
115
|
+
}
|
|
116
|
+
watch(() => props.videoId, () => {
|
|
117
|
+
player.value?.loadVideoById(props.videoId)
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}])),
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
watch(status, (status) => {
|
|
124
|
+
if (status === 'error') {
|
|
125
|
+
// @ts-expect-error untyped
|
|
126
|
+
emits('error')
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
defineExpose({
|
|
132
|
+
player,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const rootAttrs = computed(() => {
|
|
136
|
+
return defu(props.rootAttrs, {
|
|
137
|
+
'aria-busy': status.value === 'loading',
|
|
138
|
+
'aria-label': status.value === 'awaitingLoad'
|
|
139
|
+
? 'YouTube Player - Placeholder'
|
|
140
|
+
: status.value === 'loading'
|
|
141
|
+
? 'YouTube Player - Loading'
|
|
142
|
+
: 'YouTube Player - Loaded',
|
|
143
|
+
'aria-live': 'polite',
|
|
144
|
+
'role': 'application',
|
|
145
|
+
'style': {
|
|
146
|
+
cursor: 'pointer',
|
|
147
|
+
position: 'relative',
|
|
148
|
+
backgroundColor: 'black',
|
|
149
|
+
width: '100%',
|
|
150
|
+
aspectRatio: `${props.width}/${props.height}`,
|
|
151
|
+
},
|
|
152
|
+
...(trigger instanceof Promise ? trigger.ssrAttrs || {} : {}),
|
|
153
|
+
}) as HTMLAttributes
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const fallbackPlaceHolder = computed(() => `https://i.ytimg.com/vi/${props.videoId}/hqdefault.jpg`)
|
|
157
|
+
const placeholder = computed(() => `https://i.ytimg.com/${props.webp ? 'vi_webp' : 'vi'}/${props.videoId}/${props.thumbnailSize}.${props.webp ? 'webp' : 'jpg'}`)
|
|
158
|
+
const isFallbackPlaceHolder = ref(false)
|
|
159
|
+
|
|
160
|
+
if (import.meta.server) {
|
|
161
|
+
// dns-prefetch https://i.vimeocdn.com
|
|
162
|
+
useHead({
|
|
163
|
+
link: [
|
|
164
|
+
{
|
|
165
|
+
key: `nuxt-script-youtube-img`,
|
|
166
|
+
rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
|
|
167
|
+
href: 'https://i.ytimg.com',
|
|
168
|
+
},
|
|
169
|
+
props.aboveTheFold
|
|
170
|
+
// we can preload the placeholder image
|
|
171
|
+
? {
|
|
172
|
+
key: `nuxt-script-youtube-img`,
|
|
173
|
+
rel: 'preload',
|
|
174
|
+
as: 'image',
|
|
175
|
+
href: placeholder.value,
|
|
176
|
+
}
|
|
177
|
+
: {},
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const placeholderAttrs = computed(() => {
|
|
183
|
+
return defu(props.placeholderAttrs, {
|
|
184
|
+
src: isFallbackPlaceHolder.value ? fallbackPlaceHolder.value : placeholder.value,
|
|
185
|
+
alt: '',
|
|
186
|
+
loading: props.aboveTheFold ? 'eager' : 'lazy',
|
|
187
|
+
style: {
|
|
188
|
+
width: '100%',
|
|
189
|
+
objectFit: 'contain',
|
|
190
|
+
height: '100%',
|
|
191
|
+
},
|
|
192
|
+
onLoad(payload) {
|
|
193
|
+
const img = payload.target as HTMLImageElement
|
|
194
|
+
if (img.naturalWidth === 120 && img.naturalHeight === 90) {
|
|
195
|
+
isFallbackPlaceHolder.value = true
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
} satisfies ImgHTMLAttributes)
|
|
199
|
+
})
|
|
200
|
+
</script>
|
|
201
|
+
|
|
202
|
+
<template>
|
|
203
|
+
<div ref="rootEl" v-bind="rootAttrs">
|
|
204
|
+
<div ref="youtubeEl" style="width: 100%; height: 100%; position: absolute; top: 0; left: 0;" />
|
|
205
|
+
<slot v-if="!ready" :placeholder="placeholder" name="placeholder">
|
|
206
|
+
<img v-bind="placeholderAttrs">
|
|
207
|
+
</slot>
|
|
208
|
+
<slot v-if="status === 'loading'" name="loading">
|
|
209
|
+
<ScriptAriaLoadingIndicator />
|
|
210
|
+
</slot>
|
|
211
|
+
<slot v-if="status === 'awaitingLoad'" name="awaitingLoad" />
|
|
212
|
+
<slot v-else-if="status === 'error'" name="error" />
|
|
213
|
+
<slot />
|
|
214
|
+
</div>
|
|
215
|
+
</template>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { UseScriptInput } from '@unhead/vue';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { UseScriptInput } from '@unhead/vue/scripts';
|
|
2
|
+
import type { NuxtUseScriptOptions, UseScriptContext } from '../types.js';
|
|
3
|
+
type UseFunctionType<T, U> = T extends {
|
|
4
|
+
use: infer V;
|
|
5
|
+
} ? V extends (...args: any) => any ? ReturnType<V> : U : U;
|
|
6
|
+
export declare function resolveScriptKey(input: any): string;
|
|
7
|
+
export declare function useScript<T extends Record<symbol | string, any> = Record<symbol | string, any>>(input: UseScriptInput, options?: NuxtUseScriptOptions<T>): UseScriptContext<UseFunctionType<NuxtUseScriptOptions<T>, T>>;
|
|
8
|
+
export {};
|
|
@@ -1,45 +1,12 @@
|
|
|
1
|
-
import { resolveScriptKey } from "unhead";
|
|
2
1
|
import { defu } from "defu";
|
|
3
|
-
import { useScript as _useScript
|
|
4
|
-
import { parseURL } from "ufo";
|
|
5
|
-
import { onNuxtReady, useHead, useNuxtApp, useRuntimeConfig } from "nuxt/app";
|
|
2
|
+
import { useScript as _useScript } from "@unhead/vue/scripts";
|
|
6
3
|
import { reactive } from "vue";
|
|
7
|
-
import {
|
|
4
|
+
import { onNuxtReady, useNuxtApp, useRuntimeConfig, injectHead } from "#imports";
|
|
8
5
|
function useNuxtScriptRuntimeConfig() {
|
|
9
6
|
return useRuntimeConfig().public["nuxt-scripts"];
|
|
10
7
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function warmup(_, rel, head) {
|
|
14
|
-
const { src } = _;
|
|
15
|
-
const $url = parseURL(src);
|
|
16
|
-
const isPreconnect = rel && PreconnectServerModes.includes(rel);
|
|
17
|
-
const href = isPreconnect ? `${$url.protocol}${$url.host}` : src;
|
|
18
|
-
const isCrossOrigin = !!$url.host;
|
|
19
|
-
if (!rel || isPreconnect && !isCrossOrigin) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const link = {
|
|
23
|
-
href,
|
|
24
|
-
rel,
|
|
25
|
-
...pick(_, [
|
|
26
|
-
// shared keys between script and link
|
|
27
|
-
"crossorigin",
|
|
28
|
-
"referrerpolicy",
|
|
29
|
-
"fetchpriority",
|
|
30
|
-
"integrity"
|
|
31
|
-
// ignore id
|
|
32
|
-
])
|
|
33
|
-
};
|
|
34
|
-
const defaults = { fetchpriority: "low" };
|
|
35
|
-
if (rel === "preload") {
|
|
36
|
-
defaults.as = "script";
|
|
37
|
-
}
|
|
38
|
-
if (isCrossOrigin) {
|
|
39
|
-
defaults.crossorigin = "anonymous";
|
|
40
|
-
defaults.referrerpolicy = "no-referrer";
|
|
41
|
-
}
|
|
42
|
-
return useHead({ link: [defu(link, defaults)] }, { head, tagPriority: "high" });
|
|
8
|
+
export function resolveScriptKey(input) {
|
|
9
|
+
return input.key || input.src || (typeof input.innerHTML === "string" ? input.innerHTML : "");
|
|
43
10
|
}
|
|
44
11
|
export function useScript(input, options) {
|
|
45
12
|
input = typeof input === "string" ? { src: input } : input;
|
|
@@ -49,33 +16,17 @@ export function useScript(input, options) {
|
|
|
49
16
|
const head = options.head || injectHead();
|
|
50
17
|
nuxtApp.$scripts = nuxtApp.$scripts || reactive({});
|
|
51
18
|
const exists = !!nuxtApp.$scripts?.[id];
|
|
52
|
-
if (
|
|
53
|
-
options.warmupStrategy
|
|
54
|
-
|
|
55
|
-
if (options.trigger === "onNuxtReady") {
|
|
56
|
-
options.trigger = onNuxtReady;
|
|
57
|
-
}
|
|
58
|
-
if (import.meta.client) {
|
|
59
|
-
if (!exists) {
|
|
60
|
-
performance?.mark?.("mark_feature_usage", {
|
|
61
|
-
detail: {
|
|
62
|
-
feature: options.performanceMarkFeature ?? `nuxt-scripts:${id}`
|
|
63
|
-
}
|
|
64
|
-
});
|
|
19
|
+
if (options.trigger === "onNuxtReady" || options.trigger === "client") {
|
|
20
|
+
if (!options.warmupStrategy) {
|
|
21
|
+
options.warmupStrategy = "preload";
|
|
65
22
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
instance.warmup = (rel) => {
|
|
69
|
-
if (!instance._warmupEl) {
|
|
70
|
-
instance._warmupEl = warmup(input, rel, head);
|
|
23
|
+
if (options.trigger === "onNuxtReady") {
|
|
24
|
+
options.trigger = onNuxtReady;
|
|
71
25
|
}
|
|
72
|
-
};
|
|
73
|
-
if (options.warmupStrategy) {
|
|
74
|
-
instance.warmup(options.warmupStrategy);
|
|
75
26
|
}
|
|
27
|
+
const instance = _useScript(input, options);
|
|
76
28
|
const _remove = instance.remove;
|
|
77
29
|
instance.remove = () => {
|
|
78
|
-
instance._warmupEl?.dispose();
|
|
79
30
|
nuxtApp.$scripts[id] = void 0;
|
|
80
31
|
return _remove();
|
|
81
32
|
};
|
|
@@ -14,6 +14,17 @@ export function useScriptTriggerConsent(options) {
|
|
|
14
14
|
options.postConsentTrigger.then(() => runner(resolve));
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
|
+
if (typeof options?.postConsentTrigger === "function") {
|
|
18
|
+
if (options?.postConsentTrigger.length === 1) {
|
|
19
|
+
options.postConsentTrigger(resolve);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const val = options.postConsentTrigger();
|
|
23
|
+
if (val instanceof Promise) {
|
|
24
|
+
return val.then(() => runner(resolve));
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
17
28
|
if (options?.postConsentTrigger === "onNuxtReady") {
|
|
18
29
|
const idleTimeout = options?.postConsentTrigger ? nuxtApp ? onNuxtReady : requestIdleCallback : (cb) => cb();
|
|
19
30
|
runner(() => idleTimeout(resolve));
|
|
@@ -23,18 +34,17 @@ export function useScriptTriggerConsent(options) {
|
|
|
23
34
|
}
|
|
24
35
|
});
|
|
25
36
|
if (options?.consent) {
|
|
26
|
-
if (
|
|
27
|
-
|
|
37
|
+
if (isRef(options?.consent)) {
|
|
38
|
+
watch(options.consent, (_val) => {
|
|
39
|
+
const val = toValue(_val);
|
|
40
|
+
consented.value = Boolean(val);
|
|
41
|
+
}, { immediate: true });
|
|
42
|
+
} else if (typeof options?.consent === "boolean") {
|
|
43
|
+
consented.value = options?.consent;
|
|
28
44
|
} else if (options?.consent instanceof Promise) {
|
|
29
45
|
options?.consent.then((res) => {
|
|
30
46
|
consented.value = typeof res === "boolean" ? res : true;
|
|
31
47
|
});
|
|
32
|
-
} else if (isRef(options?.consent)) {
|
|
33
|
-
watch(options.consent, (_val) => {
|
|
34
|
-
const val = toValue(_val);
|
|
35
|
-
if (typeof val === "boolean")
|
|
36
|
-
consented.value = val;
|
|
37
|
-
}, { immediate: true });
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
50
|
});
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import type { RegistryScriptInput } from '#nuxt-scripts/types';
|
|
2
|
-
declare namespace google {
|
|
3
|
-
namespace maps {
|
|
4
|
-
/**
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
function __ib__(): void;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
2
|
export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
|
|
11
3
|
readonly apiKey: import("valibot").StringSchema<undefined>;
|
|
12
4
|
readonly libraries: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
@@ -15,14 +7,16 @@ export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
|
|
|
15
7
|
readonly v: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"weekly", undefined>, import("valibot").LiteralSchema<"beta", undefined>, import("valibot").LiteralSchema<"alpha", undefined>], undefined>, undefined>;
|
|
16
8
|
}, undefined>;
|
|
17
9
|
export type GoogleMapsInput = RegistryScriptInput<typeof GoogleMapsOptions>;
|
|
18
|
-
type MapsNamespace = typeof google.maps;
|
|
10
|
+
type MapsNamespace = typeof window.google.maps;
|
|
19
11
|
export interface GoogleMapsApi {
|
|
20
12
|
maps: Promise<MapsNamespace>;
|
|
21
13
|
}
|
|
22
14
|
declare global {
|
|
23
15
|
interface Window {
|
|
24
16
|
google: {
|
|
25
|
-
maps:
|
|
17
|
+
maps: {
|
|
18
|
+
__ib__(): void;
|
|
19
|
+
};
|
|
26
20
|
};
|
|
27
21
|
}
|
|
28
22
|
}
|
|
@@ -15,9 +15,6 @@ export function useScriptGoogleTagManager(_options) {
|
|
|
15
15
|
use: () => {
|
|
16
16
|
return { dataLayer: window[options.l ?? "dataLayer"], google_tag_manager: window.google_tag_manager };
|
|
17
17
|
},
|
|
18
|
-
stub: import.meta.client ? void 0 : ({ fn }) => {
|
|
19
|
-
return fn === "dataLayer" ? [] : void 0;
|
|
20
|
-
},
|
|
21
18
|
performanceMarkFeature: "nuxt-third-parties-gtm",
|
|
22
19
|
tagPriority: 1
|
|
23
20
|
},
|
|
@@ -24,10 +24,6 @@ export function useScriptMatomoAnalytics(_options) {
|
|
|
24
24
|
scriptOptions: {
|
|
25
25
|
use() {
|
|
26
26
|
return { _paq: window._paq };
|
|
27
|
-
},
|
|
28
|
-
// allow _paq to be accessed on the server
|
|
29
|
-
stub: import.meta.client ? void 0 : ({ fn }) => {
|
|
30
|
-
return fn === "_paq" ? [] : void 0;
|
|
31
27
|
}
|
|
32
28
|
},
|
|
33
29
|
clientInit: import.meta.server ? void 0 : () => {
|
|
@@ -33,24 +33,6 @@ export function useScriptSegment(_options) {
|
|
|
33
33
|
},
|
|
34
34
|
schema: import.meta.dev ? SegmentOptions : void 0,
|
|
35
35
|
scriptOptions: {
|
|
36
|
-
stub: import.meta.server ? ({ fn }) => {
|
|
37
|
-
if (fn === "analytics") {
|
|
38
|
-
return {
|
|
39
|
-
track: () => {
|
|
40
|
-
},
|
|
41
|
-
page: () => {
|
|
42
|
-
},
|
|
43
|
-
identify: () => {
|
|
44
|
-
},
|
|
45
|
-
group: () => {
|
|
46
|
-
},
|
|
47
|
-
alias: () => {
|
|
48
|
-
},
|
|
49
|
-
reset: () => {
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
} : void 0,
|
|
54
36
|
use() {
|
|
55
37
|
return methods.reduce((acc, key) => {
|
|
56
38
|
acc[key] = window[k].factory(key);
|