command.tsx
1 'use client'; 2 3 import { Command as CommandPrimitive } from 'cmdk'; 4 import { SearchIcon } from 'lucide-react'; 5 import * as React from 'react'; 6 import { 7 Dialog, 8 DialogContent, 9 DialogDescription, 10 DialogHeader, 11 DialogTitle, 12 } from '@/components/ui/dialog'; 13 import { cn } from '@/lib/utils'; 14 15 function Command({ 16 className, 17 ...props 18 }: React.ComponentProps<typeof CommandPrimitive>) { 19 return ( 20 <CommandPrimitive 21 className={cn( 22 'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md', 23 className, 24 )} 25 data-slot="command" 26 {...props} 27 /> 28 ); 29 } 30 31 function CommandDialog({ 32 title = 'Command Palette', 33 description = 'Search for a command to run...', 34 children, 35 className, 36 showCloseButton = true, 37 ...props 38 }: React.ComponentProps<typeof Dialog> & { 39 title?: string; 40 description?: string; 41 className?: string; 42 showCloseButton?: boolean; 43 }) { 44 return ( 45 <Dialog {...props}> 46 <DialogHeader className="sr-only"> 47 <DialogTitle>{title}</DialogTitle> 48 <DialogDescription>{description}</DialogDescription> 49 </DialogHeader> 50 <DialogContent 51 className={cn('overflow-hidden p-0', className)} 52 showCloseButton={showCloseButton} 53 > 54 <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[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"> 55 {children} 56 </Command> 57 </DialogContent> 58 </Dialog> 59 ); 60 } 61 62 function CommandInput({ 63 className, 64 ...props 65 }: React.ComponentProps<typeof CommandPrimitive.Input>) { 66 return ( 67 <div 68 className="flex h-9 items-center gap-2 border-b px-3" 69 data-slot="command-input-wrapper" 70 > 71 <SearchIcon className="size-4 shrink-0 opacity-50" /> 72 <CommandPrimitive.Input 73 className={cn( 74 'placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50', 75 className, 76 )} 77 data-slot="command-input" 78 {...props} 79 /> 80 </div> 81 ); 82 } 83 84 function CommandList({ 85 className, 86 ...props 87 }: React.ComponentProps<typeof CommandPrimitive.List>) { 88 return ( 89 <CommandPrimitive.List 90 className={cn( 91 'max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', 92 className, 93 )} 94 data-slot="command-list" 95 {...props} 96 /> 97 ); 98 } 99 100 function CommandEmpty({ 101 ...props 102 }: React.ComponentProps<typeof CommandPrimitive.Empty>) { 103 return ( 104 <CommandPrimitive.Empty 105 className="py-6 text-center text-sm" 106 data-slot="command-empty" 107 {...props} 108 /> 109 ); 110 } 111 112 function CommandGroup({ 113 className, 114 ...props 115 }: React.ComponentProps<typeof CommandPrimitive.Group>) { 116 return ( 117 <CommandPrimitive.Group 118 className={cn( 119 'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium', 120 className, 121 )} 122 data-slot="command-group" 123 {...props} 124 /> 125 ); 126 } 127 128 function CommandSeparator({ 129 className, 130 ...props 131 }: React.ComponentProps<typeof CommandPrimitive.Separator>) { 132 return ( 133 <CommandPrimitive.Separator 134 className={cn('bg-border -mx-1 h-px', className)} 135 data-slot="command-separator" 136 {...props} 137 /> 138 ); 139 } 140 141 function CommandItem({ 142 className, 143 ...props 144 }: React.ComponentProps<typeof CommandPrimitive.Item>) { 145 return ( 146 <CommandPrimitive.Item 147 className={cn( 148 "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", 149 className, 150 )} 151 data-slot="command-item" 152 {...props} 153 /> 154 ); 155 } 156 157 function CommandShortcut({ 158 className, 159 ...props 160 }: React.ComponentProps<'span'>) { 161 return ( 162 <span 163 className={cn( 164 'text-muted-foreground ml-auto text-xs tracking-widest', 165 className, 166 )} 167 data-slot="command-shortcut" 168 {...props} 169 /> 170 ); 171 } 172 173 export { 174 Command, 175 CommandDialog, 176 CommandInput, 177 CommandList, 178 CommandEmpty, 179 CommandGroup, 180 CommandItem, 181 CommandShortcut, 182 CommandSeparator, 183 };