-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Created a reusable "Drawer" component #89
Changes from all commits
a82f54f
f68390d
bc09c4c
d2fa0dd
9bb278b
7eca326
943f27f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/** | ||
* This file is based on the Sheet component from shadcn and customized for our needs. | ||
* The Sheet component of shadcn is based on the Dialog component of Radix UI. | ||
* | ||
* See the official docs for more info: | ||
* shadcn/ui: https://ui.shadcn.com/docs/components/sheet | ||
* Radix UI: https://www.radix-ui.com/themes/docs/components/dialog | ||
*/ | ||
'use client'; | ||
|
||
import { Icon } from '@/components/ui'; | ||
import { cn } from '@/lib/tailwind/utils'; | ||
|
||
import { | ||
Close as PrimitiveClose, | ||
Content as PrimitiveContent, | ||
Description as PrimitiveDescription, | ||
Overlay as PrimitiveOverlay, | ||
Portal as PrimitivePortal, | ||
Root as PrimitiveRoot, | ||
Title as PrimitiveTitle, | ||
Trigger as PrimitiveTrigger, | ||
} from '@radix-ui/react-dialog'; | ||
import { cva, type VariantProps } from 'class-variance-authority'; | ||
import { ComponentPropsWithoutRef, ElementRef, forwardRef, HTMLAttributes } from 'react'; | ||
|
||
const DrawerRoot = PrimitiveRoot; | ||
const DrawerTrigger = PrimitiveTrigger; | ||
const DrawerClose = PrimitiveClose; | ||
const DrawerPortal = PrimitivePortal; | ||
|
||
const DrawerOverlay = forwardRef< | ||
ElementRef<typeof PrimitiveOverlay>, | ||
ComponentPropsWithoutRef<typeof PrimitiveOverlay> | ||
>(({ className, ...props }, ref) => ( | ||
<PrimitiveOverlay | ||
className={cn( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I liked how you classify className by it's categories! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good idea! Shall we create a new issue for that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created #91 |
||
'fixed inset-0 z-50', | ||
'bg-overlay', | ||
'data-[state=open]:animate-fadeIn data-[state=closed]:animate-fadeOut', | ||
className, | ||
)} | ||
{...props} | ||
ref={ref} | ||
/> | ||
)); | ||
DrawerOverlay.displayName = PrimitiveOverlay.displayName; | ||
|
||
const DrawerVariants = cva(cn('fixed z-50 bg-white flex flex-col'), { | ||
variants: { | ||
side: { | ||
bottom: cn( | ||
'inset-x-0 bottom-0 rounded-t max-h-[calc(100vh-2rem)]', | ||
'data-[state=open]:animate-slideInFromBottom data-[state=closed]:animate-slideOutToBottom', | ||
), | ||
right: cn( | ||
'inset-y-0 right-0 h-full w-5/6 max-w-sm', | ||
'data-[state=open]:animate-slideInFromRight data-[state=closed]:animate-slideOutToRight', | ||
), | ||
}, | ||
}, | ||
defaultVariants: { | ||
side: 'bottom', | ||
}, | ||
}); | ||
|
||
interface DrawerContentProps | ||
extends ComponentPropsWithoutRef<typeof PrimitiveContent>, | ||
VariantProps<typeof DrawerVariants> {} | ||
|
||
const DrawerContent = forwardRef<ElementRef<typeof PrimitiveContent>, DrawerContentProps>( | ||
({ side, className, children, ...props }, ref) => ( | ||
<DrawerPortal> | ||
<DrawerOverlay /> | ||
<PrimitiveContent ref={ref} className={cn(DrawerVariants({ side }), className)} {...props}> | ||
{children} | ||
<DrawerClose className={cn('absolute right-3 top-3')}> | ||
<Icon iconName="close" color="black" size="sm" /> | ||
<span className="sr-only">Close</span> | ||
</DrawerClose> | ||
</PrimitiveContent> | ||
</DrawerPortal> | ||
), | ||
); | ||
DrawerContent.displayName = PrimitiveContent.displayName; | ||
|
||
const DrawerHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => ( | ||
<div | ||
className={cn( | ||
'h-12 shrink-0 px-4 border-b border-gray-light grow-1', | ||
'flex items-center', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
); | ||
DrawerHeader.displayName = 'DrawerHeader'; | ||
|
||
/** | ||
* This is a custom component that we use to wrap the body (between header and footer) of the dialog. | ||
*/ | ||
const DrawerBody = forwardRef<ElementRef<'div'>, HTMLAttributes<HTMLDivElement>>( | ||
({ className, ...props }, ref) => ( | ||
<div | ||
ref={ref} | ||
className={cn('px-4 pt-4 pb-6 overflow-y-auto max-h-full', className)} | ||
{...props} | ||
/> | ||
), | ||
); | ||
DrawerBody.displayName = 'DrawerBody'; | ||
|
||
const DrawerFooter = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => ( | ||
<div className={cn('mt-auto px-4 pt-2 pb-12 flex justify-end gap-4', className)} {...props} /> | ||
); | ||
DrawerFooter.displayName = 'DrawerFooter'; | ||
|
||
const DrawerTitle = forwardRef< | ||
ElementRef<typeof PrimitiveTitle>, | ||
ComponentPropsWithoutRef<typeof PrimitiveTitle> | ||
>(({ className, ...props }, ref) => ( | ||
<PrimitiveTitle ref={ref} className={cn('text-2xl', className)} {...props} /> | ||
)); | ||
DrawerTitle.displayName = PrimitiveTitle.displayName; | ||
|
||
const DrawerDescription = forwardRef< | ||
ElementRef<typeof PrimitiveDescription>, | ||
ComponentPropsWithoutRef<typeof PrimitiveDescription> | ||
>(({ className, ...props }, ref) => ( | ||
<PrimitiveDescription ref={ref} className={cn('', className)} {...props} /> | ||
)); | ||
DrawerDescription.displayName = PrimitiveDescription.displayName; | ||
|
||
export { | ||
DrawerBody, | ||
DrawerClose, | ||
DrawerContent, | ||
DrawerDescription, | ||
DrawerFooter, | ||
DrawerHeader, | ||
DrawerOverlay, | ||
DrawerPortal, | ||
DrawerRoot, | ||
DrawerTitle, | ||
DrawerTrigger, | ||
DrawerVariants, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/** | ||
* This file is used as an example for the Drawer component. | ||
* Once you're done with the example, you can delete this file. | ||
*/ | ||
'use client'; | ||
|
||
import { | ||
Button, | ||
DrawerBody, | ||
DrawerClose, | ||
DrawerContent, | ||
DrawerFooter, | ||
DrawerHeader, | ||
DrawerRoot, | ||
DrawerTitle, | ||
DrawerTrigger, | ||
} from '@/components/ui'; | ||
|
||
import { useState } from 'react'; | ||
|
||
export const DrawerUsageExample = () => { | ||
const [isDrawerOpen, setIsDrawerOpen] = useState(false); | ||
|
||
const handleDelete = () => { | ||
alert('Deleted!'); | ||
setIsDrawerOpen(false); | ||
}; | ||
|
||
return ( | ||
<DrawerRoot open={isDrawerOpen} onOpenChange={setIsDrawerOpen}> | ||
<DrawerTrigger asChild> | ||
<Button>Open</Button> | ||
</DrawerTrigger> | ||
<DrawerContent side="bottom"> | ||
<DrawerHeader> | ||
<DrawerTitle>Delete Container</DrawerTitle> | ||
</DrawerHeader> | ||
<DrawerBody> | ||
<ol> | ||
<li>1. Are you sure you want to delete?</li> | ||
<li>2. Are you sure you want to delete?</li> | ||
<li>3. Are you sure you want to delete?</li> | ||
<li>4. Are you sure you want to delete?</li> | ||
<li>5. Are you sure you want to delete?</li> | ||
<li>6. Are you sure you want to delete?</li> | ||
<li>7. Are you sure you want to delete?</li> | ||
<li>8. Are you sure you want to delete?</li> | ||
<li>9. Are you sure you want to delete?</li> | ||
<li>10. Are you sure you want to delete?</li> | ||
<li>11. Are you sure you want to delete?</li> | ||
<li>12. Are you sure you want to delete?</li> | ||
<li>13. Are you sure you want to delete?</li> | ||
<li>14. Are you sure you want to delete?</li> | ||
<li>15. Are you sure you want to delete?</li> | ||
<li>16. Are you sure you want to delete?</li> | ||
<li>17. Are you sure you want to delete?</li> | ||
<li>18. Are you sure you want to delete?</li> | ||
<li>19. Are you sure you want to delete?</li> | ||
<li>20. Are you sure you want to delete?</li> | ||
</ol> | ||
</DrawerBody> | ||
<DrawerFooter> | ||
<DrawerClose asChild> | ||
<Button variant="cancel" size="sm"> | ||
Cancel | ||
</Button> | ||
</DrawerClose> | ||
<Button variant="error" size="sm" onClick={handleDelete}> | ||
Delete | ||
</Button> | ||
</DrawerFooter> | ||
</DrawerContent> | ||
</DrawerRoot> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you still need this
DialogBody
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, Yes, don't care about this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