@mp70/react-networks 0.2.0-beta.1 → 0.2.0-rc.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/README.md CHANGED
@@ -13,7 +13,7 @@ A React library for creating interactive network diagrams with support for rack
13
13
  - **Fiber Networks**: Visual representation of fiber connections and patch panels
14
14
  - **Power Distribution**: Vertical PDU support with power connections
15
15
  - **View Switching**: Front/rear view switching for devices and racks
16
- - **Device Images**: Front/rear device images supported (PNG, SVG, JPEG, etc.) via `frontImageUrl` / `rearImageUrl`
16
+ - **Device Images**: Front/rear device images supported (PNG, SVG, JPEG, etc.) via `frontImageUrl` / `rearImageUrl` (`https://`, `blob:`, `data:image/*`, or relative URLs)
17
17
  - **Rack Alignment**: Align rack bottoms to the same horizontal plane
18
18
  - **Inventory Integration**: Built-in helpers to import/export generic inventory/CMDB data
19
19
  - **Customizable**: Extensive styling and theming options
@@ -98,13 +98,24 @@ export default App;
98
98
  #### Components
99
99
 
100
100
  - [`NetworkDiagram`](#networkdiagram) - Main diagram component
101
+ - [`DiagramErrorBoundary`](#diagramerrorboundary) - Error boundary for diagram errors
101
102
  - [`RackNode`](#racknode) - Rack visualization component
102
103
  - [`DeviceNode`](#devicenode) - Device visualization component
103
104
  - [`FiberNode`](#fibernode) - Fiber connection component
105
+ - [`FiberEdge`](#fiberedge) - Fiber edge component
106
+ - [`PowerEdge`](#poweredge) - Power edge component
104
107
  - [`VerticalPDU`](#verticalpdu) - Power distribution component
105
108
  - [`PatchPanelNode`](#patchpanelnode) - Patch panel component
109
+ - [`SpliceNode`](#splicenode) - Splice component
106
110
  - [`SpliceTrayNode`](#splicetraynode) - Splice tray component
111
+ - [`TubeNode`](#tubenode) - Tube component
112
+ - [`CableNode`](#cablenode) - Cable component
113
+ - [`MultiTubeCableNode`](#multitubecablenode) - Multi-tube cable component
107
114
  - [`CouplerNode`](#couplernode) - Coupler component
115
+ - [`ClosureNode`](#closurenode) - Closure component
116
+ - [`FibreSplitNode`](#fibresplitnode) - Fibre split component
117
+ - [`FibreFlowMap`](#fibreflowmap) - Fibre flow map component
118
+ - [`FibreCableWithTubesExpanded`](#fibrecablewithtubesexpanded) - Fibre cable with tubes expanded view
108
119
 
109
120
  #### Utilities
110
121
 
@@ -124,30 +135,69 @@ export default App;
124
135
  - [`validateSplicePlacements`](#validatespliceplacements) - Validate splice placements
125
136
  - [`addSpliceToTray`](#addsplicetotray) - Add splice to tray schema
126
137
  - [`removeSpliceFromTray`](#removesplicefromtray) - Remove splice from tray schema
138
+ - [`updateSpliceHolderPosition`](#updatespliceholderposition) - Update splice holder position in schema
127
139
 
128
140
  **Data Integration:**
129
141
  - [`inventoryToNetworkDiagram`](#inventorytonetworkdiagram) - Convert inventory/CMDB data to diagram
142
+ - [`generateLayout`](#generatelayout) - Generate layout from inventory
130
143
 
131
144
  **Dimension Calculations:**
132
145
  - [`calculatePanelDimensions`](#calculatepaneldimensions) - Calculate panel dimensions from children
133
146
  - [`calculateClosureDimensions`](#calculateclosuredimensions) - Calculate closure dimensions from children
134
147
  - [`getCouplerDimensions`](#getcouplerdimensions) - Get coupler dimensions
135
148
  - [`getTubeDimensions`](#gettubedimensions) - Get tube dimensions
149
+ - [`getTrayDimensions`](#gettraydimensions) - Get tray dimensions
150
+
151
+ **Other:**
152
+ - [`replaceEdge`](#replaceedge) - Replace an edge (e.g. when reconnecting)
153
+ - [`createNetworkDiagramStore`](#createnetworkdiagramstore) - Headless store for diagram state
154
+ - [`useNetworkDiagram`](#usenetworkdiagram) / [`useDiagramNodes`](#usediagramnodes) / [`useDiagramEdges`](#usediagramedges) - Headless hooks
155
+ - Power: `getPowerPortStyle`, `getConnectorConfig`, `getDeviceConnectorType`, `getPDUPortType`, `isHighPowerConnector`, `POWER_CONNECTORS`
156
+ - Fiber colors: `FIBER_COLORS_12`, `baseColorFor`, `isStriped`, `fiberSolidOrStriped`, `getFiberColor`
157
+ - Rack geometry: `getRackBounds`, `isPointInRack`, `findNearestRack`
158
+ - Constants: `U_HEIGHT_PX`, `RACK_HEADER_HEIGHT`, `RACK_WIDTH_PX`, `HANDLE_EXTENSION_PX`
159
+ - Status: `getStatusColor`
136
160
 
137
161
  ### NetworkDiagram Props
138
162
 
139
163
  | Prop | Type | Default | Description |
140
164
  |------|------|---------|-------------|
141
- | `nodes` | `NetworkNode[]` | `[]` | Array of network nodes |
142
- | `edges` | `NetworkEdge[]` | `[]` | Array of network edges |
165
+ | `nodes` | `NetworkNode[]` | `[]` | Controlled nodes array |
166
+ | `edges` | `NetworkEdge[]` | `[]` | Controlled edges array |
167
+ | `onNodesChange` | `(nodes: NetworkNode[]) => void` | - | Callback when nodes change (controlled) |
168
+ | `onEdgesChange` | `(edges: NetworkEdge[]) => void` | - | Callback when edges change (controlled) |
169
+ | `initialNodes` | `NetworkNode[]` | - | Initial nodes (uncontrolled) |
170
+ | `initialEdges` | `NetworkEdge[]` | - | Initial edges (uncontrolled) |
171
+ | `store` | `NetworkDiagramStoreApi` | - | Headless store injection |
143
172
  | `alignRacksToBottom` | `boolean` | `false` | Align rack bottoms to baseline |
144
- | `onNodeClick` | `(node: NetworkNode) => void` | - | Node click handler |
173
+ | `onNodeClick` | `(node: NetworkNode \| null) => void` | - | Node click / selection handler |
145
174
  | `onEdgeClick` | `(edge: NetworkEdge) => void` | - | Edge click handler |
146
175
  | `onViewChange` | `(nodeId: string, view: 'front' \| 'rear') => void` | - | Device view change handler |
147
176
  | `onRackFaceChange` | `(rackId: string, face: 'front' \| 'rear') => void` | - | Rack face change handler |
177
+ | `nodeTypes` | `NodeTypes` | - | Custom React Flow node types |
178
+ | `edgeTypes` | `EdgeTypes` | - | Custom React Flow edge types |
179
+ | `onConnect` | `(connection: Connection) => void` | - | Connection handler override |
180
+ | `onEdgeUpdate` | - | - | Edge update (reconnect) override |
181
+ | `isValidConnection` | `(connection: Connection) => boolean` | - | Connection validation override |
182
+ | `connectionMode` | `ConnectionMode` | - | React Flow connection mode |
183
+ | `reAssignable` | `boolean` | `true` | Allow devices to move between racks / ungroup on drag |
184
+ | `colorMode` | `'light' \| 'dark' \| 'system'` | - | Diagram color mode |
185
+ | `onInit` | `(instance: ReactFlowInstance) => void` | - | Called when React Flow is ready |
186
+ | `onFlowMethods` | `(methods: NetworkDiagramFlowMethods) => void` | - | Receive toObject/setViewport/toImage/fitView etc. |
187
+ | `showDownloadButton` | `boolean` | - | Show export image button |
188
+ | `downloadButtonPosition` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | - | Download button position |
189
+ | `useSmoothstepEdgesForTubes` | `boolean` | `false` | Use smoothstep edges for tube connections |
148
190
  | `className` | `string` | - | CSS class name |
149
191
  | `style` | `React.CSSProperties` | - | Inline styles |
150
192
  | `debug` | `boolean` | `false` | Enable debug mode |
193
+ | `readOnly` | `boolean` | `false` | Force lock diagram (no drag/connect/delete/reconnect/pan/zoom) |
194
+ | `interaction` | `NetworkDiagramInteractionOptions` | - | Fine-grained interaction (nodesDraggable, nodesConnectable, panOnDrag, etc.) |
195
+ | `actionPanel` | `NetworkDiagramActionPanelOptions` | - | Configure action panel (enabled, showRearToggle, showDeRack) |
196
+ | `connectOnClick` | `boolean` | `true` | Enable click-to-connect on handles |
197
+ | `panOnDrag` | `boolean` | - | Override pan on drag |
198
+ | `panOnScroll` | `boolean` | - | Override pan on scroll |
199
+ | `zoomOnScroll` | `boolean` | - | Override zoom on scroll |
200
+ | `fitViewOptions` | `FitViewOptions` | - | React Flow fitView options |
151
201
 
152
202
  ### NetworkNode Types
153
203
 
@@ -160,13 +210,23 @@ type NetworkNodeType =
160
210
  | 'fiber'
161
211
  | 'patch-panel'
162
212
  | 'device'
163
- | 'vertical-pdu';
213
+ | 'vertical-pdu'
214
+ | 'splice'
215
+ | 'splice-tray'
216
+ | 'tube'
217
+ | 'cable'
218
+ | 'multi-tube-cable'
219
+ | 'coupler'
220
+ | 'closure'
221
+ | 'fibre-split'
222
+ | 'fibre-flow-cable'
223
+ | 'fibre-flow-closure';
164
224
  ```
165
225
 
166
226
  ### NetworkEdge Types
167
227
 
168
228
  ```tsx
169
- type NetworkEdgeType = 'fiber' | 'ethernet' | 'power';
229
+ type NetworkEdgeType = 'fiber' | 'ethernet' | 'power' | 'smoothstep' | 'step' | 'thick-cable' | 'fibre-flow' | 'fibre-flow-link';
170
230
  ```
171
231
 
172
232
  ## Advanced Usage
@@ -357,4 +417,4 @@ See `../../LICENSE` for details. By installing, you agree to use under either li
357
417
 
358
418
  ---
359
419
 
360
- Made with love by [matt](https://github.com/MP70) from [rackout.net](https://rackout.net)
420
+ Made by [matt](https://github.com/MP70) from [rackout.net](https://rackout.net).
package/dist/index.css CHANGED
@@ -1,4 +1,4 @@
1
- /* Library styles for @react-networks/network-diagrams */
1
+ /* Library styles for @mp70/react-networks */
2
2
 
3
3
  /* Edge zIndex styles for dynamic prominence */
4
4
  .edge-prominent {
@@ -356,6 +356,80 @@
356
356
  border-color: #3b82f6 !important;
357
357
  }
358
358
 
359
+ /* Device node styles */
360
+ .device-node {
361
+ background-color: #1f2937;
362
+ background-image: var(--rn-device-bg-image, none);
363
+ background-position: var(--rn-device-bg-position, center);
364
+ background-repeat: var(--rn-device-bg-repeat, no-repeat);
365
+ background-size: var(--rn-device-bg-size, cover);
366
+ border: 1px solid var(--rn-device-border-color, #10b981);
367
+ border-radius: 2px;
368
+ box-shadow: var(--rn-device-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.1));
369
+ box-sizing: border-box;
370
+ color: white;
371
+ cursor: grab;
372
+ display: flex;
373
+ flex-direction: column;
374
+ font-family: monospace;
375
+ font-size: 8px;
376
+ height: var(--rn-device-height, 20px);
377
+ justify-content: center;
378
+ left: var(--rn-device-left, auto);
379
+ margin: 0;
380
+ padding: 0;
381
+ position: relative;
382
+ transform: translateY(var(--rn-device-translate-y, 0px));
383
+ width: var(--rn-device-width, 100%);
384
+ }
385
+
386
+ .device-node__content {
387
+ display: flex;
388
+ flex: 1;
389
+ flex-direction: column;
390
+ justify-content: center;
391
+ overflow: hidden;
392
+ padding: 2px;
393
+ text-align: center;
394
+ }
395
+
396
+ .device-node__label {
397
+ font-size: 7px;
398
+ font-weight: bold;
399
+ line-height: 1.1;
400
+ overflow: hidden;
401
+ text-overflow: ellipsis;
402
+ white-space: nowrap;
403
+ }
404
+
405
+ .device-node__manufacturer {
406
+ color: #9ca3af;
407
+ font-size: 6px;
408
+ line-height: 1;
409
+ }
410
+
411
+ .device-node__u-indicator {
412
+ background: #374151;
413
+ border-radius: 1px;
414
+ bottom: 1px;
415
+ color: #9ca3af;
416
+ font-size: 6px;
417
+ line-height: 1;
418
+ padding: 1px 2px;
419
+ position: absolute;
420
+ right: 1px;
421
+ }
422
+
423
+ .device-node__status-indicator {
424
+ background: var(--rn-device-status-color, #6b7280);
425
+ border-radius: 50%;
426
+ bottom: 1px;
427
+ height: 4px;
428
+ left: 1px;
429
+ position: absolute;
430
+ width: 4px;
431
+ }
432
+
359
433
  /* Light mode adjustments */
360
434
  .react-flow-light .coupler-node {
361
435
  background: #f9fafb;
@@ -1 +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/* 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/* 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/* 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":[]}