@mp70/react-networks 0.6.0 → 0.7.0

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.
@@ -0,0 +1,1449 @@
1
+ import { Node, Connection, NodeTypes, EdgeTypes, Edge, ConnectionMode, ReactFlowInstance, Viewport, FitViewOptions } from 'reactflow';
2
+
3
+ type FibreFlowCableKind = 'simple' | 'tube';
4
+ interface FibreFlowEndpoint {
5
+ tube?: number;
6
+ fiber: number;
7
+ }
8
+ interface FibreFlowSplice {
9
+ id: string;
10
+ from: FibreFlowEndpoint;
11
+ to: FibreFlowEndpoint;
12
+ lossDb?: number;
13
+ circuitId?: string;
14
+ label?: string;
15
+ color?: string;
16
+ }
17
+ interface FibreFlowCable {
18
+ id: string;
19
+ label: string;
20
+ kind?: FibreFlowCableKind;
21
+ fiberCount?: number;
22
+ tubeCount?: number;
23
+ fibersPerTube?: number;
24
+ tubeStartIndex?: number;
25
+ fiberStartIndex?: number;
26
+ tubeColorMap?: Record<number, string>;
27
+ jacketColor?: string;
28
+ distanceLabel?: string;
29
+ distanceMeters?: number;
30
+ }
31
+ interface FibreFlowClosure {
32
+ id: string;
33
+ chamberId?: string;
34
+ leftCable: FibreFlowCable;
35
+ rightCable: FibreFlowCable;
36
+ splices: FibreFlowSplice[];
37
+ }
38
+ interface FibreFlowCircuit {
39
+ id: string;
40
+ label: string;
41
+ color?: string;
42
+ }
43
+
44
+ /**
45
+ * Rack device width configuration
46
+ * @public
47
+ */
48
+
49
+ declare enum Width {
50
+ /** Full width device (19" rack width) */
51
+ FULL = "full",
52
+ /** Half width device (9.5" rack width) */
53
+ HALF = "half"
54
+ }
55
+ /**
56
+ * Port configuration for network devices
57
+ * @public
58
+ */
59
+ /**
60
+ * Port type enumeration
61
+ * @public
62
+ */
63
+ type PortType = "ethernet" | "rj45" | "fiber" | "console" | "mgmt" | "usb" | "power_ac" | "power_c13" | "power_c19";
64
+ /**
65
+ * Cable types used for connected network ports.
66
+ * @public
67
+ */
68
+ type PortCableType = "smf" | "cat6" | "om3" | "om4" | "om5" | "cat5e" | "cat6a" | "cat7" | "fiber" | "ethernet";
69
+ /**
70
+ * Device image fit options.
71
+ *
72
+ * Values mirror object-fit terms for API ergonomics and are mapped to valid
73
+ * background-size values by renderers where needed.
74
+ *
75
+ * @public
76
+ */
77
+ type DeviceImageFit = "cover" | "contain" | "contain-height" | "fill" | "none" | "scale-down";
78
+ /**
79
+ * Device image repeat options.
80
+ * @public
81
+ */
82
+ type DeviceImageRepeat = "no-repeat" | "repeat" | "repeat-x" | "repeat-y";
83
+ /**
84
+ * Shared image configuration for rack-mounted devices and device nodes.
85
+ * @public
86
+ */
87
+ interface DeviceImageOptions {
88
+ /** Optional front image URL for device background (PNG, SVG, JPEG, etc.) */
89
+ frontImageUrl?: string;
90
+ /** Optional rear image URL for device background (PNG, SVG, JPEG, etc.) */
91
+ rearImageUrl?: string;
92
+ /** Optional attribution URL for front image (e.g. source/license link) */
93
+ frontImageAttribution?: string;
94
+ /** Optional attribution URL for rear image (e.g. source/license link) */
95
+ rearImageAttribution?: string;
96
+ /** Optional background sizing for device images */
97
+ imageFit?: DeviceImageFit;
98
+ /** Optional background position for device images */
99
+ imagePosition?: string;
100
+ /** Optional background repeat for device images */
101
+ imageRepeat?: DeviceImageRepeat;
102
+ /** When true, stretch device image to fill the device bounds (overrides imageFit) */
103
+ stretchToFit?: boolean;
104
+ }
105
+ /**
106
+ * Explicit handle placement for a device/PDU port.
107
+ * @public
108
+ */
109
+ interface PortPosition {
110
+ /** Handle side on the node */
111
+ side?: "top" | "right" | "bottom" | "left";
112
+ /** Side offset as percentage (0-100) */
113
+ offsetPercent?: number;
114
+ /** Side offset in pixels */
115
+ offsetPx?: number;
116
+ /** Absolute X position as percentage (0-100) */
117
+ xPercent?: number;
118
+ /** Absolute Y position as percentage (0-100) */
119
+ yPercent?: number;
120
+ /** Authored port width as a percentage of the rendered image frame */
121
+ widthPercent?: number;
122
+ /** Authored port height as a percentage of the rendered image frame */
123
+ heightPercent?: number;
124
+ }
125
+ /**
126
+ * Recommended simple port input for device and PDU rendering.
127
+ * Pass a flat array in `ports`; `react-networks` groups entries into front/rear
128
+ * `PortBlock[]` internally using each port's `face` and `group`.
129
+ * @public
130
+ */
131
+ interface DevicePort {
132
+ /** Stable handle identifier override (defaults to `group + label`, or `label` for power) */
133
+ id?: string;
134
+ /** Display label for the port */
135
+ label: string;
136
+ /** Front/rear device face. `back` is accepted as an alias for `rear`. */
137
+ face?: DeviceFace | "back";
138
+ /** Optional block/group name (for example `Network Ports`, `QSFP28`, `Power Ports`) */
139
+ group?: string;
140
+ /** Optional source/detected family label used for visual kind inference */
141
+ sourceTypeLabel?: string;
142
+ /** Whether the port is currently connected */
143
+ connected?: boolean;
144
+ /** Type of port for styling and validation */
145
+ type?: PortType;
146
+ /** Cable type for connection validation */
147
+ cableType?: PortCableType;
148
+ /** Optional power connector type for rendering (mainly for PDU ports) */
149
+ connectorType?: "C13" | "C14" | "C19" | "C20";
150
+ /** Optional compatibility keys. When omitted, defaults are derived from type/cable/connector data. */
151
+ compatibility?: string[];
152
+ /** Optional sort order within a face/group bucket */
153
+ order?: number;
154
+ /**
155
+ * Optional placement hint.
156
+ * Use `side` with `offsetPercent`/`offsetPx` for edge-anchored placement,
157
+ * or `xPercent`/`yPercent` for exact coordinates.
158
+ */
159
+ position?: PortPosition;
160
+ }
161
+ interface Port {
162
+ /** Stable handle identifier override (defaults to `label`) */
163
+ id?: string;
164
+ /** Display label for the port */
165
+ label: string;
166
+ /** Optional source/detected family label used for visual kind inference */
167
+ sourceTypeLabel?: string;
168
+ /** Whether the port is currently connected */
169
+ connected: boolean;
170
+ /** Type of port for styling and validation */
171
+ type?: PortType;
172
+ /** Cable type for connection validation */
173
+ cableType?: PortCableType;
174
+ /** Optional power connector type for rendering (mainly for PDU ports) */
175
+ connectorType?: "C13" | "C14" | "C19" | "C20";
176
+ /** Optional compatibility keys. When omitted, defaults are derived from type/cable/connector data. */
177
+ compatibility?: string[];
178
+ /** Optional explicit handle placement */
179
+ position?: PortPosition;
180
+ }
181
+ /**
182
+ * Group of related ports on a device
183
+ * @public
184
+ */
185
+ interface PortBlock {
186
+ /** Name of the port group */
187
+ name: string;
188
+ /** Array of ports in this group */
189
+ ports: Port[];
190
+ }
191
+ /**
192
+ * Network node types supported by the diagram
193
+ * @public
194
+ */
195
+ 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";
196
+ /**
197
+ * Device status states
198
+ * @public
199
+ */
200
+ type DeviceStatus = "active" | "inactive" | "maintenance";
201
+ /**
202
+ * Device face orientations
203
+ * @public
204
+ */
205
+ type DeviceFace = "front" | "rear";
206
+ type DiagramPortHandleRef = {
207
+ nodeId: string;
208
+ handleId: string;
209
+ };
210
+ type DiagramPortClickPayload = {
211
+ nodeId: string;
212
+ handleId: string;
213
+ groupName: string;
214
+ portLabel: string;
215
+ face: DeviceFace;
216
+ };
217
+ /**
218
+ * Rack rendering layout modes.
219
+ * @public
220
+ */
221
+ type RackLayoutMode = "single-face" | "split-face";
222
+ /**
223
+ * Rack mounting behavior for a device.
224
+ * @public
225
+ */
226
+ type RackMountMode = "front" | "rear" | "both";
227
+ /**
228
+ * Power port side configuration
229
+ * @public
230
+ */
231
+ type PowerSide = "left" | "right";
232
+ /**
233
+ * U numbering direction for racks
234
+ * @public
235
+ */
236
+ type UNumberingDirection = "bottom-up" | "top-down";
237
+ /**
238
+ * Shared node data fields available across node types.
239
+ * Specific node kinds can narrow these fields via `NetworkNodeDataByType`.
240
+ * @public
241
+ */
242
+ interface NetworkNodeDataBase extends DeviceImageOptions {
243
+ /** Display label for the node */
244
+ label: string;
245
+ /** Current status of the node/device */
246
+ status?: DeviceStatus | string;
247
+ /** Simple flat port input or grouped port blocks. Use `portGroups` / `rearPortGroups` for explicit grouped control. */
248
+ ports?: DevicePort[] | PortBlock[] | number;
249
+ /** Advanced grouped front port input */
250
+ portGroups?: PortBlock[];
251
+ /** Advanced grouped rear port input */
252
+ rearPortGroups?: PortBlock[];
253
+ /** Grouped rear port blocks (rack JSON alias for `rearPortGroups`) */
254
+ rearPorts?: PortBlock[];
255
+ /** List of connected node IDs */
256
+ connections?: string[];
257
+ /** NetBox integration ID */
258
+ netboxId?: number | string;
259
+ /** NetBox object type */
260
+ netboxType?: "device" | "rack" | "interface" | "cable" | string;
261
+ /** Inventory integration ID */
262
+ inventoryId?: number | string;
263
+ /** Inventory object type */
264
+ inventoryType?: "device" | "rack" | "interface" | "cable" | string;
265
+ /** Rack height in U units */
266
+ uHeight?: number;
267
+ /** Device position within rack in U units */
268
+ uPosition?: number;
269
+ /** Whether this node is currently mounted inside a rack container */
270
+ isRackMounted?: boolean;
271
+ /** Front/rear orientation for devices and rack faces */
272
+ face?: DeviceFace;
273
+ /** Rack rendering layout mode */
274
+ rackLayout?: RackLayoutMode;
275
+ /** Gap in pixels between front and rear faces in split-face mode */
276
+ rackFaceGapPx?: number;
277
+ /** Device mount behavior within a rack */
278
+ mountMode?: RackMountMode;
279
+ /** Device type specification */
280
+ deviceType?: string;
281
+ /**
282
+ * When false, device elevation renders as a status-colored block without front/rear photos.
283
+ * Defaults to true (show photos when URLs exist).
284
+ */
285
+ showDeviceImages?: boolean;
286
+ /** Device manufacturer */
287
+ manufacturer?: string;
288
+ /** Device role in network */
289
+ role?: string;
290
+ /** Device width configuration */
291
+ width?: Width | number;
292
+ /** Power port side for rear face */
293
+ powerSide?: PowerSide;
294
+ /** Vertical PDU height in centimeters */
295
+ heightCm?: number;
296
+ /** Number of AC power ports */
297
+ powerPorts?: number;
298
+ /** Optional explicit PDU connector sequence */
299
+ portTypes?: Array<"C13" | "C19">;
300
+ /** Optional grouped PDU ports (supports custom positions/types) */
301
+ pduPortGroups?: PortBlock[];
302
+ /** Vertical PDU width in pixels */
303
+ widthPx?: number;
304
+ /** Optional management unit position for vertical PDUs */
305
+ mgmt_unit?: "top" | "middle" | "bottom";
306
+ /** U numbering direction for rack nodes */
307
+ uNumberingDirection?: UNumberingDirection;
308
+ /** Custom header text for rack nodes */
309
+ customHeaderText?: string;
310
+ /** Rack UI marker visibility */
311
+ showUMarkers?: boolean;
312
+ /** Holder position within tray (1-12) for splice nodes */
313
+ holderPosition?: number;
314
+ /** Loss value in dB for splice nodes */
315
+ lossDb?: number;
316
+ /** Splice mode */
317
+ mode?: "single" | "ribbon";
318
+ /** Legacy ribbon flag */
319
+ ribbon?: boolean;
320
+ /** Ribbon fiber IDs */
321
+ ribbonFiberIds?: number[];
322
+ /** Connector type for coupler nodes */
323
+ connector?: "SC" | "LC";
324
+ /** Number of fibers for coupler nodes (1, 2, or 4) */
325
+ couplerFiberCount?: 1 | 2 | 4;
326
+ /** Optional port labels for left side of coupler */
327
+ portLabelsLeft?: string[];
328
+ /** Optional port labels for right side of coupler */
329
+ portLabelsRight?: string[];
330
+ /** Slot position for couplers inside panels (1-based, vertical slots aligned to right edge) */
331
+ slotPosition?: number;
332
+ /** Width override for panel-like container nodes */
333
+ panelWidth?: number;
334
+ /** Height override for panel-like container nodes */
335
+ panelHeight?: number;
336
+ /** Width override for closure nodes */
337
+ closureWidth?: number;
338
+ /** Height override for closure nodes */
339
+ closureHeight?: number;
340
+ /** Optional rack width in pixels (for rack nodes, default: 300px) */
341
+ rackWidthPx?: number;
342
+ /** Number of rows for container nodes (patch-panel, closure) */
343
+ rows?: number;
344
+ /** Number of columns for container nodes (patch-panel, closure) */
345
+ cols?: number;
346
+ /** Number of trays for closure nodes */
347
+ trayCount?: number;
348
+ /** Header text for container nodes */
349
+ header?: string;
350
+ /** Type of fibre splitter: 'splitter' or 'WDM' (default: 'splitter') */
351
+ splitterType?: "splitter" | "WDM";
352
+ /** Number of input fibers on the left (1 or 2, default: 1) */
353
+ inputCount?: number;
354
+ /** Number of output fibers on the right (1-64, default: 8) */
355
+ outputCount?: number;
356
+ /** Tube index (1-based) */
357
+ tubeIndex?: number;
358
+ /** Tube count for multi-tube cables */
359
+ tubeCount?: number;
360
+ /** Tube start index for multi-tube cables */
361
+ tubeStartIndex?: number;
362
+ /** Number of fibers per tube */
363
+ fibersPerTube?: number;
364
+ /** Total fiber count for cables */
365
+ fiberCount?: number;
366
+ /** Cable identifier */
367
+ cableId?: string;
368
+ /** Primary node color override */
369
+ color?: string;
370
+ /** Rotation in degrees for rotatable nodes */
371
+ rotation?: number;
372
+ /** Tube handle orientation */
373
+ startOn?: "left-center" | "left" | "right";
374
+ /** Rack metadata for integrations */
375
+ facilityId?: string | number | null;
376
+ /** Rack serial metadata */
377
+ serial?: string | null;
378
+ /** Asset tag metadata */
379
+ assetTag?: string | null;
380
+ /** Site metadata */
381
+ site?: string;
382
+ /** Tenant metadata */
383
+ tenant?: string;
384
+ /** Primary IPv4 metadata */
385
+ primaryIp4?: string;
386
+ /** Primary IPv6 metadata */
387
+ primaryIp6?: string;
388
+ /** Rack name metadata */
389
+ rack?: string | number | null;
390
+ /** Optional arrays used by inventory/netbox transforms */
391
+ racks?: unknown[];
392
+ devices?: unknown[];
393
+ cables?: unknown[];
394
+ /** UI color mode metadata */
395
+ colorMode?: "light" | "dark" | "system";
396
+ /** Generic dimensions used by some helpers */
397
+ height?: number;
398
+ headerHeight?: number;
399
+ /** Optional precomputed map for handle-to-face resolution */
400
+ handleSideMap?: Record<string, DeviceFace>;
401
+ /** Additional extension metadata */
402
+ metadata?: Record<string, unknown>;
403
+ }
404
+ /**
405
+ * Rack node data.
406
+ * @public
407
+ */
408
+ interface RackNodeData extends NetworkNodeDataBase {
409
+ ports?: number;
410
+ }
411
+ /**
412
+ * Device-like node data (servers/switches/routers/generic device).
413
+ * @public
414
+ */
415
+ interface DeviceNodeData extends NetworkNodeDataBase {
416
+ ports?: DevicePort[] | PortBlock[] | number;
417
+ }
418
+ /**
419
+ * Fibre flow cable node data.
420
+ * @public
421
+ */
422
+ interface FibreFlowCableNodeData extends NetworkNodeDataBase {
423
+ cable: FibreFlowCable;
424
+ side: "left" | "right";
425
+ rowHeight: number;
426
+ columnWidth: number;
427
+ showTubeLabels: boolean;
428
+ showFiberNumbers: boolean;
429
+ layout: unknown;
430
+ colorMode?: "dark" | "light";
431
+ }
432
+ /**
433
+ * Fibre flow closure node data.
434
+ * @public
435
+ */
436
+ interface FibreFlowClosureNodeData extends NetworkNodeDataBase {
437
+ width?: number;
438
+ height?: number;
439
+ headerHeight?: number;
440
+ colorMode?: "dark" | "light";
441
+ }
442
+ /**
443
+ * Mapping from node type to corresponding data type.
444
+ * @public
445
+ */
446
+ interface NetworkNodeDataByType {
447
+ rack: RackNodeData;
448
+ switch: DeviceNodeData;
449
+ router: DeviceNodeData;
450
+ server: DeviceNodeData;
451
+ fiber: NetworkNodeDataBase;
452
+ "patch-panel": NetworkNodeDataBase;
453
+ device: DeviceNodeData;
454
+ "vertical-pdu": NetworkNodeDataBase;
455
+ splice: NetworkNodeDataBase;
456
+ "splice-tray": NetworkNodeDataBase;
457
+ tube: NetworkNodeDataBase;
458
+ cable: NetworkNodeDataBase;
459
+ "multi-tube-cable": NetworkNodeDataBase;
460
+ coupler: NetworkNodeDataBase;
461
+ closure: NetworkNodeDataBase;
462
+ "fibre-split": NetworkNodeDataBase;
463
+ "fibre-flow-cable": FibreFlowCableNodeData;
464
+ "fibre-flow-closure": FibreFlowClosureNodeData;
465
+ }
466
+ /**
467
+ * Union of all node data variants.
468
+ * @public
469
+ */
470
+ type NetworkNodeData = NetworkNodeDataByType[NetworkNodeType];
471
+ /**
472
+ * Network node structure with data discriminated by `type`.
473
+ * @public
474
+ */
475
+ type NetworkNode<TType extends NetworkNodeType = NetworkNodeType, TExtra = unknown> = TType extends NetworkNodeType ? Node<NetworkNodeDataByType[TType] & TExtra, TType> & {
476
+ /** Type of network node */
477
+ type: TType;
478
+ /** Node data and configuration */
479
+ data: NetworkNodeDataByType[TType] & TExtra;
480
+ } : never;
481
+ /**
482
+ * Network edge types
483
+ * @public
484
+ */
485
+ type NetworkEdgeType = "fiber" | "ethernet" | "power" | "smoothstep" | "step" | "thick-cable" | "fibre-flow" | "fibre-flow-link";
486
+ /**
487
+ * Edge data payload.
488
+ * @public
489
+ */
490
+ interface NetworkEdgeData {
491
+ /** Connection bandwidth */
492
+ bandwidth?: string;
493
+ /** Cable length */
494
+ length?: number;
495
+ /** Edge color for styling */
496
+ color?: string;
497
+ /** Edge kind for styling/validation */
498
+ kind?: "fiber" | "power" | "network";
499
+ /** Whether this edge represents a ribbon fiber connection */
500
+ isRibbon?: boolean;
501
+ /** Array of fiber IDs for ribbon mode (6-12 fibers) */
502
+ ribbonFiberIds?: number[];
503
+ /** Highlight edge with a pulsing stroke */
504
+ highlight?: boolean;
505
+ /** Override highlight color (defaults to edge color) */
506
+ highlightColor?: string;
507
+ /** Override highlight max stroke width */
508
+ highlightWidth?: number;
509
+ /** Optional tag for grouping edges in demos */
510
+ traceTag?: string;
511
+ /** Legacy striped edge flag */
512
+ striped?: boolean;
513
+ /** Cable type metadata used by demos/helpers */
514
+ cableType?: PortCableType;
515
+ /** NetBox integration metadata */
516
+ netboxId?: number | string;
517
+ netboxType?: "device" | "rack" | "interface" | "cable" | string;
518
+ /** Inventory integration metadata */
519
+ inventoryId?: number | string;
520
+ inventoryType?: "device" | "rack" | "interface" | "cable" | string;
521
+ /** Status metadata */
522
+ status?: string;
523
+ /** Endpoint metadata */
524
+ terminationA?: string;
525
+ terminationB?: string;
526
+ /** Optional display label for the edge */
527
+ label?: string;
528
+ /** Optional opacity for styling (0–1) */
529
+ opacity?: number;
530
+ /** Optional power edge stroke width override */
531
+ powerStrokeWidth?: number;
532
+ /** Optional power edge stroke dasharray override */
533
+ powerStrokeDasharray?: string;
534
+ /** Optional power edge opacity override (0–1) */
535
+ powerOpacity?: number;
536
+ /** Additional extension metadata */
537
+ metadata?: Record<string, unknown>;
538
+ }
539
+ /**
540
+ * Network edge data structure
541
+ * @public
542
+ */
543
+ type NetworkEdge<TData extends NetworkEdgeData = NetworkEdgeData> = {
544
+ /** Unique identifier for the edge */
545
+ id: string;
546
+ /** Source node ID */
547
+ source: string;
548
+ /** Target node ID */
549
+ target: string;
550
+ /** Source handle/port ID */
551
+ sourceHandle?: string;
552
+ /** Target handle/port ID */
553
+ targetHandle?: string;
554
+ /** Type of network connection */
555
+ type?: NetworkEdgeType;
556
+ /** Whether the edge should be hidden from rendering */
557
+ hidden?: boolean;
558
+ /** Edge data and configuration */
559
+ data?: TData;
560
+ };
561
+ /**
562
+ * Canonical persisted/editor document schema independent from React Flow handle ids.
563
+ * Prefer this model for saving diagrams, syncing external systems, and controlled
564
+ * document-mode usage via `document` / `onDocumentChange`.
565
+ * @public
566
+ */
567
+ interface DiagramDocument {
568
+ nodes: DiagramNode[];
569
+ edges: DiagramEdge[];
570
+ ui?: DiagramUiState;
571
+ metadata?: Record<string, unknown>;
572
+ }
573
+ /**
574
+ * Node kinds used by the document model.
575
+ * @public
576
+ */
577
+ type DiagramNodeKind = "rack" | "equipment" | "pdu" | "fiber" | "tube" | "cable" | "multi-tube-cable" | "splice" | "coupler" | "splitter" | "container" | "fibre-flow-cable" | "fibre-flow-closure";
578
+ /**
579
+ * Placement data for document nodes.
580
+ * @public
581
+ */
582
+ interface DiagramNodePlacement {
583
+ position: {
584
+ x: number;
585
+ y: number;
586
+ };
587
+ parentId?: string;
588
+ extent?: "parent";
589
+ rack?: {
590
+ uPosition?: number;
591
+ mountMode?: RackMountMode;
592
+ rackLayout?: RackLayoutMode;
593
+ rackWidthPx?: number;
594
+ rackFaceGapPx?: number;
595
+ };
596
+ container?: {
597
+ slotPosition?: number;
598
+ holderPosition?: number;
599
+ };
600
+ }
601
+ /**
602
+ * Endpoint definition for document nodes.
603
+ * @public
604
+ */
605
+ interface DiagramEndpoint {
606
+ id: string;
607
+ label: string;
608
+ face?: DeviceFace | "internal";
609
+ group?: string;
610
+ role?: "network" | "power" | "fiber" | "tube" | "splice" | "coupler" | "splitter" | "cable" | "generic";
611
+ medium?: "ethernet" | "fiber" | "power" | "tube" | "generic";
612
+ type?: PortType;
613
+ cableType?: PortCableType;
614
+ connector?: string;
615
+ compatibility?: string[];
616
+ layout?: PortPosition;
617
+ }
618
+ /**
619
+ * Render-focused node data for the document model.
620
+ * @public
621
+ */
622
+ interface DiagramNodeRender {
623
+ status?: DeviceStatus | string;
624
+ face?: DeviceFace;
625
+ width?: Width | number;
626
+ widthPx?: number;
627
+ height?: number;
628
+ header?: string;
629
+ color?: string;
630
+ colorMode?: "light" | "dark" | "system";
631
+ rackWidthPx?: number;
632
+ rackFaceGapPx?: number;
633
+ images?: DeviceImageOptions;
634
+ dimensions?: Record<string, number | undefined>;
635
+ showUMarkers?: boolean;
636
+ customHeaderText?: string;
637
+ powerSide?: PowerSide;
638
+ rotation?: number;
639
+ }
640
+ /**
641
+ * External reference attached to a document node.
642
+ * @public
643
+ */
644
+ interface DiagramExternalRef {
645
+ source: "netbox" | "inventory" | string;
646
+ id: string | number;
647
+ type?: string;
648
+ metadata?: Record<string, unknown>;
649
+ }
650
+ /**
651
+ * Document node.
652
+ * @public
653
+ */
654
+ interface DiagramNode {
655
+ id: string;
656
+ kind: DiagramNodeKind;
657
+ subtype?: string;
658
+ label: string;
659
+ placement: DiagramNodePlacement;
660
+ endpoints?: DiagramEndpoint[];
661
+ render?: DiagramNodeRender;
662
+ config?: Record<string, unknown>;
663
+ externalRefs?: DiagramExternalRef[];
664
+ metadata?: Record<string, unknown>;
665
+ }
666
+ /**
667
+ * Endpoint reference used by document edges.
668
+ * @public
669
+ */
670
+ interface DiagramEdgeEndpoint {
671
+ nodeId: string;
672
+ endpointId?: string | null;
673
+ }
674
+ /**
675
+ * Document edge.
676
+ * @public
677
+ */
678
+ interface DiagramEdge {
679
+ id: string;
680
+ source: DiagramEdgeEndpoint;
681
+ target: DiagramEdgeEndpoint;
682
+ type?: NetworkEdgeType;
683
+ hidden?: boolean;
684
+ data?: NetworkEdgeData;
685
+ metadata?: Record<string, unknown>;
686
+ }
687
+ /**
688
+ * Non-topology UI state stored alongside a document.
689
+ * @public
690
+ */
691
+ interface DiagramUiState {
692
+ nodeState?: Record<string, {
693
+ face?: DeviceFace;
694
+ handleSideMap?: Record<string, DeviceFace>;
695
+ }>;
696
+ metadata?: Record<string, unknown>;
697
+ }
698
+ /**
699
+ * Rack device types
700
+ * @public
701
+ */
702
+ type RackDeviceType = "server" | "switch" | "router" | "patch-panel" | "ups";
703
+ /**
704
+ * Rack configuration structure
705
+ * @public
706
+ */
707
+ interface RackConfig {
708
+ /** Unique rack identifier */
709
+ id: string;
710
+ /** Rack display name */
711
+ name: string;
712
+ /** Rack position coordinates */
713
+ position: {
714
+ x: number;
715
+ y: number;
716
+ };
717
+ /** Rack height in U units */
718
+ units: number;
719
+ /** U numbering direction (default: 'bottom-up') */
720
+ uNumberingDirection?: UNumberingDirection;
721
+ /** Custom header text for rack */
722
+ customHeaderText?: string;
723
+ /** Rack rendering layout mode */
724
+ rackLayout?: RackLayoutMode;
725
+ /** Gap in pixels between front and rear faces in split-face mode */
726
+ rackFaceGapPx?: number;
727
+ /** Devices mounted in the rack */
728
+ devices: RackDevice[];
729
+ /** Optional rack width in pixels (default: 300px which represents standard 48.26cm/19" rack) */
730
+ rackWidthPx?: number;
731
+ }
732
+ /**
733
+ * Device mounted in a rack
734
+ * @public
735
+ */
736
+ interface RackDevice extends DeviceImageOptions {
737
+ /** Unique device identifier */
738
+ id: string;
739
+ /** Device display name */
740
+ name: string;
741
+ /** Starting U position in rack */
742
+ unit: number;
743
+ /** Device height in U units */
744
+ height: number;
745
+ /** Device type */
746
+ type: RackDeviceType;
747
+ /** Device width configuration */
748
+ width?: Width;
749
+ /** Device mount behavior within a rack */
750
+ mountMode?: RackMountMode;
751
+ /** Device role in network */
752
+ role?: string;
753
+ /** Recommended simple port input (flat `DevicePort[]` or grouped `PortBlock[]`). */
754
+ ports?: DevicePort[] | PortBlock[];
755
+ /** Current status of the device */
756
+ status?: DeviceStatus | string;
757
+ /** Advanced grouped front port input */
758
+ portGroups?: PortBlock[];
759
+ /** Advanced grouped rear port input */
760
+ rearPortGroups?: PortBlock[];
761
+ /** Grouped rear port blocks (rack JSON alias for `rearPortGroups`) */
762
+ rearPorts?: PortBlock[];
763
+ /** Power port side for rear face */
764
+ powerSide?: PowerSide;
765
+ /** Connected device IDs */
766
+ connections?: string[];
767
+ }
768
+ /**
769
+ * Fiber cable types
770
+ * @public
771
+ */
772
+ type FiberCableType = "single-mode" | "multi-mode";
773
+ /**
774
+ * Fiber cable configuration
775
+ * @public
776
+ */
777
+ interface FiberCable {
778
+ /** Unique cable identifier */
779
+ id: string;
780
+ /** Cable display name */
781
+ name: string;
782
+ /** Fiber cable type */
783
+ type: FiberCableType;
784
+ /** Cable length */
785
+ length: number;
786
+ /** Cable color for visualization */
787
+ color: string;
788
+ /** Connection endpoints */
789
+ connections: {
790
+ /** Source connection point */
791
+ from: string;
792
+ /** Target connection point */
793
+ to: string;
794
+ };
795
+ }
796
+ /**
797
+ * Splice configuration structure
798
+ * @public
799
+ */
800
+ interface SpliceConfig {
801
+ /** Unique splice identifier */
802
+ id: string;
803
+ /** Splice display name */
804
+ name: string;
805
+ /** Holder position within tray (1-12) */
806
+ holder: number;
807
+ /** Loss value in dB */
808
+ lossDb?: number;
809
+ /** Splice mode: 'single' for individual fiber, 'ribbon' for ribbon splices */
810
+ mode?: "single" | "ribbon";
811
+ /** For ribbon mode: array of fiber IDs (6-12) in the ribbon */
812
+ ribbonFiberIds?: number[];
813
+ }
814
+ /**
815
+ * Splice tray configuration structure
816
+ * @public
817
+ */
818
+ interface SpliceTrayConfig {
819
+ /** Unique tray identifier */
820
+ id: string;
821
+ /** Tray display name */
822
+ name: string;
823
+ /** Tray position coordinates */
824
+ position: {
825
+ x: number;
826
+ y: number;
827
+ };
828
+ /** Splices in this tray */
829
+ splices: SpliceConfig[];
830
+ }
831
+ /**
832
+ * Fine-grained interaction controls for network diagrams.
833
+ * @public
834
+ */
835
+ interface NetworkDiagramInteractionOptions {
836
+ /** Enable node dragging. */
837
+ nodesDraggable?: boolean;
838
+ /** Enable creating connections from node handles. */
839
+ nodesConnectable?: boolean;
840
+ /** Enable selecting nodes/edges. */
841
+ elementsSelectable?: boolean;
842
+ /** Enable keyboard/mouse focus on edges. */
843
+ edgesFocusable?: boolean;
844
+ /** Enable reconnecting existing edges. */
845
+ edgesReconnectable?: boolean;
846
+ /** Enable click-to-connect behavior on handles. */
847
+ connectOnClick?: boolean;
848
+ /** Enable panning by dragging the canvas. */
849
+ panOnDrag?: boolean;
850
+ /** Enable panning by scrolling. */
851
+ panOnScroll?: boolean;
852
+ /** Enable zoom via mouse wheel/trackpad scroll. */
853
+ zoomOnScroll?: boolean;
854
+ /** Enable pinch-zoom gestures. */
855
+ zoomOnPinch?: boolean;
856
+ /** Enable zoom on double click. */
857
+ zoomOnDoubleClick?: boolean;
858
+ /** Enable deleting selected edges with keyboard keys. */
859
+ allowKeyboardDelete?: boolean;
860
+ /** Show or hide the built-in React Flow controls widget. */
861
+ showControls?: boolean;
862
+ /** Show or hide the minimap. */
863
+ showMiniMap?: boolean;
864
+ /** Show or hide the interactive lock/unlock button in controls. */
865
+ showInteractiveControl?: boolean;
866
+ }
867
+ /**
868
+ * Selection action panel options rendered above selected racks/devices.
869
+ * @public
870
+ */
871
+ interface NetworkDiagramActionPanelOptions {
872
+ /** Enable or disable the floating action panel entirely. Defaults to true. */
873
+ enabled?: boolean;
874
+ /** Show or hide the front/rear toggle button. Defaults to true. */
875
+ showRearToggle?: boolean;
876
+ /** Show or hide the De-rack button for rack-mounted devices. Defaults to true. */
877
+ showDeRack?: boolean;
878
+ }
879
+ /**
880
+ * Serializable flow snapshot payload for save/restore helpers.
881
+ * @public
882
+ */
883
+ interface NetworkDiagramFlowObject {
884
+ /** Snapshot nodes */
885
+ nodes: NetworkNode[];
886
+ /** Snapshot edges */
887
+ edges: NetworkEdge[];
888
+ /** Optional viewport state */
889
+ viewport?: Viewport;
890
+ }
891
+ /**
892
+ * Options for exported diagram images.
893
+ * @public
894
+ */
895
+ interface NetworkDiagramToImageOptions {
896
+ /** Export width in px (clamped to 1-8192). */
897
+ width?: number;
898
+ /** Export height in px (clamped to 1-8192). */
899
+ height?: number;
900
+ backgroundColor?: string;
901
+ /** Export padding in px (clamped to 0-2048). */
902
+ padding?: number;
903
+ /** Device pixel ratio multiplier (clamped to 0.1-4). */
904
+ pixelRatio?: number;
905
+ /** JPEG/WebP quality (clamped to 0-1 when used). */
906
+ quality?: number;
907
+ filter?: (domNode: HTMLElement) => boolean;
908
+ }
909
+ /**
910
+ * Fit-view options that support targeting node IDs directly.
911
+ * @public
912
+ */
913
+ interface NetworkDiagramFitViewOptions extends Omit<FitViewOptions, "nodes"> {
914
+ /** Optional node IDs to fit */
915
+ nodes?: string[];
916
+ }
917
+ /**
918
+ * Exposed methods for save/restore and export integrations.
919
+ * @public
920
+ */
921
+ interface NetworkDiagramFlowMethods {
922
+ toObject: () => NetworkDiagramFlowObject;
923
+ setViewport: (viewport: Viewport) => void;
924
+ setNodes: (nodes: NetworkNode[]) => void;
925
+ setEdges: (edges: NetworkEdge[]) => void;
926
+ toImage: (options?: NetworkDiagramToImageOptions) => Promise<string>;
927
+ getNodes: () => NetworkNode[];
928
+ getEdges: () => NetworkEdge[];
929
+ fitView: (options?: NetworkDiagramFitViewOptions) => void;
930
+ }
931
+ /**
932
+ * Store state shape used by `NetworkDiagramStoreApi`.
933
+ * @public
934
+ */
935
+ interface NetworkDiagramStoreState {
936
+ nodes: NetworkNode[];
937
+ edges: NetworkEdge[];
938
+ debug?: boolean;
939
+ }
940
+ /**
941
+ * Store connection validation parameters.
942
+ * @public
943
+ */
944
+ interface NetworkDiagramValidateConnectionParams {
945
+ source: string | null;
946
+ target: string | null;
947
+ sourceHandle?: string | null;
948
+ targetHandle?: string | null;
949
+ }
950
+ /**
951
+ * Store connection validation result.
952
+ * @public
953
+ */
954
+ interface NetworkDiagramValidationResult {
955
+ valid: boolean;
956
+ reason?: string;
957
+ }
958
+ /**
959
+ * Store contract accepted by `NetworkDiagram`.
960
+ * @public
961
+ */
962
+ interface NetworkDiagramStoreApi {
963
+ getState: () => NetworkDiagramStoreState;
964
+ setState: (partial: Partial<NetworkDiagramStoreState>) => void;
965
+ subscribe: (listener: (state: NetworkDiagramStoreState) => void) => () => void;
966
+ selectEdgeZIndex: (edge: NetworkEdge) => number;
967
+ validateConnection: (params: NetworkDiagramValidateConnectionParams) => NetworkDiagramValidationResult;
968
+ selectNodeById: (id: string) => NetworkNode | undefined;
969
+ selectConnectedEdges: (nodeId: string) => NetworkEdge[];
970
+ }
971
+ /**
972
+ * Network diagram component props
973
+ * @public
974
+ */
975
+ interface NetworkDiagramProps {
976
+ /** Controlled document model. When provided, it takes precedence over nodes/edges props. */
977
+ document?: DiagramDocument;
978
+ /** Initial document for uncontrolled document mode. */
979
+ initialDocument?: DiagramDocument;
980
+ /** Callback when the document changes in document mode. */
981
+ onDocumentChange?: (document: DiagramDocument) => void;
982
+ /** Controlled nodes array */
983
+ nodes?: NetworkNode[];
984
+ /** Controlled edges array */
985
+ edges?: NetworkEdge[];
986
+ /** Callback when nodes change (controlled mode) */
987
+ onNodesChange?: (nodes: NetworkNode[]) => void;
988
+ /** Callback when edges change (controlled mode) */
989
+ onEdgesChange?: (edges: NetworkEdge[]) => void;
990
+ /** Initial nodes for uncontrolled mode */
991
+ initialNodes?: NetworkNode[];
992
+ /** Initial edges for uncontrolled mode */
993
+ initialEdges?: NetworkEdge[];
994
+ /** Headless store injection */
995
+ store?: NetworkDiagramStoreApi;
996
+ /** Enable debug mode */
997
+ debug?: boolean;
998
+ /** Callback when a node is clicked or selection changes (null when deselected) */
999
+ onNodeClick?: (node: NetworkNode | null) => void;
1000
+ /** Callback when an edge is clicked */
1001
+ onEdgeClick?: (edge: NetworkEdge) => void;
1002
+ /** Custom React Flow node types to merge with defaults */
1003
+ nodeTypes?: NodeTypes;
1004
+ /** Custom React Flow edge types to merge with defaults */
1005
+ edgeTypes?: EdgeTypes;
1006
+ /** Optional onConnect override (React Flow connection handler) */
1007
+ onConnect?: (connection: Connection) => void;
1008
+ /** Optional onEdgeUpdate override */
1009
+ onEdgeUpdate?: (oldEdge: Edge, newConnection: Connection) => void;
1010
+ /** Optional isValidConnection override */
1011
+ isValidConnection?: (connection: Connection) => boolean;
1012
+ /** Optional connection mode override */
1013
+ connectionMode?: ConnectionMode;
1014
+ /** Callback when a device face changes */
1015
+ onFaceChange?: (nodeId: string, face: DeviceFace) => void;
1016
+ /** Callback when rack face changes */
1017
+ onRackFaceChange?: (rackId: string, face: DeviceFace) => void;
1018
+ /** CSS class name */
1019
+ className?: string;
1020
+ /** Inline styles */
1021
+ style?: React.CSSProperties;
1022
+ /** If true, vertically align rack bottoms to the same baseline */
1023
+ alignRacksToBottom?: boolean;
1024
+ /** Allow rack-mounted devices to move between racks/ungroup on drag and drop. Defaults to true. */
1025
+ reAssignable?: boolean;
1026
+ /** Color mode for the diagram */
1027
+ colorMode?: "light" | "dark" | "system";
1028
+ /** Callback when React Flow instance is initialized */
1029
+ onInit?: (instance: ReactFlowInstance) => void;
1030
+ /** Callback to get React Flow methods for save/restore */
1031
+ onFlowMethods?: (methods: NetworkDiagramFlowMethods) => void;
1032
+ /** Show download button */
1033
+ showDownloadButton?: boolean;
1034
+ /** Download button position */
1035
+ downloadButtonPosition?: "top-right" | "top-left" | "bottom-right" | "bottom-left";
1036
+ /** Custom download button text */
1037
+ downloadButtonText?: string;
1038
+ /** Download button styling options */
1039
+ downloadButtonStyle?: React.CSSProperties;
1040
+ /** Use smoothstep edges for tube connections (both tube-to-cable and cable-to-tube). Default is fiber. */
1041
+ useSmoothstepEdgesForTubes?: boolean;
1042
+ /** Force read-only behavior for the diagram (no drag/connect/delete/reconnect/pan/zoom edits). */
1043
+ readOnly?: boolean;
1044
+ /** Centralized interaction options for consistent edit/lock behavior. */
1045
+ interaction?: NetworkDiagramInteractionOptions;
1046
+ /** Configuration for the floating action panel shown on selected rack/device nodes. */
1047
+ actionPanel?: NetworkDiagramActionPanelOptions;
1048
+ /** Optional fitView options passed to React Flow */
1049
+ fitViewOptions?: FitViewOptions;
1050
+ /**
1051
+ * Minimum zoom passed to React Flow. Defaults to 0.1 so the always-on
1052
+ * fitView can actually fit tall scenes (React Flow's own 0.5 default clamps
1053
+ * the fit and crops full-height racks, which viewport culling then never
1054
+ * mounts).
1055
+ */
1056
+ minZoom?: number;
1057
+ /** Maximum zoom passed to React Flow. Defaults to 4. */
1058
+ maxZoom?: number;
1059
+ /**
1060
+ * Let React Flow render only viewport-visible nodes and edges.
1061
+ * Defaults to `false`. Enable for very large diagrams, but note that with a
1062
+ * tight `minZoom` a fit-to-view can cull off-screen nodes so they never mount.
1063
+ */
1064
+ onlyRenderVisibleElements?: boolean;
1065
+ /** Node IDs to keep at full opacity when diagram focus dimming is enabled */
1066
+ highlightedNodeIds?: string[];
1067
+ /** Edge IDs to keep at full opacity when diagram focus dimming is enabled */
1068
+ highlightedEdgeIds?: string[];
1069
+ /**
1070
+ * When true, non-highlighted nodes and edges are dimmed while focus IDs are set.
1071
+ * Edges connected to highlighted nodes remain in focus unless
1072
+ * `connectEdgesToHighlightedNodes` is false.
1073
+ */
1074
+ dimUnhighlighted?: boolean;
1075
+ /** Opacity for dimmed nodes/edges (0-1). Defaults to 0.25 */
1076
+ dimOpacity?: number;
1077
+ /** When false, only explicit highlightedEdgeIds stay bright during focus. */
1078
+ connectEdgesToHighlightedNodes?: boolean;
1079
+ /** When false, devices render without rack photos. Status border still uses `getStatusColor`. Default true. */
1080
+ showDeviceImages?: boolean;
1081
+ /** Port handles kept highlighted during diagram trace/focus. */
1082
+ highlightedPortHandles?: DiagramPortHandleRef[];
1083
+ /** Fired when a port handle is clicked (typically in read-only trace mode). */
1084
+ onPortClick?: (payload: DiagramPortClickPayload) => void;
1085
+ /**
1086
+ * Pointer distance (px) within which a drag snaps onto a handle, forwarded to
1087
+ * React Flow's `connectionRadius`. Larger values make small port handles easier
1088
+ * to target; smaller values reduce mis-targeting on densely packed devices.
1089
+ * When omitted, React Flow's default is used.
1090
+ */
1091
+ connectionRadius?: number;
1092
+ /**
1093
+ * Fired when a connection attempt is rejected by the diagram's validation
1094
+ * (incompatible endpoints, an occupied non-replaceable handle, a disallowed
1095
+ * fiber pairing, etc.). Lets host apps surface feedback instead of failing
1096
+ * silently. Not called for the continuous hover validation during a drag —
1097
+ * only when an actual connect or reconnect attempt is rejected.
1098
+ */
1099
+ onConnectRejected?: (payload: NetworkConnectionRejection) => void;
1100
+ }
1101
+ /** Payload describing why a connection attempt was rejected. */
1102
+ interface NetworkConnectionRejection {
1103
+ /** The connection the user attempted to make. */
1104
+ connection: Connection;
1105
+ /** Human-readable reason the connection was rejected. */
1106
+ reason: string;
1107
+ /** Whether the rejection happened while creating a new edge or reconnecting an existing one. */
1108
+ phase: "connect" | "reconnect";
1109
+ }
1110
+
1111
+ /**
1112
+ * Normalize source/target directional suffixes used for bidirectional handles.
1113
+ * Example: `Rear Ports-1-target` -\> `Rear Ports-1`.
1114
+ */
1115
+ declare function normalizeDirectionalHandleId(handleId: string | null | undefined): string;
1116
+ /**
1117
+ * Normalize rendered handle ids back to their canonical endpoint id.
1118
+ * This removes the directional suffix and the split-face alias, in the order
1119
+ * the renderer composes them: `<base>[--rear|--front][-source|-target]`.
1120
+ * (Previously only `--rear` was stripped; `--front` ghost aliases now
1121
+ * normalize too.)
1122
+ */
1123
+ declare function normalizeHandleId(handleId: string | null | undefined): string;
1124
+ /**
1125
+ * Returns true when a port type is considered power-related.
1126
+ */
1127
+ declare function isPowerPortType(portType: string | undefined): boolean;
1128
+ /**
1129
+ * Build a stable handle id for a port.
1130
+ * Power ports use the label directly to preserve legacy ids.
1131
+ */
1132
+ declare function buildPortHandleId(portBlockName: string, port: Pick<Port, "label" | "id"> & {
1133
+ type?: string;
1134
+ }): string;
1135
+ /**
1136
+ * Heuristic for whether a handle id represents a power endpoint.
1137
+ */
1138
+ declare function looksLikePowerHandleId(handleId: string): boolean;
1139
+ /**
1140
+ * Options for {@link applyDirectionalPortHandleId}.
1141
+ */
1142
+ interface ApplyDirectionalPortHandleIdOptions {
1143
+ /**
1144
+ * The port's `type` (e.g. `rj45`, `power_ac`). When provided, power-ness is
1145
+ * decided from it via {@link isPowerPortType} — the same rule the renderer
1146
+ * uses to decide whether a port mounts directional handles at all. Always
1147
+ * pass this when the port is available.
1148
+ */
1149
+ portType?: string;
1150
+ }
1151
+ /**
1152
+ * Apply a directional (`source`/`target`) suffix to a rendered handle id — the
1153
+ * inverse of {@link normalizeDirectionalHandleId}. Any existing directional
1154
+ * suffix is replaced first, and passing no direction is a no-op.
1155
+ * Example: `Rear Ports-1` + `target` -\> `Rear Ports-1-target`.
1156
+ *
1157
+ * Power endpoints are matched without a direction, so power handles are
1158
+ * returned unchanged. Whether a handle is a power handle is decided from
1159
+ * `options.portType` when given (exact — the renderer's rule). Without it the
1160
+ * decision falls back to {@link looksLikePowerHandleId}, a string heuristic
1161
+ * that cannot recognize power ports whose ids lack `power`/`pwr` (e.g. a port
1162
+ * labeled `PSU-A`) and misclassifies non-power ports whose group name contains
1163
+ * the word (e.g. `Power Room Uplinks-1`). Pass `portType` whenever you have
1164
+ * the port.
1165
+ */
1166
+ declare function applyDirectionalPortHandleId(handleId: string, direction?: "source" | "target" | null, options?: ApplyDirectionalPortHandleIdOptions): string;
1167
+ /**
1168
+ * The structural shape of a handle id's base (suffixes already stripped).
1169
+ *
1170
+ * - `outlet` — vertical-PDU outlets: a bare number (`"4"`).
1171
+ * - `fiber` — `fiber-<n>` (tube/cable nodes) or `fiber-<tube>-<n>`
1172
+ * (FibreFlowMap rows).
1173
+ * - `tube` — `tube-<n>` (tube and multi-tube-cable nodes).
1174
+ * - `splice-side` — bare `left` / `right` (splice nodes).
1175
+ * - `side-port` — `left-<n>` / `right-<n>` (coupler ports).
1176
+ * - `split-io` — `input-<n>` / `output-<n>` (fibre-split nodes).
1177
+ * - `cable-button` — the literal `cable-button` connector on cable nodes.
1178
+ * - `port` — everything else: device-family ports built by
1179
+ * {@link buildPortHandleId} (`<group>-<label>`, a bare power label, or an
1180
+ * explicit `port.id`). The base is not split further because group names
1181
+ * and labels may themselves contain `-`.
1182
+ * @public
1183
+ */
1184
+ type HandleShape = {
1185
+ kind: "outlet";
1186
+ outlet: number;
1187
+ } | {
1188
+ kind: "fiber";
1189
+ fiber: number;
1190
+ tube?: number;
1191
+ } | {
1192
+ kind: "tube";
1193
+ tube: number;
1194
+ } | {
1195
+ kind: "splice-side";
1196
+ side: "left" | "right";
1197
+ } | {
1198
+ kind: "side-port";
1199
+ side: "left" | "right";
1200
+ index: number;
1201
+ } | {
1202
+ kind: "split-io";
1203
+ io: "input" | "output";
1204
+ index: number;
1205
+ } | {
1206
+ kind: "cable-button";
1207
+ } | {
1208
+ kind: "port";
1209
+ };
1210
+ /**
1211
+ * A structurally parsed handle id.
1212
+ * @public
1213
+ */
1214
+ interface ParsedHandleId {
1215
+ /** The id exactly as given. */
1216
+ raw: string;
1217
+ /** `raw` with the directional suffix and face alias stripped. */
1218
+ base: string;
1219
+ /** Directional suffix, when present (`X-source` / `X-target`). */
1220
+ direction?: "source" | "target";
1221
+ /**
1222
+ * Split-face alias, when present (`X--rear` / `X--front`) — added by the
1223
+ * renderer when both faces of a device are shown and a handle id would
1224
+ * otherwise collide with its opposite face.
1225
+ */
1226
+ faceAlias?: "front" | "rear";
1227
+ /** Structural classification of {@link ParsedHandleId.base}. */
1228
+ shape: HandleShape;
1229
+ }
1230
+ /**
1231
+ * Parse a rendered/stored handle id into its structural parts: base, optional
1232
+ * directional suffix, optional split-face alias, and the {@link HandleShape}
1233
+ * of the base. Total — never throws; unrecognized bases classify as `port`.
1234
+ * @public
1235
+ */
1236
+ declare function parseHandleId(handleId: string | null | undefined): ParsedHandleId;
1237
+ /**
1238
+ * Build a fiber handle id: `fiber-<n>`, or `fiber-<tube>-<n>` when a tube
1239
+ * index is given (the FibreFlowMap row form).
1240
+ * @public
1241
+ */
1242
+ declare function buildFiberHandleId(fiber: number, tube?: number): string;
1243
+ /**
1244
+ * Build a tube handle id: `tube-<n>`.
1245
+ * @public
1246
+ */
1247
+ declare function buildTubeHandleId(tube: number): string;
1248
+ /**
1249
+ * Build a splice handle id: the bare `left` / `right` sides of a splice node.
1250
+ * @public
1251
+ */
1252
+ declare function buildSpliceHandleId(side: "left" | "right"): string;
1253
+ /**
1254
+ * Build a coupler port handle id: `left-<n>` / `right-<n>` (1-based).
1255
+ * @public
1256
+ */
1257
+ declare function buildCouplerHandleId(side: "left" | "right", index: number): string;
1258
+ /**
1259
+ * Build a fibre-split io handle id: `input-<n>` / `output-<n>`.
1260
+ * @public
1261
+ */
1262
+ declare function buildSplitIoHandleId(io: "input" | "output", index: number): string;
1263
+ /**
1264
+ * Append a split-face alias to a handle id: `X` + `rear` -\> `X--rear`.
1265
+ * Any existing alias is replaced. The renderer applies this when a hidden or
1266
+ * ghost face would mount a handle whose id collides with the visible face.
1267
+ * @public
1268
+ */
1269
+ declare function applyFaceAliasHandleId(handleId: string, face: "front" | "rear"): string;
1270
+ /**
1271
+ * Normalize a handle id for tolerant matching by stripping `+` characters.
1272
+ * Port labels like `SFP+-1` historically produced handles that some producers
1273
+ * emitted `+`-stripped (`SFP-1`), so comparisons between independently built
1274
+ * handles must be `+`-insensitive. Apply to BOTH sides of a comparison — this
1275
+ * is a matching normalization, not part of the build grammar:
1276
+ * {@link buildPortHandleId} keeps `+` so built ids always equal rendered ids.
1277
+ * @public
1278
+ */
1279
+ declare function sanitizeHandleIdForMatching(handleId: string): string;
1280
+ /**
1281
+ * For pass-through nodes with two sides, return the handle id of the opposite
1282
+ * side: splice `left` \<-\> `right`, coupler `left-<n>` \<-\> `right-<n>`.
1283
+ * Returns `undefined` for every other shape. Directional suffixes and face
1284
+ * aliases are stripped (neither occurs on splice/coupler handles in practice).
1285
+ * @public
1286
+ */
1287
+ declare function getOppositeSideHandleId(handleId: string): string | undefined;
1288
+
1289
+ /** @deprecated Use {@link buildPortHandleId}. */
1290
+ declare const buildReactNetworksHandleId: typeof buildPortHandleId;
1291
+ /**
1292
+ * Resolve the effective device face for a flat port input.
1293
+ * @public
1294
+ */
1295
+ declare function resolveDevicePortFace(port: Pick<DevicePort, 'face' | 'type'>): DeviceFace;
1296
+ /** @deprecated Use {@link resolveDevicePortFace}. */
1297
+ declare const resolveReactNetworksPortFace: typeof resolveDevicePortFace;
1298
+ /**
1299
+ * Resolve the effective port group name for a flat port input.
1300
+ * @public
1301
+ */
1302
+ declare function resolveDevicePortGroup(port: Pick<DevicePort, 'face' | 'group' | 'type'>): string;
1303
+ /** @deprecated Use {@link resolveDevicePortGroup}. */
1304
+ declare const resolveReactNetworksPortGroup: typeof resolveDevicePortGroup;
1305
+ /**
1306
+ * Normalize unknown **flat** port array input into canonical {@link DevicePort} entries.
1307
+ *
1308
+ * This handles a flat `DevicePort[]` only; grouped `PortBlock[]` input returns
1309
+ * `undefined` (blocks have no `label`). To resolve flat ports from any supported
1310
+ * form — including grouped `PortBlock[]` — use {@link resolveNodeDevicePorts}.
1311
+ * @public
1312
+ */
1313
+ declare function normalizeDevicePorts(value: unknown): DevicePort[] | undefined;
1314
+ /** @deprecated Use {@link normalizeDevicePorts}. */
1315
+ declare const normalizeReactNetworksPorts: typeof normalizeDevicePorts;
1316
+ /**
1317
+ * Resolve flat device ports from any supported port input.
1318
+ *
1319
+ * Accepts every form the renderer accepts (`getResolvedPortBlocks`): a node-data
1320
+ * record (`ports` / `portGroups` / `rearPortGroups` / `rearPorts`), a flat
1321
+ * `DevicePort[]`, or a grouped `PortBlock[]`. Grouped `PortBlock[]` carried on
1322
+ * `ports` are treated as front groups (taking precedence over `portGroups`, matching
1323
+ * the renderer); rear groups come from `rearPortGroups`, falling back to `rearPorts`.
1324
+ * @public
1325
+ */
1326
+ declare function resolveNodeDevicePorts(value: unknown): DevicePort[] | undefined;
1327
+ /** @deprecated Use {@link resolveNodeDevicePorts}. */
1328
+ declare const resolveReactNetworksNodePorts: typeof resolveNodeDevicePorts;
1329
+ /**
1330
+ * Flatten grouped port blocks into canonical flat {@link DevicePort} entries.
1331
+ * @public
1332
+ */
1333
+ declare function flattenDevicePortsFromGroups({ portGroups, rearPortGroups, }: {
1334
+ portGroups?: PortBlock[];
1335
+ rearPortGroups?: PortBlock[];
1336
+ }): DevicePort[];
1337
+ /** @deprecated Use {@link flattenDevicePortsFromGroups}. */
1338
+ declare const flattenReactNetworksPortGroups: typeof flattenDevicePortsFromGroups;
1339
+ /**
1340
+ * Build grouped port blocks from flat device port input.
1341
+ * @public
1342
+ */
1343
+ declare function buildDevicePortGroupsFromPorts(ports: DevicePort[] | undefined): {
1344
+ portGroups: PortBlock[];
1345
+ rearPortGroups: PortBlock[];
1346
+ };
1347
+ /** @deprecated Use {@link buildDevicePortGroupsFromPorts}. */
1348
+ declare const buildReactNetworksPortGroupsFromPorts: typeof buildDevicePortGroupsFromPorts;
1349
+ interface ListPossiblePortHandleIdsOptions {
1350
+ deviceType?: string;
1351
+ face?: DeviceFace;
1352
+ }
1353
+ /**
1354
+ * List the **canonical** handle ids that may exist on a rendered node for a port.
1355
+ *
1356
+ * The returned ids are in canonical form. When a device renders both faces and a
1357
+ * front/rear handle id collides, the renderer disambiguates the hidden face with a
1358
+ * `--rear` / `--front` suffix (see `normalizeHandleId`). This function does not emit
1359
+ * those split-face aliases, so callers reconciling stored/rendered handles should
1360
+ * compare through {@link normalizeHandleId} (which strips the suffix) rather than by
1361
+ * raw string equality. {@link validatePortHandleOnNodeData} does this for you.
1362
+ * @public
1363
+ */
1364
+ declare function listPossiblePortHandleIds(portBlockName: string, port: Pick<Port, 'id' | 'label' | 'type'>, options?: ListPossiblePortHandleIdsOptions): string[];
1365
+ /**
1366
+ * A rendered/stored handle id resolved back to the port that owns it.
1367
+ * @public
1368
+ */
1369
+ interface DescribedPortHandle {
1370
+ /** The port the handle belongs to. */
1371
+ port: DevicePort;
1372
+ /** The port block (group) the port renders under. */
1373
+ blockName: string;
1374
+ /** The device face the block renders on. */
1375
+ face: DeviceFace;
1376
+ }
1377
+ /**
1378
+ * Resolve a handle id back to the port that owns it — the inverse of
1379
+ * {@link buildPortHandleId} / {@link listPossiblePortHandleIds} over a node's
1380
+ * resolved port blocks. Directional suffixes and split-face aliases are
1381
+ * normalized before comparison (via {@link normalizeHandleId}), so ids taken
1382
+ * straight from edges match. Pass `options.sanitizeHandle` to match under an
1383
+ * additional app-side normalization (e.g.
1384
+ * {@link sanitizeHandleIdForMatching} for `+`-insensitive comparison).
1385
+ * Returns `undefined` when no port on the node renders that handle.
1386
+ * @public
1387
+ */
1388
+ declare function describePortHandle(nodeData: Pick<NetworkNodeDataBase, 'ports' | 'portGroups' | 'rearPortGroups'> | undefined, handle: string, options?: {
1389
+ deviceType?: string;
1390
+ sanitizeHandle?: (value: string) => string;
1391
+ }): DescribedPortHandle | undefined;
1392
+ /**
1393
+ * Validate that a handle id exists on node data after grouping resolution.
1394
+ * @public
1395
+ */
1396
+ declare function validatePortHandleOnNodeData(nodeData: Pick<NetworkNodeDataBase, 'ports' | 'portGroups' | 'rearPortGroups'> | undefined, handle: string, options?: {
1397
+ deviceType?: string;
1398
+ sanitizeHandle?: (value: string) => string;
1399
+ }): boolean;
1400
+ /**
1401
+ * Convert flat ports to grouped blocks using the same rules as renderers.
1402
+ * @public
1403
+ */
1404
+ declare function resolveDevicePortBlocksFromFlatPorts(ports: DevicePort[]): {
1405
+ portGroups: PortBlock[];
1406
+ rearPortGroups: PortBlock[];
1407
+ };
1408
+
1409
+ declare const parseSemanticPortPosition: (value: string) => PortPosition | undefined;
1410
+ declare const normalizePortPositionInput: (value: unknown) => PortPosition | undefined;
1411
+
1412
+ type PathLayoutDirection = 'horizontal' | 'vertical';
1413
+ interface PathLayoutStepInput {
1414
+ id: string;
1415
+ type?: NetworkNode['type'];
1416
+ data?: NetworkNode['data'];
1417
+ }
1418
+ interface PathLayoutEdgeInput {
1419
+ id: string;
1420
+ source: string;
1421
+ target: string;
1422
+ type?: NetworkEdge['type'];
1423
+ data?: NetworkEdge['data'];
1424
+ }
1425
+ interface BuildPathLayoutOptions {
1426
+ direction?: PathLayoutDirection;
1427
+ spacing?: number;
1428
+ origin?: {
1429
+ x: number;
1430
+ y: number;
1431
+ };
1432
+ }
1433
+ /**
1434
+ * Lay out a sequential path of nodes and connecting edges with deterministic spacing.
1435
+ * @public
1436
+ */
1437
+ declare function buildPathLayoutGraph(steps: PathLayoutStepInput[], edges: PathLayoutEdgeInput[], options?: BuildPathLayoutOptions): {
1438
+ nodes: NetworkNode[];
1439
+ edges: NetworkEdge[];
1440
+ };
1441
+
1442
+ interface NetworkGraphSnapshot {
1443
+ nodes: NetworkNode[];
1444
+ edges: NetworkEdge[];
1445
+ }
1446
+ declare function networkGraphToDiagramDocument(snapshot: NetworkGraphSnapshot, previousDocument?: DiagramDocument): DiagramDocument;
1447
+ declare function diagramDocumentToNetworkGraph(document: DiagramDocument): NetworkGraphSnapshot;
1448
+
1449
+ export { type NetworkDiagramFlowObject as $, type ApplyDirectionalPortHandleIdOptions as A, type BuildPathLayoutOptions as B, type DiagramEdgeEndpoint as C, type DeviceNodeData as D, type DiagramEndpoint as E, type FibreFlowCableNodeData as F, type DiagramExternalRef as G, type DiagramNode as H, type DiagramNodeKind as I, type DiagramNodePlacement as J, type DiagramNodeRender as K, type DiagramUiState as L, type FiberCable as M, type NetworkDiagramProps as N, type FiberCableType as O, type PortBlock as P, type FibreFlowCableKind as Q, type RackNodeData as R, type SpliceTrayConfig as S, type FibreFlowEndpoint as T, type FibreFlowSplice as U, type HandleShape as V, type ListPossiblePortHandleIdsOptions as W, type NetworkConnectionRejection as X, type NetworkDiagramActionPanelOptions as Y, type NetworkDiagramFitViewOptions as Z, type NetworkDiagramFlowMethods as _, type NetworkNode as a, type NetworkDiagramStoreApi as a0, type NetworkDiagramStoreState as a1, type NetworkDiagramToImageOptions as a2, type NetworkDiagramValidateConnectionParams as a3, type NetworkDiagramValidationResult as a4, type NetworkEdgeType as a5, type NetworkGraphSnapshot as a6, type NetworkNodeData as a7, type NetworkNodeDataByType as a8, type NetworkNodeType as a9, flattenReactNetworksPortGroups as aA, getOppositeSideHandleId as aB, isPowerPortType as aC, listPossiblePortHandleIds as aD, looksLikePowerHandleId as aE, networkGraphToDiagramDocument as aF, normalizeDevicePorts as aG, normalizeDirectionalHandleId as aH, normalizeHandleId as aI, normalizePortPositionInput as aJ, normalizeReactNetworksPorts as aK, parseHandleId as aL, parseSemanticPortPosition as aM, resolveDevicePortBlocksFromFlatPorts as aN, resolveDevicePortFace as aO, resolveDevicePortGroup as aP, resolveNodeDevicePorts as aQ, resolveReactNetworksNodePorts as aR, resolveReactNetworksPortFace as aS, resolveReactNetworksPortGroup as aT, sanitizeHandleIdForMatching as aU, validatePortHandleOnNodeData as aV, type ParsedHandleId as aa, type PathLayoutDirection as ab, type PathLayoutEdgeInput as ac, type PathLayoutStepInput as ad, type Port as ae, type PowerSide as af, type RackDeviceType as ag, type RackLayoutMode as ah, type RackMountMode as ai, type UNumberingDirection as aj, Width as ak, applyDirectionalPortHandleId as al, applyFaceAliasHandleId as am, buildCouplerHandleId as an, buildDevicePortGroupsFromPorts as ao, buildFiberHandleId as ap, buildPathLayoutGraph as aq, buildPortHandleId as ar, buildReactNetworksHandleId as as, buildReactNetworksPortGroupsFromPorts as at, buildSpliceHandleId as au, buildSplitIoHandleId as av, buildTubeHandleId as aw, describePortHandle as ax, diagramDocumentToNetworkGraph as ay, flattenDevicePortsFromGroups as az, type NetworkEdgeData as b, type NetworkNodeDataBase as c, type FibreFlowClosureNodeData as d, type FibreFlowClosure as e, type FibreFlowCircuit as f, type NetworkDiagramInteractionOptions as g, type FibreFlowCable as h, type NetworkEdge as i, type DiagramDocument as j, type RackConfig as k, type RackDevice as l, type SpliceConfig as m, type DevicePort as n, type DeviceFace as o, type PortType as p, type DeviceStatus as q, type DiagramPortHandleRef as r, type DiagramPortClickPayload as s, type PortCableType as t, type PortPosition as u, type DescribedPortHandle as v, type DeviceImageFit as w, type DeviceImageOptions as x, type DeviceImageRepeat as y, type DiagramEdge as z };