{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "waffle-chart",
  "title": "Waffle Chart",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/charts/waffle-chart/WaffleChart.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { ChartFrame } from '../shared'\n\n// WaffleChart — dependency-free SVG part-to-whole grid\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface WaffleSlice {\n  name: string\n  value: number\n  color?: string\n}\n\nexport interface WaffleChartProps {\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  className?: string\n  /** Accessible name announced for the chart image. Defaults to \"Chart\". */\n  ariaLabel?: string\n}\n\nconst DEFAULT_COLORS = ['var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', 'var(--chart-4)', 'var(--chart-5)']\n\nexport const WaffleChart = React.forwardRef<HTMLDivElement, WaffleChartProps>(\n  (\n    { data, height = 260, size = 10, radius = 2, showLegend = true, colors = DEFAULT_COLORS, className, ariaLabel },\n    ref,\n  ) => {\n    const total = data.reduce((s, d) => s + d.value, 0) || 1\n\n    const cells = React.useMemo(() => {\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.map((d, i) => ({ i, r: (d.value / total) * n - counts[i]! })).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    }, [data, size, total, colors])\n\n    return (\n      <ChartFrame\n        ref={ref}\n        height={height}\n        className={cn('flex items-center justify-center gap-5', className)}\n        ariaLabel={\n          ariaLabel ||\n          `Waffle chart: ${data.map((d) => `${d.name} ${Math.round((d.value / total) * 100)}%`).join(', ')}`\n        }\n      >\n        <svg viewBox={`0 0 ${size * 12} ${size * 12}`} className=\"aspect-square h-full max-h-full\" role=\"presentation\">\n          {cells.map((c, i) => (\n            <rect\n              key={i}\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          ))}\n        </svg>\n        {showLegend && (\n          <ul className=\"space-y-1.5 text-xs\">\n            {data.map((d, i) => (\n              <li key={d.name} className=\"flex items-center gap-2\">\n                <span className=\"size-2.5 rounded-[3px]\" style={{ background: d.color ?? colors[i % colors.length] }} />\n                <span className=\"text-foreground font-medium\">{d.name}</span>\n                <span className=\"text-muted-foreground tabular-nums\">{Math.round((d.value / total) * 100)}%</span>\n              </li>\n            ))}\n          </ul>\n        )}\n      </ChartFrame>\n    )\n  },\n)\nWaffleChart.displayName = 'WaffleChart'\n",
      "type": "registry:ui",
      "target": "~/components/ui/charts/waffle-chart/WaffleChart.tsx"
    },
    {
      "path": "packages/registry-react/components/charts/waffle-chart/index.ts",
      "content": "export { WaffleChart, type WaffleChartProps, type WaffleSlice } from './WaffleChart'\n",
      "type": "registry:ui",
      "target": "~/components/ui/charts/waffle-chart/index.ts"
    },
    {
      "path": "packages/registry-react/components/charts/shared.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport * as echartsCore from 'echarts/core'\nimport { use } from 'echarts/core'\nimport { CanvasRenderer } from 'echarts/renderers'\nimport {\n  LineChart as EChartsLineChart,\n  BarChart as EChartsBarChart,\n  PieChart as EChartsPieChart,\n  ScatterChart as EChartsScatterChart,\n  EffectScatterChart as EChartsEffectScatter,\n  PictorialBarChart as EChartsPictorialBar,\n  RadarChart as EChartsRadarChart,\n  GaugeChart as EChartsGaugeChart,\n  HeatmapChart as EChartsHeatmap,\n  TreemapChart as EChartsTreemapChart,\n  FunnelChart as EChartsFunnelChart,\n  BoxplotChart as EChartsBoxplotChart,\n  CandlestickChart as EChartsCandlestickChart,\n  CustomChart as EChartsCustomChart,\n  ChordChart as EChartsChordChart,\n  MapChart as EChartsMapChart,\n  GraphChart as EChartsGraphChart,\n  ParallelChart as EChartsParallelChart,\n  SankeyChart as EChartsSankeyChart,\n  SunburstChart as EChartsSunburstChart,\n  ThemeRiverChart,\n  TreeChart as EChartsTreeChart,\n} from 'echarts/charts'\nimport {\n  GridComponent,\n  PolarComponent,\n  TooltipComponent,\n  LegendComponent,\n  MarkLineComponent,\n  MarkAreaComponent,\n  MarkPointComponent,\n  GraphicComponent,\n  RadarComponent,\n  VisualMapComponent,\n  CalendarComponent,\n  DataZoomComponent,\n  ParallelComponent,\n  SingleAxisComponent,\n  TitleComponent,\n} from 'echarts/components'\nimport ReactECharts from 'echarts-for-react/esm/core'\nimport { cn } from '@/lib/utils'\n\nexport function heightToStyle(height: number | string): string {\n  return /^\\d+$/.test(String(height)) ? `${height}px` : String(height)\n}\n\ninterface ChartFrameProps {\n  height: number | string\n  className?: string\n  /** Apply the accessible role/tabindex/focus-ring chrome. Some chart\n   *  wrappers ship a bare `w-full` frame -- pass `false` for those. */\n  focusable?: boolean\n  /** Accessible name for role=\"img\". Defaults to \"Chart\". */\n  ariaLabel?: string\n}\n\n/** Shared `<div>` wrapper around the ECharts canvas. */\nexport const ChartFrame = React.forwardRef<HTMLDivElement, ChartFrameProps & { children: React.ReactNode }>(\n  ({ height, className, focusable = true, ariaLabel, children }, ref) => (\n    <div\n      ref={ref}\n      role=\"img\"\n      aria-label={ariaLabel || 'Chart'}\n      tabIndex={focusable ? 0 : undefined}\n      style={{ height: heightToStyle(height) }}\n      className={\n        focusable\n          ? cn('focus-visible:ring-ring w-full focus-visible:ring-2 focus-visible:outline-none', className)\n          : cn('w-full', className)\n      }\n    >\n      {children}\n    </div>\n  ),\n)\nChartFrame.displayName = 'ChartFrame'\n\n/** ECharts canvas filling its parent frame. */\nexport function EChart({ option }: { option: any }) {\n  return (\n    <ReactECharts\n      echarts={echartsCore as any}\n      option={option}\n      notMerge\n      lazyUpdate\n      style={{ width: '100%', height: '100%' }}\n    />\n  )\n}\n\nexport const echartsCoreModule = echartsCore\n\n// Register every chart type the wrappers need once at module load.\nuse([\n  CanvasRenderer,\n  EChartsLineChart,\n  EChartsBarChart,\n  EChartsPieChart,\n  EChartsScatterChart,\n  EChartsEffectScatter,\n  EChartsPictorialBar,\n  EChartsRadarChart,\n  EChartsGaugeChart,\n  EChartsHeatmap,\n  EChartsTreemapChart,\n  EChartsFunnelChart,\n  EChartsBoxplotChart,\n  EChartsCandlestickChart,\n  EChartsCustomChart,\n  EChartsChordChart,\n  EChartsMapChart,\n  EChartsGraphChart,\n  EChartsParallelChart,\n  EChartsSankeyChart,\n  EChartsSunburstChart,\n  ThemeRiverChart,\n  EChartsTreeChart,\n  GridComponent,\n  PolarComponent,\n  TooltipComponent,\n  LegendComponent,\n  MarkLineComponent,\n  MarkAreaComponent,\n  MarkPointComponent,\n  GraphicComponent,\n  RadarComponent,\n  VisualMapComponent,\n  CalendarComponent,\n  DataZoomComponent,\n  ParallelComponent,\n  SingleAxisComponent,\n  TitleComponent,\n])\n",
      "type": "registry:ui",
      "target": "~/components/ui/charts/shared.tsx"
    }
  ],
  "dependencies": [
    "echarts",
    "echarts-for-react"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "React mirror of @uipkge/waffle-chart — see the Vue registry item for the canonical description.",
  "categories": [
    "chart"
  ]
}