feat(mobile): add Drawer (vaul wrapper) for native-feel bottom sheets
This commit is contained in:
92
src/components/shared/drawer.tsx
Normal file
92
src/components/shared/drawer.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { Drawer as VaulDrawer } from 'vaul';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Drawer = ({
|
||||
shouldScaleBackground = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof VaulDrawer.Root>) => (
|
||||
<VaulDrawer.Root shouldScaleBackground={shouldScaleBackground} {...props} />
|
||||
);
|
||||
Drawer.displayName = 'Drawer';
|
||||
|
||||
const DrawerTrigger = VaulDrawer.Trigger;
|
||||
const DrawerPortal = VaulDrawer.Portal;
|
||||
const DrawerClose = VaulDrawer.Close;
|
||||
|
||||
const DrawerOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof VaulDrawer.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof VaulDrawer.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<VaulDrawer.Overlay
|
||||
ref={ref}
|
||||
className={cn('fixed inset-0 z-50 bg-black/60', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerOverlay.displayName = 'DrawerOverlay';
|
||||
|
||||
const DrawerContent = React.forwardRef<
|
||||
React.ElementRef<typeof VaulDrawer.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof VaulDrawer.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DrawerPortal>
|
||||
<DrawerOverlay />
|
||||
<VaulDrawer.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-xl border bg-background pb-safe-bottom',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="mx-auto mt-2 h-1.5 w-12 rounded-full bg-muted" aria-hidden />
|
||||
{children}
|
||||
</VaulDrawer.Content>
|
||||
</DrawerPortal>
|
||||
));
|
||||
DrawerContent.displayName = 'DrawerContent';
|
||||
|
||||
const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn('grid gap-1.5 p-4 text-left', className)} {...props} />
|
||||
);
|
||||
DrawerHeader.displayName = 'DrawerHeader';
|
||||
|
||||
const DrawerTitle = React.forwardRef<
|
||||
React.ElementRef<typeof VaulDrawer.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof VaulDrawer.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<VaulDrawer.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerTitle.displayName = 'DrawerTitle';
|
||||
|
||||
const DrawerDescription = React.forwardRef<
|
||||
React.ElementRef<typeof VaulDrawer.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof VaulDrawer.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<VaulDrawer.Description
|
||||
ref={ref}
|
||||
className={cn('text-sm text-muted-foreground', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerDescription.displayName = 'DrawerDescription';
|
||||
|
||||
export {
|
||||
Drawer,
|
||||
DrawerPortal,
|
||||
DrawerOverlay,
|
||||
DrawerTrigger,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerDescription,
|
||||
};
|
||||
Reference in New Issue
Block a user