{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "skeleton",
  "title": "Skeleton",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/skeleton/skeleton.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { skeletonLoaderVariants } from './skeleton.variants'\n\n/* ------------------------------------------------------------------ */\n/* Shimmer keyframes                                                   */\n/* Ported from Skeleton.vue's <style scoped> block. Injected once so    */\n/* the component ships self-contained (Tailwind has no equivalent      */\n/* color-mix gradient sweep utility). Slow 1.8s sweep per NN/g.        */\n/* ------------------------------------------------------------------ */\nconst shimmerCss = `\n.skeleton-shimmer {\n  background: linear-gradient(\n    90deg,\n    color-mix(in srgb, var(--muted) 100%, transparent) 0%,\n    color-mix(in srgb, var(--muted) 60%, var(--foreground) 8%) 50%,\n    color-mix(in srgb, var(--muted) 100%, transparent) 100%\n  );\n  background-size: 200% 100%;\n  animation: skeleton-shimmer 1.8s linear infinite;\n}\n@keyframes skeleton-shimmer {\n  from { background-position: 200% 0; }\n  to { background-position: -200% 0; }\n}\n@media (prefers-reduced-motion: reduce) {\n  .skeleton-shimmer {\n    animation: none;\n    background: var(--muted);\n  }\n}\n`\n\nfunction ShimmerStyle() {\n  return <style dangerouslySetInnerHTML={{ __html: shimmerCss }} />\n}\n\n/* ------------------------------------------------------------------ */\n/* Skeleton                                                            */\n/* ------------------------------------------------------------------ */\n\nconst skeletonVariantClasses: Record<NonNullable<SkeletonProps['variant']>, string> = {\n  rectangular: '',\n  rounded: 'rounded-md',\n  circular: 'rounded-full',\n  text: 'rounded h-4 w-full',\n  avatar: 'rounded-full size-10',\n  image: 'rounded-lg size-24',\n  card: 'rounded-xl size-full min-h-[120px]',\n  'table-row': 'rounded h-10 w-full',\n}\n\nexport interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {\n  variant?: 'rectangular' | 'rounded' | 'circular' | 'text' | 'avatar' | 'image' | 'card' | 'table-row'\n  width?: string\n  height?: string\n  loading?: boolean\n}\n\nconst Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(\n  ({ className, variant = 'rectangular', width, height, loading = true, style, children, ...props }, ref) => {\n    if (!loading) return <>{children}</>\n\n    const variantStyle: React.CSSProperties = { ...style }\n    if (width) variantStyle.width = width\n    if (height) variantStyle.height = height\n\n    return (\n      <>\n        <ShimmerStyle />\n        <div\n          ref={ref}\n          data-uipkge=\"\"\n          data-slot=\"skeleton\"\n          className={cn('skeleton-shimmer', skeletonVariantClasses[variant ?? 'rectangular'], className)}\n          style={variantStyle}\n          {...props}\n        />\n      </>\n    )\n  },\n)\nSkeleton.displayName = 'Skeleton'\n\n/* ------------------------------------------------------------------ */\n/* SkeletonGroup                                                       */\n/* ------------------------------------------------------------------ */\n\nexport interface SkeletonGroupProps extends React.HTMLAttributes<HTMLElement> {\n  tag?: keyof React.JSX.IntrinsicElements\n}\n\nconst SkeletonGroup = React.forwardRef<HTMLElement, SkeletonGroupProps>(\n  ({ className, tag = 'div', children, ...props }, ref) => {\n    const Tag = tag as React.ElementType\n    return (\n      <Tag\n        ref={ref}\n        data-uipkge=\"\"\n        data-slot=\"skeleton-group\"\n        className={cn('space-y-2', className)}\n        {...props}\n      >\n        {children}\n      </Tag>\n    )\n  },\n)\nSkeletonGroup.displayName = 'SkeletonGroup'\n\n/* ------------------------------------------------------------------ */\n/* SkeletonText                                                        */\n/* ------------------------------------------------------------------ */\n\nexport interface SkeletonTextProps extends React.HTMLAttributes<HTMLDivElement> {\n  lines?: number\n  lastLineWidth?: string\n  firstLineWidth?: string\n}\n\nconst SkeletonText = React.forwardRef<HTMLDivElement, SkeletonTextProps>(\n  ({ className, lines = 3, lastLineWidth = '80%', firstLineWidth = '100%', ...props }, ref) => {\n    const lineWidths = Array.from({ length: lines }, (_, i) => {\n      if (i === 0) return firstLineWidth\n      if (i === lines - 1) return lastLineWidth\n      return '100%'\n    })\n\n    return (\n      <div ref={ref} data-uipkge=\"\" data-slot=\"skeleton-text\" className={cn('space-y-2', className)} {...props}>\n        {lineWidths.map((width, i) => (\n          <div key={i} className=\"bg-primary/10 h-4 animate-pulse rounded\" style={{ width }} />\n        ))}\n      </div>\n    )\n  },\n)\nSkeletonText.displayName = 'SkeletonText'\n\n/* ------------------------------------------------------------------ */\n/* SkeletonLoader                                                      */\n/* ------------------------------------------------------------------ */\n\nexport interface SkeletonLoaderProps {\n  className?: string\n  variant?:\n    | 'text'\n    | 'chip'\n    | 'chip-icon'\n    | 'article'\n    | 'avatar'\n    | 'avatar-small'\n    | 'avatar-large'\n    | 'heading'\n    | 'heading-medium'\n    | 'heading-small'\n    | 'image'\n    | 'image-small'\n    | 'image-large'\n    | 'card'\n    | 'card-avatar'\n    | 'actions'\n    | 'table'\n    | 'table-row'\n    | 'button'\n    | 'button-icon'\n    | 'badge'\n    | 'tab'\n    | 'date-picker'\n    | 'list-item'\n    | 'list-item-two-line'\n    | 'list-item-three-line'\n  loading?: boolean\n  rows?: number\n  boilerplate?: boolean\n  children?: React.ReactNode\n}\n\nfunction SkeletonLoader({\n  className,\n  variant = 'text',\n  loading = true,\n  rows = 1,\n  boilerplate = false,\n  children,\n}: SkeletonLoaderProps) {\n  let body: React.ReactNode\n\n  if (rows === 1) {\n    body = loading ? <div className={cn(skeletonLoaderVariants({ variant }), className)} /> : children\n  } else if (!loading) {\n    body = children\n  } else if (variant === 'article') {\n    body = (\n      <>\n        <div className={cn(skeletonLoaderVariants({ variant: 'heading' }), 'mb-4')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'mb-2')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'mb-2')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'w-3/4')} />\n      </>\n    )\n  } else if (variant === 'card') {\n    body = (\n      <>\n        <div className={cn(skeletonLoaderVariants({ variant: 'image-large' }), 'mb-4')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'heading-small' }), 'mb-2')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'mb-2')} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'w-1/2')} />\n      </>\n    )\n  } else if (variant === 'card-avatar') {\n    body = (\n      <div className=\"mb-4 flex items-center gap-4\">\n        <div className={cn(skeletonLoaderVariants({ variant: 'avatar-large' }))} />\n        <div className=\"flex-1 space-y-2\">\n          <div className={cn(skeletonLoaderVariants({ variant: 'heading-small' }))} />\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'w-1/2')} />\n        </div>\n      </div>\n    )\n  } else if (variant === 'actions') {\n    body = (\n      <div className=\"flex gap-2\">\n        <div className={cn(skeletonLoaderVariants({ variant: 'button' }))} />\n        <div className={cn(skeletonLoaderVariants({ variant: 'button' }))} />\n      </div>\n    )\n  } else if (variant === 'table') {\n    body = Array.from({ length: rows }, (_, i) => (\n      <div key={i} className={cn(skeletonLoaderVariants({ variant: 'table-row' }), 'mb-2')} />\n    ))\n  } else if (variant === 'list-item') {\n    body = Array.from({ length: rows }, (_, i) => (\n      <div key={i} className=\"mb-2 flex items-center gap-3\">\n        <div className={cn(skeletonLoaderVariants({ variant: 'avatar-small' }))} />\n        <div className=\"flex-1\">\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }))} />\n        </div>\n      </div>\n    ))\n  } else if (variant === 'list-item-two-line') {\n    body = Array.from({ length: rows }, (_, i) => (\n      <div key={i} className=\"mb-2 flex items-center gap-3\">\n        <div className={cn(skeletonLoaderVariants({ variant: 'avatar' }))} />\n        <div className=\"flex-1 space-y-2\">\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }))} />\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'w-3/4')} />\n        </div>\n      </div>\n    ))\n  } else if (variant === 'list-item-three-line') {\n    body = Array.from({ length: rows }, (_, i) => (\n      <div key={i} className=\"mb-2 flex items-start gap-3\">\n        <div className={cn(skeletonLoaderVariants({ variant: 'avatar' }))} />\n        <div className=\"flex-1 space-y-2\">\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }))} />\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }))} />\n          <div className={cn(skeletonLoaderVariants({ variant: 'text' }), 'w-2/3')} />\n        </div>\n      </div>\n    ))\n  } else {\n    body = Array.from({ length: rows }, (_, i) => (\n      <div key={i} className={cn(skeletonLoaderVariants({ variant }), 'mb-2')} />\n    ))\n  }\n\n  return (\n    <div data-uipkge=\"\" data-slot=\"skeleton-loader\" className=\"space-y-2\">\n      {body}\n      {boilerplate && !loading ? <div className=\"bg-muted/50 absolute inset-0\" /> : null}\n    </div>\n  )\n}\nSkeletonLoader.displayName = 'SkeletonLoader'\n\nexport { Skeleton, SkeletonGroup, SkeletonText, SkeletonLoader }\n",
      "type": "registry:ui",
      "target": "~/components/ui/skeleton/skeleton.tsx"
    },
    {
      "path": "packages/registry-react/components/skeleton/skeleton.variants.ts",
      "content": "import type { VariantProps } from 'class-variance-authority'\nimport { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than inline in the\n * SFC) so `SkeletonLoader.vue` can import them without the cva runtime\n * coupling that breaks SSR when several `<SkeletonLoader>` instances\n * render before the module graph fully resolves. Sibling pattern to\n * `card/card.variants.ts`.\n */\nexport const skeletonLoaderVariants = cva('bg-muted animate-pulse rounded', {\n  variants: {\n    variant: {\n      text: 'h-4 w-full',\n      chip: 'h-8 w-24 rounded-full',\n      'chip-icon': 'h-8 w-8 rounded-full',\n      article: '',\n      avatar: 'size-12 rounded-full',\n      'avatar-small': 'size-8 rounded-full',\n      'avatar-large': 'size-16 rounded-full',\n      heading: 'h-6 w-3/4',\n      'heading-medium': 'h-5 w-1/2',\n      'heading-small': 'h-4 w-1/3',\n      image: 'aspect-video w-full rounded-lg',\n      'image-small': 'h-32 w-32 rounded-lg',\n      'image-large': 'h-64 w-full rounded-lg',\n      card: '',\n      'card-avatar': '',\n      actions: '',\n      table: 'h-4 w-full',\n      'table-row': 'h-12 w-full',\n      button: 'h-10 w-24 rounded-md',\n      'button-icon': 'h-10 w-10 rounded-md',\n      badge: 'h-6 w-16 rounded-full',\n      tab: 'h-8 w-24 rounded-md',\n      'date-picker': 'h-10 w-full',\n      'list-item': 'h-16 w-full',\n      'list-item-two-line': 'h-20 w-full',\n      'list-item-three-line': 'h-24 w-full',\n    },\n  },\n  defaultVariants: {\n    variant: 'text',\n  },\n})\n\nexport type SkeletonLoaderVariants = VariantProps<typeof skeletonLoaderVariants>\n",
      "type": "registry:ui",
      "target": "~/components/ui/skeleton/skeleton.variants.ts"
    },
    {
      "path": "packages/registry-react/components/skeleton/index.ts",
      "content": "export {\n  Skeleton,\n  SkeletonGroup,\n  SkeletonText,\n  SkeletonLoader,\n  type SkeletonProps,\n  type SkeletonGroupProps,\n  type SkeletonTextProps,\n  type SkeletonLoaderProps,\n} from './skeleton'\n\n// Re-export variant API from the sibling file (kept separate to mirror the\n// Vue registry convention and avoid a component <-> index circular import).\nexport { skeletonLoaderVariants, type SkeletonLoaderVariants } from './skeleton.variants'\n",
      "type": "registry:ui",
      "target": "~/components/ui/skeleton/index.ts"
    }
  ],
  "dependencies": [
    "class-variance-authority"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Animated placeholder rectangles for loading states — drop one in shape of the content that’s about to render. Variants for text lines, avatars, rounded rectangles, and circles.",
  "categories": [
    "feedback"
  ]
}