{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inline-edit",
  "title": "Inline Edit",
  "description": "A selection-anchored AI edit: suggestion toolbar, word diff, accept or reject.",
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "components/spectrumui/blocks/ai-assistants/inline-edit.tsx",
      "content": "'use client';\n\nimport { useState } from 'react';\nimport { Check, Sparkles, X } from 'lucide-react';\nimport { cn } from '@/lib/utils';\n\nconst KEYFRAMES = `\n@keyframes su-msg-in { from { opacity: 0; transform: translateY(4px) } to { opacity: 1; transform: none } }\n`;\n\nexport type InlineEditPhase = 'selected' | 'reviewing' | 'accepted';\n\nexport interface InlineEditProps {\n  before: string;\n  selection: string;\n  after: string;\n  suggestion: string;\n  actionLabel?: string;\n  phase?: InlineEditPhase;\n  onAccept?: () => void;\n  onReject?: () => void;\n  className?: string;\n}\n\nexport function InlineEdit({\n  before,\n  selection,\n  after,\n  suggestion,\n  actionLabel = 'Tighten this',\n  phase: phaseProp,\n  onAccept,\n  onReject,\n  className,\n}: InlineEditProps) {\n  const [phaseState, setPhaseState] = useState<InlineEditPhase>('selected');\n  const phase = phaseProp !== undefined ? phaseProp : phaseState;\n\n  function accept() {\n    setPhaseState('accepted');\n    onAccept?.();\n  }\n  function reject() {\n    setPhaseState('selected');\n    onReject?.();\n  }\n\n  return (\n    <div className={cn('w-full max-w-[480px] text-[13.5px]', className)}>\n      <style dangerouslySetInnerHTML={{ __html: KEYFRAMES }} />\n\n      <p className=\"leading-[1.75] text-neutral-700 dark:text-neutral-300\">\n        {before}\n        {phase === 'accepted' ? (\n          <span className=\"rounded bg-emerald-500/10 px-0.5 text-neutral-900 motion-safe:animate-[su-msg-in_240ms_cubic-bezier(0.23,1,0.32,1)_both] dark:text-neutral-100\">\n            {suggestion}\n          </span>\n        ) : (\n          <span className=\"group/edit relative inline\">\n            <span className=\"rounded bg-sky-500/15 px-0.5 dark:bg-sky-400/20\">{selection}</span>\n            {phase === 'selected' && (\n              <span className=\"absolute left-1/2 top-full z-10 mt-1.5 -translate-x-1/2 motion-safe:animate-[su-msg-in_200ms_cubic-bezier(0.23,1,0.32,1)_both]\">\n                <button\n                  type=\"button\"\n                  onClick={() => setPhaseState('reviewing')}\n                  className=\"flex items-center gap-1.5 whitespace-nowrap rounded-full border border-black/[0.08] bg-white py-1 pl-2 pr-2.5 text-[11.5px] font-medium text-neutral-700 shadow-md transition-transform duration-150 active:scale-[0.96] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 dark:border-white/[0.1] dark:bg-neutral-900 dark:text-neutral-200\"\n                >\n                  <Sparkles className=\"size-3 text-neutral-400 dark:text-neutral-500\" />\n                  {actionLabel}\n                </button>\n              </span>\n            )}\n          </span>\n        )}\n        {after}\n      </p>\n\n      {phase === 'reviewing' && (\n        <div className=\"mt-8 rounded-xl border border-black/[0.08] bg-white p-3 shadow-xs motion-safe:animate-[su-msg-in_240ms_cubic-bezier(0.23,1,0.32,1)_both] dark:border-white/[0.09] dark:bg-[#0B0B0D]\">\n          <p className=\"font-mono text-[10px] font-medium uppercase tracking-[0.07em] text-neutral-400 dark:text-neutral-600\">\n            Suggestion\n          </p>\n          <p className=\"mt-2 leading-[1.7]\">\n            <del className=\"rounded bg-red-500/10 px-0.5 text-neutral-400 line-through decoration-red-400/50 dark:text-neutral-500\">\n              {selection}\n            </del>{' '}\n            <ins className=\"rounded bg-emerald-500/10 px-0.5 text-neutral-900 no-underline dark:text-neutral-100\">\n              {suggestion}\n            </ins>\n          </p>\n          <div className=\"mt-3 flex items-center justify-end gap-1.5\">\n            <button\n              type=\"button\"\n              aria-label=\"Reject suggestion\"\n              onClick={reject}\n              className=\"grid size-7 place-items-center rounded-lg text-neutral-400 transition-[color,background-color,transform] duration-150 hover:bg-black/[0.04] hover:text-neutral-700 active:scale-[0.92] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 dark:hover:bg-white/[0.06] dark:hover:text-neutral-200\"\n            >\n              <X className=\"size-3.5\" />\n            </button>\n            <button\n              type=\"button\"\n              aria-label=\"Accept suggestion\"\n              onClick={accept}\n              className=\"grid size-7 place-items-center rounded-lg bg-neutral-900 text-white transition-transform duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.92] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 dark:bg-neutral-100 dark:text-neutral-900\"\n            >\n              <Check className=\"size-3.5\" />\n            </button>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default InlineEdit;\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/ai-assistants/inline-edit.tsx"
    }
  ],
  "type": "registry:block"
}
