@mp70/react-networks 0.1.4-alpha → 0.1.6-alpha

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/README.md CHANGED
@@ -312,14 +312,20 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
312
312
 
313
313
  ## 📄 License
314
314
 
315
- Dual-licensed under AGPL-3.0 or Commercial. See [LICENSE](LICENSE) for details.
315
+ Dual-licensed under:
316
+
317
+ - **AGPL-3.0** (Free) - For open source, personal, and educational use. Copyleft applies. [Read License](https://www.gnu.org/licenses/agpl-3.0.html)
318
+ - **Commercial** (Paid) - For proprietary/commercial use without copyleft obligations. [Contact us](mailto:info@serversearcher.com?subject=Commercial License Inquiry for @mp70/react-networks)
319
+
320
+ See [LICENSE](../../LICENSE) for details. By installing, you agree to use under either license. Contact us for commercial use.
316
321
 
317
322
  ## 🆘 Support
318
323
 
319
- - 📖 [Documentation](https://react-networks.dev)
320
- - 🐛 [Issue Tracker](https://github.com/your-org/react-networks/issues)
321
- - 💬 [Discussions](https://github.com/your-org/react-networks/discussions)
322
- - 📧 [Email Support](mailto:support@react-networks.dev)
324
+ - 📖 [Documentation](../../README.md)
325
+ - 📚 [API Documentation](docs/API.md)
326
+ - 🐛 [Issue Tracker](https://github.com/MP70/react-networks/issues)
327
+ - 💬 [Discussions](https://github.com/MP70/react-networks/discussions)
328
+ - 📧 [Email Support](mailto:info@serversearcher.com)
323
329
 
324
330
  ## 🙏 Acknowledgments
325
331
 
@@ -329,4 +335,4 @@ Dual-licensed under AGPL-3.0 or Commercial. See [LICENSE](LICENSE) for details.
329
335
 
330
336
  ---
331
337
 
332
- Made with ❤️ by the React Networks team
338
+ Made with ❤️ by [Matt Pickering](https://github.com/MP70)
package/dist/index.css CHANGED
@@ -32,7 +32,7 @@
32
32
  }
33
33
 
34
34
  .react-flow-light {
35
- --react-flow-background: #ffffff;
35
+ --react-flow-background: #f5f5f5;
36
36
  --react-flow-text: #1a1a1a;
37
37
  --react-flow-border: #e9ecef;
38
38
  --react-flow-controls-bg: #f8f9fa;
@@ -50,6 +50,15 @@
50
50
  background-color: var(--react-flow-background);
51
51
  }
52
52
 
53
+ /* Ensure canvas background is always off-white in light mode */
54
+ .react-flow-light .react-flow__viewport {
55
+ background-color: #f5f5f5 !important;
56
+ }
57
+
58
+ .react-flow-light .react-flow {
59
+ background-color: #f5f5f5;
60
+ }
61
+
53
62
  .react-flow-dark .react-flow__controls {
54
63
  background-color: var(--react-flow-controls-bg);
55
64
  border-color: var(--react-flow-controls-border);
@@ -90,6 +99,135 @@
90
99
  background-color: #e9ecef;
91
100
  }
92
101
 
102
+ /* Override React Flow default handle styles for tube fiber handles */
103
+ /* Use CSS variables set by inline styles to override React Flow defaults */
104
+ .react-flow__handle.tube-fiber-handle {
105
+ border: none !important;
106
+ transform: none !important;
107
+ background-clip: padding-box !important;
108
+ opacity: 1 !important;
109
+ /* Remove React Flow's default background completely */
110
+ background: var(--fiber-bg-image, var(--fiber-bg)) !important;
111
+ background-color: var(--fiber-bg) !important;
112
+ /* Ensure no default React Flow styles interfere */
113
+ box-shadow: none !important;
114
+ }
115
+
116
+ .react-flow__handle-right.tube-fiber-handle {
117
+ right: auto !important;
118
+ }
119
+
120
+ /* More specific selector to ensure override - target all possible React Flow handle states */
121
+ .react-flow__node .react-flow__handle.tube-fiber-handle,
122
+ .react-flow__node .react-flow__handle.tube-fiber-handle[data-handlepos],
123
+ .react-flow__handle.tube-fiber-handle[data-handlepos],
124
+ .react-flow__handle.tube-fiber-handle[data-fiber-idx] {
125
+ background: var(--fiber-bg-image, var(--fiber-bg)) !important;
126
+ background-color: var(--fiber-bg) !important;
127
+ background-image: var(--fiber-bg-image, none) !important;
128
+ }
129
+
130
+ /* Connection animation - pulse effect when edge is first created */
131
+ @keyframes edgeConnectPulse {
132
+ 0% {
133
+ opacity: 0;
134
+ stroke-width: 1;
135
+ }
136
+ 50% {
137
+ opacity: 1;
138
+ stroke-width: 4;
139
+ }
140
+ 100% {
141
+ opacity: 1;
142
+ stroke-width: 2;
143
+ }
144
+ }
145
+
146
+ .react-flow__edge.edge-connecting path,
147
+ .react-flow__edge.edge-connecting .react-flow__edge-path {
148
+ animation: edgeConnectPulse 1s ease-out;
149
+ }
150
+
151
+ /* Splice glow animation - fade in when both handles are connected */
152
+ @keyframes spliceGlowFadeIn {
153
+ 0% {
154
+ opacity: 0;
155
+ transform: translateX(-50%) scaleY(0.3);
156
+ }
157
+ 100% {
158
+ opacity: 1;
159
+ transform: translateX(-50%) scaleY(1);
160
+ }
161
+ }
162
+
163
+ .splice-glow {
164
+ animation: spliceGlowFadeIn 0.5s ease-out;
165
+ transform-origin: center;
166
+ }
167
+
168
+ /* Splice text animation - fade in when both handles are connected */
169
+ @keyframes spliceTextFadeIn {
170
+ 0% {
171
+ opacity: 0;
172
+ transform: scale(0.8);
173
+ }
174
+ 100% {
175
+ opacity: 1;
176
+ transform: scale(1);
177
+ }
178
+ }
179
+
180
+ /* Splice text overlay - blur and opacity for text readability */
181
+ .splice-text-overlay {
182
+ backdrop-filter: blur(2px);
183
+ -webkit-backdrop-filter: blur(2px);
184
+ }
185
+
186
+ /* Dark mode overlay */
187
+ .react-flow-dark .splice-text-overlay {
188
+ background: rgba(0, 0, 0, 0.6);
189
+ }
190
+
191
+ /* Light mode overlay */
192
+ .react-flow-light .splice-text-overlay {
193
+ background: rgba(255, 255, 255, 0.7);
194
+ }
195
+
196
+ /* Splice text label - theme-aware colors */
197
+ .splice-text-label {
198
+ color: #fff;
199
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 0 2px rgba(0, 0, 0, 0.6);
200
+ }
201
+
202
+ .splice-text-label.animate-in {
203
+ animation: spliceTextFadeIn 0.5s ease-out;
204
+ transform-origin: center;
205
+ }
206
+
207
+ /* Light mode text */
208
+ .react-flow-light .splice-text-label {
209
+ color: #1a1a1a;
210
+ text-shadow: 0 1px 2px rgba(255, 255, 255, 0.9), 0 0 4px rgba(255, 255, 255, 0.7);
211
+ }
212
+
213
+ /* Remove all borders from splice nodes */
214
+ .react-flow__node[data-type="splice"],
215
+ .react-flow__node[data-type="splice"] > div {
216
+ border: none !important;
217
+ outline: none !important;
218
+ }
219
+
220
+ .splice-node {
221
+ border: none !important;
222
+ outline: none !important;
223
+ }
224
+
225
+ /* Only remove box-shadow when not selected */
226
+ .react-flow__node[data-type="splice"]:not(.selected) > div,
227
+ .splice-node:not(.selected) {
228
+ box-shadow: none !important;
229
+ }
230
+
93
231
  /* React Networks Attribution */
94
232
  .react-networks-attribution {
95
233
  padding: 0;
@@ -126,3 +264,51 @@
126
264
  background: rgba(255, 255, 255, 0.8);
127
265
  }
128
266
 
267
+ /* Coupler node styles */
268
+ .coupler-node {
269
+ transition: box-shadow 0.2s ease;
270
+ }
271
+
272
+ .coupler-node.selected {
273
+ box-shadow: 0 0 0 2px #3b82f6 !important;
274
+ }
275
+
276
+ /* Patch panel node styles */
277
+ .patch-panel-node {
278
+ transition: box-shadow 0.2s ease, border-color 0.2s ease;
279
+ }
280
+
281
+ .patch-panel-node.selected {
282
+ box-shadow: 0 0 0 2px #3b82f6 !important;
283
+ border-color: #3b82f6 !important;
284
+ }
285
+
286
+ /* Closure node styles */
287
+ .closure-node {
288
+ transition: box-shadow 0.2s ease, border-color 0.2s ease;
289
+ }
290
+
291
+ .closure-node.selected {
292
+ box-shadow: 0 0 0 2px #3b82f6 !important;
293
+ border-color: #3b82f6 !important;
294
+ }
295
+
296
+ /* Light mode adjustments */
297
+ .react-flow-light .coupler-node {
298
+ background: #f9fafb;
299
+ color: #1f2937;
300
+ border-color: #d1d5db;
301
+ }
302
+
303
+ .react-flow-light .patch-panel-node {
304
+ background: transparent !important;
305
+ color: #1f2937;
306
+ border-color: #d1d5db;
307
+ }
308
+
309
+ .react-flow-light .closure-node {
310
+ background: transparent !important;
311
+ color: #1f2937;
312
+ border-color: #d1d5db;
313
+ }
314
+
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/styles/index.css"],"sourcesContent":["/* Library styles for @react-networks/network-diagrams */\n\n/* Edge zIndex styles for dynamic prominence */\n.edge-prominent {\n z-index: 1000 !important;\n opacity: 1 !important;\n}\n\n.edge-dimmed {\n z-index: 500 !important;\n opacity: 0.3 !important;\n}\n\n/* Dynamic zIndex classes */\n.edge-z-1000 {\n z-index: 1000 !important;\n}\n\n.edge-z-500 {\n z-index: 500 !important;\n}\n\n/* React Flow theming */\n.react-flow-dark {\n --react-flow-background: #1a1a1a;\n --react-flow-text: #ffffff;\n --react-flow-border: #404040;\n --react-flow-controls-bg: #2d2d2d;\n --react-flow-controls-border: #404040;\n --react-flow-minimap-bg: #2d2d2d;\n --react-flow-minimap-border: #404040;\n}\n\n.react-flow-light {\n --react-flow-background: #f5f5f5;\n --react-flow-text: #1a1a1a;\n --react-flow-border: #e9ecef;\n --react-flow-controls-bg: #f8f9fa;\n --react-flow-controls-border: #e9ecef;\n --react-flow-minimap-bg: #f8f9fa;\n --react-flow-minimap-border: #e9ecef;\n}\n\n/* Apply ReactFlow theming */\n.react-flow-dark .react-flow__background {\n background-color: var(--react-flow-background);\n}\n\n.react-flow-light .react-flow__background {\n background-color: var(--react-flow-background);\n}\n\n/* Ensure canvas background is always off-white in light mode */\n.react-flow-light .react-flow__viewport {\n background-color: #f5f5f5 !important;\n}\n\n.react-flow-light .react-flow {\n background-color: #f5f5f5;\n}\n\n.react-flow-dark .react-flow__controls {\n background-color: var(--react-flow-controls-bg);\n border-color: var(--react-flow-controls-border);\n}\n\n.react-flow-light .react-flow__controls {\n background-color: var(--react-flow-controls-bg);\n border-color: var(--react-flow-controls-border);\n}\n\n.react-flow-dark .react-flow__minimap {\n background-color: var(--react-flow-minimap-bg);\n border-color: var(--react-flow-minimap-border);\n}\n\n.react-flow-light .react-flow__minimap {\n background-color: var(--react-flow-minimap-bg);\n border-color: var(--react-flow-minimap-border);\n}\n\n.react-flow-dark .react-flow__controls-button {\n background-color: var(--react-flow-controls-bg);\n color: var(--react-flow-text);\n border-color: var(--react-flow-controls-border);\n}\n\n.react-flow-light .react-flow__controls-button {\n background-color: var(--react-flow-controls-bg);\n color: var(--react-flow-text);\n border-color: var(--react-flow-controls-border);\n}\n\n.react-flow-dark .react-flow__controls-button:hover {\n background-color: #4b5563;\n}\n\n.react-flow-light .react-flow__controls-button:hover {\n background-color: #e9ecef;\n}\n\n/* Override React Flow default handle styles for tube fiber handles */\n/* Use CSS variables set by inline styles to override React Flow defaults */\n.react-flow__handle.tube-fiber-handle {\n border: none !important;\n transform: none !important;\n background-clip: padding-box !important;\n opacity: 1 !important;\n /* Remove React Flow's default background completely */\n background: var(--fiber-bg-image, var(--fiber-bg)) !important;\n background-color: var(--fiber-bg) !important;\n /* Ensure no default React Flow styles interfere */\n box-shadow: none !important;\n}\n\n.react-flow__handle-right.tube-fiber-handle {\n right: auto !important;\n}\n\n/* More specific selector to ensure override - target all possible React Flow handle states */\n.react-flow__node .react-flow__handle.tube-fiber-handle,\n.react-flow__node .react-flow__handle.tube-fiber-handle[data-handlepos],\n.react-flow__handle.tube-fiber-handle[data-handlepos],\n.react-flow__handle.tube-fiber-handle[data-fiber-idx] {\n background: var(--fiber-bg-image, var(--fiber-bg)) !important;\n background-color: var(--fiber-bg) !important;\n background-image: var(--fiber-bg-image, none) !important;\n}\n\n/* Connection animation - pulse effect when edge is first created */\n@keyframes edgeConnectPulse {\n 0% {\n opacity: 0;\n stroke-width: 1;\n }\n 50% {\n opacity: 1;\n stroke-width: 4;\n }\n 100% {\n opacity: 1;\n stroke-width: 2;\n }\n}\n\n.react-flow__edge.edge-connecting path,\n.react-flow__edge.edge-connecting .react-flow__edge-path {\n animation: edgeConnectPulse 1s ease-out;\n}\n\n/* Splice glow animation - fade in when both handles are connected */\n@keyframes spliceGlowFadeIn {\n 0% {\n opacity: 0;\n transform: translateX(-50%) scaleY(0.3);\n }\n 100% {\n opacity: 1;\n transform: translateX(-50%) scaleY(1);\n }\n}\n\n.splice-glow {\n animation: spliceGlowFadeIn 0.5s ease-out;\n transform-origin: center;\n}\n\n/* Splice text animation - fade in when both handles are connected */\n@keyframes spliceTextFadeIn {\n 0% {\n opacity: 0;\n transform: scale(0.8);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n/* Splice text overlay - blur and opacity for text readability */\n.splice-text-overlay {\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n}\n\n/* Dark mode overlay */\n.react-flow-dark .splice-text-overlay {\n background: rgba(0, 0, 0, 0.6);\n}\n\n/* Light mode overlay */\n.react-flow-light .splice-text-overlay {\n background: rgba(255, 255, 255, 0.7);\n}\n\n/* Splice text label - theme-aware colors */\n.splice-text-label {\n color: #fff;\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 0 2px rgba(0, 0, 0, 0.6);\n}\n\n.splice-text-label.animate-in {\n animation: spliceTextFadeIn 0.5s ease-out;\n transform-origin: center;\n}\n\n/* Light mode text */\n.react-flow-light .splice-text-label {\n color: #1a1a1a;\n text-shadow: 0 1px 2px rgba(255, 255, 255, 0.9), 0 0 4px rgba(255, 255, 255, 0.7);\n}\n\n/* Remove all borders from splice nodes */\n.react-flow__node[data-type=\"splice\"],\n.react-flow__node[data-type=\"splice\"] > div {\n border: none !important;\n outline: none !important;\n}\n\n.splice-node {\n border: none !important;\n outline: none !important;\n}\n\n/* Only remove box-shadow when not selected */\n.react-flow__node[data-type=\"splice\"]:not(.selected) > div,\n.splice-node:not(.selected) {\n box-shadow: none !important;\n}\n\n/* React Networks Attribution */\n.react-networks-attribution {\n padding: 0;\n margin: 0;\n z-index: 1000;\n}\n\n.react-networks-attribution-link {\n font-size: 7px;\n color: #9ca3af;\n text-decoration: none;\n font-family: Inter, system-ui, -apple-system, sans-serif;\n transition: color 0.2s ease;\n padding: 1px 4px;\n border-radius: 2px;\n display: inline-block;\n background: rgba(0, 0, 0, 0.3);\n backdrop-filter: blur(4px);\n}\n\n.react-networks-attribution-link:hover {\n color: #e5e7eb;\n background: rgba(0, 0, 0, 0.4);\n}\n\n/* Light mode attribution */\n.react-flow-light .react-networks-attribution-link {\n color: #6b7280;\n background: rgba(255, 255, 255, 0.6);\n}\n\n.react-flow-light .react-networks-attribution-link:hover {\n color: #1a1a1a;\n background: rgba(255, 255, 255, 0.8);\n}\n\n/* Coupler node styles */\n.coupler-node {\n transition: box-shadow 0.2s ease;\n}\n\n.coupler-node.selected {\n box-shadow: 0 0 0 2px #3b82f6 !important;\n}\n\n/* Patch panel node styles */\n.patch-panel-node {\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n}\n\n.patch-panel-node.selected {\n box-shadow: 0 0 0 2px #3b82f6 !important;\n border-color: #3b82f6 !important;\n}\n\n/* Closure node styles */\n.closure-node {\n transition: box-shadow 0.2s ease, border-color 0.2s ease;\n}\n\n.closure-node.selected {\n box-shadow: 0 0 0 2px #3b82f6 !important;\n border-color: #3b82f6 !important;\n}\n\n/* Light mode adjustments */\n.react-flow-light .coupler-node {\n background: #f9fafb;\n color: #1f2937;\n border-color: #d1d5db;\n}\n\n.react-flow-light .patch-panel-node {\n background: transparent !important;\n color: #1f2937;\n border-color: #d1d5db;\n}\n\n.react-flow-light .closure-node {\n background: transparent !important;\n color: #1f2937;\n border-color: #d1d5db;\n}\n\n"],"mappings":"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","names":[]}
package/dist/index.d.mts CHANGED
@@ -39,7 +39,7 @@ interface PortBlock {
39
39
  * Network node types supported by the diagram
40
40
  * @public
41
41
  */
42
- type NetworkNodeType = 'rack' | 'switch' | 'router' | 'server' | 'fiber' | 'patch-panel' | 'device' | 'vertical-pdu';
42
+ type NetworkNodeType = 'rack' | 'switch' | 'router' | 'server' | 'fiber' | 'patch-panel' | 'device' | 'vertical-pdu' | 'splice' | 'splice-tray' | 'tube' | 'cable' | 'coupler' | 'closure';
43
43
  /**
44
44
  * Device status states
45
45
  * @public
@@ -118,6 +118,30 @@ interface NetworkNode {
118
118
  uNumberingDirection?: UNumberingDirection;
119
119
  /** Custom header text for rack nodes */
120
120
  customHeaderText?: string;
121
+ /** Holder position within tray (1-12) for splice nodes */
122
+ holderPosition?: number;
123
+ /** Loss value in dB for splice nodes */
124
+ lossDb?: number;
125
+ /** Connector type for coupler nodes */
126
+ connector?: 'SC' | 'LC';
127
+ /** Number of fibers for coupler nodes (1, 2, or 4) */
128
+ couplerFiberCount?: 1 | 2 | 4;
129
+ /** Optional port labels for left side of coupler */
130
+ portLabelsLeft?: string[];
131
+ /** Optional port labels for right side of coupler */
132
+ portLabelsRight?: string[];
133
+ /** Slot position for couplers inside panels (1-based, vertical slots aligned to right edge) */
134
+ slotPosition?: number;
135
+ /** Width override for container nodes (patch-panel, closure) */
136
+ panelWidth?: number;
137
+ /** Height override for container nodes (patch-panel, closure) */
138
+ panelHeight?: number;
139
+ /** Number of rows for container nodes (patch-panel, closure) */
140
+ rows?: number;
141
+ /** Number of columns for container nodes (patch-panel, closure) */
142
+ cols?: number;
143
+ /** Header text for container nodes */
144
+ header?: string;
121
145
  /** Additional custom properties */
122
146
  [key: string]: any;
123
147
  };
@@ -126,7 +150,7 @@ interface NetworkNode {
126
150
  * Network edge types
127
151
  * @public
128
152
  */
129
- type NetworkEdgeType = 'fiber' | 'ethernet' | 'power';
153
+ type NetworkEdgeType = 'fiber' | 'ethernet' | 'power' | 'smoothstep' | 'step' | 'thick-cable';
130
154
  /**
131
155
  * Network edge data structure
132
156
  * @public
@@ -242,6 +266,37 @@ interface FiberCable {
242
266
  to: string;
243
267
  };
244
268
  }
269
+ /**
270
+ * Splice configuration structure
271
+ * @public
272
+ */
273
+ interface SpliceConfig {
274
+ /** Unique splice identifier */
275
+ id: string;
276
+ /** Splice display name */
277
+ name: string;
278
+ /** Holder position within tray (1-12) */
279
+ holder: number;
280
+ /** Loss value in dB */
281
+ lossDb?: number;
282
+ }
283
+ /**
284
+ * Splice tray configuration structure
285
+ * @public
286
+ */
287
+ interface SpliceTrayConfig {
288
+ /** Unique tray identifier */
289
+ id: string;
290
+ /** Tray display name */
291
+ name: string;
292
+ /** Tray position coordinates */
293
+ position: {
294
+ x: number;
295
+ y: number;
296
+ };
297
+ /** Splices in this tray */
298
+ splices: SpliceConfig[];
299
+ }
245
300
  /**
246
301
  * Network diagram component props
247
302
  * @public
@@ -297,6 +352,10 @@ interface NetworkDiagramProps {
297
352
  downloadButtonText?: string;
298
353
  /** Download button styling options */
299
354
  downloadButtonStyle?: React.CSSProperties;
355
+ /** Allow reconnecting existing edges from either end */
356
+ allowReconnectExisting?: boolean;
357
+ /** Use smoothstep edges for tube connections (both tube-to-cable and cable-to-tube). Default is fiber. */
358
+ useSmoothstepEdgesForTubes?: boolean;
300
359
  }
301
360
 
302
361
  declare const NetworkDiagram: React$1.FC<NetworkDiagramProps>;
@@ -310,7 +369,9 @@ declare const RackNode: React$1.FC<RackNodeProps>;
310
369
 
311
370
  declare const FiberNode: React$1.FC<NodeProps<NetworkNode['data']>>;
312
371
 
313
- declare const FiberEdge: React$1.FC<EdgeProps<NetworkEdge['data']>>;
372
+ declare const FiberEdge: React$1.FC<EdgeProps<NetworkEdge['data']> & {
373
+ className?: string;
374
+ }>;
314
375
 
315
376
  declare const PowerEdge: React$1.FC<EdgeProps>;
316
377
 
@@ -318,6 +379,36 @@ declare const DeviceNode: React$1.FC<NodeProps<NetworkNode['data']>>;
318
379
 
319
380
  declare const VerticalPDU: React$1.FC<NodeProps<NetworkNode['data']>>;
320
381
 
382
+ declare const SpliceNode: React$1.FC<NodeProps<NetworkNode['data']>>;
383
+
384
+ declare const SpliceTrayNode: React$1.FC<NodeProps<NetworkNode['data']>>;
385
+
386
+ /**
387
+ * TubeNode
388
+ * - Rectangular node representing a buffer tube (horizontal orientation, rotated 180 degrees)
389
+ * - Renders 12 or 24 fiber handles on the top side with TIA-598 colors
390
+ * - Tube border tinted by tube index color (1..12 cycling)
391
+ * - startOn parameter controls handle positioning:
392
+ * - 'left-center' (default): handles centered on top, tube handle on bottom
393
+ * - 'left': handles on left side, tube handle on left
394
+ * - 'right': handles on right side with reversed colors, tube handle on right
395
+ */
396
+ declare const TubeNode: React$1.FC<NodeProps<NetworkNode['data']>>;
397
+
398
+ /**
399
+ * CableNode
400
+ * - Visually mirrors TubeNode but represents an entire cable
401
+ * - Each colored handle corresponds to a tube within the cable
402
+ * - Displays cable summary text (fiber count + cable identifier)
403
+ */
404
+ declare const CableNode: React$1.FC<NodeProps<NetworkNode['data']>>;
405
+
406
+ declare const CouplerNode: React$1.FC<NodeProps<NetworkNode['data']>>;
407
+
408
+ declare const PatchPanelNode: React$1.FC<NodeProps<NetworkNode['data']>>;
409
+
410
+ declare const ClosureNode: React$1.FC<NodeProps<NetworkNode['data']>>;
411
+
321
412
  interface InventoryRackDTO {
322
413
  id: string | number;
323
414
  name: string;
@@ -461,6 +552,137 @@ declare const updateDeviceUPosition$1: (device: NetworkNode, rack: NetworkNode,
461
552
  */
462
553
  declare const validateAndSnapDevice: (device: NetworkNode, rack: NetworkNode) => NetworkNode;
463
554
 
555
+ /**
556
+ * Snap a splice to the nearest holder position within a tray
557
+ */
558
+ declare const snapToSplicePosition: (splice: NetworkNode, tray: NetworkNode, newPosition: {
559
+ x: number;
560
+ y: number;
561
+ }, allNodes: NetworkNode[]) => {
562
+ x: number;
563
+ y: number;
564
+ holderPosition?: number;
565
+ };
566
+ /**
567
+ * Find the next available holder position
568
+ */
569
+ declare const findNextAvailableHolderPosition: (tray: NetworkNode, splice: NetworkNode, allNodes: NetworkNode[], startFrom?: number) => number;
570
+ /**
571
+ * Calculate splice position based on holder number within a tray
572
+ */
573
+ declare const calculateSplicePositionFromNumber: (tray: NetworkNode, holderPosition: number) => {
574
+ x: number;
575
+ y: number;
576
+ };
577
+
578
+ /**
579
+ * Panel header height in pixels
580
+ */
581
+ declare const PANEL_HEADER_HEIGHT = 32;
582
+ /**
583
+ * Coupler slot height in pixels
584
+ */
585
+ declare const COUPLER_SLOT_HEIGHT_PX = 30;
586
+ /**
587
+ * Default number of couplers per panel
588
+ */
589
+ declare const COUPLERS_PER_PANEL = 24;
590
+ /**
591
+ * Default coupler width in pixels
592
+ */
593
+ declare const COUPLER_WIDTH_PX = 80;
594
+ /**
595
+ * Default panel width in pixels
596
+ */
597
+ declare const PANEL_WIDTH_PX = 400;
598
+ /**
599
+ * Default panel height in pixels
600
+ */
601
+ declare const PANEL_HEIGHT_PX = 300;
602
+ /**
603
+ * Panel border width in pixels
604
+ */
605
+ declare const PANEL_BORDER_WIDTH = 2;
606
+ /**
607
+ * Panel padding in pixels
608
+ */
609
+ declare const PANEL_PADDING = 8;
610
+ /**
611
+ * Spacing between tubes and trays in patch panels (horizontal spacing)
612
+ */
613
+ declare const PANEL_TUBE_TRAY_SPACING = 120;
614
+ /**
615
+ * Calculate coupler dimensions based on node data
616
+ */
617
+ declare function getCouplerDimensions(node: NetworkNode): {
618
+ width: number;
619
+ height: number;
620
+ };
621
+ /**
622
+ * Calculate tube dimensions based on node data
623
+ */
624
+ declare function getTubeDimensions(node: NetworkNode): {
625
+ width: number;
626
+ height: number;
627
+ };
628
+ /**
629
+ * Get tray dimensions
630
+ */
631
+ declare function getTrayDimensions(_node: NetworkNode): {
632
+ width: number;
633
+ height: number;
634
+ };
635
+ /**
636
+ * Calculate panel width based on content
637
+ */
638
+ declare function getPanelWidth(panelNode: NetworkNode): number;
639
+ /**
640
+ * Calculate panel height based on content
641
+ */
642
+ declare function getPanelHeight(panelNode: NetworkNode): number;
643
+ /**
644
+ * Get inner content width (panel width minus borders/padding)
645
+ */
646
+ declare function getInnerContentWidth(panelNode: NetworkNode): number;
647
+ /**
648
+ * Calculate coupler right X position
649
+ */
650
+ declare function calculateCouplerRightX(panelNode: NetworkNode, couplerWidth: number): number;
651
+ /**
652
+ * Calculate slot position from Y coordinate
653
+ */
654
+ declare function calculateSlotPositionFromY(y: number, slotHeight?: number): number;
655
+ /**
656
+ * Calculate Y coordinate from slot position
657
+ */
658
+ declare function calculateYFromSlotPosition(slot: number, slotHeight?: number): number;
659
+ /**
660
+ * Snap coupler to nearest slot position
661
+ */
662
+ declare function snapToCouplerPosition(coupler: NetworkNode, panel: NetworkNode, position: {
663
+ x: number;
664
+ y: number;
665
+ }): {
666
+ x: number;
667
+ y: number;
668
+ slotPosition?: number;
669
+ };
670
+ /**
671
+ * Calculate panel dimensions based on child nodes
672
+ */
673
+ declare function calculatePanelDimensions(panelNode: NetworkNode, childNodes: NetworkNode[]): {
674
+ width: number;
675
+ height: number;
676
+ };
677
+ /**
678
+ * Calculate spacing between couplers
679
+ */
680
+ declare function calculateCouplerSpacing(numCouplers: number, couplerHeight: number, availableHeight: number): number;
681
+ /**
682
+ * Calculate coupler slot spacing
683
+ */
684
+ declare function calculateCouplerSlotSpacing(numCouplers: number, couplerHeight: number, availableHeight: number): number;
685
+
464
686
  /**
465
687
  * Configuration options for building nodes from rack schema
466
688
  */
@@ -526,6 +748,66 @@ declare function addDeviceToRack(racks: RackConfig[], rackId: string, device: Ra
526
748
  */
527
749
  declare function removeDeviceFromRack(racks: RackConfig[], rackId: string, deviceId: string): RackConfig[];
528
750
 
751
+ /**
752
+ * Configuration options for building nodes from splice schema
753
+ */
754
+ interface SpliceSchemaOptions {
755
+ /** How to handle splice placement conflicts */
756
+ conflictPolicy?: 'strict' | 'nearest';
757
+ /** Whether to validate all placements before creating nodes */
758
+ validatePlacements?: boolean;
759
+ }
760
+ /**
761
+ * Error thrown when splice placement conflicts occur in strict mode
762
+ */
763
+ declare class SplicePlacementError extends Error {
764
+ trayId: string;
765
+ spliceId: string;
766
+ holder: number;
767
+ conflictWith?: string | undefined;
768
+ constructor(trayId: string, spliceId: string, holder: number, conflictWith?: string | undefined);
769
+ }
770
+ /**
771
+ * Validation result for splice placement
772
+ */
773
+ interface SplicePlacementValidation {
774
+ isValid: boolean;
775
+ conflicts: Array<{
776
+ spliceId: string;
777
+ holder: number;
778
+ conflictWith: string;
779
+ }>;
780
+ outOfBounds: Array<{
781
+ spliceId: string;
782
+ holder: number;
783
+ max: number;
784
+ }>;
785
+ }
786
+ /**
787
+ * Validate splice placements within a tray schema
788
+ */
789
+ declare function validateSplicePlacements(tray: SpliceTrayConfig, _options?: SpliceSchemaOptions): SplicePlacementValidation;
790
+ /**
791
+ * Build NetworkNode array from SpliceTrayConfig array with comprehensive validation
792
+ */
793
+ declare function buildNodesFromSpliceConfig(trays: SpliceTrayConfig[], options?: SpliceSchemaOptions): NetworkNode[];
794
+ /**
795
+ * Create a SpliceTrayConfig from existing NetworkNode data (reverse operation)
796
+ */
797
+ declare function createSpliceConfigFromNodes(nodes: NetworkNode[]): SpliceTrayConfig[];
798
+ /**
799
+ * Update splice holder position in a splice schema
800
+ */
801
+ declare function updateSpliceHolderPosition(trays: SpliceTrayConfig[], trayId: string, spliceId: string, newHolder: number): SpliceTrayConfig[];
802
+ /**
803
+ * Add a splice to a tray schema
804
+ */
805
+ declare function addSpliceToTray(trays: SpliceTrayConfig[], trayId: string, splice: SpliceConfig, options?: SpliceSchemaOptions): SpliceTrayConfig[];
806
+ /**
807
+ * Remove a splice from a tray schema
808
+ */
809
+ declare function removeSpliceFromTray(trays: SpliceTrayConfig[], trayId: string, spliceId: string): SpliceTrayConfig[];
810
+
529
811
  /**
530
812
  * Power connector utilities for consistent styling across devices and PDUs
531
813
  */
@@ -577,6 +859,48 @@ declare function getDeviceConnectorType(deviceName: string): string;
577
859
  */
578
860
  declare function getStatusColor(status: DeviceStatus | string): string;
579
861
 
862
+ /**
863
+ * TIA-598-C standard fiber optic color codes (12 base colors)
864
+ * Colors 1-12: Blue, Orange, Green, Brown, Slate, White, Red, Black, Yellow, Violet, Rose, Aqua
865
+ * @public
866
+ */
867
+ declare const FIBER_COLORS_12: readonly ["#1f77b4", "#ff7f0e", "#2ca02c", "#8c564b", "#708090", "#ffffff", "#d62728", "#000000", "#ffdf00", "#8a2be2", "#ff69b4", "#00ffff"];
868
+ /**
869
+ * Fiber color ID type (1-24)
870
+ * @public
871
+ */
872
+ 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;
873
+ /**
874
+ * Get the base color for a fiber color ID
875
+ * Colors 13-24 use the same base colors as 1-12
876
+ * @param id - Fiber color ID (1-24)
877
+ * @returns Hex color code
878
+ * @public
879
+ */
880
+ declare function baseColorFor(id: FiberColorId | number): string;
881
+ /**
882
+ * Check if a fiber color ID uses a striped pattern (13-24)
883
+ * @param id - Fiber color ID (1-24)
884
+ * @returns True if the color should be striped
885
+ * @public
886
+ */
887
+ declare function isStriped(id: FiberColorId | number): boolean;
888
+ /**
889
+ * Get CSS properties for a fiber color (solid or striped)
890
+ * Colors 13-24 use a black stripe pattern over the base color
891
+ * @param id - Fiber color ID (1-24)
892
+ * @returns CSS properties for the color
893
+ * @public
894
+ */
895
+ declare function fiberSolidOrStriped(id: FiberColorId | number): React$1.CSSProperties;
896
+ /**
897
+ * Get the hex color code for a fiber color ID
898
+ * @param id - Fiber color ID (1-24)
899
+ * @returns Hex color code
900
+ * @public
901
+ */
902
+ declare function getFiberColor(id: FiberColorId | number): string;
903
+
580
904
  /**
581
905
  * Calculate the bounding box of a rack node
582
906
  * @param rack - The rack node
@@ -622,11 +946,13 @@ interface ReplaceEdgeOptions {
622
946
  /** Connection parameters for the new edge */
623
947
  connection: Connection;
624
948
  /** Type of edge to create */
625
- edgeType: 'power' | 'fiber';
949
+ edgeType: 'power' | 'fiber' | 'step' | 'smoothstep' | 'thick-cable';
626
950
  /** Function to calculate zIndex for the edge */
627
951
  selectEdgeZIndex: (edge: NetworkEdge) => number;
628
952
  /** Whether to find edge by source or target */
629
953
  findBy: 'source' | 'target';
954
+ /** Optional edge data to set on the new edge */
955
+ data?: NetworkEdge['data'];
630
956
  }
631
957
  /**
632
958
  * Replace an existing edge with a new connection
@@ -670,4 +996,4 @@ declare function useNetworkDiagram(store: NetworkDiagramStore): NetworkDiagramSt
670
996
  declare function useNodes(store: NetworkDiagramStore): NetworkNode[];
671
997
  declare function useEdges(store: NetworkDiagramStore): NetworkEdge[];
672
998
 
673
- export { DeviceNode, DevicePlacementError, type DevicePlacementValidation, type FiberCable, FiberEdge, FiberNode, NetworkDiagram, type NetworkDiagramProps, type NetworkEdge, type NetworkNode, POWER_CONNECTORS, type Port, type PortBlock, PowerEdge, type RackConfig, type RackDevice, RackNode, type RackSchemaOptions, type ReplaceEdgeOptions, VerticalPDU, Width, addDeviceToRack, buildNodesFromRackConfig, calculateDevicePositionFromU, createNetworkDiagramStore, createRackConfigFromNodes, findNearestRack, findNextAvailableUPosition, generateLayout, getConnectorConfig, getDeviceConnectorType, getPDUPortType, getPowerPortStyle, getRackBounds, getStatusColor, inventoryCableToNetworkEdge, inventoryDeviceToNetworkNode, inventoryRackToNetworkNode, inventoryToNetworkDiagram, isHighPowerConnector, isPointInRack, isUPositionAvailable, removeDeviceFromRack, replaceEdge, snapToUPosition, updateDeviceUPosition$1 as updateDeviceUPosition, updateDeviceUPosition as updateDeviceUPositionInSchema, useEdges as useDiagramEdges, useNodes as useDiagramNodes, useNetworkDiagram, validateAndSnapDevice, validateRackDevicePlacements };
999
+ 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, 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, 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 };