{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hold-to-confirm",
  "title": "Hold to Confirm",
  "description": "Press-and-hold button for destructive actions, with a timed fill.",
  "dependencies": [],
  "registryDependencies": [
    "utils",
    "https://ui.cuelark.com/r/theme.json",
    "https://ui.cuelark.com/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/cuelark/ui/hold-to-confirm.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { gsap, motionScale } from \"@/lib/motion\";\nimport { cn } from \"@/lib/utils\";\n\ntype HoldToConfirmProps = Omit<React.ComponentProps<\"button\">, \"onClick\"> & {\n  /** Called once the hold completes. */\n  onConfirm: () => void;\n  /** How long to hold, in ms. */\n  duration?: number;\n  /** Label shown while holding. */\n  holdingLabel?: React.ReactNode;\n  variant?: \"destructive\" | \"primary\";\n};\n\n/**\n * A button you press and hold to confirm a destructive action, so a stray click never deletes anything.\n * A fill sweeps across while held (linear: it is a timer), snaps back if released early, and the button\n * shakes off a confirmation pulse when done. Keyboard: hold Space or Enter.\n */\nfunction HoldToConfirm({ onConfirm, duration = 1400, holdingLabel = \"Keep holding…\", variant = \"destructive\", className, children, disabled, ...props }: HoldToConfirmProps) {\n  const ref = React.useRef<HTMLButtonElement>(null);\n  const fill = React.useRef<HTMLSpanElement>(null);\n  const tween = React.useRef<gsap.core.Tween | null>(null);\n  const [holding, setHolding] = React.useState(false);\n\n  const start = () => {\n    if (disabled || !fill.current) return;\n    setHolding(true);\n    tween.current?.kill();\n    tween.current = gsap.to(fill.current, {\n      clipPath: \"inset(0 0% 0 0)\",\n      duration: duration / 1000,\n      ease: \"none\",\n      onComplete: () => {\n        setHolding(false);\n        onConfirm();\n        const el = ref.current;\n        if (el && motionScale(el)) gsap.fromTo(el, { scale: 0.96 }, { scale: 1, duration: 0.5, ease: \"elastic.out(1, 0.4)\" });\n        gsap.to(fill.current, { clipPath: \"inset(0 100% 0 0)\", duration: 0.35, ease: \"cue\", delay: 0.4 });\n      },\n    });\n  };\n  const cancel = () => {\n    if (!tween.current?.isActive()) return;\n    tween.current.kill();\n    setHolding(false);\n    gsap.to(fill.current, { clipPath: \"inset(0 100% 0 0)\", duration: 0.2, ease: \"cue\" });\n  };\n\n  const tone = variant === \"destructive\" ? \"bg-destructive text-white\" : \"bg-primary text-primary-foreground\";\n\n  return (\n    <button\n      ref={ref}\n      type=\"button\"\n      data-slot=\"hold-to-confirm\"\n      data-holding={holding || undefined}\n      disabled={disabled}\n      aria-label={typeof children === \"string\" ? `${children} (press and hold)` : undefined}\n      onPointerDown={start}\n      onPointerUp={cancel}\n      onPointerLeave={cancel}\n      onKeyDown={(e) => {\n        if ((e.key === \" \" || e.key === \"Enter\") && !e.repeat) {\n          e.preventDefault();\n          start();\n        }\n      }}\n      onKeyUp={(e) => (e.key === \" \" || e.key === \"Enter\") && cancel()}\n      className={cn(\n        \"relative isolate inline-flex h-ctl-md items-center justify-center overflow-hidden rounded-lg border border-border bg-background px-4 text-sm font-medium select-none outline-none transition-[scale] duration-150 ease-cue focus-visible:ring-3 focus-visible:ring-ring/50 active:scale-[0.97] disabled:pointer-events-none disabled:opacity-50\",\n        variant === \"destructive\" ? \"text-destructive\" : \"text-foreground\",\n        className,\n      )}\n      {...props}\n    >\n      <span className=\"relative inline-flex items-center gap-1.5 whitespace-nowrap [&_svg]:size-4 [&_svg]:shrink-0\">{holding ? holdingLabel : children}</span>\n      <span ref={fill} aria-hidden=\"true\" className={cn(\"absolute inset-0 flex items-center justify-center gap-1.5 whitespace-nowrap [clip-path:inset(0_100%_0_0)] [&_svg]:size-4 [&_svg]:shrink-0\", tone)}>\n        {holding ? holdingLabel : children}\n      </span>\n    </button>\n  );\n}\n\nexport { HoldToConfirm };\nexport type { HoldToConfirmProps };\n",
      "type": "registry:ui"
    }
  ],
  "docs": "Docs and examples: https://ui.cuelark.com/components/hold-to-confirm",
  "categories": [
    "actions"
  ],
  "type": "registry:ui"
}