{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "announcement-rotating-strip",
  "title": "Announcement — Rotating Strip",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/announcement-rotating-strip/AnnouncementRotatingStrip.tsx",
      "content": "'use client'\n\nimport { useEffect, useRef, useState } from 'react'\nimport { ArrowRight } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\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\nexport function AnnouncementRotatingStrip({ interval = 6000 }: { interval?: number }) {\n  const [index, setIndex] = useState(0)\n  const paused = useRef(false)\n\n  useEffect(() => {\n    const timer = setInterval(() => {\n      if (!paused.current) setIndex((value) => (value + 1) % messages.length)\n    }, interval)\n    return () => clearInterval(timer)\n  }, [interval])\n\n  return (\n    <div\n      data-slot=\"announcement-rotating-strip\"\n      className=\"border-border bg-muted/60 border-b backdrop-blur\"\n      onMouseEnter={() => (paused.current = true)}\n      onMouseLeave={() => (paused.current = false)}\n      onFocus={() => (paused.current = true)}\n      onBlur={() => (paused.current = false)}\n    >\n      <div className=\"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 className=\"flex min-w-0 flex-1 items-center gap-3\" aria-live=\"polite\" aria-atomic=\"true\">\n          <Badge variant=\"secondary\" className=\"shrink-0\">\n            {messages[index].label}\n          </Badge>\n          <p className=\"min-w-0 truncate\">{messages[index].text}</p>\n          <Button variant=\"link\" size=\"sm\" className=\"hidden h-auto shrink-0 p-0 text-xs sm:inline-flex\">\n            {messages[index].cta}\n            <ArrowRight className=\"ml-1 size-3\" aria-hidden=\"true\" />\n          </Button>\n        </div>\n\n        <div className=\"flex shrink-0 items-center gap-1.5\">\n          {messages.map((message, i) => (\n            <button\n              key={message.text}\n              type=\"button\"\n              className={`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                i === index ? 'bg-foreground' : 'bg-muted-foreground/40 hover:bg-muted-foreground'\n              }`}\n              aria-label={`Show announcement ${i + 1} of ${messages.length}`}\n              aria-current={i === index ? 'true' : undefined}\n              onClick={() => setIndex(i)}\n            />\n          ))}\n        </div>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/AnnouncementRotatingStrip.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/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"
}