command.tsx raw
1 import { type DialogProps } from '@radix-ui/react-dialog'
2 import { Command as CommandPrimitive } from 'cmdk'
3 import { Search } from 'lucide-react'
4 import * as React from 'react'
5
6 import {
7 Dialog,
8 DialogContent,
9 DialogDescription,
10 DialogHeader,
11 DialogTitle
12 } from '@/components/ui/dialog'
13 import { ScrollArea } from '@/components/ui/scroll-area'
14 import { cn } from '@/lib/utils'
15
16 const Command = React.forwardRef<
17 React.ElementRef<typeof CommandPrimitive>,
18 React.ComponentPropsWithoutRef<typeof CommandPrimitive>
19 >(({ className, ...props }, ref) => (
20 <CommandPrimitive
21 ref={ref}
22 className={cn(
23 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
24 className
25 )}
26 {...props}
27 />
28 ))
29 Command.displayName = CommandPrimitive.displayName
30
31 const CommandDialog = ({
32 children,
33 classNames,
34 ...props
35 }: DialogProps & { classNames?: { content?: string } }) => {
36 return (
37 <Dialog {...props}>
38 <DialogHeader className="hidden">
39 <DialogTitle />
40 <DialogDescription />
41 </DialogHeader>
42 <DialogContent
43 className={cn(
44 'overflow-hidden p-0 shadow-lg top-4 translate-y-0 data-[state=closed]:slide-out-to-top-4 data-[state=open]:slide-in-from-top-4',
45 classNames?.content
46 )}
47 >
48 <Command
49 shouldFilter={false}
50 className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
51 >
52 {children}
53 </Command>
54 </DialogContent>
55 </Dialog>
56 )
57 }
58
59 const CommandInput = React.forwardRef<
60 React.ElementRef<typeof CommandPrimitive.Input>,
61 React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
62 >(({ className, ...props }, ref) => (
63 <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
64 <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
65 <CommandPrimitive.Input
66 ref={ref}
67 className={cn(
68 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 pr-6',
69 className
70 )}
71 {...props}
72 />
73 </div>
74 ))
75
76 CommandInput.displayName = CommandPrimitive.Input.displayName
77
78 const CommandList = React.forwardRef<
79 React.ElementRef<typeof CommandPrimitive.List>,
80 React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> & { scrollAreaClassName?: string }
81 >(({ className, scrollAreaClassName, ...props }, ref) => (
82 <ScrollArea className={scrollAreaClassName}>
83 <CommandPrimitive.List ref={ref} className={cn('overflow-x-hidden', className)} {...props} />
84 </ScrollArea>
85 ))
86
87 CommandList.displayName = CommandPrimitive.List.displayName
88
89 const CommandEmpty = React.forwardRef<
90 React.ElementRef<typeof CommandPrimitive.Empty>,
91 React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
92 >((props, ref) => (
93 <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />
94 ))
95
96 CommandEmpty.displayName = CommandPrimitive.Empty.displayName
97
98 const CommandGroup = React.forwardRef<
99 React.ElementRef<typeof CommandPrimitive.Group>,
100 React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
101 >(({ className, ...props }, ref) => (
102 <CommandPrimitive.Group
103 ref={ref}
104 className={cn(
105 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
106 className
107 )}
108 {...props}
109 />
110 ))
111
112 CommandGroup.displayName = CommandPrimitive.Group.displayName
113
114 const CommandSeparator = React.forwardRef<
115 React.ElementRef<typeof CommandPrimitive.Separator>,
116 React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
117 >(({ className, ...props }, ref) => (
118 <CommandPrimitive.Separator
119 ref={ref}
120 className={cn('-mx-1 h-px bg-border', className)}
121 {...props}
122 />
123 ))
124 CommandSeparator.displayName = CommandPrimitive.Separator.displayName
125
126 const CommandItem = React.forwardRef<
127 React.ElementRef<typeof CommandPrimitive.Item>,
128 React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
129 >(({ className, ...props }, ref) => (
130 <CommandPrimitive.Item
131 ref={ref}
132 className={cn(
133 'relative flex cursor-pointer gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
134 className
135 )}
136 {...props}
137 />
138 ))
139
140 CommandItem.displayName = CommandPrimitive.Item.displayName
141
142 const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
143 return (
144 <span
145 className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
146 {...props}
147 />
148 )
149 }
150 CommandShortcut.displayName = 'CommandShortcut'
151
152 export {
153 Command,
154 CommandDialog,
155 CommandEmpty,
156 CommandGroup,
157 CommandInput,
158 CommandItem,
159 CommandList,
160 CommandSeparator,
161 CommandShortcut
162 }
163