Repository Public
1'use client';2import * as React from 'react';3import * as D from '@radix-ui/react-dialog';4import { X } from 'lucide-react';5import { cn } from '@/lib/cn';6import { useBreakpoint } from '@/hooks/use-viewport';7import { BottomSheet } from './bottom-sheet';89/** Edge-anchored panel (drawer). `side="bottom"` is the mobile sheet. */10export function Sheet({11 open, onOpenChange, title, side = 'right', children, className, headerExtra,12}: {13 open: boolean;14 onOpenChange: (open: boolean) => void;15 title: string;16 side?: 'left' | 'right' | 'bottom';17 children: React.ReactNode;18 className?: string;19 headerExtra?: React.ReactNode;20}) {21 const bp = useBreakpoint();22 if (side === 'bottom' || (bp === 'mobile' && side === 'right')) {23 return (24 <BottomSheet open={open} onOpenChange={onOpenChange} title={title} headerExtra={headerExtra} className={className}>25 {children}26 </BottomSheet>27 );28 }29 const pos = {30 right: 'anim-slide-right right-0 top-0 h-full w-[min(480px,100vw)] border-l',31 left: 'anim-slide-left left-0 top-0 h-full w-[min(360px,88vw)] border-r',32 bottom: 'anim-slide-up bottom-0 left-0 max-h-[85dvh] w-full rounded-t-lg border-t',33 }[side];34 return (35 <D.Root open={open} onOpenChange={onOpenChange}>36 <D.Portal>37 <D.Overlay className="anim-fade fixed inset-0 z-50 bg-scrim" />38 <D.Content className={cn('fixed z-50 flex flex-col border-card-line bg-surface shadow-pop focus:outline-none', pos, className)}>39 <div className={cn('flex items-center gap-2 border-b border-line px-4 py-2.5', 'pt-[max(10px,env(safe-area-inset-top))]')}>40 <D.Title className="min-w-0 flex-1 truncate text-sm font-semibold">{title}</D.Title>41 <D.Description className="sr-only">{title}</D.Description>42 {headerExtra}43 <D.Close aria-label="Close" className="inline-flex size-7 items-center justify-center rounded-sm text-muted hover:bg-surface-2 hover:text-text pointer-coarse:size-11">44 <X className="size-4" />45 </D.Close>46 </div>47 <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain pb-[env(safe-area-inset-bottom)]">{children}</div>48 </D.Content>49 </D.Portal>50 </D.Root>51 );52}53