{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "shell",
  "title": "Shell",
  "description": "A command transcript and prompt with command history. Bring the commands and their effects.",
  "dependencies": [
    "class-variance-authority"
  ],
  "registryDependencies": [
    "@afterglow/theme"
  ],
  "files": [
    {
      "path": "registry/terminal/components/shell.tsx",
      "content": "\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { useCallback, useId, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst shellLineVariants = cva(\"min-h-5\", {\n  defaultVariants: { tone: \"default\" },\n  variants: {\n    tone: {\n      command: \"text-phosphor-bright\",\n      default: \"text-phosphor\",\n      error: \"text-signal\",\n      muted: \"text-phosphor-dim\",\n      warning: \"text-warning\",\n    },\n  },\n});\n\nfunction Shell({\n  className,\n  children,\n  \"aria-label\": label = \"Shell\",\n  ...props\n}: React.ComponentProps<\"section\">) {\n  return (\n    <section\n      aria-label={label}\n      className={cn(\n        \"flex min-h-48 flex-col gap-3 border border-line bg-panel-sunken p-4 font-mono text-xs shadow-panel\",\n        className\n      )}\n      data-slot=\"shell\"\n      {...props}\n    >\n      {children}\n    </section>\n  );\n}\n\nfunction ShellOutput({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      aria-live=\"polite\"\n      aria-relevant=\"additions text\"\n      className={cn(\n        \"min-h-0 flex-1 overflow-y-auto overscroll-contain whitespace-pre-wrap\",\n        className\n      )}\n      data-slot=\"shell-output\"\n      role=\"log\"\n      {...props}\n    />\n  );\n}\n\nfunction ShellLine({\n  className,\n  tone,\n  ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof shellLineVariants>) {\n  return (\n    <div\n      className={cn(shellLineVariants({ tone }), className)}\n      data-slot=\"shell-line\"\n      {...props}\n    />\n  );\n}\n\nfunction ShellCommand({\n  className,\n  children,\n  prompt = \"$\",\n  ...props\n}: React.ComponentProps<\"div\"> & { prompt?: string }) {\n  return (\n    <div\n      className={cn(\"flex min-h-5 gap-2 text-phosphor-bright\", className)}\n      data-slot=\"shell-command\"\n      {...props}\n    >\n      <span aria-hidden=\"true\" className=\"shrink-0 text-signal\">\n        {prompt}\n      </span>\n      <span className=\"min-w-0 break-words\">{children}</span>\n    </div>\n  );\n}\n\nfunction ShellPrompt({\n  className,\n  label = \"Command\",\n  onSubmit,\n  placeholder,\n  prompt = \"$\",\n  ...props\n}: Omit<React.ComponentProps<\"form\">, \"onSubmit\"> & {\n  label?: string;\n  onSubmit?: (command: string) => void;\n  placeholder?: string;\n  prompt?: string;\n}) {\n  const id = useId();\n  const [history, setHistory] = useState<readonly string[]>([]);\n  const [recall, setRecall] = useState(-1);\n  const [value, setValue] = useState(\"\");\n\n  const submit = useCallback(\n    (event: React.FormEvent<HTMLFormElement>) => {\n      event.preventDefault();\n      const command = value.trim();\n      if (!command) {\n        return;\n      }\n\n      onSubmit?.(command);\n      setHistory((current) => [command, ...current].slice(0, 40));\n      setRecall(-1);\n      setValue(\"\");\n    },\n    [onSubmit, value]\n  );\n\n  const recallCommand = useCallback(\n    (event: React.KeyboardEvent<HTMLInputElement>) => {\n      if (\n        (event.key !== \"ArrowUp\" && event.key !== \"ArrowDown\") ||\n        history.length === 0\n      ) {\n        return;\n      }\n\n      event.preventDefault();\n      const next =\n        event.key === \"ArrowUp\"\n          ? Math.min(recall + 1, history.length - 1)\n          : Math.max(recall - 1, -1);\n      setRecall(next);\n      setValue(next === -1 ? \"\" : (history[next] ?? \"\"));\n    },\n    [history, recall]\n  );\n\n  const updateValue = useCallback(\n    (event: React.ChangeEvent<HTMLInputElement>) => {\n      setValue(event.target.value);\n    },\n    []\n  );\n\n  return (\n    <form\n      className={cn(\n        \"group/shell-prompt flex items-baseline gap-2 border-line border-t pt-3 text-base focus-within:border-line-strong sm:text-xs\",\n        className\n      )}\n      data-slot=\"shell-prompt\"\n      onSubmit={submit}\n      {...props}\n    >\n      <label className=\"sr-only\" htmlFor={id}>\n        {label}\n      </label>\n      <span\n        aria-hidden=\"true\"\n        className=\"shrink-0 text-signal group-has-[:focus-visible]/shell-prompt:text-phosphor-bright\"\n      >\n        {prompt}\n      </span>\n      <input\n        autoCapitalize=\"off\"\n        autoComplete=\"off\"\n        autoCorrect=\"off\"\n        className=\"min-w-0 flex-1 border-0 bg-transparent p-0 font-mono text-phosphor-bright caret-phosphor-bright outline-none placeholder:text-phosphor-dim selection:bg-signal selection:text-white focus-visible:outline-0\"\n        id={id}\n        onChange={updateValue}\n        onKeyDown={recallCommand}\n        placeholder={placeholder}\n        spellCheck={false}\n        value={value}\n      />\n    </form>\n  );\n}\n\nexport { Shell, ShellCommand, ShellLine, ShellOutput, ShellPrompt };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}