Improve dialog logic, add "asDialog" helper

This commit is contained in:
DaneEveritt 2022-07-03 13:29:23 -04:00
parent 822949408f
commit a4feed24a8
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
10 changed files with 131 additions and 77 deletions

View file

@ -1,38 +1,37 @@
import React, { useEffect, useState } from 'react';
import React, { useRef, useState } from 'react';
import { Dialog as HDialog } from '@headlessui/react';
import { Button } from '@/components/elements/button/index';
import { XIcon } from '@heroicons/react/solid';
import DialogIcon, { IconPosition } from '@/components/elements/dialog/DialogIcon';
import { AnimatePresence, motion, useAnimation } from 'framer-motion';
import ConfirmationDialog from '@/components/elements/dialog/ConfirmationDialog';
import DialogContext from './context';
import DialogFooter from '@/components/elements/dialog/DialogFooter';
import styles from './style.module.css';
import { AnimatePresence, motion } from 'framer-motion';
import { DialogContext, IconPosition, RenderDialogProps, styles } from './';
export interface DialogProps {
open: boolean;
onClose: () => void;
}
export interface FullDialogProps extends DialogProps {
hideCloseIcon?: boolean;
preventExternalClose?: boolean;
title?: string;
description?: string | undefined;
children?: React.ReactNode;
}
const spring = { type: 'spring', damping: 15, stiffness: 300, duration: 0.15 };
const variants = {
open: { opacity: 1, scale: 1, transition: spring },
closed: { opacity: 0, scale: 0.85, transition: spring },
open: {
scale: 1,
opacity: 1,
transition: {
type: 'spring',
damping: 15,
stiffness: 300,
duration: 0.15,
},
},
closed: {
scale: 0.75,
opacity: 0,
transition: {
type: 'easeIn',
duration: 0.15,
},
},
bounce: {
scale: 0.95,
opacity: 1,
transition: { type: 'linear', duration: 0.075 },
},
};
const Dialog = ({
export default ({
open,
title,
description,
@ -40,28 +39,25 @@ const Dialog = ({
hideCloseIcon,
preventExternalClose,
children,
}: FullDialogProps) => {
const controls = useAnimation();
}: RenderDialogProps) => {
const container = useRef<HTMLDivElement>(null);
const [icon, setIcon] = useState<React.ReactNode>();
const [footer, setFooter] = useState<React.ReactNode>();
const [iconPosition, setIconPosition] = useState<IconPosition>('title');
const [down, setDown] = useState(false);
const onContainerClick = (down: boolean, e: React.MouseEvent<HTMLDivElement>): void => {
if (e.target instanceof HTMLElement && container.current?.isSameNode(e.target)) {
setDown(down);
}
};
const onDialogClose = (): void => {
if (!preventExternalClose) {
return onClose();
}
controls
.start('bounce')
.then(() => controls.start('open'))
.catch(console.error);
};
useEffect(() => {
controls.start(open ? 'open' : 'closed').catch(console.error);
}, [open]);
return (
<AnimatePresence>
{open && (
@ -78,10 +74,17 @@ const Dialog = ({
>
<div className={'fixed inset-0 bg-gray-900/50 z-40'} />
<div className={'fixed inset-0 overflow-y-auto z-50'}>
<div className={styles.container}>
<div
ref={container}
className={styles.container}
onMouseDown={onContainerClick.bind(this, true)}
onMouseUp={onContainerClick.bind(this, false)}
>
<HDialog.Panel
as={motion.div}
animate={controls}
initial={'closed'}
animate={down ? 'bounce' : 'open'}
exit={'closed'}
variants={variants}
className={styles.panel}
>
@ -125,11 +128,3 @@ const Dialog = ({
</AnimatePresence>
);
};
const _Dialog = Object.assign(Dialog, {
Confirm: ConfirmationDialog,
Footer: DialogFooter,
Icon: DialogIcon,
});
export default _Dialog;