@nuxt/scripts 0.11.1 → 0.11.3
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 +9 -9
- package/dist/client/404.html +9 -9
- package/dist/client/_nuxt/{CtQNcfGE.js → Bo1SWr6k.js} +1 -1
- package/dist/client/_nuxt/BojlM8av.js +21 -0
- package/dist/client/_nuxt/{BFM-Ncmx.js → BwFnCI0m.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/4c86029b-49d8-417d-817c-09c5117d4d78.json +1 -0
- package/dist/client/_nuxt/{entry.ipQkUTQD.css → entry.CJckMUzn.css} +1 -1
- package/dist/client/_nuxt/error-404.BiTeRF3j.css +1 -0
- package/dist/client/_nuxt/error-500.Be1AE5oK.css +1 -0
- package/dist/client/_nuxt/{BSA2bgdb.js → yRslIvSb.js} +1 -1
- package/dist/client/index.html +9 -9
- package/dist/module.json +1 -1
- package/dist/module.mjs +21 -19
- package/dist/registry.d.mts +3 -2
- package/dist/registry.d.ts +3 -2
- package/dist/registry.mjs +37 -26
- 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 -93
- package/dist/runtime/components/ScriptGoogleMaps.vue +495 -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 +288 -289
- package/dist/runtime/components/ScriptYouTubePlayer.vue +215 -215
- package/dist/runtime/composables/useScript.js +6 -3
- package/dist/runtime/composables/useScriptEventPage.js +1 -2
- package/dist/runtime/registry/clarity.d.ts +1 -1
- package/dist/runtime/registry/cloudflare-web-analytics.d.ts +1 -1
- package/dist/runtime/registry/google-adsense.js +1 -1
- package/dist/runtime/registry/google-analytics.d.ts +57 -13
- package/dist/runtime/registry/google-analytics.js +30 -28
- package/dist/runtime/registry/google-maps.d.ts +1 -1
- package/dist/runtime/registry/google-maps.js +4 -2
- package/dist/runtime/registry/google-tag-manager.d.ts +83 -21
- package/dist/runtime/registry/google-tag-manager.js +65 -24
- package/dist/runtime/types.d.ts +3 -10
- package/dist/runtime/utils.d.ts +1 -1
- package/package.json +20 -20
- package/dist/client/_nuxt/DuCkB5R-.js +0 -21
- package/dist/client/_nuxt/builds/meta/6161796c-413c-4c03-ac47-cad81a701b23.json +0 -1
- package/dist/client/_nuxt/error-404.BdjopNsg.css +0 -1
- package/dist/client/_nuxt/error-500.Bd7Z7Q7I.css +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 '
|
|
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 'nuxt/app'
|
|
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>
|
|
@@ -13,7 +13,10 @@ export function useScript(input, options) {
|
|
|
13
13
|
options = defu(options, useNuxtScriptRuntimeConfig()?.defaultScriptOptions);
|
|
14
14
|
const id = String(resolveScriptKey(input));
|
|
15
15
|
const nuxtApp = useNuxtApp();
|
|
16
|
-
|
|
16
|
+
options.head = options.head || injectHead();
|
|
17
|
+
if (!options.head) {
|
|
18
|
+
throw new Error("useScript() has been called without Nuxt context.");
|
|
19
|
+
}
|
|
17
20
|
nuxtApp.$scripts = nuxtApp.$scripts || reactive({});
|
|
18
21
|
const exists = !!nuxtApp.$scripts?.[id];
|
|
19
22
|
if (options.trigger === "onNuxtReady" || options.trigger === "client") {
|
|
@@ -47,7 +50,7 @@ export function useScript(input, options) {
|
|
|
47
50
|
};
|
|
48
51
|
nuxtApp._scripts = nuxtApp._scripts || {};
|
|
49
52
|
if (!nuxtApp._scripts[instance.id]) {
|
|
50
|
-
head.hooks.hook("script:updated", (ctx) => {
|
|
53
|
+
options.head.hooks.hook("script:updated", (ctx) => {
|
|
51
54
|
if (ctx.script.id !== instance.id)
|
|
52
55
|
return;
|
|
53
56
|
payload.events.push({
|
|
@@ -58,7 +61,7 @@ export function useScript(input, options) {
|
|
|
58
61
|
payload.$script = instance;
|
|
59
62
|
syncScripts();
|
|
60
63
|
});
|
|
61
|
-
head.hooks.hook("script:instance-fn", (ctx) => {
|
|
64
|
+
options.head.hooks.hook("script:instance-fn", (ctx) => {
|
|
62
65
|
if (ctx.script.id !== instance.id || String(ctx.fn).startsWith("__v_"))
|
|
63
66
|
return;
|
|
64
67
|
payload.events.push({
|
|
@@ -26,7 +26,7 @@ export declare const ClarityOptions: import("valibot").ObjectSchema<{
|
|
|
26
26
|
/**
|
|
27
27
|
* The Clarity token.
|
|
28
28
|
*/
|
|
29
|
-
readonly id: import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 10, undefined>]>;
|
|
29
|
+
readonly id: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 10, undefined>]>;
|
|
30
30
|
}, undefined>;
|
|
31
31
|
export type ClarityInput = RegistryScriptInput<typeof ClarityOptions>;
|
|
32
32
|
export declare function useScriptClarity<T extends ClarityApi>(_options?: ClarityInput): import("#nuxt-scripts/types").UseScriptContext<T>;
|
|
@@ -20,7 +20,7 @@ export declare const CloudflareWebAnalyticsOptions: import("valibot").ObjectSche
|
|
|
20
20
|
/**
|
|
21
21
|
* The Cloudflare Web Analytics token.
|
|
22
22
|
*/
|
|
23
|
-
readonly token: import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 32, undefined>]>;
|
|
23
|
+
readonly token: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 32, undefined>]>;
|
|
24
24
|
/**
|
|
25
25
|
* Cloudflare Web Analytics enables measuring SPAs automatically by overriding the History API’s pushState function
|
|
26
26
|
* and listening to the onpopstate. Hash-based router is not supported.
|
|
@@ -1,21 +1,65 @@
|
|
|
1
1
|
import type { RegistryScriptInput } from '#nuxt-scripts/types';
|
|
2
|
-
type
|
|
2
|
+
export type GtagCustomParams = Record<string, any>;
|
|
3
|
+
export type ConsentStatus = 'granted' | 'denied';
|
|
4
|
+
export interface ConsentOptions {
|
|
5
|
+
ad_user_data?: ConsentStatus;
|
|
6
|
+
ad_personalization?: ConsentStatus;
|
|
7
|
+
ad_storage?: ConsentStatus;
|
|
8
|
+
analytics_storage?: ConsentStatus;
|
|
9
|
+
functionality_storage?: ConsentStatus;
|
|
10
|
+
personalization_storage?: ConsentStatus;
|
|
11
|
+
security_storage?: ConsentStatus;
|
|
12
|
+
wait_for_update?: number;
|
|
13
|
+
region?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface ConfigParams extends GtagCustomParams {
|
|
16
|
+
send_page_view?: boolean;
|
|
17
|
+
transport_url?: string;
|
|
18
|
+
cookie_domain?: string;
|
|
19
|
+
cookie_prefix?: string;
|
|
20
|
+
cookie_expires?: number;
|
|
21
|
+
cookie_update?: boolean;
|
|
22
|
+
cookie_flags?: string;
|
|
23
|
+
user_id?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface EventParameters extends GtagCustomParams {
|
|
26
|
+
value?: number;
|
|
27
|
+
currency?: string;
|
|
28
|
+
transaction_id?: string;
|
|
29
|
+
items?: Array<{
|
|
30
|
+
item_id?: string;
|
|
31
|
+
item_name?: string;
|
|
32
|
+
item_category?: string;
|
|
33
|
+
item_variant?: string;
|
|
34
|
+
price?: number;
|
|
35
|
+
quantity?: number;
|
|
36
|
+
[key: string]: any;
|
|
37
|
+
}>;
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
}
|
|
40
|
+
export type DefaultEventName = 'add_payment_info' | 'add_shipping_info' | 'add_to_cart' | 'add_to_wishlist' | 'begin_checkout' | 'purchase' | 'refund' | 'remove_from_cart' | 'select_item' | 'select_promotion' | 'view_cart' | 'view_item' | 'view_item_list' | 'view_promotion' | 'login' | 'sign_up' | 'search' | 'page_view' | 'screen_view' | string;
|
|
3
41
|
export interface GTag {
|
|
4
|
-
(
|
|
5
|
-
(
|
|
6
|
-
(
|
|
7
|
-
(
|
|
8
|
-
(
|
|
42
|
+
(command: 'js', value: Date): void;
|
|
43
|
+
(command: 'config', targetId: string, configParams?: ConfigParams): void;
|
|
44
|
+
(command: 'get', targetId: string, fieldName: string, callback?: (field: any) => void): void;
|
|
45
|
+
(command: 'event', eventName: DefaultEventName, eventParams?: EventParameters): void;
|
|
46
|
+
(command: 'set', params: GtagCustomParams): void;
|
|
47
|
+
(command: 'consent', consentArg: 'default' | 'update', consentParams: ConsentOptions): void;
|
|
48
|
+
}
|
|
49
|
+
export interface DataLayerObject {
|
|
50
|
+
event?: string;
|
|
51
|
+
[key: string]: any;
|
|
52
|
+
}
|
|
53
|
+
export type DataLayer = Array<DataLayerObject>;
|
|
54
|
+
export interface GoogleAnalyticsApi {
|
|
55
|
+
gtag: GTag;
|
|
56
|
+
dataLayer: DataLayer;
|
|
9
57
|
}
|
|
10
|
-
type DataLayer = Array<Parameters<GTag> | Record<string, unknown>>;
|
|
11
58
|
export declare const GoogleAnalyticsOptions: import("valibot").ObjectSchema<{
|
|
12
59
|
readonly id: import("valibot").StringSchema<undefined>;
|
|
13
60
|
readonly l: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
14
61
|
}, undefined>;
|
|
15
62
|
export type GoogleAnalyticsInput = RegistryScriptInput<typeof GoogleAnalyticsOptions>;
|
|
16
|
-
export
|
|
17
|
-
gtag: GTag;
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
export declare function useScriptGoogleAnalytics<T extends GoogleAnalyticsApi>(_options?: GoogleAnalyticsInput): import("#nuxt-scripts/types").UseScriptContext<T>;
|
|
21
|
-
export {};
|
|
63
|
+
export declare function useScriptGoogleAnalytics<T extends GoogleAnalyticsApi>(_options?: GoogleAnalyticsInput & {
|
|
64
|
+
onBeforeGtagStart?: (gtag: GTag) => void;
|
|
65
|
+
}): import("#nuxt-scripts/types").UseScriptContext<T>;
|
|
@@ -3,36 +3,38 @@ import { useRegistryScript } from "#nuxt-scripts/utils";
|
|
|
3
3
|
import { object, string, optional } from "#nuxt-scripts-validator";
|
|
4
4
|
export const GoogleAnalyticsOptions = object({
|
|
5
5
|
id: string(),
|
|
6
|
+
// The GA4 measurement ID (format: G-XXXXXXXX)
|
|
6
7
|
l: optional(string())
|
|
8
|
+
// Optional global name for dataLayer (defaults to 'dataLayer')
|
|
7
9
|
});
|
|
8
10
|
export function useScriptGoogleAnalytics(_options) {
|
|
9
|
-
return useRegistryScript(_options?.key || "googleAnalytics", (options) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
use: () => {
|
|
16
|
-
const gtag = function(...args) {
|
|
17
|
-
window["gtag-" + (options.l ?? "dataLayer")](...args);
|
|
18
|
-
};
|
|
19
|
-
return {
|
|
20
|
-
dataLayer: window[options.l ?? "dataLayer"],
|
|
21
|
-
gtag
|
|
22
|
-
};
|
|
11
|
+
return useRegistryScript(_options?.key || "googleAnalytics", (options) => {
|
|
12
|
+
const dataLayerName = options?.l ?? "dataLayer";
|
|
13
|
+
const w = import.meta.client ? window : {};
|
|
14
|
+
return {
|
|
15
|
+
scriptInput: {
|
|
16
|
+
src: withQuery("https://www.googletagmanager.com/gtag/js", { id: options?.id, l: options?.l })
|
|
23
17
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
schema: import.meta.dev ? GoogleAnalyticsOptions : void 0,
|
|
19
|
+
scriptOptions: {
|
|
20
|
+
use: () => {
|
|
21
|
+
return {
|
|
22
|
+
dataLayer: w[dataLayerName],
|
|
23
|
+
gtag: w.gtag
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
performanceMarkFeature: "nuxt-third-parties-ga",
|
|
27
|
+
tagPriority: 1
|
|
28
|
+
},
|
|
29
|
+
clientInit: import.meta.server ? void 0 : () => {
|
|
30
|
+
w[dataLayerName] = w[dataLayerName] || [];
|
|
31
|
+
w.gtag = function() {
|
|
32
|
+
w[dataLayerName].push(arguments);
|
|
33
|
+
};
|
|
34
|
+
_options?.onBeforeGtagStart?.(w.gtag);
|
|
35
|
+
w.gtag("js", /* @__PURE__ */ new Date());
|
|
36
|
+
w.gtag("config", options?.id);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}, _options);
|
|
38
40
|
}
|
|
@@ -4,7 +4,7 @@ export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
|
|
|
4
4
|
readonly libraries: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
5
5
|
readonly language: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
6
6
|
readonly region: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
|
|
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>;
|
|
7
|
+
readonly v: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"weekly", undefined>, import("valibot").LiteralSchema<"quarterly", undefined>, import("valibot").LiteralSchema<"beta", undefined>, import("valibot").LiteralSchema<"alpha", undefined>, import("valibot").StringSchema<undefined>], undefined>, undefined>;
|
|
8
8
|
}, undefined>;
|
|
9
9
|
export type GoogleMapsInput = RegistryScriptInput<typeof GoogleMapsOptions>;
|
|
10
10
|
type MapsNamespace = typeof window.google.maps;
|