@procaaso/alphinity-ui-components 1.11.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -50,6 +50,8 @@ __export(index_exports, {
50
50
  FooterPanel: () => FooterPanel,
51
51
  FullscreenContainer: () => FullscreenContainer,
52
52
  FullscreenWorkspace: () => FullscreenWorkspace,
53
+ ISA_UNKNOWN: () => ISA_UNKNOWN,
54
+ ISA_UNKNOWN_DARK: () => ISA_UNKNOWN_DARK,
53
55
  LeftPanel: () => LeftPanel,
54
56
  LeftToggleButton: () => LeftToggleButton,
55
57
  LegacyValueEntry: () => LegacyValueEntry,
@@ -72,8 +74,9 @@ __export(index_exports, {
72
74
  ThemeProvider: () => ThemeProvider,
73
75
  ThemeToggle: () => ThemeToggle,
74
76
  TrendLine: () => TrendLine,
75
- UNKNOWN_MARK_COLOR: () => UNKNOWN_MARK_COLOR,
76
- UNKNOWN_MARK_COLOR_DARK: () => UNKNOWN_MARK_COLOR_DARK,
77
+ UNKNOWN_GLYPH_RING_DASH: () => UNKNOWN_GLYPH_RING_DASH,
78
+ UNKNOWN_STATUS_GLYPH_COLOR_VAR: () => UNKNOWN_STATUS_GLYPH_COLOR_VAR,
79
+ UnknownStatusGlyph: () => UnknownStatusGlyph,
77
80
  ValueEntry: () => ValueEntry,
78
81
  ZoomButton: () => ZoomButton,
79
82
  ZoomControls: () => ZoomControls,
@@ -85,14 +88,19 @@ __export(index_exports, {
85
88
  generateRoutePoints: () => generateRoutePoints,
86
89
  getAppearanceDefaults: () => getAppearanceDefaults,
87
90
  getAppearanceSchema: () => getAppearanceSchema,
91
+ getAvailableBadgeGlyphs: () => getAvailableBadgeGlyphs,
88
92
  getAvailableSymbols: () => getAvailableSymbols,
93
+ getBadgeGlyph: () => getBadgeGlyph,
89
94
  getPortWorldPosition: () => getPortWorldPosition,
90
95
  getSymbolDefinition: () => getSymbolDefinition,
91
96
  importDiagram: () => importDiagram,
92
97
  mockSymbolLibrary: () => mockSymbolLibrary,
93
98
  nodeHasPort: () => nodeHasPort,
99
+ normalizeDeviceStatus: () => normalizeDeviceStatus,
94
100
  overlayStyles: () => overlayStyles,
95
101
  readAppearanceValue: () => readAppearanceValue,
102
+ registerBadgeGlyph: () => registerBadgeGlyph,
103
+ registerBadgeGlyphs: () => registerBadgeGlyphs,
96
104
  registerSymbol: () => registerSymbol,
97
105
  registerSymbols: () => registerSymbols,
98
106
  resolvePresetColor: () => resolvePresetColor,
@@ -382,6 +390,16 @@ var ValueEntry = ({
382
390
  var import_react3 = require("react");
383
391
 
384
392
  // src/theme/statusColors.ts
393
+ var ISA_UNKNOWN = {
394
+ fg: "#4f4f8a",
395
+ bg: "#ebebf5",
396
+ border: "#8f8fc2"
397
+ };
398
+ var ISA_UNKNOWN_DARK = {
399
+ fg: "#b9bbdb",
400
+ bg: "#23263a",
401
+ border: "#6f74a3"
402
+ };
385
403
  var DEFAULT_STATUS_COLORS = {
386
404
  normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
387
405
  warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
@@ -389,7 +407,8 @@ var DEFAULT_STATUS_COLORS = {
389
407
  fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
390
408
  off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
391
409
  starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
392
- stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
410
+ stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
411
+ unknown: { fill: ISA_UNKNOWN.bg, stroke: ISA_UNKNOWN.border, bg: ISA_UNKNOWN.bg, text: ISA_UNKNOWN.fg, border: ISA_UNKNOWN.border }
393
412
  };
394
413
  var FORCED_MARK_COLOR = {
395
414
  fill: "#ede9fe",
@@ -398,27 +417,16 @@ var FORCED_MARK_COLOR = {
398
417
  text: "#5b21b6",
399
418
  border: "#7c3aed"
400
419
  };
401
- var UNKNOWN_MARK_COLOR = {
402
- fill: "#ebebf5",
403
- stroke: "#8f8fc2",
404
- bg: "#ebebf5",
405
- text: "#4f4f8a",
406
- border: "#8f8fc2"
407
- };
408
- var UNKNOWN_MARK_COLOR_DARK = {
409
- fill: "#23263a",
410
- stroke: "#6f74a3",
411
- bg: "#23263a",
412
- text: "#b9bbdb",
413
- border: "#6f74a3"
414
- };
415
420
  var STATUS_ALIASES = {
416
421
  running: "normal",
417
422
  stopped: "off"
418
423
  };
419
- function resolveStatusColor(status, customMap) {
424
+ function normalizeDeviceStatus(status) {
420
425
  const raw = (status || "off").toLowerCase();
421
- const key = STATUS_ALIASES[raw] ?? raw;
426
+ return STATUS_ALIASES[raw] ?? raw;
427
+ }
428
+ function resolveStatusColor(status, customMap) {
429
+ const key = normalizeDeviceStatus(status);
422
430
  const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
423
431
  const overrides = customMap?.[key];
424
432
  if (!overrides) return defaults;
@@ -858,7 +866,79 @@ var ControlPanel = ({
858
866
  };
859
867
 
860
868
  // src/components/StatusIndicator/StatusIndicator.tsx
869
+ var import_react5 = __toESM(require("react"), 1);
870
+
871
+ // src/theme/unknownStatusGlyph.tsx
861
872
  var import_jsx_runtime6 = require("react/jsx-runtime");
873
+ var UNKNOWN_STATUS_GLYPH_COLOR_VAR = "--ui-status-indicator-unknown-glyph-color";
874
+ var UNKNOWN_GLYPH_STROKE_WEIGHTS = {
875
+ small: { ring: 4.5, ringDash: "7 6", mark: 5, dot: 2.9 },
876
+ medium: { ring: 4, ringDash: "6.5 5.5", mark: 4.5, dot: 2.7 },
877
+ large: { ring: 3.5, ringDash: "6.5 5.5", mark: 4, dot: 2.5 }
878
+ };
879
+ var UNKNOWN_GLYPH_RING_DASH = UNKNOWN_GLYPH_STROKE_WEIGHTS.medium.ringDash;
880
+ var UNKNOWN_GLYPH_FILL_STYLE = {
881
+ position: "absolute",
882
+ inset: 0,
883
+ width: "100%",
884
+ height: "100%"
885
+ };
886
+ function unknownGlyphHostStyle(isUnknown, style) {
887
+ return isUnknown ? { position: "relative", ...style } : style;
888
+ }
889
+ function UnknownStatusGlyph({
890
+ size = "medium",
891
+ counterRotate = false,
892
+ style,
893
+ ...rest
894
+ }) {
895
+ const weights = UNKNOWN_GLYPH_STROKE_WEIGHTS[size];
896
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
897
+ "svg",
898
+ {
899
+ viewBox: "0 0 48 48",
900
+ "aria-hidden": "true",
901
+ focusable: "false",
902
+ style: {
903
+ display: "block",
904
+ color: `var(${UNKNOWN_STATUS_GLYPH_COLOR_VAR}, currentColor)`,
905
+ transform: counterRotate ? "rotate(-45deg)" : void 0,
906
+ ...style
907
+ },
908
+ ...rest,
909
+ children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
911
+ "circle",
912
+ {
913
+ cx: 24,
914
+ cy: 24,
915
+ r: 20,
916
+ fill: "none",
917
+ stroke: "currentColor",
918
+ strokeDasharray: weights.ringDash,
919
+ strokeLinecap: "round",
920
+ strokeWidth: weights.ring
921
+ }
922
+ ),
923
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
924
+ "path",
925
+ {
926
+ d: "M18.4 18.6a5.8 5.8 0 1 1 6.4 8.1v3.1",
927
+ fill: "none",
928
+ stroke: "currentColor",
929
+ strokeLinecap: "round",
930
+ strokeLinejoin: "round",
931
+ strokeWidth: weights.mark
932
+ }
933
+ ),
934
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: 24.6, cy: 35.4, r: weights.dot, fill: "currentColor" })
935
+ ]
936
+ }
937
+ );
938
+ }
939
+
940
+ // src/components/StatusIndicator/StatusIndicator.tsx
941
+ var import_jsx_runtime7 = require("react/jsx-runtime");
862
942
  var getStatusDescription = (status) => {
863
943
  switch (status) {
864
944
  case "alarm":
@@ -873,10 +953,23 @@ var getStatusDescription = (status) => {
873
953
  return "Operating normally";
874
954
  case "off":
875
955
  return "Equipment is off";
956
+ case "unknown":
957
+ return "Device state cannot be confirmed. Check the link or the wiring.";
876
958
  default:
877
959
  return "";
878
960
  }
879
961
  };
962
+ var visuallyHiddenStyle = {
963
+ position: "absolute",
964
+ width: "1px",
965
+ height: "1px",
966
+ padding: 0,
967
+ margin: "-1px",
968
+ overflow: "hidden",
969
+ clip: "rect(0, 0, 0, 0)",
970
+ whiteSpace: "nowrap",
971
+ border: 0
972
+ };
880
973
  var StatusIndicator = ({
881
974
  status,
882
975
  size = "medium",
@@ -889,17 +982,25 @@ var StatusIndicator = ({
889
982
  forced = false,
890
983
  realValue,
891
984
  className = "",
985
+ style,
986
+ "aria-describedby": consumerDescribedBy,
987
+ children,
892
988
  ...props
893
989
  }) => {
990
+ const generatedDescriptionId = `${import_react5.default.useId()}-status-description`;
894
991
  if (!visible) {
895
992
  return null;
896
993
  }
994
+ const describedBy = consumerDescribedBy ? `${consumerDescribedBy} ${generatedDescriptionId}` : generatedDescriptionId;
995
+ const description = getStatusDescription(status);
897
996
  const baseClass = "ui-status-indicator";
898
997
  const statusClass = status ? `ui-status-indicator--${status}` : "";
899
998
  const sizeClass = size ? `ui-status-indicator--${size}` : "";
900
999
  const shapeClass = shape ? `ui-status-indicator--${shape}` : "";
901
1000
  const animationClass = animation ? `ui-status-indicator--${animation}` : "";
902
1001
  const ledClass = led ? "ui-status-indicator--led" : "";
1002
+ const isUnknown = status === "unknown";
1003
+ const indicatorStyle = unknownGlyphHostStyle(isUnknown, style);
903
1004
  const getContainerLayout = () => {
904
1005
  switch (labelPosition) {
905
1006
  case "left":
@@ -916,19 +1017,20 @@ var StatusIndicator = ({
916
1017
  };
917
1018
  const forcedClass = forced ? "ui-status-indicator--forced" : "";
918
1019
  const hasRealValue = forced && realValue !== void 0;
919
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: getContainerLayout(), children: [
920
- label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label }),
921
- hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
1020
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: getContainerLayout(), children: [
1021
+ label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-label", children: label }),
1022
+ hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
922
1023
  "REAL ",
923
1024
  realValue
924
1025
  ] }),
925
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1026
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
1027
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
927
1028
  "span",
928
1029
  {
929
1030
  role: "status",
930
1031
  "aria-label": label || `Status: ${status}`,
931
- "aria-description": getStatusDescription(status),
1032
+ "aria-description": description,
1033
+ "aria-describedby": describedBy,
932
1034
  "data-status": status,
933
1035
  "data-forced": forced,
934
1036
  className: `
@@ -941,13 +1043,26 @@ var StatusIndicator = ({
941
1043
  ${forcedClass}
942
1044
  ${className}
943
1045
  `.replace(/\s+/g, " ").trim(),
944
- ...props
1046
+ style: indicatorStyle,
1047
+ ...props,
1048
+ children: [
1049
+ isUnknown && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1050
+ UnknownStatusGlyph,
1051
+ {
1052
+ size,
1053
+ counterRotate: shape === "diamond",
1054
+ style: UNKNOWN_GLYPH_FILL_STYLE
1055
+ }
1056
+ ),
1057
+ children,
1058
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: generatedDescriptionId, style: visuallyHiddenStyle, children: description })
1059
+ ]
945
1060
  }
946
1061
  ),
947
- forced && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
1062
+ forced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
948
1063
  ] }),
949
- label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label }),
950
- hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
1064
+ label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-label", children: label }),
1065
+ hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
951
1066
  "REAL ",
952
1067
  realValue
953
1068
  ] })
