{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inline-edit",
  "title": "Inline Edit",
  "description": "Click to edit text in place. Enter saves, Escape cancels, async saves supported.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/ui/inline-edit.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { PencilIcon } from \"lucide-react\"\n\nimport { cn } from \"@/registry/default/lib/utils\"\n\nfunction InlineEdit({\n  value,\n  onSave,\n  placeholder = \"Empty\",\n  disabled,\n  className,\n  \"aria-label\": ariaLabel,\n  ...props\n}: Omit<React.ComponentProps<\"div\">, \"onChange\"> & {\n  value: string\n  onSave: (value: string) => void | Promise<void>\n  placeholder?: string\n  disabled?: boolean\n}) {\n  const [isEditing, setIsEditing] = React.useState(false)\n  const [draft, setDraft] = React.useState(value)\n  const [hasFailed, setHasFailed] = React.useState(false)\n  const [isPending, startTransition] = React.useTransition()\n  const shouldRefocusTriggerRef = React.useRef(false)\n\n  function startEditing() {\n    setDraft(value)\n    setHasFailed(false)\n    setIsEditing(true)\n  }\n\n  function stopEditing() {\n    shouldRefocusTriggerRef.current = true\n    setIsEditing(false)\n  }\n\n  function save() {\n    if (draft === value) return stopEditing()\n    startTransition(async () => {\n      try {\n        await onSave(draft)\n        stopEditing()\n      } catch {\n        setHasFailed(true)\n      }\n    })\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {\n    switch (event.key) {\n      case \"Enter\":\n        event.preventDefault()\n        save()\n        return\n      case \"Escape\":\n        event.preventDefault()\n        stopEditing()\n        return\n    }\n  }\n\n  return (\n    <div\n      data-slot=\"inline-edit\"\n      data-editing={isEditing || undefined}\n      className={cn(\"group/inline-edit relative w-full min-w-0\", className)}\n      {...props}\n    >\n      {isEditing ? (\n        <input\n          autoFocus\n          data-slot=\"inline-edit-input\"\n          aria-label={ariaLabel}\n          aria-invalid={hasFailed || undefined}\n          aria-busy={isPending || undefined}\n          value={draft}\n          readOnly={isPending}\n          placeholder={placeholder}\n          onFocus={(event) => event.currentTarget.select()}\n          onChange={(event) => setDraft(event.target.value)}\n          onKeyDown={handleKeyDown}\n          onBlur={() => {\n            if (!isPending) save()\n          }}\n          className={cn(\n            \"-mx-2 h-8 w-[calc(100%+1rem)] rounded-md border border-input bg-transparent px-2 text-sm shadow-xs outline-none dark:bg-input/30\",\n            \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n            \"aria-busy:opacity-60 aria-invalid:border-destructive aria-invalid:ring-destructive/20\"\n          )}\n        />\n      ) : (\n        <button\n          ref={(node) => {\n            if (!node || !shouldRefocusTriggerRef.current) return\n            shouldRefocusTriggerRef.current = false\n            node.focus()\n          }}\n          type=\"button\"\n          data-slot=\"inline-edit-trigger\"\n          aria-label={ariaLabel ? `Edit ${ariaLabel}` : undefined}\n          disabled={disabled}\n          onClick={startEditing}\n          className={cn(\n            \"-mx-2 flex h-8 w-[calc(100%+1rem)] items-center justify-between gap-2 rounded-md px-2 text-left text-sm outline-none\",\n            \"hover:bg-accent/60 focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none\"\n          )}\n        >\n          <span className={cn(\"truncate\", !value && \"text-muted-foreground\")}>\n            {value || placeholder}\n          </span>\n          <PencilIcon className=\"size-3.5 shrink-0 text-muted-foreground opacity-0 transition-opacity group-focus-within/inline-edit:opacity-100 group-hover/inline-edit:opacity-100\" />\n        </button>\n      )}\n    </div>\n  )\n}\n\nexport { InlineEdit }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}