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