snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
249
apps/v4/registry/bases/aria/ui/command.tsx
Normal file
249
apps/v4/registry/bases/aria/ui/command.tsx
Normal file
@@ -0,0 +1,249 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { cn } from "cn"
|
||||
import {
|
||||
Autocomplete,
|
||||
Collection,
|
||||
composeRenderProps,
|
||||
Header,
|
||||
Input,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuSection,
|
||||
SearchField,
|
||||
Separator,
|
||||
useFilter,
|
||||
type AutocompleteProps,
|
||||
type InputProps,
|
||||
type MenuItemProps,
|
||||
type MenuProps,
|
||||
type MenuSectionProps,
|
||||
type SeparatorProps,
|
||||
} from "react-aria-components"
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
function Command({
|
||||
className,
|
||||
dir,
|
||||
style,
|
||||
...props
|
||||
}: Omit<AutocompleteProps, "className" | "style"> & {
|
||||
className?: string
|
||||
dir?: React.HTMLAttributes<HTMLDivElement>["dir"]
|
||||
style?: React.CSSProperties
|
||||
}) {
|
||||
const { contains } = useFilter({ sensitivity: "base" })
|
||||
return (
|
||||
<div
|
||||
data-slot="command"
|
||||
dir={dir}
|
||||
className={cn(
|
||||
"cn-command flex size-full flex-col overflow-hidden",
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
<Autocomplete {...props} filter={props.filter || contains}>
|
||||
{props.children}
|
||||
</Autocomplete>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandDialog({
|
||||
title = "Command Palette",
|
||||
description = "Search for a command to run...",
|
||||
children,
|
||||
open,
|
||||
onOpenChange,
|
||||
className,
|
||||
showCloseButton = false,
|
||||
...props
|
||||
}: Omit<
|
||||
React.ComponentProps<typeof Dialog>,
|
||||
"children" | "className" | "isOpen" | "onOpenChange"
|
||||
> & {
|
||||
title?: string
|
||||
description?: string
|
||||
open?: boolean
|
||||
onOpenChange?: (isOpen: boolean) => void
|
||||
className?: string
|
||||
showCloseButton?: boolean
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={open}
|
||||
onOpenChange={onOpenChange}
|
||||
className={cn(
|
||||
"cn-command-dialog top-1/3 translate-y-0 overflow-hidden p-0",
|
||||
className
|
||||
)}
|
||||
showCloseButton={showCloseButton}
|
||||
isDismissable
|
||||
{...props}
|
||||
>
|
||||
<DialogHeader className="sr-only">
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription>{description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
{children}
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandInput({ className, ...props }: InputProps) {
|
||||
return (
|
||||
<SearchField
|
||||
autoFocus
|
||||
aria-label={props.placeholder || "Search"}
|
||||
data-slot="command-input-wrapper"
|
||||
className="cn-command-input-wrapper"
|
||||
>
|
||||
<InputGroup className="cn-command-input-group">
|
||||
<Input
|
||||
{...props}
|
||||
data-slot="command-input"
|
||||
className={cn(
|
||||
"cn-command-input outline-hidden disabled:cursor-not-allowed disabled:opacity-50 [&::-webkit-search-cancel-button]:hidden",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
className="cn-command-input-icon"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</SearchField>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandList<T extends object>({ className, ...props }: MenuProps<T>) {
|
||||
return (
|
||||
<Menu
|
||||
{...props}
|
||||
data-slot="command-list"
|
||||
className={cn(
|
||||
"cn-command-list overflow-x-hidden overflow-y-auto",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandEmpty({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="command-empty"
|
||||
className={cn("cn-command-empty", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandGroup<T extends object>({
|
||||
className,
|
||||
children,
|
||||
items,
|
||||
heading,
|
||||
...props
|
||||
}: MenuSectionProps<T> & { heading?: string }) {
|
||||
return (
|
||||
<MenuSection
|
||||
data-slot="command-group"
|
||||
className={cn("cn-command-group", className)}
|
||||
{...props}
|
||||
>
|
||||
{heading && <Header cmdk-group-heading="">{heading}</Header>}
|
||||
<Collection items={items}>{children}</Collection>
|
||||
</MenuSection>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandSeparator({ className, ...props }: SeparatorProps) {
|
||||
return (
|
||||
<Separator
|
||||
data-slot="command-separator"
|
||||
className={cn("cn-command-separator", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandItem<T extends object>({
|
||||
className,
|
||||
children,
|
||||
textValue,
|
||||
...props
|
||||
}: MenuItemProps<T>) {
|
||||
return (
|
||||
<MenuItem
|
||||
{...props}
|
||||
data-slot="command-item"
|
||||
className={cn(
|
||||
"cn-command-item cn-command-item-aria group/command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
textValue={
|
||||
textValue || (typeof children === "string" ? children : undefined)
|
||||
}
|
||||
>
|
||||
{composeRenderProps(children, (children) => (
|
||||
<>
|
||||
{children}
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
className="cn-command-item-indicator ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100"
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandShortcut({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) {
|
||||
return (
|
||||
<span
|
||||
data-slot="command-shortcut"
|
||||
className={cn("cn-command-shortcut cn-command-shortcut-aria", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
Reference in New Issue
Block a user