{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "grouped-bars",
  "type": "registry:component",
  "title": "Grouped bars",
  "description": "A few series, side by side in each period. Sample data: new paid accounts per month by plan (Starter, Team, Business), July to December.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-grouped"
  ],
  "files": [
    {
      "path": "registry/chartory/components/grouped-bars.tsx",
      "type": "registry:component",
      "target": "components/chartory/grouped-bars.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Grouped bars (Chartory chart 002): 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/grouped-bars\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/002-grouped-bars/data\"\nimport { def } from \"@/lib/chartory/charts/types/002-grouped-bars/layout\"\n\nregisterChart(def, sample)\n\nexport type GroupedBarsData = typeof sample\nexport type GroupedBarsProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: GroupedBarsData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: GroupedBarsData[]\n}\n\nexport function GroupedBars(props: GroupedBarsProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/002-grouped-bars/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/002-grouped-bars/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 002 · sample data (Figma chart/002-grouped-bars, SaaS: new paid accounts by plan, Jul → Dec 2026).\nimport type { GroupedData } from \"../../plots/grouped\";\n\nexport const data: GroupedData = {\n  cats: [\"JUL\", \"AUG\", \"SEP\", \"OCT\", \"NOV\", \"DEC\"],\n  max: 600,\n  ticks: [\"600\", \"400\", \"200\", \"0\"],\n  series: [\n    { name: \"starter\", tok: \"data/cat-1\", vals: [420, 460, 510, 480, 540, 570] },\n    { name: \"team\", tok: \"data/cat-2\", vals: [260, 300, 290, 340, 360, 410] },\n    { name: \"business\", tok: \"data/cat-3\", vals: [110, 120, 150, 140, 170, 190] },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/002-grouped-bars/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/002-grouped-bars/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 002 Grouped bars (Figma chart/002-grouped-bars): C.grouped on new paid accounts by plan.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { grouped } from \"../../plots/grouped\";\nimport { data } from \"./data\";\n\n/** Deterministic wave in [-1, 1] per index and update step (no randomness: the same step gives the same period). */\nconst wave = (i: number, step: number, f = 1.7) => Math.sin(step * 2.3 + i * f + 0.5);\nconst clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));\n\nconst total = (j: number) => data.series[j].vals.reduce((a, b) => a + b, 0);\n\n/** Hover tooltip: one month's three plan bars, with the month total. */\nconst tip = (d: unknown, g: number): TooltipSpec => {\n  const o = d as typeof data;\n  const name = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n  return {\n    kind: \"series\",\n    caps: o.cats[g] + \" · NEW ACCOUNTS\",\n    rows: o.series.map((s) => ({ label: name(s.name), value: s.vals[g].toLocaleString(\"en-US\"), swatch: s.tok })),\n    total: { label: \"Total\", value: o.series.reduce((a, s) => a + s.vals[g], 0).toLocaleString(\"en-US\") },\n  };\n};\n\nexport const def: ChartDef = {\n  no: 2,\n  slug: \"grouped-bars\",\n  legend: [[\"data/cat-1\", \"Starter\"], [\"data/cat-2\", \"Team\"], [\"data/cat-3\", \"Business\"]],\n  plot: (K, p, w, d) => grouped(K, p, w, (d as typeof data | undefined) ?? data),\n  tip,\n  update: (d, step) => {\n    const o = d as typeof data;\n    // later half-years: signups grow ~4 % a period with a ±10 % swing per month and plan, inside the 600 axis\n    return { ...o, series: o.series.map((s, j) => ({ ...s, vals: s.vals.map((v, i) => clamp(Math.round(v * (1 + 0.04 * step + 0.1 * wave(i * 3 + j, step))), 40, 590)) })) };\n  },\n  describe: {\n    title: \"Signups by plan\",\n    summary: `New paid accounts per month by plan, July to December 2026: Starter ${total(0).toLocaleString(\"en-US\")}, Team ${total(1).toLocaleString(\"en-US\")}, Business ${total(2)}; December has Starter ${data.series[0].vals[5]}, Team ${data.series[1].vals[5]} and Business ${data.series[2].vals[5]}.`,\n    table: { head: [\"Month\", \"Starter\", \"Team\", \"Business\"], rows: data.cats.map((c, i) => [c, ...data.series.map((s) => s.vals[i])]) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "compare-items"
  ],
  "meta": {
    "access": "free",
    "no": 2,
    "family": "Compare items"
  }
}
