@mp70/react-networks 0.2.0-rc.0 → 0.3.0-alpha.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.
package/dist/index.css CHANGED
@@ -430,6 +430,51 @@
430
430
  width: 4px;
431
431
  }
432
432
 
433
+ .device-node__split-face {
434
+ background-color: #1f2937;
435
+ }
436
+
437
+ .device-node__split-face--front {
438
+ border-left: 1px dashed rgba(156, 163, 175, 0.35);
439
+ }
440
+
441
+ .device-node__split-face--rear {
442
+ border-right: 1px dashed rgba(156, 163, 175, 0.35);
443
+ }
444
+
445
+ .device-node__face-bridge {
446
+ position: relative;
447
+ }
448
+
449
+ .device-node__face-bridge-line {
450
+ background: linear-gradient(180deg, transparent 0%, rgba(156, 163, 175, 0.8) 20%, rgba(156, 163, 175, 0.8) 80%, transparent 100%);
451
+ left: 50%;
452
+ position: absolute;
453
+ top: 1px;
454
+ transform: translateX(-50%);
455
+ width: 1px;
456
+ height: calc(100% - 2px);
457
+ }
458
+
459
+ .device-node__face-bridge-label {
460
+ background: rgba(17, 24, 39, 0.82);
461
+ border: 1px solid rgba(156, 163, 175, 0.4);
462
+ border-radius: 999px;
463
+ color: #d1d5db;
464
+ font-size: 6px;
465
+ font-weight: 700;
466
+ left: 50%;
467
+ letter-spacing: 0.04em;
468
+ max-width: 120px;
469
+ overflow: hidden;
470
+ padding: 1px 6px;
471
+ position: absolute;
472
+ text-overflow: ellipsis;
473
+ top: 50%;
474
+ transform: translate(-50%, -50%) rotate(-90deg);
475
+ white-space: nowrap;
476
+ }
477
+
433
478
  /* Light mode adjustments */
