Skip to content

Instantly share code, notes, and snippets.

@heyitsarpit
Created February 21, 2022 14:35
Show Gist options
  • Save heyitsarpit/3e0685d651d9bd3bb0ed5bd8b4aa95f0 to your computer and use it in GitHub Desktop.
Save heyitsarpit/3e0685d651d9bd3bb0ed5bd8b4aa95f0 to your computer and use it in GitHub Desktop.
Custom Dialog built with Radix UI
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