File size: 2,131 Bytes
b4668c2
8073be8
b4668c2
eb17509
8073be8
 
e584c54
01b06a3
a1a6daf
 
e584c54
a1a6daf
 
 
e584c54
8073be8
a1a6daf
 
8073be8
 
 
 
 
 
 
 
 
 
 
 
0f3fab1
 
 
8073be8
 
 
 
 
 
 
a1a6daf
8073be8
 
 
 
a1a6daf
8073be8
b4668c2
 
8073be8
a1a6daf
8073be8
 
 
 
a1a6daf
 
 
 
38c25e1
e584c54
8073be8
 
 
 
 
a1a6daf
eb17509
 
e584c54
eb17509
 
8073be8
e584c54
 
 
 
 
a1a6daf
8073be8
b4668c2
8073be8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<script lang="ts">
	import { createEventDispatcher, onDestroy, onMount } from "svelte";
	import { cubicOut } from "svelte/easing";
	import { fade, fly } from "svelte/transition";
	import Portal from "./Portal.svelte";
	import { browser } from "$app/environment";
	import CarbonClose from "~icons/carbon/close";

	interface Props {
		width?: string;
		closeButton?: boolean;
		children?: import("svelte").Snippet;
	}

	let { width = "max-w-sm", children, closeButton = false }: Props = $props();

	let backdropEl: HTMLDivElement | undefined = $state();
	let modalEl: HTMLDivElement | undefined = $state();

	const dispatch = createEventDispatcher<{ close: void }>();

	function handleKeydown(event: KeyboardEvent) {
		// close on ESC
		if (event.key === "Escape") {
			event.preventDefault();
			dispatch("close");
		}
	}

	function handleBackdropClick(event: MouseEvent) {
		if (window?.getSelection()?.toString()) {
			return;
		}
		if (event.target === backdropEl) {
			dispatch("close");
		}
	}

	onMount(() => {
		document.getElementById("app")?.setAttribute("inert", "true");
		modalEl?.focus();
	});

	onDestroy(() => {
		if (!browser) return;
		document.getElementById("app")?.removeAttribute("inert");
	});
</script>

<Portal>
	<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
	<div
		role="presentation"
		tabindex="-1"
		bind:this={backdropEl}
		onclick={(e) => {
			e.stopPropagation();
			handleBackdropClick(e);
		}}
		transition:fade|local={{ easing: cubicOut, duration: 300 }}
		class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 backdrop-blur-sm dark:bg-black/50"
	>
		<div
			role="dialog"
			tabindex="-1"
			bind:this={modalEl}
			onkeydown={handleKeydown}
			in:fly={{ y: 100 }}
			class={[
				"relative mx-auto max-h-[95dvh] max-w-[90dvw] overflow-y-auto overflow-x-hidden rounded-2xl bg-white shadow-2xl outline-none",
				width,
			]}
		>
			{#if closeButton}
				<button class="absolute right-4 top-4 z-50" onclick={() => dispatch("close")}>
					<CarbonClose class="size-6 text-gray-700" />
				</button>
			{/if}
			{@render children?.()}
		</div>
	</div>
</Portal>