{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "skeleton",
  "title": "Skeleton",
  "description": "A shimmering placeholder that cross-fades to the real content, which rises in out of a blur.",
  "dependencies": [],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/skeleton.tsx",
      "content": "\"use client\"\n\n/* Animated skeleton. UI SDK has no skeleton, so these are plain elements with shadcn's part name\n   (Skeleton) plus a SkeletonSwap helper. This file adds motion only. Colours, radii and sizes stay yours. */\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* The sweep crosses, then rests a moment before the next one. */\nconst keyframes =\n  \"@keyframes kf-shimmer{0%{translate:-100% 0}62%,100%{translate:100% 0}}\"\n\n/* Shimmer: a soft band of light sweeps across the block. The band follows the text colour by\n   default; set --kf-shimmer to change it. With reduced motion the block stays still. */\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <>\n      <style href=\"kf-skeleton\" precedence=\"default\">\n        {keyframes}\n      </style>\n      <div\n        data-slot=\"skeleton\"\n        aria-hidden\n        className={cn(\n          \"relative isolate overflow-hidden\",\n          \"after:absolute after:inset-0 after:bg-[linear-gradient(90deg,transparent,var(--kf-shimmer,color-mix(in_oklch,currentColor_7%,transparent))_50%,transparent)]\",\n          \"after:-translate-x-full after:animate-[kf-shimmer_calc(1800ms*var(--kf-speed,1))_var(--ease-house)_infinite]\",\n          \"motion-reduce:after:hidden motion-reduce:after:animate-none!\",\n          className,\n        )}\n        {...props}\n      />\n    </>\n  )\n}\n\n/* Shows `fallback` (your skeletons) while `loading`, then crossfades to `children`: the skeletons\n   fade out and each direct child of the content rises out of a light blur, one after another.\n   Both layers share one grid cell, so the swap never jumps. Content that mounts only once loaded\n   gets the same entrance through @starting-style. */\nfunction SkeletonSwap({\n  loading,\n  fallback,\n  className,\n  contentClassName,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  loading: boolean\n  fallback: React.ReactNode\n  /** Classes for the content layer, whose direct children cascade in. */\n  contentClassName?: string\n}) {\n  return (\n    <div\n      data-slot=\"skeleton-swap\"\n      data-loading={loading || undefined}\n      aria-busy={loading || undefined}\n      className={cn(\"grid\", className)}\n      {...props}\n    >\n      <div\n        data-slot=\"skeleton-swap-fallback\"\n        aria-hidden\n        inert={!loading}\n        className={cn(\n          \"[grid-area:1/1] transition-[opacity,filter] duration-[calc(240ms*var(--kf-speed,1))] ease-house motion-reduce:transition-none!\",\n          !loading && \"pointer-events-none opacity-0 blur-[2px] [&_[data-slot=skeleton]]:after:[animation-play-state:paused]\",\n        )}\n      >\n        {fallback}\n      </div>\n      <div\n        data-slot=\"skeleton-swap-content\"\n        aria-hidden={loading || undefined}\n        inert={loading}\n        className={cn(\n          \"[grid-area:1/1]\",\n          \"*:transition-[opacity,translate,filter] *:duration-[calc(560ms*var(--kf-speed,1))] *:ease-spring\",\n          \"*:starting:translate-y-3 *:starting:opacity-0 *:starting:blur-[6px]\",\n          \"*:[transition-delay:calc(calc(90ms*var(--kf-speed,1))+(min(sibling-index(),10)-1)*calc(60ms*var(--kf-speed,1)))]\",\n          loading &&\n            \"*:translate-y-3 *:opacity-0 *:blur-[6px] *:duration-[calc(160ms*var(--kf-speed,1))] *:ease-house *:[transition-delay:0ms]\",\n          \"motion-reduce:*:transition-none\",\n          contentClassName,\n        )}\n      >\n        {children}\n      </div>\n    </div>\n  )\n}\n\nexport { Skeleton, SkeletonSwap }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/skeleton.tsx"
    },
    {
      "path": "registry/components/keyframery/skeleton.tsx",
      "content": "\"use client\"\n\n/* Styled skeleton: the animated primitive plus the Keyframery look. */\n\nimport * as React from \"react\"\n\nimport { Skeleton as SkeletonPrimitive, SkeletonSwap as SkeletonSwapPrimitive } from \"@/components/keyframery/primitives/skeleton\"\nimport { cn } from \"@/lib/utils\"\n\n/* A faint tint of the text colour, so it sits on any surface; in light mode the sweep is a band of\n   the background colour, in dark mode a slightly lighter tint. */\nfunction Skeleton({ className, ...props }: React.ComponentProps<typeof SkeletonPrimitive>) {\n  return (\n    <SkeletonPrimitive\n      className={cn(\n        \"rounded-[8px] bg-foreground/[0.07] dark:bg-foreground/[0.08]\",\n        \"[--kf-shimmer:color-mix(in_oklch,var(--background)_80%,transparent)] dark:[--kf-shimmer:color-mix(in_oklch,var(--foreground)_10%,transparent)]\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nconst SkeletonSwap = SkeletonSwapPrimitive\n\nexport { Skeleton, SkeletonSwap }\n",
      "type": "registry:component",
      "target": "components/keyframery/skeleton.tsx"
    }
  ],
  "type": "registry:component"
}