{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "countdown",
  "title": "Countdown",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/countdown/Countdown.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/lib/utils'\n\ntype Format = 'DD:HH:MM:SS' | 'HH:MM:SS' | 'MM:SS' | 'SS'\n\nconst props = withDefaults(\n  defineProps<{\n    /** Target date/time. Accepts a Date, ISO string, or epoch ms number. */\n    target: Date | string | number\n    /** Display format. Custom tokens: DD days, HH hours, MM minutes, SS seconds. */\n    format?: Format | string\n    /** Pause the countdown. */\n    paused?: boolean\n    /** Optional label rendered above the countdown. */\n    label?: string\n    /** Show leading zeros (e.g. 05 vs 5). */\n    pad?: boolean\n    /** Separator between units. */\n    separator?: string\n    class?: HTMLAttributes['class']\n  }>(),\n  {\n    format: 'DD:HH:MM:SS',\n    paused: false,\n    label: '',\n    pad: true,\n    separator: ':',\n  },\n)\n\nconst emit = defineEmits<{\n  (e: 'finish'): void\n  (e: 'tick', remaining: number): void\n}>()\n\nconst now = ref(Date.now())\nlet timer: ReturnType<typeof setInterval> | null = null\nconst finished = ref(false)\n\nconst targetMs = computed(() => {\n  if (props.target instanceof Date) return props.target.getTime()\n  if (typeof props.target === 'number') return props.target\n  return new Date(props.target).getTime()\n})\n\nconst remainingMs = computed(() => Math.max(0, targetMs.value - now.value))\n\nconst parts = computed(() => {\n  const total = remainingMs.value\n  const days = Math.floor(total / 86_400_000)\n  const hours = Math.floor((total % 86_400_000) / 3_600_000)\n  const minutes = Math.floor((total % 3_600_000) / 60_000)\n  const seconds = Math.floor((total % 60_000) / 1000)\n  return { days, hours, minutes, seconds }\n})\n\nfunction pad2(n: number) {\n  return props.pad ? String(n).padStart(2, '0') : String(n)\n}\n\nconst display = computed(() => {\n  const f = props.format\n  const { days, hours, minutes, seconds } = parts.value\n  const sep = props.separator\n  if (f === 'DD:HH:MM:SS') return `${pad2(days)}${sep}${pad2(hours)}${sep}${pad2(minutes)}${sep}${pad2(seconds)}`\n  if (f === 'HH:MM:SS') return `${pad2(days * 24 + hours)}${sep}${pad2(minutes)}${sep}${pad2(seconds)}`\n  if (f === 'MM:SS') return `${pad2(days * 24 * 60 + hours * 60 + minutes)}${sep}${pad2(seconds)}`\n  if (f === 'SS') return pad2(Math.floor(remainingMs.value / 1000))\n  // Custom token format: replace DD, HH, MM, SS tokens.\n  return f\n    .replace('DD', pad2(days))\n    .replace('HH', pad2(hours))\n    .replace('MM', pad2(minutes))\n    .replace('SS', pad2(seconds))\n})\n\nfunction startTimer() {\n  stopTimer()\n  if (props.paused) return\n  timer = setInterval(() => {\n    now.value = Date.now()\n    emit('tick', remainingMs.value)\n    if (remainingMs.value <= 0 && !finished.value) {\n      finished.value = true\n      stopTimer()\n      emit('finish')\n    }\n  }, 1000)\n}\n\nfunction stopTimer() {\n  if (timer) {\n    clearInterval(timer)\n    timer = null\n  }\n}\n\nwatch(\n  () => props.paused,\n  (paused) => {\n    if (paused) stopTimer()\n    else startTimer()\n  },\n)\n\nwatch(\n  () => props.target,\n  () => {\n    finished.value = false\n    now.value = Date.now()\n    startTimer()\n  },\n)\n\nonBeforeUnmount(stopTimer)\n\n// Kick off immediately.\nnow.value = Date.now()\nstartTimer()\n</script>\n\n<template>\n  <div\n    data-uipkge\n    data-slot=\"countdown\"\n    :data-finished=\"finished\"\n    :data-paused=\"paused\"\n    :class=\"cn('inline-flex flex-col gap-1', props.class)\"\n  >\n    <span\n      v-if=\"label\"\n      data-slot=\"countdown-label\"\n      class=\"text-muted-foreground text-xs font-medium tracking-wide uppercase\"\n    >\n      {{ label }}\n    </span>\n    <div data-slot=\"countdown-display\" class=\"flex items-baseline gap-1 font-mono tabular-nums\">\n      <slot\n        name=\"default\"\n        :days=\"parts.days\"\n        :hours=\"parts.hours\"\n        :minutes=\"parts.minutes\"\n        :seconds=\"parts.seconds\"\n        :display=\"display\"\n        :finished=\"finished\"\n      >\n        <slot name=\"days\" :days=\"parts.days\">\n          <span v-if=\"format.includes('DD')\" data-slot=\"countdown-days\" class=\"text-foreground text-2xl font-semibold\">\n            {{ pad2(parts.days) }}\n          </span>\n        </slot>\n        <span v-if=\"format.includes('DD') && format.includes('HH')\" class=\"text-muted-foreground text-2xl\">{{\n          separator\n        }}</span>\n        <slot name=\"hours\" :hours=\"parts.hours\">\n          <span v-if=\"format.includes('HH')\" data-slot=\"countdown-hours\" class=\"text-foreground text-2xl font-semibold\">\n            {{ pad2(parts.hours) }}\n          </span>\n        </slot>\n        <span v-if=\"format.includes('HH') && format.includes('MM')\" class=\"text-muted-foreground text-2xl\">{{\n          separator\n        }}</span>\n        <slot name=\"minutes\" :minutes=\"parts.minutes\">\n          <span\n            v-if=\"format.includes('MM')\"\n            data-slot=\"countdown-minutes\"\n            class=\"text-foreground text-2xl font-semibold\"\n          >\n            {{ pad2(parts.minutes) }}\n          </span>\n        </slot>\n        <span v-if=\"format.includes('MM') && format.includes('SS')\" class=\"text-muted-foreground text-2xl\">{{\n          separator\n        }}</span>\n        <slot name=\"seconds\" :seconds=\"parts.seconds\">\n          <span\n            v-if=\"format.includes('SS')\"\n            data-slot=\"countdown-seconds\"\n            class=\"text-foreground text-2xl font-semibold\"\n          >\n            {{ pad2(parts.seconds) }}\n          </span>\n        </slot>\n      </slot>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/countdown/Countdown.vue"
    },
    {
      "path": "packages/registry-vue/components/countdown/index.ts",
      "content": "export { default as Countdown } from './Countdown.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/countdown/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Countdown timer that shows time remaining to a target date. Supports DD:HH:MM:SS, HH:MM:SS, MM:SS, and SS formats plus custom token formats, named slots for days/hours/minutes/seconds, a label, leading-zero padding, a custom separator, paused state, and on-finish/tick events.",
  "categories": [
    "display",
    "utility"
  ]
}