{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "announcement-rotating-strip",
  "title": "Announcement — Rotating Strip",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/announcement-rotating-strip/AnnouncementRotatingStrip.vue",
      "content": "<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\nimport { ArrowRight } from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\n\nconst props = withDefaults(defineProps<{ interval?: number }>(), { interval: 6000 })\n\nconst messages = [\n  { label: 'New', text: 'Row-level scoping now evaluates against SCIM groups.', cta: 'Changelog' },\n  { label: 'Event', text: 'Live walkthrough of the five-week rollout, every Thursday.', cta: 'Save a seat' },\n  { label: 'Docs', text: 'The reconciliation checklist for your first close is published.', cta: 'Read it' },\n]\n\nconst index = ref(0)\nconst paused = ref(false)\nlet timer: ReturnType<typeof setInterval> | undefined\n\nfunction advance() {\n  index.value = (index.value + 1) % messages.length\n}\n\nfunction start() {\n  stop()\n  timer = setInterval(() => {\n    if (!paused.value) advance()\n  }, props.interval)\n}\n\nfunction stop() {\n  clearInterval(timer)\n  timer = undefined\n}\n\nonMounted(start)\nonBeforeUnmount(stop)\n</script>\n\n<template>\n  <div\n    data-slot=\"announcement-rotating-strip\"\n    class=\"border-border bg-muted/60 border-b backdrop-blur\"\n    @mouseenter=\"paused = true\"\n    @mouseleave=\"paused = false\"\n    @focusin=\"paused = true\"\n    @focusout=\"paused = false\"\n  >\n    <div class=\"mx-auto flex h-11 max-w-6xl items-center gap-3 px-6 text-sm\">\n      <!-- aria-live announces the rotation to screen readers without stealing focus. -->\n      <div class=\"flex min-w-0 flex-1 items-center gap-3\" aria-live=\"polite\" aria-atomic=\"true\">\n        <Badge variant=\"secondary\" class=\"shrink-0\">{{ messages[index].label }}</Badge>\n        <p class=\"min-w-0 truncate\">{{ messages[index].text }}</p>\n        <Button variant=\"link\" size=\"sm\" class=\"hidden h-auto shrink-0 p-0 text-xs sm:inline-flex\">\n          {{ messages[index].cta }}\n          <ArrowRight class=\"ml-1 size-3\" aria-hidden=\"true\" />\n        </Button>\n      </div>\n\n      <div class=\"flex shrink-0 items-center gap-1.5\">\n        <button\n          v-for=\"(message, i) in messages\"\n          :key=\"message.text\"\n          type=\"button\"\n          class=\"focus-visible:ring-ring size-1.5 rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none\"\n          :class=\"i === index ? 'bg-foreground' : 'bg-muted-foreground/40 hover:bg-muted-foreground'\"\n          :aria-label=\"`Show announcement ${i + 1} of ${messages.length}`\"\n          :aria-current=\"i === index ? 'true' : undefined\"\n          @click=\"index = i\"\n        />\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/AnnouncementRotatingStrip.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json"
  ],
  "description": "Announcement bar that cycles through several messages on a timer, pausing on hover and on focus, with dot controls for stepping between them manually.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "announcement"
}