{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "placeholder",
  "title": "Placeholder",
  "description": "deterministic abstract SVG art from a `seed` · the kit ships no raster imagery",
  "dependencies": [
    "lucide-react-native@^1.21.0",
    "react-native-svg@15.15.4"
  ],
  "registryDependencies": [
    "@kit-native/icon",
    "@kit-native/lib-palette-context",
    "@kit-native/lib-utils"
  ],
  "files": [
    {
      "path": "components/kit/placeholder.tsx",
      "content": "import { Icon } from '@/components/ui/icon';\nimport { usePalette } from '@/lib/palette-context';\nimport { cn } from '@/lib/utils';\nimport type { LucideIcon } from 'lucide-react-native';\nimport * as React from 'react';\nimport { View } from 'react-native';\nimport Svg, { Circle, Path, Rect } from 'react-native-svg';\n\ntype Palette = 'chart' | 'mono' | 'primary';\n\ntype Props = {\n  /** Any string — the same seed always draws the same art. */\n  seed: string;\n  /** Width / height. Default 1 (square). */\n  ratio?: number;\n  /** Which token family to draw in. Default `chart`. */\n  palette?: Palette;\n  /** Optional glyph centred over the art. */\n  icon?: LucideIcon;\n  className?: string;\n};\n\n/** 32-bit string hash — stable across platforms and reloads. */\nfunction hash(input: string) {\n  let h = 2166136261;\n  for (let i = 0; i < input.length; i++) {\n    h ^= input.charCodeAt(i);\n    h = Math.imul(h, 16777619);\n  }\n  return h >>> 0;\n}\n\n/** Small, fast, seedable PRNG. */\nfunction mulberry32(seed: number) {\n  let a = seed;\n  return () => {\n    a |= 0;\n    a = (a + 0x6d2b79f5) | 0;\n    let t = Math.imul(a ^ (a >>> 15), 1 | a);\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n}\n\ntype Shape =\n  | { kind: 'circle'; cx: number; cy: number; r: number; fill: number; opacity: number }\n  | { kind: 'rect'; x: number; y: number; w: number; h: number; rx: number; fill: number; opacity: number }\n  | { kind: 'arc'; d: string; fill: number; opacity: number };\n\n/**\n * Deterministic abstract SVG art from a seed — stand-in imagery that never 404s.\n *\n * Drawn from theme colours, so it follows light/dark and re-brands with the tokens.\n * Use it wherever a prototype needs a picture it does not have: product shots, covers,\n * avatars, the art on a PromoCard.\n */\nexport function Placeholder({ seed, ratio = 1, palette = 'chart', icon, className }: Props) {\n  const colors = usePalette();\n\n  const shapes = React.useMemo<Shape[]>(() => {\n    const rand = mulberry32(hash(seed));\n    const count = 5 + Math.floor(rand() * 3);\n    const out: Shape[] = [];\n    for (let i = 0; i < count; i++) {\n      const fill = Math.floor(rand() * 5);\n      const opacity = 0.12 + rand() * 0.22;\n      const pick = rand();\n      if (pick < 0.45) {\n        out.push({ kind: 'circle', cx: rand() * 100, cy: rand() * 100, r: 14 + rand() * 30, fill, opacity });\n      } else if (pick < 0.8) {\n        const w = 22 + rand() * 46;\n        const h = 22 + rand() * 46;\n        out.push({ kind: 'rect', x: rand() * (100 - w), y: rand() * (100 - h), w, h, rx: 4 + rand() * 14, fill, opacity });\n      } else {\n        const cx = rand() * 100;\n        const cy = rand() * 100;\n        const r = 20 + rand() * 34;\n        out.push({ kind: 'arc', d: `M ${cx - r} ${cy} A ${r} ${r} 0 0 1 ${cx + r} ${cy} Z`, fill, opacity });\n      }\n    }\n    return out;\n  }, [seed]);\n\n  const fills = React.useMemo(() => {\n    if (palette === 'mono') return [colors.mutedForeground, colors.border, colors.mutedForeground, colors.border, colors.mutedForeground];\n    if (palette === 'primary') return [colors.primary, colors.primary, colors.ring, colors.primary, colors.ring];\n    return [colors.chart1, colors.chart2, colors.chart3, colors.chart4, colors.chart5];\n  }, [palette, colors]);\n\n  return (\n    <View\n      className={cn('bg-muted w-full items-center justify-center overflow-hidden rounded-lg', className)}\n      style={{ aspectRatio: ratio }}\n      accessibilityElementsHidden\n      importantForAccessibility=\"no-hide-descendants\">\n      <Svg width=\"100%\" height=\"100%\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid slice\">\n        {shapes.map((s, i) =>\n          s.kind === 'circle' ? (\n            <Circle key={i} cx={s.cx} cy={s.cy} r={s.r} fill={fills[s.fill]} opacity={s.opacity} />\n          ) : s.kind === 'rect' ? (\n            <Rect key={i} x={s.x} y={s.y} width={s.w} height={s.h} rx={s.rx} fill={fills[s.fill]} opacity={s.opacity} />\n          ) : (\n            <Path key={i} d={s.d} fill={fills[s.fill]} opacity={s.opacity} />\n          )\n        )}\n      </Svg>\n      {icon ? (\n        <View className=\"absolute\">\n          <Icon as={icon} size={28} className=\"text-muted-foreground\" />\n        </View>\n      ) : null}\n    </View>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/kit/placeholder.tsx"
    }
  ],
  "meta": {
    "exports": [
      "Placeholder"
    ],
    "api": "<Placeholder seed ratio? palette=\"chart|mono|primary\" icon? />"
  },
  "docs": "Run `npx expo install --fix` afterwards so Expo SDK packages match your SDK. Needs the kit theme (`@kit-native/theme`) and `KitThemeProvider` from `@kit-native/lib-theme-context` at the root.",
  "categories": [
    "media"
  ],
  "type": "registry:component"
}