{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart",
  "type": "registry:ui",
  "title": "Chart",
  "description": "Gradient-first charts on TanStack Charts: themed host, presets that return real definitions, and the full grammar.",
  "dependencies": [
    "@tanstack/charts@^1.1.0"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json",
    "https://control-ui.dev/r/motion.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/chart-knobs.ts",
      "target": "@components/control-ui/knob-contracts/chart-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/chart.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const chartKnobs = [\n  \"--cui-chart-foreground\",\n  \"--cui-chart-background\",\n  \"--cui-chart-line-size\",\n  \"--cui-chart-area-opacity\",\n  \"--cui-chart-hatch-opacity\",\n  \"--cui-chart-hatch-tint-opacity\",\n  \"--cui-chart-tooltip-background\",\n  \"--cui-chart-tooltip-foreground\",\n  \"--cui-chart-tooltip-border-color\",\n  \"--cui-chart-tooltip-border-width\",\n  \"--cui-chart-tooltip-radius\",\n  \"--cui-chart-tooltip-shadow\",\n  \"--cui-chart-tooltip-padding\",\n  \"--cui-chart-legend-gap\",\n  \"--cui-chart-swatch-size\",\n  \"--cui-chart-swatch-radius\",\n  \"--cui-chart-animation-duration\",\n  \"--cui-chart-transition-duration\",\n  \"--cui-chart-easing\",\n] as const;\nexport type ChartKnobStyle = Partial<Record<(typeof chartKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/chart.css",
      "target": "@components/control-ui/styles/recipes/chart.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"chart\"][data-slot=\"root\"]) {\n    --cui-chart-foreground: var(--muted-foreground);\n    --cui-chart-background: var(--card);\n    --cui-chart-line-size: 2px;\n    --cui-chart-area-opacity: 1;\n    --cui-chart-hatch-opacity: 0.6;\n    --cui-chart-hatch-tint-opacity: 0.12;\n    --cui-chart-tooltip-background: var(--popover);\n    --cui-chart-tooltip-foreground: var(--popover-foreground);\n    --cui-chart-tooltip-border-color: var(--border);\n    --cui-chart-tooltip-border-width: var(--control-rim-width);\n    --cui-chart-tooltip-radius: var(--radius-md);\n    --cui-chart-tooltip-shadow: var(--shadow-md);\n    --cui-chart-tooltip-padding: calc(var(--spacing) * 2.5);\n    --cui-chart-legend-gap: calc(var(--spacing) * 4);\n    --cui-chart-swatch-size: calc(var(--spacing) * 2.5);\n    --cui-chart-swatch-radius: calc(var(--radius-sm) * 0.5);\n    --cui-chart-animation-duration: calc(var(--duration-slow) * 2);\n    --cui-chart-transition-duration: var(--duration-slow);\n    --cui-chart-easing: var(--ease-emphasized);\n    --ts-chart-1: var(--chart-blue);\n    --ts-chart-2: var(--chart-purple);\n    --ts-chart-3: var(--chart-pink);\n    --ts-chart-4: var(--chart-orange);\n    --ts-chart-5: var(--chart-green);\n    --ts-chart-6: var(--chart-yellow);\n    --ts-chart-tooltip-background: transparent;\n    --ts-chart-tooltip-color: var(--cui-chart-tooltip-foreground);\n    --ts-chart-tooltip-border: none;\n    --ts-chart-tooltip-border-radius: var(--cui-chart-tooltip-radius);\n    --ts-chart-tooltip-shadow: none;\n    --ts-chart-tooltip-padding: 0;\n    --ts-chart-tooltip-font: var(--text-label) / 1.4 var(--font-body);\n    --ts-chart-focus-fill: var(--cui-chart-background);\n    --ts-chart-crosshair-label-halo: var(--cui-chart-background);\n    --ts-chart-crosshair-marker-fill: var(--cui-chart-background);\n    display: grid;\n    gap: calc(var(--spacing) * 3);\n    min-inline-size: 0;\n    color: var(--cui-chart-foreground);\n    font-family: var(--font-body);\n    font-variant-numeric: tabular-nums;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"]) {\n    position: relative;\n    min-inline-size: 0;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-line path) {\n    stroke-width: var(--cui-chart-line-size);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-area path) {\n    fill-opacity: var(--cui-chart-area-opacity);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-area-hatched path) {\n    mask: var(--_cui-chart-fade);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] [data-slot=\"hatch-stripe\"]) {\n    fill-opacity: var(--cui-chart-hatch-opacity);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] [data-slot=\"hatch-tint\"]) {\n    fill-opacity: var(--cui-chart-hatch-tint-opacity);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] :is(path, circle)) {\n    transition:\n      d var(--cui-chart-transition-duration) var(--cui-chart-easing),\n      cx var(--cui-chart-transition-duration) var(--cui-chart-easing),\n      cy var(--cui-chart-transition-duration) var(--cui-chart-easing),\n      r var(--cui-chart-transition-duration) var(--cui-chart-easing),\n      opacity var(--duration-fast) var(--ease-standard),\n      fill-opacity var(--duration-fast) var(--ease-standard);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"][data-resizing] :is(path, circle)) {\n    transition: none;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] :is(.cui-chart-area, .cui-chart-line) path) {\n    animation: cui-chart-reveal var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-bar-y path) {\n    transform-box: fill-box;\n    transform-origin: 50% 100%;\n    animation: cui-chart-grow-y var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-bar-x path) {\n    transform-box: fill-box;\n    transform-origin: 0% 50%;\n    animation: cui-chart-grow-x var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-bar-y .cui-chart-bar-negative) {\n    transform-origin: 50% 0%;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-bar-x .cui-chart-bar-negative) {\n    transform-origin: 100% 50%;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-dot circle) {\n    transform-box: fill-box;\n    transform-origin: center;\n    animation: cui-chart-pop var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-arc) {\n    transform-box: fill-box;\n    transform-origin: center;\n    animation: cui-chart-sweep var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-radial-bar) {\n    transform-box: fill-box;\n    transform-origin: center;\n    animation: cui-chart-pop var(--cui-chart-animation-duration) var(--cui-chart-easing) backwards;\n  }\n\n  @supports (animation-delay: calc(sibling-index() * 1s)) {\n    :where([data-control-family=\"chart\"][data-slot=\"plot\"] :is(.cui-chart-bar-y, .cui-chart-bar-x) path) {\n      animation-delay: calc(min(sibling-index() - 1, 12) * var(--cui-chart-animation-duration) / 24);\n    }\n\n    :where([data-control-family=\"chart\"][data-slot=\"plot\"] .cui-chart-dot circle) {\n      animation-delay: calc(min(sibling-index() - 1, 12) * var(--cui-chart-animation-duration) / 24);\n    }\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend\"]) {\n    display: flex;\n    flex-wrap: wrap;\n    align-items: center;\n    gap: calc(var(--spacing) * 1.5) var(--cui-chart-legend-gap);\n  }\n\n  :where([data-control-family=\"chart\"] [data-slot=\"swatch\"]) {\n    flex: none;\n    inline-size: var(--cui-chart-swatch-size);\n    block-size: var(--cui-chart-swatch-size);\n    border-radius: var(--cui-chart-swatch-radius);\n    background: var(--_cui-chart-swatch);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend-item\"][data-fill=\"gradient\"] [data-slot=\"swatch\"]) {\n    background: linear-gradient(to bottom, var(--_cui-chart-swatch), oklch(from var(--_cui-chart-swatch) l c h / 0.35));\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend-item\"][data-fill=\"hatched\"] [data-slot=\"swatch\"]) {\n    background: repeating-linear-gradient(\n      -45deg,\n      var(--_cui-chart-swatch) 0 1.5px,\n      oklch(from var(--_cui-chart-swatch) l c h / 0.15) 1.5px 3.5px\n    );\n    box-shadow: inset 0 0 0 1px var(--_cui-chart-swatch);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend-item\"][data-hidden=\"true\"]) {\n    opacity: 0.45;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend-item\"][data-hidden=\"true\"] [data-slot=\"swatch\"]) {\n    background: transparent;\n    box-shadow: inset 0 0 0 1px var(--_cui-chart-swatch);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"legend-toggle\"]) {\n    display: inline-flex;\n    align-items: center;\n    gap: calc(var(--spacing) * 1.5);\n    min-block-size: var(--target-min);\n    border-radius: var(--radius-sm);\n    transition: opacity var(--duration-fast) var(--ease-standard);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"tooltip\"]) {\n    padding: var(--cui-chart-tooltip-padding);\n    border: var(--cui-chart-tooltip-border-width) solid var(--cui-chart-tooltip-border-color);\n    border-radius: var(--cui-chart-tooltip-radius);\n    background: var(--cui-chart-tooltip-background);\n    color: var(--cui-chart-tooltip-foreground);\n    box-shadow: var(--cui-chart-tooltip-shadow);\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .ts-chart) {\n    outline: none;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .ts-chart-tooltip) {\n    transition:\n      left var(--duration-base) var(--cui-chart-easing),\n      top var(--duration-base) var(--cui-chart-easing),\n      opacity var(--duration-fast) var(--ease-standard),\n      scale var(--duration-fast) var(--ease-standard),\n      display var(--duration-fast) allow-discrete;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"][data-tooltip-entering] .ts-chart-tooltip) {\n    transition:\n      opacity var(--duration-fast) var(--ease-standard),\n      scale var(--duration-fast) var(--ease-standard),\n      display var(--duration-fast) allow-discrete;\n  }\n\n  :where([data-control-family=\"chart\"][data-slot=\"plot\"] .ts-chart-tooltip[hidden]) {\n    opacity: 0;\n    scale: 0.96;\n  }\n\n  @starting-style {\n    :where([data-control-family=\"chart\"][data-slot=\"plot\"] .ts-chart-tooltip) {\n      opacity: 0;\n      scale: 0.96;\n    }\n  }\n\n  @keyframes cui-chart-reveal {\n    from {\n      clip-path: inset(-8px 100% -8px -8px);\n    }\n    to {\n      clip-path: inset(-8px);\n    }\n  }\n\n  @keyframes cui-chart-grow-y {\n    from {\n      scale: 1 0;\n    }\n  }\n\n  @keyframes cui-chart-grow-x {\n    from {\n      scale: 0 1;\n    }\n  }\n\n  @keyframes cui-chart-pop {\n    from {\n      scale: 0.6;\n      opacity: 0;\n    }\n  }\n\n  @keyframes cui-chart-sweep {\n    from {\n      scale: 0.85;\n      rotate: -25deg;\n      opacity: 0;\n    }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    :where([data-control-family=\"chart\"] *) {\n      animation: none;\n      transition: none;\n    }\n  }\n}\n\n@property --cui-chart-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-chart-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-chart-line-size {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-area-opacity {\n  syntax: \"<number>\";\n  inherits: true;\n  initial-value: 1;\n}\n\n@property --cui-chart-hatch-opacity {\n  syntax: \"<number>\";\n  inherits: true;\n  initial-value: 1;\n}\n\n@property --cui-chart-hatch-tint-opacity {\n  syntax: \"<number>\";\n  inherits: true;\n  initial-value: 1;\n}\n\n@property --cui-chart-tooltip-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-chart-tooltip-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-chart-tooltip-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-chart-tooltip-border-width {\n  syntax: \"<length>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-tooltip-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-tooltip-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-chart-tooltip-padding {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-legend-gap {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-swatch-size {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-swatch-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-chart-animation-duration {\n  syntax: \"<time>\";\n  inherits: true;\n  initial-value: 0s;\n}\n\n@property --cui-chart-transition-duration {\n  syntax: \"<time>\";\n  inherits: true;\n  initial-value: 0s;\n}\n\n@property --cui-chart-easing {\n  syntax: \"*\";\n  inherits: true;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-cartesian.ts",
      "target": "@components/control-ui/ui/chart-cartesian.ts",
      "type": "registry:ui",
      "content": "import {\n  areaY,\n  barX,\n  barY,\n  type ChartPositionScaleOptions,\n  crosshair,\n  defineChart,\n  dot,\n  group,\n  lineY,\n  stack,\n  stackRowsY,\n} from \"@tanstack/charts\";\nimport { decorative } from \"@tanstack/charts/mark/decorative\";\nimport { scaleBand } from \"@tanstack/charts/scales/band\";\nimport { scaleLinear } from \"@tanstack/charts/scales/linear\";\nimport { tooltip as pointerTooltip } from \"@tanstack/charts/tooltip\";\nimport { type ChartColor, chartColor, chartSeriesColor } from \"@/components/control-ui/ui/chart-colors\";\nimport { type ChartCurveName, chartCurve } from \"@/components/control-ui/ui/chart-curves\";\nimport {\n  type ChartPart,\n  type ChartReference,\n  chartBarFill,\n  chartBarGradients,\n  chartBars,\n  chartFillPaint,\n  chartGradients,\n  chartOutline,\n  chartPart,\n  chartReferenceMarks,\n  dimUnfocused,\n  quietAxis,\n  quietGrid,\n  seriesTooltip,\n} from \"@/components/control-ui/ui/chart-marks\";\nimport {\n  type ChartFill,\n  type ChartSeries,\n  type ChartValueKey,\n  type ChartXKey,\n  type ChartXValue,\n  chartFormatters,\n  chartSeriesRows,\n  chartXScale,\n  type ResolvedChartSeries,\n  resolveChartSeries,\n} from \"@/components/control-ui/ui/chart-series\";\n\nexport type CartesianChartOptions<TDatum> = {\n  data: readonly TDatum[];\n  x: ChartXKey<TDatum>;\n  series: readonly ChartSeries<TDatum>[];\n  fill?: ChartFill;\n  xScale?: Partial<ChartPositionScaleOptions>;\n  yScale?: Partial<ChartPositionScaleOptions>;\n  formatX?: (value: ChartXValue) => string;\n  formatValue?: (value: number) => string;\n  formatTick?: (value: number) => string;\n  locale?: Intl.LocalesArgument;\n  references?: readonly ChartReference[];\n  grid?: boolean;\n  tooltip?: boolean;\n};\n\nexport type AreaChartOptions<TDatum> = CartesianChartOptions<TDatum> & {\n  stacked?: boolean | \"percent\";\n  curve?: ChartCurveName;\n};\n\nexport type LineChartOptions<TDatum> = CartesianChartOptions<TDatum> & {\n  curve?: ChartCurveName;\n  dots?: boolean;\n};\n\nexport type BarChartOptions<TDatum> = CartesianChartOptions<TDatum> & {\n  orientation?: \"vertical\" | \"horizontal\";\n  layout?: \"grouped\" | \"stacked\" | \"percent\";\n};\n\nfunction cartesianSetup<TDatum>(options: CartesianChartOptions<TDatum>, percent: boolean) {\n  const series = resolveChartSeries(options.series, options.fill ?? \"gradient\");\n  const rows = chartSeriesRows(options.data, options.x, series);\n  const formats = chartFormatters(options.locale);\n  const formatX = options.formatX ?? formats.x;\n  const formatValue = options.formatValue ?? formats.value;\n  const valueScale = {\n    scale: scaleLinear,\n    nice: true,\n    grid: options.grid === false ? false : quietGrid,\n    axis: quietAxis(options.formatTick ?? (percent ? formats.percent : formats.tick)),\n    ...options.yScale,\n  };\n  return {\n    series,\n    rows,\n    formatX,\n    valueScale,\n    tooltip:\n      options.tooltip === false\n        ? (false as const)\n        : seriesTooltip(\n            series.map((entry) => entry.label),\n            formatX,\n            formatValue,\n          ),\n    lastX: rows.at(-1)?.x,\n  };\n}\n\nfunction gradientColors<TDatum>(series: readonly ResolvedChartSeries<TDatum>[]): ChartColor[] {\n  return series.filter((entry) => entry.fill === \"gradient\").map((entry) => entry.color);\n}\n\nconst SERIES_FOCUS_POINT = { id: \"focus\", key: \"id\", x: \"x\", z: \"series\", r: 4, fillOpacity: 0, strokeOpacity: 0 } as const;\n\nexport function areaChart<TDatum>(options: AreaChartOptions<TDatum>) {\n  const stacked = options.stacked ?? false;\n  const { series, rows, formatX, valueScale, tooltip, lastX } = cartesianSetup(options, stacked === \"percent\");\n  const curve = chartCurve(options.curve ?? \"smooth\");\n  const stackedRows = stacked\n    ? stackRowsY(rows, { x: \"x\", y: \"value\", z: \"series\", offset: stacked === \"percent\" ? \"normalize\" : undefined })\n    : [];\n  const seriesMarks = series.flatMap((entry) => {\n    const areaParts: ChartPart[] = entry.fill === \"hatched\" ? [\"area\", \"area-hatched\"] : [\"area\"];\n    const fill = chartFillPaint(entry.color, entry.fill, \"area\");\n    const line = {\n      id: `line-${entry.key}`,\n      key: \"id\",\n      x: \"x\",\n      stroke: chartColor(entry.color),\n      strokeDasharray: entry.dashed ? \"4 4\" : undefined,\n      curve,\n    } as const;\n    if (stacked) {\n      const seriesRows = stackedRows.filter((row) => row.series === entry.label);\n      return [\n        decorative(\n          chartPart(areaY(seriesRows, { id: `area-${entry.key}`, key: \"id\", x: \"x\", y1: \"y1\", y2: \"y2\", fill, curve }), ...areaParts),\n        ),\n        decorative(chartPart(lineY(seriesRows, { ...line, y: \"y2\" }), \"line\")),\n      ];\n    }\n    const seriesRows = rows.filter((row) => row.series === entry.label);\n    return [\n      decorative(chartPart(areaY(seriesRows, { id: `area-${entry.key}`, key: \"id\", x: \"x\", y: \"value\", fill, curve }), ...areaParts)),\n      decorative(chartPart(lineY(seriesRows, { ...line, y: \"value\" }), \"line\")),\n    ];\n  });\n  const focusPoints = stacked ? dot(stackedRows, { ...SERIES_FOCUS_POINT, y: \"y2\" }) : dot(rows, { ...SERIES_FOCUS_POINT, y: \"value\" });\n  return defineChart({\n    marks: [\n      ...seriesMarks,\n      ...chartReferenceMarks(options.references ?? [], \"y\", lastX),\n      focusPoints,\n      crosshair({ x: true, y: false, strokeDasharray: \"3 3\" }),\n    ],\n    scales: {\n      x: { ...chartXScale(rows, \"point\", options.xScale), axis: quietAxis(formatX) },\n      y: valueScale,\n    },\n    gradients: chartGradients(gradientColors(series), \"area\"),\n    margin: { top: 8 },\n    focus: \"group-x\",\n    maxFocusDistance: Number.POSITIVE_INFINITY,\n    tooltip,\n  });\n}\n\nexport function lineChart<TDatum>(options: LineChartOptions<TDatum>) {\n  const { series, rows, formatX, valueScale, tooltip, lastX } = cartesianSetup(options, false);\n  const curve = chartCurve(options.curve ?? \"smooth\");\n  const seriesMarks = series.flatMap((entry) => {\n    const seriesRows = rows.filter((row) => row.series === entry.label);\n    const line = decorative(\n      chartPart(\n        lineY(seriesRows, {\n          id: `line-${entry.key}`,\n          key: \"id\",\n          x: \"x\",\n          y: \"value\",\n          stroke: chartColor(entry.color),\n          strokeDasharray: entry.dashed ? \"4 4\" : undefined,\n          curve,\n        }),\n        \"line\",\n      ),\n    );\n    if (!options.dots) return [line];\n    const dots = decorative(\n      chartPart(\n        dot(seriesRows, {\n          id: `dot-${entry.key}`,\n          key: \"id\",\n          x: \"x\",\n          y: \"value\",\n          r: 3,\n          fill: chartColor(entry.color),\n          stroke: \"var(--cui-chart-background)\",\n          strokeWidth: 1.5,\n        }),\n        \"dot\",\n      ),\n    );\n    return [line, dots];\n  });\n  return defineChart({\n    marks: [\n      ...seriesMarks,\n      ...chartReferenceMarks(options.references ?? [], \"y\", lastX),\n      dot(rows, { ...SERIES_FOCUS_POINT, y: \"value\" }),\n      crosshair({ x: true, y: false, strokeDasharray: \"3 3\" }),\n    ],\n    scales: {\n      x: { ...chartXScale(rows, \"point\", options.xScale), axis: quietAxis(formatX) },\n      y: valueScale,\n    },\n    margin: { top: 8 },\n    focus: \"group-x\",\n    maxFocusDistance: Number.POSITIVE_INFINITY,\n    tooltip,\n  });\n}\n\nexport function barChart<TDatum>(options: BarChartOptions<TDatum>) {\n  const layoutName = options.layout ?? \"grouped\";\n  const { rows, formatX, valueScale, tooltip } = cartesianSetup(options, layoutName === \"percent\");\n  const barLayouts = { grouped: group({ padding: 0.15 }), stacked: undefined, percent: stack({ offset: \"normalize\" }) };\n  const layout = barLayouts[layoutName];\n  const categoryScale = { ...chartXScale(rows, \"band\", options.xScale), axis: quietAxis(formatX) };\n  const band = { inset: -4, radius: 6, fillOpacity: 0.06 };\n  const shared = {\n    id: \"bars\",\n    key: \"id\",\n    z: \"series\",\n    stroke: (row: (typeof rows)[number]) => chartOutline(row.color, row.fill),\n    strokeWidth: 1,\n    radius: { end: 6 },\n    states: dimUnfocused,\n    layout,\n  } as const;\n\n  if (options.orientation === \"horizontal\") {\n    return defineChart({\n      marks: [\n        crosshair({ x: false, y: { band } }),\n        chartBars(barX(rows, { ...shared, y: \"x\", x: \"value\", fill: (row) => chartBarFill(row, \"x\") }), \"x\"),\n        ...chartReferenceMarks(options.references ?? [], \"x\", rows[0]?.x),\n      ],\n      scales: { x: valueScale, y: categoryScale },\n      gradients: chartBarGradients(rows, \"x\"),\n      margin: { top: 8 },\n      focus: \"group-y\",\n      maxFocusDistance: Number.POSITIVE_INFINITY,\n      tooltip,\n    });\n  }\n\n  return defineChart({\n    marks: [\n      crosshair({ x: { band }, y: false }),\n      chartBars(barY(rows, { ...shared, x: \"x\", y: \"value\", fill: (row) => chartBarFill(row, \"y\") }), \"y\"),\n      ...chartReferenceMarks(options.references ?? [], \"y\", rows.at(-1)?.x),\n    ],\n    scales: { x: categoryScale, y: valueScale },\n    gradients: chartBarGradients(rows, \"y\"),\n    margin: { top: 8 },\n    focus: \"group-x\",\n    maxFocusDistance: Number.POSITIVE_INFINITY,\n    tooltip,\n  });\n}\n\nexport type ScatterChartOptions<TDatum> = {\n  data: readonly TDatum[];\n  x: ChartValueKey<TDatum>;\n  y: ChartValueKey<TDatum>;\n  size?: ChartValueKey<TDatum>;\n  group?: ChartXKey<TDatum>;\n  colors?: Partial<Record<string, ChartColor>>;\n  xLabel?: string;\n  yLabel?: string;\n  formatX?: (value: number) => string;\n  formatValue?: (value: number) => string;\n  locale?: Intl.LocalesArgument;\n  xScale?: Partial<ChartPositionScaleOptions>;\n  yScale?: Partial<ChartPositionScaleOptions>;\n  references?: readonly ChartReference[];\n};\n\ntype ScatterRow = { id: string; x: number; y: number; size: number; group: string };\n\nfunction finiteNumber(value: unknown): number | undefined {\n  return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction scatterRows<TDatum>(options: ScatterChartOptions<TDatum>): ScatterRow[] {\n  return options.data.flatMap((datum, index) => {\n    const x = finiteNumber(datum[options.x]);\n    const y = finiteNumber(datum[options.y]);\n    if (x === undefined || y === undefined) return [];\n    const size = options.size === undefined ? 0 : (finiteNumber(datum[options.size]) ?? 0);\n    const groupValue: unknown = options.group ? datum[options.group] : \"\";\n    const groupName = groupValue instanceof Date ? groupValue.toISOString() : String(groupValue ?? \"\");\n    return { id: String(index), x, y, size, group: groupName };\n  });\n}\n\nexport function scatterChart<TDatum>(options: ScatterChartOptions<TDatum>) {\n  const rows = scatterRows(options);\n  const groups = [...new Set(rows.map((row) => row.group))];\n  const maxSize = Math.max(1, ...rows.map((row) => row.size));\n  const formats = chartFormatters(options.locale);\n  const formatX = options.formatX ?? formats.value;\n  const formatValue = options.formatValue ?? formats.value;\n  const xLabel = options.xLabel ?? options.x;\n  const yLabel = options.yLabel ?? options.y;\n  const sizeKey = options.size;\n  const radius = sizeKey ? (row: ScatterRow) => 3 + 11 * Math.sqrt(row.size / maxSize) : 4;\n  const dots = groups.map((groupName, groupIndex) => {\n    const color = chartColor(options.colors?.[groupName] ?? chartSeriesColor(groupIndex));\n    return chartPart(\n      dot(\n        rows.filter((row) => row.group === groupName),\n        {\n          id: `dot-${groupName}`,\n          key: \"id\",\n          x: \"x\",\n          y: \"y\",\n          r: radius,\n          fill: color,\n          fillOpacity: 0.65,\n          stroke: color,\n          strokeWidth: 1,\n          states: dimUnfocused,\n        },\n      ),\n      \"dot\",\n    );\n  });\n  const rightmostX = rows.length > 0 ? Math.max(...rows.map((row) => row.x)) : undefined;\n  return defineChart({\n    marks: [...dots, ...chartReferenceMarks(options.references ?? [], \"y\", rightmostX)],\n    scales: {\n      x: { scale: scaleLinear, nice: true, grid: quietGrid, axis: quietAxis(formats.tick), ...options.xScale },\n      y: { scale: scaleLinear, nice: true, grid: quietGrid, axis: quietAxis(formats.tick), ...options.yScale },\n    },\n    margin: { top: 8 },\n    focus: \"nearest\",\n    tooltip: {\n      use: pointerTooltip,\n      content: (points) => {\n        const point = points[0]?.datum;\n        if (!point) return { rows: [] };\n        const color = chartColor(options.colors?.[point.group] ?? chartSeriesColor(groups.indexOf(point.group)));\n        return {\n          title: point.group || undefined,\n          rows: [\n            { label: xLabel, value: formatX(point.x), color },\n            { label: yLabel, value: formatValue(point.y), color },\n            ...(sizeKey ? [{ label: sizeKey, value: formatValue(point.size), color }] : []),\n          ],\n        };\n      },\n    },\n  });\n}\n\nexport type SparklineChartOptions<TDatum> = {\n  data: readonly TDatum[];\n  x: ChartXKey<TDatum>;\n  y: ChartValueKey<TDatum>;\n  color?: ChartColor;\n  fill?: ChartFill;\n  type?: \"area\" | \"line\" | \"bar\";\n  curve?: ChartCurveName;\n  xScale?: Partial<ChartPositionScaleOptions>;\n};\n\nexport function sparklineChart<TDatum>(options: SparklineChartOptions<TDatum>) {\n  const color = options.color ?? \"blue\";\n  const fill = options.fill ?? \"gradient\";\n  const type = options.type ?? \"area\";\n  const curve = chartCurve(options.curve ?? \"smooth\");\n  const rows = chartSeriesRows(options.data, options.x, resolveChartSeries([{ key: options.y, color, fill }]));\n  const values = rows.flatMap((row) => (row.value === null ? [] : row.value));\n  const min = values.length > 0 ? Math.min(...values) : 0;\n  const shared = {\n    guides: false,\n    margin: 2,\n    focus: false,\n    pointer: false,\n    keyboard: false,\n    tooltip: false,\n  } as const;\n  const valueScale = { scale: scaleLinear, nice: false };\n\n  if (type === \"bar\") {\n    return defineChart({\n      ...shared,\n      marks: [chartBars(barY(rows, { key: \"id\", x: \"x\", y: \"value\", fill: (row) => chartBarFill(row, \"y\"), radius: { end: 2 } }), \"y\")],\n      scales: { x: { scale: () => scaleBand().padding(0.2), ...options.xScale }, y: valueScale },\n      gradients: chartBarGradients(rows, \"y\"),\n    });\n  }\n\n  const line = chartPart(lineY(rows, { key: \"id\", x: \"x\", y: \"value\", stroke: chartColor(color), curve }), \"line\");\n  const areaParts: ChartPart[] = fill === \"hatched\" ? [\"area\", \"area-hatched\"] : [\"area\"];\n  const area = chartPart(\n    areaY(rows, { key: \"id\", x: \"x\", y1: min, y2: \"value\", fill: chartFillPaint(color, fill, \"area\"), curve }),\n    ...areaParts,\n  );\n  return defineChart({\n    ...shared,\n    marks: type === \"area\" ? [area, line] : [line],\n    scales: { x: chartXScale(rows, \"point\", options.xScale), y: valueScale },\n    gradients: type === \"area\" && fill === \"gradient\" ? chartGradients([color], \"area\") : [],\n  });\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-colors.ts",
      "target": "@components/control-ui/ui/chart-colors.ts",
      "type": "registry:ui",
      "content": "export const CHART_COLORS = [\"blue\", \"purple\", \"pink\", \"orange\", \"green\", \"yellow\", \"red\", \"neutral\"] as const;\n\nexport type ChartColor = (typeof CHART_COLORS)[number];\n\nexport const CHART_SERIES_COLORS = [\"blue\", \"purple\", \"pink\", \"orange\", \"green\", \"yellow\"] as const satisfies readonly ChartColor[];\n\nexport function chartColor(color: ChartColor) {\n  return `var(--chart-${color})`;\n}\n\nexport function chartSeriesColor(index: number): ChartColor {\n  return CHART_SERIES_COLORS[index % CHART_SERIES_COLORS.length] ?? \"blue\";\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-curves.ts",
      "target": "@components/control-ui/ui/chart-curves.ts",
      "type": "registry:ui",
      "content": "import type { ChartCurve } from \"@tanstack/charts\";\n\ntype Point = readonly [number, number];\n\nexport type ChartCurveName = \"smooth\" | \"linear\" | \"step\";\n\nfunction monotoneTangents(points: readonly Point[]): number[] {\n  const tangents = points.map(() => 0);\n  const last = points.length - 1;\n  for (let index = 1; index < last; index += 1) {\n    const [x0, y0] = points[index - 1] ?? [0, 0];\n    const [x1, y1] = points[index] ?? [0, 0];\n    const [x2, y2] = points[index + 1] ?? [0, 0];\n    const h0 = x1 - x0;\n    const h1 = x2 - x1;\n    const s0 = h0 ? (y1 - y0) / h0 : 0;\n    const s1 = h1 ? (y2 - y1) / h1 : 0;\n    const weightedSlope = (s0 * h1 + s1 * h0) / (h0 + h1);\n    tangents[index] = (Math.sign(s0) + Math.sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(weightedSlope)) || 0;\n  }\n  if (last > 0) {\n    tangents[0] = endTangent(points[0], points[1], tangents[1] ?? 0);\n    tangents[last] = endTangent(points[last - 1], points[last], tangents[last - 1] ?? 0);\n  }\n  return tangents;\n}\n\nfunction endTangent(from: Point | undefined, to: Point | undefined, neighbourTangent: number): number {\n  if (!(from && to)) return neighbourTangent;\n  const h = to[0] - from[0];\n  return h ? ((3 * (to[1] - from[1])) / h - neighbourTangent) / 2 : neighbourTangent;\n}\n\nfunction monotoneSegments(points: readonly Point[]): string[] {\n  if (points.length < 3) return points.slice(1).map(([x, y]) => `L${x},${y}`);\n  const tangents = monotoneTangents(points);\n  return points.slice(1).map(([x1, y1], index) => {\n    const [x0, y0] = points[index] ?? [x1, y1];\n    const t0 = tangents[index] ?? 0;\n    const t1 = tangents[index + 1] ?? 0;\n    const dx = (x1 - x0) / 3;\n    return `C${x0 + dx},${y0 + dx * t0} ${x1 - dx},${y1 - dx * t1} ${x1},${y1}`;\n  });\n}\n\nfunction reversedMonotoneSegments(points: readonly Point[]): string[] {\n  if (points.length < 3)\n    return points\n      .slice(0, -1)\n      .map(([x, y]) => `L${x},${y}`)\n      .reverse();\n  const tangents = monotoneTangents(points);\n  return points\n    .slice(1)\n    .map(([x1, y1], index) => {\n      const [x0, y0] = points[index] ?? [x1, y1];\n      const t0 = tangents[index] ?? 0;\n      const t1 = tangents[index + 1] ?? 0;\n      const dx = (x1 - x0) / 3;\n      return `C${x1 - dx},${y1 - dx * t1} ${x0 + dx},${y0 + dx * t0} ${x0},${y0}`;\n    })\n    .reverse();\n}\n\nfunction closedArea(top: readonly Point[], bottom: readonly Point[], topSegments: string[], bottomSegments: string[]): string {\n  const [firstX, firstY] = top[0] ?? [0, 0];\n  const [lastX, lastY] = bottom.at(-1) ?? top.at(-1) ?? [0, 0];\n  return `M${firstX},${firstY}${topSegments.join(\"\")}L${lastX},${lastY}${bottomSegments.join(\"\")}Z`;\n}\n\nexport const smoothCurve: ChartCurve = {\n  line(points) {\n    if (points.length === 0) return \"\";\n    const [x, y] = points[0] ?? [0, 0];\n    return `M${x},${y}${monotoneSegments(points).join(\"\")}`;\n  },\n  area(top, bottom) {\n    if (top.length === 0) return \"\";\n    return closedArea(top, bottom, monotoneSegments(top), reversedMonotoneSegments(bottom));\n  },\n};\n\nfunction stepSegments(points: readonly Point[]): string[] {\n  return points.slice(1).map(([x, y]) => `H${x}V${y}`);\n}\n\nfunction reversedStepSegments(points: readonly Point[]): string[] {\n  return points\n    .slice(0, -1)\n    .map(([, y], index) => `V${y}H${points[index]?.[0] ?? 0}`)\n    .reverse();\n}\n\nexport const stepCurve: ChartCurve = {\n  line(points) {\n    if (points.length === 0) return \"\";\n    const [x, y] = points[0] ?? [0, 0];\n    return `M${x},${y}${stepSegments(points).join(\"\")}`;\n  },\n  area(top, bottom) {\n    if (top.length === 0) return \"\";\n    return closedArea(top, bottom, stepSegments(top), reversedStepSegments(bottom));\n  },\n};\n\nexport function chartCurve(name: ChartCurveName): ChartCurve | undefined {\n  if (name === \"smooth\") return smoothCurve;\n  if (name === \"step\") return stepCurve;\n  return undefined;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-marks.ts",
      "target": "@components/control-ui/ui/chart-marks.ts",
      "type": "registry:ui",
      "content": "import {\n  type ChartLinearGradient,\n  type ChartTooltipContentContext,\n  type MarkRenderContext,\n  ruleX,\n  ruleY,\n  type SceneNode,\n  text,\n} from \"@tanstack/charts\";\nimport { decorative } from \"@tanstack/charts/mark/decorative\";\nimport { tooltip } from \"@tanstack/charts/tooltip\";\nimport { type ChartColor, chartColor } from \"@/components/control-ui/ui/chart-colors\";\nimport type { ChartFill, ChartSeriesRow, ChartXValue } from \"@/components/control-ui/ui/chart-series\";\n\ntype AnyChartMark = Parameters<typeof decorative>[0];\n\nexport type ChartPart = \"area\" | \"area-hatched\" | \"line\" | \"dot\" | \"reference\";\n\ntype SceneNodesTransform = (nodes: readonly SceneNode[], renderContext: MarkRenderContext) => SceneNode[];\n\nfunction withSceneNodes<TMark extends AnyChartMark>(mark: TMark, transform: SceneNodesTransform): TMark {\n  return {\n    ...mark,\n    initialize(context) {\n      const initialized = mark.initialize(context);\n      const { resolveLayout } = initialized;\n      return {\n        ...initialized,\n        render: (renderContext) => {\n          const scene = initialized.render(renderContext);\n          return { ...scene, nodes: transform(scene.nodes, renderContext) };\n        },\n        resolveLayout: resolveLayout\n          ? (layoutContext) => {\n              const layout = resolveLayout(layoutContext);\n              return {\n                ...layout,\n                render: (renderContext) => {\n                  const scene = layout.render(renderContext);\n                  return { ...scene, nodes: transform(scene.nodes, renderContext) };\n                },\n              };\n            }\n          : undefined,\n      };\n    },\n  };\n}\n\nfunction withClass<TNode extends SceneNode>(node: TNode, className: string): TNode {\n  return { ...node, className: node.className ? `${node.className} ${className}` : className };\n}\n\nexport function chartPart<TMark extends AnyChartMark>(mark: TMark, ...parts: ChartPart[]): TMark {\n  const partClass = parts.map((part) => `cui-chart-${part}`).join(\" \");\n  return withSceneNodes(mark, (nodes) => nodes.map((node) => withClass(node, partClass)));\n}\n\nconst BASELINE_TOLERANCE = 0.5;\n\nfunction withNegativeBars(nodes: readonly SceneNode[], axis: \"x\" | \"y\", baseline: number): SceneNode[] {\n  return nodes.map((node) => {\n    if (node.kind === \"group\") return { ...node, children: withNegativeBars(node.children, axis, baseline) };\n    if (node.kind !== \"rect\") return node;\n    const negative = axis === \"y\" ? node.y >= baseline - BASELINE_TOLERANCE : node.x + node.width <= baseline + BASELINE_TOLERANCE;\n    return negative ? withClass(node, \"cui-chart-bar-negative\") : node;\n  });\n}\n\nexport function chartBars<TMark extends AnyChartMark>(mark: TMark, axis: \"x\" | \"y\"): TMark {\n  return withSceneNodes(mark, (nodes, renderContext) => {\n    const valueScale = renderContext.scales[axis];\n    const tagged = valueScale ? withNegativeBars(nodes, axis, valueScale.map(0)) : [...nodes];\n    return tagged.map((node) => withClass(node, `cui-chart-bar-${axis}`));\n  });\n}\n\nexport type ChartGradientKind = \"area\" | \"bar-y\" | \"bar-y-negative\" | \"bar-x\" | \"bar-x-negative\" | \"arc\";\n\ntype GradientStop = [offset: number, opacity: number, lightnessLift?: number];\n\nconst BAR_STOPS: GradientStop[] = [\n  [0, 1],\n  [1, 0.55],\n];\n\nconst GRADIENT_GEOMETRY: Record<ChartGradientKind, Omit<ChartLinearGradient, \"id\" | \"stops\"> & { stops: GradientStop[] }> = {\n  area: {\n    x1: 0,\n    y1: 0,\n    x2: 0,\n    y2: 1,\n    stops: [\n      [0, 0.5],\n      [0.6, 0.12],\n      [1, 0],\n    ],\n  },\n  \"bar-y\": { x1: 0, y1: 0, x2: 0, y2: 1, stops: BAR_STOPS },\n  \"bar-y-negative\": { x1: 0, y1: 1, x2: 0, y2: 0, stops: BAR_STOPS },\n  \"bar-x\": { x1: 1, y1: 0, x2: 0, y2: 0, stops: BAR_STOPS },\n  \"bar-x-negative\": { x1: 0, y1: 0, x2: 1, y2: 0, stops: BAR_STOPS },\n  arc: {\n    x1: 0,\n    y1: 0,\n    x2: 1,\n    y2: 1,\n    stops: [\n      [0, 1],\n      [1, 1, 0.1],\n    ],\n  },\n};\n\nexport function chartGradient(color: ChartColor, kind: ChartGradientKind): ChartLinearGradient {\n  const { stops, ...geometry } = GRADIENT_GEOMETRY[kind];\n  return {\n    ...geometry,\n    id: `cui-${kind}-${color}`,\n    stops: stops.map(([offset, opacity, lightnessLift]) => ({\n      offset,\n      opacity,\n      color: lightnessLift ? `oklch(from ${chartColor(color)} calc(l + ${lightnessLift}) c h)` : chartColor(color),\n    })),\n  };\n}\n\nexport function chartGradients(colors: Iterable<ChartColor>, kind: ChartGradientKind): ChartLinearGradient[] {\n  return [...new Set(colors)].map((color) => chartGradient(color, kind));\n}\n\nexport function chartHatch(color: ChartColor): string {\n  return `var(--_cui-chart-hatch-${color}, ${chartColor(color)})`;\n}\n\nexport function chartFillPaint(color: ChartColor, fill: ChartFill, kind: ChartGradientKind): string {\n  if (fill === \"gradient\") return `url(#cui-${kind}-${color})`;\n  if (fill === \"hatched\") return chartHatch(color);\n  return kind === \"area\" ? `oklch(from ${chartColor(color)} l c h / 0.2)` : chartColor(color);\n}\n\ntype ChartBarPaintRow = { color: ChartColor; fill: ChartFill; value: number | null };\n\nfunction barGradientKind(axis: \"x\" | \"y\", value: number | null): ChartGradientKind {\n  return value !== null && value < 0 ? `bar-${axis}-negative` : `bar-${axis}`;\n}\n\nexport function chartBarFill(row: ChartBarPaintRow, axis: \"x\" | \"y\"): string {\n  return chartFillPaint(row.color, row.fill, barGradientKind(axis, row.value));\n}\n\nexport function chartBarGradients(rows: readonly ChartBarPaintRow[], axis: \"x\" | \"y\"): ChartLinearGradient[] {\n  const gradients = new Map<string, ChartLinearGradient>();\n  for (const row of rows) {\n    if (row.fill !== \"gradient\") continue;\n    const gradient = chartGradient(row.color, barGradientKind(axis, row.value));\n    gradients.set(gradient.id, gradient);\n  }\n  return [...gradients.values()];\n}\n\nexport function chartOutline(color: ChartColor, fill: ChartFill): string {\n  return fill === \"hatched\" ? chartColor(color) : \"none\";\n}\n\nexport function quietAxis<TValue>(format: (value: TValue) => string) {\n  return { line: false, ticks: { line: false, padding: 8, format } } as const;\n}\n\nexport const quietGrid = { strokeDasharray: \"3 3\" } as const;\n\nexport const dimUnfocused = [{ when: { focus: \"unmatched\" }, style: { opacity: 0.4 } }] as const;\n\nexport type ChartReference = { value: number; label?: string; color?: ChartColor };\n\nexport function chartReferenceMarks(references: readonly ChartReference[], axis: \"x\" | \"y\", anchor: ChartXValue | undefined) {\n  if (references.length === 0) return [];\n  const paint = {\n    strokeDasharray: \"4 4\",\n    strokeOpacity: 0.7,\n    stroke: (reference: ChartReference) => chartColor(reference.color ?? \"neutral\"),\n  };\n  const labelled = references.filter((reference) => reference.label);\n  const labelPaint = {\n    text: \"label\",\n    fill: (reference: ChartReference) => chartColor(reference.color ?? \"neutral\"),\n    fontSize: 11,\n  } as const;\n  const rules = axis === \"y\" ? ruleY(references, { y: \"value\", ...paint }) : ruleX(references, { x: \"value\", ...paint });\n  const marks = [decorative(chartPart(rules, \"reference\"))];\n  if (labelled.length === 0 || anchor === undefined) return marks;\n  const labels =\n    axis === \"y\"\n      ? text(labelled, { ...labelPaint, x: () => anchor, y: \"value\", anchor: \"end\", dy: -6 })\n      : text(labelled, { ...labelPaint, x: \"value\", y: () => anchor, anchor: \"start\", dx: 6 });\n  return [...marks, decorative(labels)];\n}\n\ntype SeriesPoint = { key: string; datum: ChartSeriesRow };\n\nexport function seriesTooltip(\n  seriesLabels: readonly string[],\n  formatX: (value: ChartXValue) => string,\n  formatValue: (value: number) => string,\n) {\n  const seriesRank = (point: SeriesPoint) => seriesLabels.indexOf(point.datum.series);\n  return {\n    use: tooltip,\n    content: (points: readonly SeriesPoint[], context: ChartTooltipContentContext) => ({\n      title: points[0] ? formatX(points[0].datum.x) : undefined,\n      rows: [...points]\n        .sort((left, right) => seriesRank(left) - seriesRank(right))\n        .flatMap((point) =>\n          point.datum.value === null\n            ? []\n            : {\n                label: point.datum.series,\n                value: formatValue(point.datum.value),\n                color: chartColor(point.datum.color),\n                active: point.key === context.primaryPoint?.key,\n              },\n        ),\n    }),\n  };\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-polar.ts",
      "target": "@components/control-ui/ui/chart-polar.ts",
      "type": "registry:ui",
      "content": "import { defineChart } from \"@tanstack/charts\";\nimport { decorative } from \"@tanstack/charts/mark/decorative\";\nimport { pie, polar, radialArc, radialBarAngle } from \"@tanstack/charts/polar\";\nimport { scaleBand } from \"@tanstack/charts/scales/band\";\nimport { scaleLinear } from \"@tanstack/charts/scales/linear\";\nimport { tooltip } from \"@tanstack/charts/tooltip\";\nimport { type ChartColor, chartColor, chartSeriesColor } from \"@/components/control-ui/ui/chart-colors\";\nimport { chartFillPaint, chartGradients, chartHatch, chartOutline, dimUnfocused } from \"@/components/control-ui/ui/chart-marks\";\nimport { type ChartFill, type ChartValueKey, type ChartXKey, chartFormatters } from \"@/components/control-ui/ui/chart-series\";\n\nexport type ChartSliceOptions<TDatum> = {\n  data: readonly TDatum[];\n  label: ChartXKey<TDatum>;\n  value: ChartValueKey<TDatum>;\n  colors?: Partial<Record<string, ChartColor>>;\n  fill?: ChartFill;\n  fills?: Partial<Record<string, ChartFill>>;\n  formatValue?: (value: number) => string;\n  locale?: Intl.LocalesArgument;\n};\n\nexport type ChartSlice = { id: string; label: string; value: number; color: ChartColor; fill: ChartFill };\n\nexport function resolveChartSlices<TDatum>(options: ChartSliceOptions<TDatum>): ChartSlice[] {\n  return options.data.flatMap((datum, index) => {\n    const label: unknown = datum[options.label];\n    const value: unknown = datum[options.value];\n    if (typeof label !== \"string\" || typeof value !== \"number\" || !Number.isFinite(value) || value < 0) return [];\n    return {\n      id: label,\n      label,\n      value,\n      color: options.colors?.[label] ?? chartSeriesColor(index),\n      fill: options.fills?.[label] ?? options.fill ?? \"gradient\",\n    };\n  });\n}\n\nexport type DonutChartOptions<TDatum> = ChartSliceOptions<TDatum> & { innerRadius?: number };\n\nexport function donutChart<TDatum>(options: DonutChartOptions<TDatum>) {\n  const slices = resolveChartSlices(options);\n  const innerRadius = options.innerRadius ?? 0.62;\n  const formats = chartFormatters(options.locale);\n  const formatValue = options.formatValue ?? formats.value;\n  return defineChart({\n    marks: [\n      polar({\n        marks: [\n          radialArc(pie(slices, { value: \"value\", gapAngle: 0.025 }), {\n            key: \"label\",\n            innerRadius: ({ radius }) => radius * innerRadius,\n            cornerRadius: 4,\n            fill: (slice) => chartFillPaint(slice.color, slice.fill, \"arc\"),\n            stroke: (slice) => chartOutline(slice.color, slice.fill),\n            strokeWidth: 1,\n            className: \"cui-chart-arc\",\n            states: dimUnfocused,\n          }),\n        ],\n        scales: { angle: null, radius: null },\n        inset: 4,\n      }),\n    ],\n    scales: { x: null, y: null },\n    gradients: chartGradients(\n      slices.filter((slice) => slice.fill === \"gradient\").map((slice) => slice.color),\n      \"arc\",\n    ),\n    tooltip: {\n      use: tooltip,\n      content: (points, context) => ({\n        rows: points.map((point) => ({\n          label: point.datum.label,\n          value: `${formatValue(point.datum.value)} · ${formats.percent(point.datum.fraction)}`,\n          color: chartColor(point.datum.color),\n          active: point.key === context.primaryPoint?.key,\n        })),\n      }),\n    },\n  });\n}\n\nexport type RadialBarChartOptions<TDatum> = ChartSliceOptions<TDatum> & {\n  max?: number;\n  track?: \"hatched\" | \"solid\" | \"none\";\n};\n\nexport function radialBarChart<TDatum>(options: RadialBarChartOptions<TDatum>) {\n  const rows = resolveChartSlices(options);\n  const max = options.max ?? Math.max(1, ...rows.map((row) => row.value));\n  const track = options.track ?? \"hatched\";\n  const formatValue = options.formatValue ?? chartFormatters(options.locale).value;\n  const ringScales = () => ({\n    angle: { scale: scaleLinear().domain([0, max]) },\n    radius: {\n      scale: () => scaleBand().padding(0.3),\n      range: [({ radius }: { radius: number }) => radius * 0.4, ({ radius }: { radius: number }) => radius] as const,\n    },\n  });\n  const trackMarks =\n    track === \"none\"\n      ? []\n      : [\n          decorative(\n            polar({\n              className: \"cui-chart-radial-track\",\n              marks: [\n                radialBarAngle(rows, {\n                  id: \"track\",\n                  key: \"id\",\n                  radius: \"label\",\n                  angle: () => max,\n                  cornerRadius: \"full\",\n                  fill: track === \"hatched\" ? chartHatch(\"neutral\") : \"oklch(from var(--chart-neutral) l c h / 0.15)\",\n                }),\n              ],\n              scales: ringScales(),\n            }),\n          ),\n        ];\n  return defineChart({\n    marks: [\n      ...trackMarks,\n      polar({\n        marks: [\n          radialBarAngle(rows, {\n            id: \"value\",\n            key: \"id\",\n            radius: \"label\",\n            angle: \"value\",\n            cornerRadius: \"full\",\n            fill: (row) => chartFillPaint(row.color, row.fill, \"arc\"),\n            stroke: (row) => chartOutline(row.color, row.fill),\n            strokeWidth: 1,\n            className: \"cui-chart-radial-bar\",\n            states: dimUnfocused,\n          }),\n        ],\n        scales: ringScales(),\n      }),\n    ],\n    scales: { x: null, y: null },\n    gradients: chartGradients(\n      rows.filter((row) => row.fill === \"gradient\").map((row) => row.color),\n      \"arc\",\n    ),\n    tooltip: {\n      use: tooltip,\n      content: (points, context) => ({\n        rows: points.map((point) => ({\n          label: point.datum.label,\n          value: `${formatValue(point.datum.value)} / ${formatValue(max)}`,\n          color: chartColor(point.datum.color),\n          active: point.key === context.primaryPoint?.key,\n        })),\n      }),\n    },\n  });\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart-series.ts",
      "target": "@components/control-ui/ui/chart-series.ts",
      "type": "registry:ui",
      "content": "import type { ChartPositionScaleOptions } from \"@tanstack/charts\";\nimport { scaleBand } from \"@tanstack/charts/scales/band\";\nimport { scaleLinear } from \"@tanstack/charts/scales/linear\";\nimport { scalePoint } from \"@tanstack/charts/scales/point\";\nimport { type ChartColor, chartSeriesColor } from \"@/components/control-ui/ui/chart-colors\";\n\nexport type ChartFill = \"gradient\" | \"hatched\" | \"solid\";\n\nexport type ChartXValue = string | number | Date;\n\nexport type ChartXKey<TDatum> = { [K in keyof TDatum]-?: TDatum[K] extends ChartXValue ? K : never }[keyof TDatum] & keyof TDatum & string;\n\nexport type ChartValueKey<TDatum> = {\n  [K in keyof TDatum]-?: TDatum[K] extends number | null | undefined ? K : never;\n}[keyof TDatum] &\n  keyof TDatum &\n  string;\n\nexport type ChartSeries<TDatum> = {\n  key: ChartValueKey<TDatum>;\n  label?: string;\n  color?: ChartColor;\n  fill?: ChartFill;\n  dashed?: boolean;\n};\n\nexport type ResolvedChartSeries<TDatum> = Required<ChartSeries<TDatum>>;\n\nexport type ChartSeriesRow = {\n  id: string;\n  x: ChartXValue;\n  value: number | null;\n  series: string;\n  color: ChartColor;\n  fill: ChartFill;\n};\n\nexport function resolveChartSeries<TDatum>(\n  series: readonly ChartSeries<TDatum>[],\n  fill: ChartFill = \"gradient\",\n): ResolvedChartSeries<TDatum>[] {\n  return series.map((entry, index) => ({\n    key: entry.key,\n    label: entry.label ?? entry.key,\n    color: entry.color ?? chartSeriesColor(index),\n    fill: entry.fill ?? fill,\n    dashed: entry.dashed ?? false,\n  }));\n}\n\nfunction isChartXValue(value: unknown): value is ChartXValue {\n  return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value)) || value instanceof Date;\n}\n\nexport function chartSeriesRows<TDatum>(\n  data: readonly TDatum[],\n  x: ChartXKey<TDatum>,\n  series: readonly ResolvedChartSeries<TDatum>[],\n): ChartSeriesRow[] {\n  return series.flatMap((entry) =>\n    data.flatMap((datum) => {\n      const xValue: unknown = datum[x];\n      if (!isChartXValue(xValue)) return [];\n      const value: unknown = datum[entry.key];\n      return {\n        id: `${entry.key}:${xValue instanceof Date ? xValue.toISOString() : String(xValue)}`,\n        x: xValue,\n        value: typeof value === \"number\" && Number.isFinite(value) ? value : null,\n        series: entry.label,\n        color: entry.color,\n        fill: entry.fill,\n      };\n    }),\n  );\n}\n\nexport type ChartFormatters = {\n  x: (value: ChartXValue) => string;\n  value: (value: number) => string;\n  tick: (value: number) => string;\n  percent: (value: number) => string;\n};\n\nexport function chartFormatters(locale: Intl.LocalesArgument = \"en-US\"): ChartFormatters {\n  const plainNumber = new Intl.NumberFormat(locale);\n  const compactNumber = new Intl.NumberFormat(locale, { notation: \"compact\" });\n  const percentNumber = new Intl.NumberFormat(locale, { style: \"percent\" });\n  const shortDay = new Intl.DateTimeFormat(locale, { month: \"short\", day: \"numeric\", timeZone: \"UTC\" });\n  return {\n    x: (value) => {\n      if (value instanceof Date) return shortDay.format(value);\n      if (typeof value === \"number\") return plainNumber.format(value);\n      return value;\n    },\n    value: (value) => plainNumber.format(value),\n    tick: (value) => compactNumber.format(value),\n    percent: (value) => percentNumber.format(value),\n  };\n}\n\nexport function chartXScale(\n  rows: readonly { x: ChartXValue }[],\n  kind: \"point\" | \"band\",\n  override?: Partial<ChartPositionScaleOptions>,\n): ChartPositionScaleOptions {\n  if (override?.scale) return { ...override, scale: override.scale };\n  const first = rows[0]?.x;\n  if (first instanceof Date) {\n    throw new Error(\"Chart presets need an xScale for Date x values, for example { scale: scaleUtc } from d3-scale.\");\n  }\n  if (typeof first === \"number\") return { scale: scaleLinear, nice: true, ...override };\n  return { scale: kind === \"band\" ? () => scaleBand().padding(0.3) : scalePoint, ...override };\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/chart.tsx",
      "target": "@components/control-ui/ui/chart.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport type { ChartTooltipContent, ChartValue } from \"@tanstack/charts\";\nimport {\n  type ChartTooltipBodyRenderContext,\n  Chart as TanStackChart,\n  type ChartProps as TanStackChartProps,\n} from \"@tanstack/charts/react/tooltip\";\nimport { type ComponentProps, type CSSProperties, type ReactNode, useEffect, useId, useRef } from \"react\";\nimport type { ChartKnobStyle } from \"@/components/control-ui/knob-contracts/chart-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { readDurationMs } from \"@/components/control-ui/lib/motion\";\nimport { CHART_COLORS, type ChartColor, chartColor } from \"@/components/control-ui/ui/chart-colors\";\nimport type { ChartFill } from \"@/components/control-ui/ui/chart-series\";\n\nconst NON_ID_CHARACTERS = /[^\\w-]/g;\n\ntype ChartStyle = CSSProperties & ChartKnobStyle;\n\nexport type ChartRootProps = Omit<ComponentProps<\"div\">, \"style\"> & { style?: ChartStyle };\n\nexport function Chart({ className, style, ...props }: ChartRootProps) {\n  return <div data-control-ui=\"chart\" data-control-family=\"chart\" data-slot=\"root\" className={cn(className)} style={style} {...props} />;\n}\n\nexport type ChartPlotProps<TDatum, TXValue extends ChartValue = ChartValue, TYValue extends ChartValue = ChartValue> = Omit<\n  TanStackChartProps<TDatum, TXValue, TYValue>,\n  \"style\" | \"className\"\n> & {\n  className?: string;\n  style?: ChartStyle;\n  children?: ReactNode;\n};\n\ntype ChartPatternStyle = Record<`--_cui-chart-hatch-${ChartColor}` | \"--_cui-chart-fade\", string>;\n\ntype ChartSwatchStyle = CSSProperties & { \"--_cui-chart-swatch\": string };\n\nfunction chartPatternStyle(id: string): ChartPatternStyle {\n  return {\n    \"--_cui-chart-hatch-blue\": `url(#${id}-hatch-blue)`,\n    \"--_cui-chart-hatch-purple\": `url(#${id}-hatch-purple)`,\n    \"--_cui-chart-hatch-pink\": `url(#${id}-hatch-pink)`,\n    \"--_cui-chart-hatch-orange\": `url(#${id}-hatch-orange)`,\n    \"--_cui-chart-hatch-green\": `url(#${id}-hatch-green)`,\n    \"--_cui-chart-hatch-yellow\": `url(#${id}-hatch-yellow)`,\n    \"--_cui-chart-hatch-red\": `url(#${id}-hatch-red)`,\n    \"--_cui-chart-hatch-neutral\": `url(#${id}-hatch-neutral)`,\n    \"--_cui-chart-fade\": `url(#${id}-fade)`,\n  };\n}\n\nfunction ChartPatterns({ id }: { id: string }) {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      focusable=\"false\"\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"patterns\"\n      width=\"0\"\n      height=\"0\"\n      className=\"absolute size-0 overflow-hidden\"\n    >\n      <defs>\n        {CHART_COLORS.map((color) => (\n          <pattern key={color} id={`${id}-hatch-${color}`} patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" patternTransform=\"rotate(45)\">\n            <rect\n              data-control-ui=\"chart\"\n              data-control-family=\"chart\"\n              data-slot=\"hatch-tint\"\n              width=\"6\"\n              height=\"6\"\n              fill={chartColor(color)}\n            />\n            <rect\n              data-control-ui=\"chart\"\n              data-control-family=\"chart\"\n              data-slot=\"hatch-stripe\"\n              width=\"2\"\n              height=\"6\"\n              fill={chartColor(color)}\n            />\n          </pattern>\n        ))}\n        <linearGradient id={`${id}-fade-gradient`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"oklch(1 0 0)\" />\n          <stop offset=\"1\" stopColor=\"oklch(1 0 0)\" stopOpacity=\"0.15\" />\n        </linearGradient>\n        <mask id={`${id}-fade`} maskContentUnits=\"objectBoundingBox\">\n          <rect width=\"1\" height=\"1\" fill={`url(#${id}-fade-gradient)`} />\n        </mask>\n      </defs>\n    </svg>\n  );\n}\n\nfunction renderChartTooltipBody<TDatum, TXValue extends ChartValue, TYValue extends ChartValue>(\n  context: ChartTooltipBodyRenderContext<TDatum, TXValue, TYValue>,\n) {\n  return <ChartTooltipBody content={context.content} />;\n}\n\nexport function ChartPlot<TDatum, TXValue extends ChartValue = ChartValue, TYValue extends ChartValue = ChartValue>({\n  className,\n  style,\n  children,\n  ...props\n}: ChartPlotProps<TDatum, TXValue, TYValue>) {\n  const patternId = `cui-chart-${useId().replace(NON_ID_CHARACTERS, \"\")}`;\n  const plotRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    const node = plotRef.current;\n    if (!node) return;\n    let settleTimer: number | undefined;\n    const observer = new ResizeObserver(() => {\n      node.dataset.resizing = \"\";\n      clearTimeout(settleTimer);\n      settleTimer = window.setTimeout(\n        () => {\n          delete node.dataset.resizing;\n        },\n        readDurationMs(node, \"--duration-fast\"),\n      );\n    });\n    observer.observe(node);\n    return () => {\n      observer.disconnect();\n      clearTimeout(settleTimer);\n    };\n  }, []);\n\n  useEffect(() => {\n    const node = plotRef.current;\n    if (!node) return;\n    let enterTimer: number | undefined;\n    const observer = new MutationObserver((records) => {\n      const tooltipShown = records.some(\n        (record) =>\n          record.oldValue !== null &&\n          record.target instanceof HTMLElement &&\n          record.target.classList.contains(\"ts-chart-tooltip\") &&\n          !record.target.hidden,\n      );\n      if (!tooltipShown) return;\n      node.dataset.tooltipEntering = \"\";\n      clearTimeout(enterTimer);\n      enterTimer = window.setTimeout(\n        () => {\n          delete node.dataset.tooltipEntering;\n        },\n        readDurationMs(node, \"--duration-fast\"),\n      );\n    });\n    observer.observe(node, { subtree: true, attributeFilter: [\"hidden\"], attributeOldValue: true });\n    return () => {\n      observer.disconnect();\n      clearTimeout(enterTimer);\n    };\n  }, []);\n\n  return (\n    <div\n      ref={plotRef}\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"plot\"\n      data-focus-ring=\"within\"\n      className={cn(className)}\n      style={{ ...chartPatternStyle(patternId), ...style }}\n    >\n      <ChartPatterns id={patternId} />\n      <TanStackChart renderTooltipBody={renderChartTooltipBody} {...props} />\n      {children}\n    </div>\n  );\n}\n\nexport function ChartCenter({ className, ...props }: ComponentProps<\"div\">) {\n  return (\n    <div\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"center\"\n      className={cn(\"pointer-events-none absolute inset-0 grid place-content-center text-center\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ChartLegend({ className, ...props }: ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"legend\"\n      className={cn(\"text-label text-muted-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\nexport type ChartLegendItemProps = Omit<ComponentProps<\"li\">, \"color\"> & {\n  color: ChartColor;\n  fill?: ChartFill;\n  hidden?: boolean;\n  onHiddenChange?: (hidden: boolean) => void;\n};\n\nfunction ChartSwatch({ color }: { color: string }) {\n  const style: ChartSwatchStyle = { \"--_cui-chart-swatch\": color };\n  return <span aria-hidden=\"true\" data-control-ui=\"chart\" data-control-family=\"chart\" data-slot=\"swatch\" style={style} />;\n}\n\nexport function ChartLegendItem({\n  color,\n  fill = \"solid\",\n  hidden = false,\n  onHiddenChange,\n  children,\n  className,\n  style,\n  ...props\n}: ChartLegendItemProps) {\n  const legendStyle: ChartSwatchStyle = { \"--_cui-chart-swatch\": chartColor(color), ...style };\n  const content = (\n    <>\n      <span aria-hidden=\"true\" data-control-ui=\"chart\" data-control-family=\"chart\" data-slot=\"swatch\" />\n      {children}\n    </>\n  );\n  return (\n    <li\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"legend-item\"\n      data-fill={fill}\n      data-hidden={hidden ? \"true\" : undefined}\n      className={cn(className)}\n      style={legendStyle}\n      {...props}\n    >\n      {onHiddenChange ? (\n        <button\n          type=\"button\"\n          data-control-ui=\"chart\"\n          data-control-family=\"chart\"\n          data-slot=\"legend-toggle\"\n          aria-pressed={!hidden}\n          onClick={() => onHiddenChange(!hidden)}\n        >\n          {content}\n        </button>\n      ) : (\n        <span className=\"inline-flex items-center gap-1.5\">{content}</span>\n      )}\n    </li>\n  );\n}\n\nexport type ChartTooltipBodyProps = Omit<ComponentProps<\"div\">, \"content\"> & { content: string | ChartTooltipContent };\n\nexport function ChartTooltipBody({ content, className, ...props }: ChartTooltipBodyProps) {\n  return (\n    <div\n      data-control-ui=\"chart\"\n      data-control-family=\"chart\"\n      data-slot=\"tooltip\"\n      className={cn(\"grid min-w-32 gap-1.5\", className)}\n      {...props}\n    >\n      {typeof content === \"string\" ? (\n        <p className=\"text-label\">{content}</p>\n      ) : (\n        <>\n          {content.title ? (\n            <p data-control-ui=\"chart\" data-control-family=\"chart\" data-slot=\"tooltip-title\" className=\"font-medium text-label\">\n              {content.title}\n            </p>\n          ) : null}\n          {content.rows.map((row) => (\n            <div\n              key={row.label}\n              data-control-ui=\"chart\"\n              data-control-family=\"chart\"\n              data-slot=\"tooltip-row\"\n              data-active={row.active ? \"true\" : undefined}\n              className=\"flex items-center gap-2 text-label\"\n            >\n              <ChartSwatch color={row.color ?? \"currentColor\"} />\n              <span className={row.active ? undefined : \"text-muted-foreground\"}>{row.label}</span>\n              <span className=\"ms-auto font-medium tabular-nums\">{row.value}</span>\n            </div>\n          ))}\n        </>\n      )}\n    </div>\n  );\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/chart.css\"": {}
  }
}
