@procaaso/alphinity-ui-components 1.8.0 → 1.8.2

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.cjs CHANGED
@@ -3382,7 +3382,10 @@ var ThemeToggle = ({
3382
3382
  };
3383
3383
 
3384
3384
  // src/components/PIDCanvas/PIDCanvas.tsx
3385
- var import_react17 = require("react");
3385
+ var import_react20 = __toESM(require("react"), 1);
3386
+
3387
+ // src/components/PIDCanvas/NodeRenderer.tsx
3388
+ var import_react10 = __toESM(require("react"), 1);
3386
3389
 
3387
3390
  // src/diagram/symbols/mockSymbolLibrary.ts
3388
3391
  var mockSymbolLibrary = {
@@ -4604,7 +4607,7 @@ function getAvailableSymbols() {
4604
4607
 
4605
4608
  // src/components/PIDCanvas/NodeRenderer.tsx
4606
4609
  var import_jsx_runtime16 = require("react/jsx-runtime");
4607
- function NodeRenderer({
4610
+ function NodeRendererImpl({
4608
4611
  nodes: nodes2,
4609
4612
  selectedNodeIds,
4610
4613
  onNodeClick,
@@ -4750,10 +4753,12 @@ function NodeRenderer({
4750
4753
  );
4751
4754
  }) });
4752
4755
  }
4756
+ var NodeRenderer = import_react10.default.memo(NodeRendererImpl);
4753
4757
 
4754
4758
  // src/components/PIDCanvas/PipeRenderer.tsx
4759
+ var import_react11 = __toESM(require("react"), 1);
4755
4760
  var import_jsx_runtime17 = require("react/jsx-runtime");
4756
- function PipeRenderer({
4761
+ function PipeRendererImpl({
4757
4762
  pipes,
4758
4763
  selectedPipeIds,
4759
4764
  onPipeClick,
@@ -4930,10 +4935,36 @@ function PipeRenderer({
4930
4935
  );
4931
4936
  }) });
4932
4937
  }
4938
+ var PipeRenderer = import_react11.default.memo(PipeRendererImpl);
4933
4939
 
4934
4940
  // src/components/PIDCanvas/DataOverlay.tsx
4941
+ var import_react12 = __toESM(require("react"), 1);
4935
4942
  var import_jsx_runtime18 = require("react/jsx-runtime");
4936
- function DataOverlay({
4943
+ var PULSE_KEYFRAME_ID = "pid-data-overlay-pulse-keyframes";
4944
+ var PULSE_ANIMATION = "pid-data-overlay-pulse 1.5s ease-in-out infinite";
4945
+ function ensurePulseKeyframes() {
4946
+ if (typeof document === "undefined") return;
4947
+ if (document.getElementById(PULSE_KEYFRAME_ID)) return;
4948
+ const style = document.createElement("style");
4949
+ style.id = PULSE_KEYFRAME_ID;
4950
+ style.textContent = "@keyframes pid-data-overlay-pulse{0%{opacity:.9}50%{opacity:.3}100%{opacity:.9}}";
4951
+ document.head.appendChild(style);
4952
+ }
4953
+ function renderStatusDot(cx, cy, scale, fill) {
4954
+ ensurePulseKeyframes();
4955
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4956
+ "circle",
4957
+ {
4958
+ className: "pid-data-overlay-status-dot",
4959
+ cx: cx + 35 * scale,
4960
+ cy: cy - 18 * scale,
4961
+ r: 3 * scale,
4962
+ fill,
4963
+ style: { animation: PULSE_ANIMATION }
4964
+ }
4965
+ );
4966
+ }
4967
+ function DataOverlayImpl({
4937
4968
  nodeId,
4938
4969
  x,
4939
4970
  y,
@@ -4953,6 +4984,24 @@ function DataOverlay({
4953
4984
  const backgroundColor = display?.backgroundColor;
4954
4985
  const offsetX = display?.offsetX ?? 0;
4955
4986
  const offsetY = display?.offsetY ?? 0;
4987
+ const sparklinePath = import_react12.default.useMemo(() => {
4988
+ if (!showSparkline || !history || history.length < 2) return "";
4989
+ const width = 70 * scale;
4990
+ const height = 20 * scale;
4991
+ const padding = 5 * scale;
4992
+ const effectiveWidth = width - padding * 2;
4993
+ const effectiveHeight = height - padding * 2;
4994
+ const hasEuRange = scaling?.euLow !== void 0 && scaling?.euHigh !== void 0 && scaling.euHigh !== scaling.euLow;
4995
+ const min = hasEuRange ? scaling.euLow : Math.min(...history);
4996
+ const max = hasEuRange ? scaling.euHigh : Math.max(...history);
4997
+ const range = max - min || 1;
4998
+ const points = history.map((val, i) => {
4999
+ const xPos = i / (history.length - 1) * effectiveWidth + padding;
5000
+ const yPos = height - padding - (val - min) / range * effectiveHeight;
5001
+ return `${xPos.toFixed(2)},${yPos.toFixed(2)}`;
5002
+ });
5003
+ return `M ${points.join(" L ")}`;
5004
+ }, [showSparkline, history, scaling, scale]);
4956
5005
  if (!showValue) {
4957
5006
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, {});
4958
5007
  }
@@ -4972,24 +5021,6 @@ function DataOverlay({
4972
5021
  const finalTextColor = textColor || colors.text;
4973
5022
  const formattedValue = formatValue(value.value);
4974
5023
  const displayText = unit ? `${formattedValue} ${unit}` : formattedValue;
4975
- const sparklinePath = (() => {
4976
- if (!showSparkline || !history || history.length < 2) return "";
4977
- const width = 70 * scale;
4978
- const height = 20 * scale;
4979
- const padding = 5 * scale;
4980
- const effectiveWidth = width - padding * 2;
4981
- const effectiveHeight = height - padding * 2;
4982
- const hasEuRange = scaling?.euLow !== void 0 && scaling?.euHigh !== void 0 && scaling.euHigh !== scaling.euLow;
4983
- const min = hasEuRange ? scaling.euLow : Math.min(...history);
4984
- const max = hasEuRange ? scaling.euHigh : Math.max(...history);
4985
- const range = max - min || 1;
4986
- const points = history.map((val, i) => {
4987
- const xPos = i / (history.length - 1) * effectiveWidth + padding;
4988
- const yPos = height - padding - (val - min) / range * effectiveHeight;
4989
- return `${xPos.toFixed(2)},${yPos.toFixed(2)}`;
4990
- });
4991
- return `M ${points.join(" L ")}`;
4992
- })();
4993
5024
  const hasSparkline = showSparkline && sparklinePath;
4994
5025
  const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale;
4995
5026
  const overlayWidth = 80 * scale;
@@ -5037,25 +5068,7 @@ function DataOverlay({
5037
5068
  children: displayText
5038
5069
  }
5039
5070
  ),
5040
- showStatus && value.status !== "normal" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5041
- "circle",
5042
- {
5043
- cx: displayX + 35 * scale,
5044
- cy: displayY - 18 * scale,
5045
- r: 3 * scale,
5046
- fill: finalTextColor,
5047
- opacity: "0.9",
5048
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5049
- "animate",
5050
- {
5051
- attributeName: "opacity",
5052
- values: "0.9;0.3;0.9",
5053
- dur: "1.5s",
5054
- repeatCount: "indefinite"
5055
- }
5056
- )
5057
- }
5058
- ),
5071
+ showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor),
5059
5072
  value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5060
5073
  "text",
5061
5074
  {
@@ -5087,9 +5100,10 @@ function DataOverlay({
5087
5100
  ) })
5088
5101
  ] });
5089
5102
  }
5103
+ var DataOverlay = import_react12.default.memo(DataOverlayImpl);
5090
5104
 
5091
5105
  // src/components/PIDCanvas/PositionPanel.tsx
5092
- var import_react10 = require("react");
5106
+ var import_react13 = require("react");
5093
5107
  var import_jsx_runtime19 = require("react/jsx-runtime");
5094
5108
  function PositionPanel({
5095
5109
  selectedNode,
@@ -5098,9 +5112,9 @@ function PositionPanel({
5098
5112
  onWaypointPositionChange,
5099
5113
  position = "top-right"
5100
5114
  }) {
5101
- const [x, setX] = (0, import_react10.useState)("");
5102
- const [y, setY] = (0, import_react10.useState)("");
5103
- (0, import_react10.useEffect)(() => {
5115
+ const [x, setX] = (0, import_react13.useState)("");
5116
+ const [y, setY] = (0, import_react13.useState)("");
5117
+ (0, import_react13.useEffect)(() => {
5104
5118
  if (selectedNode) {
5105
5119
  setX(selectedNode.transform.x.toFixed(2));
5106
5120
  setY(selectedNode.transform.y.toFixed(2));
@@ -5226,7 +5240,7 @@ function PositionPanel({
5226
5240
  }
5227
5241
 
5228
5242
  // src/diagram/hooks/useViewBox.ts
5229
- var import_react11 = require("react");
5243
+ var import_react14 = require("react");
5230
5244
  function useViewBox(options) {
5231
5245
  const {
5232
5246
  initialViewBox,
@@ -5237,16 +5251,16 @@ function useViewBox(options) {
5237
5251
  zoomSensitivity = 1e-3,
5238
5252
  allowLeftClickPan = true
5239
5253
  } = options;
5240
- const [viewBox, setViewBox] = (0, import_react11.useState)(initialViewBox);
5241
- const svgRef = (0, import_react11.useRef)(null);
5242
- const isPanningRef = (0, import_react11.useRef)(false);
5243
- const lastMousePosRef = (0, import_react11.useRef)({ x: 0, y: 0 });
5244
- const spaceKeyDownRef = (0, import_react11.useRef)(false);
5245
- const lastTouchDistanceRef = (0, import_react11.useRef)(null);
5246
- const resetViewBox = (0, import_react11.useCallback)(() => {
5254
+ const [viewBox, setViewBox] = (0, import_react14.useState)(initialViewBox);
5255
+ const svgRef = (0, import_react14.useRef)(null);
5256
+ const isPanningRef = (0, import_react14.useRef)(false);
5257
+ const lastMousePosRef = (0, import_react14.useRef)({ x: 0, y: 0 });
5258
+ const spaceKeyDownRef = (0, import_react14.useRef)(false);
5259
+ const lastTouchDistanceRef = (0, import_react14.useRef)(null);
5260
+ const resetViewBox = (0, import_react14.useCallback)(() => {
5247
5261
  setViewBox(initialViewBox);
5248
5262
  }, [initialViewBox]);
5249
- const zoomIn = (0, import_react11.useCallback)(() => {
5263
+ const zoomIn = (0, import_react14.useCallback)(() => {
5250
5264
  setViewBox((prev) => {
5251
5265
  const currentZoom = initialViewBox.width / prev.width;
5252
5266
  const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);
@@ -5263,7 +5277,7 @@ function useViewBox(options) {
5263
5277
  };
5264
5278
  });
5265
5279
  }, [initialViewBox, minZoom]);
5266
- const zoomOut = (0, import_react11.useCallback)(() => {
5280
+ const zoomOut = (0, import_react14.useCallback)(() => {
5267
5281
  setViewBox((prev) => {
5268
5282
  const currentZoom = initialViewBox.width / prev.width;
5269
5283
  const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);
@@ -5280,7 +5294,7 @@ function useViewBox(options) {
5280
5294
  };
5281
5295
  });
5282
5296
  }, [initialViewBox, maxZoom]);
5283
- const fitToContent = (0, import_react11.useCallback)((bounds, padding = 50) => {
5297
+ const fitToContent = (0, import_react14.useCallback)((bounds, padding = 50) => {
5284
5298
  const contentWidth = bounds.maxX - bounds.minX;
5285
5299
  const contentHeight = bounds.maxY - bounds.minY;
5286
5300
  if (contentWidth === 0 || contentHeight === 0) {
@@ -5308,7 +5322,7 @@ function useViewBox(options) {
5308
5322
  height: newHeight
5309
5323
  });
5310
5324
  }, [initialViewBox]);
5311
- (0, import_react11.useEffect)(() => {
5325
+ (0, import_react14.useEffect)(() => {
5312
5326
  if (!enableZoom || !svgRef.current) return;
5313
5327
  const svg = svgRef.current;
5314
5328
  const handleWheel = (e) => {
@@ -5341,7 +5355,7 @@ function useViewBox(options) {
5341
5355
  svg.addEventListener("wheel", handleWheel, { passive: false });
5342
5356
  return () => svg.removeEventListener("wheel", handleWheel);
5343
5357
  }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
5344
- (0, import_react11.useEffect)(() => {
5358
+ (0, import_react14.useEffect)(() => {
5345
5359
  if (!enablePan || !svgRef.current) return;
5346
5360
  const svg = svgRef.current;
5347
5361
  const handleMouseDown = (e) => {
@@ -5417,7 +5431,7 @@ function useViewBox(options) {
5417
5431
  window.removeEventListener("keyup", handleKeyUp);
5418
5432
  };
5419
5433
  }, [enablePan, allowLeftClickPan]);
5420
- (0, import_react11.useEffect)(() => {
5434
+ (0, import_react14.useEffect)(() => {
5421
5435
  if (!svgRef.current) return;
5422
5436
  if (!enablePan && !enableZoom) return;
5423
5437
  const svg = svgRef.current;
@@ -5508,7 +5522,7 @@ function useViewBox(options) {
5508
5522
  svg.removeEventListener("touchend", handleTouchEnd);
5509
5523
  };
5510
5524
  }, [enablePan, enableZoom, minZoom, initialViewBox]);
5511
- const screenToWorld = (0, import_react11.useCallback)(
5525
+ const screenToWorld = (0, import_react14.useCallback)(
5512
5526
  (screenX, screenY) => {
5513
5527
  const svg = svgRef.current;
5514
5528
  if (!svg) return { x: screenX, y: screenY };
@@ -5547,15 +5561,15 @@ function useViewBox(options) {
5547
5561
  }
5548
5562
 
5549
5563
  // src/diagram/hooks/useSelection.ts
5550
- var import_react12 = require("react");
5564
+ var import_react15 = require("react");
5551
5565
  function useSelection(options = {}) {
5552
5566
  const {
5553
5567
  multiSelect = true,
5554
5568
  initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
5555
5569
  onSelectionChange
5556
5570
  } = options;
5557
- const [selection, setSelection] = (0, import_react12.useState)(initialSelection);
5558
- const notifyChange = (0, import_react12.useCallback)(
5571
+ const [selection, setSelection] = (0, import_react15.useState)(initialSelection);
5572
+ const notifyChange = (0, import_react15.useCallback)(
5559
5573
  (newSelection) => {
5560
5574
  if (onSelectionChange) {
5561
5575
  onSelectionChange(newSelection);
@@ -5563,15 +5577,15 @@ function useSelection(options = {}) {
5563
5577
  },
5564
5578
  [onSelectionChange]
5565
5579
  );
5566
- const isNodeSelected = (0, import_react12.useCallback)(
5580
+ const isNodeSelected = (0, import_react15.useCallback)(
5567
5581
  (nodeId) => selection.selectedNodeIds.has(nodeId),
5568
5582
  [selection.selectedNodeIds]
5569
5583
  );
5570
- const isPipeSelected = (0, import_react12.useCallback)(
5584
+ const isPipeSelected = (0, import_react15.useCallback)(
5571
5585
  (pipeId) => selection.selectedPipeIds.has(pipeId),
5572
5586
  [selection.selectedPipeIds]
5573
5587
  );
5574
- const selectNode = (0, import_react12.useCallback)(
5588
+ const selectNode = (0, import_react15.useCallback)(
5575
5589
  (nodeId, isMultiSelect = false) => {
5576
5590
  setSelection((prev) => {
5577
5591
  const newNodeIds = new Set(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);
@@ -5590,7 +5604,7 @@ function useSelection(options = {}) {
5590
5604
  },
5591
5605
  [multiSelect, notifyChange]
5592
5606
  );
5593
- const selectPipe = (0, import_react12.useCallback)(
5607
+ const selectPipe = (0, import_react15.useCallback)(
5594
5608
  (pipeId, isMultiSelect = false) => {
5595
5609
  setSelection((prev) => {
5596
5610
  const newPipeIds = new Set(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);
@@ -5609,7 +5623,7 @@ function useSelection(options = {}) {
5609
5623
  },
5610
5624
  [multiSelect, notifyChange]
5611
5625
  );
5612
- const clearSelection = (0, import_react12.useCallback)(() => {
5626
+ const clearSelection = (0, import_react15.useCallback)(() => {
5613
5627
  const newSelection = {
5614
5628
  selectedNodeIds: /* @__PURE__ */ new Set(),
5615
5629
  selectedPipeIds: /* @__PURE__ */ new Set()
@@ -5617,7 +5631,7 @@ function useSelection(options = {}) {
5617
5631
  setSelection(newSelection);
5618
5632
  notifyChange(newSelection);
5619
5633
  }, [notifyChange]);
5620
- const selectNodes = (0, import_react12.useCallback)(
5634
+ const selectNodes = (0, import_react15.useCallback)(
5621
5635
  (nodeIds) => {
5622
5636
  const newSelection = {
5623
5637
  selectedNodeIds: new Set(nodeIds),
@@ -5628,7 +5642,7 @@ function useSelection(options = {}) {
5628
5642
  },
5629
5643
  [notifyChange]
5630
5644
  );
5631
- const selectPipes = (0, import_react12.useCallback)(
5645
+ const selectPipes = (0, import_react15.useCallback)(
5632
5646
  (pipeIds) => {
5633
5647
  const newSelection = {
5634
5648
  selectedNodeIds: /* @__PURE__ */ new Set(),
@@ -5652,23 +5666,23 @@ function useSelection(options = {}) {
5652
5666
  }
5653
5667
 
5654
5668
  // src/diagram/hooks/useTelemetry.ts
5655
- var import_react13 = require("react");
5669
+ var import_react16 = require("react");
5656
5670
  function useTelemetry(options = {}) {
5657
5671
  const {
5658
5672
  initialBindings = [],
5659
5673
  onTelemetryChange,
5660
5674
  refreshInterval = 0
5661
5675
  } = options;
5662
- const [telemetry, setTelemetry] = (0, import_react13.useState)(() => {
5676
+ const [telemetry, setTelemetry] = (0, import_react16.useState)(() => {
5663
5677
  const map = /* @__PURE__ */ new Map();
5664
5678
  initialBindings.forEach((binding) => {
5665
5679
  map.set(binding.nodeId, binding);
5666
5680
  });
5667
5681
  return map;
5668
5682
  });
5669
- const telemetryRef = (0, import_react13.useRef)(telemetry);
5683
+ const telemetryRef = (0, import_react16.useRef)(telemetry);
5670
5684
  telemetryRef.current = telemetry;
5671
- const notifyChange = (0, import_react13.useCallback)(
5685
+ const notifyChange = (0, import_react16.useCallback)(
5672
5686
  (newTelemetry) => {
5673
5687
  if (onTelemetryChange) {
5674
5688
  onTelemetryChange(newTelemetry);
@@ -5676,7 +5690,7 @@ function useTelemetry(options = {}) {
5676
5690
  },
5677
5691
  [onTelemetryChange]
5678
5692
  );
5679
- const updateTelemetry = (0, import_react13.useCallback)(
5693
+ const updateTelemetry = (0, import_react16.useCallback)(
5680
5694
  (nodeId, value) => {
5681
5695
  setTelemetry((prev) => {
5682
5696
  const newMap = new Map(prev);
@@ -5706,7 +5720,7 @@ function useTelemetry(options = {}) {
5706
5720
  },
5707
5721
  [notifyChange]
5708
5722
  );
5709
- const updateTelemetryBatch = (0, import_react13.useCallback)(
5723
+ const updateTelemetryBatch = (0, import_react16.useCallback)(
5710
5724
  (updates) => {
5711
5725
  setTelemetry((prev) => {
5712
5726
  const newMap = new Map(prev);
@@ -5760,16 +5774,16 @@ function useTelemetry(options = {}) {
5760
5774
  },
5761
5775
  [notifyChange]
5762
5776
  );
5763
- const getTelemetry = (0, import_react13.useCallback)(
5777
+ const getTelemetry = (0, import_react16.useCallback)(
5764
5778
  (nodeId) => telemetryRef.current.get(nodeId),
5765
5779
  []
5766
5780
  );
5767
- const clearTelemetry = (0, import_react13.useCallback)(() => {
5781
+ const clearTelemetry = (0, import_react16.useCallback)(() => {
5768
5782
  const newMap = /* @__PURE__ */ new Map();
5769
5783
  setTelemetry(newMap);
5770
5784
  notifyChange(newMap);
5771
5785
  }, [notifyChange]);
5772
- const setBindings = (0, import_react13.useCallback)(
5786
+ const setBindings = (0, import_react16.useCallback)(
5773
5787
  (bindings) => {
5774
5788
  const newMap = /* @__PURE__ */ new Map();
5775
5789
  bindings.forEach((binding) => {
@@ -5780,7 +5794,7 @@ function useTelemetry(options = {}) {
5780
5794
  },
5781
5795
  [notifyChange]
5782
5796
  );
5783
- (0, import_react13.useEffect)(() => {
5797
+ (0, import_react16.useEffect)(() => {
5784
5798
  if (refreshInterval <= 0) return;
5785
5799
  const intervalId = setInterval(() => {
5786
5800
  notifyChange(telemetryRef.current);
@@ -5798,10 +5812,10 @@ function useTelemetry(options = {}) {
5798
5812
  }
5799
5813
 
5800
5814
  // src/diagram/hooks/useTelemetryStatus.ts
5801
- var import_react14 = require("react");
5815
+ var import_react17 = require("react");
5802
5816
  function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
5803
5817
  const { enabled = true, mapStatus } = options;
5804
- (0, import_react14.useEffect)(() => {
5818
+ (0, import_react17.useEffect)(() => {
5805
5819
  if (!enabled) return;
5806
5820
  const defaultMapStatus = (telemetryStatus) => {
5807
5821
  switch (telemetryStatus) {
@@ -5840,7 +5854,7 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
5840
5854
  }
5841
5855
 
5842
5856
  // src/diagram/hooks/useDrag.ts
5843
- var import_react15 = require("react");
5857
+ var import_react18 = require("react");
5844
5858
  function useDrag(options = {}) {
5845
5859
  const {
5846
5860
  onDragStart,
@@ -5850,23 +5864,23 @@ function useDrag(options = {}) {
5850
5864
  dragThreshold = 3,
5851
5865
  screenToWorld = (x, y) => ({ x, y })
5852
5866
  } = options;
5853
- const [dragState, setDragState] = (0, import_react15.useState)({
5867
+ const [dragState, setDragState] = (0, import_react18.useState)({
5854
5868
  isDragging: false,
5855
5869
  startPosition: null,
5856
5870
  offset: { x: 0, y: 0 },
5857
5871
  draggedId: null
5858
5872
  });
5859
- const [isListening, setIsListening] = (0, import_react15.useState)(false);
5860
- const dragStartRef = (0, import_react15.useRef)(null);
5861
- const hasMovedRef = (0, import_react15.useRef)(false);
5862
- const applySnap = (0, import_react15.useCallback)(
5873
+ const [isListening, setIsListening] = (0, import_react18.useState)(false);
5874
+ const dragStartRef = (0, import_react18.useRef)(null);
5875
+ const hasMovedRef = (0, import_react18.useRef)(false);
5876
+ const applySnap = (0, import_react18.useCallback)(
5863
5877
  (value) => {
5864
5878
  if (snapToGrid <= 0) return value;
5865
5879
  return Math.round(value / snapToGrid) * snapToGrid;
5866
5880
  },
5867
5881
  [snapToGrid]
5868
5882
  );
5869
- const handleMouseMove = (0, import_react15.useCallback)(
5883
+ const handleMouseMove = (0, import_react18.useCallback)(
5870
5884
  (event) => {
5871
5885
  if (!dragStartRef.current) return;
5872
5886
  const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;
@@ -5907,7 +5921,7 @@ function useDrag(options = {}) {
5907
5921
  },
5908
5922
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
5909
5923
  );
5910
- const handleMouseUp = (0, import_react15.useCallback)(
5924
+ const handleMouseUp = (0, import_react18.useCallback)(
5911
5925
  (event) => {
5912
5926
  if (!dragStartRef.current || !hasMovedRef.current) {
5913
5927
  dragStartRef.current = null;
@@ -5944,7 +5958,7 @@ function useDrag(options = {}) {
5944
5958
  },
5945
5959
  [screenToWorld, applySnap, onDragEnd]
5946
5960
  );
5947
- const handleTouchMove = (0, import_react15.useCallback)(
5961
+ const handleTouchMove = (0, import_react18.useCallback)(
5948
5962
  (event) => {
5949
5963
  if (!dragStartRef.current || event.touches.length !== 1) return;
5950
5964
  const touch = event.touches[0];
@@ -5987,7 +6001,7 @@ function useDrag(options = {}) {
5987
6001
  },
5988
6002
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
5989
6003
  );
5990
- const handleTouchEnd = (0, import_react15.useCallback)(
6004
+ const handleTouchEnd = (0, import_react18.useCallback)(
5991
6005
  (event) => {
5992
6006
  if (!dragStartRef.current || !hasMovedRef.current) {
5993
6007
  dragStartRef.current = null;
@@ -6025,7 +6039,7 @@ function useDrag(options = {}) {
6025
6039
  },
6026
6040
  [screenToWorld, applySnap, onDragEnd]
6027
6041
  );
6028
- (0, import_react15.useEffect)(() => {
6042
+ (0, import_react18.useEffect)(() => {
6029
6043
  if (!isListening) return;
6030
6044
  document.addEventListener("mousemove", handleMouseMove);
6031
6045
  document.addEventListener("mouseup", handleMouseUp);
@@ -6040,7 +6054,7 @@ function useDrag(options = {}) {
6040
6054
  document.removeEventListener("touchcancel", handleTouchEnd);
6041
6055
  };
6042
6056
  }, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
6043
- const startDrag = (0, import_react15.useCallback)(
6057
+ const startDrag = (0, import_react18.useCallback)(
6044
6058
  (id, event, itemPosition) => {
6045
6059
  event.stopPropagation();
6046
6060
  let clientX;
@@ -6070,7 +6084,7 @@ function useDrag(options = {}) {
6070
6084
  },
6071
6085
  [screenToWorld]
6072
6086
  );
6073
- const cancelDrag = (0, import_react15.useCallback)(() => {
6087
+ const cancelDrag = (0, import_react18.useCallback)(() => {
6074
6088
  dragStartRef.current = null;
6075
6089
  hasMovedRef.current = false;
6076
6090
  setIsListening(false);
@@ -6081,7 +6095,7 @@ function useDrag(options = {}) {
6081
6095
  draggedId: null
6082
6096
  });
6083
6097
  }, []);
6084
- const isDraggingItem = (0, import_react15.useCallback)(
6098
+ const isDraggingItem = (0, import_react18.useCallback)(
6085
6099
  (id) => dragState.isDragging && dragState.draggedId === id,
6086
6100
  [dragState.isDragging, dragState.draggedId]
6087
6101
  );
@@ -6094,7 +6108,7 @@ function useDrag(options = {}) {
6094
6108
  }
6095
6109
 
6096
6110
  // src/diagram/hooks/useKeyboardShortcuts.ts
6097
- var import_react16 = require("react");
6111
+ var import_react19 = require("react");
6098
6112
  function useKeyboardShortcuts(options) {
6099
6113
  const {
6100
6114
  onDelete,
@@ -6105,7 +6119,7 @@ function useKeyboardShortcuts(options) {
6105
6119
  onSelectAll,
6106
6120
  enabled = true
6107
6121
  } = options;
6108
- (0, import_react16.useEffect)(() => {
6122
+ (0, import_react19.useEffect)(() => {
6109
6123
  if (!enabled) return;
6110
6124
  const handleKeyDown = (event) => {
6111
6125
  const target = event.target;
@@ -6215,18 +6229,19 @@ function nodeHasPort(node, portId) {
6215
6229
 
6216
6230
  // src/components/PIDCanvas/PIDCanvas.tsx
6217
6231
  var import_jsx_runtime20 = require("react/jsx-runtime");
6218
- function PIDCanvas({
6232
+ var DEFAULT_FEATURES = {
6233
+ pan: true,
6234
+ zoom: true,
6235
+ selection: false,
6236
+ multiSelect: true,
6237
+ telemetry: false,
6238
+ dragNodes: false
6239
+ };
6240
+ function PIDCanvasImpl({
6219
6241
  diagram,
6220
6242
  className = "",
6221
6243
  style,
6222
- features = {
6223
- pan: true,
6224
- zoom: true,
6225
- selection: false,
6226
- multiSelect: true,
6227
- telemetry: false,
6228
- dragNodes: false
6229
- },
6244
+ features = DEFAULT_FEATURES,
6230
6245
  onSelectionChange,
6231
6246
  onNodeClick,
6232
6247
  onPipeClick,
@@ -6242,21 +6257,21 @@ function PIDCanvas({
6242
6257
  statusColorMap,
6243
6258
  ...props
6244
6259
  }) {
6245
- const [localDiagram, setLocalDiagram] = (0, import_react17.useState)(diagram);
6246
- const [dragOverPosition, setDragOverPosition] = (0, import_react17.useState)(null);
6247
- const [isConnecting, setIsConnecting] = (0, import_react17.useState)(false);
6248
- const [connectionSource, setConnectionSource] = (0, import_react17.useState)(null);
6249
- const [connectionSourcePort, setConnectionSourcePort] = (0, import_react17.useState)(null);
6250
- const [connectionCursor, setConnectionCursor] = (0, import_react17.useState)(null);
6251
- const [hoveredNode, setHoveredNode] = (0, import_react17.useState)(null);
6252
- const [hoveredPort, setHoveredPort] = (0, import_react17.useState)(null);
6253
- const [selectedWaypoint, setSelectedWaypoint] = (0, import_react17.useState)(null);
6254
- const historyStack = (0, import_react17.useRef)([]);
6255
- const redoStack = (0, import_react17.useRef)([]);
6256
- const isUndoRedoAction = (0, import_react17.useRef)(false);
6257
- const isInternalChange = (0, import_react17.useRef)(false);
6258
- const lastInternalDiagram = (0, import_react17.useRef)(null);
6259
- (0, import_react17.useEffect)(() => {
6260
+ const [localDiagram, setLocalDiagram] = (0, import_react20.useState)(diagram);
6261
+ const [dragOverPosition, setDragOverPosition] = (0, import_react20.useState)(null);
6262
+ const [isConnecting, setIsConnecting] = (0, import_react20.useState)(false);
6263
+ const [connectionSource, setConnectionSource] = (0, import_react20.useState)(null);
6264
+ const [connectionSourcePort, setConnectionSourcePort] = (0, import_react20.useState)(null);
6265
+ const [connectionCursor, setConnectionCursor] = (0, import_react20.useState)(null);
6266
+ const [hoveredNode, setHoveredNode] = (0, import_react20.useState)(null);
6267
+ const [hoveredPort, setHoveredPort] = (0, import_react20.useState)(null);
6268
+ const [selectedWaypoint, setSelectedWaypoint] = (0, import_react20.useState)(null);
6269
+ const historyStack = (0, import_react20.useRef)([]);
6270
+ const redoStack = (0, import_react20.useRef)([]);
6271
+ const isUndoRedoAction = (0, import_react20.useRef)(false);
6272
+ const isInternalChange = (0, import_react20.useRef)(false);
6273
+ const lastInternalDiagram = (0, import_react20.useRef)(null);
6274
+ (0, import_react20.useEffect)(() => {
6260
6275
  const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
6261
6276
  if (isExternal) {
6262
6277
  setLocalDiagram(diagram);
@@ -6278,7 +6293,7 @@ function PIDCanvas({
6278
6293
  enablePan: features.pan ?? true,
6279
6294
  enableZoom: features.zoom ?? true
6280
6295
  });
6281
- const calculateContentBounds = (0, import_react17.useCallback)(() => {
6296
+ const calculateContentBounds = (0, import_react20.useCallback)(() => {
6282
6297
  const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
6283
6298
  if (nodes2.length === 0) {
6284
6299
  return null;
@@ -6301,7 +6316,7 @@ function PIDCanvas({
6301
6316
  });
6302
6317
  return { minX, minY, maxX, maxY };
6303
6318
  }, [localDiagram.nodes]);
6304
- (0, import_react17.useEffect)(() => {
6319
+ (0, import_react20.useEffect)(() => {
6305
6320
  if (onMounted) {
6306
6321
  const controls = {
6307
6322
  fitToContent: (padding = 50) => {
@@ -6342,8 +6357,8 @@ function PIDCanvas({
6342
6357
  });
6343
6358
  const dragEnabled = features.dragNodes ?? false;
6344
6359
  const selectionEnabled = features.selection ?? false;
6345
- const containerRef = (0, import_react17.useRef)(null);
6346
- const pushToHistory = (0, import_react17.useCallback)((currentDiagram) => {
6360
+ const containerRef = (0, import_react20.useRef)(null);
6361
+ const pushToHistory = (0, import_react20.useCallback)((currentDiagram) => {
6347
6362
  if (isUndoRedoAction.current) return;
6348
6363
  const snapshot = JSON.parse(JSON.stringify(currentDiagram));
6349
6364
  historyStack.current.push(snapshot);
@@ -6352,7 +6367,7 @@ function PIDCanvas({
6352
6367
  }
6353
6368
  redoStack.current = [];
6354
6369
  }, []);
6355
- const undo = (0, import_react17.useCallback)(() => {
6370
+ const undo = (0, import_react20.useCallback)(() => {
6356
6371
  if (historyStack.current.length === 0) return;
6357
6372
  isUndoRedoAction.current = true;
6358
6373
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6366,7 +6381,7 @@ function PIDCanvas({
6366
6381
  isUndoRedoAction.current = false;
6367
6382
  }, 0);
6368
6383
  }, [localDiagram, onDiagramChange]);
6369
- const redo = (0, import_react17.useCallback)(() => {
6384
+ const redo = (0, import_react20.useCallback)(() => {
6370
6385
  if (redoStack.current.length === 0) return;
6371
6386
  isUndoRedoAction.current = true;
6372
6387
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6380,7 +6395,7 @@ function PIDCanvas({
6380
6395
  isUndoRedoAction.current = false;
6381
6396
  }, 0);
6382
6397
  }, [localDiagram, onDiagramChange]);
6383
- (0, import_react17.useEffect)(() => {
6398
+ (0, import_react20.useEffect)(() => {
6384
6399
  const handleKeyDown = (e) => {
6385
6400
  const isCtrlOrCmd = e.ctrlKey || e.metaKey;
6386
6401
  if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
@@ -6397,7 +6412,7 @@ function PIDCanvas({
6397
6412
  window.addEventListener("keydown", handleKeyDown);
6398
6413
  return () => window.removeEventListener("keydown", handleKeyDown);
6399
6414
  }, [undo, redo]);
6400
- (0, import_react17.useEffect)(() => {
6415
+ (0, import_react20.useEffect)(() => {
6401
6416
  if (!features.dragNodes) return;
6402
6417
  const handleKeyDown = (e) => {
6403
6418
  if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
@@ -6482,7 +6497,7 @@ function PIDCanvas({
6482
6497
  onNodeMove,
6483
6498
  pushToHistory
6484
6499
  ]);
6485
- const handlePositionChange = (0, import_react17.useCallback)(
6500
+ const handlePositionChange = (0, import_react20.useCallback)(
6486
6501
  (nodeId, x, y) => {
6487
6502
  pushToHistory(localDiagram);
6488
6503
  const updatedNodes = localDiagram.nodes.map(
@@ -6504,7 +6519,7 @@ function PIDCanvas({
6504
6519
  },
6505
6520
  [localDiagram, onDiagramChange, onNodeMove, pushToHistory]
6506
6521
  );
6507
- const handleWaypointPositionChange = (0, import_react17.useCallback)(
6522
+ const handleWaypointPositionChange = (0, import_react20.useCallback)(
6508
6523
  (pipeId, pointIndex, x, y) => {
6509
6524
  pushToHistory(localDiagram);
6510
6525
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -6522,7 +6537,7 @@ function PIDCanvas({
6522
6537
  },
6523
6538
  [localDiagram, onDiagramChange, pushToHistory]
6524
6539
  );
6525
- const handleDragEnd = (0, import_react17.useCallback)(
6540
+ const handleDragEnd = (0, import_react20.useCallback)(
6526
6541
  (nodeId, offset, finalPosition) => {
6527
6542
  const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
6528
6543
  if (dragDistance < 2) {
@@ -6603,7 +6618,7 @@ function PIDCanvas({
6603
6618
  onDiagramChange?.(updatedDiagram);
6604
6619
  }
6605
6620
  });
6606
- const handleNodeDragStart = (0, import_react17.useCallback)(
6621
+ const handleNodeDragStart = (0, import_react20.useCallback)(
6607
6622
  (nodeId, event) => {
6608
6623
  const node = localDiagram.nodes.find((n) => n.id === nodeId);
6609
6624
  if (!node) return;
@@ -6611,7 +6626,7 @@ function PIDCanvas({
6611
6626
  },
6612
6627
  [localDiagram.nodes, startDrag]
6613
6628
  );
6614
- const handleWaypointClick = (0, import_react17.useCallback)(
6629
+ const handleWaypointClick = (0, import_react20.useCallback)(
6615
6630
  (pipeId, pointIndex) => {
6616
6631
  setSelectedWaypoint({ pipeId, pointIndex });
6617
6632
  if (selectionEnabled) {
@@ -6620,7 +6635,7 @@ function PIDCanvas({
6620
6635
  },
6621
6636
  [selectionEnabled, clearSelection]
6622
6637
  );
6623
- const handleWaypointDragStart = (0, import_react17.useCallback)(
6638
+ const handleWaypointDragStart = (0, import_react20.useCallback)(
6624
6639
  (pipeId, pointIndex, event) => {
6625
6640
  const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
6626
6641
  if (!pipe || pointIndex >= pipe.routePoints.length) return;
@@ -6629,7 +6644,7 @@ function PIDCanvas({
6629
6644
  },
6630
6645
  [localDiagram.pipes, startWaypointDrag]
6631
6646
  );
6632
- const handlePipeSegmentClick = (0, import_react17.useCallback)(
6647
+ const handlePipeSegmentClick = (0, import_react20.useCallback)(
6633
6648
  (pipeId, position, segmentIndex) => {
6634
6649
  pushToHistory(localDiagram);
6635
6650
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -6648,7 +6663,7 @@ function PIDCanvas({
6648
6663
  [localDiagram, onDiagramChange, pushToHistory]
6649
6664
  );
6650
6665
  const telemetryEnabled = features.telemetry ?? false;
6651
- const handleDelete = (0, import_react17.useCallback)(() => {
6666
+ const handleDelete = (0, import_react20.useCallback)(() => {
6652
6667
  if (!selectionEnabled) return;
6653
6668
  const { selectedNodeIds, selectedPipeIds } = selection;
6654
6669
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
@@ -6677,62 +6692,81 @@ function PIDCanvas({
6677
6692
  onDelete,
6678
6693
  pushToHistory
6679
6694
  ]);
6680
- const handleCopy = (0, import_react17.useCallback)(() => {
6695
+ const handleCopy = (0, import_react20.useCallback)(() => {
6681
6696
  if (!selectionEnabled) return;
6682
6697
  const { selectedNodeIds, selectedPipeIds } = selection;
6683
6698
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
6684
6699
  onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
6685
6700
  }, [selection, selectionEnabled, onItemsCopied]);
6686
- const handlePaste = (0, import_react17.useCallback)(() => {
6701
+ const handlePaste = (0, import_react20.useCallback)(() => {
6687
6702
  if (!selectionEnabled) return;
6688
6703
  onPaste?.();
6689
6704
  }, [selectionEnabled, onPaste]);
6690
- const handleNodeDoubleClick = (nodeId, event) => {
6691
- if (!selectionEnabled) return;
6692
- console.log("Node double-clicked:", nodeId);
6693
- selectNode(nodeId, event.ctrlKey || event.metaKey);
6694
- };
6705
+ const handleNodeDoubleClick = (0, import_react20.useCallback)(
6706
+ (nodeId, event) => {
6707
+ if (!selectionEnabled) return;
6708
+ console.log("Node double-clicked:", nodeId);
6709
+ selectNode(nodeId, event.ctrlKey || event.metaKey);
6710
+ },
6711
+ [selectionEnabled, selectNode]
6712
+ );
6695
6713
  useKeyboardShortcuts({
6696
6714
  enabled: features.keyboardShortcuts ?? false,
6697
6715
  onDelete: handleDelete,
6698
6716
  onCopy: handleCopy,
6699
6717
  onPaste: handlePaste
6700
6718
  });
6701
- const handleNodeClick = (nodeId, event) => {
6702
- const connectionModeEnabled = features.connectionMode ?? false;
6703
- if (connectionModeEnabled && isConnecting) {
6704
- if (connectionSource && connectionSource !== nodeId) {
6705
- onPipeCreated?.(
6706
- connectionSource,
6707
- nodeId,
6708
- connectionSourcePort || void 0,
6709
- hoveredPort || void 0
6710
- );
6711
- setIsConnecting(false);
6712
- setConnectionSource(null);
6713
- setConnectionSourcePort(null);
6714
- setConnectionCursor(null);
6715
- setHoveredPort(null);
6719
+ const handleNodeClick = (0, import_react20.useCallback)(
6720
+ (nodeId, event) => {
6721
+ const connectionModeEnabled = features.connectionMode ?? false;
6722
+ if (connectionModeEnabled && isConnecting) {
6723
+ if (connectionSource && connectionSource !== nodeId) {
6724
+ onPipeCreated?.(
6725
+ connectionSource,
6726
+ nodeId,
6727
+ connectionSourcePort || void 0,
6728
+ hoveredPort || void 0
6729
+ );
6730
+ setIsConnecting(false);
6731
+ setConnectionSource(null);
6732
+ setConnectionSourcePort(null);
6733
+ setConnectionCursor(null);
6734
+ setHoveredPort(null);
6735
+ }
6736
+ return;
6716
6737
  }
6717
- return;
6718
- }
6719
- if (connectionModeEnabled && !isConnecting) {
6720
- setIsConnecting(true);
6721
- setConnectionSource(nodeId);
6722
- setConnectionSourcePort(hoveredPort);
6723
- return;
6724
- }
6725
- if (selectionEnabled) {
6726
- selectNode(nodeId, event.ctrlKey || event.metaKey);
6727
- }
6728
- onNodeClick?.(nodeId);
6729
- };
6730
- const handlePipeClick = (pipeId, event) => {
6731
- if (selectionEnabled) {
6732
- selectPipe(pipeId, event.ctrlKey || event.metaKey);
6733
- }
6734
- onPipeClick?.(pipeId);
6735
- };
6738
+ if (connectionModeEnabled && !isConnecting) {
6739
+ setIsConnecting(true);
6740
+ setConnectionSource(nodeId);
6741
+ setConnectionSourcePort(hoveredPort);
6742
+ return;
6743
+ }
6744
+ if (selectionEnabled) {
6745
+ selectNode(nodeId, event.ctrlKey || event.metaKey);
6746
+ }
6747
+ onNodeClick?.(nodeId);
6748
+ },
6749
+ [
6750
+ features.connectionMode,
6751
+ isConnecting,
6752
+ connectionSource,
6753
+ connectionSourcePort,
6754
+ hoveredPort,
6755
+ onPipeCreated,
6756
+ selectionEnabled,
6757
+ selectNode,
6758
+ onNodeClick
6759
+ ]
6760
+ );
6761
+ const handlePipeClick = (0, import_react20.useCallback)(
6762
+ (pipeId, event) => {
6763
+ if (selectionEnabled) {
6764
+ selectPipe(pipeId, event.ctrlKey || event.metaKey);
6765
+ }
6766
+ onPipeClick?.(pipeId);
6767
+ },
6768
+ [selectionEnabled, selectPipe, onPipeClick]
6769
+ );
6736
6770
  const handleCanvasClick = (e) => {
6737
6771
  const target = e.target;
6738
6772
  if (target.closest(".pipe-route-point")) {
@@ -6743,7 +6777,7 @@ function PIDCanvas({
6743
6777
  }
6744
6778
  setSelectedWaypoint(null);
6745
6779
  };
6746
- const handleDragOver = (0, import_react17.useCallback)(
6780
+ const handleDragOver = (0, import_react20.useCallback)(
6747
6781
  (event) => {
6748
6782
  if (!features.allowSymbolDrop) return;
6749
6783
  event.preventDefault();
@@ -6754,7 +6788,7 @@ function PIDCanvas({
6754
6788
  },
6755
6789
  [features.allowSymbolDrop, screenToWorld, svgRef]
6756
6790
  );
6757
- const handleDrop = (0, import_react17.useCallback)(
6791
+ const handleDrop = (0, import_react20.useCallback)(
6758
6792
  (event) => {
6759
6793
  if (!features.allowSymbolDrop) return;
6760
6794
  event.preventDefault();
@@ -6767,10 +6801,10 @@ function PIDCanvas({
6767
6801
  },
6768
6802
  [features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
6769
6803
  );
6770
- const handleDragLeave = (0, import_react17.useCallback)(() => {
6804
+ const handleDragLeave = (0, import_react20.useCallback)(() => {
6771
6805
  setDragOverPosition(null);
6772
6806
  }, []);
6773
- const handleMouseMove = (0, import_react17.useCallback)(
6807
+ const handleMouseMove = (0, import_react20.useCallback)(
6774
6808
  (event) => {
6775
6809
  const connectionModeEnabled = features.connectionMode ?? false;
6776
6810
  if (connectionModeEnabled) {
@@ -7080,9 +7114,10 @@ function PIDCanvas({
7080
7114
  }
7081
7115
  );
7082
7116
  }
7117
+ var PIDCanvas = import_react20.default.memo(PIDCanvasImpl);
7083
7118
 
7084
7119
  // src/components/SymbolLibrary/SymbolLibrary.tsx
7085
- var import_react18 = require("react");
7120
+ var import_react21 = require("react");
7086
7121
  var import_jsx_runtime21 = require("react/jsx-runtime");
7087
7122
  function SymbolLibrary({
7088
7123
  className = "",
@@ -7090,8 +7125,8 @@ function SymbolLibrary({
7090
7125
  showCategories = true,
7091
7126
  categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
7092
7127
  }) {
7093
- const [selectedCategory, setSelectedCategory] = (0, import_react18.useState)("all");
7094
- const [searchQuery, setSearchQuery] = (0, import_react18.useState)("");
7128
+ const [selectedCategory, setSelectedCategory] = (0, import_react21.useState)("all");
7129
+ const [searchQuery, setSearchQuery] = (0, import_react21.useState)("");
7095
7130
  const symbolIds = getAvailableSymbols();
7096
7131
  const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
7097
7132
  const categoryMap = {
@@ -8142,13 +8177,13 @@ function createControlBinding(nodeId, deviceConfig, actions) {
8142
8177
  }
8143
8178
 
8144
8179
  // src/hooks/useDeviceControls.ts
8145
- var import_react19 = require("react");
8180
+ var import_react22 = require("react");
8146
8181
  function commandKey(nodeId, kind, suffix) {
8147
8182
  return suffix ? `${nodeId}:${kind}:${suffix}` : `${nodeId}:${kind}`;
8148
8183
  }
8149
8184
  function useDeviceControls(initialBindings, options) {
8150
8185
  const { commandTimeoutMs } = options ?? {};
8151
- const [controls, setControls] = (0, import_react19.useState)(() => {
8186
+ const [controls, setControls] = (0, import_react22.useState)(() => {
8152
8187
  const map = /* @__PURE__ */ new Map();
8153
8188
  if (initialBindings) {
8154
8189
  initialBindings.forEach((binding) => {
@@ -8157,12 +8192,12 @@ function useDeviceControls(initialBindings, options) {
8157
8192
  }
8158
8193
  return map;
8159
8194
  });
8160
- const pendingRef = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
8161
- const [pendingCommands, setPendingCommands] = (0, import_react19.useState)(() => /* @__PURE__ */ new Set());
8162
- const syncPending = (0, import_react19.useCallback)(() => {
8195
+ const pendingRef = (0, import_react22.useRef)(/* @__PURE__ */ new Map());
8196
+ const [pendingCommands, setPendingCommands] = (0, import_react22.useState)(() => /* @__PURE__ */ new Set());
8197
+ const syncPending = (0, import_react22.useCallback)(() => {
8163
8198
  setPendingCommands(new Set(pendingRef.current.keys()));
8164
8199
  }, []);
8165
- const updateControl = (0, import_react19.useCallback)((nodeId, updates) => {
8200
+ const updateControl = (0, import_react22.useCallback)((nodeId, updates) => {
8166
8201
  setControls((prev) => {
8167
8202
  const newMap = new Map(prev);
8168
8203
  const existing = newMap.get(nodeId);
@@ -8176,7 +8211,7 @@ function useDeviceControls(initialBindings, options) {
8176
8211
  return newMap;
8177
8212
  });
8178
8213
  }, []);
8179
- const updateControlBatch = (0, import_react19.useCallback)((updates) => {
8214
+ const updateControlBatch = (0, import_react22.useCallback)((updates) => {
8180
8215
  setControls((prev) => {
8181
8216
  const newMap = new Map(prev);
8182
8217
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -8188,7 +8223,7 @@ function useDeviceControls(initialBindings, options) {
8188
8223
  return newMap;
8189
8224
  });
8190
8225
  }, []);
8191
- const updateDeviceState = (0, import_react19.useCallback)(
8226
+ const updateDeviceState = (0, import_react22.useCallback)(
8192
8227
  (nodeId, stateUpdates) => {
8193
8228
  setControls((prev) => {
8194
8229
  const newMap = new Map(prev);
@@ -8204,7 +8239,7 @@ function useDeviceControls(initialBindings, options) {
8204
8239
  },
8205
8240
  []
8206
8241
  );
8207
- const updateParameter = (0, import_react19.useCallback)(
8242
+ const updateParameter = (0, import_react22.useCallback)(
8208
8243
  (nodeId, parameterId, value) => {
8209
8244
  setControls((prev) => {
8210
8245
  const newMap = new Map(prev);
@@ -8231,27 +8266,27 @@ function useDeviceControls(initialBindings, options) {
8231
8266
  },
8232
8267
  []
8233
8268
  );
8234
- const setControlBinding = (0, import_react19.useCallback)((binding) => {
8269
+ const setControlBinding = (0, import_react22.useCallback)((binding) => {
8235
8270
  setControls((prev) => {
8236
8271
  const newMap = new Map(prev);
8237
8272
  newMap.set(binding.nodeId, binding);
8238
8273
  return newMap;
8239
8274
  });
8240
8275
  }, []);
8241
- const removeControlBinding = (0, import_react19.useCallback)((nodeId) => {
8276
+ const removeControlBinding = (0, import_react22.useCallback)((nodeId) => {
8242
8277
  setControls((prev) => {
8243
8278
  const newMap = new Map(prev);
8244
8279
  newMap.delete(nodeId);
8245
8280
  return newMap;
8246
8281
  });
8247
8282
  }, []);
8248
- const getControlBinding = (0, import_react19.useCallback)(
8283
+ const getControlBinding = (0, import_react22.useCallback)(
8249
8284
  (nodeId) => {
8250
8285
  return controls.get(nodeId);
8251
8286
  },
8252
8287
  [controls]
8253
8288
  );
8254
- const isCommandPending = (0, import_react19.useCallback)(
8289
+ const isCommandPending = (0, import_react22.useCallback)(
8255
8290
  (nodeId, kind) => {
8256
8291
  if (kind) {
8257
8292
  const prefix2 = `${nodeId}:${kind}`;
@@ -8268,7 +8303,7 @@ function useDeviceControls(initialBindings, options) {
8268
8303
  },
8269
8304
  [pendingCommands]
8270
8305
  );
8271
- const markPending = (0, import_react19.useCallback)(
8306
+ const markPending = (0, import_react22.useCallback)(
8272
8307
  (key, delta) => {
8273
8308
  const next = (pendingRef.current.get(key) ?? 0) + delta;
8274
8309
  if (next > 0) pendingRef.current.set(key, next);
@@ -8277,7 +8312,7 @@ function useDeviceControls(initialBindings, options) {
8277
8312
  },
8278
8313
  [syncPending]
8279
8314
  );
8280
- const runCommand = (0, import_react19.useCallback)(
8315
+ const runCommand = (0, import_react22.useCallback)(
8281
8316
  async (nodeId, key, invoke, messages) => {
8282
8317
  const binding = controls.get(nodeId);
8283
8318
  if (!binding) return;
@@ -8317,7 +8352,7 @@ function useDeviceControls(initialBindings, options) {
8317
8352
  },
8318
8353
  [controls, updateDeviceState, markPending, commandTimeoutMs]
8319
8354
  );
8320
- const sendModeChange = (0, import_react19.useCallback)(
8355
+ const sendModeChange = (0, import_react22.useCallback)(
8321
8356
  (nodeId, mode) => runCommand(
8322
8357
  nodeId,
8323
8358
  commandKey(nodeId, "mode"),
@@ -8326,7 +8361,7 @@ function useDeviceControls(initialBindings, options) {
8326
8361
  ),
8327
8362
  [runCommand]
8328
8363
  );
8329
- const sendParameterChange = (0, import_react19.useCallback)(
8364
+ const sendParameterChange = (0, import_react22.useCallback)(
8330
8365
  (nodeId, parameterId, value) => runCommand(
8331
8366
  nodeId,
8332
8367
  commandKey(nodeId, "parameter", parameterId),
@@ -8335,21 +8370,21 @@ function useDeviceControls(initialBindings, options) {
8335
8370
  ),
8336
8371
  [runCommand]
8337
8372
  );
8338
- const sendStartCommand = (0, import_react19.useCallback)(
8373
+ const sendStartCommand = (0, import_react22.useCallback)(
8339
8374
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "start"), (binding) => binding.actions.onStart?.(), {
8340
8375
  success: "Start command sent",
8341
8376
  failure: "Start command failed"
8342
8377
  }),
8343
8378
  [runCommand]
8344
8379
  );
8345
- const sendStopCommand = (0, import_react19.useCallback)(
8380
+ const sendStopCommand = (0, import_react22.useCallback)(
8346
8381
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "stop"), (binding) => binding.actions.onStop?.(), {
8347
8382
  success: "Stop command sent",
8348
8383
  failure: "Stop command failed"
8349
8384
  }),
8350
8385
  [runCommand]
8351
8386
  );
8352
- const sendCustomAction = (0, import_react19.useCallback)(
8387
+ const sendCustomAction = (0, import_react22.useCallback)(
8353
8388
  (nodeId, actionId) => runCommand(
8354
8389
  nodeId,
8355
8390
  commandKey(nodeId, "action", actionId),
@@ -8402,9 +8437,9 @@ function createConfigBinding(nodeId, tag, parameters, actions, options) {
8402
8437
  }
8403
8438
 
8404
8439
  // src/hooks/useDeviceConfigs.ts
8405
- var import_react20 = require("react");
8440
+ var import_react23 = require("react");
8406
8441
  function useDeviceConfigs(initialConfigs) {
8407
- const [configs, setConfigs] = (0, import_react20.useState)(() => {
8442
+ const [configs, setConfigs] = (0, import_react23.useState)(() => {
8408
8443
  const map = /* @__PURE__ */ new Map();
8409
8444
  if (initialConfigs) {
8410
8445
  initialConfigs.forEach((config) => {
@@ -8413,13 +8448,13 @@ function useDeviceConfigs(initialConfigs) {
8413
8448
  }
8414
8449
  return map;
8415
8450
  });
8416
- const getConfig = (0, import_react20.useCallback)(
8451
+ const getConfig = (0, import_react23.useCallback)(
8417
8452
  (nodeId) => {
8418
8453
  return configs.get(nodeId);
8419
8454
  },
8420
8455
  [configs]
8421
8456
  );
8422
- const updateConfig = (0, import_react20.useCallback)((nodeId, updates) => {
8457
+ const updateConfig = (0, import_react23.useCallback)((nodeId, updates) => {
8423
8458
  setConfigs((prev) => {
8424
8459
  const newMap = new Map(prev);
8425
8460
  const existing = newMap.get(nodeId);
@@ -8433,7 +8468,7 @@ function useDeviceConfigs(initialConfigs) {
8433
8468
  return newMap;
8434
8469
  });
8435
8470
  }, []);
8436
- const updateConfigState = (0, import_react20.useCallback)((nodeId, stateUpdates) => {
8471
+ const updateConfigState = (0, import_react23.useCallback)((nodeId, stateUpdates) => {
8437
8472
  setConfigs((prev) => {
8438
8473
  const newMap = new Map(prev);
8439
8474
  const existing = newMap.get(nodeId);
@@ -8446,7 +8481,7 @@ function useDeviceConfigs(initialConfigs) {
8446
8481
  return newMap;
8447
8482
  });
8448
8483
  }, []);
8449
- const updateConfigBatch = (0, import_react20.useCallback)((updates) => {
8484
+ const updateConfigBatch = (0, import_react23.useCallback)((updates) => {
8450
8485
  setConfigs((prev) => {
8451
8486
  const newMap = new Map(prev);
8452
8487
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -8458,7 +8493,7 @@ function useDeviceConfigs(initialConfigs) {
8458
8493
  return newMap;
8459
8494
  });
8460
8495
  }, []);
8461
- const updateParameterValue = (0, import_react20.useCallback)((nodeId, parameterId, value) => {
8496
+ const updateParameterValue = (0, import_react23.useCallback)((nodeId, parameterId, value) => {
8462
8497
  setConfigs((prev) => {
8463
8498
  const newMap = new Map(prev);
8464
8499
  const existing = newMap.get(nodeId);
@@ -8475,7 +8510,7 @@ function useDeviceConfigs(initialConfigs) {
8475
8510
  return newMap;
8476
8511
  });
8477
8512
  }, []);
8478
- const applyConfig = (0, import_react20.useCallback)(
8513
+ const applyConfig = (0, import_react23.useCallback)(
8479
8514
  async (nodeId) => {
8480
8515
  const config = configs.get(nodeId);
8481
8516
  if (!config || !config.actions.onApply) {
@@ -8508,7 +8543,7 @@ function useDeviceConfigs(initialConfigs) {
8508
8543
  },
8509
8544
  [configs, updateConfigState]
8510
8545
  );
8511
- const saveConfig = (0, import_react20.useCallback)(
8546
+ const saveConfig = (0, import_react23.useCallback)(
8512
8547
  async (nodeId) => {
8513
8548
  const config = configs.get(nodeId);
8514
8549
  if (!config || !config.actions.onSave) {
@@ -8542,7 +8577,7 @@ function useDeviceConfigs(initialConfigs) {
8542
8577
  },
8543
8578
  [configs, updateConfigState]
8544
8579
  );
8545
- const resetConfig = (0, import_react20.useCallback)(
8580
+ const resetConfig = (0, import_react23.useCallback)(
8546
8581
  async (nodeId) => {
8547
8582
  const config = configs.get(nodeId);
8548
8583
  if (!config) {
@@ -8572,7 +8607,7 @@ function useDeviceConfigs(initialConfigs) {
8572
8607
  },
8573
8608
  [configs, updateConfig, updateConfigState]
8574
8609
  );
8575
- const cancelConfig = (0, import_react20.useCallback)(
8610
+ const cancelConfig = (0, import_react23.useCallback)(
8576
8611
  (nodeId) => {
8577
8612
  const config = configs.get(nodeId);
8578
8613
  if (config?.actions.onCancel) {
@@ -8581,7 +8616,7 @@ function useDeviceConfigs(initialConfigs) {
8581
8616
  },
8582
8617
  [configs]
8583
8618
  );
8584
- const validateConfig = (0, import_react20.useCallback)(
8619
+ const validateConfig = (0, import_react23.useCallback)(
8585
8620
  (nodeId) => {
8586
8621
  const config = configs.get(nodeId);
8587
8622
  if (!config) {
@@ -8623,21 +8658,21 @@ function useDeviceConfigs(initialConfigs) {
8623
8658
  },
8624
8659
  [configs, updateConfigState]
8625
8660
  );
8626
- const setConfig = (0, import_react20.useCallback)((config) => {
8661
+ const setConfig = (0, import_react23.useCallback)((config) => {
8627
8662
  setConfigs((prev) => {
8628
8663
  const newMap = new Map(prev);
8629
8664
  newMap.set(config.nodeId, config);
8630
8665
  return newMap;
8631
8666
  });
8632
8667
  }, []);
8633
- const removeConfig = (0, import_react20.useCallback)((nodeId) => {
8668
+ const removeConfig = (0, import_react23.useCallback)((nodeId) => {
8634
8669
  setConfigs((prev) => {
8635
8670
  const newMap = new Map(prev);
8636
8671
  newMap.delete(nodeId);
8637
8672
  return newMap;
8638
8673
  });
8639
8674
  }, []);
8640
- const clearConfigs = (0, import_react20.useCallback)(() => {
8675
+ const clearConfigs = (0, import_react23.useCallback)(() => {
8641
8676
  setConfigs(/* @__PURE__ */ new Map());
8642
8677
  }, []);
8643
8678
  return {
@@ -8659,7 +8694,7 @@ function useDeviceConfigs(initialConfigs) {
8659
8694
  }
8660
8695
 
8661
8696
  // src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
8662
- var import_react21 = require("react");
8697
+ var import_react24 = require("react");
8663
8698
  var import_jsx_runtime23 = require("react/jsx-runtime");
8664
8699
  function DeviceConfigPanel({
8665
8700
  binding,
@@ -8678,7 +8713,7 @@ function DeviceConfigPanel({
8678
8713
  showControlsButton = true,
8679
8714
  embedded = false
8680
8715
  }) {
8681
- const [localValues, setLocalValues] = (0, import_react21.useState)(() => {
8716
+ const [localValues, setLocalValues] = (0, import_react24.useState)(() => {
8682
8717
  if (binding) {
8683
8718
  const values = {};
8684
8719
  binding.parameters.forEach((param) => {
@@ -8688,7 +8723,7 @@ function DeviceConfigPanel({
8688
8723
  }
8689
8724
  return {};
8690
8725
  });
8691
- const [collapsedSections, setCollapsedSections] = (0, import_react21.useState)(() => {
8726
+ const [collapsedSections, setCollapsedSections] = (0, import_react24.useState)(() => {
8692
8727
  const collapsed = /* @__PURE__ */ new Set();
8693
8728
  if (binding?.sections) {
8694
8729
  binding.sections.forEach((section) => {
@@ -8699,9 +8734,9 @@ function DeviceConfigPanel({
8699
8734
  }
8700
8735
  return collapsed;
8701
8736
  });
8702
- const [showToast, setShowToast] = (0, import_react21.useState)(true);
8703
- const [bindingId, setBindingId] = (0, import_react21.useState)(binding?.nodeId || null);
8704
- const lastResultTimestampRef = (0, import_react21.useRef)(0);
8737
+ const [showToast, setShowToast] = (0, import_react24.useState)(true);
8738
+ const [bindingId, setBindingId] = (0, import_react24.useState)(binding?.nodeId || null);
8739
+ const lastResultTimestampRef = (0, import_react24.useRef)(0);
8705
8740
  if (binding && binding.nodeId !== bindingId) {
8706
8741
  const values = {};
8707
8742
  binding.parameters.forEach((param) => {
@@ -8717,21 +8752,24 @@ function DeviceConfigPanel({
8717
8752
  setCollapsedSections(collapsed);
8718
8753
  setBindingId(binding.nodeId);
8719
8754
  }
8720
- (0, import_react21.useEffect)(() => {
8755
+ (0, import_react24.useEffect)(() => {
8721
8756
  const currentTimestamp = binding?.state.lastSaved || 0;
8722
8757
  if (binding?.state.lastSaveResult && currentTimestamp !== lastResultTimestampRef.current) {
8723
8758
  lastResultTimestampRef.current = currentTimestamp;
8759
+ let hideTimer;
8724
8760
  const showTimer = setTimeout(() => {
8725
8761
  setShowToast(true);
8726
- const hideTimer = setTimeout(() => {
8762
+ hideTimer = setTimeout(() => {
8727
8763
  setShowToast(false);
8728
8764
  }, toastDuration);
8729
- return () => clearTimeout(hideTimer);
8730
8765
  }, 0);
8731
- return () => clearTimeout(showTimer);
8766
+ return () => {
8767
+ clearTimeout(showTimer);
8768
+ if (hideTimer) clearTimeout(hideTimer);
8769
+ };
8732
8770
  }
8733
8771
  }, [binding?.state.lastSaveResult, binding?.state.lastSaved, toastDuration]);
8734
- const parametersBySection = (0, import_react21.useMemo)(() => {
8772
+ const parametersBySection = (0, import_react24.useMemo)(() => {
8735
8773
  if (!binding) return { _unsectioned: [] };
8736
8774
  const groups = { _unsectioned: [] };
8737
8775
  binding.parameters.forEach((param) => {
@@ -8746,7 +8784,7 @@ function DeviceConfigPanel({
8746
8784
  });
8747
8785
  return groups;
8748
8786
  }, [binding]);
8749
- const sortedSections = (0, import_react21.useMemo)(() => {
8787
+ const sortedSections = (0, import_react24.useMemo)(() => {
8750
8788
  if (!binding?.sections) return [];
8751
8789
  return [...binding.sections].sort((a, b) => (a.order || 0) - (b.order || 0));
8752
8790
  }, [binding]);
@@ -9362,7 +9400,7 @@ function DeviceConfigPanel({
9362
9400
  }
9363
9401
 
9364
9402
  // src/diagram/hooks/useSimulation.ts
9365
- var import_react22 = require("react");
9403
+ var import_react25 = require("react");
9366
9404
  function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
9367
9405
  const {
9368
9406
  interval = 2e3,
@@ -9373,7 +9411,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
9373
9411
  historyLength = 10,
9374
9412
  generateValue
9375
9413
  } = options;
9376
- (0, import_react22.useEffect)(() => {
9414
+ (0, import_react25.useEffect)(() => {
9377
9415
  if (!enabled) return;
9378
9416
  const intervalId = setInterval(() => {
9379
9417
  const updates = [];