@mp70/react-networks 0.1.8-beta → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,10 +1,11 @@
1
- import React$1 from 'react';
2
- import { NodeProps, EdgeProps, Edge, Connection } from 'reactflow';
1
+ import React$1, { Component, ReactNode, ErrorInfo } from 'react';
2
+ import { NodeTypes, EdgeTypes, Connection, Edge, ConnectionMode, FitViewOptions, NodeProps, EdgeProps } from 'reactflow';
3
3
 
4
4
  /**
5
5
  * Rack device width configuration
6
6
  * @public
7
7
  */
8
+
8
9
  declare enum Width {
9
10
  /** Full width device (19" rack width) */
10
11
  FULL = "full",
@@ -44,7 +45,7 @@ interface PortBlock {
44
45
  * Network node types supported by the diagram
45
46
  * @public
46
47
  */
47
- type NetworkNodeType = 'rack' | 'switch' | 'router' | 'server' | 'fiber' | 'patch-panel' | 'device' | 'vertical-pdu' | 'splice' | 'splice-tray' | 'tube' | 'cable' | 'multi-tube-cable' | 'coupler' | 'closure' | 'fibre-split';
48
+ 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';
48
49
  /**
49
50
  * Device status states
50
51
  * @public
@@ -115,6 +116,22 @@ interface NetworkNode {
115
116
  rearPorts?: PortBlock[];
116
117
  /** Power port side for rear view */
117
118
  powerSide?: PowerSide;
119
+ /** Optional front image URL for device background (PNG, SVG, JPEG, etc.) */
120
+ frontImageUrl?: string;
121
+ /** Optional rear image URL for device background (PNG, SVG, JPEG, etc.) */
122
+ rearImageUrl?: string;
123
+ /** Optional attribution URL for front image (e.g. source/license link) */
124
+ frontImageAttribution?: string;
125
+ /** Optional attribution URL for rear image (e.g. source/license link) */
126
+ rearImageAttribution?: string;
127
+ /** Optional background sizing for device images */
128
+ imageFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
129
+ /** Optional background position for device images */
130
+ imagePosition?: string;
131
+ /** Optional background repeat for device images */
132
+ imageRepeat?: 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y';
133
+ /** When true, stretch device image to fill the device bounds (overrides imageFit) */
134
+ stretchToFit?: boolean;
118
135
  /** Vertical PDU height in centimeters */
119
136
  heightCm?: number;
120
137
  /** Number of AC power ports */
@@ -163,7 +180,7 @@ interface NetworkNode {
163
180
  * Network edge types
164
181
  * @public
165
182
  */
166
- type NetworkEdgeType = 'fiber' | 'ethernet' | 'power' | 'smoothstep' | 'step' | 'thick-cable';
183
+ type NetworkEdgeType = 'fiber' | 'ethernet' | 'power' | 'smoothstep' | 'step' | 'thick-cable' | 'fibre-flow' | 'fibre-flow-link';
167
184
  /**
168
185
  * Network edge data structure
169
186
  * @public
@@ -262,6 +279,22 @@ interface RackDevice {
262
279
  rearPorts?: PortBlock[];
263
280
  /** Power port side for rear view */
264
281
  powerSide?: PowerSide;
282
+ /** Optional front image URL for device background (PNG, SVG, JPEG, etc.) */
283
+ frontImageUrl?: string;
284
+ /** Optional rear image URL for device background (PNG, SVG, JPEG, etc.) */
285
+ rearImageUrl?: string;
286
+ /** Optional attribution URL for front image (e.g. source/license link) */
287
+ frontImageAttribution?: string;
288
+ /** Optional attribution URL for rear image (e.g. source/license link) */
289
+ rearImageAttribution?: string;
290
+ /** Optional background sizing for device images */
291
+ imageFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
292
+ /** Optional background position for device images */
293
+ imagePosition?: string;
294
+ /** Optional background repeat for device images */
295
+ imageRepeat?: 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y';
296
+ /** When true, stretch device image to fill the device bounds (overrides imageFit) */
297
+ stretchToFit?: boolean;
265
298
  /** Connected device IDs */
266
299
  connections?: string[];
267
300
  }
@@ -353,6 +386,18 @@ interface NetworkDiagramProps {
353
386
  onNodeClick?: (node: NetworkNode | null) => void;
354
387
  /** Callback when an edge is clicked */
355
388
  onEdgeClick?: (edge: NetworkEdge) => void;
389
+ /** Custom React Flow node types to merge with defaults */
390
+ nodeTypes?: NodeTypes;
391
+ /** Custom React Flow edge types to merge with defaults */
392
+ edgeTypes?: EdgeTypes;
393
+ /** Optional onConnect override (React Flow connection handler) */
394
+ onConnect?: (connection: Connection) => void;
395
+ /** Optional onEdgeUpdate override */
396
+ onEdgeUpdate?: (oldEdge: Edge, newConnection: Connection) => void;
397
+ /** Optional isValidConnection override */
398
+ isValidConnection?: (connection: Connection) => boolean;
399
+ /** Optional connection mode override */
400
+ connectionMode?: ConnectionMode;
356
401
  /** Callback when device view changes */
357
402
  onViewChange?: (nodeId: string, view: DeviceView) => void;
358
403
  /** Callback when rack face changes */
@@ -396,25 +441,165 @@ interface NetworkDiagramProps {
396
441
  panOnScroll?: boolean;
397
442
  /** Disable zooming on scroll. Default is true. */
398
443
  zoomOnScroll?: boolean;
444
+ /** Optional fitView options passed to React Flow */
445
+ fitViewOptions?: FitViewOptions;
399
446
  }
400
447
 
448
+ /**
449
+ * Main component for rendering interactive network diagrams.
450
+ *
451
+ * The NetworkDiagram component provides a complete solution for visualizing
452
+ * network infrastructure including racks, devices, fiber connections, and power distribution.
453
+ *
454
+ * @example
455
+ * ```tsx
456
+ * import { NetworkDiagram, NetworkNode, NetworkEdge } from '@mp70/react-networks';
457
+ *
458
+ * const nodes: NetworkNode[] = [
459
+ * {
460
+ * id: 'rack-1',
461
+ * type: 'rack',
462
+ * position: { x: 100, y: 100 },
463
+ * data: { label: 'Main Rack', uHeight: 42 }
464
+ * }
465
+ * ];
466
+ *
467
+ * <NetworkDiagram nodes={nodes} edges={[]} />
468
+ * ```
469
+ *
470
+ * @public
471
+ */
401
472
  declare const NetworkDiagram: React$1.FC<NetworkDiagramProps>;
402
473
 
474
+ interface DiagramErrorBoundaryProps {
475
+ /** Content to render when an error is caught */
476
+ children: ReactNode;
477
+ /** Optional fallback UI when an error occurs (default: simple message) */
478
+ fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
479
+ /** Optional callback when an error is caught (e.g. for logging) */
480
+ onError?: (error: Error, errorInfo: ErrorInfo) => void;
481
+ }
482
+ interface State {
483
+ error: Error | null;
484
+ }
485
+ /**
486
+ * Error boundary that catches errors in the diagram tree (e.g. React Flow,
487
+ * custom nodes) and renders a fallback instead of crashing the whole app.
488
+ * Wrap &lt;NetworkDiagram&gt; (or the diagram subtree) with this for production.
489
+ *
490
+ * @example
491
+ * ```tsx
492
+ * <DiagramErrorBoundary
493
+ * fallback={(error, reset) => (
494
+ * <div>
495
+ * <p>Diagram failed: {error.message}</p>
496
+ * <button onClick={reset}>Try again</button>
497
+ * </div>
498
+ * )}
499
+ * onError={(err, info) => logToService(err, info)}
500
+ * >
501
+ * <NetworkDiagram nodes={nodes} edges={edges} />
502
+ * </DiagramErrorBoundary>
503
+ * ```
504
+ */
505
+ declare class DiagramErrorBoundary extends Component<DiagramErrorBoundaryProps, State> {
506
+ state: State;
507
+ static getDerivedStateFromError(error: Error): State;
508
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
509
+ reset: () => void;
510
+ render(): ReactNode;
511
+ }
512
+
403
513
  interface RackNodeProps extends NodeProps<NetworkNode['data']> {
404
514
  onViewChange?: (nodeId: string, view: 'front' | 'rear') => void;
405
515
  onRackFaceChange?: (rackId: string, face: 'front' | 'rear') => void;
406
516
  isDragOver?: boolean;
407
517
  }
518
+ /**
519
+ * Rack visualization component with U positioning support.
520
+ *
521
+ * Displays a 19" rack with configurable height, front/rear view switching,
522
+ * and support for mounting devices at specific U positions.
523
+ *
524
+ * @example
525
+ * ```tsx
526
+ * {
527
+ * id: 'rack-1',
528
+ * type: 'rack',
529
+ * position: { x: 100, y: 100 },
530
+ * data: {
531
+ * label: 'Main Rack',
532
+ * uHeight: 42,
533
+ * status: 'active'
534
+ * }
535
+ * }
536
+ * ```
537
+ *
538
+ * @public
539
+ */
408
540
  declare const RackNode: React$1.FC<RackNodeProps>;
409
541
 
410
542
  declare const FiberNode: React$1.FC<NodeProps<NetworkNode['data']>>;
411
543
 
544
+ /**
545
+ * Fiber edge component for connecting fiber ports between nodes.
546
+ *
547
+ * Supports both single fiber connections with color coding and ribbon fiber
548
+ * connections (6-12 fibers) with parallel stripe visualization.
549
+ *
550
+ * @example
551
+ * ```tsx
552
+ * {
553
+ * id: 'edge-1',
554
+ * source: 'node-1',
555
+ * target: 'node-2',
556
+ * sourceHandle: 'fiber-1',
557
+ * targetHandle: 'fiber-2',
558
+ * type: 'fiber',
559
+ * data: {
560
+ * kind: 'fiber',
561
+ * ribbonFiberIds: [1, 2, 3, 4, 5, 6] // For ribbon mode
562
+ * }
563
+ * }
564
+ * ```
565
+ *
566
+ * @public
567
+ */
412
568
  declare const FiberEdge: React$1.FC<EdgeProps<NetworkEdge['data']> & {
413
569
  className?: string;
414
570
  }>;
415
571
 
416
572
  declare const PowerEdge: React$1.FC<EdgeProps>;
417
573
 
574
+ /**
575
+ * Device visualization component with port management.
576
+ *
577
+ * Represents a device that can be placed in a rack. Supports port configuration,
578
+ * U positioning, front/rear views, and various device types (servers, switches, routers, etc.).
579
+ *
580
+ * @example
581
+ * ```tsx
582
+ * {
583
+ * id: 'server-1',
584
+ * type: 'device',
585
+ * position: { x: 120, y: 150 },
586
+ * parentId: 'rack-1',
587
+ * data: {
588
+ * label: 'Web Server',
589
+ * deviceType: 'server',
590
+ * uPosition: 1,
591
+ * ports: [{
592
+ * name: 'Network Ports',
593
+ * ports: [
594
+ * { label: 'eth0', connected: true, type: 'ethernet' }
595
+ * ]
596
+ * }]
597
+ * }
598
+ * }
599
+ * ```
600
+ *
601
+ * @public
602
+ */
418
603
  declare const DeviceNode: React$1.FC<NodeProps<NetworkNode['data']>>;
419
604
 
420
605
  declare const VerticalPDU: React$1.FC<NodeProps<NetworkNode['data']>>;
@@ -465,6 +650,105 @@ declare const ClosureNode: React$1.FC<NodeProps<NetworkNode['data']>>;
465
650
  */
466
651
  declare const FibreSplitNode: React$1.FC<NodeProps<NetworkNode['data']>>;
467
652
 
653
+ type FibreFlowCableKind = 'simple' | 'tube';
654
+ interface FibreFlowEndpoint {
655
+ tube?: number;
656
+ fiber: number;
657
+ }
658
+ interface FibreFlowSplice {
659
+ id: string;
660
+ from: FibreFlowEndpoint;
661
+ to: FibreFlowEndpoint;
662
+ lossDb?: number;
663
+ circuitId?: string;
664
+ label?: string;
665
+ color?: string;
666
+ }
667
+ interface FibreFlowCable {
668
+ id: string;
669
+ label: string;
670
+ kind?: FibreFlowCableKind;
671
+ fiberCount?: number;
672
+ tubeCount?: number;
673
+ fibersPerTube?: number;
674
+ tubeStartIndex?: number;
675
+ fiberStartIndex?: number;
676
+ tubeColorMap?: Record<number, string>;
677
+ jacketColor?: string;
678
+ distanceLabel?: string;
679
+ distanceMeters?: number;
680
+ }
681
+ interface FibreFlowClosure {
682
+ id: string;
683
+ chamberId?: string;
684
+ leftCable: FibreFlowCable;
685
+ rightCable: FibreFlowCable;
686
+ splices: FibreFlowSplice[];
687
+ }
688
+ interface FibreFlowCircuit {
689
+ id: string;
690
+ label: string;
691
+ color?: string;
692
+ }
693
+
694
+ type FibreFlowLayoutDirection = 'horizontal' | 'vertical';
695
+ type FibreFlowColorMode = 'dark' | 'light';
696
+ interface FibreFlowMapProps {
697
+ closures: FibreFlowClosure[];
698
+ circuits?: FibreFlowCircuit[];
699
+ highlightedCircuitId?: string;
700
+ layout?: FibreFlowLayoutDirection;
701
+ rowHeight?: number;
702
+ tubeGap?: number;
703
+ closureGap?: number;
704
+ cableColumnWidth?: number;
705
+ spliceAreaWidth?: number;
706
+ showTubeLabels?: boolean;
707
+ showFiberNumbers?: boolean;
708
+ colorMode?: FibreFlowColorMode;
709
+ showCircuitId?: boolean;
710
+ className?: string;
711
+ style?: React$1.CSSProperties;
712
+ panOnDrag?: boolean;
713
+ panOnScroll?: boolean;
714
+ zoomOnScroll?: boolean;
715
+ }
716
+ declare const FibreFlowMap: React$1.FC<FibreFlowMapProps>;
717
+
718
+ interface FibreFlowRow {
719
+ key: string;
720
+ tubeIndex?: number;
721
+ fiberIndex: number;
722
+ y: number;
723
+ color: string;
724
+ striped: boolean;
725
+ backgroundImage?: string;
726
+ }
727
+ interface FibreFlowTubeLabel {
728
+ tubeIndex: number;
729
+ y: number;
730
+ label: string;
731
+ color: string;
732
+ }
733
+ interface FibreFlowCableLayout {
734
+ rows: FibreFlowRow[];
735
+ tubeLabels: FibreFlowTubeLabel[];
736
+ height: number;
737
+ }
738
+
739
+ interface FibreCableWithTubesExpandedProps {
740
+ cable: FibreFlowCable;
741
+ side: 'left' | 'right';
742
+ rowHeight?: number;
743
+ tubeGap?: number;
744
+ columnWidth?: number;
745
+ layout?: FibreFlowCableLayout;
746
+ showTubeLabels?: boolean;
747
+ showFiberNumbers?: boolean;
748
+ showCableLabel?: boolean;
749
+ }
750
+ declare const FibreCableWithTubesExpanded: React$1.FC<FibreCableWithTubesExpandedProps>;
751
+
468
752
  interface InventoryRackDTO {
469
753
  id: string | number;
470
754
  name: string;
@@ -671,6 +955,17 @@ declare const PANEL_PADDING = 8;
671
955
  declare const PANEL_TUBE_TRAY_SPACING = 120;
672
956
  /**
673
957
  * Calculate coupler dimensions based on node data
958
+ *
959
+ * @param node - The coupler node with optional couplerFiberCount in data
960
+ * @returns Object with width and height in pixels
961
+ * @public
962
+ *
963
+ * @example
964
+ * ```ts
965
+ * const node = { type: 'coupler', data: { couplerFiberCount: 2 } };
966
+ * const dims = getCouplerDimensions(node);
967
+ * // Returns: { width: 80, height: 30 }
968
+ * ```
674
969
  */
675
970
  declare function getCouplerDimensions(node: NetworkNode): {
676
971
  width: number;
@@ -678,6 +973,17 @@ declare function getCouplerDimensions(node: NetworkNode): {
678
973
  };
679
974
  /**
680
975
  * Calculate tube dimensions based on node data
976
+ *
977
+ * @param node - The tube node with optional fibersPerTube in data (default: 12)
978
+ * @returns Object with width and height in pixels
979
+ * @public
980
+ *
981
+ * @example
982
+ * ```ts
983
+ * const node = { type: 'tube', data: { fibersPerTube: 12 } };
984
+ * const dims = getTubeDimensions(node);
985
+ * // Returns: { width: calculated, height: 20 }
986
+ * ```
681
987
  */
682
988
  declare function getTubeDimensions(node: NetworkNode): {
683
989
  width: number;
@@ -685,6 +991,12 @@ declare function getTubeDimensions(node: NetworkNode): {
685
991
  };
686
992
  /**
687
993
  * Get tray dimensions
994
+ *
995
+ * Tray dimensions are fixed and do not depend on node data.
996
+ *
997
+ * @param _node - The tray node (unused, dimensions are fixed)
998
+ * @returns Object with fixed width (TRAY_WIDTH_PX) and height (0)
999
+ * @public
688
1000
  */
689
1001
  declare function getTrayDimensions(_node: NetworkNode): {
690
1002
  width: number;
@@ -692,30 +1004,73 @@ declare function getTrayDimensions(_node: NetworkNode): {
692
1004
  };
693
1005
  /**
694
1006
  * Calculate panel width based on content
1007
+ *
1008
+ * @param panelNode - The panel node with optional panelWidth in data
1009
+ * @returns Panel width in pixels, or default PANEL_WIDTH_PX if not specified
1010
+ * @public
695
1011
  */
696
1012
  declare function getPanelWidth(panelNode: NetworkNode): number;
697
1013
  /**
698
1014
  * Calculate panel height based on content
1015
+ *
1016
+ * @param panelNode - The panel node with optional panelHeight in data
1017
+ * @returns Panel height in pixels, or default PANEL_HEIGHT_PX if not specified
1018
+ * @public
699
1019
  */
700
1020
  declare function getPanelHeight(panelNode: NetworkNode): number;
701
1021
  /**
702
1022
  * Get inner content width (panel width minus borders/padding)
1023
+ *
1024
+ * Calculates the usable width inside a panel after accounting for borders and padding.
1025
+ *
1026
+ * @param panelNode - The panel node
1027
+ * @returns Inner content width in pixels
1028
+ * @public
703
1029
  */
704
1030
  declare function getInnerContentWidth(panelNode: NetworkNode): number;
705
1031
  /**
706
1032
  * Calculate coupler right X position
1033
+ *
1034
+ * Calculates the X position for the right edge of a coupler within a panel.
1035
+ *
1036
+ * @param panelNode - The panel node containing the coupler
1037
+ * @param couplerWidth - Width of the coupler in pixels
1038
+ * @returns X position for the right edge of the coupler
1039
+ * @public
707
1040
  */
708
1041
  declare function calculateCouplerRightX(panelNode: NetworkNode, couplerWidth: number): number;
709
1042
  /**
710
1043
  * Calculate slot position from Y coordinate
1044
+ *
1045
+ * Converts a Y pixel coordinate to a slot number (1-indexed).
1046
+ *
1047
+ * @param y - Y coordinate in pixels
1048
+ * @param slotHeight - Height of each slot in pixels (default: COUPLER_SLOT_HEIGHT_PX)
1049
+ * @returns Slot position (1-indexed)
1050
+ * @public
711
1051
  */
712
1052
  declare function calculateSlotPositionFromY(y: number, slotHeight?: number): number;
713
1053
  /**
714
1054
  * Calculate Y coordinate from slot position
1055
+ *
1056
+ * Converts a slot number (1-indexed) to a Y pixel coordinate.
1057
+ *
1058
+ * @param slot - Slot position (1-indexed)
1059
+ * @param slotHeight - Height of each slot in pixels (default: COUPLER_SLOT_HEIGHT_PX)
1060
+ * @returns Y coordinate in pixels
1061
+ * @public
715
1062
  */
716
1063
  declare function calculateYFromSlotPosition(slot: number, slotHeight?: number): number;
717
1064
  /**
718
1065
  * Snap coupler to nearest slot position
1066
+ *
1067
+ * Snaps a coupler's position to the nearest valid slot within a panel.
1068
+ *
1069
+ * @param coupler - The coupler node to snap
1070
+ * @param panel - The panel node containing the coupler
1071
+ * @param position - Current position { x, y }
1072
+ * @returns Snapped position with optional slotPosition
1073
+ * @public
719
1074
  */
720
1075
  declare function snapToCouplerPosition(coupler: NetworkNode, panel: NetworkNode, position: {
721
1076
  x: number;
@@ -727,6 +1082,21 @@ declare function snapToCouplerPosition(coupler: NetworkNode, panel: NetworkNode,
727
1082
  };
728
1083
  /**
729
1084
  * Calculate panel dimensions based on child nodes
1085
+ *
1086
+ * Automatically calculates the width and height of a panel based on its child nodes.
1087
+ * Supports special layouts for patch panels with tubes, trays, and couplers.
1088
+ *
1089
+ * @param panelNode - The panel node
1090
+ * @param childNodes - Array of child nodes within the panel
1091
+ * @returns Object with calculated width and height in pixels
1092
+ * @public
1093
+ *
1094
+ * @example
1095
+ * ```ts
1096
+ * const panel = { id: 'panel-1', type: 'patch-panel', data: {} };
1097
+ * const children = [tubeNode, trayNode, couplerNode];
1098
+ * const dims = calculatePanelDimensions(panel, children);
1099
+ * ```
730
1100
  */
731
1101
  declare function calculatePanelDimensions(panelNode: NetworkNode, childNodes: NetworkNode[]): {
732
1102
  width: number;
@@ -734,10 +1104,27 @@ declare function calculatePanelDimensions(panelNode: NetworkNode, childNodes: Ne
734
1104
  };
735
1105
  /**
736
1106
  * Calculate spacing between couplers
1107
+ *
1108
+ * Calculates the vertical spacing needed between couplers to fit them evenly
1109
+ * within the available height.
1110
+ *
1111
+ * @param numCouplers - Number of couplers to space
1112
+ * @param couplerHeight - Height of each coupler in pixels
1113
+ * @param availableHeight - Total available height in pixels
1114
+ * @returns Spacing between couplers in pixels (includes coupler height)
1115
+ * @public
737
1116
  */
738
1117
  declare function calculateCouplerSpacing(numCouplers: number, couplerHeight: number, availableHeight: number): number;
739
1118
  /**
740
1119
  * Calculate coupler slot spacing
1120
+ *
1121
+ * Alias for calculateCouplerSpacing. Calculates spacing between coupler slots.
1122
+ *
1123
+ * @param numCouplers - Number of couplers to space
1124
+ * @param couplerHeight - Height of each coupler in pixels
1125
+ * @param availableHeight - Total available height in pixels
1126
+ * @returns Spacing between coupler slots in pixels
1127
+ * @public
741
1128
  */
742
1129
  declare function calculateCouplerSlotSpacing(numCouplers: number, couplerHeight: number, availableHeight: number): number;
743
1130
 
@@ -783,10 +1170,57 @@ interface DevicePlacementValidation {
783
1170
  }
784
1171
  /**
785
1172
  * Validate device placements within a rack schema
1173
+ *
1174
+ * Checks for out-of-bounds placements and device-to-device conflicts.
1175
+ * Uses the generic validatePlacements utility for consistent validation logic.
1176
+ *
1177
+ * @param rack - The rack configuration to validate
1178
+ * @param _options - Validation options (currently unused)
1179
+ * @returns Validation result with conflicts and out-of-bounds errors
1180
+ * @public
1181
+ *
1182
+ * @example
1183
+ * ```ts
1184
+ * const rack: RackConfig = {
1185
+ * id: 'rack-1',
1186
+ * units: 42,
1187
+ * devices: [
1188
+ * { id: 'dev-1', unit: 1, height: 2, ... },
1189
+ * { id: 'dev-2', unit: 2, height: 1, ... } // Conflicts with dev-1
1190
+ * ]
1191
+ * };
1192
+ * const result = validateRackDevicePlacements(rack);
1193
+ * if (!result.isValid) {
1194
+ * console.log('Conflicts:', result.conflicts);
1195
+ * }
1196
+ * ```
786
1197
  */
787
1198
  declare function validateRackDevicePlacements(rack: RackConfig, _options?: RackSchemaOptions): DevicePlacementValidation;
788
1199
  /**
789
1200
  * Build NetworkNode array from RackConfig array with comprehensive validation
1201
+ *
1202
+ * Converts rack configurations to React Flow nodes with automatic validation
1203
+ * and conflict resolution. Supports strict and nearest conflict policies.
1204
+ *
1205
+ * @param racks - Array of rack configurations
1206
+ * @param options - Build options including conflict policy and validation settings
1207
+ * @returns Array of NetworkNode objects ready for React Flow
1208
+ * @throws {DevicePlacementError} If validation fails in strict mode
1209
+ * @public
1210
+ *
1211
+ * @example
1212
+ * ```ts
1213
+ * const racks: RackConfig[] = [{
1214
+ * id: 'rack-1',
1215
+ * name: 'Main Rack',
1216
+ * units: 42,
1217
+ * devices: [...]
1218
+ * }];
1219
+ * const nodes = buildNodesFromRackConfig(racks, {
1220
+ * conflictPolicy: 'strict',
1221
+ * validatePlacements: true
1222
+ * });
1223
+ * ```
790
1224
  */
791
1225
  declare function buildNodesFromRackConfig(racks: RackConfig[], options?: RackSchemaOptions): NetworkNode[];
792
1226
  /**
@@ -843,10 +1277,55 @@ interface SplicePlacementValidation {
843
1277
  }
844
1278
  /**
845
1279
  * Validate splice placements within a tray schema
1280
+ *
1281
+ * Checks for out-of-bounds placements and splice-to-splice conflicts.
1282
+ * Uses the generic validatePlacements utility for consistent validation logic.
1283
+ *
1284
+ * @param tray - The splice tray configuration to validate
1285
+ * @param _options - Validation options (currently unused)
1286
+ * @returns Validation result with conflicts and out-of-bounds errors
1287
+ * @public
1288
+ *
1289
+ * @example
1290
+ * ```ts
1291
+ * const tray: SpliceTrayConfig = {
1292
+ * id: 'tray-1',
1293
+ * splices: [
1294
+ * { id: 'splice-1', holder: 1, ... },
1295
+ * { id: 'splice-2', holder: 1, ... } // Conflicts with splice-1
1296
+ * ]
1297
+ * };
1298
+ * const result = validateSplicePlacements(tray);
1299
+ * if (!result.isValid) {
1300
+ * console.log('Conflicts:', result.conflicts);
1301
+ * }
1302
+ * ```
846
1303
  */
847
1304
  declare function validateSplicePlacements(tray: SpliceTrayConfig, _options?: SpliceSchemaOptions): SplicePlacementValidation;
848
1305
  /**
849
1306
  * Build NetworkNode array from SpliceTrayConfig array with comprehensive validation
1307
+ *
1308
+ * Converts splice tray configurations to React Flow nodes with automatic validation
1309
+ * and conflict resolution. Supports strict and nearest conflict policies.
1310
+ *
1311
+ * @param trays - Array of splice tray configurations
1312
+ * @param options - Build options including conflict policy and validation settings
1313
+ * @returns Array of NetworkNode objects ready for React Flow
1314
+ * @throws {SplicePlacementError} If validation fails in strict mode
1315
+ * @public
1316
+ *
1317
+ * @example
1318
+ * ```ts
1319
+ * const trays: SpliceTrayConfig[] = [{
1320
+ * id: 'tray-1',
1321
+ * name: 'Tray 1',
1322
+ * splices: [...]
1323
+ * }];
1324
+ * const nodes = buildNodesFromSpliceConfig(trays, {
1325
+ * conflictPolicy: 'strict',
1326
+ * validatePlacements: true
1327
+ * });
1328
+ * ```
850
1329
  */
851
1330
  declare function buildNodesFromSpliceConfig(trays: SpliceTrayConfig[], options?: SpliceSchemaOptions): NetworkNode[];
852
1331
  /**
@@ -995,6 +1474,15 @@ declare function findNearestRack(point: {
995
1474
  y: number;
996
1475
  }, racks: NetworkNode[]): NetworkNode | null;
997
1476
 
1477
+ declare const U_HEIGHT_PX = 20;
1478
+ declare const RACK_HEADER_HEIGHT = 60;
1479
+ declare const RACK_WIDTH_PX = 300;
1480
+ /**
1481
+ * Handle extension in pixels - handles extend this many pixels outside nodes
1482
+ * Used in dimension calculations for panels and closures
1483
+ */
1484
+ declare const HANDLE_EXTENSION_PX = 5;
1485
+
998
1486
  /**
999
1487
  * Options for replacing an edge in the edges array
1000
1488
  */
@@ -1054,4 +1542,4 @@ declare function useNetworkDiagram(store: NetworkDiagramStore): NetworkDiagramSt
1054
1542
  declare function useNodes(store: NetworkDiagramStore): NetworkNode[];
1055
1543
  declare function useEdges(store: NetworkDiagramStore): NetworkEdge[];
1056
1544
 
1057
- export { COUPLERS_PER_PANEL, COUPLER_SLOT_HEIGHT_PX, COUPLER_WIDTH_PX, CableNode, ClosureNode, CouplerNode, DeviceNode, DevicePlacementError, type DevicePlacementValidation, FIBER_COLORS_12, type FiberCable, type FiberColorId, FiberEdge, FiberNode, FibreSplitNode, MultiTubeCableNode, NetworkDiagram, type NetworkDiagramProps, type NetworkEdge, type NetworkNode, PANEL_BORDER_WIDTH, PANEL_HEADER_HEIGHT, PANEL_HEIGHT_PX, PANEL_PADDING, PANEL_TUBE_TRAY_SPACING, PANEL_WIDTH_PX, POWER_CONNECTORS, PatchPanelNode, type Port, type PortBlock, type PortType, PowerEdge, type RackConfig, type RackDevice, RackNode, type RackSchemaOptions, type ReplaceEdgeOptions, type SpliceConfig, SpliceNode, SplicePlacementError, type SplicePlacementValidation, type SpliceSchemaOptions, type SpliceTrayConfig, SpliceTrayNode, TubeNode, VerticalPDU, Width, addDeviceToRack, addSpliceToTray, baseColorFor, buildNodesFromRackConfig, buildNodesFromSpliceConfig, calculateCouplerRightX, calculateCouplerSlotSpacing, calculateCouplerSpacing, calculateDevicePositionFromU, calculatePanelDimensions, calculateSlotPositionFromY, calculateSplicePositionFromNumber, calculateYFromSlotPosition, createNetworkDiagramStore, createRackConfigFromNodes, createSpliceConfigFromNodes, fiberSolidOrStriped, findNearestRack, findNextAvailableHolderPosition, findNextAvailableUPosition, generateLayout, getConnectorConfig, getCouplerDimensions, getDeviceConnectorType, getFiberColor, getInnerContentWidth, getPDUPortType, getPanelHeight, getPanelWidth, getPowerPortStyle, getRackBounds, getStatusColor, getTrayDimensions, getTubeDimensions, inventoryCableToNetworkEdge, inventoryDeviceToNetworkNode, inventoryRackToNetworkNode, inventoryToNetworkDiagram, isHighPowerConnector, isPointInRack, isStriped, isUPositionAvailable, removeDeviceFromRack, removeSpliceFromTray, replaceEdge, snapToCouplerPosition, snapToSplicePosition, snapToUPosition, updateDeviceUPosition$1 as updateDeviceUPosition, updateDeviceUPosition as updateDeviceUPositionInSchema, updateSpliceHolderPosition, useEdges as useDiagramEdges, useNodes as useDiagramNodes, useNetworkDiagram, validateAndSnapDevice, validateRackDevicePlacements, validateSplicePlacements };
1545
+ export { COUPLERS_PER_PANEL, COUPLER_SLOT_HEIGHT_PX, COUPLER_WIDTH_PX, CableNode, ClosureNode, CouplerNode, DeviceNode, DevicePlacementError, type DevicePlacementValidation, DiagramErrorBoundary, type DiagramErrorBoundaryProps, FIBER_COLORS_12, type FiberCable, type FiberColorId, FiberEdge, FiberNode, FibreCableWithTubesExpanded, type FibreFlowCable, type FibreFlowCableKind, type FibreFlowCircuit, type FibreFlowClosure, type FibreFlowEndpoint, FibreFlowMap, type FibreFlowMapProps, type FibreFlowSplice, FibreSplitNode, HANDLE_EXTENSION_PX, MultiTubeCableNode, NetworkDiagram, type NetworkDiagramProps, type NetworkEdge, type NetworkNode, PANEL_BORDER_WIDTH, PANEL_HEADER_HEIGHT, PANEL_HEIGHT_PX, PANEL_PADDING, PANEL_TUBE_TRAY_SPACING, PANEL_WIDTH_PX, POWER_CONNECTORS, PatchPanelNode, type Port, type PortBlock, type PortType, PowerEdge, RACK_HEADER_HEIGHT, RACK_WIDTH_PX, type RackConfig, type RackDevice, RackNode, type RackSchemaOptions, type ReplaceEdgeOptions, type SpliceConfig, SpliceNode, SplicePlacementError, type SplicePlacementValidation, type SpliceSchemaOptions, type SpliceTrayConfig, SpliceTrayNode, TubeNode, U_HEIGHT_PX, VerticalPDU, Width, addDeviceToRack, addSpliceToTray, baseColorFor, buildNodesFromRackConfig, buildNodesFromSpliceConfig, calculateCouplerRightX, calculateCouplerSlotSpacing, calculateCouplerSpacing, calculateDevicePositionFromU, calculatePanelDimensions, calculateSlotPositionFromY, calculateSplicePositionFromNumber, calculateYFromSlotPosition, createNetworkDiagramStore, createRackConfigFromNodes, createSpliceConfigFromNodes, fiberSolidOrStriped, findNearestRack, findNextAvailableHolderPosition, findNextAvailableUPosition, generateLayout, getConnectorConfig, getCouplerDimensions, getDeviceConnectorType, getFiberColor, getInnerContentWidth, getPDUPortType, getPanelHeight, getPanelWidth, getPowerPortStyle, getRackBounds, getStatusColor, getTrayDimensions, getTubeDimensions, inventoryCableToNetworkEdge, inventoryDeviceToNetworkNode, inventoryRackToNetworkNode, inventoryToNetworkDiagram, isHighPowerConnector, isPointInRack, isStriped, isUPositionAvailable, removeDeviceFromRack, removeSpliceFromTray, replaceEdge, snapToCouplerPosition, snapToSplicePosition, snapToUPosition, updateDeviceUPosition$1 as updateDeviceUPosition, updateDeviceUPosition as updateDeviceUPositionInSchema, updateSpliceHolderPosition, useEdges as useDiagramEdges, useNodes as useDiagramNodes, useNetworkDiagram, validateAndSnapDevice, validateRackDevicePlacements, validateSplicePlacements };