434
479
  .react-flow-light .coupler-node {
435
480
  background: #f9fafb;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/styles/index.css"],"sourcesContent":["/* Library styles for @mp70/react-networks */\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/* Mobile-friendly control buttons - larger touch targets */\n@media (max-width: 768px) {\n .react-flow__controls-button {\n width: 44px !important;\n height: 44px !important;\n min-width: 44px !important;\n min-height: 44px !important;\n }\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 /* Ensure no default React Flow styles interfere */\n box-shadow: none !important;\n /* Don't set background here - let inline styles or specific rules handle it */\n}\n\n/* Tube fiber handles - use fiber color */\n.react-flow__handle.tube-fiber-handle {\n background: var(--fiber-bg-image, var(--fiber-bg)) !important;\n background-color: var(--fiber-bg) !important;\n}\n\n/* Fibre flow map handles */\n.react-flow__handle.fibre-flow-handle {\n border: none !important;\n transform: none !important;\n background-clip: padding-box !important;\n opacity: 1 !important;\n box-shadow: none !important;\n}\n\n.react-flow__handle.fibre-flow-handle {\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\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/* Only apply to non-ribbon handles */\n.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle),\n.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],\n.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],\n.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-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/* Ribbon bundle handles - simple solid color (removed gradient complexity) */\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/* Highlighted edge pulse + dash motion (trace paths) */\n@keyframes rnEdgeHighlightPulse {\n 0%,\n 100% {\n opacity: 0.85;\n stroke-width: var(--rn-edge-highlight-from, 2px);\n }\n 50% {\n opacity: 1;\n stroke-width: var(--rn-edge-highlight-to, 6px);\n }\n}\n\n@keyframes rnEdgeHighlightDash {\n 0% {\n stroke-dashoffset: 0;\n }\n 100% {\n stroke-dashoffset: -48;\n }\n}\n\n.rn-edge-highlight {\n animation: rnEdgeHighlightPulse 2.4s ease-in-out infinite,\n rnEdgeHighlightDash 1.8s linear infinite;\n opacity: 0.9;\n stroke-linecap: round;\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 background: transparent !important;\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: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\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/* Device node styles */\n.device-node {\n background-color: #1f2937;\n background-image: var(--rn-device-bg-image, none);\n background-position: var(--rn-device-bg-position, center);\n background-repeat: var(--rn-device-bg-repeat, no-repeat);\n background-size: var(--rn-device-bg-size, cover);\n border: 1px solid var(--rn-device-border-color, #10b981);\n border-radius: 2px;\n box-shadow: var(--rn-device-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.1));\n box-sizing: border-box;\n color: white;\n cursor: grab;\n display: flex;\n flex-direction: column;\n font-family: monospace;\n font-size: 8px;\n height: var(--rn-device-height, 20px);\n justify-content: center;\n left: var(--rn-device-left, auto);\n margin: 0;\n padding: 0;\n position: relative;\n transform: translateY(var(--rn-device-translate-y, 0px));\n width: var(--rn-device-width, 100%);\n}\n\n.device-node__content {\n display: flex;\n flex: 1;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n padding: 2px;\n text-align: center;\n}\n\n.device-node__label {\n font-size: 7px;\n font-weight: bold;\n line-height: 1.1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.device-node__manufacturer {\n color: #9ca3af;\n font-size: 6px;\n line-height: 1;\n}\n\n.device-node__u-indicator {\n background: #374151;\n border-radius: 1px;\n bottom: 1px;\n color: #9ca3af;\n font-size: 6px;\n line-height: 1;\n padding: 1px 2px;\n position: absolute;\n right: 1px;\n}\n\n.device-node__status-indicator {\n background: var(--rn-device-status-color, #6b7280);\n border-radius: 50%;\n bottom: 1px;\n height: 4px;\n left: 1px;\n position: absolute;\n width: 4px;\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/* Triangle node styles */\n.react-flow__node[data-type=\"fibre-split\"],\n.react-flow__node.react-flow__node-fibre-split {\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n}\n\n.react-flow__node[data-type=\"fibre-split\"] > div,\n.react-flow__node.react-flow__node-fibre-split > div {\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n box-shadow: none !important;\n overflow: visible !important;\n}\n\n.react-flow__node[data-type=\"fibre-split\"] svg,\n.react-flow__node.react-flow__node-fibre-split svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n}\n\n.triangle-node {\n position: relative !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n margin: 0 !important;\n box-shadow: none !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\n\n.triangle-node-text {\n text-align: center;\n position: relative;\n z-index: 2;\n width: 46px;\n height: 46px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n color: #000000;\n font-weight: bold;\n font-size: 12px;\n}\n\n/* Cable node rotation */\n.cable-node-rotated {\n transform-origin: center center !important;\n}\n\n/* Ensure Fibre Flow edges render with full saturation and aren't affected by node overlays */\n.react-flow__edge[data-type=\"fibre-flow\"] path,\n.react-flow__edge[data-type=\"fibre-flow\"] .react-flow__edge-path {\n opacity: 1 !important;\n stroke-opacity: 1 !important;\n mix-blend-mode: normal !important;\n filter: none !important;\n}\n\n.react-flow__edge[data-type=\"fibre-flow-link\"] path,\n.react-flow__edge[data-type=\"fibre-flow-link\"] .react-flow__edge-path {\n opacity: 1 !important;\n stroke-opacity: 1 !important;\n mix-blend-mode: normal !important;\n filter: none !important;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/styles/index.css"],"sourcesContent":["/* Library styles for @mp70/react-networks */\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/* Mobile-friendly control buttons - larger touch targets */\n@media (max-width: 768px) {\n .react-flow__controls-button {\n width: 44px !important;\n height: 44px !important;\n min-width: 44px !important;\n min-height: 44px !important;\n }\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 /* Ensure no default React Flow styles interfere */\n box-shadow: none !important;\n /* Don't set background here - let inline styles or specific rules handle it */\n}\n\n/* Tube fiber handles - use fiber color */\n.react-flow__handle.tube-fiber-handle {\n background: var(--fiber-bg-image, var(--fiber-bg)) !important;\n background-color: var(--fiber-bg) !important;\n}\n\n/* Fibre flow map handles */\n.react-flow__handle.fibre-flow-handle {\n border: none !important;\n transform: none !important;\n background-clip: padding-box !important;\n opacity: 1 !important;\n box-shadow: none !important;\n}\n\n.react-flow__handle.fibre-flow-handle {\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\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/* Only apply to non-ribbon handles */\n.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle),\n.react-flow__node .react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],\n.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-handle)[data-handlepos],\n.react-flow__handle.tube-fiber-handle:not(.ribbon-bundle-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/* Ribbon bundle handles - simple solid color (removed gradient complexity) */\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/* Highlighted edge pulse + dash motion (trace paths) */\n@keyframes rnEdgeHighlightPulse {\n 0%,\n 100% {\n opacity: 0.85;\n stroke-width: var(--rn-edge-highlight-from, 2px);\n }\n 50% {\n opacity: 1;\n stroke-width: var(--rn-edge-highlight-to, 6px);\n }\n}\n\n@keyframes rnEdgeHighlightDash {\n 0% {\n stroke-dashoffset: 0;\n }\n 100% {\n stroke-dashoffset: -48;\n }\n}\n\n.rn-edge-highlight {\n animation: rnEdgeHighlightPulse 2.4s ease-in-out infinite,\n rnEdgeHighlightDash 1.8s linear infinite;\n opacity: 0.9;\n stroke-linecap: round;\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 background: transparent !important;\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: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\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/* Device node styles */\n.device-node {\n background-color: #1f2937;\n background-image: var(--rn-device-bg-image, none);\n background-position: var(--rn-device-bg-position, center);\n background-repeat: var(--rn-device-bg-repeat, no-repeat);\n background-size: var(--rn-device-bg-size, cover);\n border: 1px solid var(--rn-device-border-color, #10b981);\n border-radius: 2px;\n box-shadow: var(--rn-device-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.1));\n box-sizing: border-box;\n color: white;\n cursor: grab;\n display: flex;\n flex-direction: column;\n font-family: monospace;\n font-size: 8px;\n height: var(--rn-device-height, 20px);\n justify-content: center;\n left: var(--rn-device-left, auto);\n margin: 0;\n padding: 0;\n position: relative;\n transform: translateY(var(--rn-device-translate-y, 0px));\n width: var(--rn-device-width, 100%);\n}\n\n.device-node__content {\n display: flex;\n flex: 1;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n padding: 2px;\n text-align: center;\n}\n\n.device-node__label {\n font-size: 7px;\n font-weight: bold;\n line-height: 1.1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.device-node__manufacturer {\n color: #9ca3af;\n font-size: 6px;\n line-height: 1;\n}\n\n.device-node__u-indicator {\n background: #374151;\n border-radius: 1px;\n bottom: 1px;\n color: #9ca3af;\n font-size: 6px;\n line-height: 1;\n padding: 1px 2px;\n position: absolute;\n right: 1px;\n}\n\n.device-node__status-indicator {\n background: var(--rn-device-status-color, #6b7280);\n border-radius: 50%;\n bottom: 1px;\n height: 4px;\n left: 1px;\n position: absolute;\n width: 4px;\n}\n\n.device-node__split-face {\n background-color: #1f2937;\n}\n\n.device-node__split-face--front {\n border-left: 1px dashed rgba(156, 163, 175, 0.35);\n}\n\n.device-node__split-face--rear {\n border-right: 1px dashed rgba(156, 163, 175, 0.35);\n}\n\n.device-node__face-bridge {\n position: relative;\n}\n\n.device-node__face-bridge-line {\n background: linear-gradient(180deg, transparent 0%, rgba(156, 163, 175, 0.8) 20%, rgba(156, 163, 175, 0.8) 80%, transparent 100%);\n left: 50%;\n position: absolute;\n top: 1px;\n transform: translateX(-50%);\n width: 1px;\n height: calc(100% - 2px);\n}\n\n.device-node__face-bridge-label {\n background: rgba(17, 24, 39, 0.82);\n border: 1px solid rgba(156, 163, 175, 0.4);\n border-radius: 999px;\n color: #d1d5db;\n font-size: 6px;\n font-weight: 700;\n left: 50%;\n letter-spacing: 0.04em;\n max-width: 120px;\n overflow: hidden;\n padding: 1px 6px;\n position: absolute;\n text-overflow: ellipsis;\n top: 50%;\n transform: translate(-50%, -50%) rotate(-90deg);\n white-space: nowrap;\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/* Triangle node styles */\n.react-flow__node[data-type=\"fibre-split\"],\n.react-flow__node.react-flow__node-fibre-split {\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n}\n\n.react-flow__node[data-type=\"fibre-split\"] > div,\n.react-flow__node.react-flow__node-fibre-split > div {\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n box-shadow: none !important;\n overflow: visible !important;\n}\n\n.react-flow__node[data-type=\"fibre-split\"] svg,\n.react-flow__node.react-flow__node-fibre-split svg {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n}\n\n.triangle-node {\n position: relative !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n margin: 0 !important;\n box-shadow: none !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\n\n.triangle-node-text {\n text-align: center;\n position: relative;\n z-index: 2;\n width: 46px;\n height: 46px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n color: #000000;\n font-weight: bold;\n font-size: 12px;\n}\n\n/* Cable node rotation */\n.cable-node-rotated {\n transform-origin: center center !important;\n}\n\n/* Ensure Fibre Flow edges render with full saturation and aren't affected by node overlays */\n.react-flow__edge[data-type=\"fibre-flow\"] path,\n.react-flow__edge[data-type=\"fibre-flow\"] .react-flow__edge-path {\n opacity: 1 !important;\n stroke-opacity: 1 !important;\n mix-blend-mode: normal !important;\n filter: none !important;\n}\n\n.react-flow__edge[data-type=\"fibre-flow-link\"] path,\n.react-flow__edge[data-type=\"fibre-flow-link\"] .react-flow__edge-path {\n opacity: 1 !important;\n stroke-opacity: 1 !important;\n mix-blend-mode: normal !important;\n filter: none !important;\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.mts CHANGED
@@ -42,6 +42,36 @@ interface FibreFlowCircuit {
42
42
  color?: string;
43
43
  }
44
44
 
45
+ interface NetBoxPortPosition {
46
+ side?: 'top' | 'right' | 'bottom' | 'left';
47
+ offsetPercent?: number;
48
+ offsetPx?: number;
49
+ xPercent?: number;
50
+ yPercent?: number;
51
+ }
52
+ interface NetBoxMappedPort {
53
+ id?: string;
54
+ label?: string;
55
+ face?: 'front' | 'rear';
56
+ group?: string;
57
+ type?: string;
58
+ cableType?: string;
59
+ connected?: boolean;
60
+ connectorType?: 'C13' | 'C19' | 'C14' | 'C20';
61
+ position?: NetBoxPortPosition;
62
+ }
63
+ interface NetBoxDeviceTransformOptions {
64
+ /** Include interface arrays as `ports`/`rearPorts` in generated nodes */
65
+ includeInterfacePorts?: boolean;
66
+ /** Include per-port position metadata when provided */
67
+ includePortPositions?: boolean;
68
+ /** Optional mapper for full control over interface->port mapping */
69
+ mapInterfaceToPort?: (args: {
70
+ device: NetBoxDevice;
71
+ iface: NetBoxInterface;
72
+ index: number;
73
+ }) => NetBoxMappedPort | null | undefined;
74
+ }
45
75
  interface NetBoxDevice {
46
76
  id: number;
47
77
  name: string;
@@ -102,6 +132,18 @@ interface NetBoxInterface {
102
132
  type: string;
103
133
  color: string;
104
134
  } | null;
135
+ /** Optional face hint used by UI transforms */
136
+ face?: 'front' | 'rear' | null;
137
+ /** Optional display/ordering position from external enrichments */
138
+ position?: number | null;
139
+ /** Optional grouping hint used by UI transforms */
140
+ port_group?: string | null;
141
+ /** Optional explicit connector hint (e.g., C13/C19 for PDUs) */
142
+ connector_type?: 'C13' | 'C19' | 'C14' | 'C20' | null;
143
+ /** Optional transform layout metadata */
144
+ layout?: NetBoxMappedPort;
145
+ /** Optional custom fields payload from NetBox */
146
+ custom_fields?: Record<string, unknown>;
105
147
  }
106
148
  interface NetBoxRack {
107
149
  id: number;
@@ -239,7 +281,25 @@ interface DeviceImageOptions {
239
281
  /** When true, stretch device image to fill the device bounds (overrides imageFit) */
240
282
  stretchToFit?: boolean;
241
283
  }
284
+ /**
285
+ * Explicit handle placement for a device/PDU port.
286
+ * @public
287
+ */
288
+ interface PortPosition {
289
+ /** Handle side on the node */
290
+ side?: 'top' | 'right' | 'bottom' | 'left';
291
+ /** Side offset as percentage (0-100) */
292
+ offsetPercent?: number;
293
+ /** Side offset in pixels */
294
+ offsetPx?: number;
295
+ /** Absolute X position as percentage (0-100) */
296
+ xPercent?: number;
297
+ /** Absolute Y position as percentage (0-100) */
298
+ yPercent?: number;
299
+ }
242
300
  interface Port {
301
+ /** Stable handle identifier override (defaults to `label`) */
302
+ id?: string;
243
303
  /** Display label for the port */
244
304
  label: string;
245
305
  /** Whether the port is currently connected */
@@ -248,6 +308,10 @@ interface Port {
248
308
  type?: PortType;
249
309
  /** Cable type for connection validation */
250
310
  cableType?: PortCableType;
311
+ /** Optional power connector type for rendering (mainly for PDU ports) */
312
+ connectorType?: 'C13' | 'C14' | 'C19' | 'C20';
313
+ /** Optional explicit handle placement */
314
+ position?: PortPosition;
251
315
  }
252
316
  /**
253
317
  * Group of related ports on a device
@@ -274,6 +338,16 @@ type DeviceStatus = 'active' | 'inactive' | 'maintenance';
274
338
  * @public
275
339
  */
276
340
  type DeviceView = 'front' | 'rear';
341
+ /**
342
+ * Rack rendering layout modes.
343
+ * @public
344
+ */
345
+ type RackLayoutMode = 'single-face' | 'split-face';
346
+ /**
347
+ * Rack mounting behavior for a device.
348
+ * @public
349
+ */
350
+ type RackMountMode = 'front' | 'rear' | 'both';
277
351
  /**
278
352
  * Power port side configuration
279
353
  * @public
@@ -316,6 +390,12 @@ interface NetworkNodeDataBase extends DeviceImageOptions {
316
390
  view?: DeviceView;
317
391
  /** Rack face orientation */
318
392
  face?: DeviceView;
393
+ /** Rack rendering layout mode */
394
+ rackLayout?: RackLayoutMode;
395
+ /** Gap in pixels between front and rear faces in split-face mode */
396
+ rackFaceGapPx?: number;
397
+ /** Device mount behavior within a rack */
398
+ mountMode?: RackMountMode;
319
399
  /** Device type specification */
320
400
  deviceType?: string;
321
401
  /** Device manufacturer */
@@ -330,6 +410,10 @@ interface NetworkNodeDataBase extends DeviceImageOptions {
330
410
  heightCm?: number;
331
411
  /** Number of AC power ports */
332
412
  powerPorts?: number;
413
+ /** Optional explicit PDU connector sequence */
414
+ portTypes?: Array<'C13' | 'C19'>;
415
+ /** Optional grouped PDU ports (supports custom positions/types) */
416
+ pduPortGroups?: PortBlock[];
333
417
  /** Vertical PDU width in pixels */
334
418
  widthPx?: number;
335
419
  /** Optional management unit position for vertical PDUs */
@@ -558,6 +642,12 @@ interface NetworkEdgeData {
558
642
  label?: string;
559
643
  /** Optional opacity for styling (0–1) */
560
644
  opacity?: number;
645
+ /** Optional power edge stroke width override */
646
+ powerStrokeWidth?: number;
647
+ /** Optional power edge stroke dasharray override */
648
+ powerStrokeDasharray?: string;
649
+ /** Optional power edge opacity override (0–1) */
650
+ powerOpacity?: number;
561
651
  /** Additional extension metadata */
562
652
  metadata?: Record<string, unknown>;
563
653
  }
@@ -606,6 +696,10 @@ interface RackConfig {
606
696
  uNumberingDirection?: UNumberingDirection;
607
697
  /** Custom header text for rack */
608
698
  customHeaderText?: string;
699
+ /** Rack rendering layout mode */
700
+ rackLayout?: RackLayoutMode;
701
+ /** Gap in pixels between front and rear faces in split-face mode */
702
+ rackFaceGapPx?: number;
609
703
  /** Devices mounted in the rack */
610
704
  devices: RackDevice[];
611
705
  /** Optional rack width in pixels (default: 300px which represents standard 48.26cm/19" rack) */
@@ -628,6 +722,8 @@ interface RackDevice extends DeviceImageOptions {
628
722
  type: RackDeviceType;
629
723
  /** Device width configuration */
630
724
  width?: Width;
725
+ /** Device mount behavior within a rack */
726
+ mountMode?: RackMountMode;
631
727
  /** Device role in network */
632
728
  role?: string;
633
729
  /** Current status of the device */
@@ -1299,7 +1395,7 @@ declare const netboxRackToNetworkNode: (rack: NetBoxRack) => NetworkNode;
1299
1395
  /**
1300
1396
  * Convert NetBox device data to NetworkNode
1301
1397
  */
1302
- declare const netboxDeviceToNetworkNode: (device: NetBoxDevice) => NetworkNode;
1398
+ declare const netboxDeviceToNetworkNode: (device: NetBoxDevice, options?: NetBoxDeviceTransformOptions) => NetworkNode;
1303
1399
  /**
1304
1400
  * Convert NetBox cable data to NetworkEdge
1305
1401
  */
@@ -1311,7 +1407,7 @@ declare const netboxToNetworkDiagram: (data: {
1311
1407
  racks: NetBoxRack[];
1312
1408
  devices: NetBoxDevice[];
1313
1409
  cables: NetBoxCable[];
1314
- }) => {
1410
+ }, options?: NetBoxDeviceTransformOptions) => {
1315
1411
  nodes: NetworkNode[];
1316
1412
  edges: NetworkEdge[];
1317
1413
  };
@@ -1342,7 +1438,7 @@ declare const findNextAvailableUPosition: (rack: NetworkNode, device: NetworkNod
1342
1438
  /**
1343
1439
  * Calculate device position based on U position within a rack
1344
1440
  */
1345
- declare const calculateDevicePositionFromU: (rack: NetworkNode, uPosition: number, deviceHeight?: number) => {
1441
+ declare const calculateDevicePositionFromU: (rack: NetworkNode, uPosition: number, deviceHeight?: number, deviceData?: Pick<NetworkNode["data"], "mountMode">) => {
1346
1442
  x: number;
1347
1443
  y: number;
1348
1444
  };
@@ -1836,7 +1932,7 @@ declare function removeSpliceFromTray(trays: SpliceTrayConfig[], trayId: string,
1836
1932
  * Power connector utilities for consistent styling across devices and PDUs
1837
1933
  */
1838
1934
  interface PowerConnectorConfig {
1839
- type: 'C13' | 'C14' | 'C19' | 'C20';
1935
+ type: 'C13' | 'C14' | 'C19' | 'C20' | 'AC';
1840
1936
  color: string;
1841
1937
  borderColor: string;
1842
1938
  amperage: number;
@@ -1998,6 +2094,276 @@ interface ReplaceEdgeOptions {
1998
2094
  */
1999
2095
  declare function replaceEdge(options: ReplaceEdgeOptions): Edge[] | null;
2000
2096
 
2097
+ /**
2098
+ * Template Schema V2 — unified device template model.
2099
+ *
2100
+ * Supports rackable devices (1U+), 0U/unrackable devices (vertical PDUs),
2101
+ * and hybrid front/rear pass-through devices. Strictly more expressive than
2102
+ * NetBox device-type YAML while remaining import-compatible.
2103
+ *
2104
+ * @public
2105
+ */
2106
+
2107
+ /** Current schema version constant. */
2108
+ declare const TEMPLATE_SCHEMA_VERSION = 2;
2109
+ /** Device mount class — distinguishes rackable from 0U/standalone devices. */
2110
+ type MountClass = 'rackable' | 'zero-u';
2111
+ /** Device width within a rack (full 19" or half 9.5"). */
2112
+ type TemplateWidth = 'full' | 'half';
2113
+ /**
2114
+ * Individual port inside a template port block.
2115
+ * @public
2116
+ */
2117
+ interface TemplatePort {
2118
+ /** Stable identifier for the port (must be unique within the template). */
2119
+ id: string;
2120
+ /** Human-readable label. */
2121
+ label: string;
2122
+ /** Port classification for styling and validation. */
2123
+ type?: PortType;
2124
+ /** Cable type hint. */
2125
+ cableType?: PortCableType;
2126
+ /** Power connector classification. */
2127
+ connectorType?: 'C13' | 'C14' | 'C19' | 'C20' | 'AC';
2128
+ /** Explicit handle placement. */
2129
+ position?: PortPosition;
2130
+ }
2131
+ /**
2132
+ * Group of related ports on a single face.
2133
+ * @public
2134
+ */
2135
+ interface TemplatePortBlock {
2136
+ /** Group name. */
2137
+ name: string;
2138
+ /** Ports in this group. */
2139
+ ports: TemplatePort[];
2140
+ }
2141
+ /**
2142
+ * Per-face data container for front or rear.
2143
+ * @public
2144
+ */
2145
+ interface TemplateFaceData {
2146
+ /** Port blocks on this face. */
2147
+ portBlocks: TemplatePortBlock[];
2148
+ /** Optional image URL for this face. */
2149
+ imageUrl?: string;
2150
+ /** Optional attribution for the image. */
2151
+ imageAttribution?: string;
2152
+ }
2153
+ /**
2154
+ * Explicit front-to-rear pass-through link between ports.
2155
+ * @public
2156
+ */
2157
+ interface TemplateFrontRearPortLink {
2158
+ /** Port ID on the front face. */
2159
+ frontPortId: string;
2160
+ /** Port ID on the rear face. */
2161
+ rearPortId: string;
2162
+ }
2163
+ /**
2164
+ * Source provenance for an imported template.
2165
+ * @public
2166
+ */
2167
+ interface TemplateSource {
2168
+ /** Source system kind (e.g. 'netbox', 'manual'). */
2169
+ kind: string;
2170
+ /** Source repository URL. */
2171
+ repository?: string;
2172
+ /** Path within the repository. */
2173
+ path?: string;
2174
+ }
2175
+ /**
2176
+ * Canonical device template schema V2.
2177
+ * @public
2178
+ */
2179
+ interface DeviceTemplateV2 {
2180
+ /** Schema version — always 2. */
2181
+ templateSchemaVersion: 2;
2182
+ /** Unique identifier (e.g. 'cisco-c9300-48p'). */
2183
+ id: string;
2184
+ /** URL-safe slug. */
2185
+ slug: string;
2186
+ /** Device manufacturer. */
2187
+ manufacturer: string;
2188
+ /** Device model. */
2189
+ model: string;
2190
+ /** Device role (e.g. 'switch', 'pdu', 'server'). */
2191
+ role: string;
2192
+ /** Mount class — rackable (1U+) or zero-u. */
2193
+ mountClass: MountClass;
2194
+ /** Height in rack units (0 for zero-u devices). */
2195
+ uHeight: number;
2196
+ /** Width within a rack. */
2197
+ width: TemplateWidth;
2198
+ /** Per-face port and image data. */
2199
+ faces: {
2200
+ front: TemplateFaceData;
2201
+ rear: TemplateFaceData;
2202
+ };
2203
+ /** Explicit front-to-rear pass-through links. */
2204
+ frontRearPortLinks: TemplateFrontRearPortLink[];
2205
+ /** Optional image configuration. */
2206
+ images?: {
2207
+ front?: string | null;
2208
+ rear?: string | null;
2209
+ };
2210
+ /** Source provenance. */
2211
+ source?: TemplateSource;
2212
+ /** Optional tags for search/filtering. */
2213
+ tags?: string[];
2214
+ }
2215
+ /**
2216
+ * Single validation issue from the parser pipeline.
2217
+ * @public
2218
+ */
2219
+ interface TemplateValidationIssue {
2220
+ /** Severity level. */
2221
+ severity: 'error' | 'warning';
2222
+ /** Machine-readable code. */
2223
+ code: string;
2224
+ /** Human-readable description. */
2225
+ message: string;
2226
+ /** Optional path to the problematic field. */
2227
+ path?: string;
2228
+ }
2229
+ /**
2230
+ * Validation report emitted by the parser pipeline.
2231
+ * @public
2232
+ */
2233
+ interface TemplateValidationReport {
2234
+ /** Whether the template is valid (no errors — warnings are allowed). */
2235
+ valid: boolean;
2236
+ /** List of issues found. */
2237
+ issues: TemplateValidationIssue[];
2238
+ /** Summary counts per face. */
2239
+ portCounts: {
2240
+ front: number;
2241
+ rear: number;
2242
+ };
2243
+ }
2244
+ /**
2245
+ * Result of the full parser pipeline.
2246
+ * @public
2247
+ */
2248
+ interface TemplateParseResult {
2249
+ /** Parsed template (present when valid). */
2250
+ template: DeviceTemplateV2 | null;
2251
+ /** Validation report. */
2252
+ report: TemplateValidationReport;
2253
+ }
2254
+
2255
+ /**
2256
+ * NetBox → Template V2 parser pipeline.
2257
+ *
2258
+ * Five stages: Ingest → Normalize → Enrich → Validate → Export.
2259
+ *
2260
+ * **Port position semantics**: Positions use `xPercent` / `yPercent` (0-100)
2261
+ * to express where the port CENTER should be relative to the device face.
2262
+ * The renderer (`DeviceNode`) converts these to pixel coordinates and clamps
2263
+ * them so the port stays fully inside the device bounds. Clamp bounds are
2264
+ * computed from the **actual** rendered port dimensions (which vary by port
2265
+ * type — e.g., power C13/C19 connectors are larger than generic ethernet
2266
+ * handles). Templates therefore do NOT need to account for port size; the
2267
+ * renderer handles that.
2268
+ *
2269
+ * @public
2270
+ */
2271
+
2272
+ /**
2273
+ * Raw port entry from a NetBox-style template.
2274
+ * @public
2275
+ */
2276
+ interface RawTemplatePort {
2277
+ id?: string;
2278
+ name?: string;
2279
+ label?: string;
2280
+ type?: string;
2281
+ connectorType?: string;
2282
+ connector_type?: string;
2283
+ position?: {
2284
+ side?: string;
2285
+ offsetPercent?: number;
2286
+ offset_percent?: number;
2287
+ offsetPx?: number;
2288
+ offset_px?: number;
2289
+ xPercent?: number;
2290
+ x_percent?: number;
2291
+ yPercent?: number;
2292
+ y_percent?: number;
2293
+ };
2294
+ }
2295
+ /**
2296
+ * Raw port block from a NetBox-style template.
2297
+ * @public
2298
+ */
2299
+ interface RawTemplatePortBlock {
2300
+ name?: string;
2301
+ ports?: RawTemplatePort[];
2302
+ }
2303
+ /**
2304
+ * Raw NetBox-style template input for the parser.
2305
+ * @public
2306
+ */
2307
+ interface RawNetboxTemplate {
2308
+ id?: string;
2309
+ slug?: string;
2310
+ manufacturer?: string;
2311
+ model?: string;
2312
+ role?: string;
2313
+ deviceType?: string;
2314
+ device_type?: string;
2315
+ uHeight?: number;
2316
+ u_height?: number;
2317
+ width?: string;
2318
+ ports?: RawTemplatePortBlock[];
2319
+ rearPorts?: RawTemplatePortBlock[];
2320
+ rear_ports?: RawTemplatePortBlock[];
2321
+ frontRearPortLinks?: Array<{
2322
+ frontPortId?: string;
2323
+ rearPortId?: string;
2324
+ front_port_id?: string;
2325
+ rear_port_id?: string;
2326
+ }>;
2327
+ front_rear_port_links?: Array<{
2328
+ frontPortId?: string;
2329
+ rearPortId?: string;
2330
+ front_port_id?: string;
2331
+ rear_port_id?: string;
2332
+ }>;
2333
+ frontImageUrl?: string;
2334
+ front_image_url?: string;
2335
+ rearImageUrl?: string;
2336
+ rear_image_url?: string;
2337
+ frontImageAttribution?: string;
2338
+ rearImageAttribution?: string;
2339
+ tags?: string[];
2340
+ sourceRepository?: string;
2341
+ source_repository?: string;
2342
+ sourcePath?: string;
2343
+ source_path?: string;
2344
+ }
2345
+ /**
2346
+ * Parse a raw NetBox-style template through the full 5-stage pipeline.
2347
+ *
2348
+ * Returns a `TemplateParseResult` containing the validated V2 template
2349
+ * (or `null` if validation failed) and a full validation report.
2350
+ *
2351
+ * @public
2352
+ */
2353
+ declare function parseNetboxTemplate(raw: RawNetboxTemplate): TemplateParseResult;
2354
+ /**
2355
+ * Count the total number of ports on a given face of a V2 template.
2356
+ * @public
2357
+ */
2358
+ declare function countTemplateFacePorts(face: TemplateFaceData): number;
2359
+ /**
2360
+ * Validate that rendered handle counts match the template port counts.
2361
+ * Returns issues when counts diverge — used as a regression guardrail.
2362
+ *
2363
+ * @public
2364
+ */
2365
+ declare function validateRenderFidelity(template: DeviceTemplateV2, renderedFrontHandleCount: number, renderedRearHandleCount: number): TemplateValidationIssue[];
2366
+
2001
2367
  interface NetworkDiagramState {
2002
2368
  nodes: NetworkNode[];
2003
2369
  edges: NetworkEdge[];
@@ -2033,4 +2399,4 @@ declare function useNetworkDiagram(store: NetworkDiagramStore): NetworkDiagramSt
2033
2399
  declare function useNodes(store: NetworkDiagramStore): NetworkNode[];
2034
2400
  declare function useEdges(store: NetworkDiagramStore): NetworkEdge[];
2035
2401
 
2036
- export { COUPLERS_PER_PANEL, COUPLER_SLOT_HEIGHT_PX, COUPLER_WIDTH_PX, CableNode, ClosureNode, CouplerNode, type DeviceImageFit, type DeviceImageOptions, type DeviceImageRepeat, DeviceNode, DevicePlacementError, type DevicePlacementValidation, DiagramErrorBoundary, type DiagramErrorBoundaryProps, FIBER_COLORS_12, type FiberCable, type FiberColorId, FiberEdge, FiberNode, FibreCableWithTubesExpanded, type FibreFlowCable, type FibreFlowCableKind, type FibreFlowCableNodeData, type FibreFlowCircuit, type FibreFlowClosure, type FibreFlowClosureNodeData, type FibreFlowEndpoint, FibreFlowMap, type FibreFlowMapProps, type FibreFlowSplice, FibreSplitNode, HANDLE_EXTENSION_PX, MultiTubeCableNode, NetworkDiagram, type NetworkDiagramFitViewOptions, type NetworkDiagramFlowMethods, type NetworkDiagramFlowObject, type NetworkDiagramOptions, type NetworkDiagramProps, type NetworkDiagramStoreApi, type NetworkDiagramToImageOptions, type NetworkEdge, type NetworkEdgeData, type NetworkNode, type NetworkNodeData, type NetworkNodeDataBase, type NetworkNodeDataByType, PANEL_BORDER_WIDTH, PANEL_HEADER_HEIGHT, PANEL_HEIGHT_PX, PANEL_PADDING, PANEL_TUBE_TRAY_SPACING, PANEL_WIDTH_PX, POWER_CONNECTORS, PatchPanelNode, type Port, type PortBlock, type PortCableType, type PortType, PowerEdge, RACK_HEADER_HEIGHT, RACK_WIDTH_PX, type RackConfig, type RackDevice, RackNode, type RackSchemaOptions, type ReplaceEdgeOptions, type SpliceConfig, SpliceNode, SplicePlacementError, type SplicePlacementValidation, type SpliceSchemaOptions, type SpliceTrayConfig, SpliceTrayNode, TubeNode, U_HEIGHT_PX, type ValidateConnectionParams, type ValidationResult, VerticalPDU, Width, addDeviceToRack, addSpliceToTray, baseColorFor, buildNodesFromRackConfig, buildNodesFromSpliceConfig, calculateClosureDimensions, calculateCouplerRightX, calculateCouplerSlotSpacing, calculateCouplerSpacing, calculateDevicePositionFromU, calculatePanelDimensions, calculateSlotPositionFromY, calculateSplicePositionFromNumber, calculateUPositions, 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, netboxCableToNetworkEdge, netboxDeviceToNetworkNode, netboxRackToNetworkNode, netboxToNetworkDiagram, removeDeviceFromRack, removeSpliceFromTray, replaceEdge, snapToCouplerPosition, snapToSplicePosition, snapToUPosition, updateDeviceUPosition$1 as updateDeviceUPosition, updateDeviceUPosition as updateDeviceUPositionInSchema, updateSpliceHolderPosition, useEdges as useDiagramEdges, useNodes as useDiagramNodes, useNetworkDiagram, validateAndSnapDevice, validateRackDevicePlacements, validateSplicePlacements };
2402
+ export { COUPLERS_PER_PANEL, COUPLER_SLOT_HEIGHT_PX, COUPLER_WIDTH_PX, CableNode, ClosureNode, CouplerNode, type DeviceImageFit, type DeviceImageOptions, type DeviceImageRepeat, DeviceNode, DevicePlacementError, type DevicePlacementValidation, type DeviceTemplateV2, DiagramErrorBoundary, type DiagramErrorBoundaryProps, FIBER_COLORS_12, type FiberCable, type FiberColorId, FiberEdge, FiberNode, FibreCableWithTubesExpanded, type FibreFlowCable, type FibreFlowCableKind, type FibreFlowCableNodeData, type FibreFlowCircuit, type FibreFlowClosure, type FibreFlowClosureNodeData, type FibreFlowEndpoint, FibreFlowMap, type FibreFlowMapProps, type FibreFlowSplice, FibreSplitNode, HANDLE_EXTENSION_PX, type MountClass, MultiTubeCableNode, NetworkDiagram, type NetworkDiagramFitViewOptions, type NetworkDiagramFlowMethods, type NetworkDiagramFlowObject, type NetworkDiagramOptions, type NetworkDiagramProps, type NetworkDiagramStoreApi, type NetworkDiagramToImageOptions, type NetworkEdge, type NetworkEdgeData, type NetworkNode, type NetworkNodeData, type NetworkNodeDataBase, type NetworkNodeDataByType, PANEL_BORDER_WIDTH, PANEL_HEADER_HEIGHT, PANEL_HEIGHT_PX, PANEL_PADDING, PANEL_TUBE_TRAY_SPACING, PANEL_WIDTH_PX, POWER_CONNECTORS, PatchPanelNode, type Port, type PortBlock, type PortCableType, type PortType, PowerEdge, RACK_HEADER_HEIGHT, RACK_WIDTH_PX, type RackConfig, type RackDevice, type RackLayoutMode, type RackMountMode, RackNode, type RackSchemaOptions, type RawNetboxTemplate, type RawTemplatePort, type RawTemplatePortBlock, type ReplaceEdgeOptions, type SpliceConfig, SpliceNode, SplicePlacementError, type SplicePlacementValidation, type SpliceSchemaOptions, type SpliceTrayConfig, SpliceTrayNode, TEMPLATE_SCHEMA_VERSION, type TemplateFaceData, type TemplateFrontRearPortLink, type TemplateParseResult, type TemplatePort, type TemplatePortBlock, type TemplateSource, type TemplateValidationIssue, type TemplateValidationReport, type TemplateWidth, TubeNode, U_HEIGHT_PX, type ValidateConnectionParams, type ValidationResult, VerticalPDU, Width, addDeviceToRack, addSpliceToTray, baseColorFor, buildNodesFromRackConfig, buildNodesFromSpliceConfig, calculateClosureDimensions, calculateCouplerRightX, calculateCouplerSlotSpacing, calculateCouplerSpacing, calculateDevicePositionFromU, calculatePanelDimensions, calculateSlotPositionFromY, calculateSplicePositionFromNumber, calculateUPositions, calculateYFromSlotPosition, countTemplateFacePorts, 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, netboxCableToNetworkEdge, netboxDeviceToNetworkNode, netboxRackToNetworkNode, netboxToNetworkDiagram, parseNetboxTemplate, removeDeviceFromRack, removeSpliceFromTray, replaceEdge, snapToCouplerPosition, snapToSplicePosition, snapToUPosition, updateDeviceUPosition$1 as updateDeviceUPosition, updateDeviceUPosition as updateDeviceUPositionInSchema, updateSpliceHolderPosition, useEdges as useDiagramEdges, useNodes as useDiagramNodes, useNetworkDiagram, validateAndSnapDevice, validateRackDevicePlacements, validateRenderFidelity, validateSplicePlacements };