{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart-stat-flow",
  "type": "registry:component",
  "title": "Chart Stat Flow",
  "description": "Animated stat value and label for chart overlays",
  "dependencies": [
    "@number-flow/react",
    "motion"
  ],
  "registryDependencies": [
    "@bklit/utils"
  ],
  "files": [
    {
      "path": "src/charts/chart-stat-flow.tsx",
      "content": "\"use client\";\n\nimport NumberFlow from \"@number-flow/react\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n/** Subset of `Intl.NumberFormatOptions` supported by NumberFlow */\nexport interface ChartStatFlowFormat {\n  notation?: \"standard\" | \"compact\";\n  compactDisplay?: \"short\" | \"long\";\n  minimumFractionDigits?: number;\n  maximumFractionDigits?: number;\n  minimumIntegerDigits?: number;\n  minimumSignificantDigits?: number;\n  maximumSignificantDigits?: number;\n  style?: \"decimal\" | \"percent\" | \"currency\";\n  currency?: string;\n  currencyDisplay?: \"symbol\" | \"narrowSymbol\" | \"code\" | \"name\";\n  unit?: string;\n  unitDisplay?: \"short\" | \"long\" | \"narrow\";\n}\n\nexport const defaultChartStatFlowFormat: ChartStatFlowFormat = {\n  notation: \"standard\",\n  maximumFractionDigits: 0,\n};\n\nfunction formatStatValue(\n  value: number,\n  formatOptions: ChartStatFlowFormat,\n  prefix?: string,\n  suffix?: string\n): string {\n  const formatted = new Intl.NumberFormat(undefined, formatOptions).format(\n    value\n  );\n  return `${prefix ?? \"\"}${formatted}${suffix ?? \"\"}`;\n}\n\nfunction useNumberFlowElementReady(): boolean {\n  const [ready, setReady] = useState(\n    () =>\n      typeof customElements !== \"undefined\" &&\n      Boolean(customElements.get(\"number-flow-react\"))\n  );\n\n  useEffect(() => {\n    if (ready) {\n      return;\n    }\n    let cancelled = false;\n    customElements.whenDefined(\"number-flow-react\").then(() => {\n      if (!cancelled) {\n        setReady(true);\n      }\n    });\n    return () => {\n      cancelled = true;\n    };\n  }, [ready]);\n\n  return ready;\n}\n\nexport interface ChartStatFlowProps {\n  value: number;\n  label: string;\n  formatOptions?: ChartStatFlowFormat;\n  prefix?: string;\n  suffix?: string;\n  valueClassName?: string;\n  labelClassName?: string;\n  icon?: ReactNode;\n}\n\n/**\n * Shared value + label stack using NumberFlow (same layout as pie / ring centers).\n * Parent should provide flex alignment and sizing when needed.\n */\nexport function ChartStatFlow({\n  value,\n  label,\n  formatOptions = defaultChartStatFlowFormat,\n  prefix,\n  suffix,\n  valueClassName = \"text-2xl font-bold\",\n  labelClassName = \"text-xs\",\n  icon,\n}: ChartStatFlowProps) {\n  const numberFlowReady = useNumberFlowElementReady();\n  const staticValue = useMemo(\n    () => formatStatValue(value, formatOptions, prefix, suffix),\n    [value, formatOptions, prefix, suffix]\n  );\n\n  return (\n    <>\n      {icon ? (\n        <div className=\"mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-muted/50\">\n          {icon}\n        </div>\n      ) : null}\n      <span className={cn(\"text-foreground tabular-nums\", valueClassName)}>\n        {numberFlowReady ? (\n          <NumberFlow\n            format={formatOptions}\n            isolate\n            prefix={prefix}\n            suffix={suffix}\n            value={value}\n            willChange\n          />\n        ) : (\n          staticValue\n        )}\n      </span>\n      <span className={cn(\"mt-0.5 text-chart-label\", labelClassName)}>\n        {label}\n      </span>\n    </>\n  );\n}\n\nChartStatFlow.displayName = \"ChartStatFlow\";\n",
      "type": "registry:component",
      "target": "components/charts/chart-stat-flow.tsx"
    }
  ]
}