diff --git a/packages/script/src/registry-types.json b/packages/script/src/registry-types.json index a185f659c..fb728872d 100644 --- a/packages/script/src/registry-types.json +++ b/packages/script/src/registry-types.json @@ -27,6 +27,11 @@ "name": "ScriptBlueskyEmbedProps", "kind": "interface", "code": "interface ScriptBlueskyEmbedProps {\n /**\n * The Bluesky post URL to embed\n * @example 'https://bsky.app/profile/bsky.app/post/3mgnwwvj3u22a'\n */\n postUrl: string\n /**\n * Custom API endpoint for fetching post data\n */\n apiEndpoint?: string\n /**\n * Custom image proxy endpoint\n */\n imageProxyEndpoint?: string\n /**\n * Root element attributes\n */\n rootAttrs?: HTMLAttributes\n}" + }, + { + "name": "ScriptBlueskyEmbedSlots", + "kind": "interface", + "code": "interface ScriptBlueskyEmbedSlots {\n default?: (props: object) => any\n loading?: () => any\n error?: (props: object) => any\n}" } ], "clarity": [ @@ -78,6 +83,11 @@ "name": "ScriptCrispEvents", "kind": "interface", "code": "interface ScriptCrispEvents {\n ready: ReturnType\n error: -\n}" + }, + { + "name": "ScriptCrispSlots", + "kind": "interface", + "code": "interface ScriptCrispSlots {\n default?: (props: { ready: boolean }) => any\n awaitingLoad?: () => any\n loading?: () => any\n error?: () => any\n}" } ], "databuddy-analytics": [ @@ -124,6 +134,11 @@ "name": "ScriptGoogleAdsenseEvents", "kind": "interface", "code": "interface ScriptGoogleAdsenseEvents {\n ready: ReturnType\n error: -\n}" + }, + { + "name": "ScriptGoogleAdsenseSlots", + "kind": "interface", + "code": "interface ScriptGoogleAdsenseSlots {\n awaitingLoad?: () => any\n loading?: () => any\n error?: () => any\n}" } ], "google-analytics": [ @@ -209,6 +224,11 @@ "kind": "interface", "code": "interface ScriptGoogleMapsEvents {\n ready: typeof googleMaps\n error: -\n}" }, + { + "name": "ScriptGoogleMapsSlots", + "kind": "interface", + "code": "interface ScriptGoogleMapsSlots {\n default?: () => any\n placeholder?: () => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" + }, { "name": "ScriptGoogleMapsCircleProps", "kind": "interface", @@ -244,6 +264,11 @@ "kind": "interface", "code": "interface ScriptGoogleMapsInfoWindowEvents {\n close: -\n closeclick: -\n content_changed: -\n domready: -\n headercontent_changed: -\n headerdisabled_changed: -\n position_changed: -\n visible: -\n zindex_changed: -\n}" }, + { + "name": "ScriptGoogleMapsInfoWindowSlots", + "kind": "interface", + "code": "interface ScriptGoogleMapsInfoWindowSlots {\n default?: () => any\n}" + }, { "name": "ScriptGoogleMapsMarkerProps", "kind": "interface", @@ -254,6 +279,11 @@ "kind": "interface", "code": "interface ScriptGoogleMapsMarkerEvents {\n click: google.maps.MapMouseEvent\n drag: google.maps.MapMouseEvent\n dragend: google.maps.MapMouseEvent\n dragstart: google.maps.MapMouseEvent\n}" }, + { + "name": "ScriptGoogleMapsMarkerSlots", + "kind": "interface", + "code": "interface ScriptGoogleMapsMarkerSlots {\n default?: () => any\n content?: () => any\n}" + }, { "name": "ScriptGoogleMapsMarkerClustererProps", "kind": "interface", @@ -264,11 +294,21 @@ "kind": "interface", "code": "interface ScriptGoogleMapsMarkerClustererEvents {\n click: MarkerClustererInstance\n clusteringbegin: MarkerClustererInstance\n clusteringend: MarkerClustererInstance\n}" }, + { + "name": "ScriptGoogleMapsMarkerClustererSlots", + "kind": "interface", + "code": "interface ScriptGoogleMapsMarkerClustererSlots {\n default?: () => any\n renderer?: (props: { cluster: Cluster, stats: ClusterStats, map: google.maps.Map }) => any\n}" + }, { "name": "ScriptGoogleMapsOverlayViewProps", "kind": "interface", "code": "interface ScriptGoogleMapsOverlayViewProps {\n /**\n * Geographic position for the overlay. Falls back to parent marker position if omitted.\n * @see https://developers.google.com/maps/documentation/javascript/reference/overlay-view#OverlayView\n */\n position?: google.maps.LatLngLiteral\n /**\n * Anchor point of the overlay relative to its position.\n * @default 'bottom-center'\n */\n anchor?: OverlayAnchor\n /**\n * Pixel offset from the anchor position.\n */\n offset?: { x: number, y: number }\n /**\n * The map pane on which to render the overlay.\n * @default 'floatPane'\n * @see https://developers.google.com/maps/documentation/javascript/reference/overlay-view#MapPanes\n */\n pane?: OverlayPane\n /**\n * CSS z-index for the overlay element.\n */\n zIndex?: number\n /**\n * Whether to block map click and gesture events from passing through the overlay.\n * @default true\n */\n blockMapInteraction?: boolean\n /**\n * Pan the map so the overlay is fully visible when opened, similar to InfoWindow behavior.\n * Set to `true` for default 40px padding, or a number for custom padding.\n * @default true\n */\n panOnOpen?: boolean | number\n /**\n * Automatically hide the overlay when its parent marker joins a cluster (on zoom out).\n * Only applies when nested inside a ScriptGoogleMapsMarkerClusterer.\n * @default true\n */\n hideWhenClustered?: boolean\n}" }, + { + "name": "ScriptGoogleMapsOverlayViewSlots", + "kind": "interface", + "code": "interface ScriptGoogleMapsOverlayViewSlots {\n default?: () => any\n}" + }, { "name": "ScriptGoogleMapsPolygonProps", "kind": "interface", @@ -440,6 +480,11 @@ "name": "ScriptInstagramEmbedProps", "kind": "interface", "code": "interface ScriptInstagramEmbedProps {\n /**\n * The Instagram post URL to embed\n * e.g., https://www.instagram.com/p/ABC123/\n */\n postUrl: string\n /**\n * Whether to include captions in the embed\n * @default true\n */\n captions?: boolean\n /**\n * Custom API endpoint for fetching embed HTML\n */\n apiEndpoint?: string\n /**\n * Root element attributes\n */\n rootAttrs?: HTMLAttributes\n}" + }, + { + "name": "ScriptInstagramEmbedSlots", + "kind": "interface", + "code": "interface ScriptInstagramEmbedSlots {\n default?: (props: { html: string, shortcode: string | undefined, postUrl: string }) => any\n loading?: () => any\n error?: (props: object) => any\n}" } ], "intercom": [ @@ -462,6 +507,11 @@ "name": "ScriptIntercomEvents", "kind": "interface", "code": "interface ScriptIntercomEvents {\n ready: ReturnType\n error: -\n}" + }, + { + "name": "ScriptIntercomSlots", + "kind": "interface", + "code": "interface ScriptIntercomSlots {\n default?: (props: { ready: boolean }) => any\n awaitingLoad?: () => any\n loading?: () => any\n error?: () => any\n}" } ], "lemon-squeezy": [ @@ -484,6 +534,11 @@ "name": "ScriptLemonSqueezyEvents", "kind": "interface", "code": "interface ScriptLemonSqueezyEvents {\n ready: ReturnType\n lemonSqueezyEvent: LemonSqueezyEventPayload\n}" + }, + { + "name": "ScriptLemonSqueezySlots", + "kind": "interface", + "code": "interface ScriptLemonSqueezySlots {\n default?: () => any\n}" } ], "matomo-analytics": [ @@ -580,6 +635,11 @@ "kind": "interface", "code": "interface ScriptPayPalButtonsEvents {\n ready: SdkInstance\n error: unknown\n}" }, + { + "name": "ScriptPayPalButtonsSlots", + "kind": "interface", + "code": "interface ScriptPayPalButtonsSlots {\n default?: (props: { sdkInstance: SdkInstance | undefined }) => any\n placeholder?: () => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" + }, { "name": "ScriptPayPalMessagesProps", "kind": "interface", @@ -589,6 +649,11 @@ "name": "ScriptPayPalMessagesEvents", "kind": "interface", "code": "interface ScriptPayPalMessagesEvents {\n ready: PayPalMessagesSession\n error: unknown\n}" + }, + { + "name": "ScriptPayPalMessagesSlots", + "kind": "interface", + "code": "interface ScriptPayPalMessagesSlots {\n default?: (props: { messagesSession: PayPalMessagesSession | undefined }) => any\n placeholder?: () => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" } ], "plausible-analytics": [ @@ -738,6 +803,11 @@ "name": "ScriptStripePricingTableEvents", "kind": "interface", "code": "interface ScriptStripePricingTableEvents {\n ready: ReturnType\n error: -\n}" + }, + { + "name": "ScriptStripePricingTableSlots", + "kind": "interface", + "code": "interface ScriptStripePricingTableSlots {\n default?: () => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" } ], "tiktok-pixel": [ @@ -831,6 +901,11 @@ "name": "ScriptVimeoPlayerProps", "kind": "interface", "code": "interface ScriptVimeoPlayerProps {\n // custom\n trigger?: ElementScriptTrigger\n placeholderAttrs?: ImgHTMLAttributes\n rootAttrs?: HTMLAttributes\n aboveTheFold?: boolean\n vimeoOptions?: VimeoOptions\n id?: number | undefined\n url?: string | undefined\n ratio?: string\n /**\n * Object-fit for the placeholder image.\n *\n * @default 'contain'\n */\n placeholderObjectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n}" + }, + { + "name": "ScriptVimeoPlayerSlots", + "kind": "interface", + "code": "interface ScriptVimeoPlayerSlots {\n default?: () => any\n placeholder?: (props: { placeholder: string | undefined }) => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" } ], "x-embed": [ @@ -848,6 +923,11 @@ "name": "ScriptXEmbedProps", "kind": "interface", "code": "interface ScriptXEmbedProps {\n /**\n * The tweet ID to embed\n */\n tweetId: string\n /**\n * Custom API endpoint for fetching tweet data\n */\n apiEndpoint?: string\n /**\n * Custom image proxy endpoint\n */\n imageProxyEndpoint?: string\n /**\n * Root element attributes\n */\n rootAttrs?: HTMLAttributes\n}" + }, + { + "name": "ScriptXEmbedSlots", + "kind": "interface", + "code": "interface ScriptXEmbedSlots {\n default?: (props: object) => any\n loading?: () => any\n error?: (props: object) => any\n}" } ], "x-pixel": [ @@ -892,6 +972,11 @@ "name": "ScriptYouTubePlayerEvents", "kind": "interface", "code": "interface ScriptYouTubePlayerEvents {\n ready: YT.PlayerEvent\n state-change: YT.OnStateChangeEvent\n playback-quality-change: YT.OnPlaybackQualityChangeEvent\n playback-rate-change: YT.OnPlaybackRateChangeEvent\n error: YT.OnErrorEvent\n api-change: YT.PlayerEvent\n}" + }, + { + "name": "ScriptYouTubePlayerSlots", + "kind": "interface", + "code": "interface ScriptYouTubePlayerSlots {\n default?: () => any\n placeholder?: (props: { placeholder: string }) => any\n loading?: () => any\n awaitingLoad?: () => any\n error?: () => any\n}" } ], "carbon-ads": [ @@ -904,6 +989,11 @@ "name": "ScriptCarbonAdsEvents", "kind": "interface", "code": "interface ScriptCarbonAdsEvents {\n error: string | Event\n ready: HTMLScriptElement\n}" + }, + { + "name": "ScriptCarbonAdsSlots", + "kind": "interface", + "code": "interface ScriptCarbonAdsSlots {\n awaitingLoad?: () => any\n loading?: () => any\n error?: () => any\n}" } ] }, @@ -2149,6 +2239,33 @@ "description": "Fired when the Google Maps script fails to load." } ], + "ScriptGoogleMapsSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "placeholder", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptGoogleMapsCircleProps": [ { "name": "options", @@ -2403,6 +2520,13 @@ "description": "Fired when the z-index of the info window changes." } ], + "ScriptGoogleMapsInfoWindowSlots": [ + { + "name": "default", + "type": "-", + "required": false + } + ], "ScriptGoogleMapsMarkerProps": [ { "name": "position", @@ -2443,6 +2567,18 @@ "description": "Fired when the user starts dragging the marker." } ], + "ScriptGoogleMapsMarkerSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "content", + "type": "-", + "required": false + } + ], "ScriptGoogleMapsMarkerClustererProps": [ { "name": "options", @@ -2471,6 +2607,18 @@ "description": "Fired when the clusterer finishes clustering markers." } ], + "ScriptGoogleMapsMarkerClustererSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "renderer", + "type": "{ cluster: Cluster, stats: ClusterStats, map: google.maps.Map }", + "required": false + } + ], "ScriptGoogleMapsOverlayViewProps": [ { "name": "position", @@ -2531,6 +2679,13 @@ "required": false } ], + "ScriptGoogleMapsOverlayViewSlots": [ + { + "name": "default", + "type": "-", + "required": false + } + ], "ScriptGoogleMapsPolygonProps": [ { "name": "options", @@ -2791,6 +2946,23 @@ "description": "Root element attributes" } ], + "ScriptBlueskyEmbedSlots": [ + { + "name": "default", + "type": "object", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "object", + "required": false + } + ], "ScriptCarbonAdsProps": [ { "name": "serve", @@ -2826,6 +2998,23 @@ "required": false } ], + "ScriptCarbonAdsSlots": [ + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptCrispProps": [ { "name": "trigger", @@ -2871,6 +3060,28 @@ "required": false } ], + "ScriptCrispSlots": [ + { + "name": "default", + "type": "{ ready: boolean }", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptGoogleAdsenseProps": [ { "name": "dataAdClient", @@ -2916,6 +3127,23 @@ "required": false } ], + "ScriptGoogleAdsenseSlots": [ + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptInstagramEmbedProps": [ { "name": "postUrl", @@ -2943,6 +3171,23 @@ "description": "Root element attributes" } ], + "ScriptInstagramEmbedSlots": [ + { + "name": "default", + "type": "{ html: string, shortcode: string | undefined, postUrl: string }", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "object", + "required": false + } + ], "ScriptIntercomProps": [ { "name": "appId", @@ -3003,6 +3248,28 @@ "required": false } ], + "ScriptIntercomSlots": [ + { + "name": "default", + "type": "{ ready: boolean }", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptLemonSqueezyProps": [ { "name": "trigger", @@ -3022,6 +3289,13 @@ "required": false } ], + "ScriptLemonSqueezySlots": [ + { + "name": "default", + "type": "-", + "required": false + } + ], "ScriptPayPalButtonsProps": [ { "name": "rootAttrs", @@ -3097,6 +3371,33 @@ "required": false } ], + "ScriptPayPalButtonsSlots": [ + { + "name": "default", + "type": "{ sdkInstance: SdkInstance | undefined }", + "required": false + }, + { + "name": "placeholder", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptPayPalMessagesProps": [ { "name": "rootAttrs", @@ -3171,6 +3472,33 @@ "required": false } ], + "ScriptPayPalMessagesSlots": [ + { + "name": "default", + "type": "{ messagesSession: PayPalMessagesSession | undefined }", + "required": false + }, + { + "name": "placeholder", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptStripePricingTableProps": [ { "name": "trigger", @@ -3215,6 +3543,28 @@ "required": false } ], + "ScriptStripePricingTableSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptVimeoPlayerProps": [ { "name": "trigger", @@ -3264,6 +3614,33 @@ "defaultValue": "'contain'" } ], + "ScriptVimeoPlayerSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "placeholder", + "type": "{ placeholder: string | undefined }", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } + ], "ScriptXEmbedProps": [ { "name": "tweetId", @@ -3290,6 +3667,23 @@ "description": "Root element attributes" } ], + "ScriptXEmbedSlots": [ + { + "name": "default", + "type": "object", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "object", + "required": false + } + ], "ScriptYouTubePlayerProps": [ { "name": "placeholderAttrs", @@ -3397,6 +3791,33 @@ "type": "YT.PlayerEvent", "required": false } + ], + "ScriptYouTubePlayerSlots": [ + { + "name": "default", + "type": "-", + "required": false + }, + { + "name": "placeholder", + "type": "{ placeholder: string }", + "required": false + }, + { + "name": "loading", + "type": "-", + "required": false + }, + { + "name": "awaitingLoad", + "type": "-", + "required": false + }, + { + "name": "error", + "type": "-", + "required": false + } ] } } diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue index 9171a170c..9e89d4180 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue @@ -94,6 +94,14 @@ const emits = defineEmits<{ error: [] }>() +defineSlots<{ + default?: () => any + placeholder?: () => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + const apiKey = props.apiKey || scriptRuntimeConfig('googleMaps')?.apiKey const runtimeConfig = useRuntimeConfig() diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue index 3227486d0..ada70a9cd 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue @@ -52,6 +52,10 @@ const emit = defineEmits<{ zindex_changed: [] }>() +defineSlots<{ + default?: () => any +}>() + const infoWindowEvents = [ 'close', 'closeclick', diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue index be878a74e..5ea8d52cd 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue @@ -42,6 +42,10 @@ const emit = defineEmits<{ */ dragstart: [payload: google.maps.MapMouseEvent] }>() +defineSlots<{ + default?: () => any + content?: () => any +}>() const dragEvents = ['drag', 'dragend', 'dragstart'] as const const slots = useSlots() const markerContent = useTemplateRef('marker-content') diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue index aa026c551..310916afc 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue @@ -69,6 +69,11 @@ const emit = defineEmits<{ clusteringend: [payload: MarkerClustererInstance] }>() +defineSlots<{ + default?: () => any + renderer?: (props: { cluster: Cluster, stats: ClusterStats, map: google.maps.Map }) => any +}>() + const markerClustererEvents = [ 'click', 'clusteringbegin', diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue index 1d1f447bb..e988f2c3b 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue @@ -64,6 +64,10 @@ const props = withDefaults(defineProps<{ hideWhenClustered: true, }) +defineSlots<{ + default?: () => any +}>() + const open = defineModel('open', { default: undefined }) const markerContext = inject(MARKER_INJECTION_KEY, undefined) diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue index ca9caf330..b890f3a24 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue @@ -107,6 +107,9 @@ const props = withDefaults(defineProps<{ height: 400, }) +defineSlots<{ + default?: (props: { src: string }) => any +}>() const runtimeConfig = useRuntimeConfig() const proxyConfig = (runtimeConfig.public['nuxt-scripts'] as any)?.googleStaticMapsProxy const apiKey = props.apiKey || scriptRuntimeConfig('googleMaps')?.apiKey diff --git a/packages/script/src/runtime/components/ScriptBlueskyEmbed.vue b/packages/script/src/runtime/components/ScriptBlueskyEmbed.vue index 6ed96278e..4893e403c 100644 --- a/packages/script/src/runtime/components/ScriptBlueskyEmbed.vue +++ b/packages/script/src/runtime/components/ScriptBlueskyEmbed.vue @@ -29,6 +29,12 @@ const props = withDefaults(defineProps<{ imageProxyEndpoint: undefined, }) +defineSlots<{ + default?: (props: NonNullable) => any + loading?: () => any + error?: (props: { error: typeof error.value }) => any +}>() + const prefix = scriptsPrefix() const resolvedApiEndpoint = computed((): string => props.apiEndpoint || `${prefix}/embed/bluesky`) diff --git a/packages/script/src/runtime/components/ScriptCarbonAds.vue b/packages/script/src/runtime/components/ScriptCarbonAds.vue index e505f5669..2658bd5ac 100644 --- a/packages/script/src/runtime/components/ScriptCarbonAds.vue +++ b/packages/script/src/runtime/components/ScriptCarbonAds.vue @@ -19,6 +19,12 @@ const emit = defineEmits<{ ready: [HTMLScriptElement] }>() +defineSlots<{ + awaitingLoad?: () => any + loading?: () => any + error?: () => any +}>() + const attrId = `_carbonads_js` const carbonadsEl = ref(import.meta.client ? document.getElementById(attrId) : null) // syncs to useScript status diff --git a/packages/script/src/runtime/components/ScriptCrisp.vue b/packages/script/src/runtime/components/ScriptCrisp.vue index c1e8e50fc..e6f5774a9 100644 --- a/packages/script/src/runtime/components/ScriptCrisp.vue +++ b/packages/script/src/runtime/components/ScriptCrisp.vue @@ -26,6 +26,13 @@ const emits = defineEmits<{ error: [] }>() +defineSlots<{ + default?: (props: { ready: boolean }) => any + awaitingLoad?: () => any + loading?: () => any + error?: () => any +}>() + const rootEl = ref(null) const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl }) diff --git a/packages/script/src/runtime/components/ScriptGoogleAdsense.vue b/packages/script/src/runtime/components/ScriptGoogleAdsense.vue index 46dfc2bea..7da2914de 100644 --- a/packages/script/src/runtime/components/ScriptGoogleAdsense.vue +++ b/packages/script/src/runtime/components/ScriptGoogleAdsense.vue @@ -27,6 +27,12 @@ const emits = defineEmits<{ error: [] }>() +defineSlots<{ + awaitingLoad?: () => any + loading?: () => any + error?: () => any +}>() + const rootEl = ref(null) const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl }) diff --git a/packages/script/src/runtime/components/ScriptInstagramEmbed.vue b/packages/script/src/runtime/components/ScriptInstagramEmbed.vue index 9387ad399..5e6190705 100644 --- a/packages/script/src/runtime/components/ScriptInstagramEmbed.vue +++ b/packages/script/src/runtime/components/ScriptInstagramEmbed.vue @@ -29,6 +29,12 @@ const props = withDefaults(defineProps<{ apiEndpoint: undefined, }) +defineSlots<{ + default?: (props: { html: string, shortcode: string | undefined, postUrl: string }) => any + loading?: () => any + error?: (props: { error: typeof error.value }) => any +}>() + const prefix = scriptsPrefix() const apiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed/instagram`) diff --git a/packages/script/src/runtime/components/ScriptIntercom.vue b/packages/script/src/runtime/components/ScriptIntercom.vue index 53e95be69..e68969a7a 100644 --- a/packages/script/src/runtime/components/ScriptIntercom.vue +++ b/packages/script/src/runtime/components/ScriptIntercom.vue @@ -28,6 +28,13 @@ const emits = defineEmits<{ error: [] }>() +defineSlots<{ + default?: (props: { ready: boolean }) => any + awaitingLoad?: () => any + loading?: () => any + error?: () => any +}>() + const rootEl = ref(null) const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl }) diff --git a/packages/script/src/runtime/components/ScriptLemonSqueezy.vue b/packages/script/src/runtime/components/ScriptLemonSqueezy.vue index 674abae0b..56a43f7bb 100644 --- a/packages/script/src/runtime/components/ScriptLemonSqueezy.vue +++ b/packages/script/src/runtime/components/ScriptLemonSqueezy.vue @@ -16,6 +16,10 @@ const emits = defineEmits<{ lemonSqueezyEvent: [LemonSqueezyEventPayload] }>() +defineSlots<{ + default?: () => any +}>() + const rootEl = ref(null) const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl }) const instance = useScriptLemonSqueezy({ diff --git a/packages/script/src/runtime/components/ScriptPayPalButtons.vue b/packages/script/src/runtime/components/ScriptPayPalButtons.vue index 0d1755c8e..8bf3a894f 100644 --- a/packages/script/src/runtime/components/ScriptPayPalButtons.vue +++ b/packages/script/src/runtime/components/ScriptPayPalButtons.vue @@ -68,6 +68,14 @@ const emit = defineEmits<{ error: [error: unknown] }>() +defineSlots<{ + default?: (props: { sdkInstance: SdkInstance | undefined }) => any + placeholder?: () => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + const el = ref(null) const rootEl = ref(null) const ready = ref(false) diff --git a/packages/script/src/runtime/components/ScriptPayPalMessages.vue b/packages/script/src/runtime/components/ScriptPayPalMessages.vue index 55b455f82..c5893c4c7 100644 --- a/packages/script/src/runtime/components/ScriptPayPalMessages.vue +++ b/packages/script/src/runtime/components/ScriptPayPalMessages.vue @@ -69,6 +69,14 @@ const emit = defineEmits<{ error: [error: unknown] }>() +defineSlots<{ + default?: (props: { messagesSession: PayPalMessagesSession | undefined }) => any + placeholder?: () => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + const el = ref(null) const rootEl = ref(null) const ready = ref(false) diff --git a/packages/script/src/runtime/components/ScriptStripePricingTable.vue b/packages/script/src/runtime/components/ScriptStripePricingTable.vue index 35fb46970..6d9b8a3a4 100644 --- a/packages/script/src/runtime/components/ScriptStripePricingTable.vue +++ b/packages/script/src/runtime/components/ScriptStripePricingTable.vue @@ -20,6 +20,13 @@ const emit = defineEmits<{ error: [] }>() +defineSlots<{ + default?: () => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + const rootEl = ref() const containerEl = ref() const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl }) diff --git a/packages/script/src/runtime/components/ScriptVimeoPlayer.vue b/packages/script/src/runtime/components/ScriptVimeoPlayer.vue index 9fa2cb46a..4646672e6 100644 --- a/packages/script/src/runtime/components/ScriptVimeoPlayer.vue +++ b/packages/script/src/runtime/components/ScriptVimeoPlayer.vue @@ -67,6 +67,14 @@ const props = withDefaults(defineProps<{ const emits = defineEmits() +defineSlots<{ + default?: () => any + placeholder?: (props: { placeholder: string | undefined }) => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + type EventMap = [event: Vimeo.EventMap[E], player: Vimeo] interface TEmits { diff --git a/packages/script/src/runtime/components/ScriptXEmbed.vue b/packages/script/src/runtime/components/ScriptXEmbed.vue index aa01d6300..d831dc58a 100644 --- a/packages/script/src/runtime/components/ScriptXEmbed.vue +++ b/packages/script/src/runtime/components/ScriptXEmbed.vue @@ -28,6 +28,12 @@ const props = withDefaults(defineProps<{ imageProxyEndpoint: undefined, }) +defineSlots<{ + default?: (props: NonNullable) => any + loading?: () => any + error?: (props: { error: typeof error.value }) => any +}>() + const prefix = scriptsPrefix() const apiEndpoint = computed(() => props.apiEndpoint || `${prefix}/embed/x`) diff --git a/packages/script/src/runtime/components/ScriptYouTubePlayer.vue b/packages/script/src/runtime/components/ScriptYouTubePlayer.vue index 0c4a8fdcc..c5ff06714 100644 --- a/packages/script/src/runtime/components/ScriptYouTubePlayer.vue +++ b/packages/script/src/runtime/components/ScriptYouTubePlayer.vue @@ -72,6 +72,14 @@ const emits = defineEmits<{ 'error': [e: YT.OnErrorEvent, target: YT.Player] 'api-change': [e: YT.PlayerEvent, target: YT.Player] }>() +defineSlots<{ + default?: () => any + placeholder?: (props: { placeholder: string }) => any + loading?: () => any + awaitingLoad?: () => any + error?: () => any +}>() + const events: (keyof YT.Events)[] = [ 'onReady', 'onStateChange', diff --git a/scripts/generate-registry-types.ts b/scripts/generate-registry-types.ts index 08e6f0483..13dc5f98e 100644 --- a/scripts/generate-registry-types.ts +++ b/scripts/generate-registry-types.ts @@ -263,6 +263,7 @@ interface ComponentMeta { fields: SchemaFieldMeta[] events: SchemaFieldMeta[] models: SchemaFieldMeta[] + slots: SchemaFieldMeta[] } function resolveTSType(node: any, source: string): string { @@ -340,6 +341,7 @@ function extractComponentMeta(scriptSource: string, fileName: string): Component let propsResult: { code: string, defaults: Record, fields: SchemaFieldMeta[] } | null = null const events: SchemaFieldMeta[] = [] const models: SchemaFieldMeta[] = [] + const slots: SchemaFieldMeta[] = [] const constArrays: Record = {} // First pass: collect `as const` arrays for event name resolution @@ -480,6 +482,44 @@ function extractComponentMeta(scriptSource: string, fileName: string): Component return } + // defineSlots<{...}>() + if (node.callee?.name === 'defineSlots') { + const typeArg = node.typeArguments?.params?.[0] + if (typeArg?.type === 'TSTypeLiteral') { + const slotsCode = scriptSource.slice(typeArg.start, typeArg.end) + const slotsComments = parseSchemaComments(slotsCode) + + for (const member of typeArg.members || []) { + if (member.type !== 'TSPropertySignature') + continue + const slotName = member.key?.name || member.key?.value + if (!slotName) + continue + + // Extract slot props type from the function signature: (props: { ... }) => any + let propsType = '-' + const fnType = member.typeAnnotation?.typeAnnotation + if (fnType?.type === 'TSFunctionType' && fnType.params?.length) { + const param = fnType.params[0] + const paramType = param?.typeAnnotation?.typeAnnotation + if (paramType) { + const resolved = resolveTSType(paramType, scriptSource) + // Avoid leaking unresolvable `typeof` references from runtime variables + propsType = resolved.includes('typeof') ? 'object' : resolved + } + } + + slots.push({ + name: slotName, + type: propsType, + required: !member.optional, + description: slotsComments[slotName]?.description, + }) + } + } + return + } + // defineProps / withDefaults(defineProps) let definePropsCall: any = null let defaultsObj: any = null @@ -532,6 +572,7 @@ function extractComponentMeta(scriptSource: string, fileName: string): Component fields: [...propsResult.fields, ...models], events, models, + slots, } } @@ -649,6 +690,16 @@ for (const [componentName, meta] of Object.entries(componentMetas)) { code: `interface ${componentName}Events {\n${meta.events.map(e => ` ${e.name}: ${e.type}`).join('\n')}\n}`, }) } + + // Store slots as schema fields under a separate key + if (meta.slots.length) { + schemaFields[`${componentName}Slots`] = meta.slots + types[slug].push({ + name: `${componentName}Slots`, + kind: 'interface', + code: `interface ${componentName}Slots {\n${meta.slots.map(s => ` ${s.name}${s.required ? '' : '?'}: ${s.type === '-' ? '() => any' : `(props: ${s.type}) => any`}`).join('\n')}\n}`, + }) + } } const output = {