command.tsx 4.7 KB

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