{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stacked-bars",
  "type": "registry:component",
  "title": "Stacked bars",
  "description": "The total per period, and what it is made of. Sample data: failed payments per week by reason (card declined, insufficient funds, fraud block), W27 to W40.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-v-stack"
  ],
  "files": [
    {
      "path": "registry/chartory/components/stacked-bars.tsx",
      "type": "registry:component",
      "target": "components/chartory/stacked-bars.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Stacked bars (Chartory chart 003): 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/stacked-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/003-stacked-bars/data\"\nimport { def } from \"@/lib/chartory/charts/types/003-stacked-bars/layout\"\n\nregisterChart(def, sample)\n\nexport type StackedBarsData = typeof sample\nexport type StackedBarsProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: StackedBarsData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: StackedBarsData[]\n}\n\nexport function StackedBars(props: StackedBarsProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/003-stacked-bars/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/003-stacked-bars/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 003 Stacked bars · sample data (Figma chart/003-stacked-bars, fintech: failed payments per week by reason, W27 → W40).\nimport type { VStackData } from \"../../plots/v-stack\";\n\nexport const data: VStackData = {\n  max: 600,\n  ticks: [\"600\", \"400\", \"200\", \"0\"],\n  labels: { 0: \"W27\", 3: \"W30\", 6: \"W33\", 9: \"W36\", 13: \"W40\" },\n  stacks: [\n    {  name: \"card declined\", tok: \"data/cat-1\", vals: [304, 296, 298, 279, 269, 262, 249, 237, 219, 188, 171, 152, 136, 118]  },\n    {  name: \"insufficient funds\", tok: \"data/cat-2\", vals: [166, 161, 162, 152, 147, 143, 136, 129, 119, 103, 93, 83, 74, 64]  },\n    {  name: \"fraud block\", tok: \"data/cat-3\", vals: [82, 81, 81, 76, 73, 71, 67, 65, 60, 51, 47, 41, 37, 32]  },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/003-stacked-bars/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/003-stacked-bars/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 003 Stacked bars (Figma chart/003-stacked-bars): C.vStack on the weekly failed-payments sample.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { vStack } from \"../../plots/v-stack\";\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);\n\nconst n = data.stacks[0].vals.length;\nconst week = (i: number) => \"W\" + (27 + i);\nconst total = (i: number) => data.stacks.reduce((a, s) => a + s.vals[i], 0);\nconst cap = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n\n/** Hover tooltip: one week's stack, a row per reason and the week total. */\nconst tip = (d: unknown, g: number): TooltipSpec => {\n  const o = d as typeof data;\n  return {\n    kind: \"series\",\n    caps: week(g) + \" · FAILED PAYMENTS\",\n    rows: o.stacks.map((s) => ({ label: cap(s.name), value: s.vals[g].toLocaleString(\"en-US\"), swatch: s.tok })),\n    total: { label: \"Total\", value: o.stacks.reduce((a, s) => a + s.vals[g], 0).toLocaleString(\"en-US\") },\n  };\n};\n\nexport const def: ChartDef = {\n  no: 3,\n  slug: \"stacked-bars\",\n  legend: [[\"data/cat-1\", \"Card declined\"], [\"data/cat-2\", \"Insufficient funds\"], [\"data/cat-3\", \"Fraud block\"]],\n  plot: (K, p, w, d) => vStack(K, p, w, (d as typeof data | undefined) ?? data),\n  tip,\n  update: (d, step) => {\n    const o = d as typeof data;\n    // each reason moves ±12 % per week; a column whose total would pass 590 is scaled back under the 600 axis\n    const stacks = o.stacks.map((s, j) => ({ ...s, vals: s.vals.map((v, i) => Math.max(1, Math.round(v * (1 + 0.12 * wave(i + j * 5, step))))) }));\n    for (let i = 0; i < stacks[0].vals.length; i++) {\n      const t = stacks.reduce((a, s) => a + s.vals[i], 0);\n      if (t > 590) for (const s of stacks) s.vals[i] = Math.floor((s.vals[i] * 590) / t);\n    }\n    return { ...o, stacks };\n  },\n  describe: {\n    title: \"Failed payments by reason\",\n    summary: `Failed payments per week by reason, W27 to W40: ${total(0)} in W27, ${total(n - 1)} in W40 (${data.stacks.map((s) => s.vals[n - 1] + \" \" + s.name).join(\", \")}).`,\n    table: {\n      head: [\"Week\", ...data.stacks.map((s) => cap(s.name)), \"Total\"],\n      rows: Array.from({ length: n }, (_, i) => [week(i), ...data.stacks.map((s) => s.vals[i]), total(i)]),\n    },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "part-of-a-whole"
  ],
  "meta": {
    "access": "free",
    "no": 3,
    "family": "Part of a whole"
  }
}
