{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flip-card-demo",
  "type": "registry:example",
  "title": "Flip Card Demo",
  "description": "A two-by-two matching game played by turning cards over.",
  "registryDependencies": [
    "@loomui/flip-card"
  ],
  "files": [
    {
      "path": "registry/example/flip-card-demo.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { FlipCard } from \"@/registry/loomui/flip-card\"\n\n/** Fixed order, not shuffled, so the server and the client agree. */\nconst DECK = [\"🫐\", \"🍑\", \"🍑\", \"🫐\"]\nconst MISS_DELAY = 700\n/** The card's own turn. The match ring waits for both to land. */\nconst FLIP_MS = 480\n\nconst FACE =\n  \"grid size-24 place-items-center rounded-xl border text-3xl transition-colors\"\n\nexport default function FlipCardDemo() {\n  const [faceUp, setFaceUp] = React.useState<number[]>([])\n  const [matched, setMatched] = React.useState<number[]>([])\n  // The ring waits for the turn, so it lands on a card already face up.\n  const [landed, setLanded] = React.useState<number[]>([])\n  const timer = React.useRef<ReturnType<typeof setTimeout>>(undefined)\n  const ring = React.useRef<ReturnType<typeof setTimeout>>(undefined)\n\n  React.useEffect(\n    () => () => {\n      clearTimeout(timer.current)\n      clearTimeout(ring.current)\n    },\n    []\n  )\n\n  const reveal = (index: number) => {\n    if (\n      faceUp.length === 2 ||\n      faceUp.includes(index) ||\n      matched.includes(index)\n    ) {\n      return\n    }\n\n    const next = [...faceUp, index]\n    setFaceUp(next)\n\n    if (next.length < 2) {\n      return\n    }\n\n    const [first, second] = next\n    if (DECK[first] === DECK[second]) {\n      setMatched((current) => [...current, first, second])\n      setFaceUp([])\n      ring.current = setTimeout(\n        () => setLanded((current) => [...current, first, second]),\n        FLIP_MS\n      )\n      return\n    }\n\n    timer.current = setTimeout(() => setFaceUp([]), MISS_DELAY)\n  }\n\n  const reset = () => {\n    clearTimeout(timer.current)\n    clearTimeout(ring.current)\n    setFaceUp([])\n    setMatched([])\n    setLanded([])\n  }\n\n  const won = landed.length === DECK.length\n\n  return (\n    <div className=\"flex flex-col items-center gap-5\">\n      <div className=\"grid grid-cols-2 gap-3\">\n        {DECK.map((emoji, index) => (\n          <FlipCard\n            key={index}\n            flipped={faceUp.includes(index) || matched.includes(index)}\n            onClick={() => reveal(index)}\n            aria-label={`Card ${index + 1}`}\n            front={\n              <span\n                className={`${FACE} bg-card text-muted-foreground/60 text-xl`}\n              >\n                ?\n              </span>\n            }\n            back={\n              <span\n                className={`${FACE} bg-card ${\n                  landed.includes(index) ? \"border-accent\" : \"\"\n                }`}\n              >\n                {emoji}\n              </span>\n            }\n          />\n        ))}\n      </div>\n\n      {won ? (\n        <button\n          type=\"button\"\n          onClick={reset}\n          className=\"text-muted-foreground hover:text-foreground cursor-pointer text-xs underline underline-offset-4\"\n        >\n          Nailed it. Again?\n        </button>\n      ) : (\n        <p className=\"text-muted-foreground text-xs\">Two pairs. Go.</p>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:example"
    }
  ]
}