{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "metric-cluster",
  "type": "registry:component",
  "title": "Metric Cluster",
  "description": "Compact stack of related metrics pinned to a canvas object's corner.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/metric-cluster/metric-cluster.tsx",
      "content": "\"use client\";\n\nimport {\n  type ComponentPropsWithoutRef,\n  forwardRef,\n  type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\n\n/**\n * Tone of a single metric line — drives the dot color.\n *\n * @public\n */\nexport type MetricClusterTone = \"danger\" | \"neutral\" | \"success\" | \"warn\";\n\nconst TONE_DOT: Record<MetricClusterTone, string> = {\n  danger: \"bg-red-500\",\n  neutral: \"bg-muted-foreground\",\n  success: \"bg-emerald-500\",\n  warn: \"bg-amber-500\",\n};\n\n/**\n * Anchor corner relative to the canvas object the cluster attaches to.\n *\n * @public\n */\nexport type MetricClusterAnchor =\n  | \"bottom-left\"\n  | \"bottom-right\"\n  | \"top-left\"\n  | \"top-right\";\n\nconst ANCHOR_TRANSFORM: Record<MetricClusterAnchor, string> = {\n  \"bottom-left\": \"translate(-100%, 100%)\",\n  \"bottom-right\": \"translate(0%, 100%)\",\n  \"top-left\": \"translate(-100%, -100%)\",\n  \"top-right\": \"translate(0%, -100%)\",\n};\n\n/**\n * One metric in the cluster.\n *\n * @public\n */\nexport type MetricClusterEntry = {\n  /** Stable identifier — used as the React key + analytics hook. */\n  id: string;\n  /** Short label (e.g. `\"errs/min\"`). */\n  label: ReactNode;\n  /** Optional tone for the leading dot. Defaults to `\"neutral\"`. */\n  tone?: MetricClusterTone;\n  /** Display value (already formatted by host). */\n  value: ReactNode;\n};\n\n/**\n * Localizable strings.\n *\n * @public\n */\nexport type MetricClusterLabels = {\n  /** Aria-label override. Defaults to `\"Metric cluster\"`. */\n  region?: string;\n};\n\nconst DEFAULT_LABELS = {\n  region: \"Metric cluster\",\n} as const satisfies Required<MetricClusterLabels>;\n\n/**\n * Props for {@link MetricCluster}.\n *\n * @public\n */\nexport type MetricClusterProps = {\n  /** Anchor corner. Defaults to `\"top-right\"`. */\n  anchor?: MetricClusterAnchor;\n  /** Localizable strings. */\n  labels?: MetricClusterLabels;\n  /** Metric entries in render order. */\n  metrics: MetricClusterEntry[];\n  /** Optional cluster title rendered above the rows. */\n  title?: ReactNode;\n  /** Anchor X in canvas pixels. */\n  x: number;\n  /** Anchor Y in canvas pixels. */\n  y: number;\n} & ComponentPropsWithoutRef<\"div\">;\n\nconst Row = (props: { entry: MetricClusterEntry }): React.ReactElement => {\n  const { entry } = props;\n  const tone = entry.tone ?? \"neutral\";\n  return (\n    <li\n      className=\"flex items-center justify-between gap-2 text-[11px]\"\n      data-metric-cluster-row={entry.id}\n      data-metric-cluster-tone={tone}\n    >\n      <span className=\"flex items-center gap-1.5 text-muted-foreground\">\n        <span\n          aria-hidden=\"true\"\n          className={cn(\"size-1.5 rounded-full\", TONE_DOT[tone])}\n        />\n        {entry.label}\n      </span>\n      <span className=\"font-semibold text-foreground\">{entry.value}</span>\n    </li>\n  );\n};\n\n/**\n * Compact stack of related metrics pinned to a canvas object's corner.\n * Use when a single `StickyMetric` doesn't carry enough signal — for\n * runs whose throughput, latency, and error rate must all be visible\n * at once. Pure presentation; the host supplies the anchor coords + the\n * metric list.\n *\n * The wrapper is `pointer-events: none` — host gestures pass through.\n *\n * @example\n * ```tsx\n * <MetricCluster\n *   x={420} y={180}\n *   anchor=\"top-right\"\n *   title=\"research-2025\"\n *   metrics={[\n *     { id: \"qps\",  label: \"qps\",   value: \"240\", tone: \"success\" },\n *     { id: \"errs\", label: \"errs\",  value: \"14\",  tone: \"danger\" },\n *     { id: \"p95\",  label: \"p95\",   value: \"180ms\" },\n *   ]}\n * />\n * ```\n *\n * @public\n */\nexport const MetricCluster = forwardRef<HTMLDivElement, MetricClusterProps>(\n  (props, ref) => {\n    const {\n      anchor = \"top-right\",\n      className,\n      labels,\n      metrics,\n      title,\n      x,\n      y,\n      ...rest\n    } = props;\n    const resolvedLabels = { ...DEFAULT_LABELS, ...labels };\n    return (\n      <div\n        aria-label={resolvedLabels.region}\n        className={cn(\n          \"pointer-events-none absolute z-20 flex flex-col gap-1 rounded-md border border-border bg-background/90 p-2 shadow-sm backdrop-blur\",\n          className,\n        )}\n        data-metric-cluster\n        data-metric-cluster-anchor={anchor}\n        ref={ref}\n        role=\"status\"\n        style={{\n          left: x,\n          top: y,\n          transform: ANCHOR_TRANSFORM[anchor],\n        }}\n        {...rest}\n      >\n        {title ? (\n          <header\n            className=\"text-[10px] font-medium uppercase tracking-wide text-muted-foreground\"\n            data-metric-cluster-title\n          >\n            {title}\n          </header>\n        ) : null}\n        <ul className=\"space-y-0.5\">\n          {metrics.map((entry) => (\n            <Row entry={entry} key={entry.id} />\n          ))}\n        </ul>\n      </div>\n    );\n  },\n);\nMetricCluster.displayName = \"MetricCluster\";\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
