import React from 'react'; import type { ColorToken } from '../../shared/color-token'; import { type ForceSettings } from './force-simulation'; import type { GraphEdge, GraphFeatureRef, GraphLabelMode, GraphLayout, GraphNode } from './graph.types'; /** Imperative handle, exposed through `controlRef`. */ export interface NetworkGraphControl { /** Frames every node. */ fitView(): void; /** Frames one node and selects it. */ focusNode(id: string): void; resetCamera(): void; /** Re-runs the layout from the current positions. */ restartLayout(): void; /** Current node positions, for persisting a hand-arranged diagram. */ getPositions(): Record; } export interface NetworkGraphProps extends Omit, 'onSelect'> { nodes: GraphNode[]; edges: GraphEdge[]; /** @default '3d' */ layout?: GraphLayout; /** @default '480px' */ height?: string; /** Controlled selection. */ selectedId?: string | null; onSelect?: (id: string | null, feature: GraphFeatureRef | null) => void; onHover?: (id: string | null, feature: GraphFeatureRef | null) => void; /** * Dims everything outside the selected node's immediate neighbourhood. * The only practical way to read a dense ontology. * @default 'neighbors' */ focusMode?: 'neighbors' | 'none'; /** @default 'auto' — labels appear once a node is large enough on screen. */ labels?: GraphLabelMode; /** Draws arrowheads on every edge that does not say otherwise. @default false */ directed?: boolean; /** Base radius in layout units. @default 6 */ nodeRadius?: number; /** * Ceiling on the largest node's on-screen radius, in pixels. * * Radii are in layout units, so a sparse graph framed to fill the canvas would * otherwise draw discs big enough to swallow the edges between them. One * factor is applied to every node, so relative weight survives the cap. * @default 11 */ maxNodeRadiusPx?: number; /** * Frames the whole graph once the layout settles, unless the viewer has * already moved the camera. @default true */ autoFit?: boolean; /** Overrides for the physics. */ physics?: ForceSettings; /** Slowly rotates while the pointer is away. Suppressed under reduced motion. */ autoRotate?: boolean; /** Colors assigned to node/relation types, in order of first appearance. */ typeTokens?: ColorToken[]; /** @default "Relationship graph" */ ariaLabel?: string; /** Fires once the layout comes to rest. */ onLayoutSettled?: () => void; controlRef?: React.Ref; /** Replaces the built-in empty state. */ emptyState?: React.ReactNode; /** @default "No nodes to display" */ emptyLabel?: string; } /** * Three-dimensional graph for ontologies and any information with relationships. * * @description * A force-directed layout rendered to a canvas: Barnes-Hut repulsion, springs * along the edges, and a perspective projection with depth cueing. Nothing is * pulled in to do it — a graph draws discs and lines, so the WebGL a 3D library * provides would replace the easy half and leave the layout, which has to be * written either way. * * The layout is deterministic: the same graph always arranges the same way, so * "the node on the left" keeps meaning something between sessions. * * @ai-rules * 1. Give every node a stable `id` — selection, focus and layout seeding all key off it. * 2. Use `type` on nodes and `relation` on edges rather than per-item colors; the palette and legend follow from them. * 3. Pair it with `` — a canvas is not reachable by screen reader on its own. * 4. Keep `focusMode="neighbors"` for anything denser than a few dozen nodes. */ export declare const NetworkGraph: React.ForwardRefExoticComponent>;