Last active
October 31, 2024 13:35
-
-
Save wking-io/c2f93179562ca7efd5c2b64d8bace577 to your computer and use it in GitHub Desktop.
AnimatePresence Fix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { AnimatePresence, motion, Variants } from 'framer-motion' | |
import * as DialogPrimitive from '@radix-ui/react-dialog' | |
import { forwardRef, PropsWithChildren, useState } from 'react' | |
import clsx from 'clsx' | |
export default function Page() { | |
const [open, setOpen] = useState(false) | |
return ( | |
<div> | |
<button onClick={() => setOpen(true)}>Open Modal</button> | |
<Dialog open={open} onClose={() => setOpen(false)}> | |
Hello world | |
</Dialog> | |
</div> | |
) | |
} | |
function Dialog({ | |
open, | |
onClose, | |
className, | |
children, | |
}: PropsWithChildren<{ open: boolean; onClose(): void; className?: string }>) { | |
return ( | |
<Fade show={open}> | |
<DialogPrimitive.Root open={open} onOpenChange={onClose}> | |
<DialogPrimitive.Portal> | |
<div className="relative z-50"> | |
<Fade className="fixed inset-0 z-50" nested> | |
<DialogPrimitive.Overlay className="bg-foreground/[80%] fixed inset-0 flex w-screen justify-center overflow-y-auto p-2 focus:outline-0" /> | |
</Fade> | |
<div className="fixed inset-0 z-50 w-screen overflow-y-auto pt-6 sm:pt-0"> | |
<div className="grid min-h-full grid-rows-[4rem_auto_auto] justify-items-center p-4 lg:grid-rows-[8rem_auto_auto] 2xl:grid-rows-[12rem_auto_auto]"> | |
{open && ( | |
<DialogPrimitive.Content | |
asChild | |
onInteractOutside={(e) => { | |
// Don't close the dialog when a 1password button is clicked inside a password field | |
if (e.target.tagName === 'COM-1PASSWORD-BUTTON') { | |
e.preventDefault() | |
} | |
}} | |
> | |
<motion.div | |
initial={{ opacity: 0, transform: 'translateY(10%)' }} | |
animate={{ opacity: 1, transform: 'translateY(0)' }} | |
exit={{ opacity: 0, transform: 'translateY(10%)' }} | |
className={clsx('row-start-2 w-full max-w-lg', className)} | |
> | |
<div | |
className={clsx( | |
'bg-background shadow-dialog relative overflow-hidden rounded-2xl p-5 transition-all duration-300 forced-colors:outline', | |
)} | |
> | |
{children} | |
</div> | |
</motion.div> | |
</DialogPrimitive.Content> | |
)} | |
</div> | |
</div> | |
</div> | |
</DialogPrimitive.Portal> | |
</DialogPrimitive.Root> | |
</Fade> | |
) | |
} | |
export const Fade = forwardRef< | |
HTMLDivElement, | |
PropsWithChildren<{ show?: boolean; nested?: boolean; className?: string }> | |
>(({ children, show = false, nested = false, ...props }, ref) => { | |
const child = ( | |
<motion.div | |
ref={ref} | |
initial={{ opacity: 0 }} | |
animate={{ opacity: 1 }} | |
exit={{ opacity: 0 }} | |
{...props} | |
> | |
{children} | |
</motion.div> | |
) | |
return nested ? ( | |
child | |
) : ( | |
<AnimatePresence>{show ? child : null}</AnimatePresence> | |
) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment