{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "quadrant",
  "type": "registry:component",
  "title": "Quadrant",
  "description": "Items in four zones that tell you what to do. Sample data: products by growth (−20% to +60%) and margin (0 to 60%), grow, protect, fix margin and review.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-quadrant"
  ],
  "files": [
    {
      "path": "registry/chartory/components/quadrant.tsx",
      "type": "registry:component",
      "target": "components/chartory/quadrant.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Quadrant (Chartory chart 072): 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/quadrant\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/072-quadrant/data\"\nimport { def } from \"@/lib/chartory/charts/types/072-quadrant/layout\"\n\nregisterChart(def, sample)\n\nexport type QuadrantData = typeof sample\nexport type QuadrantProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: QuadrantData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: QuadrantData[]\n}\n\nexport function Quadrant(props: QuadrantProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/072-quadrant/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/072-quadrant/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 072 Quadrant · sample data (Figma chart/072, product lines: x = sales growth %, y = gross margin %, r = revenue weight).\nimport type { QuadrantData } from \"../../plots/quadrant\";\n\nexport const data: QuadrantData = {\n  xmin: -20, xmax: 60, ymin: 0, ymax: 60, mx: 15, my: 30,\n  ticks: [\"60%\", \"40%\", \"20%\", \"0\"],\n  xt: [[-20, \"−20%\"], [0, \"0\"], [20, \"+20%\"], [40, \"+40%\"], [60, \"+60%\"]],\n  quads: [\"PROTECT\", \"GROW\", \"REVIEW\", \"FIX MARGIN\"],\n  pts: [\n    { label: \"Linen\", x: 42, y: 48, r: 9, show: true }, { label: \"Denim\", x: 8, y: 44, r: 11, show: true }, { label: \"Knit\", x: 28, y: 36, r: 6 },\n    { label: \"Socks\", x: -8, y: 22, r: 5, show: true }, { label: \"Boots\", x: 34, y: 18, r: 8, show: true }, { label: \"Caps\", x: 4, y: 38, r: 4 },\n    { label: \"Belts\", x: -12, y: 12, r: 4 }, { label: \"Tees\", x: 18, y: 26, r: 10 }, { label: \"Scarf\", x: 50, y: 34, r: 5 },\n    { label: \"Bags\", x: 22, y: 52, r: 7 }, { label: \"Kids\", x: -2, y: 30, r: 6 }, { label: \"Swim\", x: 46, y: 14, r: 5 },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/072-quadrant/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/072-quadrant/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 072 Quadrant (Figma chart/072, \"Product portfolio\"): C.quadrant, 12 product lines by growth and margin.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { quadrant } from \"../../plots/quadrant\";\nimport { data } from \"./data\";\n\ntype QuadrantPoint = (typeof data.pts)[number];\nconst quad = (d: QuadrantPoint) => (d.x >= data.mx ? (d.y >= data.my ? \"Grow\" : \"Fix margin\") : d.y >= data.my ? \"Protect\" : \"Review\");\nconst pct = (v: number) => (v > 0 ? \"+\" : v < 0 ? \"−\" : \"\") + Math.abs(v) + \"%\";\nconst n = (q: string) => data.pts.filter((d) => quad(d) === q).length;\n\n// tooltip: one product line (group = its rank by growth, as the plot pops them left to right): growth, margin and\n// revenue weight, swatch = the dot's quadrant colour\nconst tip = (o: typeof data, g: number): TooltipSpec | null => {\n  const d = [...o.pts].sort((a, b) => a.x - b.x)[g];\n  if (!d) return null;\n  const q = d.x >= o.mx ? (d.y >= o.my ? \"Grow\" : \"Fix margin\") : d.y >= o.my ? \"Protect\" : \"Review\";\n  const tok = d.x >= o.mx ? (d.y >= o.my ? \"status/success\" : \"status/warning\") : d.y >= o.my ? \"data/primary\" : \"status/danger\";\n  return {\n    kind: \"range\",\n    caps: d.label.toUpperCase() + \" · \" + q.toUpperCase(),\n    rows: [{ label: \"Sales growth\", value: pct(d.x), swatch: tok }, { label: \"Gross margin\", value: d.y + \"%\", swatch: tok }, { label: \"Revenue weight\", value: String(d.r), swatch: tok }],\n  };\n};\n\nexport const def: ChartDef = {\n  no: 72,\n  slug: \"quadrant\",\n  legend: [[\"status/success\", \"Grow\"], [\"data/primary\", \"Protect\"], [\"status/warning\", \"Fix margin\"], [\"status/danger\", \"Review\"]],\n  plot: (K, p, w, d) => quadrant(K, p, w, (d as typeof data | undefined) ?? data),\n  tip: (d, g) => tip(d as typeof data, g),\n  // the next quarter: every line moves a few points in growth and margin (and its revenue weight by up to 1), each\n  // staying in its quadrant and on the axes\n  update: (d, step) => {\n    const o = d as typeof data;\n    const side = (v: number, m: number) => v >= m;\n    return {\n      ...o,\n      pts: o.pts.map((q, i) => {\n        let x = Math.min(o.xmax - 4, Math.max(o.xmin + 4, q.x + Math.round(4 * Math.sin(i * 1.3 + step * 2)))), y = Math.min(o.ymax - 4, Math.max(o.ymin + 4, q.y + Math.round(3 * Math.sin(i * 0.7 + step * 1.6))));\n        if (side(x, o.mx) !== side(q.x, o.mx)) x = q.x;\n        if (side(y, o.my) !== side(q.y, o.my)) y = q.y;\n        return { ...q, x, y, r: Math.max(3, q.r + Math.round(Math.sin(i * 2.1 + step * 1.3))) };\n      }),\n    };\n  },\n  describe: {\n    title: \"Portfolio map\",\n    summary: `${data.pts.length} product lines by sales growth and gross margin, split at ${pct(data.mx)} growth and ${data.my}% margin: ${n(\"Grow\")} grow, ${n(\"Protect\")} protect, ${n(\"Fix margin\")} fix margin, ${n(\"Review\")} review.`,\n    table: { head: [\"Product\", \"Growth\", \"Margin\", \"Quadrant\"], rows: data.pts.map((d) => [d.label, pct(d.x), d.y + \"%\", quad(d)]) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "relationship"
  ],
  "meta": {
    "access": "free",
    "no": 72,
    "family": "Relationship"
  }
}
