refactor(popup): Refactored Modals + Popups and made them respect animation + transition durations

This commit is contained in:
LynithDev 2024-05-18 12:25:14 +02:00
parent ea715f15bb
commit 5b25e50ab8
2 changed files with 34 additions and 67 deletions

View file

@ -4,7 +4,7 @@ import type {
ParentProps,
Setter,
} from 'solid-js';
import { For, Show, createEffect, createSignal, mergeProps } from 'solid-js';
import { For, mergeProps } from 'solid-js';
import { Portal } from 'solid-js/web';
import Button from '../base/Button';
@ -34,52 +34,35 @@ type ModalProps = {
} & ParentProps;
function Modal(props: ModalProps) {
const [localVisible, setLocalVisible] = createSignal(false);
const [animate, setAnimate] = createSignal('animate-fade-in');
const merged: ModalProps = mergeProps({ buttons: ['Ok'] }, props);
createEffect(() => {
if (props.visible()) {
setAnimate('animate-fade-in');
setLocalVisible(true);
}
else {
setAnimate('animate-fade-out');
setTimeout(() => {
setLocalVisible(false);
}, 150);
}
});
function onBackdropClick() {
props.setVisible(false);
}
return (
<Show when={localVisible()}>
<Portal>
<div class={`fixed z-[1000] top-0 left-0 w-screen h-screen bg-black/60 backdrop-blur-sm backdrop-grayscale ${animate()}`}>
<div class="absolute w-full h-full" onClick={() => onBackdropClick()} />
<Portal>
<div class={`fixed z-[1000] top-0 left-0 w-screen h-screen bg-black/60 backdrop-blur-sm backdrop-grayscale transition-all ${props.visible() ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}>
<div class="absolute w-full h-full" onClick={() => onBackdropClick()} />
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<div class="bg-primary border border-white/5 p-4 rounded-lg text-center flex flex-col gap-y-2">
<h2>{props.title}</h2>
<div class="flex flex-col">
{props.children}
</div>
<div class="flex flex-row gap-x-4 [&>*]:flex-1">
<For each={merged.buttons}>
{button => (
<ModalButton props={button} />
)}
</For>
</div>
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<div class="bg-primary border border-white/5 p-4 rounded-lg text-center flex flex-col gap-y-2">
<h2>{props.title}</h2>
<div class="flex flex-col">
{props.children}
</div>
<div class="flex flex-row gap-x-4 [&>*]:flex-1">
<For each={merged.buttons}>
{button => (
<ModalButton props={button} />
)}
</For>
</div>
</div>
</div>
</Portal>
</Show>
</div>
</Portal>
);
}

View file

@ -1,8 +1,5 @@
import { mergeRefs } from '@solid-primitives/refs';
import {
Show,
createEffect,
createSignal } from 'solid-js';
import { createEffect } from 'solid-js';
import type {
Accessor,
JSX,
@ -22,14 +19,11 @@ declare namespace Popup {
}
function Popup(props: Popup.PopupProps) {
const [localVisible, setLocalVisible] = createSignal(false);
const [animate, setAnimate] = createSignal('animate-fade-in');
let popupRef!: HTMLDivElement;
function onMouseDown(e: MouseEvent) {
e.stopPropagation();
if (!popupRef || !localVisible())
if (!popupRef || !props.visible())
return;
const clicked = e.target === popupRef || popupRef.contains(e.target as Node);
@ -38,34 +32,24 @@ function Popup(props: Popup.PopupProps) {
}
createEffect(() => {
if (props.visible()) {
if (props.visible())
document.addEventListener('mousedown', onMouseDown);
setAnimate('animate-fade-in');
setLocalVisible(true);
}
else {
else
document.removeEventListener('mousedown', onMouseDown);
setAnimate('animate-fade-out');
setTimeout(() => {
setLocalVisible(false);
}, 150);
}
});
return (
<Show when={localVisible()}>
<Portal
mount={props.mount || document.body}
ref={mergeRefs((el) => {
el.classList.add('absolute', 'z-[1000]');
return el;
}, props.ref)}
>
<div ref={popupRef} style={props.style || ''} class={`${animate()} ${props.class || ''}`}>
{props.children}
</div>
</Portal>
</Show>
<Portal
mount={props.mount || document.body}
ref={mergeRefs((el) => {
el.classList.add('absolute', 'z-[1000]', 'pointer-events-none');
return el;
}, props.ref)}
>
<div ref={popupRef} style={props.style || ''} class={`transition-opacity ${props.visible() ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'} ${props.class || ''}`}>
{props.children}
</div>
</Portal>
);
}