Created
February 21, 2022 14:35
-
-
Save heyitsarpit/3e0685d651d9bd3bb0ed5bd8b4aa95f0 to your computer and use it in GitHub Desktop.
Custom Dialog built with Radix UI
This file contains hidden or 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 * as RadixDialog from '@radix-ui/react-dialog' | |
import { keyframes, styled } from '@stitches/react' | |
import clsx from 'clsx' | |
import { forwardRef } from 'react' | |
/** | |
* This is a custom dialog component that has tailwind classes and and some structure pre built. | |
* | |
* Example: | |
* ```tsx | |
* import { Dialog } from './Dialog'; | |
* | |
* export function Modal() ( | |
* <Dialog.Root> | |
* <Dialog.Trigger>Dialog trigger</Dialog.Trigger> | |
* <Dialog.Content title="Hello World"> | |
* <div>Dialog Content</div> | |
* </Dialog.Content> | |
* </Dialog.Root> | |
* ); | |
* ``` | |
*/ | |
const Root = ({ children, ...props }: RadixDialog.DialogProps) => { | |
return <RadixDialog.Root {...props}>{children}</RadixDialog.Root> | |
} | |
const Trigger = RadixDialog.Trigger | |
/** ------------------ Dialog.Content --------------------------- */ | |
const overlayEnter = keyframes({ | |
'0%': { opacity: 0 }, | |
'100%': { opacity: 1 } | |
}) | |
const overlayExit = keyframes({ | |
'0%': { opacity: 1 }, | |
'100%': { opacity: 0 } | |
}) | |
const contentEnter = keyframes({ | |
'0%': { opacity: 0, transform: 'translate(0%, 100%)' }, | |
'100%': { opacity: 1, transform: 'translate(0%, 0%)' } | |
}) | |
const contentExit = keyframes({ | |
'0%': { opacity: 1, transform: 'translate(0%, 0%)' }, | |
'100%': { opacity: 0, transform: 'translate(0%, 100%)' } | |
}) | |
const contentEnterMD = keyframes({ | |
'0%': { opacity: 0, transform: 'translate(-50%, 70%) scale(.97)' }, | |
'100%': { opacity: 1, transform: 'translate(-50%, 50%) scale(1)' } | |
}) | |
const contentExitMD = keyframes({ | |
'0%': { opacity: 1, transform: 'translate(-50%, 50%) scale(1)' }, | |
'100%': { opacity: 0, transform: 'translate(-50%, 70%) scale(.97)' } | |
}) | |
const StyledOverlay = styled(RadixDialog.Overlay, { | |
animationDuration: '300ms', | |
animationTimingFunction: 'ease-in-out', | |
'&[data-state="open"]': { animationName: overlayEnter }, | |
'&[data-state="closed"]': { animationName: overlayExit } | |
}) | |
const StyledContent = styled(RadixDialog.Content, { | |
animationDuration: '300ms', | |
animationTimingFunction: 'ease-in-out', | |
'@media (max-width: 768px)': { | |
'&[data-state="open"]': { animationName: contentEnter }, | |
'&[data-state="closed"]': { animationName: contentExit } | |
}, | |
'@media (min-width: 768px)': { | |
'&[data-state="open"]': { animationName: contentEnterMD }, | |
'&[data-state="closed"]': { animationName: contentExitMD } | |
} | |
}) | |
const Content = forwardRef< | |
HTMLDivElement, | |
RadixDialog.DialogContentProps & { title: string } | |
>(({ children, title, ...props }, forwardedRef) => { | |
return ( | |
<RadixDialog.Portal> | |
<StyledOverlay className='fixed z-[52] inset-0 bg-black/50 backdrop-blur-[10px]' /> | |
<StyledContent | |
{...props} | |
ref={forwardedRef} | |
className={clsx( | |
'fixed z-[100] bg-grey-11 py-8', | |
'rounded-t-xl md:rounded-md', | |
'bottom-0 md:bottom-1/2 md:left-1/2', | |
'md:-translate-x-1/2 md:translate-y-1/2', | |
'w-screen md:max-w-md', | |
'shadow-2xl shadow-black/70', | |
props.className | |
)}> | |
<div className='mx-auto w-20 h-[5px] rounded-lg bg-grey-9 -translate-y-4 cursor-all-scroll md:hidden block'></div> | |
<div className='flex items-center justify-between px-6 py-4 mb-6 md:mb-2 border-y border-grey-10 md:py-0 md:border-none'> | |
<RadixDialog.Title className='md:heading title-1'>{title}</RadixDialog.Title> | |
<RadixDialog.Close className='hidden p-2 rounded-full focus:ring md:block hover:bg-grey-8 focus:bg-grey-8'> | |
<img src='/images/logos/cross.svg' alt='close' /> | |
</RadixDialog.Close> | |
</div> | |
<div className='px-6 pt-1 max-h-[80vh] overflow-y-auto'>{children}</div> | |
</StyledContent> | |
</RadixDialog.Portal> | |
) | |
}) | |
export const Dialog = { | |
Root, | |
Trigger, | |
Content | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment