1- import React , { useRef } from 'react' ;
1+ import React , { useEffect , useState } from 'react' ;
22import { Dialog as HDialog } from '@headlessui/react' ;
33import { Button } from '@/components/elements/button/index' ;
44import { XIcon } from '@heroicons/react/solid' ;
5- import DialogIcon from '@/components/elements/dialog/DialogIcon' ;
6- import { AnimatePresence , motion } from 'framer-motion' ;
5+ import DialogIcon , { IconPosition } from '@/components/elements/dialog/DialogIcon' ;
6+ import { AnimatePresence , motion , useAnimation } from 'framer-motion' ;
77import ConfirmationDialog from '@/components/elements/dialog/ConfirmationDialog' ;
88import DialogContext from './context' ;
99import DialogFooter from '@/components/elements/dialog/DialogFooter' ;
@@ -16,20 +16,56 @@ export interface DialogProps {
1616
1717export interface FullDialogProps extends DialogProps {
1818 hideCloseIcon ?: boolean ;
19+ preventExternalClose ?: boolean ;
1920 title ?: string ;
2021 description ?: string | undefined ;
2122 children ?: React . ReactNode ;
2223}
2324
24- const Dialog = ( { open, title, description, onClose, hideCloseIcon, children } : FullDialogProps ) => {
25- const ref = useRef < HTMLDivElement > ( null ) ;
26- const icon = useRef < HTMLDivElement > ( null ) ;
27- const buttons = useRef < HTMLDivElement > ( null ) ;
25+ const spring = { type : 'spring' , damping : 15 , stiffness : 300 , duration : 0.15 } ;
26+ const variants = {
27+ open : { opacity : 1 , scale : 1 , transition : spring } ,
28+ closed : { opacity : 0 , scale : 0.85 , transition : spring } ,
29+ bounce : {
30+ scale : 0.95 ,
31+ transition : { type : 'linear' , duration : 0.075 } ,
32+ } ,
33+ } ;
34+
35+ const Dialog = ( {
36+ open,
37+ title,
38+ description,
39+ onClose,
40+ hideCloseIcon,
41+ preventExternalClose,
42+ children,
43+ } : FullDialogProps ) => {
44+ const controls = useAnimation ( ) ;
45+
46+ const [ icon , setIcon ] = useState < React . ReactNode > ( ) ;
47+ const [ footer , setFooter ] = useState < React . ReactNode > ( ) ;
48+ const [ iconPosition , setIconPosition ] = useState < IconPosition > ( 'title' ) ;
49+
50+ const onDialogClose = ( ) : void => {
51+ if ( ! preventExternalClose ) {
52+ return onClose ( ) ;
53+ }
54+
55+ controls
56+ . start ( 'bounce' )
57+ . then ( ( ) => controls . start ( 'open' ) )
58+ . catch ( console . error ) ;
59+ } ;
60+
61+ useEffect ( ( ) => {
62+ controls . start ( open ? 'open' : 'closed' ) . catch ( console . error ) ;
63+ } , [ open ] ) ;
2864
2965 return (
3066 < AnimatePresence >
3167 { open && (
32- < DialogContext . Provider value = { { icon , buttons } } >
68+ < DialogContext . Provider value = { { setIcon , setFooter , setIconPosition } } >
3369 < HDialog
3470 static
3571 as = { motion . div }
@@ -38,23 +74,22 @@ const Dialog = ({ open, title, description, onClose, hideCloseIcon, children }:
3874 exit = { { opacity : 0 } }
3975 transition = { { duration : 0.15 } }
4076 open = { open }
41- onClose = { onClose }
77+ onClose = { onDialogClose }
4278 >
4379 < div className = { 'fixed inset-0 bg-gray-900/50 z-40' } />
4480 < div className = { 'fixed inset-0 overflow-y-auto z-50' } >
4581 < div className = { styles . container } >
4682 < HDialog . Panel
4783 as = { motion . div }
48- initial = { { opacity : 0 , scale : 0.85 } }
49- animate = { { opacity : 1 , scale : 1 } }
50- exit = { { opacity : 0 } }
51- transition = { { type : 'spring' , damping : 15 , stiffness : 300 , duration : 0.15 } }
84+ animate = { controls }
85+ variants = { variants }
5286 className = { styles . panel }
5387 >
5488 < div className = { 'flex p-6 overflow-y-auto' } >
55- < div ref = { ref } className = { 'flex-1 max-h-[70vh]' } >
89+ { iconPosition === 'container' && icon }
90+ < div className = { 'flex-1 max-h-[70vh]' } >
5691 < div className = { 'flex items-center' } >
57- < div ref = { icon } />
92+ { iconPosition !== 'container' && icon }
5893 < div >
5994 { title && (
6095 < HDialog . Title className = { styles . title } > { title } </ HDialog . Title >
@@ -67,7 +102,7 @@ const Dialog = ({ open, title, description, onClose, hideCloseIcon, children }:
67102 { children }
68103 </ div >
69104 </ div >
70- < div ref = { buttons } />
105+ { footer }
71106 { /* Keep this below the other buttons so that it isn't the default focus if they're present. */ }
72107 { ! hideCloseIcon && (
73108 < div className = { 'absolute right-0 top-0 m-4' } >
0 commit comments