{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "waffle-chart",
  "title": "Waffle Chart",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/waffle-chart/WaffleChart.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface WaffleSlice {\n    name: string\n    value: number\n    color?: string\n  }\n\n  export interface WaffleChartProps extends HTMLAttributes<HTMLDivElement> {\n    data: WaffleSlice[]\n    height?: number | string\n    /** Cells per side (total = size²). Default 10. */\n    size?: number\n    /** Cell corner radius. Default 2. */\n    radius?: number\n    showLegend?: boolean\n    colors?: string[]\n    /** Accessible name announced for the chart image. */\n    ariaLabel?: string\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let {\n    data,\n    height = 260,\n    size = 10,\n    radius = 2,\n    showLegend = true,\n    colors = ['var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', 'var(--chart-4)', 'var(--chart-5)'],\n    class: className,\n    ariaLabel,\n    ...restProps\n  }: WaffleChartProps = $props()\n\n  const heightStyle = $derived(/^\\d+$/.test(String(height)) ? `${height}px` : String(height))\n  const total = $derived(data.reduce((s, d) => s + d.value, 0) || 1)\n\n  const cells = $derived.by(() => {\n    const n = size * size\n    const counts = data.map((d) => Math.floor((d.value / total) * n))\n    let rest = n - counts.reduce((s, c) => s + c, 0)\n    const remainders = data\n      .map((d, i) => ({ i, r: (d.value / total) * n - counts[i]! }))\n      .sort((a, b) => b.r - a.r)\n    for (const { i } of remainders) {\n      if (rest <= 0) break\n      counts[i]!++\n      rest--\n    }\n    const out: { color: string; name: string }[] = []\n    data.forEach((d, i) => {\n      for (let k = 0; k < counts[i]!; k++) out.push({ color: d.color ?? colors[i % colors.length]!, name: d.name })\n    })\n    return out.reverse()\n  })\n\n  const fallbackLabel = $derived(\n    `Waffle chart: ${data.map((d) => `${d.name} ${Math.round((d.value / total) * 100)}%`).join(', ')}`,\n  )\n</script>\n\n<div\n  data-slot=\"waffle-chart\"\n  role=\"img\"\n  tabindex=\"0\"\n  aria-label={ariaLabel || fallbackLabel}\n  style:height={heightStyle}\n  class={cn(\n    'focus-visible:ring-ring flex w-full items-center justify-center gap-5 focus-visible:ring-2 focus-visible:outline-none',\n    className,\n  )}\n  {...restProps}\n>\n  <svg viewBox={`0 0 ${size * 12} ${size * 12}`} class=\"aspect-square h-full max-h-full\" role=\"presentation\">\n    {#each cells as c, i (i)}\n      <rect\n        x={(i % size) * 12 + 1}\n        y={Math.floor(i / size) * 12 + 1}\n        width=\"10\"\n        height=\"10\"\n        rx={radius}\n        fill={c.color}\n      >\n        <title>{c.name}</title>\n      </rect>\n    {/each}\n  </svg>\n  {#if showLegend}\n    <ul class=\"space-y-1.5 text-xs\">\n      {#each data as d, i (d.name)}\n        <li class=\"flex items-center gap-2\">\n          <span class=\"size-2.5 rounded-[3px]\" style:background={d.color ?? colors[i % colors.length]}></span>\n          <span class=\"text-foreground font-medium\">{d.name}</span>\n          <span class=\"text-muted-foreground tabular-nums\">{Math.round((d.value / total) * 100)}%</span>\n        </li>\n      {/each}\n    </ul>\n  {/if}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/waffle-chart/WaffleChart.svelte"
    },
    {
      "path": "packages/registry-svelte/components/waffle-chart/index.ts",
      "content": "export { default as WaffleChart, type WaffleChartProps, type WaffleSlice } from './WaffleChart.svelte'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/waffle-chart/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Waffle chart as dependency-free SVG. 10×10 part-to-whole grid with legend. No extra npm packages.",
  "categories": [
    "chart"
  ]
}