mirror of https://github.com/VERT-sh/VERT.git
fix: dropdown menu fixes
This commit is contained in:
parent
e9db7a9568
commit
e61214619b
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { duration, fade, transition } from "$lib/util/animation";
|
import { duration, fade, transition } from "$lib/util/animation";
|
||||||
import { ChevronDown } from "lucide-svelte";
|
import { ChevronDown } from "lucide-svelte";
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { quintOut } from "svelte/easing";
|
import { quintOut } from "svelte/easing";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -26,10 +25,10 @@
|
||||||
let hover = $state(false);
|
let hover = $state(false);
|
||||||
let isUp = $state(false);
|
let isUp = $state(false);
|
||||||
let dropdown = $state<HTMLDivElement>();
|
let dropdown = $state<HTMLDivElement>();
|
||||||
|
let menuElement = $state<HTMLDivElement>();
|
||||||
const toggle = () => {
|
let button = $state<HTMLButtonElement>();
|
||||||
open = !open;
|
let clickHandler: ((e: MouseEvent) => void) | null = null;
|
||||||
};
|
let resizeHandler: (() => void) | null = null;
|
||||||
|
|
||||||
const getValue = (option: string | { value: string; label: string }) =>
|
const getValue = (option: string | { value: string; label: string }) =>
|
||||||
typeof option === "string" ? option : option.value;
|
typeof option === "string" ? option : option.value;
|
||||||
|
|
@ -49,15 +48,48 @@
|
||||||
toggle();
|
toggle();
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
const toggle = () => {
|
||||||
const click = (e: MouseEvent) => {
|
open = !open;
|
||||||
if (dropdown && !dropdown.contains(e.target as Node)) {
|
};
|
||||||
open = false;
|
|
||||||
}
|
const updateMenuPosition = () => {
|
||||||
|
if (open && menuElement && button) {
|
||||||
|
const rect = button.getBoundingClientRect();
|
||||||
|
menuElement.style.top = `${rect.bottom + 4}px`;
|
||||||
|
menuElement.style.left = `${rect.left}px`;
|
||||||
|
menuElement.style.width = `${rect.width}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// outside clicks
|
||||||
|
$effect(() => {
|
||||||
|
clickHandler = (e: MouseEvent) => {
|
||||||
|
if (dropdown && !dropdown.contains(e.target as Node)) open = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("click", click);
|
window.addEventListener("click", clickHandler);
|
||||||
return () => window.removeEventListener("click", click);
|
|
||||||
|
return () => {
|
||||||
|
if (clickHandler) window.removeEventListener("click", clickHandler);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// dropdown menu positioning
|
||||||
|
$effect(() => {
|
||||||
|
if (open && menuElement && button) {
|
||||||
|
resizeHandler = updateMenuPosition;
|
||||||
|
window.addEventListener("resize", resizeHandler);
|
||||||
|
document.body.appendChild(menuElement);
|
||||||
|
menuElement.style.position = "fixed";
|
||||||
|
updateMenuPosition();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (resizeHandler)
|
||||||
|
window.removeEventListener("resize", resizeHandler);
|
||||||
|
if (menuElement?.parentNode === document.body)
|
||||||
|
document.body.removeChild(menuElement);
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -68,6 +100,7 @@
|
||||||
bind:this={dropdown}
|
bind:this={dropdown}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
bind:this={button}
|
||||||
class="font-display w-full {settingsStyle
|
class="font-display w-full {settingsStyle
|
||||||
? 'justify-between'
|
? 'justify-between'
|
||||||
: 'justify-center'} overflow-hidden relative cursor-pointer {settingsStyle
|
: 'justify-center'} overflow-hidden relative cursor-pointer {settingsStyle
|
||||||
|
|
@ -82,7 +115,6 @@
|
||||||
onmouseleave={() => (hover = false)}
|
onmouseleave={() => (hover = false)}
|
||||||
{disabled}
|
{disabled}
|
||||||
>
|
>
|
||||||
<!-- <p>{selected}</p> -->
|
|
||||||
<div class="grid grid-cols-1 grid-rows-1 w-fit flex-grow-0">
|
<div class="grid grid-cols-1 grid-rows-1 w-fit flex-grow-0">
|
||||||
{#key selected}
|
{#key selected}
|
||||||
<p
|
<p
|
||||||
|
|
@ -121,23 +153,24 @@
|
||||||
: 0}deg); transition: transform {duration}ms {transition};"
|
: 0}deg); transition: transform {duration}ms {transition};"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{#if open}
|
|
||||||
<div
|
|
||||||
style={hover ? "will-change: opacity, fade, transform" : ""}
|
|
||||||
transition:fade={{
|
|
||||||
duration,
|
|
||||||
easing: quintOut,
|
|
||||||
}}
|
|
||||||
class="w-full shadow-xl bg-panel-alt shadow-black/25 absolute overflow-hidden top-full mt-1 left-0 z-50 bg-background rounded-xl max-h-[30vh] overflow-y-auto"
|
|
||||||
>
|
|
||||||
{#each options as option}
|
|
||||||
<button
|
|
||||||
class="w-full p-2 px-4 text-left hover:bg-panel"
|
|
||||||
onclick={() => select(option)}
|
|
||||||
>
|
|
||||||
{getLabel(option)}
|
|
||||||
</button>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if open}
|
||||||
|
<div
|
||||||
|
bind:this={menuElement}
|
||||||
|
transition:fade={{
|
||||||
|
duration,
|
||||||
|
easing: quintOut,
|
||||||
|
}}
|
||||||
|
class="shadow-xl bg-panel-alt shadow-black/25 overflow-hidden z-[9999] bg-background rounded-xl max-h-[23.5vh] overflow-y-auto"
|
||||||
|
>
|
||||||
|
{#each options as option}
|
||||||
|
<button
|
||||||
|
class="w-full p-2 px-4 text-left hover:bg-panel font-normal text-sm text-muted"
|
||||||
|
onclick={() => select(option)}
|
||||||
|
>
|
||||||
|
{getLabel(option)}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue