| | <script lang="ts"> |
| | import { createEventDispatcher, onDestroy, onMount } from "svelte"; |
| | import { cubicOut } from "svelte/easing"; |
| | import { fade } from "svelte/transition"; |
| | import Portal from "./Portal.svelte"; |
| | import { browser } from "$app/environment"; |
| |
|
| | export let width = "w-9/10"; |
| | let backdropEl: HTMLDivElement; |
| | let modalEl: HTMLDivElement; |
| |
|
| | const dispatch = createEventDispatcher<{ close: void }>(); |
| |
|
| | function handleKeydown(event: KeyboardEvent) { |
| | |
| | if (event.key === "Escape") { |
| | event.preventDefault(); |
| | dispatch("close"); |
| | } |
| | } |
| |
|
| | function handleBackdropClick(event: MouseEvent) { |
| | if (event.target === backdropEl) { |
| | dispatch("close"); |
| | } |
| | } |
| |
|
| | onMount(() => { |
| | document.getElementById("app")?.setAttribute("inert", "true"); |
| | modalEl.focus(); |
| | }); |
| |
|
| | onDestroy(() => { |
| | if (!browser) return; |
| | |
| | if (document.querySelectorAll('[role="dialog"]:not(#app *)').length === 1) { |
| | document.getElementById("app")?.removeAttribute("inert"); |
| | } |
| | }); |
| | </script> |
| |
|
| | <Portal> |
| | <div |
| | role="presentation" |
| | tabindex="-1" |
| | bind:this={backdropEl} |
| | on:click={handleBackdropClick} |
| | transition:fade={{ easing: cubicOut, duration: 300 }} |
| | class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50" |
| | > |
| | <div |
| | role="dialog" |
| | tabindex="-1" |
| | bind:this={modalEl} |
| | on:keydown={handleKeydown} |
| | class="-mt-10 overflow-hidden bg-white shadow-2xl outline-none md:-mt-20 {width}" |
| | > |
| | <slot /> |
| | </div> |
| | </div> |
| | </Portal> |
| | |