47 lines
1002 B
Svelte
47 lines
1002 B
Svelte
<script lang="ts">
|
|
import { onDestroy, onMount, type Snippet } from 'svelte';
|
|
|
|
let {
|
|
buttonChildren,
|
|
children,
|
|
dialogClass = '',
|
|
buttonClass = ''
|
|
}: {
|
|
buttonChildren: Snippet;
|
|
children: Snippet;
|
|
dialogClass?: string;
|
|
buttonClass?: string;
|
|
} = $props();
|
|
|
|
let open = $state(false);
|
|
let ref: HTMLDivElement;
|
|
let btn: HTMLButtonElement;
|
|
|
|
function callOutside(e: MouseEvent) {
|
|
if (!ref) return;
|
|
if (ref.contains(e.target as any) || btn.contains(e.target as any)) return;
|
|
open = false;
|
|
}
|
|
|
|
onMount(() => {
|
|
window.document.addEventListener('click', callOutside);
|
|
});
|
|
onDestroy(() => {
|
|
window.document.removeEventListener('click', callOutside);
|
|
});
|
|
</script>
|
|
|
|
<div class="relative">
|
|
<button class={buttonClass} onclick={() => (open = true)} bind:this={btn}>
|
|
{@render buttonChildren()}
|
|
</button>
|
|
{#if open}
|
|
<div
|
|
bind:this={ref}
|
|
class="absolute top-full left-0 bg-white p-2 rounded-lg shadow-lg {dialogClass}"
|
|
>
|
|
{@render children()}
|
|
</div>
|
|
{/if}
|
|
</div>
|