# React Networks - API Reference (Embedded) This file documents the full public API of the `@mp70/react-networks` package (packages/network-diagrams). All components, utilities, types, and constants listed are exported from that package. # API Reference ## Components ### DiagramErrorBoundary Error boundary that catches errors in the diagram tree (e.g. React Flow, custom nodes) and renders a fallback instead of crashing the app. Wrap with this for production. ```tsx import { DiagramErrorBoundary } from '@mp70/react-networks'; ``` #### Props (DiagramErrorBoundaryProps) | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `ReactNode` | - | Content to render (e.g. NetworkDiagram) | | `fallback` | `ReactNode \| (error: Error, reset: () => void) => ReactNode` | - | Optional fallback UI when an error occurs | | `onError` | `(error: Error, errorInfo: ErrorInfo) => void` | - | Optional callback when an error is caught (e.g. for logging) | #### Example ```tsx (

Diagram failed: {error.message}

)} onError={(err, info) => logToService(err, info)} >
``` ### NetworkDiagram The main component for rendering interactive network diagrams. ```tsx import { NetworkDiagram } from '@mp70/react-networks'; ``` #### Props (NetworkDiagramProps) | Prop | Type | Default | Description | |------|------|---------|-------------| | `nodes` | `NetworkNode[]` | `[]` | Controlled nodes array | | `edges` | `NetworkEdge[]` | `[]` | Controlled edges array | | `onNodesChange` | `(nodes: NetworkNode[]) => void` | - | Callback when nodes change (controlled mode) | | `onEdgesChange` | `(edges: NetworkEdge[]) => void` | - | Callback when edges change (controlled mode) | | `initialNodes` | `NetworkNode[]` | `[]` | Initial nodes for uncontrolled mode | | `initialEdges` | `NetworkEdge[]` | `[]` | Initial edges for uncontrolled mode | | `store` | `any` | - | Headless store injection | | `debug` | `boolean` | `false` | Enable debug mode | | `onNodeClick` | `(node: NetworkNode \| null) => void` | - | Callback when a node is clicked or selection changes (null when deselected) | | `onEdgeClick` | `(edge: NetworkEdge) => void` | - | Callback when an edge is clicked | | `nodeTypes` | `NodeTypes` | - | Custom React Flow node types to merge with defaults | | `edgeTypes` | `EdgeTypes` | - | Custom React Flow edge types to merge with defaults | | `onConnect` | `(connection: Connection) => void` | - | Optional onConnect override (React Flow connection handler) | | `onEdgeUpdate` | `(oldEdge: Edge, newConnection: Connection) => void` | - | Optional onEdgeUpdate override | | `isValidConnection` | `(connection: Connection) => boolean` | - | Optional isValidConnection override | | `connectionMode` | `ConnectionMode` | - | Optional connection mode override | | `onViewChange` | `(nodeId: string, view: DeviceView) => void` | - | Callback when device view changes | | `onRackFaceChange` | `(rackId: string, face: DeviceView) => void` | - | Callback when rack face changes | | `className` | `string` | - | CSS class name | | `style` | `React.CSSProperties` | - | Inline styles | | `alignRacksToBottom` | `boolean` | `false` | If true, vertically align rack bottoms to the same baseline | | `colorMode` | `'light' \| 'dark' \| 'system'` | - | Color mode for the diagram | | `onInit` | `(instance: any) => void` | - | Callback when React Flow instance is initialized | | `onFlowMethods` | `(methods: { toObject, setViewport, setNodes, setEdges, toImage, getNodes, getEdges, fitView }) => void` | - | Callback to get React Flow methods for save/restore | | `showDownloadButton` | `boolean` | - | Show download button | | `downloadButtonPosition` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | - | Download button position | | `downloadButtonText` | `string` | - | Custom download button text | | `downloadButtonStyle` | `React.CSSProperties` | - | Download button styling options | | `useSmoothstepEdgesForTubes` | `boolean` | - | Use smoothstep edges for tube connections. Default is fiber. | | `connectOnClick` | `boolean` | `true` | Enable connecting edges by clicking on handles. When true, increases handle sizes. | | `panOnDrag` | `boolean` | `false` | Disable panning on drag when false. | | `panOnScroll` | `boolean` | `true` | Disable panning on scroll when false. | | `zoomOnScroll` | `boolean` | `true` | Disable zooming on scroll when false. | | `fitViewOptions` | `FitViewOptions` | - | Optional fitView options passed to React Flow | #### Example ```tsx console.log('Node clicked:', node)} onEdgeClick={(edge) => console.log('Edge clicked:', edge)} onViewChange={(nodeId, view) => console.log(`Node ${nodeId} view: ${view}`)} onRackFaceChange={(rackId, face) => console.log(`Rack ${rackId} face: ${face}`)} /> ``` ### RackNode Rack visualization component with U positioning support. Used as a React Flow node type; props come from React Flow NodeProps. Documented here is the node **data** shape. ```tsx import { RackNode } from '@mp70/react-networks'; ``` RackNode receives React Flow NodeProps; the main configuration is in **node.data** (see table below). View/face callbacks are provided by NetworkDiagram. #### Node data (RackNodeData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | Rack display label | | `uHeight` | `number` | - | Rack height in U units | | `view` | `'front' \| 'rear'` | - | Current face (front or rear) | | `uNumberingDirection` | `'bottom-up' \| 'top-down'` | - | U numbering direction | | `customHeaderText` | `string` | - | Custom header text for rack | | `rackWidthPx` | `number` | - | Optional rack width in pixels (default from constants) | ### DeviceNode Device visualization component with port management. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { DeviceNode } from '@mp70/react-networks'; ``` #### Node data (DeviceNodeData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | Device display label | | `ports` | `PortBlock[]` | - | Front port blocks | | `rearPorts` | `PortBlock[]` | - | Rear port blocks | | `view` | `'front' \| 'rear'` | - | Current view | | `uPosition` | `number` | - | U position within rack | | `width` | `Width` | - | Full or half width | | `powerSide` | `'left' \| 'right'` | - | Power port side for rear view | | `status` | `'active' \| 'inactive' \| 'maintenance'` | - | Device status | | `frontImageUrl` | `string` | - | Optional front background image URL | | `rearImageUrl` | `string` | - | Optional rear background image URL | | `frontImageAttribution` | `string` | - | Optional attribution URL for front image | | `rearImageAttribution` | `string` | - | Optional attribution URL for rear image | | `imageFit` | `'cover' \| 'contain' \| 'fill' \| 'none' \| 'scale-down'` | - | Background image sizing | | `imagePosition` | `string` | - | Background position | | `imageRepeat` | `string` | - | Background repeat | | `stretchToFit` | `boolean` | - | When true, stretch device image to fill bounds | ### FiberNode Fiber connection point component. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { FiberNode } from '@mp70/react-networks'; ``` #### Node data (FiberNodeData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | Fiber node label | | `status` | `'active' \| 'inactive' \| 'maintenance'` | `'active'` | Status for border/indicator color | | `type` | `'single-mode' \| 'multi-mode'` | - | Fiber type (if used) | | `connections` | `string[]` | - | Connected node IDs (if used) | ### FiberEdge Renders a fiber edge (single-fiber or ribbon). Used as a React Flow edge type; configuration is in **edge.data**. ```tsx import { FiberEdge } from '@mp70/react-networks'; ``` #### Edge data (NetworkEdge.data for type 'fiber') | Field | Type | Default | Description | |-------|------|---------|-------------| | `color` | `string` | - | Edge stroke color | | `fiberId` | `number` | - | Single fiber ID (1-24) for traditional edges | | `ribbonFiberIds` | `number[]` | - | Array of fiber IDs (6-12) for ribbon edges; when present edge is ribbon | | `isRibbon` | `boolean` | - | Convenience flag for ribbon fiber edge | | `highlight` | `boolean` | - | Highlight edge with pulsing stroke | | `highlightColor` | `string` | - | Override highlight color | | `highlightWidth` | `number` | - | Override highlight max stroke width | | `bandwidth` | `string` | - | Optional label | | `length` | `number` | - | Cable length | | `kind` | `'fiber' \| 'power' \| 'network'` | - | Edge kind | ### PowerEdge Renders a power cable edge (C13/C19 styling). Used as a React Flow edge type; configuration is in **edge.data**. ```tsx import { PowerEdge } from '@mp70/react-networks'; ``` #### Edge data (NetworkEdge.data for type 'power') | Field | Type | Default | Description | |-------|------|---------|-------------| | `connectorType` | `'C13' \| 'C19'` | `'C13'` | Connector type (C19 = thicker solid line, C13 = dashed) | | `color` | `string` | - | Edge stroke color (default amber) | ### TubeNode Tube node representing a buffer tube with fiber handles. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { TubeNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `fibersPerTube` | `number` | `12` | Number of fibers (1-24) | | `tubeIndex` | `number` | `1` | Tube index for TIA-598 color (1-12 cycle) | | `startOn` | `'left-center' \| 'left' \| 'right'` | `'left-center'` | Handle layout: left-center = handles on top/bottom, left/right = side handles | | `mode` | `'ribbon'` | - | Set for ribbon mode | | `ribbon` | `boolean` | - | Alternative flag for ribbon mode | ### CableNode Multi-fiber cable node (1-24 fibers) with colored handles. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { CableNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `fiberCount` | `number` | `12` | Number of fibers (1-24) | | `cableId` | `string` | `'CBL-002'` | Cable identifier for label | | `label` | `string` | - | Primary label (default: e.g. "12f Cable") | | `color` | `string` | - | Cable border/handle color | | `rotation` | `number` | `0` | Rotation in degrees (0 = top, 90 = right, etc.) | ### MultiTubeCableNode Multi-tube cable node (1-24 tubes). Used as a React Flow node type; configuration is in **node.data**. ```tsx import { MultiTubeCableNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `tubeCount` | `number` | `12` | Number of tubes (1-24) | | `fibersPerTube` | `number` | `12` | Fibers per tube | | `fiberCount` | `number` | - | Total fiber count (default: tubeCount * fibersPerTube) | | `cableId` | `string` | `'CBL-002'` | Cable identifier | | `label` | `string` | - | Primary label | | `tubeStartIndex` | `number` | `1` | First tube index for TIA-598 colors | | `color` | `string` | - | Cable border color | ### CouplerNode Coupler/splice panel node with left/right ports. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { CouplerNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `connector` | `'SC' \| 'LC'` | `'LC'` | Connector type | | `couplerFiberCount` | `1 \| 2 \| 4` | `2` | Number of fibers (ports) | | `label` | `string` | - | Label | | `portLabelsLeft` | `string[]` | - | Optional port labels left side | | `portLabelsRight` | `string[]` | - | Optional port labels right side | | `slotPosition` | `number` | - | Slot position inside panel (1-based) | ### PatchPanelNode Container node for patch panels; dimensions can be explicit or auto from children. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { PatchPanelNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | `'Patch Panel'` | Panel label | | `header` | `string` | - | Header text | | `panelWidth` | `number` | - | Explicit width in pixels (else calculated from children) | | `panelHeight` | `number` | - | Explicit height in pixels (else calculated from children) | ### ClosureNode Container node for closures; dimensions can be explicit or auto from children. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { ClosureNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | `'Closure'` | Closure label | | `header` | `string` | - | Header text | | `closureWidth` | `number` | - | Explicit width (or panelWidth) | | `closureHeight` | `number` | - | Explicit height (or panelHeight) | | `panelWidth` | `number` | - | Alternative to closureWidth | | `panelHeight` | `number` | - | Alternative to closureHeight | ### FibreSplitNode Fiber splitter or WDM node (trapezoid: narrow input, wider outputs). Used as a React Flow node type; configuration is in **node.data**. ```tsx import { FibreSplitNode } from '@mp70/react-networks'; ``` #### Node data | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | Label (default "Splitter" or "WDM") | | `splitterType` | `'splitter' \| 'WDM'` | `'splitter'` | Type of splitter | | `inputCount` | `1 \| 2` | `1` | Number of input fibers on the left | | `outputCount` | `number` | `8` | Number of output fibers on the right (1-48) | ### VerticalPDU ### VerticalPDU Power distribution unit component (vertical C13/C19 ports). Used as a React Flow node type; configuration is in **node.data**. ```tsx import { VerticalPDU } from '@mp70/react-networks'; ``` #### Node data (VerticalPDUData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | PDU label | | `status` | `'active' \| 'inactive' \| 'maintenance'` | `'active'` | Status for styling | | `heightCm` | `number` | `100` | Height in centimeters | | `powerPorts` | `number` | `36` | Number of AC power ports (cycle: 8×C13, 2×C19) | | `widthPx` | `number` | `15` | Width in pixels | | `mgmt_unit` | `string` | - | Optional management unit position (e.g. top/middle/bottom) | | `connections` | `string[]` | - | Connected node IDs (if used) | ### SpliceTrayNode Splice tray visualization with holder positioning (12 holders per tray). Used as a React Flow node type; configuration is in **node.data**. ```tsx import { SpliceTrayNode } from '@mp70/react-networks'; ``` #### Node data (SpliceTrayNodeData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | `'Splice Tray'` | Tray label | | `status` | `'active' \| 'inactive' \| 'maintenance'` | - | Optional status | ### SpliceNode Fiber splice component for connecting fiber strands. Used as a React Flow node type; configuration is in **node.data**. ```tsx import { SpliceNode } from '@mp70/react-networks'; ``` #### Node data (SpliceNodeData) | Field | Type | Default | Description | |-------|------|---------|-------------| | `label` | `string` | - | Splice label | | `holderPosition` | `number` | - | Holder position within tray (1-12) | | `lossDb` | `number` | - | Loss value in dB | | `mode` | `'single' \| 'ribbon'` | `'single'` | Splice mode | | `ribbonFiberIds` | `number[]` | - | For ribbon mode: array of fiber IDs (6-12, each 1-24). Required when mode is 'ribbon'. | ### FibreFlowMap Standalone fibre flow diagram: closures, cables, tubes, splices, and optional circuits. Renders a full diagram from FibreFlowClosure[] and optional FibreFlowCircuit[]. ```tsx import { FibreFlowMap } from '@mp70/react-networks'; ``` #### Props (FibreFlowMapProps) | Prop | Type | Default | Description | |------|------|---------|-------------| | `closures` | `FibreFlowClosure[]` | - | Closure definitions (left/right cables + splices) | | `circuits` | `FibreFlowCircuit[]` | - | Optional circuits for highlighting/labels | | `highlightedCircuitId` | `string` | - | Optional circuit ID to highlight | | `layout` | `'horizontal' \| 'vertical'` | - | Layout direction | | `rowHeight` | `number` | - | Row height in pixels | | `tubeGap` | `number` | - | Gap between tubes | | `closureGap` | `number` | - | Gap between closures | | `cableColumnWidth` | `number` | - | Cable column width | | `spliceAreaWidth` | `number` | - | Splice area width | | `showTubeLabels` | `boolean` | - | Show tube labels | | `showFiberNumbers` | `boolean` | - | Show fiber numbers | | `colorMode` | `'dark' \| 'light'` | - | Color mode | | `showCircuitId` | `boolean` | - | Show circuit ID on edges | | `className` | `string` | - | CSS class name | | `style` | `React.CSSProperties` | - | Inline styles | | `panOnDrag` | `boolean` | - | Enable pan on drag | | `panOnScroll` | `boolean` | - | Enable pan on scroll | | `zoomOnScroll` | `boolean` | - | Enable zoom on scroll | ### FibreCableWithTubesExpanded Renders a single fibre flow cable with tubes expanded (used inside FibreFlowMap or standalone). ```tsx import { FibreCableWithTubesExpanded } from '@mp70/react-networks'; ``` #### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `cable` | `FibreFlowCable` | - | Cable definition | | `side` | `'left' \| 'right'` | - | Which side (left or right of closure) | | `rowHeight` | `number` | `22` | Row height in pixels | | `tubeGap` | `number` | `10` | Gap between tubes | | `columnWidth` | `number` | `150` | Column width in pixels | | `layout` | `FibreFlowCableLayout` | - | Precomputed layout (optional) | | `showTubeLabels` | `boolean` | - | Show tube labels | | `showFiberNumbers` | `boolean` | `true` | Show fiber numbers | | `showCableLabel` | `boolean` | `true` | Show cable label | ## Utilities ### Rack Schema Management #### buildNodesFromRackConfig Convert rack configuration to network nodes. ```tsx import { buildNodesFromRackConfig } from '@mp70/react-networks'; const nodes = buildNodesFromRackConfig(racks: RackConfig[], options?: RackSchemaOptions): NetworkNode[] ``` **Parameters:** - `racks`: Array of rack configurations - `options`: Optional RackSchemaOptions (conflict policy, validation) **Returns:** - Array of network nodes **Example:** ```tsx const rackConfig: RackConfig[] = [ { id: 'rack-1', name: 'Main Rack', position: { x: 100, y: 100 }, units: 42, devices: [ { id: 'server-1', name: 'Web Server', unit: 1, height: 1, type: 'server', width: Width.FULL } ] } ]; const nodes = buildNodesFromRackConfig(rackConfig); ``` #### createRackConfigFromNodes Create rack configuration from existing nodes. ```tsx import { createRackConfigFromNodes } from '@mp70/react-networks'; const rackConfig = createRackConfigFromNodes(nodes: NetworkNode[]): RackConfig[] ``` **Parameters:** - `nodes`: Array of network nodes **Returns:** - Array of rack configurations #### addDeviceToRack Add device to rack configuration. ```tsx import { addDeviceToRack } from '@mp70/react-networks'; const updatedRacks = addDeviceToRack(racks: RackConfig[], rackId: string, device: RackDevice, options?: RackSchemaOptions): RackConfig[] ``` **Parameters:** - `racks`: Array of rack configurations - `rackId`: Rack identifier - `device`: Device configuration - `options`: Optional RackSchemaOptions (conflict handling) **Returns:** - Updated array of rack configurations #### removeDeviceFromRack Remove device from rack configuration. ```tsx import { removeDeviceFromRack } from '@mp70/react-networks'; const updatedRacks = removeDeviceFromRack(racks: RackConfig[], rackId: string, deviceId: string): RackConfig[] ``` **Parameters:** - `racks`: Array of rack configurations - `rackId`: Rack identifier - `deviceId`: Device identifier **Returns:** - Updated array of rack configurations #### validateRackDevicePlacements Validate device placements in rack. ```tsx import { validateRackDevicePlacements } from '@mp70/react-networks'; const validation = validateRackDevicePlacements(rackConfig: RackConfig): DevicePlacementValidation ``` **Parameters:** - `rackConfig`: Rack configuration **Returns:** - Validation result with errors and warnings ### Splice Schema Management #### buildNodesFromSpliceConfig Convert splice tray configuration to network nodes. ```tsx import { buildNodesFromSpliceConfig } from '@mp70/react-networks'; const nodes = buildNodesFromSpliceConfig(trayConfig: SpliceTrayConfig[], options?: SpliceSchemaOptions): NetworkNode[] ``` **Parameters:** - `trayConfig`: Array of splice tray configurations - `options`: Optional configuration for conflict handling **Returns:** - Array of network nodes **Example:** ```tsx const trayConfig: SpliceTrayConfig[] = [ { id: 'tray-1', name: 'Main Tray', position: { x: 100, y: 100 }, splices: [ { id: 'splice-1', name: 'Splice 1', holder: 1, lossDb: 0.02 } ] } ]; const nodes = buildNodesFromSpliceConfig(trayConfig); ``` **Note:** Each tray supports up to 12 holders (HOLDERS_PER_TRAY = 12). Holder positions are numbered 1-12, with each holder accommodating one splice. #### createSpliceConfigFromNodes Create splice tray configuration from existing nodes. ```tsx import { createSpliceConfigFromNodes } from '@mp70/react-networks'; const trayConfig = createSpliceConfigFromNodes(nodes: NetworkNode[]): SpliceTrayConfig[] ``` **Parameters:** - `nodes`: Array of network nodes **Returns:** - Array of splice tray configurations #### addSpliceToTray Add splice to tray configuration. ```tsx import { addSpliceToTray } from '@mp70/react-networks'; const updatedTrays = addSpliceToTray(trays: SpliceTrayConfig[], trayId: string, splice: SpliceConfig, options?: SpliceSchemaOptions): SpliceTrayConfig[] ``` **Parameters:** - `trays`: Array of tray configurations - `trayId`: Tray identifier - `splice`: Splice configuration - `options`: Optional configuration for conflict handling **Returns:** - Updated array of tray configurations #### removeSpliceFromTray Remove splice from tray configuration. ```tsx import { removeSpliceFromTray } from '@mp70/react-networks'; const updatedTrays = removeSpliceFromTray(trays: SpliceTrayConfig[], trayId: string, spliceId: string): SpliceTrayConfig[] ``` **Parameters:** - `trays`: Array of tray configurations - `trayId`: Tray identifier - `spliceId`: Splice identifier **Returns:** - Updated array of tray configurations #### updateSpliceHolderPosition Update splice holder position in tray configuration. ```tsx import { updateSpliceHolderPosition } from '@mp70/react-networks'; const updatedTrays = updateSpliceHolderPosition(trays: SpliceTrayConfig[], trayId: string, spliceId: string, newHolder: number): SpliceTrayConfig[] ``` **Parameters:** - `trays`: Array of tray configurations - `trayId`: Tray identifier - `spliceId`: Splice identifier - `newHolder`: New holder position (1-12) **Returns:** - Updated array of tray configurations #### validateSplicePlacements Validate splice placements in tray. ```tsx import { validateSplicePlacements } from '@mp70/react-networks'; const validation = validateSplicePlacements(tray: SpliceTrayConfig, options?: SpliceSchemaOptions): SplicePlacementValidation ``` **Parameters:** - `tray`: Tray configuration - `options`: Optional configuration **Returns:** - Validation result with conflicts and out-of-bounds errors ### U Positioning #### snapToUPosition Snap device to U position. ```tsx import { snapToUPosition } from '@mp70/react-networks'; const updatedNode = snapToUPosition(rackNode: NetworkNode, uPosition: number): NetworkNode ``` **Parameters:** - `rackNode`: Rack node configuration - `uPosition`: U position to snap to **Returns:** - Updated rack node #### isUPositionAvailable Check if U position is available. ```tsx import { isUPositionAvailable } from '@mp70/react-networks'; const available = isUPositionAvailable(rackNode: NetworkNode, uPosition: number, height: number): boolean ``` **Parameters:** - `rackNode`: Rack node configuration - `uPosition`: U position to check - `height`: Device height in U units **Returns:** - Whether position is available #### findNextAvailableUPosition Find next available U position. ```tsx import { findNextAvailableUPosition } from '@mp70/react-networks'; const position = findNextAvailableUPosition(rackNode: NetworkNode, height: number): number ``` **Parameters:** - `rackNode`: Rack node configuration - `height`: Device height in U units **Returns:** - Next available U position #### calculateDevicePositionFromU Calculate device position from U position. ```tsx import { calculateDevicePositionFromU } from '@mp70/react-networks'; const position = calculateDevicePositionFromU(rackNode: NetworkNode, uPosition: number): { x: number; y: number } ``` **Parameters:** - `rackNode`: Rack node configuration - `uPosition`: U position **Returns:** - Calculated position coordinates #### updateDeviceUPosition Update device U position. ```tsx import { updateDeviceUPosition } from '@mp70/react-networks'; updateDeviceUPosition(nodeId: string, uPosition: number): void ``` **Parameters:** - `nodeId`: Node identifier - `uPosition`: New U position #### validateAndSnapDevice Validate and snap device to U position. ```tsx import { validateAndSnapDevice } from '@mp70/react-networks'; const success = validateAndSnapDevice(nodeId: string, uPosition: number): boolean ``` **Parameters:** - `nodeId`: Node identifier - `uPosition`: U position to snap to **Returns:** - Whether operation was successful ### Splice Positioning #### snapToSplicePosition Snap a splice node to the nearest holder position within a tray. ```tsx import { snapToSplicePosition } from '@mp70/react-networks'; const result = snapToSplicePosition(splice: NetworkNode, tray: NetworkNode, newPosition: { x: number; y: number }, allNodes: NetworkNode[]): { x: number; y: number; holderPosition?: number } ``` **Parameters:** - `splice`: The splice node to snap - `tray`: The parent tray node - `newPosition`: Desired position { x, y } - `allNodes`: All nodes in the diagram (for conflict check) **Returns:** - Snapped position and optional holderPosition (1-12) #### findNextAvailableHolderPosition Find the next available holder position in a tray. ```tsx import { findNextAvailableHolderPosition } from '@mp70/react-networks'; const position = findNextAvailableHolderPosition(tray: NetworkNode, splice: NetworkNode, allNodes: NetworkNode[], startFrom?: number): number ``` **Parameters:** - `tray`: Tray node - `splice`: Splice node (to exclude from conflict check) - `allNodes`: All nodes - `startFrom`: Start searching from this holder (default 1) **Returns:** - Holder position (1-12) #### calculateSplicePositionFromNumber Calculate x,y position from holder number within a tray (single-mode spacing). ```tsx import { calculateSplicePositionFromNumber } from '@mp70/react-networks'; const position = calculateSplicePositionFromNumber(tray: NetworkNode, holderPosition: number): { x: number; y: number } ``` **Parameters:** - `tray`: Tray node - `holderPosition`: Holder number (1-12) **Returns:** - { x, y } in pixels ### Coupler Positioning Constants and functions for patch panel / closure layout (couplers, tubes, trays). **Constants:** ```tsx import { COUPLER_SLOT_HEIGHT_PX, PANEL_HEADER_HEIGHT, COUPLERS_PER_PANEL, COUPLER_WIDTH_PX, PANEL_WIDTH_PX, PANEL_HEIGHT_PX, PANEL_BORDER_WIDTH, PANEL_PADDING, PANEL_TUBE_TRAY_SPACING, } from '@mp70/react-networks'; ``` | Constant | Value | Description | |----------|-------|-------------| | `COUPLER_SLOT_HEIGHT_PX` | 30 | Slot height in pixels | | `PANEL_HEADER_HEIGHT` | 32 | Panel header height | | `COUPLERS_PER_PANEL` | 24 | Default couplers per panel | | `COUPLER_WIDTH_PX` | 80 | Coupler width | | `PANEL_WIDTH_PX` | 400 | Default panel width | | `PANEL_HEIGHT_PX` | 300 | Default panel height | | `PANEL_BORDER_WIDTH` | 2 | Panel border width | | `PANEL_PADDING` | 8 | Panel padding | | `PANEL_TUBE_TRAY_SPACING` | 120 | Spacing between tubes and trays | **Functions:** | Function | Signature | Description | |----------|-----------|-------------| | `getPanelWidth` | `(panelNode: NetworkNode) => number` | Panel width from data or default | | `getPanelHeight` | `(panelNode: NetworkNode) => number` | Panel height from data or default | | `getInnerContentWidth` | `(panelNode: NetworkNode) => number` | Width minus borders/padding | | `calculateCouplerRightX` | `(panelNode: NetworkNode, couplerWidth: number) => number` | Right X of coupler in panel | | `calculateSlotPositionFromY` | `(y: number, slotHeight?: number) => number` | Slot number (1-based) from Y | | `calculateYFromSlotPosition` | `(slot: number, slotHeight?: number) => number` | Y from slot number | | `getCouplerDimensions` | `(node: NetworkNode) => { width: number; height: number }` | Coupler dimensions from node data | | `getTubeDimensions` | `(node: NetworkNode) => { width: number; height: number }` | Tube dimensions from node data | | `getTrayDimensions` | `(node: NetworkNode) => { width: number; height: number }` | Tray dimensions (fixed) | | `snapToCouplerPosition` | `(coupler: NetworkNode, panel: NetworkNode, position: { x: number; y: number }) => { x: number; y: number; slotPosition?: number }` | Snap coupler to nearest slot | | `calculatePanelDimensions` | `(panelNode: NetworkNode, childNodes: NetworkNode[]) => { width: number; height: number }` | Panel size from children | | `calculateCouplerSpacing` | `(numCouplers: number, couplerHeight: number, availableHeight: number) => number` | Spacing between couplers | | `calculateCouplerSlotSpacing` | Same as calculateCouplerSpacing | Alias for slot spacing | ### Power Connectors ```tsx import { getPowerPortStyle, getConnectorConfig, getDeviceConnectorType, getPDUPortType, isHighPowerConnector, POWER_CONNECTORS, } from '@mp70/react-networks'; ``` | Function / Export | Signature / Type | Description | |------------------|------------------|-------------| | `getPowerPortStyle` | `(connectorType: string) => PowerPortStyle` | CSS-style for a connector (C13/C14/C19/C20) | | `getConnectorConfig` | `(connectorType: string) => PowerConnectorConfig` | Config for connector type | | `getDeviceConnectorType` | `(deviceName: string) => string` | C14 or C20 from device name | | `getPDUPortType` | `(portIndex: number) => string` | C13 or C19 by position in cycle (8×C13, 2×C19) | | `isHighPowerConnector` | `(connectorType: string) => boolean` | True for 16A (C19/C20) | | `POWER_CONNECTORS` | `Record` | C13, C14, C19, C20 configs | **PowerConnectorConfig:** `{ type, color, borderColor, amperage, voltage, phases }` **PowerPortStyle:** `{ width, height, borderRadius?, clipPath?, color, borderColor, fontSize }` ### Status Colors ```tsx import { getStatusColor } from '@mp70/react-networks'; getStatusColor(status: DeviceStatus | string): string ``` Returns hex color for `'active'` (green), `'inactive'` (gray), `'maintenance'` (amber), or default gray. ### Fiber Colors ```tsx import { FIBER_COLORS_12, baseColorFor, isStriped, fiberSolidOrStriped, getFiberColor, } from '@mp70/react-networks'; import type { FiberColorId } from '@mp70/react-networks'; ``` | Export | Signature / Type | Description | |--------|------------------|-------------| | `FIBER_COLORS_12` | `readonly string[]` | TIA-598-C base colors (1-12) | | `baseColorFor` | `(id: FiberColorId \| number) => string` | Hex for fiber ID (1-24, 13-24 same as 1-12) | | `isStriped` | `(id: FiberColorId \| number) => boolean` | True for 13-24 (striped) | | `fiberSolidOrStriped` | `(id: FiberColorId \| number) => React.CSSProperties` | Background (and stripe) CSS | | `getFiberColor` | `(id: FiberColorId \| number) => string` | Hex color for ID | ### Rack Geometry ```tsx import { getRackBounds, isPointInRack, findNearestRack } from '@mp70/react-networks'; ``` | Function | Signature | Description | |----------|-----------|-------------| | `getRackBounds` | `(rack: NetworkNode) => { left, right, top, bottom }` | Bounding box of rack in pixels | | `isPointInRack` | `(point: { x: number; y: number }, rack: NetworkNode) => boolean` | Whether point is inside rack | | `findNearestRack` | `(point: { x: number; y: number }, racks: NetworkNode[]) => NetworkNode \| null` | Nearest rack that contains the point | ### Edge Connection ```tsx import { replaceEdge } from '@mp70/react-networks'; import type { ReplaceEdgeOptions } from '@mp70/react-networks'; replaceEdge(options: ReplaceEdgeOptions): Edge[] | null ``` Replaces an existing edge (found by source or target handle) with a new connection. Options: `edges`, `connection`, `edgeType`, `selectEdgeZIndex`, `findBy` ('source' | 'target'), optional `matchOn` ('source' | 'target', defaults to `findBy`—use when connection's target handle is on the edge's source, e.g. replacing switch connection when dragging from server to switch), optional `data`. Uses normalized handle comparison for bidirectional handles. Returns new edges array or null if no matching edge. ### Core / Headless Store and hooks for headless use (e.g. custom UI with shared state). ```tsx import { createNetworkDiagramStore, useNetworkDiagram, useDiagramNodes, useDiagramEdges, } from '@mp70/react-networks'; ``` | Export | Signature | Description | |--------|-----------|-------------| | `createNetworkDiagramStore` | `(options?: NetworkDiagramOptions) => NetworkDiagramStore` | Create store; options can include `validateConnection` | | `useNetworkDiagram` | `(store: NetworkDiagramStore) => NetworkDiagramState` | Full state (nodes, edges, debug) | | `useDiagramNodes` | `(store: NetworkDiagramStore) => NetworkNode[]` | Nodes from store | | `useDiagramEdges` | `(store: NetworkDiagramStore) => NetworkEdge[]` | Edges from store | **NetworkDiagramStore:** `getState`, `setState`, `subscribe`, `selectEdgeZIndex`, `validateConnection`, `selectNodeById`, `selectConnectedEdges` **NetworkDiagramOptions:** `{ validateConnection?: (params, ctx) => ValidationResult }` **ValidationResult:** `{ valid: boolean; reason?: string }` **ValidateConnectionParams:** `{ source, target, sourceHandle?, targetHandle? }` (strings or null) ### Inventory Integration #### inventoryRackToNetworkNode Convert inventory rack to network node. ```tsx import { inventoryRackToNetworkNode } from '@mp70/react-networks'; const node = inventoryRackToNetworkNode(rack: any): NetworkNode ``` **Parameters:** - `rack`: inventory rack data **Returns:** - Network node #### inventoryDeviceToNetworkNode Convert inventory device to network node. ```tsx import { inventoryDeviceToNetworkNode } from '@mp70/react-networks'; const node = inventoryDeviceToNetworkNode(device: any): NetworkNode ``` **Parameters:** - `device`: inventory device data **Returns:** - Network node #### inventoryCableToNetworkEdge Convert inventory cable to network edge. ```tsx import { inventoryCableToNetworkEdge } from '@mp70/react-networks'; const edge = inventoryCableToNetworkEdge(cable: any): NetworkEdge ``` **Parameters:** - `cable`: inventory cable data **Returns:** - Network edge #### inventoryToNetworkDiagram Convert inventory data to complete diagram. ```tsx import { inventoryToNetworkDiagram } from '@mp70/react-networks'; const diagram = inventoryToNetworkDiagram(data: { racks: any[]; devices: any[]; cables: any[] }): { nodes: NetworkNode[]; edges: NetworkEdge[] } ``` **Parameters:** - `data`: inventory data object **Returns:** - Diagram with nodes and edges #### generateLayout Generate a simple layout from an array of nodes. ```tsx import { generateLayout } from '@mp70/react-networks'; const laidOutNodes = generateLayout(nodes: NetworkNode[]): NetworkNode[] ``` **Parameters:** - `nodes`: Array of network nodes **Returns:** - Nodes with updated positions ## Types ### NetworkNode ```tsx interface NetworkNode { id: string; type: NetworkNodeType; position: { x: number; y: number }; parentId?: string; extent?: 'parent' | [[number, number], [number, number]]; data: { label: string; ports?: PortBlock[]; connections?: string[]; status?: DeviceStatus; netboxId?: number; netboxType?: 'device' | 'rack' | 'interface' | 'cable'; uHeight?: number; uPosition?: number; view?: DeviceView; deviceType?: string; manufacturer?: string; role?: string; width?: Width; rearPorts?: PortBlock[]; powerSide?: PowerSide; frontImageUrl?: string; rearImageUrl?: string; frontImageAttribution?: string; rearImageAttribution?: string; imageFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'; imagePosition?: string; imageRepeat?: string; stretchToFit?: boolean; heightCm?: number; powerPorts?: number; uNumberingDirection?: UNumberingDirection; customHeaderText?: string; rackWidthPx?: number; holderPosition?: number; lossDb?: number; connector?: 'SC' | 'LC'; couplerFiberCount?: 1 | 2 | 4; portLabelsLeft?: string[]; portLabelsRight?: string[]; slotPosition?: number; panelWidth?: number; panelHeight?: number; rows?: number; cols?: number; header?: string; splitterType?: 'splitter' | 'WDM'; inputCount?: number; outputCount?: number; [key: string]: any; }; } ``` ### NetworkEdge ```tsx interface NetworkEdge { id: string; source: string; target: string; sourceHandle?: string; targetHandle?: string; type?: NetworkEdgeType; data?: { bandwidth?: string; length?: number; color?: string; kind?: 'fiber' | 'power' | 'network'; fiberId?: number; ribbonFiberIds?: number[]; isRibbon?: boolean; highlight?: boolean; highlightColor?: string; highlightWidth?: number; traceTag?: string; connectorType?: string; [key: string]: any; }; } ``` ### NetworkNodeType ```tsx type NetworkNodeType = | 'rack' | 'switch' | 'router' | 'server' | 'fiber' | 'patch-panel' | 'device' | 'vertical-pdu' | 'splice' | 'splice-tray' | 'tube' | 'cable' | 'multi-tube-cable' | 'coupler' | 'closure' | 'fibre-split' | 'fibre-flow-cable' | 'fibre-flow-closure'; ``` ### NetworkEdgeType ```tsx type NetworkEdgeType = | 'fiber' | 'ethernet' | 'power' | 'smoothstep' | 'step' | 'thick-cable' | 'fibre-flow' | 'fibre-flow-link'; ``` ### RackConfig ```tsx interface RackConfig { id: string; name: string; position: { x: number; y: number }; units: number; uNumberingDirection?: UNumberingDirection; customHeaderText?: string; rackWidthPx?: number; devices: RackDevice[]; } ``` ### RackDevice ```tsx interface RackDevice { id: string; name: string; unit: number; height: number; type: RackDeviceType; width?: Width; role?: string; ports?: PortBlock[]; rearPorts?: PortBlock[]; powerSide?: PowerSide; frontImageUrl?: string; rearImageUrl?: string; frontImageAttribution?: string; rearImageAttribution?: string; imageFit?: string; imagePosition?: string; imageRepeat?: string; stretchToFit?: boolean; connections?: string[]; } ``` ### PortBlock and Port ```tsx interface PortBlock { name: string; ports: Port[]; } type PortType = 'ethernet' | 'fiber' | 'console' | 'mgmt' | 'usb' | 'power_ac' | 'power_c13' | 'power_c19'; interface Port { label: string; connected: boolean; type?: PortType; cableType?: 'smf' | 'cat6' | 'om3' | 'om4' | 'om5' | 'cat5e' | 'cat6a' | 'cat7' | 'fiber' | 'ethernet'; } ``` ### Other type definitions ```tsx type DeviceStatus = 'active' | 'inactive' | 'maintenance'; type DeviceView = 'front' | 'rear'; type PowerSide = 'left' | 'right'; type UNumberingDirection = 'bottom-up' | 'top-down'; type RackDeviceType = 'server' | 'switch' | 'router' | 'patch-panel' | 'ups'; type FiberCableType = 'single-mode' | 'multi-mode'; enum Width { FULL = 'full', HALF = 'half' } ``` ### FiberCable ```tsx interface FiberCable { id: string; name: string; type: FiberCableType; length: number; color: string; connections: { from: string; to: string }; } ``` ### SpliceConfig and SpliceTrayConfig ```tsx interface SpliceConfig { id: string; name: string; holder: number; lossDb?: number; mode?: 'single' | 'ribbon'; ribbonFiberIds?: number[]; } interface SpliceTrayConfig { id: string; name: string; position: { x: number; y: number }; splices: SpliceConfig[]; } ``` ### Fibre flow types ```tsx type FibreFlowCableKind = 'simple' | 'tube'; interface FibreFlowEndpoint { tube?: number; fiber: number; } interface FibreFlowSplice { id: string; from: FibreFlowEndpoint; to: FibreFlowEndpoint; lossDb?: number; circuitId?: string; label?: string; color?: string; } interface FibreFlowCable { id: string; label: string; kind?: FibreFlowCableKind; fiberCount?: number; tubeCount?: number; fibersPerTube?: number; tubeStartIndex?: number; fiberStartIndex?: number; tubeColorMap?: Record; jacketColor?: string; distanceLabel?: string; distanceMeters?: number; } interface FibreFlowClosure { id: string; chamberId?: string; leftCable: FibreFlowCable; rightCable: FibreFlowCable; splices: FibreFlowSplice[]; } interface FibreFlowCircuit { id: string; label: string; color?: string; } ``` ### Rack schema options and validation ```tsx interface RackSchemaOptions { conflictPolicy?: 'strict' | 'nearest'; validatePlacements?: boolean; deviceTypeMapping?: Record; } interface DevicePlacementValidation { isValid: boolean; conflicts: Array<{ deviceId: string; uPosition: number; uHeight: number; conflictWith: string }>; outOfBounds: Array<{ deviceId: string; uPosition: number; uHeight: number; rackUHeight: number }>; } ``` ### Splice schema options and validation ```tsx interface SpliceSchemaOptions { conflictPolicy?: 'strict' | 'nearest'; validatePlacements?: boolean; } interface SplicePlacementValidation { isValid: boolean; conflicts: Array<{ spliceId: string; holder: number; conflictWith: string }>; outOfBounds: Array<{ spliceId: string; holder: number; max: number }>; } ``` ### ReplaceEdgeOptions ```tsx interface ReplaceEdgeOptions { edges: Edge[]; connection: Connection; edgeType: 'power' | 'fiber' | 'step' | 'smoothstep' | 'thick-cable'; selectEdgeZIndex: (edge: NetworkEdge) => number; findBy: 'source' | 'target'; data?: NetworkEdge['data']; } ``` ### FiberColorId ```tsx type FiberColorId = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24; ``` ## Error Handling ### DevicePlacementError Thrown when device placement conflicts occur in strict mode (rack schema). ```tsx class DevicePlacementError extends Error { constructor( public rackId: string, public deviceId: string, public uPosition: number, public uHeight: number, public conflictWith?: string ) { super(`Device placement conflict: ${deviceId} at U${uPosition}-${uPosition + uHeight - 1} in rack ${rackId}${conflictWith ? ` conflicts with ${conflictWith}` : ''}`); this.name = 'DevicePlacementError'; } } ``` ### SplicePlacementError Thrown when splice placement conflicts occur in strict mode (splice schema). ```tsx class SplicePlacementError extends Error { constructor( public trayId: string, public spliceId: string, public holder: number, public conflictWith?: string ) { super(`Splice placement conflict: ${spliceId} at holder ${holder} in tray ${trayId}${conflictWith ? ` conflicts with ${conflictWith}` : ''}`); this.name = 'SplicePlacementError'; } } ``` ## Constants Exported from `@mp70/react-networks`: ```tsx const U_HEIGHT_PX = 20; // Height of 1U in pixels const RACK_HEADER_HEIGHT = 60; // Fixed rack header height in pixels const RACK_WIDTH_PX = 300; // Fixed rack width in pixels (standard 19" rack) const HANDLE_EXTENSION_PX = 5; // Handles extend this many pixels outside nodes ``` ## Events These callbacks are supported by **NetworkDiagram** via NetworkDiagramProps. React Flow may expose additional events when using custom `nodeTypes` / `edgeTypes` or the instance from `onInit` / `onFlowMethods`. ### Diagram callbacks (NetworkDiagramProps) | Callback | Signature | Description | |----------|-----------|-------------| | `onNodeClick` | `(node: NetworkNode \| null) => void` | When a node is clicked or selection changes (null when deselected) | | `onEdgeClick` | `(edge: NetworkEdge) => void` | When an edge is clicked | | `onViewChange` | `(nodeId: string, view: DeviceView) => void` | When device view (front/rear) changes | | `onRackFaceChange` | `(rackId: string, face: DeviceView) => void` | When rack face changes | | `onConnect` | `(connection: Connection) => void` | When a new connection is made (optional override) | | `onEdgeUpdate` | `(oldEdge: Edge, newConnection: Connection) => void` | When an edge is updated (optional override) | | `onInit` | `(instance: any) => void` | When React Flow instance is initialized | | `onFlowMethods` | `(methods: { toObject, setViewport, setNodes, setEdges, toImage, getNodes, getEdges, fitView }) => void` | Callback to get save/restore and view methods |