@@ -955,7 +1070,7 @@ var StatusIndicator = ({
955
1070
  };
956
1071
 
957
1072
  // src/components/NodeControlsPanel/NodeControlsPanel.tsx
958
- var import_jsx_runtime7 = require("react/jsx-runtime");
1073
+ var import_jsx_runtime8 = require("react/jsx-runtime");
959
1074
  var NodeControlsPanel = ({
960
1075
  config,
961
1076
  onClose,
@@ -1028,8 +1143,8 @@ var NodeControlsPanel = ({
1028
1143
  overflowY: "auto",
1029
1144
  flex: 1
1030
1145
  };
1031
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1032
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1146
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1147
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1033
1148
  "div",
1034
1149
  {
1035
1150
  style: {
@@ -1042,16 +1157,16 @@ var NodeControlsPanel = ({
1042
1157
  onClick: onClose
1043
1158
  }
1044
1159
  ),
1045
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1160
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1046
1161
  "div",
1047
1162
  {
1048
1163
  className: `node-controls-panel ${touchClass} ${className}`.trim(),
1049
1164
  style: containerStyle,
1050
1165
  ...props,
1051
1166
  children: [
1052
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: headerStyle, children: [
1053
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: titleStyle, children: config.title }),
1054
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1167
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: headerStyle, children: [
1168
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: titleStyle, children: config.title }),
1169
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1055
1170
  "button",
1056
1171
  {
1057
1172
  style: closeButtonStyle,
@@ -1069,7 +1184,7 @@ var NodeControlsPanel = ({
1069
1184
  }
1070
1185
  )
1071
1186
  ] }),
1072
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: contentStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1187
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: contentStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1073
1188
  ControlPanel,
1074
1189
  {
1075
1190
  title: config.nodeId,
@@ -1098,7 +1213,7 @@ var NodeControlsPanel = ({
1098
1213
  ]
1099
1214
  }
1100
1215
  ),
1101
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
1216
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
1102
1217
  @keyframes slideUp {
1103
1218
  from {
1104
1219
  transform: translateY(100%);
@@ -1144,8 +1259,8 @@ var NodeControlsPanel = ({
1144
1259
  };
1145
1260
 
1146
1261
  // src/components/DeviceControlPanel/DeviceControlPanel.tsx
1147
- var import_react5 = __toESM(require("react"), 1);
1148
- var import_jsx_runtime8 = require("react/jsx-runtime");
1262
+ var import_react6 = __toESM(require("react"), 1);
1263
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1149
1264
  function DeviceControlPanelImpl({
1150
1265
  binding,
1151
1266
  onClose,
@@ -1173,11 +1288,11 @@ function DeviceControlPanelImpl({
1173
1288
  showBuiltInToast = true,
1174
1289
  embedded = false
1175
1290
  }) {
1176
- const [localParameterValues, setLocalParameterValues] = (0, import_react5.useState)({});
1177
- const [showModeModal, setShowModeModal] = (0, import_react5.useState)(false);
1178
- const [pendingMode, setPendingMode] = (0, import_react5.useState)(null);
1179
- const [showToast, setShowToast] = (0, import_react5.useState)(true);
1180
- (0, import_react5.useEffect)(() => {
1291
+ const [localParameterValues, setLocalParameterValues] = (0, import_react6.useState)({});
1292
+ const [showModeModal, setShowModeModal] = (0, import_react6.useState)(false);
1293
+ const [pendingMode, setPendingMode] = (0, import_react6.useState)(null);
1294
+ const [showToast, setShowToast] = (0, import_react6.useState)(true);
1295
+ (0, import_react6.useEffect)(() => {
1181
1296
  if (binding) {
1182
1297
  const currentParams2 = binding.parameters[binding.state.currentMode] || [];
1183
1298
  const values = {};
@@ -1187,7 +1302,7 @@ function DeviceControlPanelImpl({
1187
1302
  setLocalParameterValues(values);
1188
1303
  }
1189
1304
  }, [binding, binding?.state.currentMode]);
1190
- (0, import_react5.useEffect)(() => {
1305
+ (0, import_react6.useEffect)(() => {
1191
1306
  if (binding?.state.lastCommandResult) {
1192
1307
  setShowToast(true);
1193
1308
  const timer = setTimeout(() => {
@@ -1225,6 +1340,7 @@ function DeviceControlPanelImpl({
1225
1340
  const selectedColor = "#b4d0fe";
1226
1341
  const statusEntry = resolveStatusColor(binding.state.status, binding.theme?.statusColors);
1227
1342
  const statusColor = statusEntry.bg;
1343
+ const isUnknownStatus = normalizeDeviceStatus(binding.state.status) === "unknown";
1228
1344
  const handleModeChange = (mode) => {
1229
1345
  onModeChange?.(mode);
1230
1346
  };
@@ -1279,9 +1395,9 @@ function DeviceControlPanelImpl({
1279
1395
  ...binding.display?.style
1280
1396
  };
1281
1397
  const titleText = binding.display?.title || binding.deviceName || binding.tag || binding.nodeId;
1282
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1283
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
1284
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1398
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1399
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
1400
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1285
1401
  "div",
1286
1402
  {
1287
1403
  style: {
@@ -1293,8 +1409,8 @@ function DeviceControlPanelImpl({
1293
1409
  borderBottom: `2px solid ${borderColor}`
1294
1410
  },
1295
1411
  children: [
1296
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1297
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1412
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1413
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1298
1414
  "h3",
1299
1415
  {
1300
1416
  style: {
@@ -1314,7 +1430,7 @@ function DeviceControlPanelImpl({
1314
1430
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
1315
1431
  }
1316
1432
  ),
1317
- binding.deviceType && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1433
+ binding.deviceType && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1318
1434
  "div",
1319
1435
  {
1320
1436
  style: {
@@ -1327,8 +1443,8 @@ function DeviceControlPanelImpl({
1327
1443
  }
1328
1444
  )
1329
1445
  ] }),
1330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1331
- showConfigButton && onOpenConfig && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1446
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1447
+ showConfigButton && onOpenConfig && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1332
1448
  "button",
1333
1449
  {
1334
1450
  onClick: onOpenConfig,
@@ -1349,7 +1465,7 @@ function DeviceControlPanelImpl({
1349
1465
  children: "\u2699"
1350
1466
  }
1351
1467
  ),
1352
- onUndock && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1468
+ onUndock && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1353
1469
  "button",
1354
1470
  {
1355
1471
  onClick: onUndock,
@@ -1370,7 +1486,7 @@ function DeviceControlPanelImpl({
1370
1486
  children: undockIcon
1371
1487
  }
1372
1488
  ),
1373
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1489
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1374
1490
  "button",
1375
1491
  {
1376
1492
  onClick: onClose,
@@ -1393,7 +1509,7 @@ function DeviceControlPanelImpl({
1393
1509
  ]
1394
1510
  }
1395
1511
  ),
1396
- binding.state.status && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1512
+ binding.state.status && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1397
1513
  "div",
1398
1514
  {
1399
1515
  style: {
@@ -1407,7 +1523,7 @@ function DeviceControlPanelImpl({
1407
1523
  marginBottom: spacing.marginBottom
1408
1524
  },
1409
1525
  children: [
1410
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1526
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1411
1527
  "div",
1412
1528
  {
1413
1529
  style: {
@@ -1415,12 +1531,17 @@ function DeviceControlPanelImpl({
1415
1531
  height: "10px",
1416
1532
  borderRadius: "50%",
1417
1533
  backgroundColor: statusColor,
1418
- border: "1px solid #333"
1419
- }
1534
+ border: "1px solid #333",
1535
+ // The shared helper positions this dot only while it shows
1536
+ // the unknown marker. The glyph then fills the dot with an
1537
+ // absolute inset, the same pattern StatusIndicator uses.
1538
+ ...unknownGlyphHostStyle(isUnknownStatus)
1539
+ },
1540
+ children: isUnknownStatus && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UnknownStatusGlyph, { size: "small", style: UNKNOWN_GLYPH_FILL_STYLE })
1420
1541
  }
1421
1542
  ),
1422
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1 }, children: [
1423
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1543
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1 }, children: [
1544
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1424
1545
  "div",
1425
1546
  {
1426
1547
  style: {
@@ -1434,7 +1555,7 @@ function DeviceControlPanelImpl({
1434
1555
  children: binding.state.status
1435
1556
  }
1436
1557
  ),
1437
- binding.state.statusMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1558
+ binding.state.statusMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1438
1559
  "div",
1439
1560
  {
1440
1561
  style: {
@@ -1447,28 +1568,36 @@ function DeviceControlPanelImpl({
1447
1568
  }
1448
1569
  )
1449
1570
  ] }),
1450
- binding.state.isRunning !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1571
+ binding.state.isRunning !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1451
1572
  "div",
1452
1573
  {
1453
1574
  style: {
1454
1575
  padding: "4px 10px",
1455
- backgroundColor: binding.state.isRunning ? selectedColor : surfaceColor,
1456
- border: `1px solid ${borderColor}`,
1576
+ // This badge shows the last published isRunning value. It
1577
+ // never re-derives that value here. When status is
1578
+ // unknown, the value may be stale. Muted colors carry that
1579
+ // warning alongside the word, so color is not the only
1580
+ // channel and the wording is not the only channel either.
1581
+ backgroundColor: isUnknownStatus ? statusEntry.bg : binding.state.isRunning ? selectedColor : surfaceColor,
1582
+ border: `1px solid ${isUnknownStatus ? statusEntry.border : borderColor}`,
1457
1583
  borderRadius: "2px",
1458
1584
  fontSize: "10px",
1459
1585
  fontWeight: 600,
1460
1586
  fontFamily: "Arial, sans-serif",
1461
1587
  letterSpacing: "0.5px",
1462
- color: textColor
1588
+ color: isUnknownStatus ? statusEntry.text : textColor
1463
1589
  },
1464
- children: binding.state.isRunning ? "RUNNING" : "STOPPED"
1590
+ children: [
1591
+ binding.state.isRunning ? "RUNNING" : "STOPPED",
1592
+ isUnknownStatus && " (unconfirmed)"
1593
+ ]
1465
1594
  }
1466
1595
  )
1467
1596
  ]
1468
1597
  }
1469
1598
  ),
1470
- binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginBottom: "16px" }, children: [
1471
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1599
+ binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: "16px" }, children: [
1600
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1472
1601
  "label",
1473
1602
  {
1474
1603
  style: {
@@ -1484,7 +1613,7 @@ function DeviceControlPanelImpl({
1484
1613
  children: "Mode"
1485
1614
  }
1486
1615
  ),
1487
- modeSelectionStyle === "dropdown" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1616
+ modeSelectionStyle === "dropdown" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1488
1617
  "select",
1489
1618
  {
1490
1619
  value: currentMode,
@@ -1505,10 +1634,10 @@ function DeviceControlPanelImpl({
1505
1634
  paddingRight: "12px",
1506
1635
  cursor: "pointer"
1507
1636
  },
1508
- children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: mode.value, disabled: mode.enabled === false, children: mode.label }, mode.value))
1637
+ children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: mode.value, disabled: mode.enabled === false, children: mode.label }, mode.value))
1509
1638
  }
1510
- ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1511
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1639
+ ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1640
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1512
1641
  "div",
1513
1642
  {
1514
1643
  onClick: () => {
@@ -1531,12 +1660,12 @@ function DeviceControlPanelImpl({
1531
1660
  alignItems: "center"
1532
1661
  },
1533
1662
  children: [
1534
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1535
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1663
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1536
1665
  ]
1537
1666
  }
1538
1667
  ),
1539
- showModeModal && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1668
+ showModeModal && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1540
1669
  "div",
1541
1670
  {
1542
1671
  style: {
@@ -1555,7 +1684,7 @@ function DeviceControlPanelImpl({
1555
1684
  setShowModeModal(false);
1556
1685
  setPendingMode(null);
1557
1686
  },
1558
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1687
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1559
1688
  "div",
1560
1689
  {
1561
1690
  onClick: (e) => e.stopPropagation(),
@@ -1568,7 +1697,7 @@ function DeviceControlPanelImpl({
1568
1697
  border: `2px solid ${borderColor}`
1569
1698
  },
1570
1699
  children: [
1571
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1700
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1572
1701
  "h3",
1573
1702
  {
1574
1703
  style: {
@@ -1581,7 +1710,7 @@ function DeviceControlPanelImpl({
1581
1710
  children: "Select Mode"
1582
1711
  }
1583
1712
  ),
1584
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1713
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1585
1714
  "div",
1586
1715
  {
1587
1716
  style: {
@@ -1595,7 +1724,7 @@ function DeviceControlPanelImpl({
1595
1724
  children: binding.display?.title || binding.deviceName || binding.tag || binding.nodeId
1596
1725
  }
1597
1726
  ),
1598
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1727
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1599
1728
  "select",
1600
1729
  {
1601
1730
  value: pendingMode || currentMode,
@@ -1617,7 +1746,7 @@ function DeviceControlPanelImpl({
1617
1746
  paddingRight: "12px",
1618
1747
  cursor: "pointer"
1619
1748
  },
1620
- children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1749
+ children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1621
1750
  "option",
1622
1751
  {
1623
1752
  value: mode.value,
@@ -1632,7 +1761,7 @@ function DeviceControlPanelImpl({
1632
1761
  const selectedMode = binding.modes.find(
1633
1762
  (m) => m.value === (pendingMode || currentMode)
1634
1763
  );
1635
- return selectedMode?.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1764
+ return selectedMode?.description ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1636
1765
  "div",
1637
1766
  {
1638
1767
  style: {
@@ -1650,8 +1779,8 @@ function DeviceControlPanelImpl({
1650
1779
  }
1651
1780
  ) : null;
1652
1781
  })(),
1653
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [
1654
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1782
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1655
1784
  "button",
1656
1785
  {
1657
1786
  onClick: () => {
@@ -1679,7 +1808,7 @@ function DeviceControlPanelImpl({
1679
1808
  children: "Confirm"
1680
1809
  }
1681
1810
  ),
1682
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1811
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1683
1812
  "button",
1684
1813
  {
1685
1814
  onClick: () => {
@@ -1709,7 +1838,7 @@ function DeviceControlPanelImpl({
1709
1838
  )
1710
1839
  }
1711
1840
  )
1712
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1841
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1713
1842
  "div",
1714
1843
  {
1715
1844
  style: {
@@ -1725,7 +1854,7 @@ function DeviceControlPanelImpl({
1725
1854
  children: binding.modes.map((mode) => {
1726
1855
  const isSelected = mode.value === currentMode;
1727
1856
  const isEnabled = mode.enabled !== false;
1728
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1857
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1729
1858
  "button",
1730
1859
  {
1731
1860
  onClick: () => isEnabled && handleModeChange(mode.value),
@@ -1755,8 +1884,8 @@ function DeviceControlPanelImpl({
1755
1884
  }
1756
1885
  )
1757
1886
  ] }),
1758
- currentParams.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginBottom: spacing.marginBottom }, children: [
1759
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1887
+ currentParams.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: spacing.marginBottom }, children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1760
1889
  "label",
1761
1890
  {
1762
1891
  style: {
@@ -1772,7 +1901,7 @@ function DeviceControlPanelImpl({
1772
1901
  children: "Parameters"
1773
1902
  }
1774
1903
  ),
1775
- currentParams.map((param) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1904
+ currentParams.map((param) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1776
1905
  "div",
1777
1906
  {
1778
1907
  style: {
@@ -1783,7 +1912,7 @@ function DeviceControlPanelImpl({
1783
1912
  borderRadius: "6px"
1784
1913
  },
1785
1914
  children: [
1786
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1915
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1787
1916
  "div",
1788
1917
  {
1789
1918
  style: {
@@ -1792,7 +1921,7 @@ function DeviceControlPanelImpl({
1792
1921
  marginBottom: spacing.gap
1793
1922
  },
1794
1923
  children: [
1795
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1924
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1796
1925
  "span",
1797
1926
  {
1798
1927
  style: {
@@ -1808,7 +1937,7 @@ function DeviceControlPanelImpl({
1808
1937
  },
1809
1938
  children: [
1810
1939
  param.label,
1811
- param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1940
+ param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1812
1941
  "span",
1813
1942
  {
1814
1943
  "aria-label": "Forced",
@@ -1831,7 +1960,7 @@ function DeviceControlPanelImpl({
1831
1960
  ]
1832
1961
  }
1833
1962
  ),
1834
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1963
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1835
1964
  "span",
1836
1965
  {
1837
1966
  style: {
@@ -1843,14 +1972,14 @@ function DeviceControlPanelImpl({
1843
1972
  children: [
1844
1973
  localParameterValues[param.id] ?? param.value,
1845
1974
  " ",
1846
- param.unit && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1975
+ param.unit && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1847
1976
  ]
1848
1977
  }
1849
1978
  )
1850
1979
  ]
1851
1980
  }
1852
1981
  ),
1853
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1982
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1854
1983
  "div",
1855
1984
  {
1856
1985
  style: {
@@ -1871,7 +2000,7 @@ function DeviceControlPanelImpl({
1871
2000
  ]
1872
2001
  }
1873
2002
  ),
1874
- param.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2003
+ param.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1875
2004
  "button",
1876
2005
  {
1877
2006
  onClick: () => {
@@ -1896,7 +2025,7 @@ function DeviceControlPanelImpl({
1896
2025
  },
1897
2026
  children: localParameterValues[param.id] ? "ON" : "OFF"
1898
2027
  }
1899
- ) : param.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2028
+ ) : param.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1900
2029
  "select",
1901
2030
  {
1902
2031
  value: localParameterValues[param.id] || param.value,
@@ -1917,12 +2046,12 @@ function DeviceControlPanelImpl({
1917
2046
  fontFamily: "monospace",
1918
2047
  cursor: "pointer"
1919
2048
  },
1920
- children: param.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
2049
+ children: param.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1921
2050
  }
1922
2051
  ) : onParameterActivate && !param.readOnly ? (
1923
2052
  // Tappable value: defer editing to the consumer's editor (e.g. a
1924
2053
  // numpad dialog). Commit happens via onParameterChange.
1925
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2054
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1926
2055
  "button",
1927
2056
  {
1928
2057
  type: "button",
@@ -1949,7 +2078,7 @@ function DeviceControlPanelImpl({
1949
2078
  ]
1950
2079
  }
1951
2080
  )
1952
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2081
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1953
2082
  "input",
1954
2083
  {
1955
2084
  type: param.type === "number" ? "number" : "text",
@@ -1982,8 +2111,8 @@ function DeviceControlPanelImpl({
1982
2111
  param.id
1983
2112
  ))
1984
2113
  ] }),
1985
- binding.display?.showStartStop !== false && (activeCapabilities?.canStart || activeCapabilities?.canStop) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: spacing.gap, marginBottom: spacing.marginBottom }, children: [
1986
- activeCapabilities?.canStart && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2114
+ binding.display?.showStartStop !== false && (activeCapabilities?.canStart || activeCapabilities?.canStop) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: spacing.gap, marginBottom: spacing.marginBottom }, children: [
2115
+ activeCapabilities?.canStart && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1987
2116
  "button",
1988
2117
  {
1989
2118
  onClick: onStart,
@@ -2004,7 +2133,7 @@ function DeviceControlPanelImpl({
2004
2133
  children: startPending ? "STARTING\u2026" : "START"
2005
2134
  }
2006
2135
  ),
2007
- activeCapabilities?.canStop && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2136
+ activeCapabilities?.canStop && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2008
2137
  "button",
2009
2138
  {
2010
2139
  onClick: onStop,
@@ -2026,9 +2155,9 @@ function DeviceControlPanelImpl({
2026
2155
  }
2027
2156
  )
2028
2157
  ] }),
2029
- activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => {
2158
+ activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => {
2030
2159
  const actionDisabled = action.disabled === true;
2031
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2160
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2032
2161
  "button",
2033
2162
  {
2034
2163
  onClick: () => {
@@ -2054,7 +2183,7 @@ function DeviceControlPanelImpl({
2054
2183
  transition: "all 0.15s"
2055
2184
  },
2056
2185
  children: [
2057
- action.icon && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { marginRight: "6px" }, children: action.icon }),
2186
+ action.icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { marginRight: "6px" }, children: action.icon }),
2058
2187
  action.label
2059
2188
  ]
2060
2189
  },
@@ -2062,7 +2191,7 @@ function DeviceControlPanelImpl({
2062
2191
  );
2063
2192
  }) })
2064
2193
  ] }),
2065
- binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2194
+ binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2066
2195
  "div",
2067
2196
  {
2068
2197
  style: {
@@ -2086,7 +2215,7 @@ function DeviceControlPanelImpl({
2086
2215
  children: binding.state.lastCommandResult.message
2087
2216
  }
2088
2217
  ),
2089
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
2218
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
2090
2219
  @keyframes slideInToast {
2091
2220
  from {
2092
2221
  opacity: 0;
@@ -2118,11 +2247,11 @@ function DeviceControlPanelImpl({
2118
2247
  ` })
2119
2248
  ] });
2120
2249
  }
2121
- var DeviceControlPanel = import_react5.default.memo(DeviceControlPanelImpl);
2250
+ var DeviceControlPanel = import_react6.default.memo(DeviceControlPanelImpl);
2122
2251
 
2123
2252
  // src/components/NumpadDialog/NumpadDialog.tsx
2124
- var import_react6 = require("react");
2125
- var import_jsx_runtime9 = require("react/jsx-runtime");
2253
+ var import_react7 = require("react");
2254
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2126
2255
  var NumpadDialog = ({
2127
2256
  isOpen,
2128
2257
  onClose,
@@ -2136,24 +2265,24 @@ var NumpadDialog = ({
2136
2265
  currentValue = 0,
2137
2266
  touchOptimized = true
2138
2267
  }) => {
2139
- const [inputValue, setInputValue] = (0, import_react6.useState)("");
2140
- const [pristine, setPristine] = (0, import_react6.useState)(true);
2141
- const dialogRef = (0, import_react6.useRef)(null);
2142
- const titleId = (0, import_react6.useId)();
2268
+ const [inputValue, setInputValue] = (0, import_react7.useState)("");
2269
+ const [pristine, setPristine] = (0, import_react7.useState)(true);
2270
+ const dialogRef = (0, import_react7.useRef)(null);
2271
+ const titleId = (0, import_react7.useId)();
2143
2272
  const decimals = precision ?? 1;
2144
- (0, import_react6.useEffect)(() => {
2273
+ (0, import_react7.useEffect)(() => {
2145
2274
  if (isOpen) {
2146
2275
  setInputValue(Number(currentValue).toFixed(decimals));
2147
2276
  setPristine(true);
2148
2277
  }
2149
2278
  }, [isOpen, currentValue, decimals]);
2150
- (0, import_react6.useEffect)(() => {
2279
+ (0, import_react7.useEffect)(() => {
2151
2280
  if (!isOpen) return;
2152
2281
  const previouslyFocused = document.activeElement;
2153
2282
  dialogRef.current?.focus();
2154
2283
  return () => previouslyFocused?.focus?.();
2155
2284
  }, [isOpen]);
2156
- (0, import_react6.useEffect)(() => {
2285
+ (0, import_react7.useEffect)(() => {
2157
2286
  if (!isOpen) return;
2158
2287
  const prevOverflow = document.body.style.overflow;
2159
2288
  document.body.style.overflow = "hidden";
@@ -2161,13 +2290,13 @@ var NumpadDialog = ({
2161
2290
  document.body.style.overflow = prevOverflow;
2162
2291
  };
2163
2292
  }, [isOpen]);
2164
- const handleApply = (0, import_react6.useCallback)(() => {
2293
+ const handleApply = (0, import_react7.useCallback)(() => {
2165
2294
  const n = Number(inputValue);
2166
2295
  if (inputValue === "" || inputValue === "-" || inputValue === "." || inputValue === "-.") return;
2167
2296
  if (isNaN(n) || n < min || n > max) return;
2168
2297
  onApply(Number(n.toFixed(decimals)));
2169
2298
  }, [inputValue, min, max, onApply, decimals]);
2170
- const appendDigit = (0, import_react6.useCallback)(
2299
+ const appendDigit = (0, import_react7.useCallback)(
2171
2300
  (digit) => {
2172
2301
  setInputValue((prev) => {
2173
2302
  const base = pristine ? "" : prev;
@@ -2187,15 +2316,15 @@ var NumpadDialog = ({
2187
2316
  },
2188
2317
  [pristine, decimals]
2189
2318
  );
2190
- const handleBackspace = (0, import_react6.useCallback)(() => {
2319
+ const handleBackspace = (0, import_react7.useCallback)(() => {
2191
2320
  setPristine(false);
2192
2321
  setInputValue((prev) => prev.slice(0, -1));
2193
2322
  }, []);
2194
- const handleClear = (0, import_react6.useCallback)(() => {
2323
+ const handleClear = (0, import_react7.useCallback)(() => {
2195
2324
  setPristine(false);
2196
2325
  setInputValue("");
2197
2326
  }, []);
2198
- const handleToggleSign = (0, import_react6.useCallback)(() => {
2327
+ const handleToggleSign = (0, import_react7.useCallback)(() => {
2199
2328
  if (min >= 0) return;
2200
2329
  setPristine(false);
2201
2330
  setInputValue((prev) => {
@@ -2204,8 +2333,8 @@ var NumpadDialog = ({
2204
2333
  return "-" + prev;
2205
2334
  });
2206
2335
  }, [min]);
2207
- const bsTimer = (0, import_react6.useRef)(null);
2208
- const bsLongFired = (0, import_react6.useRef)(false);
2336
+ const bsTimer = (0, import_react7.useRef)(null);
2337
+ const bsLongFired = (0, import_react7.useRef)(false);
2209
2338
  const clearBsTimer = () => {
2210
2339
  if (bsTimer.current !== null) {
2211
2340
  clearTimeout(bsTimer.current);
@@ -2227,8 +2356,8 @@ var NumpadDialog = ({
2227
2356
  }
2228
2357
  handleBackspace();
2229
2358
  };
2230
- (0, import_react6.useEffect)(() => () => clearBsTimer(), []);
2231
- (0, import_react6.useEffect)(() => {
2359
+ (0, import_react7.useEffect)(() => () => clearBsTimer(), []);
2360
+ (0, import_react7.useEffect)(() => {
2232
2361
  if (!isOpen) return;
2233
2362
  const handler = (e) => {
2234
2363
  if (e.key === "Tab") {
@@ -2326,7 +2455,7 @@ var NumpadDialog = ({
2326
2455
  };
2327
2456
  const reason = belowMin ? `Below minimum of ${min} ${unit}` : aboveMax ? `Above maximum of ${max} ${unit}` : "Type or tap to change the value";
2328
2457
  const backspaceInGrid = min >= 0;
2329
- const BackspaceButton = ({ style, label }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2458
+ const BackspaceButton = ({ style, label }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2330
2459
  "button",
2331
2460
  {
2332
2461
  type: "button",
@@ -2343,7 +2472,7 @@ var NumpadDialog = ({
2343
2472
  );
2344
2473
  return (
2345
2474
  // Backdrop
2346
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2475
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2347
2476
  "div",
2348
2477
  {
2349
2478
  style: {
@@ -2360,14 +2489,14 @@ var NumpadDialog = ({
2360
2489
  },
2361
2490
  onClick: onClose,
2362
2491
  children: [
2363
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
2492
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: `
2364
2493
  .np-key { transition: background .1s, transform .05s; touch-action: manipulation; }
2365
2494
  .np-key:active:not(:disabled) { background:#e2e8f0; transform: translateY(1px); }
2366
2495
  .np-key:focus-visible, .np-action:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }
2367
2496
  @keyframes np-blink { 0%,49%{opacity:1} 50%,100%{opacity:0} }
2368
2497
  .np-caret { display:inline-block; width:2px; height:1.1em; background:#2563eb; animation: np-blink 1s step-end infinite; }
2369
2498
  ` }),
2370
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2499
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2371
2500
  "div",
2372
2501
  {
2373
2502
  ref: dialogRef,
@@ -2388,9 +2517,9 @@ var NumpadDialog = ({
2388
2517
  },
2389
2518
  onClick: (e) => e.stopPropagation(),
2390
2519
  children: [
2391
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { padding: "14px 16px 0 16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { id: titleId, style: { margin: 0, fontSize: 15, fontWeight: 700, color: "#0f172a" }, children: deviceName ? `${deviceName} - ${parameterLabel}` : parameterLabel }) }),
2392
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { padding: 16, display: "flex", flexDirection: "column", gap: 10 }, children: [
2393
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2520
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { padding: "14px 16px 0 16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { id: titleId, style: { margin: 0, fontSize: 15, fontWeight: 700, color: "#0f172a" }, children: deviceName ? `${deviceName} - ${parameterLabel}` : parameterLabel }) }),
2521
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { padding: 16, display: "flex", flexDirection: "column", gap: 10 }, children: [
2522
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2394
2523
  "div",
2395
2524
  {
2396
2525
  style: {
@@ -2400,24 +2529,24 @@ var NumpadDialog = ({
2400
2529
  color: "#64748b"
2401
2530
  },
2402
2531
  children: [
2403
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2532
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
2404
2533
  "Current: ",
2405
2534
  currentValue,
2406
2535
  " ",
2407
2536
  unit
2408
2537
  ] }),
2409
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2538
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
2410
2539
  "Range: ",
2411
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: limitStyle(belowMin), children: min }),
2540
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: limitStyle(belowMin), children: min }),
2412
2541
  "-",
2413
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: limitStyle(aboveMax), children: max }),
2542
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: limitStyle(aboveMax), children: max }),
2414
2543
  " ",
2415
2544
  unit
2416
2545
  ] })
2417
2546
  ]
2418
2547
  }
2419
2548
  ),
2420
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2549
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2421
2550
  "div",
2422
2551
  {
2423
2552
  "aria-live": "polite",
@@ -2439,13 +2568,13 @@ var NumpadDialog = ({
2439
2568
  border: outOfRange ? "1.5px solid #fca5a5" : "1.5px solid #e2e8f0"
2440
2569
  },
2441
2570
  children: [
2442
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: inputValue || "0" }),
2443
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "np-caret", "aria-hidden": "true" }),
2444
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: 14, color: "#94a3b8", fontWeight: 500 }, children: unit })
2571
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: inputValue || "0" }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "np-caret", "aria-hidden": "true" }),
2573
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: 14, color: "#94a3b8", fontWeight: 500 }, children: unit })
2445
2574
  ]
2446
2575
  }
2447
2576
  ),
2448
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2577
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2449
2578
  "div",
2450
2579
  {
2451
2580
  role: "status",
@@ -2460,8 +2589,8 @@ var NumpadDialog = ({
2460
2589
  children: reason
2461
2590
  }
2462
2591
  ),
2463
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 5 }, children: [
2464
- ["7", "8", "9", "4", "5", "6", "1", "2", "3"].map((digit) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2592
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 5 }, children: [
2593
+ ["7", "8", "9", "4", "5", "6", "1", "2", "3"].map((digit) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2465
2594
  "button",
2466
2595
  {
2467
2596
  type: "button",
@@ -2473,7 +2602,7 @@ var NumpadDialog = ({
2473
2602
  },
2474
2603
  digit
2475
2604
  )),
2476
- min < 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2605
+ min < 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2477
2606
  "button",
2478
2607
  {
2479
2608
  type: "button",
@@ -2484,9 +2613,9 @@ var NumpadDialog = ({
2484
2613
  onClick: handleToggleSign,
2485
2614
  children: "+/\u2212"
2486
2615
  }
2487
- ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BackspaceButton, { style: { ...keyStyle, fontSize: 20, background: "#f8fafc", color: "#64748b" }, label: "\u232B" }),
2488
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: keyStyle, onClick: () => appendDigit("0"), children: "0" }),
2489
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2616
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BackspaceButton, { style: { ...keyStyle, fontSize: 20, background: "#f8fafc", color: "#64748b" }, label: "\u232B" }),
2617
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: keyStyle, onClick: () => appendDigit("0"), children: "0" }),
2618
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2490
2619
  "button",
2491
2620
  {
2492
2621
  type: "button",
@@ -2504,12 +2633,12 @@ var NumpadDialog = ({
2504
2633
  }
2505
2634
  )
2506
2635
  ] }),
2507
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: 5 }, children: [
2508
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: utilKeyStyle, onClick: handleClear, children: "Clear" }),
2509
- !backspaceInGrid && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BackspaceButton, { style: utilKeyStyle, label: "Backspace" })
2636
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", gap: 5 }, children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: utilKeyStyle, onClick: handleClear, children: "Clear" }),
2638
+ !backspaceInGrid && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BackspaceButton, { style: utilKeyStyle, label: "Backspace" })
2510
2639
  ] }),
2511
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2512
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2640
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2641
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2513
2642
  "button",
2514
2643
  {
2515
2644
  type: "button",
@@ -2529,7 +2658,7 @@ var NumpadDialog = ({
2529
2658
  children: "Cancel"
2530
2659
  }
2531
2660
  ),
2532
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2661
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2533
2662
  "button",
2534
2663
  {
2535
2664
  type: "button",
@@ -2564,13 +2693,13 @@ var NumpadDialog = ({
2564
2693
  };
2565
2694
 
2566
2695
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
2567
- var import_react8 = __toESM(require("react"), 1);
2696
+ var import_react9 = __toESM(require("react"), 1);
2568
2697
  var import_material3 = require("@mui/material");
2569
2698
 
2570
2699
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
2571
2700
  var import_material = require("@mui/material");
2572
2701
  var import_styled = __toESM(require("@emotion/styled"), 1);
2573
- var import_jsx_runtime10 = require("react/jsx-runtime");
2702
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2574
2703
  var FullscreenContainer = (0, import_styled.default)(import_material.Box)(
2575
2704
  ({ leftCollapsed, rightCollapsed }) => {
2576
2705
  const getGridTemplateAreas = () => {
@@ -2695,7 +2824,7 @@ var DisplayModeToggle = (0, import_styled.default)(import_material.IconButton)((
2695
2824
  transform: "translateX(-50%) scale(1.05)"
2696
2825
  }
2697
2826
  }));
2698
- var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2827
+ var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2699
2828
  "div",
2700
2829
  {
2701
2830
  style: {
@@ -2707,7 +2836,7 @@ var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2707
2836
  }
2708
2837
  }
2709
2838
  );
2710
- var ChevronRight = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2839
+ var ChevronRight = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2711
2840
  "div",
2712
2841
  {
2713
2842
  style: {
@@ -2818,10 +2947,10 @@ var ScrollableSVGWrapper = (0, import_styled.default)("div")({
2818
2947
  });
2819
2948
 
2820
2949
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx
2821
- var import_react7 = require("react");
2950
+ var import_react8 = require("react");
2822
2951
  var import_material2 = require("@mui/material");
2823
2952
  var import_styled2 = __toESM(require("@emotion/styled"), 1);
2824
- var import_jsx_runtime11 = require("react/jsx-runtime");
2953
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2825
2954
  var baseOverlayStyles = {
2826
2955
  tank: {
2827
2956
  background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
@@ -2883,8 +3012,8 @@ var SVGLockedOverlay = ({
2883
3012
  onClick,
2884
3013
  containerSelector = ".tff-svg-container"
2885
3014
  }) => {
2886
- const [svgOffset, setSvgOffset] = (0, import_react7.useState)({ x: 0, y: 0 });
2887
- (0, import_react7.useEffect)(() => {
3015
+ const [svgOffset, setSvgOffset] = (0, import_react8.useState)({ x: 0, y: 0 });
3016
+ (0, import_react8.useEffect)(() => {
2888
3017
  const updateSvgOffset = () => {
2889
3018
  const containerElement = document.querySelector(containerSelector);
2890
3019
  const svgElement = containerElement?.querySelector("svg");
@@ -2904,7 +3033,7 @@ var SVGLockedOverlay = ({
2904
3033
  const pixelX = svgX + svgOffset.x;
2905
3034
  const pixelY = svgY + svgOffset.y;
2906
3035
  const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
2907
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3036
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2908
3037
  import_material2.Box,
2909
3038
  {
2910
3039
  className: `svg-locked-overlay ${className}`.trim(),
@@ -2968,7 +3097,7 @@ var CardUnit = (0, import_styled2.default)("div")({
2968
3097
  });
2969
3098
 
2970
3099
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
2971
- var import_jsx_runtime12 = require("react/jsx-runtime");
3100
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2972
3101
  var forcedTagStyle = {
2973
3102
  position: "absolute",
2974
3103
  top: "-6px",
@@ -2996,7 +3125,7 @@ var TrendLine = ({
2996
3125
  forced = false
2997
3126
  }) => {
2998
3127
  if (!values || values.length < 2) {
2999
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3128
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3000
3129
  "div",
3001
3130
  {
3002
3131
  style: {
@@ -3010,8 +3139,8 @@ var TrendLine = ({
3010
3139
  justifyContent: "center"
3011
3140
  },
3012
3141
  children: [
3013
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
3014
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3142
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
3143
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3015
3144
  ]
3016
3145
  }
3017
3146
  );
@@ -3024,7 +3153,7 @@ var TrendLine = ({
3024
3153
  const x = 4 + i / (values.length - 1) * (width - 8);
3025
3154
  return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
3026
3155
  }).join(" ");
3027
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3156
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3028
3157
  "div",
3029
3158
  {
3030
3159
  style: {
@@ -3036,14 +3165,14 @@ var TrendLine = ({
3036
3165
  overflow: "visible"
3037
3166
  },
3038
3167
  children: [
3039
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3168
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3040
3169
  "svg",
3041
3170
  {
3042
3171
  width,
3043
3172
  height,
3044
3173
  style: { position: "absolute", top: 0, left: 0, overflow: "hidden", borderRadius: "2px" },
3045
3174
  children: [
3046
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3175
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3047
3176
  "path",
3048
3177
  {
3049
3178
  d: pathData,
@@ -3054,7 +3183,7 @@ var TrendLine = ({
3054
3183
  strokeLinejoin: "round"
3055
3184
  }
3056
3185
  ),
3057
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3186
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3058
3187
  "circle",
3059
3188
  {
3060
3189
  cx: 4 + (width - 8),
@@ -3066,7 +3195,7 @@ var TrendLine = ({
3066
3195
  ]
3067
3196
  }
3068
3197
  ),
3069
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3198
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3070
3199
  ]
3071
3200
  }
3072
3201
  );
@@ -3098,7 +3227,7 @@ var CircularGauge = ({
3098
3227
  const borderColor = isHex ? hexToRgba(color, 0.9) : color;
3099
3228
  const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
3100
3229
  const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
3101
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3230
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3102
3231
  "div",
3103
3232
  {
3104
3233
  style: {
@@ -3107,7 +3236,7 @@ var CircularGauge = ({
3107
3236
  alignItems: "center"
3108
3237
  },
3109
3238
  children: [
3110
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3239
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3111
3240
  "div",
3112
3241
  {
3113
3242
  style: {
@@ -3119,8 +3248,8 @@ var CircularGauge = ({
3119
3248
  border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : `1px solid ${borderStrokeColor}`
3120
3249
  },
3121
3250
  children: [
3122
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
3123
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3251
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
3252
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3124
3253
  "circle",
3125
3254
  {
3126
3255
  cx: size / 2,
@@ -3131,7 +3260,7 @@ var CircularGauge = ({
3131
3260
  strokeWidth: 1
3132
3261
  }
3133
3262
  ),
3134
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3263
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3135
3264
  "circle",
3136
3265
  {
3137
3266
  cx: size / 2,
@@ -3142,7 +3271,7 @@ var CircularGauge = ({
3142
3271
  fill: "transparent"
3143
3272
  }
3144
3273
  ),
3145
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3274
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3146
3275
  "circle",
3147
3276
  {
3148
3277
  cx: size / 2,
@@ -3158,7 +3287,7 @@ var CircularGauge = ({
3158
3287
  }
3159
3288
  )
3160
3289
  ] }),
3161
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3290
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3162
3291
  "div",
3163
3292
  {
3164
3293
  style: {
@@ -3174,14 +3303,14 @@ var CircularGauge = ({
3174
3303
  },
3175
3304
  children: [
3176
3305
  value.toFixed(1),
3177
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3306
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3178
3307
  ]
3179
3308
  }
3180
3309
  )
3181
3310
  ]
3182
3311
  }
3183
3312
  ),
3184
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3313
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3185
3314
  "div",
3186
3315
  {
3187
3316
  style: {
@@ -3193,7 +3322,7 @@ var CircularGauge = ({
3193
3322
  children: label
3194
3323
  }
3195
3324
  ),
3196
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3325
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3197
3326
  "span",
3198
3327
  {
3199
3328
  "aria-label": "Forced",
@@ -3214,7 +3343,7 @@ var CircularGauge = ({
3214
3343
  children: "F"
3215
3344
  }
3216
3345
  ),
3217
- forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3346
+ forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3218
3347
  "REAL ",
3219
3348
  realValue.toFixed(1),
3220
3349
  " ",
@@ -3239,7 +3368,7 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3239
3368
  const y = height - 8 - (value - min) / range * (height - 8);
3240
3369
  return `${x + 4},${y + 4}`;
3241
3370
  }).join(" ");
3242
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3371
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3243
3372
  "div",
3244
3373
  {
3245
3374
  style: {
@@ -3255,13 +3384,13 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3255
3384
  boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
3256
3385
  },
3257
3386
  children: [
3258
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
3259
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3387
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
3388
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3260
3389
  ]
3261
3390
  }
3262
3391
  );
3263
3392
  };
3264
- var EquipmentForcedBadge = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3393
+ var EquipmentForcedBadge = () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3265
3394
  "span",
3266
3395
  {
3267
3396
  "aria-label": "Forced",
@@ -3296,9 +3425,9 @@ var EquipmentIndicatorWithSparkline = ({
3296
3425
  forced = false
3297
3426
  }) => {
3298
3427
  const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
3299
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3300
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
3301
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3428
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3429
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
3430
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3302
3431
  "div",
3303
3432
  {
3304
3433
  style: {
@@ -3319,9 +3448,9 @@ var EquipmentIndicatorWithSparkline = ({
3319
3448
  children: label
3320
3449
  }
3321
3450
  ),
3322
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
3451
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EquipmentForcedBadge, {})
3323
3452
  ] }) }),
3324
- hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
3453
+ hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
3325
3454
  ] });
3326
3455
  };
3327
3456
  var EquipmentIndicator = ({
@@ -3335,8 +3464,8 @@ var EquipmentIndicator = ({
3335
3464
  forced = false
3336
3465
  }) => {
3337
3466
  const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
3338
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
3339
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3467
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
3468
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3340
3469
  "div",
3341
3470
  {
3342
3471
  style: {
@@ -3357,12 +3486,12 @@ var EquipmentIndicator = ({
3357
3486
  children: label
3358
3487
  }
3359
3488
  ),
3360
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
3489
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EquipmentForcedBadge, {})
3361
3490
  ] }) });
3362
3491
  };
3363
3492
 
3364
3493
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
3365
- var import_jsx_runtime13 = require("react/jsx-runtime");
3494
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3366
3495
  function FullscreenWorkspace({
3367
3496
  svgContent,
3368
3497
  overlays,
@@ -3390,10 +3519,10 @@ function FullscreenWorkspace({
3390
3519
  className = "",
3391
3520
  ...rest
3392
3521
  }) {
3393
- const [leftCollapsedState, setLeftCollapsedState] = import_react8.default.useState(defaultLeftCollapsed);
3394
- const [rightCollapsedState, setRightCollapsedState] = import_react8.default.useState(defaultRightCollapsed);
3395
- const [internalDisplayMode, setInternalDisplayMode] = import_react8.default.useState(displayMode ?? defaultDisplayMode);
3396
- const [internalTab, setInternalTab] = import_react8.default.useState(
3522
+ const [leftCollapsedState, setLeftCollapsedState] = import_react9.default.useState(defaultLeftCollapsed);
3523
+ const [rightCollapsedState, setRightCollapsedState] = import_react9.default.useState(defaultRightCollapsed);
3524
+ const [internalDisplayMode, setInternalDisplayMode] = import_react9.default.useState(displayMode ?? defaultDisplayMode);
3525
+ const [internalTab, setInternalTab] = import_react9.default.useState(
3397
3526
  tabs && tabs.length > 0 ? tabs[0].value : ""
3398
3527
  );
3399
3528
  const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
@@ -3401,10 +3530,10 @@ function FullscreenWorkspace({
3401
3530
  const isDisplayModeControlled = displayMode !== void 0;
3402
3531
  const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
3403
3532
  const isTabControlled = activeTab !== void 0 && activeTab !== null;
3404
- const resolvedTabs = import_react8.default.useMemo(() => tabs ?? [], [tabs]);
3533
+ const resolvedTabs = import_react9.default.useMemo(() => tabs ?? [], [tabs]);
3405
3534
  const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
3406
3535
  const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
3407
- import_react8.default.useEffect(() => {
3536
+ import_react9.default.useEffect(() => {
3408
3537
  if (resolvedTabs.length > 0) {
3409
3538
  const values = resolvedTabs.map((tab) => tab.value);
3410
3539
  if (!values.includes(currentTab)) {
@@ -3413,7 +3542,7 @@ function FullscreenWorkspace({
3413
3542
  }
3414
3543
  }
3415
3544
  }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
3416
- import_react8.default.useEffect(() => {
3545
+ import_react9.default.useEffect(() => {
3417
3546
  if (displayMode !== void 0) {
3418
3547
  setInternalDisplayMode(displayMode);
3419
3548
  }
@@ -3448,7 +3577,7 @@ function FullscreenWorkspace({
3448
3577
  const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
3449
3578
  const showLeftToggle = Boolean(leftPanel);
3450
3579
  const showRightToggle = Boolean(rightPanel);
3451
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3580
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3452
3581
  FullscreenContainer,
3453
3582
  {
3454
3583
  leftCollapsed,
@@ -3456,25 +3585,25 @@ function FullscreenWorkspace({
3456
3585
  className: `tff-svg-container ${className}`.trim(),
3457
3586
  ...rest,
3458
3587
  children: [
3459
- showLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3588
+ showLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3460
3589
  LeftToggleButton,
3461
3590
  {
3462
3591
  collapsed: leftCollapsed,
3463
3592
  onClick: handleLeftToggle,
3464
3593
  "aria-label": leftCollapsed ? "Expand left panel" : "Collapse left panel",
3465
- children: leftCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronRight, {}) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronLeft, {})
3594
+ children: leftCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRight, {}) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronLeft, {})
3466
3595
  }
3467
3596
  ),
3468
- showRightToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3597
+ showRightToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3469
3598
  RightToggleButton,
3470
3599
  {
3471
3600
  collapsed: rightCollapsed,
3472
3601
  onClick: handleRightToggle,
3473
3602
  "aria-label": rightCollapsed ? "Expand right panel" : "Collapse right panel",
3474
- children: rightCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronLeft, {}) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronRight, {})
3603
+ children: rightCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronLeft, {}) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRight, {})
3475
3604
  }
3476
3605
  ),
3477
- showDisplayModeToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3606
+ showDisplayModeToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3478
3607
  DisplayModeToggle,
3479
3608
  {
3480
3609
  mode: currentDisplayMode,
@@ -3483,9 +3612,9 @@ function FullscreenWorkspace({
3483
3612
  children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
3484
3613
  }
3485
3614
  ),
3486
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(SVGArea, { children: [
3487
- showZoomControls && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ZoomControls, { children: [
3488
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3615
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(SVGArea, { children: [
3616
+ showZoomControls && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(ZoomControls, { children: [
3617
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3489
3618
  ZoomButton,
3490
3619
  {
3491
3620
  onClick: onZoomIn,
@@ -3495,7 +3624,7 @@ function FullscreenWorkspace({
3495
3624
  children: "+"
3496
3625
  }
3497
3626
  ),
3498
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3627
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3499
3628
  ZoomButton,
3500
3629
  {
3501
3630
  onClick: onZoomOut,
@@ -3505,7 +3634,7 @@ function FullscreenWorkspace({
3505
3634
  children: "-"
3506
3635
  }
3507
3636
  ),
3508
- onResetZoom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3637
+ onResetZoom && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3509
3638
  ZoomButton,
3510
3639
  {
3511
3640
  onClick: onResetZoom,
@@ -3516,44 +3645,44 @@ function FullscreenWorkspace({
3516
3645
  }
3517
3646
  )
3518
3647
  ] }),
3519
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(FixedSVGContainer, { className: "svg-container", children: [
3648
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(FixedSVGContainer, { className: "svg-container", children: [
3520
3649
  svgContent,
3521
3650
  overlays
3522
3651
  ] }) })
3523
3652
  ] }),
3524
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3525
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3653
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3654
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3526
3655
  PanelTabs,
3527
3656
  {
3528
3657
  value: currentTab,
3529
3658
  onChange: handleTabChangeInternal,
3530
3659
  "aria-label": "Left panel tabs",
3531
- children: resolvedTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material3.Tab, { label: tab.label, value: tab.value }, tab.value))
3660
+ children: resolvedTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material3.Tab, { label: tab.label, value: tab.value }, tab.value))
3532
3661
  }
3533
3662
  ),
3534
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PanelContent, { children: currentTabContent })
3663
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PanelContent, { children: currentTabContent })
3535
3664
  ] }) : leftPanel }),
3536
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3537
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(FooterPanel, { children: footer })
3665
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3666
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(FooterPanel, { children: footer })
3538
3667
  ]
3539
3668
  }
3540
3669
  );
3541
3670
  }
3542
3671
 
3543
3672
  // src/theme/ThemeContext.tsx
3544
- var import_react9 = require("react");
3545
- var import_jsx_runtime14 = require("react/jsx-runtime");
3546
- var ThemeContext = (0, import_react9.createContext)(void 0);
3673
+ var import_react10 = require("react");
3674
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3675
+ var ThemeContext = (0, import_react10.createContext)(void 0);
3547
3676
  var useTheme = () => {
3548
- const context = (0, import_react9.useContext)(ThemeContext);
3677
+ const context = (0, import_react10.useContext)(ThemeContext);
3549
3678
  if (!context) {
3550
3679
  throw new Error("useTheme must be used within a ThemeProvider");
3551
3680
  }
3552
3681
  return context;
3553
3682
  };
3554
3683
  var ThemeProvider = ({ children }) => {
3555
- const [theme, setThemeState] = (0, import_react9.useState)("modern");
3556
- (0, import_react9.useEffect)(() => {
3684
+ const [theme, setThemeState] = (0, import_react10.useState)("modern");
3685
+ (0, import_react10.useEffect)(() => {
3557
3686
  document.body.className = "";
3558
3687
  document.body.classList.add(`theme-${theme}`);
3559
3688
  document.documentElement.className = "";
@@ -3565,11 +3694,11 @@ var ThemeProvider = ({ children }) => {
3565
3694
  const setTheme = (newTheme) => {
3566
3695
  setThemeState(newTheme);
3567
3696
  };
3568
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3697
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3569
3698
  };
3570
3699
 
3571
3700
  // src/theme/ThemeToggle.tsx
3572
- var import_jsx_runtime15 = require("react/jsx-runtime");
3701
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3573
3702
  var ThemeToggle = ({
3574
3703
  size = "medium",
3575
3704
  position = "top-right",
@@ -3640,18 +3769,18 @@ var ThemeToggle = ({
3640
3769
  transition: "all 0.2s ease",
3641
3770
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
3642
3771
  };
3643
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
3644
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
3645
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: toggleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: thumbStyle }) }),
3646
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
3772
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
3773
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
3774
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: toggleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: thumbStyle }) }),
3775
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
3647
3776
  ] });
3648
3777
  };
3649
3778
 
3650
3779
  // src/components/PIDCanvas/PIDCanvas.tsx
3651
- var import_react21 = __toESM(require("react"), 1);
3780
+ var import_react22 = __toESM(require("react"), 1);
3652
3781
 
3653
3782
  // src/components/PIDCanvas/NodeRenderer.tsx
3654
- var import_react10 = __toESM(require("react"), 1);
3783
+ var import_react11 = __toESM(require("react"), 1);
3655
3784
 
3656
3785
  // src/diagram/symbols/mockSymbolLibrary.ts
3657
3786
  var mockSymbolLibrary = {
@@ -5025,9 +5154,110 @@ function writeAppearanceValue(node, field, value) {
5025
5154
  return { metadata: { ...node.metadata, [field.key]: value } };
5026
5155
  }
5027
5156
 
5157
+ // src/diagram/badges/nodeBadgeGlyphs.ts
5158
+ var PROHIBIT_GLYPH = {
5159
+ id: "prohibit",
5160
+ svgContent: '<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2.4"/><line x1="5.6" y1="18.4" x2="18.4" y2="5.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/>'
5161
+ };
5162
+ var builtInBadgeGlyphs = {
5163
+ [PROHIBIT_GLYPH.id]: PROHIBIT_GLYPH
5164
+ };
5165
+ var customBadgeGlyphs = {};
5166
+ function registerBadgeGlyph(glyph) {
5167
+ customBadgeGlyphs[glyph.id] = glyph;
5168
+ }
5169
+ function registerBadgeGlyphs(glyphs) {
5170
+ if (Array.isArray(glyphs)) {
5171
+ glyphs.forEach((glyph) => registerBadgeGlyph(glyph));
5172
+ } else {
5173
+ Object.values(glyphs).forEach((glyph) => registerBadgeGlyph(glyph));
5174
+ }
5175
+ }
5176
+ function getBadgeGlyph(glyphId) {
5177
+ return customBadgeGlyphs[glyphId] ?? builtInBadgeGlyphs[glyphId];
5178
+ }
5179
+ function getAvailableBadgeGlyphs() {
5180
+ return [...Object.keys(customBadgeGlyphs), ...Object.keys(builtInBadgeGlyphs)];
5181
+ }
5182
+
5028
5183
  // src/components/PIDCanvas/NodeRenderer.tsx
5029
- var import_jsx_runtime16 = require("react/jsx-runtime");
5030
- var HATCH_SIZE = 6;
5184
+ var import_jsx_runtime17 = require("react/jsx-runtime");
5185
+ var HATCH_TILE_SIZE = 7;
5186
+ var HATCH_STRIPE_WIDTH = 2;
5187
+ var HATCH_STRIPE_ANGLE = 135;
5188
+ var HATCH_STRIPE_OPACITY = 85 / 255;
5189
+ function isUnknownNode(node) {
5190
+ return node.positionUnknown === true || normalizeDeviceStatus(node.status) === "unknown";
5191
+ }
5192
+ var DEFAULT_BADGE_CORNER = "top-right";
5193
+ var DEFAULT_BADGE_SIZE = 14;
5194
+ var DEFAULT_BADGE_COLOR = "#111827";
5195
+ var DEFAULT_BADGE_BACKGROUND = "#d1d5db";
5196
+ var BADGE_GLYPH_BOX = 24;
5197
+ var BADGE_BLINK_KEYFRAME_ID = "pid-node-badge-blink-keyframes";
5198
+ var BADGE_BLINK_KEYFRAME_NAME = "pid-node-badge-blink";
5199
+ function ensureBadgeBlinkKeyframes() {
5200
+ if (typeof document === "undefined") return;
5201
+ if (document.getElementById(BADGE_BLINK_KEYFRAME_ID)) return;
5202
+ const style = document.createElement("style");
5203
+ style.id = BADGE_BLINK_KEYFRAME_ID;
5204
+ style.textContent = `@keyframes ${BADGE_BLINK_KEYFRAME_NAME}{0%{opacity:1}50%{opacity:.15}100%{opacity:1}}`;
5205
+ document.head.appendChild(style);
5206
+ }
5207
+ function badgeCenter(corner, vb, size) {
5208
+ const margin = size / 4;
5209
+ switch (corner) {
5210
+ case "top-left":
5211
+ return { x: -margin, y: -margin };
5212
+ case "bottom-left":
5213
+ return { x: -margin, y: vb.height + margin };
5214
+ case "bottom-right":
5215
+ return { x: vb.width + margin, y: vb.height + margin };
5216
+ case "top-right":
5217
+ default:
5218
+ return { x: vb.width + margin, y: -margin };
5219
+ }
5220
+ }
5221
+ function renderNodeBadge(badge, vb, rotation) {
5222
+ const glyphDef = getBadgeGlyph(badge.glyph);
5223
+ const size = badge.size ?? DEFAULT_BADGE_SIZE;
5224
+ const color = badge.color ?? DEFAULT_BADGE_COLOR;
5225
+ const backgroundColor = badge.backgroundColor ?? DEFAULT_BADGE_BACKGROUND;
5226
+ const corner = badge.corner ?? DEFAULT_BADGE_CORNER;
5227
+ const { x: cx, y: cy } = badgeCenter(corner, vb, size);
5228
+ const radius = size / 2;
5229
+ const glyphScale = size / BADGE_GLYPH_BOX;
5230
+ let blinkStyle;
5231
+ if (badge.blink) {
5232
+ ensureBadgeBlinkKeyframes();
5233
+ blinkStyle = {
5234
+ animation: `${BADGE_BLINK_KEYFRAME_NAME} ${badge.blinkPeriodMs}ms ease-in-out infinite`
5235
+ };
5236
+ }
5237
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5238
+ "g",
5239
+ {
5240
+ "data-node-badge": badge.glyph,
5241
+ "data-badge-corner": corner,
5242
+ "data-badge-blink": badge.blink ? "true" : "false",
5243
+ "aria-label": badge.label,
5244
+ role: badge.label ? "img" : void 0,
5245
+ transform: rotation ? `translate(${cx}, ${cy}) rotate(${-rotation})` : `translate(${cx}, ${cy})`,
5246
+ style: blinkStyle,
5247
+ children: [
5248
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { r: radius, fill: backgroundColor }),
5249
+ glyphDef && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5250
+ "g",
5251
+ {
5252
+ color,
5253
+ transform: `scale(${glyphScale}) translate(${-BADGE_GLYPH_BOX / 2}, ${-BADGE_GLYPH_BOX / 2})`,
5254
+ dangerouslySetInnerHTML: { __html: glyphDef.svgContent }
5255
+ }
5256
+ )
5257
+ ]
5258
+ }
5259
+ );
5260
+ }
5031
5261
  function NodeRendererImpl({
5032
5262
  nodes: nodes2,
5033
5263
  selectedNodeIds,
@@ -5039,41 +5269,42 @@ function NodeRendererImpl({
5039
5269
  enableDrag = false,
5040
5270
  statusColorMap
5041
5271
  }) {
5042
- const hatchId = `pid-unknown-hatch-${import_react10.default.useId().replace(/[^A-Za-z0-9_-]/g, "")}`;
5043
- const hasUnknown = nodes2.some((n) => n.positionUnknown === true && n.visible !== false);
5044
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { id: "layer-nodes", children: [
5045
- hasUnknown && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5272
+ const hatchPatternId = `node-unknown-hatch-${import_react11.default.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
5273
+ const visibleNodes = nodes2.filter((node) => node.visible !== false);
5274
+ const hasUnknownNode = visibleNodes.some(isUnknownNode);
5275
+ const unknownEntry = resolveStatusColor("unknown", statusColorMap);
5276
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { id: "layer-nodes", children: [
5277
+ hasUnknownNode && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5046
5278
  "pattern",
5047
5279
  {
5048
- id: hatchId,
5049
- "data-testid": "position-unknown-pattern",
5280
+ id: hatchPatternId,
5281
+ "data-testid": "unknown-hatch-pattern",
5050
5282
  patternUnits: "userSpaceOnUse",
5051
- width: HATCH_SIZE,
5052
- height: HATCH_SIZE,
5053
- patternTransform: "rotate(45)",
5283
+ width: HATCH_TILE_SIZE,
5284
+ height: HATCH_TILE_SIZE,
5285
+ patternTransform: `rotate(${HATCH_STRIPE_ANGLE})`,
5054
5286
  children: [
5055
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { width: HATCH_SIZE, height: HATCH_SIZE, fill: UNKNOWN_MARK_COLOR.fill }),
5056
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5057
- "line",
5287
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("rect", { width: HATCH_TILE_SIZE, height: HATCH_TILE_SIZE, fill: unknownEntry.fill }),
5288
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5289
+ "rect",
5058
5290
  {
5059
- x1: "0",
5060
- y1: "0",
5061
- x2: "0",
5062
- y2: HATCH_SIZE,
5063
- stroke: UNKNOWN_MARK_COLOR.text,
5064
- strokeWidth: "2"
5291
+ x: HATCH_TILE_SIZE - HATCH_STRIPE_WIDTH,
5292
+ width: HATCH_STRIPE_WIDTH,
5293
+ height: HATCH_TILE_SIZE,
5294
+ fill: unknownEntry.stroke,
5295
+ fillOpacity: HATCH_STRIPE_OPACITY
5065
5296
  }
5066
5297
  )
5067
5298
  ]
5068
5299
  }
5069
5300
  ) }),
5070
- nodes2.filter((node) => node.visible !== false).map((node) => {
5301
+ visibleNodes.map((node) => {
5071
5302
  const symbol = getSymbolDefinition(node.symbolId);
5072
5303
  const isSelected = selectedNodeIds?.has(node.id) ?? false;
5073
5304
  const isDragging = draggingNodeId === node.id;
5074
5305
  if (!symbol) {
5075
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { children: [
5076
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5306
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { children: [
5307
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5077
5308
  "circle",
5078
5309
  {
5079
5310
  cx: node.transform.x,
@@ -5085,7 +5316,7 @@ function NodeRendererImpl({
5085
5316
  strokeWidth: "2"
5086
5317
  }
5087
5318
  ),
5088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5319
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5089
5320
  "text",
5090
5321
  {
5091
5322
  x: node.transform.x,
@@ -5125,9 +5356,9 @@ function NodeRendererImpl({
5125
5356
  );
5126
5357
  }
5127
5358
  const statusEntry = resolveStatusColor(node.status, statusColorMap);
5128
- const isUnknown = node.positionUnknown === true;
5129
- const fillColor = isUnknown ? `url(#${hatchId})` : node.customColors?.fill ?? statusEntry.fill;
5130
- const strokeColor = isUnknown ? UNKNOWN_MARK_COLOR.stroke : node.customColors?.stroke ?? statusEntry.stroke;
5359
+ const isUnknown = isUnknownNode(node);
5360
+ const fillColor = isUnknown ? `url(#${hatchPatternId})` : node.customColors?.fill ?? statusEntry.fill;
5361
+ const strokeColor = isUnknown ? unknownEntry.stroke : node.customColors?.stroke ?? statusEntry.stroke;
5131
5362
  const appearance = { ...getAppearanceDefaults(node.symbolId), ...node.metadata ?? {} };
5132
5363
  const ledStyle = {};
5133
5364
  if (appearance.shape !== void 0) {
@@ -5138,7 +5369,8 @@ function NodeRendererImpl({
5138
5369
  ledStyle["--led-bezel"] = appearance.led ? "2" : "0";
5139
5370
  }
5140
5371
  if (appearance.glow) {
5141
- ledStyle.filter = `drop-shadow(0 0 4px ${fillColor})`;
5372
+ const glowColor = isUnknown ? unknownEntry.stroke : fillColor;
5373
+ ledStyle.filter = `drop-shadow(0 0 4px ${glowColor})`;
5142
5374
  }
5143
5375
  const ledAnimation = typeof appearance.animation === "string" && appearance.animation !== "none" ? appearance.animation : void 0;
5144
5376
  const vb = symbol.viewBox;
@@ -5161,7 +5393,7 @@ function NodeRendererImpl({
5161
5393
  labelY = vb.height / 2 + oy;
5162
5394
  labelAnchor = "start";
5163
5395
  }
5164
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5396
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5165
5397
  "g",
5166
5398
  {
5167
5399
  "data-node-id": node.id,
@@ -5169,7 +5401,7 @@ function NodeRendererImpl({
5169
5401
  "data-selected": isSelected,
5170
5402
  "data-dragging": isDragging,
5171
5403
  "data-led-animation": ledAnimation,
5172
- "data-position-unknown": isUnknown ? "true" : void 0,
5404
+ "data-position-unknown": node.positionUnknown === true ? "true" : void 0,
5173
5405
  transform: transforms.join(" "),
5174
5406
  style: {
5175
5407
  "--symbol-fill": fillColor,
@@ -5197,7 +5429,7 @@ function NodeRendererImpl({
5197
5429
  }
5198
5430
  },
5199
5431
  children: [
5200
- isSelected && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5432
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5201
5433
  "rect",
5202
5434
  {
5203
5435
  x: "-5",
@@ -5212,7 +5444,7 @@ function NodeRendererImpl({
5212
5444
  pointerEvents: "none"
5213
5445
  }
5214
5446
  ),
5215
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5447
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5216
5448
  "g",
5217
5449
  {
5218
5450
  dangerouslySetInnerHTML: { __html: symbol.svgContent },
@@ -5220,7 +5452,7 @@ function NodeRendererImpl({
5220
5452
  style: { pointerEvents: "auto" }
5221
5453
  }
5222
5454
  ),
5223
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5455
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5224
5456
  "text",
5225
5457
  {
5226
5458
  x: labelX,
@@ -5232,7 +5464,8 @@ function NodeRendererImpl({
5232
5464
  transform: node.transform.rotation ? `rotate(${-node.transform.rotation}, ${labelX}, ${labelY})` : void 0,
5233
5465
  children: node.label || node.id
5234
5466
  }
5235
- )
5467
+ ),
5468
+ node.badge && renderNodeBadge(node.badge, vb, node.transform.rotation)
5236
5469
  ]
5237
5470
  },
5238
5471
  node.id
@@ -5240,11 +5473,11 @@ function NodeRendererImpl({
5240
5473
  })
5241
5474
  ] });
5242
5475
  }
5243
- var NodeRenderer = import_react10.default.memo(NodeRendererImpl);
5476
+ var NodeRenderer = import_react11.default.memo(NodeRendererImpl);
5244
5477
 
5245
5478
  // src/components/PIDCanvas/PipeRenderer.tsx
5246
- var import_react11 = __toESM(require("react"), 1);
5247
- var import_jsx_runtime17 = require("react/jsx-runtime");
5479
+ var import_react12 = __toESM(require("react"), 1);
5480
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5248
5481
  function PipeRendererImpl({
5249
5482
  pipes,
5250
5483
  selectedPipeIds,
@@ -5259,7 +5492,7 @@ function PipeRendererImpl({
5259
5492
  waypointDragOffset,
5260
5493
  onPipeSegmentClick
5261
5494
  }) {
5262
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5495
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5263
5496
  const isSelected = selectedPipeIds?.has(pipe.id) ?? false;
5264
5497
  const isEditing = enableWaypointEditing && editingPipeId === pipe.id;
5265
5498
  const showEditingControls = enableWaypointEditing && isSelected;
@@ -5278,7 +5511,7 @@ function PipeRendererImpl({
5278
5511
  const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
5279
5512
  const strokeDasharray = pipeStyle.strokeDasharray;
5280
5513
  const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
5281
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5514
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5282
5515
  "g",
5283
5516
  {
5284
5517
  "data-pipe-id": pipe.id,
@@ -5291,8 +5524,8 @@ function PipeRendererImpl({
5291
5524
  cursor: onPipeClick ? "pointer" : "default"
5292
5525
  },
5293
5526
  children: [
5294
- !enableWaypointEditing && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
5295
- onPipeClick && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5527
+ !enableWaypointEditing && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
5528
+ onPipeClick && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5296
5529
  "polyline",
5297
5530
  {
5298
5531
  points: pointsString,
@@ -5304,7 +5537,7 @@ function PipeRendererImpl({
5304
5537
  pointerEvents: "stroke"
5305
5538
  }
5306
5539
  ),
5307
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5308
5541
  "polyline",
5309
5542
  {
5310
5543
  points: pointsString,
@@ -5328,7 +5561,7 @@ function PipeRendererImpl({
5328
5561
  const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
5329
5562
  const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
5330
5563
  const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
5331
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5564
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5332
5565
  "circle",
5333
5566
  {
5334
5567
  cx: point.x,
@@ -5365,12 +5598,12 @@ function PipeRendererImpl({
5365
5598
  `${pipe.id}-point-${idx}`
5366
5599
  );
5367
5600
  }),
5368
- showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: displayPoints.slice(0, -1).map((point, idx) => {
5601
+ showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: displayPoints.slice(0, -1).map((point, idx) => {
5369
5602
  const nextPoint = displayPoints[idx + 1];
5370
5603
  const midX = (point.x + nextPoint.x) / 2;
5371
5604
  const midY = (point.y + nextPoint.y) / 2;
5372
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { children: [
5373
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5605
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
5606
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5374
5607
  "circle",
5375
5608
  {
5376
5609
  cx: midX,
@@ -5386,7 +5619,7 @@ function PipeRendererImpl({
5386
5619
  }
5387
5620
  }
5388
5621
  ),
5389
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5622
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5390
5623
  "circle",
5391
5624
  {
5392
5625
  cx: midX,
@@ -5402,7 +5635,7 @@ function PipeRendererImpl({
5402
5635
  )
5403
5636
  ] }, `${pipe.id}-segment-${idx}`);
5404
5637
  }) }),
5405
- pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5638
+ pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5406
5639
  "text",
5407
5640
  {
5408
5641
  x: pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x + (pipe.labelOffset?.x ?? 0),
@@ -5422,11 +5655,11 @@ function PipeRendererImpl({
5422
5655
  );
5423
5656
  }) });
5424
5657
  }
5425
- var PipeRenderer = import_react11.default.memo(PipeRendererImpl);
5658
+ var PipeRenderer = import_react12.default.memo(PipeRendererImpl);
5426
5659
 
5427
5660
  // src/components/PIDCanvas/DataOverlay.tsx
5428
- var import_react12 = __toESM(require("react"), 1);
5429
- var import_jsx_runtime18 = require("react/jsx-runtime");
5661
+ var import_react13 = __toESM(require("react"), 1);
5662
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5430
5663
  var PULSE_KEYFRAME_ID = "pid-data-overlay-pulse-keyframes";
5431
5664
  var PULSE_ANIMATION = "pid-data-overlay-pulse 1.5s ease-in-out infinite";
5432
5665
  function ensurePulseKeyframes() {
@@ -5437,9 +5670,10 @@ function ensurePulseKeyframes() {
5437
5670
  style.textContent = "@keyframes pid-data-overlay-pulse{0%{opacity:.9}50%{opacity:.3}100%{opacity:.9}}";
5438
5671
  document.head.appendChild(style);
5439
5672
  }
5440
- function renderStatusDot(cx, cy, scale, fill) {
5441
- ensurePulseKeyframes();
5442
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5673
+ function renderStatusDot(cx, cy, scale, fill, status) {
5674
+ const isUnknown = normalizeDeviceStatus(status) === "unknown";
5675
+ if (!isUnknown) ensurePulseKeyframes();
5676
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5443
5677
  "circle",
5444
5678
  {
5445
5679
  className: "pid-data-overlay-status-dot",
@@ -5447,7 +5681,7 @@ function renderStatusDot(cx, cy, scale, fill) {
5447
5681
  cy: cy - 18 * scale,
5448
5682
  r: 3 * scale,
5449
5683
  fill,
5450
- style: { animation: PULSE_ANIMATION }
5684
+ style: isUnknown ? void 0 : { animation: PULSE_ANIMATION }
5451
5685
  }
5452
5686
  );
5453
5687
  }
@@ -5473,7 +5707,7 @@ function DataOverlayImpl({
5473
5707
  const backgroundColor = display?.backgroundColor;
5474
5708
  const offsetX = display?.offsetX ?? 0;
5475
5709
  const offsetY = display?.offsetY ?? 0;
5476
- const sparklinePath = import_react12.default.useMemo(() => {
5710
+ const sparklinePath = import_react13.default.useMemo(() => {
5477
5711
  if (!showSparkline || !history || history.length < 2) return "";
5478
5712
  const width = 70 * scale;
5479
5713
  const height = 20 * scale;
@@ -5492,7 +5726,7 @@ function DataOverlayImpl({
5492
5726
  return `M ${points.join(" L ")}`;
5493
5727
  }, [showSparkline, history, scaling, scale]);
5494
5728
  if (!showValue) {
5495
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, {});
5729
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, {});
5496
5730
  }
5497
5731
  const formatValue = (val) => {
5498
5732
  if (typeof val === "number") {
@@ -5517,10 +5751,11 @@ function DataOverlayImpl({
5517
5751
  const extraMarkRows = realDisplayText ? 1 : 0;
5518
5752
  const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale + extraMarkRows * 9 * scale;
5519
5753
  const overlayWidth = 80 * scale;
5754
+ const isUnknownValue = normalizeDeviceStatus(value.status) === "unknown";
5520
5755
  const displayX = x + offsetX;
5521
5756
  const displayY = y + offsetY;
5522
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
5523
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5757
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
5758
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5524
5759
  "rect",
5525
5760
  {
5526
5761
  x: displayX - overlayWidth / 2,
@@ -5535,7 +5770,7 @@ function DataOverlayImpl({
5535
5770
  filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
5536
5771
  }
5537
5772
  ),
5538
- label && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5773
+ label && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5539
5774
  "text",
5540
5775
  {
5541
5776
  x: displayX,
@@ -5548,7 +5783,7 @@ function DataOverlayImpl({
5548
5783
  children: label
5549
5784
  }
5550
5785
  ),
5551
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5786
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5552
5787
  "text",
5553
5788
  {
5554
5789
  x: displayX,
@@ -5561,8 +5796,17 @@ function DataOverlayImpl({
5561
5796
  children: displayText
5562
5797
  }
5563
5798
  ),
5564
- showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor),
5565
- value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5799
+ showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor, value.status),
5800
+ showStatus && isUnknownValue && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5801
+ UnknownStatusGlyph,
5802
+ {
5803
+ x: displayX - overlayWidth / 2 + 2 * scale,
5804
+ y: displayY - 25 * scale - 6 * scale,
5805
+ width: 12 * scale,
5806
+ height: 12 * scale
5807
+ }
5808
+ ),
5809
+ value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5566
5810
  "text",
5567
5811
  {
5568
5812
  x: displayX,
@@ -5579,13 +5823,13 @@ function DataOverlayImpl({
5579
5823
  ]
5580
5824
  }
5581
5825
  ),
5582
- isForced && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5826
+ isForced && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5583
5827
  "g",
5584
5828
  {
5585
5829
  transform: `translate(${displayX + overlayWidth / 2}, ${displayY - 25 * scale})`,
5586
5830
  "aria-label": "Forced",
5587
5831
  children: [
5588
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5832
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5589
5833
  "circle",
5590
5834
  {
5591
5835
  r: 7 * scale,
@@ -5594,7 +5838,7 @@ function DataOverlayImpl({
5594
5838
  strokeWidth: 1.5 * scale
5595
5839
  }
5596
5840
  ),
5597
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5841
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5598
5842
  "text",
5599
5843
  {
5600
5844
  textAnchor: "middle",
@@ -5608,7 +5852,7 @@ function DataOverlayImpl({
5608
5852
  ]
5609
5853
  }
5610
5854
  ),
5611
- realDisplayText && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5855
+ realDisplayText && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5612
5856
  "text",
5613
5857
  {
5614
5858
  x: displayX,
@@ -5621,7 +5865,7 @@ function DataOverlayImpl({
5621
5865
  children: realDisplayText
5622
5866
  }
5623
5867
  ),
5624
- hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5868
+ hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5625
5869
  "path",
5626
5870
  {
5627
5871
  d: sparklinePath,
@@ -5635,11 +5879,11 @@ function DataOverlayImpl({
5635
5879
  ) })
5636
5880
  ] });
5637
5881
  }
5638
- var DataOverlay = import_react12.default.memo(DataOverlayImpl);
5882
+ var DataOverlay = import_react13.default.memo(DataOverlayImpl);
5639
5883
 
5640
5884
  // src/components/PIDCanvas/PositionPanel.tsx
5641
- var import_react13 = require("react");
5642
- var import_jsx_runtime19 = require("react/jsx-runtime");
5885
+ var import_react14 = require("react");
5886
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5643
5887
  function PositionPanel({
5644
5888
  selectedNode,
5645
5889
  selectedWaypoint,
@@ -5647,9 +5891,9 @@ function PositionPanel({
5647
5891
  onWaypointPositionChange,
5648
5892
  position = "top-right"
5649
5893
  }) {
5650
- const [x, setX] = (0, import_react13.useState)("");
5651
- const [y, setY] = (0, import_react13.useState)("");
5652
- (0, import_react13.useEffect)(() => {
5894
+ const [x, setX] = (0, import_react14.useState)("");
5895
+ const [y, setY] = (0, import_react14.useState)("");
5896
+ (0, import_react14.useEffect)(() => {
5653
5897
  if (selectedNode) {
5654
5898
  setX(selectedNode.transform.x.toFixed(2));
5655
5899
  setY(selectedNode.transform.y.toFixed(2));
@@ -5708,7 +5952,7 @@ function PositionPanel({
5708
5952
  "bottom-left": { bottom: 10, left: 10 },
5709
5953
  "bottom-right": { bottom: 10, right: 10 }
5710
5954
  };
5711
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5955
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5712
5956
  "div",
5713
5957
  {
5714
5958
  style: {
@@ -5725,11 +5969,11 @@ function PositionPanel({
5725
5969
  fontSize: "13px"
5726
5970
  },
5727
5971
  children: [
5728
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
5729
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
5730
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5731
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
5732
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5972
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
5973
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
5974
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5975
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
5976
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5733
5977
  "input",
5734
5978
  {
5735
5979
  type: "number",
@@ -5747,9 +5991,9 @@ function PositionPanel({
5747
5991
  }
5748
5992
  )
5749
5993
  ] }),
5750
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5751
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
5752
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5994
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5995
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
5996
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5753
5997
  "input",
5754
5998
  {
5755
5999
  type: "number",
@@ -5768,14 +6012,14 @@ function PositionPanel({
5768
6012
  )
5769
6013
  ] })
5770
6014
  ] }),
5771
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
6015
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
5772
6016
  ]
5773
6017
  }
5774
6018
  );
5775
6019
  }
5776
6020
 
5777
6021
  // src/diagram/hooks/useViewBox.ts
5778
- var import_react14 = require("react");
6022
+ var import_react15 = require("react");
5779
6023
  function useViewBox(options) {
5780
6024
  const {
5781
6025
  initialViewBox,
@@ -5786,16 +6030,16 @@ function useViewBox(options) {
5786
6030
  zoomSensitivity = 1e-3,
5787
6031
  allowLeftClickPan = true
5788
6032
  } = options;
5789
- const [viewBox, setViewBox] = (0, import_react14.useState)(initialViewBox);
5790
- const svgRef = (0, import_react14.useRef)(null);
5791
- const isPanningRef = (0, import_react14.useRef)(false);
5792
- const lastMousePosRef = (0, import_react14.useRef)({ x: 0, y: 0 });
5793
- const spaceKeyDownRef = (0, import_react14.useRef)(false);
5794
- const lastTouchDistanceRef = (0, import_react14.useRef)(null);
5795
- const resetViewBox = (0, import_react14.useCallback)(() => {
6033
+ const [viewBox, setViewBox] = (0, import_react15.useState)(initialViewBox);
6034
+ const svgRef = (0, import_react15.useRef)(null);
6035
+ const isPanningRef = (0, import_react15.useRef)(false);
6036
+ const lastMousePosRef = (0, import_react15.useRef)({ x: 0, y: 0 });
6037
+ const spaceKeyDownRef = (0, import_react15.useRef)(false);
6038
+ const lastTouchDistanceRef = (0, import_react15.useRef)(null);
6039
+ const resetViewBox = (0, import_react15.useCallback)(() => {
5796
6040
  setViewBox(initialViewBox);
5797
6041
  }, [initialViewBox]);
5798
- const zoomIn = (0, import_react14.useCallback)(() => {
6042
+ const zoomIn = (0, import_react15.useCallback)(() => {
5799
6043
  setViewBox((prev) => {
5800
6044
  const currentZoom = initialViewBox.width / prev.width;
5801
6045
  const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);
@@ -5812,7 +6056,7 @@ function useViewBox(options) {
5812
6056
  };
5813
6057
  });
5814
6058
  }, [initialViewBox, minZoom]);
5815
- const zoomOut = (0, import_react14.useCallback)(() => {
6059
+ const zoomOut = (0, import_react15.useCallback)(() => {
5816
6060
  setViewBox((prev) => {
5817
6061
  const currentZoom = initialViewBox.width / prev.width;
5818
6062
  const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);
@@ -5829,7 +6073,7 @@ function useViewBox(options) {
5829
6073
  };
5830
6074
  });
5831
6075
  }, [initialViewBox, maxZoom]);
5832
- const fitToContent = (0, import_react14.useCallback)((bounds, padding = 50) => {
6076
+ const fitToContent = (0, import_react15.useCallback)((bounds, padding = 50) => {
5833
6077
  const contentWidth = bounds.maxX - bounds.minX;
5834
6078
  const contentHeight = bounds.maxY - bounds.minY;
5835
6079
  if (contentWidth === 0 || contentHeight === 0) {
@@ -5857,7 +6101,7 @@ function useViewBox(options) {
5857
6101
  height: newHeight
5858
6102
  });
5859
6103
  }, [initialViewBox]);
5860
- (0, import_react14.useEffect)(() => {
6104
+ (0, import_react15.useEffect)(() => {
5861
6105
  if (!enableZoom || !svgRef.current) return;
5862
6106
  const svg = svgRef.current;
5863
6107
  const handleWheel = (e) => {
@@ -5890,7 +6134,7 @@ function useViewBox(options) {
5890
6134
  svg.addEventListener("wheel", handleWheel, { passive: false });
5891
6135
  return () => svg.removeEventListener("wheel", handleWheel);
5892
6136
  }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
5893
- (0, import_react14.useEffect)(() => {
6137
+ (0, import_react15.useEffect)(() => {
5894
6138
  if (!enablePan || !svgRef.current) return;
5895
6139
  const svg = svgRef.current;
5896
6140
  const handleMouseDown = (e) => {
@@ -5966,7 +6210,7 @@ function useViewBox(options) {
5966
6210
  window.removeEventListener("keyup", handleKeyUp);
5967
6211
  };
5968
6212
  }, [enablePan, allowLeftClickPan]);
5969
- (0, import_react14.useEffect)(() => {
6213
+ (0, import_react15.useEffect)(() => {
5970
6214
  if (!svgRef.current) return;
5971
6215
  if (!enablePan && !enableZoom) return;
5972
6216
  const svg = svgRef.current;
@@ -6057,7 +6301,7 @@ function useViewBox(options) {
6057
6301
  svg.removeEventListener("touchend", handleTouchEnd);
6058
6302
  };
6059
6303
  }, [enablePan, enableZoom, minZoom, initialViewBox]);
6060
- const screenToWorld = (0, import_react14.useCallback)(
6304
+ const screenToWorld = (0, import_react15.useCallback)(
6061
6305
  (screenX, screenY) => {
6062
6306
  const svg = svgRef.current;
6063
6307
  if (!svg) return { x: screenX, y: screenY };
@@ -6096,15 +6340,15 @@ function useViewBox(options) {
6096
6340
  }
6097
6341
 
6098
6342
  // src/diagram/hooks/useSelection.ts
6099
- var import_react15 = require("react");
6343
+ var import_react16 = require("react");
6100
6344
  function useSelection(options = {}) {
6101
6345
  const {
6102
6346
  multiSelect = true,
6103
6347
  initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
6104
6348
  onSelectionChange
6105
6349
  } = options;
6106
- const [selection, setSelection] = (0, import_react15.useState)(initialSelection);
6107
- const notifyChange = (0, import_react15.useCallback)(
6350
+ const [selection, setSelection] = (0, import_react16.useState)(initialSelection);
6351
+ const notifyChange = (0, import_react16.useCallback)(
6108
6352
  (newSelection) => {
6109
6353
  if (onSelectionChange) {
6110
6354
  onSelectionChange(newSelection);
@@ -6112,15 +6356,15 @@ function useSelection(options = {}) {
6112
6356
  },
6113
6357
  [onSelectionChange]
6114
6358
  );
6115
- const isNodeSelected = (0, import_react15.useCallback)(
6359
+ const isNodeSelected = (0, import_react16.useCallback)(
6116
6360
  (nodeId) => selection.selectedNodeIds.has(nodeId),
6117
6361
  [selection.selectedNodeIds]
6118
6362
  );
6119
- const isPipeSelected = (0, import_react15.useCallback)(
6363
+ const isPipeSelected = (0, import_react16.useCallback)(
6120
6364
  (pipeId) => selection.selectedPipeIds.has(pipeId),
6121
6365
  [selection.selectedPipeIds]
6122
6366
  );
6123
- const selectNode = (0, import_react15.useCallback)(
6367
+ const selectNode = (0, import_react16.useCallback)(
6124
6368
  (nodeId, isMultiSelect = false) => {
6125
6369
  setSelection((prev) => {
6126
6370
  const newNodeIds = new Set(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);
@@ -6139,7 +6383,7 @@ function useSelection(options = {}) {
6139
6383
  },
6140
6384
  [multiSelect, notifyChange]
6141
6385
  );
6142
- const selectPipe = (0, import_react15.useCallback)(
6386
+ const selectPipe = (0, import_react16.useCallback)(
6143
6387
  (pipeId, isMultiSelect = false) => {
6144
6388
  setSelection((prev) => {
6145
6389
  const newPipeIds = new Set(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);
@@ -6158,7 +6402,7 @@ function useSelection(options = {}) {
6158
6402
  },
6159
6403
  [multiSelect, notifyChange]
6160
6404
  );
6161
- const clearSelection = (0, import_react15.useCallback)(() => {
6405
+ const clearSelection = (0, import_react16.useCallback)(() => {
6162
6406
  const newSelection = {
6163
6407
  selectedNodeIds: /* @__PURE__ */ new Set(),
6164
6408
  selectedPipeIds: /* @__PURE__ */ new Set()
@@ -6166,7 +6410,7 @@ function useSelection(options = {}) {
6166
6410
  setSelection(newSelection);
6167
6411
  notifyChange(newSelection);
6168
6412
  }, [notifyChange]);
6169
- const selectNodes = (0, import_react15.useCallback)(
6413
+ const selectNodes = (0, import_react16.useCallback)(
6170
6414
  (nodeIds) => {
6171
6415
  const newSelection = {
6172
6416
  selectedNodeIds: new Set(nodeIds),
@@ -6177,7 +6421,7 @@ function useSelection(options = {}) {
6177
6421
  },
6178
6422
  [notifyChange]
6179
6423
  );
6180
- const selectPipes = (0, import_react15.useCallback)(
6424
+ const selectPipes = (0, import_react16.useCallback)(
6181
6425
  (pipeIds) => {
6182
6426
  const newSelection = {
6183
6427
  selectedNodeIds: /* @__PURE__ */ new Set(),
@@ -6201,23 +6445,23 @@ function useSelection(options = {}) {
6201
6445
  }
6202
6446
 
6203
6447
  // src/diagram/hooks/useTelemetry.ts
6204
- var import_react16 = require("react");
6448
+ var import_react17 = require("react");
6205
6449
  function useTelemetry(options = {}) {
6206
6450
  const {
6207
6451
  initialBindings = [],
6208
6452
  onTelemetryChange,
6209
6453
  refreshInterval = 0
6210
6454
  } = options;
6211
- const [telemetry, setTelemetry] = (0, import_react16.useState)(() => {
6455
+ const [telemetry, setTelemetry] = (0, import_react17.useState)(() => {
6212
6456
  const map = /* @__PURE__ */ new Map();
6213
6457
  initialBindings.forEach((binding) => {
6214
6458
  map.set(binding.nodeId, binding);
6215
6459
  });
6216
6460
  return map;
6217
6461
  });
6218
- const telemetryRef = (0, import_react16.useRef)(telemetry);
6462
+ const telemetryRef = (0, import_react17.useRef)(telemetry);
6219
6463
  telemetryRef.current = telemetry;
6220
- const notifyChange = (0, import_react16.useCallback)(
6464
+ const notifyChange = (0, import_react17.useCallback)(
6221
6465
  (newTelemetry) => {
6222
6466
  if (onTelemetryChange) {
6223
6467
  onTelemetryChange(newTelemetry);
@@ -6225,7 +6469,7 @@ function useTelemetry(options = {}) {
6225
6469
  },
6226
6470
  [onTelemetryChange]
6227
6471
  );
6228
- const updateTelemetry = (0, import_react16.useCallback)(
6472
+ const updateTelemetry = (0, import_react17.useCallback)(
6229
6473
  (nodeId, value) => {
6230
6474
  setTelemetry((prev) => {
6231
6475
  const newMap = new Map(prev);
@@ -6255,7 +6499,7 @@ function useTelemetry(options = {}) {
6255
6499
  },
6256
6500
  [notifyChange]
6257
6501
  );
6258
- const updateTelemetryBatch = (0, import_react16.useCallback)(
6502
+ const updateTelemetryBatch = (0, import_react17.useCallback)(
6259
6503
  (updates) => {
6260
6504
  setTelemetry((prev) => {
6261
6505
  const newMap = new Map(prev);
@@ -6309,16 +6553,16 @@ function useTelemetry(options = {}) {
6309
6553
  },
6310
6554
  [notifyChange]
6311
6555
  );
6312
- const getTelemetry = (0, import_react16.useCallback)(
6556
+ const getTelemetry = (0, import_react17.useCallback)(
6313
6557
  (nodeId) => telemetryRef.current.get(nodeId),
6314
6558
  []
6315
6559
  );
6316
- const clearTelemetry = (0, import_react16.useCallback)(() => {
6560
+ const clearTelemetry = (0, import_react17.useCallback)(() => {
6317
6561
  const newMap = /* @__PURE__ */ new Map();
6318
6562
  setTelemetry(newMap);
6319
6563
  notifyChange(newMap);
6320
6564
  }, [notifyChange]);
6321
- const setBindings = (0, import_react16.useCallback)(
6565
+ const setBindings = (0, import_react17.useCallback)(
6322
6566
  (bindings) => {
6323
6567
  const newMap = /* @__PURE__ */ new Map();
6324
6568
  bindings.forEach((binding) => {
@@ -6329,7 +6573,7 @@ function useTelemetry(options = {}) {
6329
6573
  },
6330
6574
  [notifyChange]
6331
6575
  );
6332
- (0, import_react16.useEffect)(() => {
6576
+ (0, import_react17.useEffect)(() => {
6333
6577
  if (refreshInterval <= 0) return;
6334
6578
  const intervalId = setInterval(() => {
6335
6579
  notifyChange(telemetryRef.current);
@@ -6347,10 +6591,10 @@ function useTelemetry(options = {}) {
6347
6591
  }
6348
6592
 
6349
6593
  // src/diagram/hooks/useTelemetryStatus.ts
6350
- var import_react17 = require("react");
6594
+ var import_react18 = require("react");
6351
6595
  function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6352
6596
  const { enabled = true, mapStatus } = options;
6353
- (0, import_react17.useEffect)(() => {
6597
+ (0, import_react18.useEffect)(() => {
6354
6598
  if (!enabled) return;
6355
6599
  const defaultMapStatus = (telemetryStatus) => {
6356
6600
  switch (telemetryStatus) {
@@ -6363,8 +6607,13 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6363
6607
  return "alarm";
6364
6608
  case "off":
6365
6609
  return "stopped";
6366
- default:
6610
+ case "unknown":
6611
+ return "unknown";
6612
+ default: {
6613
+ const exhaustive = telemetryStatus;
6614
+ void exhaustive;
6367
6615
  return "stopped";
6616
+ }
6368
6617
  }
6369
6618
  };
6370
6619
  const statusMapper = mapStatus || defaultMapStatus;
@@ -6389,10 +6638,10 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6389
6638
  }
6390
6639
 
6391
6640
  // src/diagram/hooks/useBooleanIndicators.ts
6392
- var import_react18 = require("react");
6641
+ var import_react19 = require("react");
6393
6642
  function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
6394
6643
  const { enabled = true, symbolId = "status-indicator" } = options;
6395
- (0, import_react18.useEffect)(() => {
6644
+ (0, import_react19.useEffect)(() => {
6396
6645
  if (!enabled) return;
6397
6646
  const tagIndex = /* @__PURE__ */ new Map();
6398
6647
  telemetry.forEach((binding) => {
@@ -6430,7 +6679,7 @@ function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
6430
6679
  }
6431
6680
 
6432
6681
  // src/diagram/hooks/useDrag.ts
6433
- var import_react19 = require("react");
6682
+ var import_react20 = require("react");
6434
6683
  function useDrag(options = {}) {
6435
6684
  const {
6436
6685
  onDragStart,
@@ -6440,23 +6689,23 @@ function useDrag(options = {}) {
6440
6689
  dragThreshold = 3,
6441
6690
  screenToWorld = (x, y) => ({ x, y })
6442
6691
  } = options;
6443
- const [dragState, setDragState] = (0, import_react19.useState)({
6692
+ const [dragState, setDragState] = (0, import_react20.useState)({
6444
6693
  isDragging: false,
6445
6694
  startPosition: null,
6446
6695
  offset: { x: 0, y: 0 },
6447
6696
  draggedId: null
6448
6697
  });
6449
- const [isListening, setIsListening] = (0, import_react19.useState)(false);
6450
- const dragStartRef = (0, import_react19.useRef)(null);
6451
- const hasMovedRef = (0, import_react19.useRef)(false);
6452
- const applySnap = (0, import_react19.useCallback)(
6698
+ const [isListening, setIsListening] = (0, import_react20.useState)(false);
6699
+ const dragStartRef = (0, import_react20.useRef)(null);
6700
+ const hasMovedRef = (0, import_react20.useRef)(false);
6701
+ const applySnap = (0, import_react20.useCallback)(
6453
6702
  (value) => {
6454
6703
  if (snapToGrid <= 0) return value;
6455
6704
  return Math.round(value / snapToGrid) * snapToGrid;
6456
6705
  },
6457
6706
  [snapToGrid]
6458
6707
  );
6459
- const handleMouseMove = (0, import_react19.useCallback)(
6708
+ const handleMouseMove = (0, import_react20.useCallback)(
6460
6709
  (event) => {
6461
6710
  if (!dragStartRef.current) return;
6462
6711
  const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;
@@ -6497,7 +6746,7 @@ function useDrag(options = {}) {
6497
6746
  },
6498
6747
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
6499
6748
  );
6500
- const handleMouseUp = (0, import_react19.useCallback)(
6749
+ const handleMouseUp = (0, import_react20.useCallback)(
6501
6750
  (event) => {
6502
6751
  if (!dragStartRef.current || !hasMovedRef.current) {
6503
6752
  dragStartRef.current = null;
@@ -6534,7 +6783,7 @@ function useDrag(options = {}) {
6534
6783
  },
6535
6784
  [screenToWorld, applySnap, onDragEnd]
6536
6785
  );
6537
- const handleTouchMove = (0, import_react19.useCallback)(
6786
+ const handleTouchMove = (0, import_react20.useCallback)(
6538
6787
  (event) => {
6539
6788
  if (!dragStartRef.current || event.touches.length !== 1) return;
6540
6789
  const touch = event.touches[0];
@@ -6577,7 +6826,7 @@ function useDrag(options = {}) {
6577
6826
  },
6578
6827
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
6579
6828
  );
6580
- const handleTouchEnd = (0, import_react19.useCallback)(
6829
+ const handleTouchEnd = (0, import_react20.useCallback)(
6581
6830
  (event) => {
6582
6831
  if (!dragStartRef.current || !hasMovedRef.current) {
6583
6832
  dragStartRef.current = null;
@@ -6615,7 +6864,7 @@ function useDrag(options = {}) {
6615
6864
  },
6616
6865
  [screenToWorld, applySnap, onDragEnd]
6617
6866
  );
6618
- (0, import_react19.useEffect)(() => {
6867
+ (0, import_react20.useEffect)(() => {
6619
6868
  if (!isListening) return;
6620
6869
  document.addEventListener("mousemove", handleMouseMove);
6621
6870
  document.addEventListener("mouseup", handleMouseUp);
@@ -6630,7 +6879,7 @@ function useDrag(options = {}) {
6630
6879
  document.removeEventListener("touchcancel", handleTouchEnd);
6631
6880
  };
6632
6881
  }, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
6633
- const startDrag = (0, import_react19.useCallback)(
6882
+ const startDrag = (0, import_react20.useCallback)(
6634
6883
  (id, event, itemPosition) => {
6635
6884
  event.stopPropagation();
6636
6885
  let clientX;
@@ -6660,7 +6909,7 @@ function useDrag(options = {}) {
6660
6909
  },
6661
6910
  [screenToWorld]
6662
6911
  );
6663
- const cancelDrag = (0, import_react19.useCallback)(() => {
6912
+ const cancelDrag = (0, import_react20.useCallback)(() => {
6664
6913
  dragStartRef.current = null;
6665
6914
  hasMovedRef.current = false;
6666
6915
  setIsListening(false);
@@ -6671,7 +6920,7 @@ function useDrag(options = {}) {
6671
6920
  draggedId: null
6672
6921
  });
6673
6922
  }, []);
6674
- const isDraggingItem = (0, import_react19.useCallback)(
6923
+ const isDraggingItem = (0, import_react20.useCallback)(
6675
6924
  (id) => dragState.isDragging && dragState.draggedId === id,
6676
6925
  [dragState.isDragging, dragState.draggedId]
6677
6926
  );
@@ -6684,7 +6933,7 @@ function useDrag(options = {}) {
6684
6933
  }
6685
6934
 
6686
6935
  // src/diagram/hooks/useKeyboardShortcuts.ts
6687
- var import_react20 = require("react");
6936
+ var import_react21 = require("react");
6688
6937
  function useKeyboardShortcuts(options) {
6689
6938
  const {
6690
6939
  onDelete,
@@ -6695,7 +6944,7 @@ function useKeyboardShortcuts(options) {
6695
6944
  onSelectAll,
6696
6945
  enabled = true
6697
6946
  } = options;
6698
- (0, import_react20.useEffect)(() => {
6947
+ (0, import_react21.useEffect)(() => {
6699
6948
  if (!enabled) return;
6700
6949
  const handleKeyDown = (event) => {
6701
6950
  const target = event.target;
@@ -6804,7 +7053,7 @@ function nodeHasPort(node, portId) {
6804
7053
  }
6805
7054
 
6806
7055
  // src/components/PIDCanvas/PIDCanvas.tsx
6807
- var import_jsx_runtime20 = require("react/jsx-runtime");
7056
+ var import_jsx_runtime21 = require("react/jsx-runtime");
6808
7057
  var DEFAULT_FEATURES = {
6809
7058
  pan: true,
6810
7059
  zoom: true,
@@ -6833,21 +7082,21 @@ function PIDCanvasImpl({
6833
7082
  statusColorMap,
6834
7083
  ...props
6835
7084
  }) {
6836
- const [localDiagram, setLocalDiagram] = (0, import_react21.useState)(diagram);
6837
- const [dragOverPosition, setDragOverPosition] = (0, import_react21.useState)(null);
6838
- const [isConnecting, setIsConnecting] = (0, import_react21.useState)(false);
6839
- const [connectionSource, setConnectionSource] = (0, import_react21.useState)(null);
6840
- const [connectionSourcePort, setConnectionSourcePort] = (0, import_react21.useState)(null);
6841
- const [connectionCursor, setConnectionCursor] = (0, import_react21.useState)(null);
6842
- const [hoveredNode, setHoveredNode] = (0, import_react21.useState)(null);
6843
- const [hoveredPort, setHoveredPort] = (0, import_react21.useState)(null);
6844
- const [selectedWaypoint, setSelectedWaypoint] = (0, import_react21.useState)(null);
6845
- const historyStack = (0, import_react21.useRef)([]);
6846
- const redoStack = (0, import_react21.useRef)([]);
6847
- const isUndoRedoAction = (0, import_react21.useRef)(false);
6848
- const isInternalChange = (0, import_react21.useRef)(false);
6849
- const lastInternalDiagram = (0, import_react21.useRef)(null);
6850
- (0, import_react21.useEffect)(() => {
7085
+ const [localDiagram, setLocalDiagram] = (0, import_react22.useState)(diagram);
7086
+ const [dragOverPosition, setDragOverPosition] = (0, import_react22.useState)(null);
7087
+ const [isConnecting, setIsConnecting] = (0, import_react22.useState)(false);
7088
+ const [connectionSource, setConnectionSource] = (0, import_react22.useState)(null);
7089
+ const [connectionSourcePort, setConnectionSourcePort] = (0, import_react22.useState)(null);
7090
+ const [connectionCursor, setConnectionCursor] = (0, import_react22.useState)(null);
7091
+ const [hoveredNode, setHoveredNode] = (0, import_react22.useState)(null);
7092
+ const [hoveredPort, setHoveredPort] = (0, import_react22.useState)(null);
7093
+ const [selectedWaypoint, setSelectedWaypoint] = (0, import_react22.useState)(null);
7094
+ const historyStack = (0, import_react22.useRef)([]);
7095
+ const redoStack = (0, import_react22.useRef)([]);
7096
+ const isUndoRedoAction = (0, import_react22.useRef)(false);
7097
+ const isInternalChange = (0, import_react22.useRef)(false);
7098
+ const lastInternalDiagram = (0, import_react22.useRef)(null);
7099
+ (0, import_react22.useEffect)(() => {
6851
7100
  const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
6852
7101
  if (isExternal) {
6853
7102
  setLocalDiagram(diagram);
@@ -6869,7 +7118,7 @@ function PIDCanvasImpl({
6869
7118
  enablePan: features.pan ?? true,
6870
7119
  enableZoom: features.zoom ?? true
6871
7120
  });
6872
- const calculateContentBounds = (0, import_react21.useCallback)(() => {
7121
+ const calculateContentBounds = (0, import_react22.useCallback)(() => {
6873
7122
  const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
6874
7123
  if (nodes2.length === 0) {
6875
7124
  return null;
@@ -6892,7 +7141,7 @@ function PIDCanvasImpl({
6892
7141
  });
6893
7142
  return { minX, minY, maxX, maxY };
6894
7143
  }, [localDiagram.nodes]);
6895
- (0, import_react21.useEffect)(() => {
7144
+ (0, import_react22.useEffect)(() => {
6896
7145
  if (onMounted) {
6897
7146
  const controls = {
6898
7147
  fitToContent: (padding = 50) => {
@@ -6933,8 +7182,8 @@ function PIDCanvasImpl({
6933
7182
  });
6934
7183
  const dragEnabled = features.dragNodes ?? false;
6935
7184
  const selectionEnabled = features.selection ?? false;
6936
- const containerRef = (0, import_react21.useRef)(null);
6937
- const pushToHistory = (0, import_react21.useCallback)((currentDiagram) => {
7185
+ const containerRef = (0, import_react22.useRef)(null);
7186
+ const pushToHistory = (0, import_react22.useCallback)((currentDiagram) => {
6938
7187
  if (isUndoRedoAction.current) return;
6939
7188
  const snapshot = JSON.parse(JSON.stringify(currentDiagram));
6940
7189
  historyStack.current.push(snapshot);
@@ -6943,7 +7192,7 @@ function PIDCanvasImpl({
6943
7192
  }
6944
7193
  redoStack.current = [];
6945
7194
  }, []);
6946
- const undo = (0, import_react21.useCallback)(() => {
7195
+ const undo = (0, import_react22.useCallback)(() => {
6947
7196
  if (historyStack.current.length === 0) return;
6948
7197
  isUndoRedoAction.current = true;
6949
7198
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6957,7 +7206,7 @@ function PIDCanvasImpl({
6957
7206
  isUndoRedoAction.current = false;
6958
7207
  }, 0);
6959
7208
  }, [localDiagram, onDiagramChange]);
6960
- const redo = (0, import_react21.useCallback)(() => {
7209
+ const redo = (0, import_react22.useCallback)(() => {
6961
7210
  if (redoStack.current.length === 0) return;
6962
7211
  isUndoRedoAction.current = true;
6963
7212
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6971,7 +7220,7 @@ function PIDCanvasImpl({
6971
7220
  isUndoRedoAction.current = false;
6972
7221
  }, 0);
6973
7222
  }, [localDiagram, onDiagramChange]);
6974
- (0, import_react21.useEffect)(() => {
7223
+ (0, import_react22.useEffect)(() => {
6975
7224
  const handleKeyDown = (e) => {
6976
7225
  const isCtrlOrCmd = e.ctrlKey || e.metaKey;
6977
7226
  if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
@@ -6988,7 +7237,7 @@ function PIDCanvasImpl({
6988
7237
  window.addEventListener("keydown", handleKeyDown);
6989
7238
  return () => window.removeEventListener("keydown", handleKeyDown);
6990
7239
  }, [undo, redo]);
6991
- (0, import_react21.useEffect)(() => {
7240
+ (0, import_react22.useEffect)(() => {
6992
7241
  if (!features.dragNodes) return;
6993
7242
  const handleKeyDown = (e) => {
6994
7243
  if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
@@ -7073,7 +7322,7 @@ function PIDCanvasImpl({
7073
7322
  onNodeMove,
7074
7323
  pushToHistory
7075
7324
  ]);
7076
- const handlePositionChange = (0, import_react21.useCallback)(
7325
+ const handlePositionChange = (0, import_react22.useCallback)(
7077
7326
  (nodeId, x, y) => {
7078
7327
  pushToHistory(localDiagram);
7079
7328
  const updatedNodes = localDiagram.nodes.map(
@@ -7095,7 +7344,7 @@ function PIDCanvasImpl({
7095
7344
  },
7096
7345
  [localDiagram, onDiagramChange, onNodeMove, pushToHistory]
7097
7346
  );
7098
- const handleWaypointPositionChange = (0, import_react21.useCallback)(
7347
+ const handleWaypointPositionChange = (0, import_react22.useCallback)(
7099
7348
  (pipeId, pointIndex, x, y) => {
7100
7349
  pushToHistory(localDiagram);
7101
7350
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -7113,7 +7362,7 @@ function PIDCanvasImpl({
7113
7362
  },
7114
7363
  [localDiagram, onDiagramChange, pushToHistory]
7115
7364
  );
7116
- const handleDragEnd = (0, import_react21.useCallback)(
7365
+ const handleDragEnd = (0, import_react22.useCallback)(
7117
7366
  (nodeId, offset, finalPosition) => {
7118
7367
  const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
7119
7368
  if (dragDistance < 2) {
@@ -7194,7 +7443,7 @@ function PIDCanvasImpl({
7194
7443
  onDiagramChange?.(updatedDiagram);
7195
7444
  }
7196
7445
  });
7197
- const handleNodeDragStart = (0, import_react21.useCallback)(
7446
+ const handleNodeDragStart = (0, import_react22.useCallback)(
7198
7447
  (nodeId, event) => {
7199
7448
  const node = localDiagram.nodes.find((n) => n.id === nodeId);
7200
7449
  if (!node) return;
@@ -7202,7 +7451,7 @@ function PIDCanvasImpl({
7202
7451
  },
7203
7452
  [localDiagram.nodes, startDrag]
7204
7453
  );
7205
- const handleWaypointClick = (0, import_react21.useCallback)(
7454
+ const handleWaypointClick = (0, import_react22.useCallback)(
7206
7455
  (pipeId, pointIndex) => {
7207
7456
  setSelectedWaypoint({ pipeId, pointIndex });
7208
7457
  if (selectionEnabled) {
@@ -7211,7 +7460,7 @@ function PIDCanvasImpl({
7211
7460
  },
7212
7461
  [selectionEnabled, clearSelection]
7213
7462
  );
7214
- const handleWaypointDragStart = (0, import_react21.useCallback)(
7463
+ const handleWaypointDragStart = (0, import_react22.useCallback)(
7215
7464
  (pipeId, pointIndex, event) => {
7216
7465
  const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
7217
7466
  if (!pipe || pointIndex >= pipe.routePoints.length) return;
@@ -7220,7 +7469,7 @@ function PIDCanvasImpl({
7220
7469
  },
7221
7470
  [localDiagram.pipes, startWaypointDrag]
7222
7471
  );
7223
- const handlePipeSegmentClick = (0, import_react21.useCallback)(
7472
+ const handlePipeSegmentClick = (0, import_react22.useCallback)(
7224
7473
  (pipeId, position, segmentIndex) => {
7225
7474
  pushToHistory(localDiagram);
7226
7475
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -7239,7 +7488,7 @@ function PIDCanvasImpl({
7239
7488
  [localDiagram, onDiagramChange, pushToHistory]
7240
7489
  );
7241
7490
  const telemetryEnabled = features.telemetry ?? false;
7242
- const handleDelete = (0, import_react21.useCallback)(() => {
7491
+ const handleDelete = (0, import_react22.useCallback)(() => {
7243
7492
  if (!selectionEnabled) return;
7244
7493
  const { selectedNodeIds, selectedPipeIds } = selection;
7245
7494
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
@@ -7268,17 +7517,17 @@ function PIDCanvasImpl({
7268
7517
  onDelete,
7269
7518
  pushToHistory
7270
7519
  ]);
7271
- const handleCopy = (0, import_react21.useCallback)(() => {
7520
+ const handleCopy = (0, import_react22.useCallback)(() => {
7272
7521
  if (!selectionEnabled) return;
7273
7522
  const { selectedNodeIds, selectedPipeIds } = selection;
7274
7523
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
7275
7524
  onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
7276
7525
  }, [selection, selectionEnabled, onItemsCopied]);
7277
- const handlePaste = (0, import_react21.useCallback)(() => {
7526
+ const handlePaste = (0, import_react22.useCallback)(() => {
7278
7527
  if (!selectionEnabled) return;
7279
7528
  onPaste?.();
7280
7529
  }, [selectionEnabled, onPaste]);
7281
- const handleNodeDoubleClick = (0, import_react21.useCallback)(
7530
+ const handleNodeDoubleClick = (0, import_react22.useCallback)(
7282
7531
  (nodeId, event) => {
7283
7532
  if (!selectionEnabled) return;
7284
7533
  console.log("Node double-clicked:", nodeId);
@@ -7292,7 +7541,7 @@ function PIDCanvasImpl({
7292
7541
  onCopy: handleCopy,
7293
7542
  onPaste: handlePaste
7294
7543
  });
7295
- const handleNodeClick = (0, import_react21.useCallback)(
7544
+ const handleNodeClick = (0, import_react22.useCallback)(
7296
7545
  (nodeId, event) => {
7297
7546
  const connectionModeEnabled = features.connectionMode ?? false;
7298
7547
  if (connectionModeEnabled && isConnecting) {
@@ -7334,7 +7583,7 @@ function PIDCanvasImpl({
7334
7583
  onNodeClick
7335
7584
  ]
7336
7585
  );
7337
- const handlePipeClick = (0, import_react21.useCallback)(
7586
+ const handlePipeClick = (0, import_react22.useCallback)(
7338
7587
  (pipeId, event) => {
7339
7588
  if (selectionEnabled) {
7340
7589
  selectPipe(pipeId, event.ctrlKey || event.metaKey);
@@ -7353,7 +7602,7 @@ function PIDCanvasImpl({
7353
7602
  }
7354
7603
  setSelectedWaypoint(null);
7355
7604
  };
7356
- const handleDragOver = (0, import_react21.useCallback)(
7605
+ const handleDragOver = (0, import_react22.useCallback)(
7357
7606
  (event) => {
7358
7607
  if (!features.allowSymbolDrop) return;
7359
7608
  event.preventDefault();
@@ -7364,7 +7613,7 @@ function PIDCanvasImpl({
7364
7613
  },
7365
7614
  [features.allowSymbolDrop, screenToWorld, svgRef]
7366
7615
  );
7367
- const handleDrop = (0, import_react21.useCallback)(
7616
+ const handleDrop = (0, import_react22.useCallback)(
7368
7617
  (event) => {
7369
7618
  if (!features.allowSymbolDrop) return;
7370
7619
  event.preventDefault();
@@ -7377,10 +7626,10 @@ function PIDCanvasImpl({
7377
7626
  },
7378
7627
  [features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
7379
7628
  );
7380
- const handleDragLeave = (0, import_react21.useCallback)(() => {
7629
+ const handleDragLeave = (0, import_react22.useCallback)(() => {
7381
7630
  setDragOverPosition(null);
7382
7631
  }, []);
7383
- const handleMouseMove = (0, import_react21.useCallback)(
7632
+ const handleMouseMove = (0, import_react22.useCallback)(
7384
7633
  (event) => {
7385
7634
  const connectionModeEnabled = features.connectionMode ?? false;
7386
7635
  if (connectionModeEnabled) {
@@ -7417,7 +7666,7 @@ function PIDCanvasImpl({
7417
7666
  const viewBox = controlledViewBox;
7418
7667
  const displayDiagram = localDiagram;
7419
7668
  const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
7420
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7669
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7421
7670
  "div",
7422
7671
  {
7423
7672
  ref: containerRef,
@@ -7432,7 +7681,7 @@ function PIDCanvasImpl({
7432
7681
  },
7433
7682
  ...props,
7434
7683
  children: [
7435
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7684
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7436
7685
  "svg",
7437
7686
  {
7438
7687
  ref: svgRef,
@@ -7451,15 +7700,15 @@ function PIDCanvasImpl({
7451
7700
  onDrop: handleDrop,
7452
7701
  onDragLeave: handleDragLeave,
7453
7702
  children: [
7454
- features.showGrid !== false ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
7455
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("defs", { children: [
7456
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
7457
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
7458
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
7459
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
7703
+ features.showGrid !== false ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7704
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("defs", { children: [
7705
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
7706
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
7707
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
7708
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
7460
7709
  ] })
7461
7710
  ] }),
7462
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7711
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7463
7712
  "rect",
7464
7713
  {
7465
7714
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7469,7 +7718,7 @@ function PIDCanvasImpl({
7469
7718
  fill: "url(#grid-major)"
7470
7719
  }
7471
7720
  )
7472
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7721
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7473
7722
  "rect",
7474
7723
  {
7475
7724
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7479,7 +7728,7 @@ function PIDCanvasImpl({
7479
7728
  fill: features.backgroundColor ?? "#ffffff"
7480
7729
  }
7481
7730
  ),
7482
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7731
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7483
7732
  PipeRenderer,
7484
7733
  {
7485
7734
  pipes: displayDiagram.pipes,
@@ -7493,7 +7742,7 @@ function PIDCanvasImpl({
7493
7742
  onPipeSegmentClick: void 0
7494
7743
  }
7495
7744
  ),
7496
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7745
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7497
7746
  NodeRenderer,
7498
7747
  {
7499
7748
  nodes: displayDiagram.nodes,
@@ -7507,7 +7756,7 @@ function PIDCanvasImpl({
7507
7756
  statusColorMap
7508
7757
  }
7509
7758
  ),
7510
- (features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7759
+ (features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7511
7760
  PipeRenderer,
7512
7761
  {
7513
7762
  pipes: displayDiagram.pipes,
@@ -7524,7 +7773,7 @@ function PIDCanvasImpl({
7524
7773
  onPipeSegmentClick: handlePipeSegmentClick
7525
7774
  }
7526
7775
  ),
7527
- telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7776
+ telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7528
7777
  if (node.symbolId === "status-indicator") return null;
7529
7778
  const binding = telemetry.get(node.id);
7530
7779
  if (!binding) return null;
@@ -7532,7 +7781,7 @@ function PIDCanvasImpl({
7532
7781
  if (!symbol) return null;
7533
7782
  const overlayX = node.transform.x + symbol.viewBox.width / 2;
7534
7783
  const overlayY = node.transform.y + symbol.viewBox.height + 50;
7535
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7784
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7536
7785
  DataOverlay,
7537
7786
  {
7538
7787
  nodeId: node.id,
@@ -7545,7 +7794,7 @@ function PIDCanvasImpl({
7545
7794
  `telemetry-${node.id}`
7546
7795
  );
7547
7796
  }) }),
7548
- dragOverPosition && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7797
+ dragOverPosition && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7549
7798
  "circle",
7550
7799
  {
7551
7800
  cx: dragOverPosition.x,
@@ -7558,7 +7807,7 @@ function PIDCanvasImpl({
7558
7807
  pointerEvents: "none"
7559
7808
  }
7560
7809
  ),
7561
- isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7810
+ isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7562
7811
  const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
7563
7812
  if (!sourceNode) return null;
7564
7813
  const symbol = getSymbolDefinition(sourceNode.symbolId);
@@ -7574,8 +7823,8 @@ function PIDCanvasImpl({
7574
7823
  }
7575
7824
  }
7576
7825
  }
7577
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
7578
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7826
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7827
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7579
7828
  "circle",
7580
7829
  {
7581
7830
  cx: lineStartX,
@@ -7587,7 +7836,7 @@ function PIDCanvasImpl({
7587
7836
  opacity: 0.6
7588
7837
  }
7589
7838
  ),
7590
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7839
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7591
7840
  "line",
7592
7841
  {
7593
7842
  x1: lineStartX,
@@ -7600,7 +7849,7 @@ function PIDCanvasImpl({
7600
7849
  opacity: 0.8
7601
7850
  }
7602
7851
  ),
7603
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7852
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7604
7853
  "circle",
7605
7854
  {
7606
7855
  cx: connectionCursor.x,
@@ -7612,7 +7861,7 @@ function PIDCanvasImpl({
7612
7861
  )
7613
7862
  ] });
7614
7863
  })() }),
7615
- features.connectionMode && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7864
+ features.connectionMode && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7616
7865
  const symbol = getSymbolDefinition(node.symbolId);
7617
7866
  if (!symbol?.ports) return null;
7618
7867
  return symbol.ports.map((port) => {
@@ -7620,8 +7869,8 @@ function PIDCanvasImpl({
7620
7869
  if (!portPos) return null;
7621
7870
  const isHovered = hoveredPort === port.id && hoveredNode === node.id;
7622
7871
  const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
7623
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("g", { children: [
7624
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7872
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("g", { children: [
7873
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7625
7874
  "circle",
7626
7875
  {
7627
7876
  cx: portPos.x,
@@ -7654,7 +7903,7 @@ function PIDCanvasImpl({
7654
7903
  }
7655
7904
  }
7656
7905
  ),
7657
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7906
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7658
7907
  "circle",
7659
7908
  {
7660
7909
  cx: portPos.x,
@@ -7673,7 +7922,7 @@ function PIDCanvasImpl({
7673
7922
  ]
7674
7923
  }
7675
7924
  ),
7676
- features.dragNodes && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7925
+ features.dragNodes && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7677
7926
  PositionPanel,
7678
7927
  {
7679
7928
  selectedNode,
@@ -7691,19 +7940,19 @@ function PIDCanvasImpl({
7691
7940
  }
7692
7941
  );
7693
7942
  }
7694
- var PIDCanvas = import_react21.default.memo(PIDCanvasImpl);
7943
+ var PIDCanvas = import_react22.default.memo(PIDCanvasImpl);
7695
7944
 
7696
7945
  // src/components/SymbolLibrary/SymbolLibrary.tsx
7697
- var import_react22 = require("react");
7698
- var import_jsx_runtime21 = require("react/jsx-runtime");
7946
+ var import_react23 = require("react");
7947
+ var import_jsx_runtime22 = require("react/jsx-runtime");
7699
7948
  function SymbolLibrary({
7700
7949
  className = "",
7701
7950
  onSymbolDragStart,
7702
7951
  showCategories = true,
7703
7952
  categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
7704
7953
  }) {
7705
- const [selectedCategory, setSelectedCategory] = (0, import_react22.useState)("all");
7706
- const [searchQuery, setSearchQuery] = (0, import_react22.useState)("");
7954
+ const [selectedCategory, setSelectedCategory] = (0, import_react23.useState)("all");
7955
+ const [searchQuery, setSearchQuery] = (0, import_react23.useState)("");
7707
7956
  const symbolIds = getAvailableSymbols();
7708
7957
  const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
7709
7958
  const categoryMap = {
@@ -7724,9 +7973,9 @@ function SymbolLibrary({
7724
7973
  event.dataTransfer.effectAllowed = "copy";
7725
7974
  onSymbolDragStart?.(symbol.id, event);
7726
7975
  };
7727
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
7728
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { style: styles.title, children: "Symbol Library" }) }),
7729
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.searchContainer, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7976
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
7977
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: styles.title, children: "Symbol Library" }) }),
7978
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.searchContainer, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7730
7979
  "input",
7731
7980
  {
7732
7981
  type: "text",
@@ -7736,8 +7985,8 @@ function SymbolLibrary({
7736
7985
  style: styles.searchInput
7737
7986
  }
7738
7987
  ) }),
7739
- showCategories && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: styles.categories, children: [
7740
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7988
+ showCategories && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: styles.categories, children: [
7989
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7741
7990
  "button",
7742
7991
  {
7743
7992
  onClick: () => setSelectedCategory("all"),
@@ -7748,7 +7997,7 @@ function SymbolLibrary({
7748
7997
  children: "All"
7749
7998
  }
7750
7999
  ),
7751
- categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8000
+ categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7752
8001
  "button",
7753
8002
  {
7754
8003
  onClick: () => setSelectedCategory(category),
@@ -7761,7 +8010,7 @@ function SymbolLibrary({
7761
8010
  category
7762
8011
  ))
7763
8012
  ] }),
7764
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8013
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7765
8014
  "div",
7766
8015
  {
7767
8016
  draggable: true,
@@ -7769,15 +8018,15 @@ function SymbolLibrary({
7769
8018
  style: styles.symbolCard,
7770
8019
  title: symbol.metadata?.description || symbol.name,
7771
8020
  children: [
7772
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.symbolPreview, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8021
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.symbolPreview, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7773
8022
  "svg",
7774
8023
  {
7775
8024
  viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
7776
8025
  style: styles.symbolSvg,
7777
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
8026
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
7778
8027
  }
7779
8028
  ) }),
7780
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.symbolName, children: symbol.name })
8029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.symbolName, children: symbol.name })
7781
8030
  ]
7782
8031
  },
7783
8032
  symbol.id
@@ -7886,7 +8135,7 @@ var styles = {
7886
8135
  };
7887
8136
 
7888
8137
  // src/components/NodeConfigPanel/NodeConfigPanel.tsx
7889
- var import_jsx_runtime22 = require("react/jsx-runtime");
8138
+ var import_jsx_runtime23 = require("react/jsx-runtime");
7890
8139
  function NodeConfigPanel({
7891
8140
  node,
7892
8141
  binding,
@@ -7909,15 +8158,15 @@ function NodeConfigPanel({
7909
8158
  };
7910
8159
  const appearanceFields = getAppearanceSchema(node.symbolId);
7911
8160
  const showGenericTelemetry = appearanceFields.length === 0;
7912
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, style: defaultStyle, children: [
7913
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
8161
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, style: defaultStyle, children: [
8162
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
7914
8163
  "Configure: ",
7915
8164
  node.id
7916
8165
  ] }),
7917
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
7918
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
7919
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
7920
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8166
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8167
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
8168
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
8169
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7921
8170
  "input",
7922
8171
  {
7923
8172
  type: "text",
@@ -7933,10 +8182,10 @@ function NodeConfigPanel({
7933
8182
  }
7934
8183
  }
7935
8184
  ),
7936
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
7937
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
7938
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
7939
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8185
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8186
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8187
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
8188
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7940
8189
  "input",
7941
8190
  {
7942
8191
  type: "number",
@@ -7957,9 +8206,9 @@ function NodeConfigPanel({
7957
8206
  }
7958
8207
  )
7959
8208
  ] }),
7960
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
7961
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
7962
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8209
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8210
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
8211
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7963
8212
  "input",
7964
8213
  {
7965
8214
  type: "number",
@@ -7981,9 +8230,9 @@ function NodeConfigPanel({
7981
8230
  )
7982
8231
  ] })
7983
8232
  ] }),
7984
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
7985
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
7986
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8233
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8234
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
8235
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7987
8236
  "input",
7988
8237
  {
7989
8238
  type: "number",
@@ -8003,9 +8252,9 @@ function NodeConfigPanel({
8003
8252
  }
8004
8253
  )
8005
8254
  ] }),
8006
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
8007
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
8008
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8255
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8256
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
8257
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8009
8258
  "input",
8010
8259
  {
8011
8260
  type: "number",
@@ -8030,8 +8279,8 @@ function NodeConfigPanel({
8030
8279
  )
8031
8280
  ] })
8032
8281
  ] }),
8033
- appearanceFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8034
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
8282
+ appearanceFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8283
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
8035
8284
  appearanceFields.map((field) => {
8036
8285
  const value = readAppearanceValue(node, field);
8037
8286
  const fieldLabel = field.label ?? field.key;
@@ -8044,8 +8293,8 @@ function NodeConfigPanel({
8044
8293
  };
8045
8294
  let control;
8046
8295
  if (field.kind === "boolean") {
8047
- control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
8048
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8296
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
8297
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8049
8298
  "input",
8050
8299
  {
8051
8300
  type: "checkbox",
@@ -8057,28 +8306,28 @@ function NodeConfigPanel({
8057
8306
  fieldLabel
8058
8307
  ] });
8059
8308
  } else if (field.kind === "select") {
8060
- control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8061
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8309
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8310
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8062
8311
  fieldLabel,
8063
8312
  ":"
8064
8313
  ] }),
8065
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8314
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8066
8315
  "select",
8067
8316
  {
8068
8317
  value: String(value),
8069
8318
  onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
8070
8319
  style: inputStyle,
8071
- children: field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: opt, children: opt }, opt))
8320
+ children: field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: opt, children: opt }, opt))
8072
8321
  }
8073
8322
  )
8074
8323
  ] });
8075
8324
  } else if (field.kind === "number") {
8076
- control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8077
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8325
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8326
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8078
8327
  fieldLabel,
8079
8328
  ":"
8080
8329
  ] }),
8081
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8330
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8082
8331
  "input",
8083
8332
  {
8084
8333
  type: "number",
@@ -8093,12 +8342,12 @@ function NodeConfigPanel({
8093
8342
  const listId = `tags-${node.id}-${field.key}`;
8094
8343
  const known = tagValue.length > 0 && availableTags.includes(tagValue);
8095
8344
  const unknown = tagValue.length > 0 && !known;
8096
- control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8097
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8345
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8346
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8098
8347
  fieldLabel,
8099
8348
  ":"
8100
8349
  ] }),
8101
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8350
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8102
8351
  "input",
8103
8352
  {
8104
8353
  type: "text",
@@ -8112,8 +8361,8 @@ function NodeConfigPanel({
8112
8361
  }
8113
8362
  }
8114
8363
  ),
8115
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: t }, t)) }),
8116
- tagValue.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8364
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: t }, t)) }),
8365
+ tagValue.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8117
8366
  "div",
8118
8367
  {
8119
8368
  style: {
@@ -8126,12 +8375,12 @@ function NodeConfigPanel({
8126
8375
  )
8127
8376
  ] });
8128
8377
  } else {
8129
- control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8130
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8378
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8379
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8131
8380
  fieldLabel,
8132
8381
  ":"
8133
8382
  ] }),
8134
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8383
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8135
8384
  "input",
8136
8385
  {
8137
8386
  type: "text",
@@ -8142,9 +8391,9 @@ function NodeConfigPanel({
8142
8391
  )
8143
8392
  ] });
8144
8393
  }
8145
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "10px" }, children: [
8394
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "10px" }, children: [
8146
8395
  control,
8147
- field.help && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8396
+ field.help && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8148
8397
  "div",
8149
8398
  {
8150
8399
  style: {
@@ -8159,9 +8408,9 @@ function NodeConfigPanel({
8159
8408
  ] }, field.key);
8160
8409
  })
8161
8410
  ] }),
8162
- showGenericTelemetry && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8163
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
8164
- !binding ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8411
+ showGenericTelemetry && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8412
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
8413
+ !binding ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8165
8414
  "button",
8166
8415
  {
8167
8416
  onClick: () => {
@@ -8204,9 +8453,9 @@ function NodeConfigPanel({
8204
8453
  },
8205
8454
  children: "+ Add Telemetry"
8206
8455
  }
8207
- ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8208
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
8209
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8456
+ ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8457
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
8458
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8210
8459
  "input",
8211
8460
  {
8212
8461
  type: "text",
@@ -8226,8 +8475,8 @@ function NodeConfigPanel({
8226
8475
  }
8227
8476
  }
8228
8477
  ),
8229
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
8230
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8478
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
8479
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8231
8480
  "input",
8232
8481
  {
8233
8482
  type: "number",
@@ -8249,8 +8498,8 @@ function NodeConfigPanel({
8249
8498
  }
8250
8499
  }
8251
8500
  ),
8252
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
8253
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8501
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
8502
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8254
8503
  "input",
8255
8504
  {
8256
8505
  type: "text",
@@ -8272,8 +8521,8 @@ function NodeConfigPanel({
8272
8521
  }
8273
8522
  }
8274
8523
  ),
8275
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8276
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8524
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8525
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8277
8526
  "input",
8278
8527
  {
8279
8528
  type: "checkbox",
@@ -8295,8 +8544,8 @@ function NodeConfigPanel({
8295
8544
  ),
8296
8545
  "Show Sparkline"
8297
8546
  ] }),
8298
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginTop: "12px" }, children: [
8299
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8547
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginTop: "12px" }, children: [
8548
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8300
8549
  "label",
8301
8550
  {
8302
8551
  style: {
@@ -8308,10 +8557,10 @@ function NodeConfigPanel({
8308
8557
  children: "Telemetry Position Offset:"
8309
8558
  }
8310
8559
  ),
8311
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8312
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
8313
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
8314
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8560
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8561
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8562
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
8563
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8315
8564
  "input",
8316
8565
  {
8317
8566
  type: "number",
@@ -8338,9 +8587,9 @@ function NodeConfigPanel({
8338
8587
  }
8339
8588
  )
8340
8589
  ] }),
8341
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
8342
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
8343
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8590
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8591
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
8592
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8344
8593
  "input",
8345
8594
  {
8346
8595
  type: "number",
@@ -8368,8 +8617,8 @@ function NodeConfigPanel({
8368
8617
  )
8369
8618
  ] })
8370
8619
  ] }),
8371
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginTop: "16px" }, children: [
8372
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8620
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginTop: "16px" }, children: [
8621
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8373
8622
  "label",
8374
8623
  {
8375
8624
  style: {
@@ -8381,10 +8630,10 @@ function NodeConfigPanel({
8381
8630
  children: "Display Colors:"
8382
8631
  }
8383
8632
  ),
8384
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8385
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
8386
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8387
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8633
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8634
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
8635
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8636
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8388
8637
  "input",
8389
8638
  {
8390
8639
  type: "color",
@@ -8410,7 +8659,7 @@ function NodeConfigPanel({
8410
8659
  }
8411
8660
  }
8412
8661
  ),
8413
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8662
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8414
8663
  "input",
8415
8664
  {
8416
8665
  type: "text",
@@ -8440,10 +8689,10 @@ function NodeConfigPanel({
8440
8689
  )
8441
8690
  ] })
8442
8691
  ] }),
8443
- binding.display?.showSparkline && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8444
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
8445
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8446
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8692
+ binding.display?.showSparkline && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8693
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
8694
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8695
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8447
8696
  "input",
8448
8697
  {
8449
8698
  type: "color",
@@ -8469,7 +8718,7 @@ function NodeConfigPanel({
8469
8718
  }
8470
8719
  }
8471
8720
  ),
8472
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8721
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8473
8722
  "input",
8474
8723
  {
8475
8724
  type: "text",
@@ -8499,9 +8748,9 @@ function NodeConfigPanel({
8499
8748
  )
8500
8749
  ] })
8501
8750
  ] }),
8502
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8503
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
8504
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8752
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
8753
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8505
8754
  "input",
8506
8755
  {
8507
8756
  type: "text",
@@ -8529,12 +8778,12 @@ function NodeConfigPanel({
8529
8778
  }
8530
8779
  }
8531
8780
  ),
8532
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
8781
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
8533
8782
  ] })
8534
8783
  ] }),
8535
8784
  " "
8536
8785
  ] }),
8537
- onRemoveTelemetry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8786
+ onRemoveTelemetry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8538
8787
  "button",
8539
8788
  {
8540
8789
  onClick: onRemoveTelemetry,
@@ -8554,13 +8803,13 @@ function NodeConfigPanel({
8554
8803
  )
8555
8804
  ] })
8556
8805
  ] }),
8557
- showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8558
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
8806
+ showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8807
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
8559
8808
  ["highHigh", "high", "low", "lowLow"].map((key) => {
8560
8809
  const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
8561
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8562
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
8563
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8810
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8811
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
8812
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8564
8813
  "input",
8565
8814
  {
8566
8815
  type: "number",
@@ -8584,8 +8833,8 @@ function NodeConfigPanel({
8584
8833
  ] }, key);
8585
8834
  })
8586
8835
  ] }),
8587
- showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8588
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
8836
+ showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8837
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
8589
8838
  ["normal", "warning", "alarm", "fault", "off"].map((status) => {
8590
8839
  const defaultColors = {
8591
8840
  normal: "#10b981",
@@ -8595,13 +8844,13 @@ function NodeConfigPanel({
8595
8844
  off: "#6b7280"
8596
8845
  };
8597
8846
  const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
8598
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8599
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8847
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8848
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8600
8849
  label,
8601
8850
  ":"
8602
8851
  ] }),
8603
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8604
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8852
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8853
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8605
8854
  "input",
8606
8855
  {
8607
8856
  type: "color",
@@ -8622,7 +8871,7 @@ function NodeConfigPanel({
8622
8871
  }
8623
8872
  }
8624
8873
  ),
8625
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8874
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8626
8875
  "input",
8627
8876
  {
8628
8877
  type: "text",
@@ -8649,7 +8898,7 @@ function NodeConfigPanel({
8649
8898
  ] }, status);
8650
8899
  })
8651
8900
  ] }),
8652
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8901
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8653
8902
  "button",
8654
8903
  {
8655
8904
  onClick: onRemove,
@@ -8926,13 +9175,13 @@ function createControlBinding(nodeId, deviceConfig, actions) {
8926
9175
  }
8927
9176
 
8928
9177
  // src/hooks/useDeviceControls.ts
8929
- var import_react23 = require("react");
9178
+ var import_react24 = require("react");
8930
9179
  function commandKey(nodeId, kind, suffix) {
8931
9180
  return suffix ? `${nodeId}:${kind}:${suffix}` : `${nodeId}:${kind}`;
8932
9181
  }
8933
9182
  function useDeviceControls(initialBindings, options) {
8934
9183
  const { commandTimeoutMs } = options ?? {};
8935
- const [controls, setControls] = (0, import_react23.useState)(() => {
9184
+ const [controls, setControls] = (0, import_react24.useState)(() => {
8936
9185
  const map = /* @__PURE__ */ new Map();
8937
9186
  if (initialBindings) {
8938
9187
  initialBindings.forEach((binding) => {
@@ -8941,12 +9190,12 @@ function useDeviceControls(initialBindings, options) {
8941
9190
  }
8942
9191
  return map;
8943
9192
  });
8944
- const pendingRef = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
8945
- const [pendingCommands, setPendingCommands] = (0, import_react23.useState)(() => /* @__PURE__ */ new Set());
8946
- const syncPending = (0, import_react23.useCallback)(() => {
9193
+ const pendingRef = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
9194
+ const [pendingCommands, setPendingCommands] = (0, import_react24.useState)(() => /* @__PURE__ */ new Set());
9195
+ const syncPending = (0, import_react24.useCallback)(() => {
8947
9196
  setPendingCommands(new Set(pendingRef.current.keys()));
8948
9197
  }, []);
8949
- const updateControl = (0, import_react23.useCallback)((nodeId, updates) => {
9198
+ const updateControl = (0, import_react24.useCallback)((nodeId, updates) => {
8950
9199
  setControls((prev) => {
8951
9200
  const newMap = new Map(prev);
8952
9201
  const existing = newMap.get(nodeId);
@@ -8960,7 +9209,7 @@ function useDeviceControls(initialBindings, options) {
8960
9209
  return newMap;
8961
9210
  });
8962
9211
  }, []);
8963
- const updateControlBatch = (0, import_react23.useCallback)((updates) => {
9212
+ const updateControlBatch = (0, import_react24.useCallback)((updates) => {
8964
9213
  setControls((prev) => {
8965
9214
  const newMap = new Map(prev);
8966
9215
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -8972,7 +9221,7 @@ function useDeviceControls(initialBindings, options) {
8972
9221
  return newMap;
8973
9222
  });
8974
9223
  }, []);
8975
- const updateDeviceState = (0, import_react23.useCallback)(
9224
+ const updateDeviceState = (0, import_react24.useCallback)(
8976
9225
  (nodeId, stateUpdates) => {
8977
9226
  setControls((prev) => {
8978
9227
  const newMap = new Map(prev);
@@ -8988,7 +9237,7 @@ function useDeviceControls(initialBindings, options) {
8988
9237
  },
8989
9238
  []
8990
9239
  );
8991
- const updateParameter = (0, import_react23.useCallback)(
9240
+ const updateParameter = (0, import_react24.useCallback)(
8992
9241
  (nodeId, parameterId, value) => {
8993
9242
  setControls((prev) => {
8994
9243
  const newMap = new Map(prev);
@@ -9015,27 +9264,27 @@ function useDeviceControls(initialBindings, options) {
9015
9264
  },
9016
9265
  []
9017
9266
  );
9018
- const setControlBinding = (0, import_react23.useCallback)((binding) => {
9267
+ const setControlBinding = (0, import_react24.useCallback)((binding) => {
9019
9268
  setControls((prev) => {
9020
9269
  const newMap = new Map(prev);
9021
9270
  newMap.set(binding.nodeId, binding);
9022
9271
  return newMap;
9023
9272
  });
9024
9273
  }, []);
9025
- const removeControlBinding = (0, import_react23.useCallback)((nodeId) => {
9274
+ const removeControlBinding = (0, import_react24.useCallback)((nodeId) => {
9026
9275
  setControls((prev) => {
9027
9276
  const newMap = new Map(prev);
9028
9277
  newMap.delete(nodeId);
9029
9278
  return newMap;
9030
9279
  });
9031
9280
  }, []);
9032
- const getControlBinding = (0, import_react23.useCallback)(
9281
+ const getControlBinding = (0, import_react24.useCallback)(
9033
9282
  (nodeId) => {
9034
9283
  return controls.get(nodeId);
9035
9284
  },
9036
9285
  [controls]
9037
9286
  );
9038
- const isCommandPending = (0, import_react23.useCallback)(
9287
+ const isCommandPending = (0, import_react24.useCallback)(
9039
9288
  (nodeId, kind) => {
9040
9289
  if (kind) {
9041
9290
  const prefix2 = `${nodeId}:${kind}`;
@@ -9052,7 +9301,7 @@ function useDeviceControls(initialBindings, options) {
9052
9301
  },
9053
9302
  [pendingCommands]
9054
9303
  );
9055
- const markPending = (0, import_react23.useCallback)(
9304
+ const markPending = (0, import_react24.useCallback)(
9056
9305
  (key, delta) => {
9057
9306
  const next = (pendingRef.current.get(key) ?? 0) + delta;
9058
9307
  if (next > 0) pendingRef.current.set(key, next);
@@ -9061,7 +9310,7 @@ function useDeviceControls(initialBindings, options) {
9061
9310
  },
9062
9311
  [syncPending]
9063
9312
  );
9064
- const runCommand = (0, import_react23.useCallback)(
9313
+ const runCommand = (0, import_react24.useCallback)(
9065
9314
  async (nodeId, key, invoke, messages) => {
9066
9315
  const binding = controls.get(nodeId);
9067
9316
  if (!binding) return;
@@ -9101,7 +9350,7 @@ function useDeviceControls(initialBindings, options) {
9101
9350
  },
9102
9351
  [controls, updateDeviceState, markPending, commandTimeoutMs]
9103
9352
  );
9104
- const sendModeChange = (0, import_react23.useCallback)(
9353
+ const sendModeChange = (0, import_react24.useCallback)(
9105
9354
  (nodeId, mode) => runCommand(
9106
9355
  nodeId,
9107
9356
  commandKey(nodeId, "mode"),
@@ -9110,7 +9359,7 @@ function useDeviceControls(initialBindings, options) {
9110
9359
  ),
9111
9360
  [runCommand]
9112
9361
  );
9113
- const sendParameterChange = (0, import_react23.useCallback)(
9362
+ const sendParameterChange = (0, import_react24.useCallback)(
9114
9363
  (nodeId, parameterId, value) => runCommand(
9115
9364
  nodeId,
9116
9365
  commandKey(nodeId, "parameter", parameterId),
@@ -9119,21 +9368,21 @@ function useDeviceControls(initialBindings, options) {
9119
9368
  ),
9120
9369
  [runCommand]
9121
9370
  );
9122
- const sendStartCommand = (0, import_react23.useCallback)(
9371
+ const sendStartCommand = (0, import_react24.useCallback)(
9123
9372
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "start"), (binding) => binding.actions.onStart?.(), {
9124
9373
  success: "Start command sent",
9125
9374
  failure: "Start command failed"
9126
9375
  }),
9127
9376
  [runCommand]
9128
9377
  );
9129
- const sendStopCommand = (0, import_react23.useCallback)(
9378
+ const sendStopCommand = (0, import_react24.useCallback)(
9130
9379
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "stop"), (binding) => binding.actions.onStop?.(), {
9131
9380
  success: "Stop command sent",
9132
9381
  failure: "Stop command failed"
9133
9382
  }),
9134
9383
  [runCommand]
9135
9384
  );
9136
- const sendCustomAction = (0, import_react23.useCallback)(
9385
+ const sendCustomAction = (0, import_react24.useCallback)(
9137
9386
  (nodeId, actionId) => runCommand(
9138
9387
  nodeId,
9139
9388
  commandKey(nodeId, "action", actionId),
@@ -9186,9 +9435,9 @@ function createConfigBinding(nodeId, tag, parameters, actions, options) {
9186
9435
  }
9187
9436
 
9188
9437
  // src/hooks/useDeviceConfigs.ts
9189
- var import_react24 = require("react");
9438
+ var import_react25 = require("react");
9190
9439
  function useDeviceConfigs(initialConfigs) {
9191
- const [configs, setConfigs] = (0, import_react24.useState)(() => {
9440
+ const [configs, setConfigs] = (0, import_react25.useState)(() => {
9192
9441
  const map = /* @__PURE__ */ new Map();
9193
9442
  if (initialConfigs) {
9194
9443
  initialConfigs.forEach((config) => {
@@ -9197,13 +9446,13 @@ function useDeviceConfigs(initialConfigs) {
9197
9446
  }
9198
9447
  return map;
9199
9448
  });
9200
- const getConfig = (0, import_react24.useCallback)(
9449
+ const getConfig = (0, import_react25.useCallback)(
9201
9450
  (nodeId) => {
9202
9451
  return configs.get(nodeId);
9203
9452
  },
9204
9453
  [configs]
9205
9454
  );
9206
- const updateConfig = (0, import_react24.useCallback)((nodeId, updates) => {
9455
+ const updateConfig = (0, import_react25.useCallback)((nodeId, updates) => {
9207
9456
  setConfigs((prev) => {
9208
9457
  const newMap = new Map(prev);
9209
9458
  const existing = newMap.get(nodeId);
@@ -9217,7 +9466,7 @@ function useDeviceConfigs(initialConfigs) {
9217
9466
  return newMap;
9218
9467
  });
9219
9468
  }, []);
9220
- const updateConfigState = (0, import_react24.useCallback)((nodeId, stateUpdates) => {
9469
+ const updateConfigState = (0, import_react25.useCallback)((nodeId, stateUpdates) => {
9221
9470
  setConfigs((prev) => {
9222
9471
  const newMap = new Map(prev);
9223
9472
  const existing = newMap.get(nodeId);
@@ -9230,7 +9479,7 @@ function useDeviceConfigs(initialConfigs) {
9230
9479
  return newMap;
9231
9480
  });
9232
9481
  }, []);
9233
- const updateConfigBatch = (0, import_react24.useCallback)((updates) => {
9482
+ const updateConfigBatch = (0, import_react25.useCallback)((updates) => {
9234
9483
  setConfigs((prev) => {
9235
9484
  const newMap = new Map(prev);
9236
9485
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -9242,7 +9491,7 @@ function useDeviceConfigs(initialConfigs) {
9242
9491
  return newMap;
9243
9492
  });
9244
9493
  }, []);
9245
- const updateParameterValue = (0, import_react24.useCallback)((nodeId, parameterId, value) => {
9494
+ const updateParameterValue = (0, import_react25.useCallback)((nodeId, parameterId, value) => {
9246
9495
  setConfigs((prev) => {
9247
9496
  const newMap = new Map(prev);
9248
9497
  const existing = newMap.get(nodeId);
@@ -9259,7 +9508,7 @@ function useDeviceConfigs(initialConfigs) {
9259
9508
  return newMap;
9260
9509
  });
9261
9510
  }, []);
9262
- const applyConfig = (0, import_react24.useCallback)(
9511
+ const applyConfig = (0, import_react25.useCallback)(
9263
9512
  async (nodeId) => {
9264
9513
  const config = configs.get(nodeId);
9265
9514
  if (!config || !config.actions.onApply) {
@@ -9292,7 +9541,7 @@ function useDeviceConfigs(initialConfigs) {
9292
9541
  },
9293
9542
  [configs, updateConfigState]
9294
9543
  );
9295
- const saveConfig = (0, import_react24.useCallback)(
9544
+ const saveConfig = (0, import_react25.useCallback)(
9296
9545
  async (nodeId) => {
9297
9546
  const config = configs.get(nodeId);
9298
9547
  if (!config || !config.actions.onSave) {
@@ -9326,7 +9575,7 @@ function useDeviceConfigs(initialConfigs) {
9326
9575
  },
9327
9576
  [configs, updateConfigState]
9328
9577
  );
9329
- const resetConfig = (0, import_react24.useCallback)(
9578
+ const resetConfig = (0, import_react25.useCallback)(
9330
9579
  async (nodeId) => {
9331
9580
  const config = configs.get(nodeId);
9332
9581
  if (!config) {
@@ -9356,7 +9605,7 @@ function useDeviceConfigs(initialConfigs) {
9356
9605
  },
9357
9606
  [configs, updateConfig, updateConfigState]
9358
9607
  );
9359
- const cancelConfig = (0, import_react24.useCallback)(
9608
+ const cancelConfig = (0, import_react25.useCallback)(
9360
9609
  (nodeId) => {
9361
9610
  const config = configs.get(nodeId);
9362
9611
  if (config?.actions.onCancel) {
@@ -9365,7 +9614,7 @@ function useDeviceConfigs(initialConfigs) {
9365
9614
  },
9366
9615
  [configs]
9367
9616
  );
9368
- const validateConfig = (0, import_react24.useCallback)(
9617
+ const validateConfig = (0, import_react25.useCallback)(
9369
9618
  (nodeId) => {
9370
9619
  const config = configs.get(nodeId);
9371
9620
  if (!config) {
@@ -9407,21 +9656,21 @@ function useDeviceConfigs(initialConfigs) {
9407
9656
  },
9408
9657
  [configs, updateConfigState]
9409
9658
  );
9410
- const setConfig = (0, import_react24.useCallback)((config) => {
9659
+ const setConfig = (0, import_react25.useCallback)((config) => {
9411
9660
  setConfigs((prev) => {
9412
9661
  const newMap = new Map(prev);
9413
9662
  newMap.set(config.nodeId, config);
9414
9663
  return newMap;
9415
9664
  });
9416
9665
  }, []);
9417
- const removeConfig = (0, import_react24.useCallback)((nodeId) => {
9666
+ const removeConfig = (0, import_react25.useCallback)((nodeId) => {
9418
9667
  setConfigs((prev) => {
9419
9668
  const newMap = new Map(prev);
9420
9669
  newMap.delete(nodeId);
9421
9670
  return newMap;
9422
9671
  });
9423
9672
  }, []);
9424
- const clearConfigs = (0, import_react24.useCallback)(() => {
9673
+ const clearConfigs = (0, import_react25.useCallback)(() => {
9425
9674
  setConfigs(/* @__PURE__ */ new Map());
9426
9675
  }, []);
9427
9676
  return {
@@ -9443,8 +9692,8 @@ function useDeviceConfigs(initialConfigs) {
9443
9692
  }
9444
9693
 
9445
9694
  // src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
9446
- var import_react25 = __toESM(require("react"), 1);
9447
- var import_jsx_runtime23 = require("react/jsx-runtime");
9695
+ var import_react26 = __toESM(require("react"), 1);
9696
+ var import_jsx_runtime24 = require("react/jsx-runtime");
9448
9697
  function DeviceConfigPanelImpl({
9449
9698
  binding,
9450
9699
  onClose,
@@ -9463,7 +9712,7 @@ function DeviceConfigPanelImpl({
9463
9712
  showBuiltInToast = true,
9464
9713
  embedded = false
9465
9714
  }) {
9466
- const [localValues, setLocalValues] = (0, import_react25.useState)(() => {
9715
+ const [localValues, setLocalValues] = (0, import_react26.useState)(() => {
9467
9716
  if (binding) {
9468
9717
  const values = {};
9469
9718
  binding.parameters.forEach((param) => {
@@ -9473,7 +9722,7 @@ function DeviceConfigPanelImpl({
9473
9722
  }
9474
9723
  return {};
9475
9724
  });
9476
- const [collapsedSections, setCollapsedSections] = (0, import_react25.useState)(() => {
9725
+ const [collapsedSections, setCollapsedSections] = (0, import_react26.useState)(() => {
9477
9726
  const collapsed = /* @__PURE__ */ new Set();
9478
9727
  if (binding?.sections) {
9479
9728
  binding.sections.forEach((section) => {
@@ -9484,9 +9733,9 @@ function DeviceConfigPanelImpl({
9484
9733
  }
9485
9734
  return collapsed;
9486
9735
  });
9487
- const [showToast, setShowToast] = (0, import_react25.useState)(true);
9488
- const [bindingId, setBindingId] = (0, import_react25.useState)(binding?.nodeId || null);
9489
- const lastResultTimestampRef = (0, import_react25.useRef)(0);
9736
+ const [showToast, setShowToast] = (0, import_react26.useState)(true);
9737
+ const [bindingId, setBindingId] = (0, import_react26.useState)(binding?.nodeId || null);
9738
+ const lastResultTimestampRef = (0, import_react26.useRef)(0);
9490
9739
  if (binding && binding.nodeId !== bindingId) {
9491
9740
  const values = {};
9492
9741
  binding.parameters.forEach((param) => {
@@ -9502,7 +9751,7 @@ function DeviceConfigPanelImpl({
9502
9751
  setCollapsedSections(collapsed);
9503
9752
  setBindingId(binding.nodeId);
9504
9753
  }
9505
- (0, import_react25.useEffect)(() => {
9754
+ (0, import_react26.useEffect)(() => {
9506
9755
  const currentTimestamp = binding?.state.lastSaved || 0;
9507
9756
  if (binding?.state.lastSaveResult && currentTimestamp !== lastResultTimestampRef.current) {
9508
9757
  lastResultTimestampRef.current = currentTimestamp;
@@ -9519,7 +9768,7 @@ function DeviceConfigPanelImpl({
9519
9768
  };
9520
9769
  }
9521
9770
  }, [binding?.state.lastSaveResult, binding?.state.lastSaved, toastDuration]);
9522
- const parametersBySection = (0, import_react25.useMemo)(() => {
9771
+ const parametersBySection = (0, import_react26.useMemo)(() => {
9523
9772
  if (!binding) return { _unsectioned: [] };
9524
9773
  const groups = { _unsectioned: [] };
9525
9774
  binding.parameters.forEach((param) => {
@@ -9534,7 +9783,7 @@ function DeviceConfigPanelImpl({
9534
9783
  });
9535
9784
  return groups;
9536
9785
  }, [binding]);
9537
- const sortedSections = (0, import_react25.useMemo)(() => {
9786
+ const sortedSections = (0, import_react26.useMemo)(() => {
9538
9787
  if (!binding?.sections) return [];
9539
9788
  return [...binding.sections].sort((a, b) => (a.order || 0) - (b.order || 0));
9540
9789
  }, [binding]);
@@ -9610,14 +9859,14 @@ function DeviceConfigPanelImpl({
9610
9859
  const value = localValues[param.id];
9611
9860
  const error = binding.state.errors?.[param.id];
9612
9861
  const isDisabled = param.readOnly || param.enabled === false;
9613
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9862
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9614
9863
  "div",
9615
9864
  {
9616
9865
  style: {
9617
9866
  marginBottom: spacing.marginBottom
9618
9867
  },
9619
9868
  children: [
9620
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9869
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9621
9870
  "label",
9622
9871
  {
9623
9872
  style: {
@@ -9632,13 +9881,13 @@ function DeviceConfigPanelImpl({
9632
9881
  },
9633
9882
  children: [
9634
9883
  param.label,
9635
- param.required && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { color: errorColor }, children: " *" }),
9636
- param.unit && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { style: { color: mutedTextColor, fontWeight: "normal" }, children: [
9884
+ param.required && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { color: errorColor }, children: " *" }),
9885
+ param.unit && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { style: { color: mutedTextColor, fontWeight: "normal" }, children: [
9637
9886
  " (",
9638
9887
  param.unit,
9639
9888
  ")"
9640
9889
  ] }),
9641
- param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9890
+ param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9642
9891
  "span",
9643
9892
  {
9644
9893
  "aria-label": "Forced",
@@ -9665,7 +9914,7 @@ function DeviceConfigPanelImpl({
9665
9914
  ]
9666
9915
  }
9667
9916
  ),
9668
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9917
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9669
9918
  "div",
9670
9919
  {
9671
9920
  style: {
@@ -9683,7 +9932,7 @@ function DeviceConfigPanelImpl({
9683
9932
  ]
9684
9933
  }
9685
9934
  ),
9686
- param.description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9935
+ param.description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9687
9936
  "div",
9688
9937
  {
9689
9938
  style: {
@@ -9695,7 +9944,7 @@ function DeviceConfigPanelImpl({
9695
9944
  children: param.description
9696
9945
  }
9697
9946
  ),
9698
- param.type === "number" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9947
+ param.type === "number" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9699
9948
  "input",
9700
9949
  {
9701
9950
  type: "number",
@@ -9719,7 +9968,7 @@ function DeviceConfigPanelImpl({
9719
9968
  }
9720
9969
  }
9721
9970
  ),
9722
- param.type === "string" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9971
+ param.type === "string" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9723
9972
  "input",
9724
9973
  {
9725
9974
  type: "text",
@@ -9740,7 +9989,7 @@ function DeviceConfigPanelImpl({
9740
9989
  }
9741
9990
  }
9742
9991
  ),
9743
- param.type === "boolean" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9992
+ param.type === "boolean" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9744
9993
  "label",
9745
9994
  {
9746
9995
  style: {
@@ -9750,7 +9999,7 @@ function DeviceConfigPanelImpl({
9750
9999
  cursor: isDisabled ? "not-allowed" : "pointer"
9751
10000
  },
9752
10001
  children: [
9753
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10002
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9754
10003
  "input",
9755
10004
  {
9756
10005
  type: "checkbox",
@@ -9764,11 +10013,11 @@ function DeviceConfigPanelImpl({
9764
10013
  }
9765
10014
  }
9766
10015
  ),
9767
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
10016
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
9768
10017
  ]
9769
10018
  }
9770
10019
  ),
9771
- param.type === "select" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10020
+ param.type === "select" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9772
10021
  "select",
9773
10022
  {
9774
10023
  value: value ?? "",
@@ -9786,10 +10035,10 @@ function DeviceConfigPanelImpl({
9786
10035
  borderRadius: "2px",
9787
10036
  outline: "none"
9788
10037
  },
9789
- children: param.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: option.value, children: option.label }, option.value))
10038
+ children: param.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: option.value, children: option.label }, option.value))
9790
10039
  }
9791
10040
  ),
9792
- error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10041
+ error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9793
10042
  "div",
9794
10043
  {
9795
10044
  style: {
@@ -9809,7 +10058,7 @@ function DeviceConfigPanelImpl({
9809
10058
  const renderSection = (section) => {
9810
10059
  const params = parametersBySection[section.id] || [];
9811
10060
  const isCollapsed = collapsedSections.has(section.id);
9812
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10061
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9813
10062
  "div",
9814
10063
  {
9815
10064
  style: {
@@ -9819,7 +10068,7 @@ function DeviceConfigPanelImpl({
9819
10068
  backgroundColor: surfaceColor
9820
10069
  },
9821
10070
  children: [
9822
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10071
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9823
10072
  "div",
9824
10073
  {
9825
10074
  onClick: () => section.collapsible && toggleSection(section.id),
@@ -9832,8 +10081,8 @@ function DeviceConfigPanelImpl({
9832
10081
  alignItems: "center"
9833
10082
  },
9834
10083
  children: [
9835
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
9836
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10084
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
10085
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9837
10086
  "div",
9838
10087
  {
9839
10088
  style: {
@@ -9845,12 +10094,12 @@ function DeviceConfigPanelImpl({
9845
10094
  letterSpacing: "0.5px"
9846
10095
  },
9847
10096
  children: [
9848
- section.icon && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { marginRight: "8px" }, children: section.icon }),
10097
+ section.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { marginRight: "8px" }, children: section.icon }),
9849
10098
  section.title
9850
10099
  ]
9851
10100
  }
9852
10101
  ),
9853
- section.description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10102
+ section.description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9854
10103
  "div",
9855
10104
  {
9856
10105
  style: {
@@ -9863,11 +10112,11 @@ function DeviceConfigPanelImpl({
9863
10112
  }
9864
10113
  )
9865
10114
  ] }),
9866
- section.collapsible && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
10115
+ section.collapsible && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
9867
10116
  ]
9868
10117
  }
9869
10118
  ),
9870
- !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
10119
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
9871
10120
  ]
9872
10121
  },
9873
10122
  section.id
@@ -9926,9 +10175,9 @@ function DeviceConfigPanelImpl({
9926
10175
  const showSave = binding.display?.showSave !== false && binding.actions.onSave;
9927
10176
  const showReset = binding.display?.showReset !== false && binding.actions.onReset;
9928
10177
  const showCancel = binding.display?.showCancel !== false;
9929
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
9930
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
9931
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10178
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
10179
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
10180
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9932
10181
  "div",
9933
10182
  {
9934
10183
  style: {
@@ -9940,8 +10189,8 @@ function DeviceConfigPanelImpl({
9940
10189
  borderBottom: `2px solid ${borderColor}`
9941
10190
  },
9942
10191
  children: [
9943
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
9944
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10192
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
10193
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9945
10194
  "h3",
9946
10195
  {
9947
10196
  style: {
@@ -9961,7 +10210,7 @@ function DeviceConfigPanelImpl({
9961
10210
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
9962
10211
  }
9963
10212
  ),
9964
- binding.display?.subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10213
+ binding.display?.subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9965
10214
  "div",
9966
10215
  {
9967
10216
  style: {
@@ -9974,8 +10223,8 @@ function DeviceConfigPanelImpl({
9974
10223
  }
9975
10224
  )
9976
10225
  ] }),
9977
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
9978
- showControlsButton && onOpenControls && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10226
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
10227
+ showControlsButton && onOpenControls && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9979
10228
  "button",
9980
10229
  {
9981
10230
  onClick: onOpenControls,
@@ -9998,7 +10247,7 @@ function DeviceConfigPanelImpl({
9998
10247
  children: "CTRL"
9999
10248
  }
10000
10249
  ),
10001
- onUndock && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10250
+ onUndock && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10002
10251
  "button",
10003
10252
  {
10004
10253
  onClick: onUndock,
@@ -10019,7 +10268,7 @@ function DeviceConfigPanelImpl({
10019
10268
  children: undockIcon
10020
10269
  }
10021
10270
  ),
10022
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10271
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10023
10272
  "button",
10024
10273
  {
10025
10274
  onClick: onClose,
@@ -10042,7 +10291,7 @@ function DeviceConfigPanelImpl({
10042
10291
  ]
10043
10292
  }
10044
10293
  ),
10045
- binding.state.isDirty && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10294
+ binding.state.isDirty && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10046
10295
  "div",
10047
10296
  {
10048
10297
  style: {
@@ -10057,11 +10306,11 @@ function DeviceConfigPanelImpl({
10057
10306
  children: "Unsaved changes"
10058
10307
  }
10059
10308
  ),
10060
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
10309
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
10061
10310
  /* Render unsectioned parameters */
10062
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
10311
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
10063
10312
  ) }),
10064
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10313
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
10065
10314
  "div",
10066
10315
  {
10067
10316
  style: {
@@ -10072,7 +10321,7 @@ function DeviceConfigPanelImpl({
10072
10321
  flexWrap: "wrap"
10073
10322
  },
10074
10323
  children: [
10075
- showApply && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10324
+ showApply && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10076
10325
  "button",
10077
10326
  {
10078
10327
  onClick: handleApply,
@@ -10095,7 +10344,7 @@ function DeviceConfigPanelImpl({
10095
10344
  children: binding.state.isSaving ? "Applying..." : "Apply"
10096
10345
  }
10097
10346
  ),
10098
- showSave && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10347
+ showSave && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10099
10348
  "button",
10100
10349
  {
10101
10350
  onClick: handleSave,
@@ -10118,7 +10367,7 @@ function DeviceConfigPanelImpl({
10118
10367
  children: binding.state.isSaving ? "Saving..." : "Save"
10119
10368
  }
10120
10369
  ),
10121
- showReset && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10370
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10122
10371
  "button",
10123
10372
  {
10124
10373
  onClick: handleReset,
@@ -10141,7 +10390,7 @@ function DeviceConfigPanelImpl({
10141
10390
  children: "Reset"
10142
10391
  }
10143
10392
  ),
10144
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10393
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10145
10394
  "button",
10146
10395
  {
10147
10396
  onClick: handleCancel,
@@ -10168,7 +10417,7 @@ function DeviceConfigPanelImpl({
10168
10417
  }
10169
10418
  )
10170
10419
  ] }),
10171
- binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10420
+ binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10172
10421
  "div",
10173
10422
  {
10174
10423
  style: {
@@ -10190,10 +10439,10 @@ function DeviceConfigPanelImpl({
10190
10439
  )
10191
10440
  ] });
10192
10441
  }
10193
- var DeviceConfigPanel = import_react25.default.memo(DeviceConfigPanelImpl);
10442
+ var DeviceConfigPanel = import_react26.default.memo(DeviceConfigPanelImpl);
10194
10443
 
10195
10444
  // src/diagram/hooks/useSimulation.ts
10196
- var import_react26 = require("react");
10445
+ var import_react27 = require("react");
10197
10446
  function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10198
10447
  const {
10199
10448
  interval = 2e3,
@@ -10204,7 +10453,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10204
10453
  historyLength = 10,
10205
10454
  generateValue
10206
10455
  } = options;
10207
- (0, import_react26.useEffect)(() => {
10456
+ (0, import_react27.useEffect)(() => {
10208
10457
  if (!enabled) return;
10209
10458
  const intervalId = setInterval(() => {
10210
10459
  const updates = [];
@@ -10274,6 +10523,8 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10274
10523
  FooterPanel,
10275
10524
  FullscreenContainer,
10276
10525
  FullscreenWorkspace,
10526
+ ISA_UNKNOWN,
10527
+ ISA_UNKNOWN_DARK,
10277
10528
  LeftPanel,
10278
10529
  LeftToggleButton,
10279
10530
  LegacyValueEntry,
@@ -10296,8 +10547,9 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10296
10547
  ThemeProvider,
10297
10548
  ThemeToggle,
10298
10549
  TrendLine,
10299
- UNKNOWN_MARK_COLOR,
10300
- UNKNOWN_MARK_COLOR_DARK,
10550
+ UNKNOWN_GLYPH_RING_DASH,
10551
+ UNKNOWN_STATUS_GLYPH_COLOR_VAR,
10552
+ UnknownStatusGlyph,
10301
10553
  ValueEntry,
10302
10554
  ZoomButton,
10303
10555
  ZoomControls,
@@ -10309,14 +10561,19 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10309
10561
  generateRoutePoints,
10310
10562
  getAppearanceDefaults,
10311
10563
  getAppearanceSchema,
10564
+ getAvailableBadgeGlyphs,
10312
10565
  getAvailableSymbols,
10566
+ getBadgeGlyph,
10313
10567
  getPortWorldPosition,
10314
10568
  getSymbolDefinition,
10315
10569
  importDiagram,
10316
10570
  mockSymbolLibrary,
10317
10571
  nodeHasPort,
10572
+ normalizeDeviceStatus,
10318
10573
  overlayStyles,
10319
10574
  readAppearanceValue,
10575
+ registerBadgeGlyph,
10576
+ registerBadgeGlyphs,
10320
10577
  registerSymbol,
10321
10578
  registerSymbols,
10322
10579
  resolvePresetColor,