{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "treemap",
  "type": "registry:component",
  "title": "Treemap",
  "description": "Many parts in groups, sized by value. Sample data: net sales by subcategory in apparel, home, beauty and outdoor, shirts $84K.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-treemap"
  ],
  "files": [
    {
      "path": "registry/chartory/components/treemap.tsx",
      "type": "registry:component",
      "target": "components/chartory/treemap.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Treemap (Chartory chart 030): 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/treemap\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/030-treemap/data\"\nimport { def } from \"@/lib/chartory/charts/types/030-treemap/layout\"\n\nregisterChart(def, sample)\n\nexport type TreemapData = typeof sample\nexport type TreemapProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: TreemapData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: TreemapData[]\n}\n\nexport function Treemap(props: TreemapProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/030-treemap/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/030-treemap/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 030 Treemap · sample data (Figma chart/030, e-commerce: Q3 net sales by category and subcategory, $K).\nimport type { TreemapData } from \"../../plots/treemap\";\n\nexport const data: TreemapData = {\n  fmt: (v) => \"$\" + v + \"K\",\n  groups: [\n    {  name: \"Apparel\", tok: \"data/cat-1\", items: [[\"Shirts\", 84], [\"Denim\", 62], [\"Outerwear\", 41], [\"Knitwear\", 28], [\"Socks\", 12]]  },\n    {  name: \"Home\", tok: \"data/cat-2\", items: [[\"Bedding\", 58], [\"Lighting\", 36], [\"Kitchen\", 33], [\"Decor\", 21]]  },\n    {  name: \"Beauty\", tok: \"data/cat-3\", items: [[\"Skincare\", 47], [\"Fragrance\", 25], [\"Haircare\", 18]]  },\n    {  name: \"Outdoor\", tok: \"data/cat-5\", items: [[\"Tents\", 30], [\"Footwear\", 26], [\"Packs\", 14]]  },\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/030-treemap/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/030-treemap/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 030 Treemap (Figma chart/030): C.treemap on the category mix sample.\nimport { buildVariant, type ChartDef, type Size, type TooltipSpec } from \"../../core/shell\";\nimport { treemap } from \"../../plots/treemap\";\nimport { data } from \"./data\";\n\nconst tot = (g: (typeof data.groups)[number]) => g.items.reduce((s, i) => s + i[1], 0);\nconst all = data.groups.reduce((s, g) => s + tot(g), 0);\nconst top = [...data.groups].sort((a, b) => tot(b) - tot(a))[0];\n\n// The squarified layout sits close to the label thresholds (48 × 22, value from 38 high) at every size, so the update\n// takes the first candidate move (largest first) that keeps every variant's marks.\nconst shape = (d: unknown) => ([\"xs\", \"s\", \"m\", \"l\"] as Size[]).flatMap((s) => [true, false].map((lg) => buildVariant(def, s, lg, d).marks.map((m) => m.kind + \"|\" + (m.kind === \"text\" ? m.style : m.name)).join(\"\\n\"))).join(\"\\n\\n\");\nlet base: string | undefined;\nconst keep = <T>(make: (a: number, gk: number) => T): T => {\n  base ??= shape(data);\n  for (const gk of [1, 0.8, 0.6, 0.5]) for (const a of [1, 0.75, 0.5, 0.35, 0.25, 0.15, 0]) { const c = make(a, gk); if (shape(c) === base) return c; }\n  return make(0, 0);\n};\n\n/** Tooltip for one tile (group = the tile's place in drawing order: categories by total, items by value): the item,\n *  its sales and its share of its category. */\nfunction tipOf(o: typeof data, g: number): TooltipSpec | null {\n  const sum = (x: (typeof o.groups)[number]) => x.items.reduce((s, i) => s + i[1], 0);\n  let k = 0;\n  for (const grp of [...o.groups].sort((a, b) => sum(b) - sum(a)))\n    for (const [label, v] of [...grp.items].sort((a, b) => b[1] - a[1])) {\n      if (k++ !== g) continue;\n      return { kind: \"cell\", caps: `${grp.name} · ${label}`.toUpperCase(), value: o.fmt ? o.fmt(v) : String(v), swatch: grp.tok, share: `${Math.round((v / sum(grp)) * 100)}% OF ${grp.name.toUpperCase()}` };\n    }\n  return null;\n}\n\nexport const def: ChartDef = {\n  no: 30,\n  slug: \"treemap\",\n  legend: [[\"data/cat-1\", \"Apparel\"], [\"data/cat-2\", \"Home\"], [\"data/cat-3\", \"Beauty\"], [\"data/cat-5\", \"Outdoor\"]],\n  // update: the next quarter; sales move up to 10 % overall, each category up to ±10 % on top and each item ±4 %\n  // (whole $K), as far as every size keeps the same tiles and labels (see keep)\n  update: (d, step) => {\n    const o = d as typeof data;\n    return keep((a, gk) => ({\n      ...o,\n      groups: o.groups.map((g, gi) => {\n        const k = (1 + gk * (step % 2 ? 0.1 : -0.08)) * (1 + a * 0.1 * Math.sin(step * 1.9 + gi * 2.4));\n        return { ...g, items: g.items.map(([l, v], i) => [l, Math.round(v * k * (1 + a * 0.04 * Math.sin(step * 2.7 + i * 1.3)))] as [string, number]) };\n      }),\n    }));\n  },\n  plot: (K, p, w, d) => treemap(K, p, w, (d as typeof data | undefined) ?? data),\n  tip: (d, g) => tipOf(d as typeof data, g),\n  describe: {\n    title: \"Sales by category\",\n    summary: `Q3 net sales of $${all}K across ${data.groups.length} categories and ${data.groups.reduce((s, g) => s + g.items.length, 0)} subcategories; ${top.name} is the largest at $${tot(top)}K, led by ${top.items[0][0]} at $${top.items[0][1]}K.`,\n    table: { head: [\"Category\", \"Subcategory\", \"Net sales\"], rows: data.groups.flatMap((g) => g.items.map(([l, v]) => [g.name, l, \"$\" + v + \"K\"])) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "part-of-a-whole"
  ],
  "meta": {
    "access": "free",
    "no": 30,
    "family": "Part of a whole"
  }
}
