@liforma/client 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/dist/next/index.js +5186 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/next/createLiformaSessionRouteHandler.d.ts +45 -0
- package/dist/next/next/createLiformaSessionRouteHandler.d.ts.map +1 -0
- package/dist/next/next/index.d.ts +8 -0
- package/dist/next/next/index.d.ts.map +1 -0
- package/dist/next/react/ExperienceThumbnail.d.ts +22 -0
- package/dist/next/react/ExperienceThumbnail.d.ts.map +1 -0
- package/dist/next/react/ExperienceWidget.d.ts +35 -0
- package/dist/next/react/ExperienceWidget.d.ts.map +1 -0
- package/dist/next/shims/apiBaseUrl.d.ts +14 -0
- package/dist/next/shims/apiBaseUrl.d.ts.map +1 -0
- package/dist/next/shims/localStack.d.ts +6 -0
- package/dist/next/shims/localStack.d.ts.map +1 -0
- package/dist/next/thumbnail/attachThumbnailParallax.d.ts +7 -0
- package/dist/next/thumbnail/attachThumbnailParallax.d.ts.map +1 -0
- package/dist/next/thumbnail/ensureStyles.d.ts +3 -0
- package/dist/next/thumbnail/ensureStyles.d.ts.map +1 -0
- package/dist/next/thumbnail/hostedLaunchUrl.d.ts +23 -0
- package/dist/next/thumbnail/hostedLaunchUrl.d.ts.map +1 -0
- package/dist/next/thumbnail/index.d.ts +9 -0
- package/dist/next/thumbnail/index.d.ts.map +1 -0
- package/dist/next/thumbnail/lazyLoad.d.ts +8 -0
- package/dist/next/thumbnail/lazyLoad.d.ts.map +1 -0
- package/dist/next/thumbnail/scrollParallax.d.ts +13 -0
- package/dist/next/thumbnail/scrollParallax.d.ts.map +1 -0
- package/dist/next/thumbnail/styles.d.ts +3 -0
- package/dist/next/thumbnail/styles.d.ts.map +1 -0
- package/dist/next/thumbnail/toGalleryThumbUrl.d.ts +23 -0
- package/dist/next/thumbnail/toGalleryThumbUrl.d.ts.map +1 -0
- package/dist/next/thumbnail/toGalleryThumbUrl.test.d.ts +2 -0
- package/dist/next/thumbnail/toGalleryThumbUrl.test.d.ts.map +1 -0
- package/dist/next/thumbnail/types.d.ts +37 -0
- package/dist/next/thumbnail/types.d.ts.map +1 -0
- package/dist/next/v2/api/fetchExperiencePreview.d.ts +15 -0
- package/dist/next/v2/api/fetchExperiencePreview.d.ts.map +1 -0
- package/dist/next/v2/api/mintPublicSession.d.ts +25 -0
- package/dist/next/v2/api/mintPublicSession.d.ts.map +1 -0
- package/dist/next/v2/api/sessionEndpointRequest.d.ts +16 -0
- package/dist/next/v2/api/sessionEndpointRequest.d.ts.map +1 -0
- package/dist/next/v2/conversationProcessor.d.ts +6 -0
- package/dist/next/v2/conversationProcessor.d.ts.map +1 -0
- package/dist/next/v2/embed/iframeHost.d.ts +70 -0
- package/dist/next/v2/embed/iframeHost.d.ts.map +1 -0
- package/dist/next/v2/embed/playerReachability.d.ts +4 -0
- package/dist/next/v2/embed/playerReachability.d.ts.map +1 -0
- package/dist/next/v2/embed/protocol.d.ts +181 -0
- package/dist/next/v2/embed/protocol.d.ts.map +1 -0
- package/dist/next/v2/embed/readyGate.d.ts +7 -0
- package/dist/next/v2/embed/readyGate.d.ts.map +1 -0
- package/dist/next/v2/experience.d.ts +133 -0
- package/dist/next/v2/experience.d.ts.map +1 -0
- package/dist/next/v2/experienceEvents.d.ts +27 -0
- package/dist/next/v2/experienceEvents.d.ts.map +1 -0
- package/dist/next/v2/shims/embedBaseUrl.d.ts +19 -0
- package/dist/next/v2/shims/embedBaseUrl.d.ts.map +1 -0
- package/dist/next/v2/speechOnlyManifest.d.ts +7 -0
- package/dist/next/v2/speechOnlyManifest.d.ts.map +1 -0
- package/dist/next/v2/types/sessionInteraction.d.ts +120 -0
- package/dist/next/v2/types/sessionInteraction.d.ts.map +1 -0
- package/dist/next/v2/types/sessionManifest.d.ts +93 -0
- package/dist/next/v2/types/sessionManifest.d.ts.map +1 -0
- package/dist/next/v2/types/sessionManifestSchema.d.ts +183 -0
- package/dist/next/v2/types/sessionManifestSchema.d.ts.map +1 -0
- package/dist/next/v2/types/sessionPipeline.d.ts +23 -0
- package/dist/next/v2/types/sessionPipeline.d.ts.map +1 -0
- package/dist/next/widget/dockGeometry.d.ts +26 -0
- package/dist/next/widget/dockGeometry.d.ts.map +1 -0
- package/dist/next/widget/index.d.ts +5 -0
- package/dist/next/widget/index.d.ts.map +1 -0
- package/dist/next/widget/mountExperienceWidget.d.ts +13 -0
- package/dist/next/widget/mountExperienceWidget.d.ts.map +1 -0
- package/dist/next/widget/styles.d.ts +4 -0
- package/dist/next/widget/styles.d.ts.map +1 -0
- package/dist/next/widget/types.d.ts +62 -0
- package/dist/next/widget/types.d.ts.map +1 -0
- package/dist/npm/index.js +4859 -0
- package/dist/npm/index.js.map +1 -0
- package/dist/npm/shims/apiBaseUrl.d.ts +14 -0
- package/dist/npm/shims/apiBaseUrl.d.ts.map +1 -0
- package/dist/npm/shims/localStack.d.ts +6 -0
- package/dist/npm/shims/localStack.d.ts.map +1 -0
- package/dist/npm/svelte/experienceLoadError.d.ts +16 -0
- package/dist/npm/svelte/experienceLoadError.d.ts.map +1 -0
- package/dist/npm/svelte/experienceLoadErrorOverlay.d.ts +8 -0
- package/dist/npm/svelte/experienceLoadErrorOverlay.d.ts.map +1 -0
- package/dist/npm/svelte/experienceLoadErrorStyles.d.ts +5 -0
- package/dist/npm/svelte/experienceLoadErrorStyles.d.ts.map +1 -0
- package/dist/npm/thumbnail/attachThumbnailParallax.d.ts +7 -0
- package/dist/npm/thumbnail/attachThumbnailParallax.d.ts.map +1 -0
- package/dist/npm/thumbnail/ensureStyles.d.ts +3 -0
- package/dist/npm/thumbnail/ensureStyles.d.ts.map +1 -0
- package/dist/npm/thumbnail/hostedLaunchUrl.d.ts +23 -0
- package/dist/npm/thumbnail/hostedLaunchUrl.d.ts.map +1 -0
- package/dist/npm/thumbnail/index.d.ts +9 -0
- package/dist/npm/thumbnail/index.d.ts.map +1 -0
- package/dist/npm/thumbnail/lazyLoad.d.ts +8 -0
- package/dist/npm/thumbnail/lazyLoad.d.ts.map +1 -0
- package/dist/npm/thumbnail/scrollParallax.d.ts +13 -0
- package/dist/npm/thumbnail/scrollParallax.d.ts.map +1 -0
- package/dist/npm/thumbnail/styles.d.ts +3 -0
- package/dist/npm/thumbnail/styles.d.ts.map +1 -0
- package/dist/npm/thumbnail/toGalleryThumbUrl.d.ts +23 -0
- package/dist/npm/thumbnail/toGalleryThumbUrl.d.ts.map +1 -0
- package/dist/npm/thumbnail/types.d.ts +37 -0
- package/dist/npm/thumbnail/types.d.ts.map +1 -0
- package/dist/npm/v2/api/fetchExperiencePreview.d.ts +15 -0
- package/dist/npm/v2/api/fetchExperiencePreview.d.ts.map +1 -0
- package/dist/npm/v2/api/mintPublicSession.d.ts +25 -0
- package/dist/npm/v2/api/mintPublicSession.d.ts.map +1 -0
- package/dist/npm/v2/api/sessionEndpointRequest.d.ts +16 -0
- package/dist/npm/v2/api/sessionEndpointRequest.d.ts.map +1 -0
- package/dist/npm/v2/conversationProcessor.d.ts +6 -0
- package/dist/npm/v2/conversationProcessor.d.ts.map +1 -0
- package/dist/npm/v2/embed/iframeHost.d.ts +70 -0
- package/dist/npm/v2/embed/iframeHost.d.ts.map +1 -0
- package/dist/npm/v2/embed/playerReachability.d.ts +4 -0
- package/dist/npm/v2/embed/playerReachability.d.ts.map +1 -0
- package/dist/npm/v2/embed/protocol.d.ts +181 -0
- package/dist/npm/v2/embed/protocol.d.ts.map +1 -0
- package/dist/npm/v2/embed/readyGate.d.ts +7 -0
- package/dist/npm/v2/embed/readyGate.d.ts.map +1 -0
- package/dist/npm/v2/embed/returnNavigation.d.ts +4 -0
- package/dist/npm/v2/embed/returnNavigation.d.ts.map +1 -0
- package/dist/npm/v2/experience.d.ts +133 -0
- package/dist/npm/v2/experience.d.ts.map +1 -0
- package/dist/npm/v2/experienceEvents.d.ts +27 -0
- package/dist/npm/v2/experienceEvents.d.ts.map +1 -0
- package/dist/npm/v2/index.d.ts +21 -0
- package/dist/npm/v2/index.d.ts.map +1 -0
- package/dist/npm/v2/liforma-experience-thumbnail.d.ts +9 -0
- package/dist/npm/v2/liforma-experience-thumbnail.d.ts.map +1 -0
- package/dist/npm/v2/liforma-experience-widget.d.ts +8 -0
- package/dist/npm/v2/liforma-experience-widget.d.ts.map +1 -0
- package/dist/npm/v2/liforma-experience.d.ts +15 -0
- package/dist/npm/v2/liforma-experience.d.ts.map +1 -0
- package/dist/npm/v2/npm.d.ts +10 -0
- package/dist/npm/v2/npm.d.ts.map +1 -0
- package/dist/npm/v2/shims/embedBaseUrl.d.ts +19 -0
- package/dist/npm/v2/shims/embedBaseUrl.d.ts.map +1 -0
- package/dist/npm/v2/speechOnlyManifest.d.ts +7 -0
- package/dist/npm/v2/speechOnlyManifest.d.ts.map +1 -0
- package/dist/npm/v2/types/index.d.ts +3 -0
- package/dist/npm/v2/types/index.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts +120 -0
- package/dist/npm/v2/types/sessionInteraction.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionManifest.d.ts +93 -0
- package/dist/npm/v2/types/sessionManifest.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionManifestSchema.d.ts +183 -0
- package/dist/npm/v2/types/sessionManifestSchema.d.ts.map +1 -0
- package/dist/npm/v2/types/sessionPipeline.d.ts +23 -0
- package/dist/npm/v2/types/sessionPipeline.d.ts.map +1 -0
- package/dist/npm/widget/dockGeometry.d.ts +26 -0
- package/dist/npm/widget/dockGeometry.d.ts.map +1 -0
- package/dist/npm/widget/index.d.ts +5 -0
- package/dist/npm/widget/index.d.ts.map +1 -0
- package/dist/npm/widget/mountExperienceWidget.d.ts +13 -0
- package/dist/npm/widget/mountExperienceWidget.d.ts.map +1 -0
- package/dist/npm/widget/styles.d.ts +4 -0
- package/dist/npm/widget/styles.d.ts.map +1 -0
- package/dist/npm/widget/types.d.ts +62 -0
- package/dist/npm/widget/types.d.ts.map +1 -0
- package/dist/react/component/experienceComponentLaunch.d.ts +7 -0
- package/dist/react/component/experienceComponentLaunch.d.ts.map +1 -0
- package/dist/react/component/experienceComponentRuntime.d.ts +55 -0
- package/dist/react/component/experienceComponentRuntime.d.ts.map +1 -0
- package/dist/react/component/experienceComponentTypes.d.ts +60 -0
- package/dist/react/component/experienceComponentTypes.d.ts.map +1 -0
- package/dist/react/index.js +5499 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/react/Experience.d.ts +4 -0
- package/dist/react/react/Experience.d.ts.map +1 -0
- package/dist/react/react/ExperienceThumbnail.d.ts +22 -0
- package/dist/react/react/ExperienceThumbnail.d.ts.map +1 -0
- package/dist/react/react/ExperienceWidget.d.ts +35 -0
- package/dist/react/react/ExperienceWidget.d.ts.map +1 -0
- package/dist/react/react/index.d.ts +8 -0
- package/dist/react/react/index.d.ts.map +1 -0
- package/dist/react/shims/apiBaseUrl.d.ts +14 -0
- package/dist/react/shims/apiBaseUrl.d.ts.map +1 -0
- package/dist/react/shims/localStack.d.ts +6 -0
- package/dist/react/shims/localStack.d.ts.map +1 -0
- package/dist/react/svelte/experienceLoadError.d.ts +16 -0
- package/dist/react/svelte/experienceLoadError.d.ts.map +1 -0
- package/dist/react/svelte/experienceLoadErrorOverlay.d.ts +8 -0
- package/dist/react/svelte/experienceLoadErrorOverlay.d.ts.map +1 -0
- package/dist/react/svelte/experienceLoadErrorStyles.d.ts +5 -0
- package/dist/react/svelte/experienceLoadErrorStyles.d.ts.map +1 -0
- package/dist/react/thumbnail/attachThumbnailParallax.d.ts +7 -0
- package/dist/react/thumbnail/attachThumbnailParallax.d.ts.map +1 -0
- package/dist/react/thumbnail/ensureStyles.d.ts +3 -0
- package/dist/react/thumbnail/ensureStyles.d.ts.map +1 -0
- package/dist/react/thumbnail/hostedLaunchUrl.d.ts +23 -0
- package/dist/react/thumbnail/hostedLaunchUrl.d.ts.map +1 -0
- package/dist/react/thumbnail/index.d.ts +9 -0
- package/dist/react/thumbnail/index.d.ts.map +1 -0
- package/dist/react/thumbnail/lazyLoad.d.ts +8 -0
- package/dist/react/thumbnail/lazyLoad.d.ts.map +1 -0
- package/dist/react/thumbnail/scrollParallax.d.ts +13 -0
- package/dist/react/thumbnail/scrollParallax.d.ts.map +1 -0
- package/dist/react/thumbnail/styles.d.ts +3 -0
- package/dist/react/thumbnail/styles.d.ts.map +1 -0
- package/dist/react/thumbnail/toGalleryThumbUrl.d.ts +23 -0
- package/dist/react/thumbnail/toGalleryThumbUrl.d.ts.map +1 -0
- package/dist/react/thumbnail/toGalleryThumbUrl.test.d.ts +2 -0
- package/dist/react/thumbnail/toGalleryThumbUrl.test.d.ts.map +1 -0
- package/dist/react/thumbnail/types.d.ts +37 -0
- package/dist/react/thumbnail/types.d.ts.map +1 -0
- package/dist/react/v2/api/fetchExperiencePreview.d.ts +15 -0
- package/dist/react/v2/api/fetchExperiencePreview.d.ts.map +1 -0
- package/dist/react/v2/api/mintPublicSession.d.ts +25 -0
- package/dist/react/v2/api/mintPublicSession.d.ts.map +1 -0
- package/dist/react/v2/api/sessionEndpointRequest.d.ts +16 -0
- package/dist/react/v2/api/sessionEndpointRequest.d.ts.map +1 -0
- package/dist/react/v2/conversationProcessor.d.ts +6 -0
- package/dist/react/v2/conversationProcessor.d.ts.map +1 -0
- package/dist/react/v2/embed/iframeHost.d.ts +70 -0
- package/dist/react/v2/embed/iframeHost.d.ts.map +1 -0
- package/dist/react/v2/embed/playerReachability.d.ts +4 -0
- package/dist/react/v2/embed/playerReachability.d.ts.map +1 -0
- package/dist/react/v2/embed/protocol.d.ts +181 -0
- package/dist/react/v2/embed/protocol.d.ts.map +1 -0
- package/dist/react/v2/embed/readyGate.d.ts +7 -0
- package/dist/react/v2/embed/readyGate.d.ts.map +1 -0
- package/dist/react/v2/experience.d.ts +133 -0
- package/dist/react/v2/experience.d.ts.map +1 -0
- package/dist/react/v2/experienceEvents.d.ts +27 -0
- package/dist/react/v2/experienceEvents.d.ts.map +1 -0
- package/dist/react/v2/shims/embedBaseUrl.d.ts +19 -0
- package/dist/react/v2/shims/embedBaseUrl.d.ts.map +1 -0
- package/dist/react/v2/speechOnlyManifest.d.ts +7 -0
- package/dist/react/v2/speechOnlyManifest.d.ts.map +1 -0
- package/dist/react/v2/types/sessionInteraction.d.ts +120 -0
- package/dist/react/v2/types/sessionInteraction.d.ts.map +1 -0
- package/dist/react/v2/types/sessionManifest.d.ts +93 -0
- package/dist/react/v2/types/sessionManifest.d.ts.map +1 -0
- package/dist/react/v2/types/sessionManifestSchema.d.ts +183 -0
- package/dist/react/v2/types/sessionManifestSchema.d.ts.map +1 -0
- package/dist/react/v2/types/sessionPipeline.d.ts +23 -0
- package/dist/react/v2/types/sessionPipeline.d.ts.map +1 -0
- package/dist/react/widget/dockGeometry.d.ts +26 -0
- package/dist/react/widget/dockGeometry.d.ts.map +1 -0
- package/dist/react/widget/index.d.ts +5 -0
- package/dist/react/widget/index.d.ts.map +1 -0
- package/dist/react/widget/mountExperienceWidget.d.ts +13 -0
- package/dist/react/widget/mountExperienceWidget.d.ts.map +1 -0
- package/dist/react/widget/styles.d.ts +4 -0
- package/dist/react/widget/styles.d.ts.map +1 -0
- package/dist/react/widget/types.d.ts +62 -0
- package/dist/react/widget/types.d.ts.map +1 -0
- package/dist/sdk/v2/client.js +806 -0
- package/dist/sdk/v2/client.js.map +1 -0
- package/dist/svelte/Experience.svelte +522 -0
- package/dist/svelte/Experience.svelte.d.ts +15 -0
- package/dist/svelte/ExperienceThumbnail.svelte +376 -0
- package/dist/svelte/ExperienceThumbnail.svelte.d.ts +22 -0
- package/dist/svelte/ExperienceWidget.svelte +146 -0
- package/dist/svelte/ExperienceWidget.svelte.d.ts +35 -0
- package/dist/svelte/experienceLoadError.d.ts +15 -0
- package/dist/svelte/experienceLoadError.js +82 -0
- package/dist/svelte/experienceLoadError.test.d.ts +1 -0
- package/dist/svelte/experienceLoadError.test.js +18 -0
- package/dist/svelte/experienceLoadErrorOverlay.d.ts +7 -0
- package/dist/svelte/experienceLoadErrorOverlay.js +48 -0
- package/dist/svelte/experienceLoadErrorStyles.d.ts +4 -0
- package/dist/svelte/experienceLoadErrorStyles.js +112 -0
- package/dist/svelte/index.d.ts +7 -0
- package/dist/svelte/index.js +5 -0
- package/dist/svelte/types.d.ts +1 -0
- package/dist/svelte/types.js +1 -0
- package/package.json +154 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import type { Attachment } from 'svelte/attachments';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
attachImageReady,
|
|
7
|
+
attachLazyThumb,
|
|
8
|
+
attachScrollLinkedParallax,
|
|
9
|
+
ensureExperienceThumbnailStyles,
|
|
10
|
+
EXPERIENCE_THUMBNAIL_CSS,
|
|
11
|
+
horizontalParallaxFromViewportY,
|
|
12
|
+
resolveThumbnailHref,
|
|
13
|
+
resolveThumbnailInteraction,
|
|
14
|
+
resolveThumbnailLayers,
|
|
15
|
+
type GalleryThumb
|
|
16
|
+
} from '@liforma/client';
|
|
17
|
+
|
|
18
|
+
let {
|
|
19
|
+
galleryThumb,
|
|
20
|
+
avatarImage,
|
|
21
|
+
backgroundImage,
|
|
22
|
+
foregroundImage,
|
|
23
|
+
alt,
|
|
24
|
+
experienceId,
|
|
25
|
+
href,
|
|
26
|
+
target,
|
|
27
|
+
rel,
|
|
28
|
+
onclick,
|
|
29
|
+
returnUrl,
|
|
30
|
+
playerBaseUrl,
|
|
31
|
+
parallax = true,
|
|
32
|
+
lazy = true,
|
|
33
|
+
class: className = '',
|
|
34
|
+
fallbackImage
|
|
35
|
+
}: {
|
|
36
|
+
galleryThumb?: GalleryThumb;
|
|
37
|
+
avatarImage?: string;
|
|
38
|
+
backgroundImage?: string;
|
|
39
|
+
foregroundImage?: string;
|
|
40
|
+
alt: string;
|
|
41
|
+
experienceId?: string;
|
|
42
|
+
href?: string;
|
|
43
|
+
target?: string;
|
|
44
|
+
rel?: string;
|
|
45
|
+
onclick?: (event: MouseEvent) => void;
|
|
46
|
+
returnUrl?: string;
|
|
47
|
+
playerBaseUrl?: string;
|
|
48
|
+
parallax?: boolean;
|
|
49
|
+
lazy?: boolean;
|
|
50
|
+
class?: string;
|
|
51
|
+
fallbackImage?: string;
|
|
52
|
+
} = $props();
|
|
53
|
+
|
|
54
|
+
const layers = $derived(
|
|
55
|
+
resolveThumbnailLayers({
|
|
56
|
+
galleryThumb,
|
|
57
|
+
avatarImage,
|
|
58
|
+
backgroundImage,
|
|
59
|
+
foregroundImage,
|
|
60
|
+
fallbackImage
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const interaction = $derived(
|
|
65
|
+
resolveThumbnailInteraction({
|
|
66
|
+
href,
|
|
67
|
+
hasClickHandler: typeof onclick === 'function',
|
|
68
|
+
experienceId
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const hasScene = $derived(Boolean(layers?.backgroundImage));
|
|
73
|
+
const isHostedLaunch = $derived(interaction === 'anchor' && !href?.trim() && Boolean(experienceId?.trim()));
|
|
74
|
+
|
|
75
|
+
let resolvedHref = $state<string | undefined>(undefined);
|
|
76
|
+
let shouldLoad = $state(false);
|
|
77
|
+
let hovering = $state(false);
|
|
78
|
+
let pointerDown = $state(false);
|
|
79
|
+
let scrollParallax = $state(false);
|
|
80
|
+
let parallaxX = $state(0);
|
|
81
|
+
let parallaxY = $state(0);
|
|
82
|
+
let avatarLoadFailed = $state(false);
|
|
83
|
+
let backgroundReady = $state(false);
|
|
84
|
+
let avatarReady = $state(false);
|
|
85
|
+
let foregroundReady = $state(false);
|
|
86
|
+
let detachGlobalPointerEnd: (() => void) | null = null;
|
|
87
|
+
|
|
88
|
+
const parallaxEnabled = $derived(parallax !== false);
|
|
89
|
+
const parallaxLayersActive = $derived(parallaxEnabled && (hovering || scrollParallax));
|
|
90
|
+
const resolvedAvatarImage = $derived(
|
|
91
|
+
layers
|
|
92
|
+
? avatarLoadFailed && layers.fallbackImage
|
|
93
|
+
? layers.fallbackImage
|
|
94
|
+
: layers.avatarImage
|
|
95
|
+
: ''
|
|
96
|
+
);
|
|
97
|
+
const sceneLayersReady = $derived(
|
|
98
|
+
Boolean(layers) &&
|
|
99
|
+
(!layers?.backgroundImage || backgroundReady) &&
|
|
100
|
+
avatarReady &&
|
|
101
|
+
(!layers?.foregroundImage || foregroundReady)
|
|
102
|
+
);
|
|
103
|
+
const revealThumb = $derived(shouldLoad && sceneLayersReady);
|
|
104
|
+
|
|
105
|
+
$effect(() => {
|
|
106
|
+
if (lazy === false) shouldLoad = true;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
function refreshHref(): void {
|
|
110
|
+
resolvedHref = resolveThumbnailHref({
|
|
111
|
+
href,
|
|
112
|
+
experienceId,
|
|
113
|
+
returnUrl,
|
|
114
|
+
playerBaseUrl,
|
|
115
|
+
useCurrentPageAsReturnUrl: isHostedLaunch && !returnUrl?.trim()
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
$effect(() => {
|
|
120
|
+
void href;
|
|
121
|
+
void experienceId;
|
|
122
|
+
void returnUrl;
|
|
123
|
+
void playerBaseUrl;
|
|
124
|
+
void isHostedLaunch;
|
|
125
|
+
refreshHref();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
$effect(() => {
|
|
129
|
+
void layers?.backgroundImage;
|
|
130
|
+
void layers?.foregroundImage;
|
|
131
|
+
void resolvedAvatarImage;
|
|
132
|
+
backgroundReady = false;
|
|
133
|
+
avatarReady = false;
|
|
134
|
+
foregroundReady = false;
|
|
135
|
+
avatarLoadFailed = false;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
onMount(() => {
|
|
139
|
+
ensureExperienceThumbnailStyles(EXPERIENCE_THUMBNAIL_CSS);
|
|
140
|
+
refreshHref();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
function imageReadyAttachment(onReady: () => void): Attachment<HTMLImageElement> {
|
|
144
|
+
return (element) => attachImageReady(element, onReady);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const lazyLoadAttach: Attachment<HTMLElement> = (element) => {
|
|
148
|
+
if (!lazy) {
|
|
149
|
+
shouldLoad = true;
|
|
150
|
+
return () => {};
|
|
151
|
+
}
|
|
152
|
+
return attachLazyThumb(element, {
|
|
153
|
+
onVisibleChange: (visible) => {
|
|
154
|
+
if (visible) shouldLoad = true;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const scrollParallaxAttach: Attachment<HTMLElement> = (element) => {
|
|
160
|
+
if (!parallaxEnabled) return () => {};
|
|
161
|
+
return attachScrollLinkedParallax(element, {
|
|
162
|
+
onParallax: (x) => {
|
|
163
|
+
scrollParallax = true;
|
|
164
|
+
if (!pointerDown) {
|
|
165
|
+
parallaxX = x;
|
|
166
|
+
parallaxY = 0;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
pointerActive: () => pointerDown
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
function onPointerMove(event: PointerEvent): void {
|
|
174
|
+
if (!parallaxEnabled || scrollParallax) return;
|
|
175
|
+
const thumb = event.currentTarget as HTMLElement;
|
|
176
|
+
const rect = thumb.getBoundingClientRect();
|
|
177
|
+
if (rect.width <= 0 || rect.height <= 0) return;
|
|
178
|
+
parallaxX = ((event.clientX - rect.left) / rect.width - 0.5) * 2;
|
|
179
|
+
parallaxY = ((event.clientY - rect.top) / rect.height - 0.5) * 2;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function refreshScrollParallax(thumb: HTMLElement): void {
|
|
183
|
+
parallaxX = horizontalParallaxFromViewportY(thumb.getBoundingClientRect(), window.innerHeight);
|
|
184
|
+
parallaxY = 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function clearPointerInteraction(thumb: HTMLElement): void {
|
|
188
|
+
const wasDown = pointerDown;
|
|
189
|
+
pointerDown = false;
|
|
190
|
+
hovering = false;
|
|
191
|
+
if (scrollParallax && wasDown) {
|
|
192
|
+
refreshScrollParallax(thumb);
|
|
193
|
+
} else if (!scrollParallax) {
|
|
194
|
+
parallaxX = 0;
|
|
195
|
+
parallaxY = 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function onPointerDown(event: PointerEvent): void {
|
|
200
|
+
if (!parallaxEnabled) return;
|
|
201
|
+
const thumb = event.currentTarget as HTMLElement;
|
|
202
|
+
pointerDown = true;
|
|
203
|
+
if (event.pointerType === 'mouse') hovering = true;
|
|
204
|
+
|
|
205
|
+
detachGlobalPointerEnd?.();
|
|
206
|
+
const onGlobalEnd = () => {
|
|
207
|
+
clearPointerInteraction(thumb);
|
|
208
|
+
detachGlobalPointerEnd = null;
|
|
209
|
+
};
|
|
210
|
+
detachGlobalPointerEnd = () => {
|
|
211
|
+
window.removeEventListener('pointerup', onGlobalEnd);
|
|
212
|
+
window.removeEventListener('pointercancel', onGlobalEnd);
|
|
213
|
+
detachGlobalPointerEnd = null;
|
|
214
|
+
};
|
|
215
|
+
window.addEventListener('pointerup', onGlobalEnd);
|
|
216
|
+
window.addEventListener('pointercancel', onGlobalEnd);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function endPointerInteraction(event: PointerEvent): void {
|
|
220
|
+
clearPointerInteraction(event.currentTarget as HTMLElement);
|
|
221
|
+
detachGlobalPointerEnd?.();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function onPointerEnter(event: PointerEvent): void {
|
|
225
|
+
if (parallaxEnabled && event.pointerType === 'mouse') hovering = true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function onPointerLeave(_event: PointerEvent): void {
|
|
229
|
+
if (!pointerDown) {
|
|
230
|
+
hovering = false;
|
|
231
|
+
if (!scrollParallax) {
|
|
232
|
+
parallaxX = 0;
|
|
233
|
+
parallaxY = 0;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function onAvatarError(): void {
|
|
239
|
+
if (layers?.fallbackImage) avatarLoadFailed = true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function handleClick(event: MouseEvent): void {
|
|
243
|
+
onclick?.(event);
|
|
244
|
+
if (event.defaultPrevented) return;
|
|
245
|
+
|
|
246
|
+
if (isHostedLaunch && !returnUrl?.trim()) {
|
|
247
|
+
const next = resolveThumbnailHref({
|
|
248
|
+
experienceId,
|
|
249
|
+
playerBaseUrl,
|
|
250
|
+
useCurrentPageAsReturnUrl: true
|
|
251
|
+
});
|
|
252
|
+
if (next && event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey) {
|
|
253
|
+
event.preventDefault();
|
|
254
|
+
window.location.assign(next);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const rootClass = $derived(
|
|
260
|
+
[
|
|
261
|
+
'liforma-et',
|
|
262
|
+
hasScene ? 'liforma-et--scene' : '',
|
|
263
|
+
parallaxLayersActive ? 'liforma-et--parallax' : '',
|
|
264
|
+
scrollParallax ? 'liforma-et--scroll-parallax' : '',
|
|
265
|
+
shouldLoad && !revealThumb ? 'liforma-et--loading' : '',
|
|
266
|
+
revealThumb ? 'liforma-et--revealed' : '',
|
|
267
|
+
className
|
|
268
|
+
]
|
|
269
|
+
.filter(Boolean)
|
|
270
|
+
.join(' ')
|
|
271
|
+
);
|
|
272
|
+
</script>
|
|
273
|
+
|
|
274
|
+
{#if layers}
|
|
275
|
+
{#if interaction === 'anchor' && resolvedHref}
|
|
276
|
+
<a
|
|
277
|
+
class={rootClass}
|
|
278
|
+
href={resolvedHref}
|
|
279
|
+
{target}
|
|
280
|
+
{rel}
|
|
281
|
+
aria-label={alt}
|
|
282
|
+
style:--liforma-et-parallax-x={parallaxX}
|
|
283
|
+
style:--liforma-et-parallax-y={parallaxY}
|
|
284
|
+
{@attach lazyLoadAttach}
|
|
285
|
+
{@attach scrollParallaxAttach}
|
|
286
|
+
onclick={handleClick}
|
|
287
|
+
onpointerdown={onPointerDown}
|
|
288
|
+
onpointerup={endPointerInteraction}
|
|
289
|
+
onpointercancel={endPointerInteraction}
|
|
290
|
+
onpointerenter={onPointerEnter}
|
|
291
|
+
onpointermove={onPointerMove}
|
|
292
|
+
onpointerleave={onPointerLeave}
|
|
293
|
+
>
|
|
294
|
+
{@render media()}
|
|
295
|
+
</a>
|
|
296
|
+
{:else if interaction === 'button'}
|
|
297
|
+
<button
|
|
298
|
+
type="button"
|
|
299
|
+
class={rootClass}
|
|
300
|
+
aria-label={alt}
|
|
301
|
+
style:--liforma-et-parallax-x={parallaxX}
|
|
302
|
+
style:--liforma-et-parallax-y={parallaxY}
|
|
303
|
+
{@attach lazyLoadAttach}
|
|
304
|
+
{@attach scrollParallaxAttach}
|
|
305
|
+
onclick={handleClick}
|
|
306
|
+
onpointerdown={onPointerDown}
|
|
307
|
+
onpointerup={endPointerInteraction}
|
|
308
|
+
onpointercancel={endPointerInteraction}
|
|
309
|
+
onpointerenter={onPointerEnter}
|
|
310
|
+
onpointermove={onPointerMove}
|
|
311
|
+
onpointerleave={onPointerLeave}
|
|
312
|
+
>
|
|
313
|
+
{@render media()}
|
|
314
|
+
</button>
|
|
315
|
+
{:else}
|
|
316
|
+
<div
|
|
317
|
+
class={rootClass}
|
|
318
|
+
role={alt ? 'img' : undefined}
|
|
319
|
+
aria-label={alt || undefined}
|
|
320
|
+
aria-hidden={alt ? undefined : 'true'}
|
|
321
|
+
style:--liforma-et-parallax-x={parallaxX}
|
|
322
|
+
style:--liforma-et-parallax-y={parallaxY}
|
|
323
|
+
{@attach lazyLoadAttach}
|
|
324
|
+
{@attach scrollParallaxAttach}
|
|
325
|
+
onpointerdown={onPointerDown}
|
|
326
|
+
onpointerup={endPointerInteraction}
|
|
327
|
+
onpointercancel={endPointerInteraction}
|
|
328
|
+
onpointerenter={onPointerEnter}
|
|
329
|
+
onpointermove={onPointerMove}
|
|
330
|
+
onpointerleave={onPointerLeave}
|
|
331
|
+
>
|
|
332
|
+
{@render media()}
|
|
333
|
+
</div>
|
|
334
|
+
{/if}
|
|
335
|
+
{/if}
|
|
336
|
+
|
|
337
|
+
{#snippet media()}
|
|
338
|
+
<span class="liforma-et__placeholder" aria-hidden="true"></span>
|
|
339
|
+
{#if shouldLoad && layers?.backgroundImage}
|
|
340
|
+
<img
|
|
341
|
+
class="liforma-et__background liforma-et__media"
|
|
342
|
+
class:liforma-et__media--ready={backgroundReady}
|
|
343
|
+
src={layers.backgroundImage}
|
|
344
|
+
alt=""
|
|
345
|
+
decoding="async"
|
|
346
|
+
{@attach imageReadyAttachment(() => {
|
|
347
|
+
backgroundReady = true;
|
|
348
|
+
})}
|
|
349
|
+
/>
|
|
350
|
+
{/if}
|
|
351
|
+
{#if shouldLoad && resolvedAvatarImage}
|
|
352
|
+
<img
|
|
353
|
+
class="liforma-et__avatar liforma-et__media"
|
|
354
|
+
class:liforma-et__media--ready={avatarReady}
|
|
355
|
+
src={resolvedAvatarImage}
|
|
356
|
+
alt=""
|
|
357
|
+
decoding="async"
|
|
358
|
+
{@attach imageReadyAttachment(() => {
|
|
359
|
+
avatarReady = true;
|
|
360
|
+
})}
|
|
361
|
+
onerror={onAvatarError}
|
|
362
|
+
/>
|
|
363
|
+
{/if}
|
|
364
|
+
{#if shouldLoad && layers?.foregroundImage}
|
|
365
|
+
<img
|
|
366
|
+
class="liforma-et__foreground liforma-et__media"
|
|
367
|
+
class:liforma-et__media--ready={foregroundReady}
|
|
368
|
+
src={layers.foregroundImage}
|
|
369
|
+
alt=""
|
|
370
|
+
decoding="async"
|
|
371
|
+
{@attach imageReadyAttachment(() => {
|
|
372
|
+
foregroundReady = true;
|
|
373
|
+
})}
|
|
374
|
+
/>
|
|
375
|
+
{/if}
|
|
376
|
+
{/snippet}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type GalleryThumb } from '@liforma/client';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
galleryThumb?: GalleryThumb;
|
|
4
|
+
avatarImage?: string;
|
|
5
|
+
backgroundImage?: string;
|
|
6
|
+
foregroundImage?: string;
|
|
7
|
+
alt: string;
|
|
8
|
+
experienceId?: string;
|
|
9
|
+
href?: string;
|
|
10
|
+
target?: string;
|
|
11
|
+
rel?: string;
|
|
12
|
+
onclick?: (event: MouseEvent) => void;
|
|
13
|
+
returnUrl?: string;
|
|
14
|
+
playerBaseUrl?: string;
|
|
15
|
+
parallax?: boolean;
|
|
16
|
+
lazy?: boolean;
|
|
17
|
+
class?: string;
|
|
18
|
+
fallbackImage?: string;
|
|
19
|
+
};
|
|
20
|
+
declare const ExperienceThumbnail: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
21
|
+
type ExperienceThumbnail = ReturnType<typeof ExperienceThumbnail>;
|
|
22
|
+
export default ExperienceThumbnail;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import {
|
|
4
|
+
mountExperienceWidget,
|
|
5
|
+
type ExperienceFit,
|
|
6
|
+
type ExperienceMode,
|
|
7
|
+
type ExperienceWidgetController,
|
|
8
|
+
type ExperienceWidgetPosition,
|
|
9
|
+
type ExperienceWidgetPrefetch,
|
|
10
|
+
type GalleryThumb,
|
|
11
|
+
type SpeechInputMode,
|
|
12
|
+
type StartButtonOptions
|
|
13
|
+
} from '@liforma/client';
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
experienceId,
|
|
17
|
+
alt,
|
|
18
|
+
galleryThumb,
|
|
19
|
+
avatarImage,
|
|
20
|
+
backgroundImage,
|
|
21
|
+
foregroundImage,
|
|
22
|
+
fallbackImage,
|
|
23
|
+
prefetch = 'onExpand',
|
|
24
|
+
parallax = true,
|
|
25
|
+
position = 'static',
|
|
26
|
+
offset,
|
|
27
|
+
sessionEndpoint,
|
|
28
|
+
language,
|
|
29
|
+
mode,
|
|
30
|
+
speechInputMode,
|
|
31
|
+
speechOnly,
|
|
32
|
+
fit,
|
|
33
|
+
embedBaseUrl,
|
|
34
|
+
expandedMaxWidth,
|
|
35
|
+
expandedMaxHeight,
|
|
36
|
+
startButtonLabel,
|
|
37
|
+
startButton,
|
|
38
|
+
class: className = '',
|
|
39
|
+
onExpanded,
|
|
40
|
+
onCollapsed,
|
|
41
|
+
onStarted,
|
|
42
|
+
onClose,
|
|
43
|
+
onError,
|
|
44
|
+
onPrefetchReady
|
|
45
|
+
}: {
|
|
46
|
+
experienceId: string;
|
|
47
|
+
alt: string;
|
|
48
|
+
galleryThumb?: GalleryThumb;
|
|
49
|
+
avatarImage?: string;
|
|
50
|
+
backgroundImage?: string;
|
|
51
|
+
foregroundImage?: string;
|
|
52
|
+
fallbackImage?: string;
|
|
53
|
+
prefetch?: ExperienceWidgetPrefetch;
|
|
54
|
+
parallax?: boolean;
|
|
55
|
+
position?: ExperienceWidgetPosition;
|
|
56
|
+
offset?: number | string;
|
|
57
|
+
sessionEndpoint?: string;
|
|
58
|
+
language?: 'en' | 'es';
|
|
59
|
+
mode?: ExperienceMode;
|
|
60
|
+
speechInputMode?: SpeechInputMode;
|
|
61
|
+
speechOnly?: boolean;
|
|
62
|
+
fit?: ExperienceFit;
|
|
63
|
+
embedBaseUrl?: string;
|
|
64
|
+
expandedMaxWidth?: string;
|
|
65
|
+
expandedMaxHeight?: string;
|
|
66
|
+
startButtonLabel?: string;
|
|
67
|
+
startButton?: StartButtonOptions;
|
|
68
|
+
class?: string;
|
|
69
|
+
onExpanded?: () => void;
|
|
70
|
+
onCollapsed?: () => void;
|
|
71
|
+
onStarted?: () => void;
|
|
72
|
+
onClose?: () => void;
|
|
73
|
+
onError?: (error: Error) => void;
|
|
74
|
+
onPrefetchReady?: () => void;
|
|
75
|
+
} = $props();
|
|
76
|
+
|
|
77
|
+
let hostEl: HTMLDivElement | undefined = $state();
|
|
78
|
+
let controller: ExperienceWidgetController | null = null;
|
|
79
|
+
|
|
80
|
+
const anchored = $derived(position === 'bottom-right' || position === 'bottom-left');
|
|
81
|
+
|
|
82
|
+
$effect(() => {
|
|
83
|
+
const host = hostEl;
|
|
84
|
+
if (!host || !experienceId?.trim()) return;
|
|
85
|
+
|
|
86
|
+
controller?.destroy();
|
|
87
|
+
controller = mountExperienceWidget(host, {
|
|
88
|
+
experienceId,
|
|
89
|
+
alt,
|
|
90
|
+
galleryThumb,
|
|
91
|
+
avatarImage,
|
|
92
|
+
backgroundImage,
|
|
93
|
+
foregroundImage,
|
|
94
|
+
fallbackImage,
|
|
95
|
+
prefetch,
|
|
96
|
+
parallax,
|
|
97
|
+
position,
|
|
98
|
+
offset,
|
|
99
|
+
sessionEndpoint,
|
|
100
|
+
language,
|
|
101
|
+
mode,
|
|
102
|
+
speechInputMode,
|
|
103
|
+
speechOnly,
|
|
104
|
+
fit,
|
|
105
|
+
embedBaseUrl,
|
|
106
|
+
expandedMaxWidth,
|
|
107
|
+
expandedMaxHeight,
|
|
108
|
+
startButtonLabel,
|
|
109
|
+
startButton,
|
|
110
|
+
onExpanded,
|
|
111
|
+
onCollapsed,
|
|
112
|
+
onStarted,
|
|
113
|
+
onClose,
|
|
114
|
+
onError,
|
|
115
|
+
onPrefetchReady
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return () => {
|
|
119
|
+
controller?.destroy();
|
|
120
|
+
controller = null;
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
onDestroy(() => {
|
|
125
|
+
controller?.destroy();
|
|
126
|
+
controller = null;
|
|
127
|
+
});
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<div
|
|
131
|
+
class="liforma-ew-svelte {className}"
|
|
132
|
+
class:liforma-ew-svelte--anchored={anchored}
|
|
133
|
+
bind:this={hostEl}
|
|
134
|
+
></div>
|
|
135
|
+
|
|
136
|
+
<style>
|
|
137
|
+
.liforma-ew-svelte {
|
|
138
|
+
width: 100%;
|
|
139
|
+
height: 100%;
|
|
140
|
+
min-height: inherit;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.liforma-ew-svelte--anchored {
|
|
144
|
+
display: contents;
|
|
145
|
+
}
|
|
146
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ExperienceFit, type ExperienceMode, type ExperienceWidgetPosition, type ExperienceWidgetPrefetch, type GalleryThumb, type SpeechInputMode, type StartButtonOptions } from '@liforma/client';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
experienceId: string;
|
|
4
|
+
alt: string;
|
|
5
|
+
galleryThumb?: GalleryThumb;
|
|
6
|
+
avatarImage?: string;
|
|
7
|
+
backgroundImage?: string;
|
|
8
|
+
foregroundImage?: string;
|
|
9
|
+
fallbackImage?: string;
|
|
10
|
+
prefetch?: ExperienceWidgetPrefetch;
|
|
11
|
+
parallax?: boolean;
|
|
12
|
+
position?: ExperienceWidgetPosition;
|
|
13
|
+
offset?: number | string;
|
|
14
|
+
sessionEndpoint?: string;
|
|
15
|
+
language?: 'en' | 'es';
|
|
16
|
+
mode?: ExperienceMode;
|
|
17
|
+
speechInputMode?: SpeechInputMode;
|
|
18
|
+
speechOnly?: boolean;
|
|
19
|
+
fit?: ExperienceFit;
|
|
20
|
+
embedBaseUrl?: string;
|
|
21
|
+
expandedMaxWidth?: string;
|
|
22
|
+
expandedMaxHeight?: string;
|
|
23
|
+
startButtonLabel?: string;
|
|
24
|
+
startButton?: StartButtonOptions;
|
|
25
|
+
class?: string;
|
|
26
|
+
onExpanded?: () => void;
|
|
27
|
+
onCollapsed?: () => void;
|
|
28
|
+
onStarted?: () => void;
|
|
29
|
+
onClose?: () => void;
|
|
30
|
+
onError?: (error: Error) => void;
|
|
31
|
+
onPrefetchReady?: () => void;
|
|
32
|
+
};
|
|
33
|
+
declare const ExperienceWidget: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
34
|
+
type ExperienceWidget = ReturnType<typeof ExperienceWidget>;
|
|
35
|
+
export default ExperienceWidget;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ExperienceLoadErrorKind = 'not_found' | 'origin_not_allowed' | 'browser_embeds_disabled' | 'generic';
|
|
2
|
+
export type ExperienceLoadErrorPresentation = {
|
|
3
|
+
readonly kind: ExperienceLoadErrorKind;
|
|
4
|
+
readonly title: string;
|
|
5
|
+
readonly detail: string;
|
|
6
|
+
readonly technicalMessage: string;
|
|
7
|
+
readonly experienceId?: string;
|
|
8
|
+
readonly origin?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function extractExperienceIdFromMessage(message: string): string | undefined;
|
|
11
|
+
export declare function extractOriginFromMessage(message: string): string | undefined;
|
|
12
|
+
export declare function presentExperienceLoadError(error: unknown, options?: {
|
|
13
|
+
readonly experienceId?: string | null;
|
|
14
|
+
readonly origin?: string | null;
|
|
15
|
+
}): ExperienceLoadErrorPresentation;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const EXPERIENCE_ID_IN_MESSAGE = /\b(exp_[A-Za-z0-9][A-Za-z0-9_-]{2,127})\b/;
|
|
2
|
+
const ORIGIN_IN_MESSAGE = /(?:Your origin|origin)\s+(\S+)\s+is not an allowed origin/i;
|
|
3
|
+
function toErrorMessage(error) {
|
|
4
|
+
if (error instanceof Error)
|
|
5
|
+
return error.message;
|
|
6
|
+
return String(error);
|
|
7
|
+
}
|
|
8
|
+
function currentPageOrigin() {
|
|
9
|
+
try {
|
|
10
|
+
if (typeof globalThis.location?.origin === 'string' && globalThis.location.origin) {
|
|
11
|
+
return globalThis.location.origin;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
/* ignore */
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
export function extractExperienceIdFromMessage(message) {
|
|
20
|
+
return EXPERIENCE_ID_IN_MESSAGE.exec(message)?.[1];
|
|
21
|
+
}
|
|
22
|
+
export function extractOriginFromMessage(message) {
|
|
23
|
+
return ORIGIN_IN_MESSAGE.exec(message)?.[1];
|
|
24
|
+
}
|
|
25
|
+
export function presentExperienceLoadError(error, options) {
|
|
26
|
+
const technicalMessage = toErrorMessage(error).trim() || 'Unknown error';
|
|
27
|
+
const experienceId = options?.experienceId?.trim() ||
|
|
28
|
+
extractExperienceIdFromMessage(technicalMessage) ||
|
|
29
|
+
undefined;
|
|
30
|
+
const origin = options?.origin?.trim() ||
|
|
31
|
+
extractOriginFromMessage(technicalMessage) ||
|
|
32
|
+
currentPageOrigin() ||
|
|
33
|
+
undefined;
|
|
34
|
+
if (/No playable experience found/i.test(technicalMessage) ||
|
|
35
|
+
/^Experience is not available\.?$/i.test(technicalMessage) ||
|
|
36
|
+
/^Unknown experience\.?$/i.test(technicalMessage) ||
|
|
37
|
+
/experience_unavailable/i.test(technicalMessage)) {
|
|
38
|
+
const idLabel = experienceId ?? 'the requested experience';
|
|
39
|
+
return {
|
|
40
|
+
kind: 'not_found',
|
|
41
|
+
title: 'The application tried to load an avatar experience that doesn’t exist.',
|
|
42
|
+
detail: `Experience with id ${idLabel} does not exist`,
|
|
43
|
+
technicalMessage,
|
|
44
|
+
experienceId,
|
|
45
|
+
origin
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (/origin_not_allowed/i.test(technicalMessage) ||
|
|
49
|
+
/is not an allowed origin/i.test(technicalMessage) ||
|
|
50
|
+
/^Origin not allowed/i.test(technicalMessage)) {
|
|
51
|
+
const originLabel = origin ?? 'this page';
|
|
52
|
+
const idLabel = experienceId ?? 'the requested experience';
|
|
53
|
+
return {
|
|
54
|
+
kind: 'origin_not_allowed',
|
|
55
|
+
title: 'The application tried to load an avatar experience from a website that isn’t allowed.',
|
|
56
|
+
detail: `Origin ${originLabel} is not allowed for experience ${idLabel}`,
|
|
57
|
+
technicalMessage,
|
|
58
|
+
experienceId,
|
|
59
|
+
origin
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (/browser_embeds_disabled/i.test(technicalMessage) ||
|
|
63
|
+
/^Browser embeds are not enabled/i.test(technicalMessage)) {
|
|
64
|
+
const idLabel = experienceId ?? 'the requested experience';
|
|
65
|
+
return {
|
|
66
|
+
kind: 'browser_embeds_disabled',
|
|
67
|
+
title: 'The application tried to load an avatar experience that isn’t enabled for browser embeds.',
|
|
68
|
+
detail: `Browser embeds are not enabled for experience ${idLabel}`,
|
|
69
|
+
technicalMessage,
|
|
70
|
+
experienceId,
|
|
71
|
+
origin
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
kind: 'generic',
|
|
76
|
+
title: 'This avatar experience couldn’t be started.',
|
|
77
|
+
detail: technicalMessage,
|
|
78
|
+
technicalMessage,
|
|
79
|
+
experienceId,
|
|
80
|
+
origin
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { presentExperienceLoadError } from './experienceLoadError';
|
|
3
|
+
describe('presentExperienceLoadError', () => {
|
|
4
|
+
it('maps unavailable experiences to a friendly not-found presentation', () => {
|
|
5
|
+
const presentation = presentExperienceLoadError(new Error('No playable experience found for “exp_01MISSING”. Check that the experience id is correct.'), { experienceId: 'exp_01MISSING' });
|
|
6
|
+
expect(presentation.kind).toBe('not_found');
|
|
7
|
+
expect(presentation.title).toBe('The application tried to load an avatar experience that doesn’t exist.');
|
|
8
|
+
expect(presentation.detail).toBe('Experience with id exp_01MISSING does not exist');
|
|
9
|
+
});
|
|
10
|
+
it('maps origin denials to a friendly origin presentation', () => {
|
|
11
|
+
const presentation = presentExperienceLoadError(new Error('Your origin http://localhost:5173 is not an allowed origin for experience exp_01DEMO. If you own this experience, sign in to the Liforma developer portal.'), { experienceId: 'exp_01DEMO', origin: 'http://localhost:5173' });
|
|
12
|
+
expect(presentation.kind).toBe('origin_not_allowed');
|
|
13
|
+
expect(presentation.title).toBe('The application tried to load an avatar experience from a website that isn’t allowed.');
|
|
14
|
+
expect(presentation.detail).toBe('Origin http://localhost:5173 is not allowed for experience exp_01DEMO');
|
|
15
|
+
expect(presentation.experienceId).toBe('exp_01DEMO');
|
|
16
|
+
expect(presentation.origin).toBe('http://localhost:5173');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExperienceLoadErrorPresentation } from './experienceLoadError';
|
|
2
|
+
export type ExperienceLoadErrorOverlay = {
|
|
3
|
+
readonly root: HTMLDivElement;
|
|
4
|
+
setPresentation(presentation: ExperienceLoadErrorPresentation): void;
|
|
5
|
+
remove(): void;
|
|
6
|
+
};
|
|
7
|
+
export declare function createExperienceLoadErrorOverlay(container: HTMLElement, initial: ExperienceLoadErrorPresentation): ExperienceLoadErrorOverlay;
|