refactor component props with improved state & event handling
This commit is contained in:
@@ -1,18 +1,22 @@
|
|||||||
<!-- @component
|
<!-- @component
|
||||||
The Jitsi component is a lightweight wrapper that manages loading the Jitsi Meet External API
|
The Jitsi component is a lightweight wrapper that manages loading the Jitsi Meet External API
|
||||||
and joining a Jitsi meeting room. It accepts configuration options and provides a callback
|
and joining a Jitsi meeting room. It accepts configuration options and several callbacks that
|
||||||
when the API is ready for use.
|
allow you to respond to basic meeting events such as joining and leaving. For advanced event
|
||||||
|
handling, use the getAPI() method to interact with the Jitsi instance directly.
|
||||||
|
|
||||||
WARNING: Assume that ALL properties are NOT reactive. Due to the nature of the Jitsi Meet
|
WARNING: While properties are reactive, in most cases changing them after the API has
|
||||||
External API, changing properties after initialization will NOT update the Jitsi instance.
|
initialized will trigger a complete re-render of the component, which will destroy the
|
||||||
Instead, use the getAPI() method to interact with the Jitsi instance directly.
|
existing Jitsi instance and interrupt any ongoing meetings. Use the getAPI() method to
|
||||||
|
interact with the Jitsi instance directly without causing a re-render.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, type Snippet } from 'svelte';
|
import { onMount, type Snippet } from 'svelte';
|
||||||
import type {
|
import type {
|
||||||
JitsiMeetExternalAPIOptions,
|
JitsiMeetExternalAPIOptions,
|
||||||
JitsiMeetExternalAPI
|
JitsiMeetExternalAPI,
|
||||||
|
VideoConferenceJoinedEvent,
|
||||||
|
VideoConferenceLeftEvent
|
||||||
} from '$lib/jitsi-iframe-api.d.ts';
|
} from '$lib/jitsi-iframe-api.d.ts';
|
||||||
import type { ClassValue } from 'svelte/elements';
|
import type { ClassValue } from 'svelte/elements';
|
||||||
|
|
||||||
@@ -32,29 +36,59 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
|
|||||||
*/
|
*/
|
||||||
class?: ClassValue;
|
class?: ClassValue;
|
||||||
/**
|
/**
|
||||||
* Children are rendered inside the Jitsi container until the API is initialized.
|
* Optional snippet rendered until the API is initialized and the meeting
|
||||||
|
* is joined. Can be used to provide a loading indicator or placeholder content.
|
||||||
*/
|
*/
|
||||||
children?: Snippet;
|
loading?: Snippet;
|
||||||
|
/** Whether to hold loading state until the meeting is joined (default: false). */
|
||||||
|
holdLoadingUntilJoined?: boolean;
|
||||||
|
/**
|
||||||
|
* Optional snippet rendered after the API is initialized and the meeting is joined.
|
||||||
|
* Can be used to provide additional UI elements or controls related to the meeting.
|
||||||
|
*/
|
||||||
|
joined?: Snippet<[api: JitsiMeetExternalAPI]>;
|
||||||
|
/**
|
||||||
|
* Optional snippet rendered after the user has left the meeting. Can be used to
|
||||||
|
* provide a farewell message or other post-meeting content.
|
||||||
|
*/
|
||||||
|
left?: Snippet;
|
||||||
/**
|
/**
|
||||||
* Callback function that is called when the Jitsi API is loaded. Can
|
* Callback function that is called when the Jitsi API is loaded. Can
|
||||||
* be used to provide a loading indicator until the API is ready.
|
* be used to provide a loading indicator until the API is ready.
|
||||||
* @param api The Jitsi Meet External API instance.
|
* @param api The Jitsi Meet External API instance.
|
||||||
*/
|
*/
|
||||||
onready?: (api: JitsiMeetExternalAPI) => void;
|
onapiready?: (api: JitsiMeetExternalAPI) => void;
|
||||||
|
/** Callback triggered when the local user joins the meeting. */
|
||||||
|
onjoin?: (ev: VideoConferenceJoinedEvent) => void;
|
||||||
|
/** Callback triggered when the local user leaves the meeting. */
|
||||||
|
onleave?: (ev: VideoConferenceLeftEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
domain = 'https://meet.jit.si',
|
domain = 'https://meet.jit.si',
|
||||||
options,
|
options,
|
||||||
class: classValue,
|
class: classValue,
|
||||||
children,
|
loading,
|
||||||
onready
|
holdLoadingUntilJoined = false,
|
||||||
|
joined,
|
||||||
|
left,
|
||||||
|
onapiready,
|
||||||
|
onjoin,
|
||||||
|
onleave
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
const src = $derived(`${new URL('external_api.js', domain).toString()}`);
|
const src = $derived(`${new URL('external_api.js', domain).toString()}`);
|
||||||
|
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let ready = $state(false);
|
/** tracks whether the Jitsi API is ready */
|
||||||
|
let apiReady = $state(false);
|
||||||
|
/** tracks whether the local user has joined the meeting */
|
||||||
|
let joinedMeeting = $state(false);
|
||||||
|
/** tracks whether the local user has left the meeting */
|
||||||
|
let leftMeeting = $state(false);
|
||||||
|
/** whether to display the loading state */
|
||||||
|
const showLoading = $derived(holdLoadingUntilJoined ? !joinedMeeting : !apiReady);
|
||||||
|
|
||||||
let api = $state<JitsiMeetExternalAPI | null>(null);
|
let api = $state<JitsiMeetExternalAPI | null>(null);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -64,13 +98,14 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onload = () => {
|
/** handles Jitsi script load event */
|
||||||
|
const handleScriptLoad = () => {
|
||||||
if (typeof window.JitsiMeetExternalAPI === 'undefined') {
|
if (typeof window.JitsiMeetExternalAPI === 'undefined') {
|
||||||
console.error('Jitsi Meet External API is not available on the window object.');
|
console.error('Jitsi Meet External API is not available on the window object.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ready = true;
|
apiReady = true;
|
||||||
// Initialize the Jitsi Meet External API
|
// Initialize the Jitsi Meet External API
|
||||||
api = new window.JitsiMeetExternalAPI(new URL(domain).host, {
|
api = new window.JitsiMeetExternalAPI(new URL(domain).host, {
|
||||||
...options,
|
...options,
|
||||||
@@ -80,8 +115,18 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
|
|||||||
console.error('Failed to initialize Jitsi Meet External API.');
|
console.error('Failed to initialize Jitsi Meet External API.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Call the onready callback if provided
|
// Call the onapiready callback if provided
|
||||||
onready?.(api);
|
onapiready?.(api);
|
||||||
|
|
||||||
|
// Attach event listeners for meeting join and leave events
|
||||||
|
api.addListener('videoConferenceJoined', (ev: VideoConferenceJoinedEvent) => {
|
||||||
|
joinedMeeting = true;
|
||||||
|
onjoin?.(ev);
|
||||||
|
});
|
||||||
|
api.addListener('videoConferenceLeft', (ev: VideoConferenceLeftEvent) => {
|
||||||
|
leftMeeting = true;
|
||||||
|
onleave?.(ev);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,11 +139,21 @@ Instead, use the getAPI() method to interact with the Jitsi instance directly.
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<script {src} {onload}></script>
|
<script {src} onload={handleScriptLoad}></script>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div id="jitsi-container" bind:this={container} class={[classValue]}>
|
<div class={['relative', classValue]}>
|
||||||
{#if !ready}
|
{#if showLoading}
|
||||||
{@render children?.()}
|
<div class="absolute inset-0">{@render loading?.()}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if joinedMeeting && api && joined}
|
||||||
|
<div class="absolute inset-0 pointer-events-none">{@render joined(api)}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if leftMeeting}
|
||||||
|
<div class="absolute inset-0">{@render left?.()}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div id="jitsi-container" bind:this={container} class={['w-full h-full min-w-0']}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user