{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "metric-cluster",
  "title": "Metric Cluster",
  "description": "Compact stack of related metrics pinned to a canvas object's corner.",
  "dependencies": [
    "@vllnt/ui@^0.3.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/metric-cluster/metric-cluster.tsx",
      "content": "\"use client\";\n\nimport type { ComponentPropsWithoutRef, ReactNode } 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 = ({\n  ref,\n  ...props\n}: MetricClusterProps & { ref?: React.Ref<HTMLDivElement> }) => {\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};\nMetricCluster.displayName = \"MetricCluster\";\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component",
  "version": "0.3.0",
  "stability": "stable"
}
