{"name":"stopwatch","title":"Stopwatch","type":"registry:ui","files":[{"path":"src/components/ui/stopwatch.tsx","type":"registry:ui","target":"@ui/stopwatch.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"./lib/utils\";\n\nexport interface LapRecord {\n  lap: number;\n  time: number; // in milliseconds\n  formatted: string;\n}\n\nexport interface StopwatchProps extends React.HTMLAttributes<HTMLDivElement> {\n  autoStart?: boolean;\n  onLap?: (lap: LapRecord) => void;\n  className?: string;\n}\n\nexport function Stopwatch({\n  autoStart = false,\n  onLap,\n  className,\n  ...props\n}: StopwatchProps) {\n  const [isRunning, setIsRunning] = React.useState(autoStart);\n  const [time, setTime] = React.useState(0);\n  const [laps, setLaps] = React.useState<LapRecord[]>([]);\n  const timerRef = React.useRef<number | null>(null);\n  const startTimeRef = React.useRef<number>(0);\n\n  const formatTime = (ms: number) => {\n    const totalSeconds = Math.floor(ms / 1000);\n    const minutes = Math.floor(totalSeconds / 60);\n    const seconds = totalSeconds % 60;\n    const centiseconds = Math.floor((ms % 1000) / 10);\n\n    const m = minutes.toString().padStart(2, \"0\");\n    const s = seconds.toString().padStart(2, \"0\");\n    const cs = centiseconds.toString().padStart(2, \"0\");\n\n    return `${m}:${s}.${cs}`;\n  };\n\n  React.useEffect(() => {\n    if (isRunning) {\n      startTimeRef.current = performance.now() - time;\n      timerRef.current = window.setInterval(() => {\n        setTime(performance.now() - startTimeRef.current);\n      }, 10);\n    } else if (timerRef.current !== null) {\n      clearInterval(timerRef.current);\n      timerRef.current = null;\n    }\n\n    return () => {\n      if (timerRef.current !== null) {\n        clearInterval(timerRef.current);\n      }\n    };\n  }, [isRunning]);\n\n  const handleStartStop = () => {\n    setIsRunning((prev) => !prev);\n  };\n\n  const handleReset = () => {\n    setIsRunning(false);\n    setTime(0);\n    setLaps([]);\n  };\n\n  const handleRecordLap = () => {\n    if (time === 0) return;\n    const newLap: LapRecord = {\n      lap: laps.length + 1,\n      time,\n      formatted: formatTime(time),\n    };\n    setLaps((prev) => [newLap, ...prev]);\n    onLap?.(newLap);\n  };\n\n  return (\n    <div\n      className={cn(\n        \"relative flex flex-col items-center rounded-lg border-2 border-foreground bg-card p-6 font-mono select-none shadow-md\",\n        className\n      )}\n      {...props}\n    >\n      {/* Ticket notches */}\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute -left-2 top-1/2 -translate-y-1/2 size-4 rounded-full border-2 border-foreground bg-background\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute -right-2 top-1/2 -translate-y-1/2 size-4 rounded-full border-2 border-foreground bg-background\"\n      />\n\n      {/* Micro header */}\n      <div className=\"flex w-full items-center justify-between border-b border-dashed border-border pb-2 text-[10px] uppercase tracking-widest text-muted-foreground\">\n        <div className=\"flex items-center gap-1.5\">\n          <span\n            className={cn(\n              \"size-2 rounded-full\",\n              isRunning ? \"bg-accent animate-ping\" : \"bg-muted-foreground\"\n            )}\n          />\n          <span>TURNSTILE CHRONO</span>\n        </div>\n        <span>REC-001</span>\n      </div>\n\n      {/* Main Digital Clock Display */}\n      <div className=\"my-6 text-center\">\n        <div className=\"text-4xl font-black tracking-tight tabular-nums text-foreground sm:text-5xl\">\n          {formatTime(time)}\n        </div>\n        <div className=\"mt-1 text-[10px] uppercase tracking-widest text-muted-foreground\">\n          MINUTES : SECONDS . CENTISECONDS\n        </div>\n      </div>\n\n      {/* Controls */}\n      <div className=\"flex w-full items-center justify-center gap-2 border-t border-dashed border-border pt-4\">\n        <button\n          type=\"button\"\n          onClick={handleStartStop}\n          className={cn(\n            \"cursor-pointer rounded-md border-2 border-foreground px-4 py-2 text-xs font-bold uppercase tracking-wider shadow-xs transition-transform active:scale-95\",\n            isRunning\n              ? \"bg-accent text-accent-foreground\"\n              : \"bg-foreground text-background\"\n          )}\n        >\n          {isRunning ? \"PAUSE\" : \"START\"}\n        </button>\n\n        <button\n          type=\"button\"\n          disabled={!isRunning && time === 0}\n          onClick={handleRecordLap}\n          className=\"cursor-pointer rounded-md border-2 border-border bg-secondary px-3 py-2 text-xs font-bold uppercase tracking-wider text-foreground transition-colors hover:bg-card disabled:cursor-not-allowed disabled:opacity-40\"\n        >\n          LAP STUB\n        </button>\n\n        <button\n          type=\"button\"\n          disabled={time === 0}\n          onClick={handleReset}\n          className=\"cursor-pointer rounded-md border border-border bg-background px-3 py-2 text-xs font-bold uppercase tracking-wider text-muted-foreground transition-colors hover:bg-secondary disabled:cursor-not-allowed disabled:opacity-40\"\n        >\n          RESET\n        </button>\n      </div>\n\n      {/* Laps List (Perforated ticket stub receipts) */}\n      {laps.length > 0 && (\n        <div className=\"mt-4 w-full space-y-1.5 border-t border-border pt-3 max-h-36 overflow-y-auto\">\n          {laps.map((lap) => (\n            <div\n              key={lap.lap}\n              className=\"flex items-center justify-between rounded border border-dashed border-border bg-secondary/50 px-3 py-1.5 text-xs\"\n            >\n              <span className=\"font-bold text-muted-foreground\">\n                LAP #{lap.lap.toString().padStart(2, \"0\")}\n              </span>\n              <span className=\"font-bold tabular-nums text-foreground\">\n                {lap.formatted}\n              </span>\n            </div>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n}\n"}],"registryDependencies":["https://ui.bigbullapp.com/r/utils.json"]}