86 lines · 2.8 KB · TypeScript
RawDownload
import { ArrowDownIcon, ArrowUpIcon } from "lucide-react";import { type ComponentProps, type ReactNode, useLayoutEffect, useRef } from "react"; import { Command, CommandFooter, CommandInput, CommandPanel } from "./ui/command";import { Kbd, KbdGroup } from "./ui/kbd"; type CommandPaletteContentProps = Omit<ComponentProps<typeof Command>, "children"> & {  readonly children: ReactNode;  readonly escapeLabel?: ReactNode;  readonly footerActionLabel?: ReactNode;  readonly footerTrailing?: ReactNode;  readonly inputAccessory?: ReactNode;  readonly inputProps: ComponentProps<typeof CommandInput>;  readonly panelClassName?: string;  readonly showBackHint?: boolean;  readonly testId?: string;}; /** * Shared command palette chrome. Palette modes provide their query behavior, * results, and optional input accessory while retaining one input, panel, and * keyboard-hint gutter. */export function CommandPaletteContent({  children,  escapeLabel = "Close",  footerActionLabel,  footerTrailing,  inputAccessory,  inputProps,  panelClassName,  showBackHint,  testId,  ...commandProps}: CommandPaletteContentProps) {  const inputRef = useRef<HTMLInputElement>(null);   // Direct-open flows replace the initial palette view after the dialog has  // already moved focus. Reclaim it when the replacement input mounts so  // typing cannot continue in the composer behind the modal.  useLayoutEffect(() => {    inputRef.current?.focus();  }, []);   return (    <div className="contents" data-testid={testId}>      <Command {...commandProps}>        <div className="relative">          <CommandInput {...inputProps} ref={inputRef} />          {inputAccessory}        </div>        <CommandPanel className={panelClassName}>{children}</CommandPanel>        <CommandFooter className="gap-3 max-sm:flex-col max-sm:items-start">          <div className="flex items-center gap-3">            <KbdGroup className="items-center gap-1.5">              <Kbd>                <ArrowUpIcon />              </Kbd>              <Kbd>                <ArrowDownIcon />              </Kbd>              <span>Navigate</span>            </KbdGroup>            {footerActionLabel !== undefined ? (              <KbdGroup className="items-center gap-1.5">                <Kbd>Enter</Kbd>                <span>{footerActionLabel}</span>              </KbdGroup>            ) : null}            {showBackHint ? (              <KbdGroup className="items-center gap-1.5">                <Kbd>Backspace</Kbd>                <span>Back</span>              </KbdGroup>            ) : null}            <KbdGroup className="items-center gap-1.5">              <Kbd>Esc</Kbd>              <span>{escapeLabel}</span>            </KbdGroup>          </div>          {footerTrailing}        </CommandFooter>      </Command>    </div>  );}