{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gantt",
  "type": "registry:component",
  "title": "Gantt",
  "description": "Who is busy when, lane by lane. Sample data: trucks at six docks from 06:00 to 14:00, loading, unloading, waiting and delayed.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-gantt"
  ],
  "files": [
    {
      "path": "registry/chartory/components/gantt.tsx",
      "type": "registry:component",
      "target": "components/chartory/gantt.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Gantt (Chartory chart 037): 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/gantt\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/037-gantt/data\"\nimport { def } from \"@/lib/chartory/charts/types/037-gantt/layout\"\n\nregisterChart(def, sample)\n\nexport type GanttData = typeof sample\nexport type GanttProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: GanttData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: GanttData[]\n}\n\nexport function Gantt(props: GanttProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/037-gantt/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/037-gantt/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 037 Gantt · sample data (Figma chart/037, logistics: today's truck schedule on 6 docks, 06:00 to 14:00, now 10:30).\nimport type { GanttData } from \"../../plots/gantt\";\n\nexport const data: GanttData = {\n  yW: 64,\n  rows: [\"Dock 1\", \"Dock 2\", \"Dock 3\", \"Dock 4\", \"Dock 5\", \"Dock 6\"],\n  start: 6,\n  end: 14,\n  ticks: [[6, \"06:00\"], [8, \"08:00\"], [10, \"10:00\"], [12, \"12:00\"], [14, \"14:00\"]],\n  now: 10.5,\n  bars: [\n    [0, 6, 7.4, \"status/success\", \"TR-104\"], [0, 7.6, 9.8, \"data/cat-2\", \"TR-131\"], [0, 10.2, 12.6, \"status/success\", \"TR-220\"],\n    [1, 6.3, 8.9, \"data/cat-2\", \"TR-112\"], [1, 9.2, 11.4, \"status/danger\", \"TR-217 · late\"], [1, 11.8, 13.6, \"status/success\", \"TR-236\"],\n    [2, 6, 6.8, \"status/warning\", \"Wait\"], [2, 7, 9.5, \"status/success\", \"TR-145\"], [2, 10, 13.2, \"data/cat-2\", \"TR-251\"],\n    [3, 6.5, 10.8, \"status/success\", \"TR-162 · bulk\"], [3, 11.2, 13.8, \"status/warning\", \"Waiting\"],\n    [4, 7.2, 8.6, \"data/cat-2\", \"TR-178\"], [4, 9, 11, \"status/success\", \"TR-190\"], [4, 11.4, 12.4, \"data/cat-2\", \"TR-203\"],\n    [5, 6, 9, \"status/warning\", \"Maintenance\"], [5, 9.6, 12.2, \"status/success\", \"TR-244\"],\n  ],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/037-gantt/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/037-gantt/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 037 Gantt (Figma chart/037): C.gantt on the dock schedule sample.\nimport { buildVariant, type ChartDef, type Size, type TooltipSpec } from \"../../core/shell\";\nimport { gantt } from \"../../plots/gantt\";\nimport { data } from \"./data\";\n\nconst legend: [string, string][] = [[\"status/success\", \"Loading\"], [\"data/cat-2\", \"Unloading\"], [\"status/warning\", \"Waiting\"], [\"status/danger\", \"Delayed\"]];\nconst state = (tok: string) => legend.find((l) => l[0] === tok)![1];\nconst hm = (h: number) => String(Math.floor(h)).padStart(2, \"0\") + \":\" + String(Math.round((h % 1) * 60)).padStart(2, \"0\");\nconst late = data.bars.filter((b) => b[3] === \"status/danger\").length;\n\ntype Bar = (typeof data.bars)[number];\nconst q = (h: number) => Math.round(h * 20) / 20;\nfunction later(o: typeof data, step: number, amp: number): typeof data {\n  const now = o.now! + 0.05 * step;\n  const bars = o.bars.map(([r, a, b, tok, label], i): Bar => {\n    const m = amp * 0.25 * Math.sin(step * 1.9 + i * 1.3);\n    if (b <= now) return [r, a, b, tok, label];\n    if (a <= now) return [r, a, q(b + Math.abs(m)), tok, label];\n    const a1 = Math.max(q(now + 0.05), q(a + m));\n    return [r, a1, q(a1 + b - a), tok, label];\n  });\n  for (let i = 0; i < bars.length; i++) {\n    const cur = bars[i], prev = bars[i - 1], next = bars[i + 1];\n    if (prev?.[0] === cur[0] && cur[1] < prev[2] + 0.1) { const dur = cur[2] - cur[1]; cur[1] = q(prev[2] + 0.1); cur[2] = q(cur[1] + dur); }\n    const lim = next?.[0] === cur[0] ? next[1] - 0.1 : o.end;\n    if (cur[2] > lim) cur[2] = q(lim);\n  }\n  return { ...o, now, bars };\n}\n\n// A job's label shows when it fits the job's width in whole pixels, which differs per size; the update takes the\n// largest shift (of 1, ¾, ½ …) 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) => T): T => {\n  base ??= shape(data);\n  for (const a of [1, 0.8, 0.6, 0.4, 0.2]) { const c = make(a); if (shape(c) === base) return c; }\n  return make(0);\n};\n\n/** Tooltip for one slot (group = the slot's index): dock and truck, its state with the time window, its duration. */\nfunction tipOf(o: typeof data, g: number): TooltipSpec | null {\n  const b = o.bars[g];\n  if (!b) return null;\n  const [r, a, e, tok, label] = b, min = Math.round((e - a) * 60);\n  return {\n    kind: \"range\", caps: `${o.rows[r]} · ${label}`.toUpperCase(),\n    rows: [{ label: state(tok), value: hm(a) + \"–\" + hm(e), swatch: tok }, { label: \"Duration\", value: ((min >= 60 ? Math.floor(min / 60) + \" h \" : \"\") + (min % 60 ? (min % 60) + \" min\" : \"\")).trim(), swatch: tok }],\n  };\n}\n\nexport const def: ChartDef = {\n  no: 37,\n  slug: \"gantt\",\n  legend,\n  // update: the schedule a few minutes on (now +3 min per step); finished slots stay, running ones run over by up to\n  // 15 min, slots that have not started slip or move up by up to 15 min with their duration (never before now, never\n  // into the slot before them, never past the day's end)\n  update: (d, step) => keep((amp) => later(d as typeof data, step, amp)),\n  plot: (K, p, w, d) => gantt(K, p, w, (d as typeof data | undefined) ?? data),\n  tip: (d, g) => tipOf(d as typeof data, g),\n  describe: {\n    title: \"Dock schedule\",\n    summary: `${data.bars.length} slots on ${data.rows.length} docks from ${hm(data.start)} to ${hm(data.end)}, now ${hm(data.now!)}; ${late} truck delayed.`,\n    table: { head: [\"Dock\", \"Slot\", \"From\", \"To\", \"State\"], rows: data.bars.map(([r, a, b, tok, label]) => [data.rows[r], label, hm(a), hm(b), state(tok)]) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "schedule-and-status"
  ],
  "meta": {
    "access": "free",
    "no": 37,
    "family": "Schedule and status"
  }
}
