{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ring-grid",
  "type": "registry:component",
  "title": "Ring grid",
  "description": "One small ring per site, in a grid. Sample data: same-day dispatch at eight sites, Brno 99%, Ghent 89%.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-ring-grid"
  ],
  "files": [
    {
      "path": "registry/chartory/components/ring-grid.tsx",
      "type": "registry:component",
      "target": "components/chartory/ring-grid.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Ring grid (Chartory chart 065): sizes xs | s | m | l, laid out again from the data at each\n// size; collection \"hearth\" (default) or \"signal\" (with @chartory/signal, Code and Complete). Data in the type's shape (default: the sample). Docs:\n// https://usechartory.com/docs/charts/ring-grid\nimport { ChartView, type ChartViewProps } from \"@/lib/chartory/charts/chart-view\"\nimport { registerChart } from \"@/lib/chartory/charts/defs\"\nimport { data as sample } from \"@/lib/chartory/charts/types/065-ring-grid/data\"\nimport { def } from \"@/lib/chartory/charts/types/065-ring-grid/layout\"\n\nregisterChart(def, sample)\n\nexport type RingGridData = typeof sample\nexport type RingGridProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: RingGridData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: RingGridData[]\n}\n\nexport function RingGrid(props: RingGridProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/065-ring-grid/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/065-ring-grid/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 065 Ring grid · sample data (Figma chart/065, same-day dispatch rate per site, %; good from 97, warn from 92).\nimport type { RingGridData } from \"../../plots/ring-grid\";\n\nexport const data: RingGridData = {\n  good: 97, warn: 92,\n  items: [\n    { label: \"Leeds\", v: 98, sub: \"4.1K ORDERS\" }, { label: \"Lyon\", v: 97, sub: \"3.6K ORDERS\" },\n    { label: \"Porto\", v: 91, sub: \"2.2K ORDERS\" }, { label: \"Gdansk\", v: 96, sub: \"2.9K ORDERS\" },\n    { label: \"Brno\", v: 99, sub: \"1.8K ORDERS\" }, { label: \"Turin\", v: 94, sub: \"2.4K ORDERS\" },\n    { label: \"Ghent\", v: 89, sub: \"1.6K ORDERS\" }, { label: \"Malmo\", v: 97, sub: \"1.9K ORDERS\" },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/065-ring-grid/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/065-ring-grid/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 065 Ring grid (Figma chart/065, \"Same-day dispatch\"): C.ringGrid, dispatch rate for 8 sites.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { ringGrid } from \"../../plots/ring-grid\";\nimport { data } from \"./data\";\n\nconst below = data.items.filter((q) => q.v < data.warn).map((q) => `${q.label} ${q.v}%`);\nconst orders = (s: string) => s.replace(\" ORDERS\", \"\").replace(\"K\", \",\") + \"00\";\n\n// tooltip: one site's ring (group = site): its rate against the good threshold, tone = the ring's colour\nconst tip = (o: typeof data, g: number): TooltipSpec | null => {\n  const q = o.items[g];\n  if (!q) return null;\n  const dv = q.v - o.good, tone = q.v >= o.good ? \"success\" : q.v >= o.warn ? \"info\" : \"warning\";\n  return { kind: \"compare\", caps: q.label.toUpperCase() + \" · \" + q.sub, value: q.v + \"%\", delta: { text: (dv > 0 ? \"+\" : dv < 0 ? \"−\" : \"±\") + Math.abs(dv) + (Math.abs(dv) === 1 ? \" pt\" : \" pts\"), tone }, comparison: \"VS \" + o.good + \"% TARGET\" };\n};\n\nexport const def: ChartDef = {\n  no: 65,\n  slug: \"ring-grid\",\n  legend: null,\n  plot: (K, p, w, d) => ringGrid(K, p, w, (d as typeof data | undefined) ?? data),\n  tip: (d, g) => tip(d as typeof data, g),\n  // the next day: each site's rate moves by up to 2 points (whole %, below 100)\n  update: (d, step) => {\n    const o = d as typeof data;\n    return { ...o, items: o.items.map((q, i) => ({ ...q, v: Math.min(99, Math.max(80, q.v + Math.round(2 * Math.sin(i * 1.3 + step * 2.1)))) })) };\n  },\n  describe: {\n    title: \"Dispatch by site\",\n    summary: `Same-day dispatch rate for ${data.items.length} sites, from ${Math.min(...data.items.map((q) => q.v))}% to ${Math.max(...data.items.map((q) => q.v))}%; ${below.length} sites below ${data.warn}%: ${below.join(\", \")}.`,\n    table: { head: [\"Site\", \"Same-day dispatch\", \"Orders\"], rows: data.items.map((q) => [q.label, q.v + \"%\", orders(q.sub)]) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "compare-items"
  ],
  "meta": {
    "access": "free",
    "no": 65,
    "family": "Compare items"
  }
}
