{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bowtie",
  "type": "registry:component",
  "title": "Bowtie",
  "description": "Win the customer, then grow the revenue. Sample data: 48K visits to 420 won deals, then $61K onboard to $124K expand.",
  "registryDependencies": [
    "@chartory/core",
    "@chartory/plot-bowtie"
  ],
  "files": [
    {
      "path": "registry/chartory/components/bowtie.tsx",
      "type": "registry:component",
      "target": "components/chartory/bowtie.tsx",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// Bowtie (Chartory chart 087): 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/bowtie\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/087-bowtie/data\"\nimport { def } from \"@/lib/chartory/charts/types/087-bowtie/layout\"\n\nregisterChart(def, sample)\n\nexport type BowtieData = typeof sample\nexport type BowtieProps = Omit<ChartViewProps, \"def\" | \"data\" | \"states\"> & {\n  /** the data to draw (default: the sample) */\n  data?: BowtieData\n  /** further data states: the chart morphs to them (update) or ticks through them (live, with interval) */\n  states?: BowtieData[]\n}\n\nexport function Bowtie(props: BowtieProps) {\n  return <ChartView def={def} {...props} />\n}\n"
    },
    {
      "path": "registry/chartory/charts/types/087-bowtie/data.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/087-bowtie/data.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 087 Revenue bowtie · sample data (Figma chart/087-bowtie-revenue).\nimport type { BowtieData } from \"../../plots/bowtie\";\n\nexport const data: BowtieData = {\n  fmt: (v) => String(v),\n  left: [{ label: \"VISITS\", v: 100, text: \"48K\" }, { label: \"TRIALS\", v: 70, text: \"6.2K\" }, { label: \"SQL\", v: 45, text: \"1.9K\" }],\n  knot: { label: \"WON\", v: 22, text: \"420\" },\n  right: [{ label: \"ONBOARD\", v: 34, text: \"$61K\" }, { label: \"ADOPT\", v: 52, text: \"$88K\" }, { label: \"EXPAND\", v: 74, text: \"$124K\" }],\n};\n"
    },
    {
      "path": "registry/chartory/charts/types/087-bowtie/layout.ts",
      "type": "registry:lib",
      "target": "lib/chartory/charts/types/087-bowtie/layout.ts",
      "content": "// SPDX-License-Identifier: MIT · Copyright (c) 2026 BEY AGENCY LTD · Chartory, usechartory.com\n// 087 Bowtie (Figma chart/087-bowtie-revenue): C.bowtie, acquisition stages to the won knot, then growth stages.\nimport type { ChartDef, TooltipSpec } from \"../../core/shell\";\nimport { bowtie } from \"../../plots/bowtie\";\nimport { data } from \"./data\";\n\nconst segs = [...data.left.map((s) => ({ ...s, side: \"Acquire\" })), { ...data.knot, side: \"Win\" }, ...data.right.map((s) => ({ ...s, side: \"Grow\" }))];\n\nconst BASE = [48000, 6200, 1900, 420, 61, 88, 124];\nconst count = (n: number) => (n >= 10000 ? Math.round(n / 1000) + \"K\" : n >= 1000 ? (n / 1000).toFixed(1) + \"K\" : String(n));\n/** A later cohort: every stage moves by up to ±11 % (funnel order kept), its drawn size by the same ratio. */\nfunction update(d0: unknown, step: number): typeof data {\n  const d = d0 as typeof data;\n  const f = (i: number) => 1 + 0.11 * Math.sin(i * 2.1 + step * 1.7 + 0.4);\n  const seg = (s: (typeof data)[\"knot\"], i: number) => {\n    const n = Math.round(BASE[i] * f(i));\n    return { ...s, v: Math.round(s.v * f(i)), text: i < 4 ? count(n) : \"$\" + n + \"K\" };\n  };\n  return { ...d, left: d.left.map((s, i) => seg(s, i)), knot: seg(d.knot, 3), right: d.right.map((s, i) => seg(s, i + 4)) };\n}\n\n/** Hover: one stage (its trapezoid and value): side, stage and value. */\nfunction tip(d0: unknown, g: number): TooltipSpec | null {\n  const d = d0 as typeof data;\n  const all = [...d.left.map((s) => ({ ...s, side: \"Acquire\" })), { ...d.knot, side: \"Win\" }, ...d.right.map((s) => ({ ...s, side: \"Grow\" }))];\n  const s = all[g];\n  return s ? { kind: \"value\", text: `${s.side} · ${s.label.charAt(0) + s.label.slice(1).toLowerCase()} · ${s.text ?? d.fmt(s.v)}` } : null;\n}\n\nexport const def: ChartDef = {\n  no: 87,\n  slug: \"bowtie\",\n  legend: [[\"data/cat-2\", \"Acquire\"], [\"text/strong\", \"Win\"], [\"data/primary\", \"Grow\"]],\n  plot: (K, p, w, d) => bowtie(K, p, w, (d as typeof data | undefined) ?? data),\n  tip,\n  update,\n  describe: {\n    title: \"Customer bowtie\",\n    summary: `September cohort: ${segs.map((s) => `${s.label.toLowerCase()} ${s.text}`).join(\", \")}.`,\n    table: { head: [\"Stage\", \"Side\", \"Value\"], rows: segs.map((s) => [s.label, s.side, s.text ?? data.fmt(s.v)]) },\n  },\n};\n"
    }
  ],
  "categories": [
    "charts",
    "flow-between-steps"
  ],
  "meta": {
    "access": "free",
    "no": 87,
    "family": "Flow between steps"
  }
}
