{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inline-edit",
  "type": "registry:ui",
  "title": "Inline edit",
  "description": "Handles read, edit, save, error, and commit states inside shared geometry.",
  "dependencies": [
    "motion"
  ],
  "categories": [
    "forms-input"
  ],
  "docs": "https://motion-lexicon.pages.dev/en/components/inline-edit/",
  "meta": {
    "engines": [
      "motion"
    ],
    "runtimeCost": "light",
    "signature": "Displayed value becomes a savable field in place",
    "sceneFamily": "product-mono",
    "motionRole": "ui",
    "primaryState": "Editable project name",
    "assetProvenance": "self-contained"
  },
  "files": [
    {
      "path": "src/registry/components/inline-edit.tsx",
      "type": "registry:ui",
      "target": "components/motion-lexicon/inline-edit.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId, useRef, useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\n\nexport type InlineEditProps = { value: string; label?: string; onSave?: (value: string) => void | Promise<void>; placeholder?: string; className?: string };\n\nexport function InlineEdit({ value, label = \"Editable value\", onSave, placeholder = \"Enter a value\", className = \"\" }: InlineEditProps) {\n  const reduced = useReducedMotion() === true; const inputId = useId(); const inputRef = useRef<HTMLInputElement>(null); const [saved, setSaved] = useState(value); const [draft, setDraft] = useState(value); const [editing, setEditing] = useState(false); const [status, setStatus] = useState<\"idle\" | \"pending\" | \"error\">(\"idle\");\n  useEffect(() => { if (!editing) { setSaved(value); setDraft(value); } }, [editing, value]);\n  useEffect(() => { if (editing) requestAnimationFrame(() => inputRef.current?.focus()); }, [editing]);\n  const save = async () => { if (!draft.trim()) { setStatus(\"error\"); return; } try { setStatus(\"pending\"); await onSave?.(draft); setSaved(draft); setEditing(false); setStatus(\"idle\"); } catch { setStatus(\"error\"); } };\n  return <section aria-label={label} className={`rounded-[14px] border border-black/[.1] bg-white p-3 shadow-[0_12px_28px_-23px_rgba(28,28,28,.38)] ${className}`}><span className=\"font-mono text-[10px] uppercase tracking-[.15em] text-neutral-500\">{label}</span><AnimatePresence mode=\"wait\" initial={false}>{editing ? <motion.div key=\"edit\" initial={reduced ? false : { opacity: 0, y: 5 }} animate={{ opacity: 1, y: 0 }} exit={reduced ? undefined : { opacity: 0 }} className=\"mt-2\"><label htmlFor={inputId} className=\"sr-only\">{label}</label><input ref={inputRef} id={inputId} value={draft} onChange={(event) => { setDraft(event.target.value); setStatus(\"idle\"); }} onKeyDown={(event) => { if (event.key === \"Enter\") { event.preventDefault(); void save(); } if (event.key === \"Escape\") { setDraft(saved); setEditing(false); setStatus(\"idle\"); } }} placeholder={placeholder} className={`min-h-11 w-full rounded-lg border px-3 text-[13px] outline-none focus-visible:ring-2 focus-visible:ring-[#4568FF] ${status === \"error\" ? \"border-red-500\" : \"border-black/[.13]\"}`} /><div className=\"mt-2 flex items-center justify-between gap-2\"><button type=\"button\" onClick={() => { setDraft(saved); setEditing(false); setStatus(\"idle\"); }} className=\"min-h-11 rounded-full px-3 text-[11px] text-neutral-500 outline-none hover:bg-neutral-100 focus-visible:ring-2 focus-visible:ring-[#4568FF]\">Cancel</button><button type=\"button\" onClick={() => void save()} disabled={status === \"pending\"} className=\"min-h-11 rounded-full bg-[#242424] px-4 text-[11px] text-white outline-none hover:bg-[#3a3a3a] disabled:opacity-50 focus-visible:ring-2 focus-visible:ring-[#4568FF]\">{status === \"pending\" ? \"Saving…\" : \"Save\"}</button></div>{status === \"error\" ? <p role=\"alert\" className=\"mt-2 text-[11px] text-red-600\">Enter a value and try saving again.</p> : null}</motion.div> : <motion.div key=\"read\" initial={reduced ? false : { opacity: 0, y: -4 }} animate={{ opacity: 1, y: 0 }} className=\"mt-2 flex min-h-11 items-center justify-between gap-3\"><strong className=\"truncate text-[14px] font-medium text-[#292929]\">{saved || placeholder}</strong><button type=\"button\" onClick={() => setEditing(true)} className=\"min-h-11 rounded-full border border-black/[.1] px-3 text-[11px] outline-none hover:bg-neutral-50 focus-visible:ring-2 focus-visible:ring-[#4568FF]\">Edit</button></motion.div>}</AnimatePresence></section>;\n}\n"
    }
  ]
}
