{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "confirm-morph",
  "type": "registry:ui",
  "title": "Confirm Morph",
  "description": "Adaptive inline confirmation button that morphs into question, spinner, success with undo, and error with retry.",
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/registry/ui/confirm-morph.tsx",
      "content": "\"use client\";\n\nimport {\n  useCallback,\n  useEffect,\n  useId,\n  useImperativeHandle,\n  useLayoutEffect,\n  useRef,\n  useState,\n  useSyncExternalStore,\n  type KeyboardEvent as ReactKeyboardEvent,\n  type ReactNode,\n  type Ref,\n} from \"react\";\nimport {\n  AnimatePresence,\n  animate,\n  motion,\n  useIsPresent,\n  useMotionValue,\n  useReducedMotion,\n  type AnimationPlaybackControls,\n  type Transition,\n  type Variants,\n} from \"motion/react\";\nimport { CircleAlert, LoaderCircle } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ConfirmMorphState =\n  | \"idle\"\n  | \"confirming\"\n  | \"pending\"\n  | \"done\"\n  | \"error\";\n\nexport interface ConfirmMorphProps {\n  label: ReactNode;\n  icon?: ReactNode;\n  prompt?: ReactNode;\n  confirmLabel?: string;\n  cancelLabel?: string;\n  pendingLabel?: string;\n  doneLabel?: string;\n  errorLabel?: string;\n  retryLabel?: string;\n  undoLabel?: string;\n  undoingLabel?: string;\n  tone?: \"danger\" | \"neutral\";\n  onConfirm?: () => void | Promise<unknown>;\n  onUndo?: () => void | Promise<unknown>;\n  onCancel?: () => void;\n  state?: ConfirmMorphState;\n  defaultState?: ConfirmMorphState;\n  onStateChange?: (state: ConfirmMorphState) => void;\n  confirmTimeout?: number;\n  resultTimeout?: number;\n  cancelOnOutsidePress?: boolean;\n  disabled?: boolean;\n  className?: string;\n  ref?: Ref<HTMLDivElement>;\n}\n\nconst GROW: Transition = {\n  type: \"spring\",\n  stiffness: 420,\n  damping: 32,\n  mass: 0.8,\n};\n\nconst SHRINK: Transition = {\n  type: \"spring\",\n  stiffness: 460,\n  damping: 34,\n  mass: 0.8,\n};\n\nconst SLIDE: Transition = {\n  type: \"spring\",\n  stiffness: 420,\n  damping: 32,\n  mass: 0.8,\n};\n\nconst emptySubscribe = () => () => {};\n\nfunction useReducedFlag() {\n  const hydrated = useSyncExternalStore(\n    emptySubscribe,\n    () => true,\n    () => false,\n  );\n  const reducedMotion = useReducedMotion();\n  return Boolean(reducedMotion && hydrated);\n}\n\nconst faceVariants: Variants = {\n  hidden: (direction: number) => ({\n    opacity: 0,\n    x: direction * 8,\n  }),\n  shown: {\n    opacity: 1,\n    x: 0,\n    transition: {\n      x: SLIDE,\n      opacity: { duration: 0.16, ease: [0.16, 1, 0.3, 1] },\n    },\n  },\n  gone: (direction: number) => ({\n    opacity: 0,\n    x: direction * -6,\n    transition: {\n      duration: 0.09,\n      ease: [0.2, 0, 0, 1],\n    },\n  }),\n};\n\nconst fadeVariants: Variants = {\n  hidden: { opacity: 0 },\n  shown: { opacity: 1, transition: { duration: 0.12 } },\n  gone: { opacity: 0, transition: { duration: 0.08 } },\n};\n\nfunction Face({\n  id,\n  direction,\n  reduced,\n  onSize,\n  children,\n  labelledBy,\n}: {\n  id: ConfirmMorphState;\n  direction: number;\n  reduced: boolean;\n  onSize: (id: ConfirmMorphState, width: number) => void;\n  children: ReactNode;\n  labelledBy?: string;\n}) {\n  const ref = useRef<HTMLDivElement>(null);\n  const present = useIsPresent();\n\n  useLayoutEffect(() => {\n    const node = ref.current;\n    if (!node || !present) return;\n    const report = () => {\n      const flex = node.style.flex;\n      node.style.flex = \"none\";\n      const width =\n        node.scrollWidth || Math.ceil(node.getBoundingClientRect().width);\n      node.style.flex = flex;\n      onSize(id, width);\n    };\n    report();\n    if (typeof ResizeObserver === \"undefined\") return;\n    const observer = new ResizeObserver(report);\n    observer.observe(node);\n    return () => observer.disconnect();\n  }, [id, onSize, present]);\n\n  return (\n    <motion.div\n      ref={ref}\n      className=\"flex h-full items-center justify-center gap-1.5 px-3 whitespace-nowrap text-xs select-none will-change-[transform,opacity]\"\n      data-face={id}\n      custom={direction}\n      role={labelledBy ? \"group\" : undefined}\n      aria-labelledby={labelledBy}\n      variants={reduced ? fadeVariants : faceVariants}\n      initial=\"hidden\"\n      animate=\"shown\"\n      exit=\"gone\"\n      inert={!present || undefined}\n    >\n      {children}\n    </motion.div>\n  );\n}\n\nfunction Check({ reduced }: { reduced: boolean }) {\n  return (\n    <svg\n      className=\"size-4 shrink-0\"\n      viewBox=\"0 0 18 18\"\n      fill=\"none\"\n      aria-hidden=\"true\"\n    >\n      <motion.circle\n        className=\"fill-emerald-500/15 stroke-emerald-500 dark:stroke-emerald-400\"\n        cx=\"9\"\n        cy=\"9\"\n        r=\"7.5\"\n        strokeWidth=\"1.5\"\n        style={{ transformOrigin: \"9px 9px\" }}\n        initial={reduced ? false : { scale: 0.4, opacity: 0 }}\n        animate={{ scale: 1, opacity: 1 }}\n        transition={{\n          scale: { type: \"spring\", stiffness: 450, damping: 28 },\n          opacity: { duration: 0.12 },\n        }}\n      />\n      <motion.path\n        className=\"stroke-emerald-500 dark:stroke-emerald-400\"\n        d=\"M5.6 9.3 7.8 11.4 12.4 6.7\"\n        strokeWidth=\"1.8\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n        initial={reduced ? false : { pathLength: 0 }}\n        animate={{ pathLength: 1 }}\n        transition={{ duration: 0.24, ease: [0.16, 1, 0.3, 1], delay: 0.08 }}\n      />\n    </svg>\n  );\n}\n\nexport function ConfirmMorph({\n  label,\n  icon,\n  prompt,\n  confirmLabel = \"Delete\",\n  cancelLabel = \"Cancel\",\n  pendingLabel = \"Deleting\",\n  doneLabel = \"Deleted\",\n  errorLabel = \"Couldn’t finish\",\n  retryLabel = \"Retry\",\n  undoLabel = \"Undo\",\n  undoingLabel = \"Restoring\",\n  tone = \"danger\",\n  onConfirm,\n  onUndo,\n  onCancel,\n  state: stateProp,\n  defaultState = \"idle\",\n  onStateChange,\n  confirmTimeout = 6000,\n  resultTimeout = 5000,\n  cancelOnOutsidePress = true,\n  disabled = false,\n  className,\n  ref,\n}: ConfirmMorphProps) {\n  const reduced = useReducedFlag();\n  const uid = useId();\n  const promptId = `${uid}-prompt`;\n  const rootRef = useRef<HTMLDivElement>(null);\n  useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n\n  const [inner, setInner] = useState<ConfirmMorphState>(defaultState);\n  const state = stateProp ?? inner;\n  const [direction, setDirection] = useState(1);\n  const [working, setWorking] = useState<\"confirm\" | \"undo\">(\"confirm\");\n  const [announcement, setAnnouncement] = useState(\"\");\n\n  const live = useRef({\n    state,\n    onStateChange,\n    controlled: stateProp !== undefined,\n  });\n  useLayoutEffect(() => {\n    live.current = {\n      state,\n      onStateChange,\n      controlled: stateProp !== undefined,\n    };\n  });\n  const pendingFocus = useRef(false);\n  const run = useRef(0);\n\n  const go = useCallback((next: ConfirmMorphState) => {\n    const current = live.current.state;\n    if (next === current) return;\n    const root = rootRef.current;\n    pendingFocus.current =\n      Boolean(root) &&\n      (root?.contains(document.activeElement) ||\n        document.activeElement === document.body);\n    setDirection(next === \"idle\" ? -1 : 1);\n    if (!live.current.controlled) setInner(next);\n    live.current.state = next;\n    live.current.onStateChange?.(next);\n  }, []);\n\n  const toIdle = useCallback(() => {\n    run.current++;\n    go(\"idle\");\n  }, [go]);\n\n  const perform = useCallback(\n    async (kind: \"confirm\" | \"undo\") => {\n      const handler = kind === \"confirm\" ? onConfirm : onUndo;\n      const token = ++run.current;\n      setWorking(kind);\n      let result: void | Promise<unknown> | undefined;\n      try {\n        result = handler?.();\n      } catch {\n        go(\"error\");\n        setAnnouncement(errorLabel);\n        return;\n      }\n      if (result && typeof (result as Promise<unknown>).then === \"function\") {\n        go(\"pending\");\n        setAnnouncement(kind === \"confirm\" ? pendingLabel : undoingLabel);\n        try {\n          await result;\n        } catch {\n          if (token !== run.current) return;\n          go(\"error\");\n          setAnnouncement(errorLabel);\n          return;\n        }\n        if (token !== run.current) return;\n      }\n      if (kind === \"undo\") {\n        go(\"idle\");\n        setAnnouncement(\"Undone\");\n        return;\n      }\n      go(\"done\");\n      setAnnouncement(\n        onUndo ? `${doneLabel}. ${undoLabel} is available.` : doneLabel,\n      );\n    },\n    [\n      doneLabel,\n      errorLabel,\n      go,\n      onConfirm,\n      onUndo,\n      pendingLabel,\n      undoLabel,\n      undoingLabel,\n    ],\n  );\n\n  const cancel = useCallback(() => {\n    onCancel?.();\n    toIdle();\n    setAnnouncement(\"Cancelled\");\n  }, [onCancel, toIdle]);\n\n  const expire = useRef(() => {});\n  useLayoutEffect(() => {\n    expire.current = () => {\n      if (live.current.state === \"confirming\") cancel();\n      else toIdle();\n    };\n  });\n\n  const width = useMotionValue<number | \"auto\">(\"auto\");\n  const target = useRef(0);\n  const flight = useRef(0);\n\n  const onFaceSize = useCallback(\n    (id: ConfirmMorphState, w: number) => {\n      if (id !== live.current.state || Math.abs(w - target.current) < 0.5)\n        return;\n      const from = target.current;\n      target.current = w;\n      if (!from || reduced) {\n        width.set(w);\n        return;\n      }\n      if (width.get() === \"auto\") width.jump(from);\n      const token = ++flight.current;\n      animate(width, w, w > from ? GROW : SHRINK).then(() => {\n        if (token === flight.current) width.set(w);\n      });\n    },\n    [reduced, width],\n  );\n\n  const drain = useMotionValue(1);\n  const clock = useRef<AnimationPlaybackControls | null>(null);\n  const holds = useRef({ hover: false, hidden: false });\n  const timeout =\n    state === \"confirming\"\n      ? confirmTimeout\n      : state === \"done\" || state === \"error\"\n        ? resultTimeout\n        : 0;\n\n  const sync = useCallback(() => {\n    const control = clock.current;\n    if (!control) return;\n    const held = holds.current.hover || holds.current.hidden;\n    if (held) control.pause();\n    else control.play();\n  }, []);\n\n  useEffect(() => {\n    if (!timeout) return;\n    drain.jump(1);\n    const control = animate(drain, 0, {\n      duration: timeout / 1000,\n      ease: \"linear\",\n    });\n    clock.current = control;\n    control.then(() => {\n      if (clock.current === control) {\n        clock.current = null;\n        expire.current();\n      }\n    });\n    sync();\n    return () => {\n      if (clock.current === control) clock.current = null;\n      control.stop();\n    };\n  }, [drain, state, sync, timeout]);\n\n  useEffect(() => {\n    const onVisibility = () => {\n      holds.current.hidden = document.hidden;\n      sync();\n    };\n    document.addEventListener(\"visibilitychange\", onVisibility);\n    return () => document.removeEventListener(\"visibilitychange\", onVisibility);\n  }, [sync]);\n\n  useEffect(() => {\n    if (state !== \"confirming\" || !cancelOnOutsidePress) return;\n    const down = (event: PointerEvent) => {\n      if (!rootRef.current?.contains(event.target as Node)) cancel();\n    };\n    document.addEventListener(\"pointerdown\", down);\n    return () => document.removeEventListener(\"pointerdown\", down);\n  }, [cancel, cancelOnOutsidePress, state]);\n\n  useLayoutEffect(() => {\n    if (!pendingFocus.current) return;\n    pendingFocus.current = false;\n    const root = rootRef.current;\n    if (!root) return;\n    const faceElement = root.querySelector<HTMLElement>(\n      `[data-face=\"${state}\"]`,\n    );\n    const autofocus = faceElement?.querySelector<HTMLElement>(\n      \"[data-autofocus]:not(:disabled)\",\n    );\n    (autofocus ?? root).focus({ preventScroll: true });\n  }, [state]);\n\n  const onKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n    if (event.key !== \"Escape\") return;\n    if (state === \"confirming\") {\n      event.preventDefault();\n      event.stopPropagation();\n      cancel();\n    } else if (state === \"done\" || state === \"error\") {\n      event.preventDefault();\n      event.stopPropagation();\n      toIdle();\n    }\n  };\n\n  const shownPrompt = prompt ?? <>{label}?</>;\n\n  const face = (() => {\n    switch (state) {\n      case \"confirming\":\n        return (\n          <>\n            <span\n              id={promptId}\n              className=\"text-xs font-medium text-zinc-100 pr-1 select-none\"\n            >\n              {shownPrompt}\n            </span>\n            <button\n              type=\"button\"\n              className=\"rounded-full px-2.5 py-1 text-xs font-medium text-zinc-300 hover:text-white bg-zinc-800 hover:bg-zinc-700 transition-colors cursor-pointer outline-none focus-visible:ring-1 focus-visible:ring-zinc-400 active:scale-95\"\n              data-autofocus\n              onClick={cancel}\n            >\n              {cancelLabel}\n            </button>\n            <button\n              type=\"button\"\n              className={cn(\n                \"rounded-full px-2.5 py-1 text-xs font-medium transition-all cursor-pointer outline-none active:scale-95 shadow-xs\",\n                tone === \"danger\"\n                  ? \"bg-rose-600 text-white hover:bg-rose-500 focus-visible:ring-1 focus-visible:ring-rose-400\"\n                  : \"bg-foreground text-background hover:bg-foreground/90 focus-visible:ring-1 focus-visible:ring-foreground/30\",\n              )}\n              disabled={disabled}\n              onClick={() => void perform(\"confirm\")}\n            >\n              {confirmLabel}\n            </button>\n          </>\n        );\n      case \"pending\":\n        return (\n          <span className=\"flex items-center gap-2 text-xs font-medium text-zinc-300 select-none\">\n            <LoaderCircle\n              className=\"size-3.5 shrink-0 animate-spin text-zinc-400\"\n              strokeWidth={2}\n              aria-hidden=\"true\"\n            />\n            <span>{working === \"undo\" ? undoingLabel : pendingLabel}</span>\n          </span>\n        );\n      case \"done\":\n        return (\n          <>\n            <span className=\"flex items-center gap-1.5 text-xs font-medium text-emerald-400 select-none\">\n              <Check reduced={reduced} />\n              <span>{doneLabel}</span>\n            </span>\n            {onUndo && (\n              <button\n                type=\"button\"\n                className=\"rounded-full px-2.5 py-1 text-xs font-medium text-zinc-300 hover:text-white bg-zinc-800 hover:bg-zinc-700 transition-colors cursor-pointer outline-none focus-visible:ring-1 focus-visible:ring-zinc-400 active:scale-95 ml-1\"\n                data-autofocus\n                onClick={() => void perform(\"undo\")}\n              >\n                {undoLabel}\n              </button>\n            )}\n          </>\n        );\n      case \"error\":\n        return (\n          <>\n            <span className=\"flex items-center gap-1.5 text-xs font-medium text-rose-400 select-none\">\n              <CircleAlert\n                className=\"size-3.5 shrink-0 text-rose-400\"\n                strokeWidth={2}\n                aria-hidden=\"true\"\n              />\n              <span>{errorLabel}</span>\n            </span>\n            <button\n              type=\"button\"\n              className=\"rounded-full px-2.5 py-1 text-xs font-medium text-rose-300 hover:text-white bg-rose-500/20 hover:bg-rose-500/30 border border-rose-500/30 transition-colors cursor-pointer outline-none focus-visible:ring-1 focus-visible:ring-rose-400 active:scale-95 ml-1\"\n              data-autofocus\n              onClick={() => void perform(working)}\n            >\n              {retryLabel}\n            </button>\n          </>\n        );\n      default:\n        return (\n          <button\n            type=\"button\"\n            className={cn(\n              \"inline-flex items-center gap-1.5 text-xs font-medium cursor-pointer transition-colors outline-none rounded-full select-none\",\n              tone === \"danger\"\n                ? \"text-rose-400 hover:text-rose-300\"\n                : \"text-zinc-200 hover:text-white\",\n              disabled && \"opacity-50 pointer-events-none cursor-not-allowed\",\n            )}\n            data-autofocus\n            disabled={disabled}\n            onClick={() => {\n              setAnnouncement(\n                typeof shownPrompt === \"string\" ? shownPrompt : \"\",\n              );\n              go(\"confirming\");\n            }}\n          >\n            {icon && (\n              <span\n                className=\"shrink-0 size-3.5 flex items-center justify-center text-current\"\n                aria-hidden=\"true\"\n              >\n                {icon}\n              </span>\n            )}\n            <span>{label}</span>\n          </button>\n        );\n    }\n  })();\n\n  return (\n    <div\n      ref={rootRef}\n      className={cn(\n        \"relative inline-flex items-center select-none\",\n        disabled &&\n          (state === \"idle\" || state === \"confirming\") &&\n          \"opacity-50 pointer-events-none\",\n        className,\n      )}\n      data-state={state}\n      data-tone={tone}\n      data-disabled={disabled || undefined}\n      tabIndex={-1}\n      onKeyDown={onKeyDown}\n      aria-busy={state === \"pending\" || undefined}\n      onPointerEnter={() => {\n        holds.current.hover = true;\n        sync();\n      }}\n      onPointerLeave={() => {\n        holds.current.hover = false;\n        sync();\n      }}\n      onPointerCancel={() => {\n        holds.current.hover = false;\n        sync();\n      }}\n    >\n      <motion.div\n        className={cn(\n          \"box-content relative inline-flex h-8 items-center justify-center overflow-hidden rounded-full border transition-colors duration-150 backdrop-blur-md\",\n          tone === \"danger\" &&\n            state === \"idle\" &&\n            \"border-rose-500/25 bg-rose-500/10 hover:border-rose-500/40 hover:bg-rose-500/15\",\n          tone === \"neutral\" &&\n            state === \"idle\" &&\n            \"border-zinc-700/60 bg-zinc-800/80 hover:border-zinc-600 hover:bg-zinc-800\",\n          state === \"confirming\" && \"border-zinc-700/80 bg-zinc-900 shadow-md\",\n          state === \"pending\" && \"border-zinc-700/80 bg-zinc-900/90 shadow-md\",\n          state === \"done\" && \"border-emerald-500/30 bg-emerald-500/10\",\n          state === \"error\" && \"border-rose-500/30 bg-rose-500/10\",\n        )}\n        style={{ width }}\n      >\n        <AnimatePresence mode=\"popLayout\" initial={false} custom={direction}>\n          <Face\n            key={state}\n            id={state}\n            direction={direction}\n            reduced={reduced}\n            onSize={onFaceSize}\n            labelledBy={state === \"confirming\" ? promptId : undefined}\n          >\n            {face}\n          </Face>\n        </AnimatePresence>\n      </motion.div>\n      <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n        {announcement}\n      </span>\n    </div>\n  );\n}\n\nexport default ConfirmMorph;\n",
      "type": "registry:ui",
      "target": "@ui/confirm-morph.tsx"
    },
    {
      "path": "src/registry/ui/delete-selection.tsx",
      "content": "\"use client\";\n\nimport { useRef, useState } from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { Check, FileSpreadsheet, FileText, Minus, Trash2 } from \"lucide-react\";\nimport { ConfirmMorph } from \"./confirm-morph\";\nimport { cn } from \"@/lib/utils\";\n\nexport const deleteFiles = async (ids: string[]) => {\n  await new Promise((resolve) => setTimeout(resolve, 900));\n  return ids;\n};\n\nexport const restoreFiles = async (ids: string[]) => {\n  await new Promise((resolve) => setTimeout(resolve, 700));\n  return ids;\n};\n\nexport interface DeleteSelectionProps {\n  ids: string[];\n  onConfirm?: (ids: string[]) => void | Promise<unknown>;\n  onUndo?: (ids: string[]) => void | Promise<unknown>;\n  disabled?: boolean;\n}\n\nexport function DeleteSelection({\n  ids,\n  onConfirm,\n  onUndo,\n  disabled,\n}: DeleteSelectionProps) {\n  const count = ids.length;\n  const promptText = `Delete ${count} ${count === 1 ? \"file\" : \"files\"}?`;\n\n  return (\n    <ConfirmMorph\n      label=\"Delete\"\n      icon={<Trash2 size={16} strokeWidth={1.75} />}\n      prompt={promptText}\n      tone=\"danger\"\n      disabled={disabled || count === 0}\n      onConfirm={() => (onConfirm ? onConfirm(ids) : deleteFiles(ids))}\n      onUndo={() => (onUndo ? onUndo(ids) : restoreFiles(ids))}\n    />\n  );\n}\n\ninterface FileItem {\n  id: string;\n  name: string;\n  author: string;\n  date: string;\n  size: string;\n  type: \"image\" | \"pdf\" | \"sheet\";\n  thumbnail?: string;\n}\n\nconst INITIAL_FILES: FileItem[] = [\n  {\n    id: \"1\",\n    name: \"pookie virat 01.jpg\",\n    author: \"Pookie Virat\",\n    date: \"Sep 21\",\n    size: \"4.2 MB\",\n    type: \"image\",\n    thumbnail:\n      \"https://i.pinimg.com/736x/1d/49/b5/1d49b5da4ebfc59d5d7d4f1c288ecf17.jpg\",\n  },\n  {\n    id: \"2\",\n    name: \"pookie virat 02.jpg\",\n    author: \"Pookie Virat\",\n    date: \"Sep 20\",\n    size: \"3.8 MB\",\n    type: \"image\",\n    thumbnail:\n      \"https://i.pinimg.com/1200x/63/01/21/630121fe689e8d2c43b0b10180d31f84.jpg\",\n  },\n  {\n    id: \"3\",\n    name: \"pookie virat 03.jpg\",\n    author: \"Pookie Virat\",\n    date: \"Sep 19\",\n    size: \"5.1 MB\",\n    type: \"image\",\n    thumbnail:\n      \"https://i.pinimg.com/736x/54/cc/b5/54ccb5138e6452e45dcec18aee7b9f39.jpg\",\n  },\n  {\n    id: \"4\",\n    name: \"pookie virat 04.jpg\",\n    author: \"Pookie Virat\",\n    date: \"Sep 18\",\n    size: \"2.9 MB\",\n    type: \"image\",\n    thumbnail:\n      \"https://i.pinimg.com/736x/25/4b/0b/254b0b03a39fc3736053c28263fa5053.jpg\",\n  },\n  {\n    id: \"5\",\n    name: \"pookie virat 05.jpg\",\n    author: \"Pookie Virat\",\n    date: \"Sep 17\",\n    size: \"4.6 MB\",\n    type: \"image\",\n    thumbnail:\n      \"https://i.pinimg.com/736x/78/68/5e/78685eb464deaa7a7cc9cad4b12e9ef9.jpg\",\n  },\n];\n\nexport function DeleteSelectionShowcase() {\n  const [files, setFiles] = useState<FileItem[]>(INITIAL_FILES);\n  const [selectedIds, setSelectedIds] = useState<string[]>([\"2\", \"3\"]);\n  const [outcome, setOutcome] = useState<\"succeeds\" | \"fails\">(\"succeeds\");\n  const [lastDeleted, setLastDeleted] = useState<{\n    items: FileItem[];\n    ids: string[];\n  } | null>(null);\n\n  const highlightRef = useRef<HTMLDivElement>(null);\n  const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n  const handleMouseEnter = (index: number) => {\n    const el = itemRefs.current[index];\n    const hl = highlightRef.current;\n    if (!el || !hl) return;\n    hl.style.transform = `translate3d(${el.offsetLeft}px, ${el.offsetTop}px, 0)`;\n    hl.style.width = `${el.offsetWidth}px`;\n    hl.style.height = `${el.offsetHeight}px`;\n    hl.style.opacity = \"1\";\n  };\n\n  const handleMouseLeave = () => {\n    const hl = highlightRef.current;\n    if (!hl) return;\n    hl.style.opacity = \"0\";\n  };\n\n  const toggleSelect = (id: string) => {\n    setSelectedIds((prev) =>\n      prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],\n    );\n  };\n\n  const toggleAll = () => {\n    if (selectedIds.length > 0) {\n      setSelectedIds([]);\n    } else {\n      setSelectedIds(files.map((f) => f.id));\n    }\n  };\n\n  const handleConfirm = async (ids: string[]) => {\n    await new Promise((resolve) => setTimeout(resolve, 900));\n    if (outcome === \"fails\") {\n      throw new Error(\"Failed to delete files\");\n    }\n    const removed = files.filter((f) => ids.includes(f.id));\n    setLastDeleted({ items: removed, ids });\n    setFiles((prev) => prev.filter((f) => !ids.includes(f.id)));\n    setSelectedIds([]);\n    handleMouseLeave();\n  };\n\n  const handleUndo = async () => {\n    await new Promise((resolve) => setTimeout(resolve, 700));\n    if (lastDeleted) {\n      setFiles((prev) => {\n        const merged = [...prev];\n        for (const item of lastDeleted.items) {\n          if (!merged.some((m) => m.id === item.id)) {\n            merged.push(item);\n          }\n        }\n        return merged.sort(\n          (a, b) =>\n            INITIAL_FILES.findIndex((f) => f.id === a.id) -\n            INITIAL_FILES.findIndex((f) => f.id === b.id),\n        );\n      });\n      setSelectedIds(lastDeleted.ids);\n      setLastDeleted(null);\n    }\n  };\n\n  const isAllSelected = files.length > 0 && selectedIds.length === files.length;\n  const isPartiallySelected =\n    selectedIds.length > 0 && selectedIds.length < files.length;\n\n  return (\n    <div className=\"flex flex-col items-center justify-center w-full max-w-lg mx-auto p-4 select-none\">\n      <div className=\"w-full rounded-[26px] bg-[#161618] border border-white/8 p-5 shadow-2xl transition-all\">\n        <div className=\"flex items-center justify-between pb-4\">\n          <div className=\"flex items-center gap-3\">\n            <AnimatePresence mode=\"popLayout\" initial={false}>\n              {files.length > 0 && (\n                <motion.button\n                  key=\"select-all-btn\"\n                  type=\"button\"\n                  role=\"checkbox\"\n                  aria-checked={\n                    isAllSelected ? true : isPartiallySelected ? \"mixed\" : false\n                  }\n                  aria-label={\n                    isAllSelected ? \"Deselect all files\" : \"Select all files\"\n                  }\n                  initial={{ scale: 0, opacity: 0, width: 0 }}\n                  animate={{ scale: 1, opacity: 1, width: 28 }}\n                  exit={{ scale: 0, opacity: 0, width: 0 }}\n                  transition={{ type: \"spring\", stiffness: 450, damping: 32 }}\n                  onClick={toggleAll}\n                  className=\"size-7 shrink-0 rounded-lg bg-zinc-800 border border-zinc-700/60 flex items-center justify-center cursor-pointer transition-colors hover:bg-zinc-700/70 outline-none focus-visible:ring-1 focus-visible:ring-zinc-400 overflow-hidden\"\n                >\n                  <AnimatePresence mode=\"wait\">\n                    {isAllSelected ? (\n                      <motion.div\n                        key=\"check\"\n                        initial={{ scale: 0.5, opacity: 0 }}\n                        animate={{ scale: 1, opacity: 1 }}\n                        exit={{ scale: 0.5, opacity: 0 }}\n                        transition={{ duration: 0.12 }}\n                      >\n                        <Check\n                          size={14}\n                          className=\"text-zinc-200\"\n                          strokeWidth={2.5}\n                        />\n                      </motion.div>\n                    ) : isPartiallySelected ? (\n                      <motion.div\n                        key=\"minus\"\n                        initial={{ scale: 0.5, opacity: 0 }}\n                        animate={{ scale: 1, opacity: 1 }}\n                        exit={{ scale: 0.5, opacity: 0 }}\n                        transition={{ duration: 0.12 }}\n                      >\n                        <Minus\n                          size={14}\n                          className=\"text-zinc-200\"\n                          strokeWidth={2.5}\n                        />\n                      </motion.div>\n                    ) : null}\n                  </AnimatePresence>\n                </motion.button>\n              )}\n            </AnimatePresence>\n\n            <div className=\"flex flex-col text-left\">\n              <span className=\"text-sm font-medium text-zinc-100 leading-tight\">\n                pookie virat\n              </span>\n              <span className=\"text-xs text-zinc-400 leading-normal\">\n                {files.length === 0\n                  ? \"No files remaining\"\n                  : `${selectedIds.length} of ${files.length} selected`}\n              </span>\n            </div>\n          </div>\n\n          <DeleteSelection\n            ids={selectedIds}\n            onConfirm={handleConfirm}\n            onUndo={handleUndo}\n          />\n        </div>\n\n        <div\n          onMouseLeave={handleMouseLeave}\n          className=\"relative flex flex-col gap-1 mt-1 min-h-10\"\n        >\n          {files.length > 0 && (\n            <div\n              ref={highlightRef}\n              aria-hidden=\"true\"\n              className=\"pointer-events-none absolute top-0 left-0 rounded-2xl bg-white/[0.07] dark:bg-white/[0.07] border border-white/5 z-0 opacity-0 transition-[transform,width,height,opacity] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)]\"\n            />\n          )}\n\n          <AnimatePresence mode=\"popLayout\" initial={false}>\n            {files.map((file, idx) => {\n              const isSelected = selectedIds.includes(file.id);\n              return (\n                <motion.div\n                  layout\n                  key={file.id}\n                  ref={(node) => {\n                    itemRefs.current[idx] = node;\n                  }}\n                  initial={{ opacity: 0, y: 10, scale: 0.98 }}\n                  animate={{ opacity: 1, y: 0, scale: 1 }}\n                  exit={{\n                    opacity: 0,\n                    scale: 0.96,\n                    y: -6,\n                    transition: { duration: 0.16, ease: [0.2, 0, 0, 1] },\n                  }}\n                  transition={{\n                    layout: { type: \"spring\", stiffness: 450, damping: 32 },\n                    opacity: { duration: 0.18 },\n                  }}\n                  onMouseEnter={() => handleMouseEnter(idx)}\n                  onClick={() => toggleSelect(file.id)}\n                  className={cn(\n                    \"group relative z-10 flex items-center justify-between px-3 py-2.5 rounded-2xl cursor-pointer transition-colors duration-150\",\n                    isSelected\n                      ? \"bg-zinc-800/80 border border-white/5 shadow-xs\"\n                      : \"border border-transparent\",\n                  )}\n                >\n                  <div className=\"flex items-center gap-3.5 min-w-0\">\n                    <div\n                      className={cn(\n                        \"size-5 rounded-md border flex items-center justify-center shrink-0 transition-colors\",\n                        isSelected\n                          ? \"bg-zinc-200 border-zinc-200 text-zinc-950\"\n                          : \"border-zinc-700 bg-zinc-800/40 group-hover:border-zinc-600\",\n                      )}\n                    >\n                      {isSelected && (\n                        <Check\n                          size={12}\n                          strokeWidth={3}\n                          className=\"text-zinc-950\"\n                        />\n                      )}\n                    </div>\n\n                    <div className=\"size-10 rounded-xl overflow-hidden shrink-0 border border-white/10 flex items-center justify-center bg-zinc-800/90 text-zinc-400\">\n                      {file.type === \"image\" && file.thumbnail ? (\n                        <img\n                          src={file.thumbnail}\n                          alt={file.name}\n                          className=\"size-full object-cover\"\n                          loading=\"lazy\"\n                        />\n                      ) : file.type === \"pdf\" ? (\n                        <FileText size={18} className=\"text-zinc-300\" />\n                      ) : (\n                        <FileSpreadsheet size={18} className=\"text-zinc-300\" />\n                      )}\n                    </div>\n\n                    <div className=\"flex flex-col text-left min-w-0 truncate\">\n                      <span\n                        className={cn(\n                          \"text-sm font-medium leading-snug truncate\",\n                          isSelected ? \"text-zinc-100\" : \"text-zinc-200\",\n                        )}\n                      >\n                        {file.name}\n                      </span>\n                      <span className=\"text-xs text-zinc-400 truncate\">\n                        {file.author} · {file.date}\n                      </span>\n                    </div>\n                  </div>\n\n                  <div className=\"text-xs text-zinc-400 font-mono shrink-0 pl-3\">\n                    {file.size}\n                  </div>\n                </motion.div>\n              );\n            })}\n          </AnimatePresence>\n\n          {files.length === 0 && (\n            <motion.div\n              key=\"empty-state\"\n              initial={{ opacity: 0, scale: 0.96, y: 6 }}\n              animate={{ opacity: 1, scale: 1, y: 0 }}\n              exit={{ opacity: 0, scale: 0.96, y: -6 }}\n              transition={{ type: \"spring\", stiffness: 420, damping: 32 }}\n              className=\"flex flex-col items-center justify-center py-8 px-4 text-center select-none\"\n            >\n              <div className=\"size-10 rounded-2xl bg-zinc-800/60 border border-white/10 flex items-center justify-center text-zinc-400 mb-2.5\">\n                <Trash2 size={18} strokeWidth={1.75} />\n              </div>\n              <span className=\"text-sm font-medium text-zinc-200\">\n                All files deleted\n              </span>\n            </motion.div>\n          )}\n        </div>\n      </div>\n\n      <div className=\"mt-6 flex items-center justify-center\">\n        <div className=\"relative inline-flex items-center p-1 rounded-full bg-[#161618] border border-white/8 shadow-lg\">\n          <button\n            type=\"button\"\n            onClick={() => setOutcome(\"succeeds\")}\n            className={cn(\n              \"relative z-10 px-4 py-1 text-xs font-medium rounded-full cursor-pointer transition-colors duration-200 outline-none focus-visible:ring-1 focus-visible:ring-zinc-400\",\n              outcome === \"succeeds\"\n                ? \"text-white\"\n                : \"text-zinc-400 hover:text-zinc-200\",\n            )}\n          >\n            {outcome === \"succeeds\" && (\n              <motion.div\n                layoutId=\"outcome-slider\"\n                className=\"absolute inset-0 rounded-full bg-zinc-800 border border-white/10 shadow-xs -z-10\"\n                transition={{\n                  type: \"spring\",\n                  stiffness: 480,\n                  damping: 34,\n                  mass: 0.8,\n                }}\n              />\n            )}\n            Succeeds\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => setOutcome(\"fails\")}\n            className={cn(\n              \"relative z-10 px-4 py-1 text-xs font-medium rounded-full cursor-pointer transition-colors duration-200 outline-none focus-visible:ring-1 focus-visible:ring-zinc-400\",\n              outcome === \"fails\"\n                ? \"text-white\"\n                : \"text-zinc-400 hover:text-zinc-200\",\n            )}\n          >\n            {outcome === \"fails\" && (\n              <motion.div\n                layoutId=\"outcome-slider\"\n                className=\"absolute inset-0 rounded-full bg-zinc-800 border border-white/10 shadow-xs -z-10\"\n                transition={{\n                  type: \"spring\",\n                  stiffness: 480,\n                  damping: 34,\n                  mass: 0.8,\n                }}\n              />\n            )}\n            Fails\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default DeleteSelectionShowcase;\n",
      "type": "registry:ui",
      "target": "@ui/delete-selection.tsx"
    }
  ]
}
