返回 AiToEarn
sheet.tsx
根目录 / project / aitoearn-web / src / components / ui / sheet.tsx
1 'use client'
2
3 import * as DialogPrimitive from '@radix-ui/react-dialog'
4 import { X } from 'lucide-react'
5 import * as React from 'react'
6 import { cn } from '@/utils/className'
7
8 const Sheet = DialogPrimitive.Root
9 const SheetTrigger = DialogPrimitive.Trigger
10 const SheetClose = DialogPrimitive.Close
11 const SheetPortal = DialogPrimitive.Portal
12
13 const SheetOverlay = React.forwardRef<
14 React.ElementRef<typeof DialogPrimitive.Overlay>,
15 React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
16 >(({ className, ...props }, ref) => (
17 <DialogPrimitive.Overlay
18 ref={ref}
19 className={cn(
20 'fixed inset-0 z-50 bg-foreground/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
21 className,
22 )}
23 {...props}
24 />
25 ))
26 SheetOverlay.displayName = DialogPrimitive.Overlay.displayName
27
28 type SheetSide = 'top' | 'right' | 'bottom' | 'left'
29
30 const sheetSideClassMap: Record<SheetSide, string> = {
31 top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
32 right: 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
33 bottom: 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
34 left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
35 }
36
37 interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
38 side?: SheetSide
39 overlayClassName?: string
40 hideCloseButton?: boolean
41 closeLabel?: string
42 }
43
44 const SheetContent = React.forwardRef<
45 React.ElementRef<typeof DialogPrimitive.Content>,
46 SheetContentProps
47 >(({ side = 'right', className, children, overlayClassName, hideCloseButton, closeLabel = 'Close', ...props }, ref) => (
48 <SheetPortal>
49 <SheetOverlay className={overlayClassName} />
50 <DialogPrimitive.Content
51 ref={ref}
52 className={cn(
53 'fixed z-50 gap-4 bg-background p-6 shadow-2xl transition ease-in-out data-[state=closed]:animate-out data-[state=open]:animate-in data-[state=closed]:duration-300 data-[state=open]:duration-500',
54 sheetSideClassMap[side],
55 className,
56 )}
57 {...props}
58 >
59 {children}
60 {!hideCloseButton && (
61 <DialogPrimitive.Close className="absolute right-4 top-4 rounded-md p-1 opacity-70 ring-offset-background transition-opacity hover:bg-accent hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none">
62 <X className="h-4 w-4" />
63 <span className="sr-only">{closeLabel}</span>
64 </DialogPrimitive.Close>
65 )}
66 </DialogPrimitive.Content>
67 </SheetPortal>
68 ))
69 SheetContent.displayName = DialogPrimitive.Content.displayName
70
71 function SheetHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
72 return <div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
73 }
74 SheetHeader.displayName = 'SheetHeader'
75
76 function SheetFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
77 return <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} />
78 }
79 SheetFooter.displayName = 'SheetFooter'
80
81 const SheetTitle = React.forwardRef<
82 React.ElementRef<typeof DialogPrimitive.Title>,
83 React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
84 >(({ className, ...props }, ref) => (
85 <DialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold text-foreground', className)} {...props} />
86 ))
87 SheetTitle.displayName = DialogPrimitive.Title.displayName
88
89 const SheetDescription = React.forwardRef<
90 React.ElementRef<typeof DialogPrimitive.Description>,
91 React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
92 >(({ className, ...props }, ref) => (
93 <DialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
94 ))
95 SheetDescription.displayName = DialogPrimitive.Description.displayName
96
97 export {
98 Sheet,
99 SheetClose,
100 SheetContent,
101 SheetDescription,
102 SheetFooter,
103 SheetHeader,
104 SheetOverlay,
105 SheetPortal,
106 SheetTitle,
107 SheetTrigger,
108 }
109
109 lines Plain Text