@procaaso/alphinity-ui-components 1.11.0 → 1.12.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,
@@ -91,6 +94,7 @@ __export(index_exports, {
91
94
  importDiagram: () => importDiagram,
92
95
  mockSymbolLibrary: () => mockSymbolLibrary,
93
96
  nodeHasPort: () => nodeHasPort,
97
+ normalizeDeviceStatus: () => normalizeDeviceStatus,
94
98
  overlayStyles: () => overlayStyles,
95
99
  readAppearanceValue: () => readAppearanceValue,
96
100
  registerSymbol: () => registerSymbol,
@@ -382,6 +386,16 @@ var ValueEntry = ({
382
386
  var import_react3 = require("react");
383
387
 
384
388
  // src/theme/statusColors.ts
389
+ var ISA_UNKNOWN = {
390
+ fg: "#4f4f8a",
391
+ bg: "#ebebf5",
392
+ border: "#8f8fc2"
393
+ };
394
+ var ISA_UNKNOWN_DARK = {
395
+ fg: "#b9bbdb",
396
+ bg: "#23263a",
397
+ border: "#6f74a3"
398
+ };
385
399
  var DEFAULT_STATUS_COLORS = {
386
400
  normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
387
401
  warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
@@ -389,7 +403,8 @@ var DEFAULT_STATUS_COLORS = {
389
403
  fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
390
404
  off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
391
405
  starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
392
- stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
406
+ stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
407
+ unknown: { fill: ISA_UNKNOWN.bg, stroke: ISA_UNKNOWN.border, bg: ISA_UNKNOWN.bg, text: ISA_UNKNOWN.fg, border: ISA_UNKNOWN.border }
393
408
  };
394
409
  var FORCED_MARK_COLOR = {
395
410
  fill: "#ede9fe",
@@ -398,27 +413,16 @@ var FORCED_MARK_COLOR = {
398
413
  text: "#5b21b6",
399
414
  border: "#7c3aed"
400
415
  };
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
416
  var STATUS_ALIASES = {
416
417
  running: "normal",
417
418
  stopped: "off"
418
419
  };
419
- function resolveStatusColor(status, customMap) {
420
+ function normalizeDeviceStatus(status) {
420
421
  const raw = (status || "off").toLowerCase();
421
- const key = STATUS_ALIASES[raw] ?? raw;
422
+ return STATUS_ALIASES[raw] ?? raw;
423
+ }
424
+ function resolveStatusColor(status, customMap) {
425
+ const key = normalizeDeviceStatus(status);
422
426
  const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
423
427
  const overrides = customMap?.[key];
424
428
  if (!overrides) return defaults;
@@ -858,7 +862,79 @@ var ControlPanel = ({
858
862
  };
859
863
 
860
864
  // src/components/StatusIndicator/StatusIndicator.tsx
865
+ var import_react5 = __toESM(require("react"), 1);
866
+
867
+ // src/theme/unknownStatusGlyph.tsx
861
868
  var import_jsx_runtime6 = require("react/jsx-runtime");
869
+ var UNKNOWN_STATUS_GLYPH_COLOR_VAR = "--ui-status-indicator-unknown-glyph-color";
870
+ var UNKNOWN_GLYPH_STROKE_WEIGHTS = {
871
+ small: { ring: 4.5, ringDash: "7 6", mark: 5, dot: 2.9 },
872
+ medium: { ring: 4, ringDash: "6.5 5.5", mark: 4.5, dot: 2.7 },
873
+ large: { ring: 3.5, ringDash: "6.5 5.5", mark: 4, dot: 2.5 }
874
+ };
875
+ var UNKNOWN_GLYPH_RING_DASH = UNKNOWN_GLYPH_STROKE_WEIGHTS.medium.ringDash;
876
+ var UNKNOWN_GLYPH_FILL_STYLE = {
877
+ position: "absolute",
878
+ inset: 0,
879
+ width: "100%",
880
+ height: "100%"
881
+ };
882
+ function unknownGlyphHostStyle(isUnknown, style) {
883
+ return isUnknown ? { position: "relative", ...style } : style;
884
+ }
885
+ function UnknownStatusGlyph({
886
+ size = "medium",
887
+ counterRotate = false,
888
+ style,
889
+ ...rest
890
+ }) {
891
+ const weights = UNKNOWN_GLYPH_STROKE_WEIGHTS[size];
892
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
893
+ "svg",
894
+ {
895
+ viewBox: "0 0 48 48",
896
+ "aria-hidden": "true",
897
+ focusable: "false",
898
+ style: {
899
+ display: "block",
900
+ color: `var(${UNKNOWN_STATUS_GLYPH_COLOR_VAR}, currentColor)`,
901
+ transform: counterRotate ? "rotate(-45deg)" : void 0,
902
+ ...style
903
+ },
904
+ ...rest,
905
+ children: [
906
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
907
+ "circle",
908
+ {
909
+ cx: 24,
910
+ cy: 24,
911
+ r: 20,
912
+ fill: "none",
913
+ stroke: "currentColor",
914
+ strokeDasharray: weights.ringDash,
915
+ strokeLinecap: "round",
916
+ strokeWidth: weights.ring
917
+ }
918
+ ),
919
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
920
+ "path",
921
+ {
922
+ d: "M18.4 18.6a5.8 5.8 0 1 1 6.4 8.1v3.1",
923
+ fill: "none",
924
+ stroke: "currentColor",
925
+ strokeLinecap: "round",
926
+ strokeLinejoin: "round",
927
+ strokeWidth: weights.mark
928
+ }
929
+ ),
930
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: 24.6, cy: 35.4, r: weights.dot, fill: "currentColor" })
931
+ ]
932
+ }
933
+ );
934
+ }
935
+
936
+ // src/components/StatusIndicator/StatusIndicator.tsx
937
+ var import_jsx_runtime7 = require("react/jsx-runtime");
862
938
  var getStatusDescription = (status) => {
863
939
  switch (status) {
864
940
  case "alarm":
@@ -873,10 +949,23 @@ var getStatusDescription = (status) => {
873
949
  return "Operating normally";
874
950
  case "off":
875
951
  return "Equipment is off";
952
+ case "unknown":
953
+ return "Device state cannot be confirmed. Check the link or the wiring.";
876
954
  default:
877
955
  return "";
878
956
  }
879
957
  };
958
+ var visuallyHiddenStyle = {
959
+ position: "absolute",
960
+ width: "1px",
961
+ height: "1px",
962
+ padding: 0,
963
+ margin: "-1px",
964
+ overflow: "hidden",
965
+ clip: "rect(0, 0, 0, 0)",
966
+ whiteSpace: "nowrap",
967
+ border: 0
968
+ };
880
969
  var StatusIndicator = ({
881
970
  status,
882
971
  size = "medium",
@@ -889,17 +978,25 @@ var StatusIndicator = ({
889
978
  forced = false,
890
979
  realValue,
891
980
  className = "",
981
+ style,
982
+ "aria-describedby": consumerDescribedBy,
983
+ children,
892
984
  ...props
893
985
  }) => {
986
+ const generatedDescriptionId = `${import_react5.default.useId()}-status-description`;
894
987
  if (!visible) {
895
988
  return null;
896
989
  }
990
+ const describedBy = consumerDescribedBy ? `${consumerDescribedBy} ${generatedDescriptionId}` : generatedDescriptionId;
991
+ const description = getStatusDescription(status);
897
992
  const baseClass = "ui-status-indicator";
898
993
  const statusClass = status ? `ui-status-indicator--${status}` : "";
899
994
  const sizeClass = size ? `ui-status-indicator--${size}` : "";
900
995
  const shapeClass = shape ? `ui-status-indicator--${shape}` : "";
901
996
  const animationClass = animation ? `ui-status-indicator--${animation}` : "";
902
997
  const ledClass = led ? "ui-status-indicator--led" : "";
998
+ const isUnknown = status === "unknown";
999
+ const indicatorStyle = unknownGlyphHostStyle(isUnknown, style);
903
1000
  const getContainerLayout = () => {
904
1001
  switch (labelPosition) {
905
1002
  case "left":
@@ -916,19 +1013,20 @@ var StatusIndicator = ({
916
1013
  };
917
1014
  const forcedClass = forced ? "ui-status-indicator--forced" : "";
918
1015
  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: [
1016
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: getContainerLayout(), children: [
1017
+ label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-label", children: label }),
1018
+ hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
922
1019
  "REAL ",
923
1020
  realValue
924
1021
  ] }),
925
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1022
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
1023
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
927
1024
  "span",
928
1025
  {
929
1026
  role: "status",
930
1027
  "aria-label": label || `Status: ${status}`,
931
- "aria-description": getStatusDescription(status),
1028
+ "aria-description": description,
1029
+ "aria-describedby": describedBy,
932
1030
  "data-status": status,
933
1031
  "data-forced": forced,
934
1032
  className: `
@@ -941,13 +1039,26 @@ var StatusIndicator = ({
941
1039
  ${forcedClass}
942
1040
  ${className}
943
1041
  `.replace(/\s+/g, " ").trim(),
944
- ...props
1042
+ style: indicatorStyle,
1043
+ ...props,
1044
+ children: [
1045
+ isUnknown && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1046
+ UnknownStatusGlyph,
1047
+ {
1048
+ size,
1049
+ counterRotate: shape === "diamond",
1050
+ style: UNKNOWN_GLYPH_FILL_STYLE
1051
+ }
1052
+ ),
1053
+ children,
1054
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { id: generatedDescriptionId, style: visuallyHiddenStyle, children: description })
1055
+ ]
945
1056
  }
946
1057
  ),
947
- forced && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
1058
+ forced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
948
1059
  ] }),
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: [
1060
+ label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ui-status-indicator-label", children: label }),
1061
+ hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
951
1062
  "REAL ",
952
1063
  realValue
953
1064
  ] })
@@ -955,7 +1066,7 @@ var StatusIndicator = ({
955
1066
  };
956
1067
 
957
1068
  // src/components/NodeControlsPanel/NodeControlsPanel.tsx
958
- var import_jsx_runtime7 = require("react/jsx-runtime");
1069
+ var import_jsx_runtime8 = require("react/jsx-runtime");
959
1070
  var NodeControlsPanel = ({
960
1071
  config,
961
1072
  onClose,
@@ -1028,8 +1139,8 @@ var NodeControlsPanel = ({
1028
1139
  overflowY: "auto",
1029
1140
  flex: 1
1030
1141
  };
1031
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1032
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1142
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1143
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1033
1144
  "div",
1034
1145
  {
1035
1146
  style: {
@@ -1042,16 +1153,16 @@ var NodeControlsPanel = ({
1042
1153
  onClick: onClose
1043
1154
  }
1044
1155
  ),
1045
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1156
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1046
1157
  "div",
1047
1158
  {
1048
1159
  className: `node-controls-panel ${touchClass} ${className}`.trim(),
1049
1160
  style: containerStyle,
1050
1161
  ...props,
1051
1162
  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)(
1163
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: headerStyle, children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: titleStyle, children: config.title }),
1165
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1055
1166
  "button",
1056
1167
  {
1057
1168
  style: closeButtonStyle,
@@ -1069,7 +1180,7 @@ var NodeControlsPanel = ({
1069
1180
  }
1070
1181
  )
1071
1182
  ] }),
1072
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: contentStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1183
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: contentStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1073
1184
  ControlPanel,
1074
1185
  {
1075
1186
  title: config.nodeId,
@@ -1098,7 +1209,7 @@ var NodeControlsPanel = ({
1098
1209
  ]
1099
1210
  }
1100
1211
  ),
1101
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
1212
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
1102
1213
  @keyframes slideUp {
1103
1214
  from {
1104
1215
  transform: translateY(100%);
@@ -1144,8 +1255,8 @@ var NodeControlsPanel = ({
1144
1255
  };
1145
1256
 
1146
1257
  // src/components/DeviceControlPanel/DeviceControlPanel.tsx
1147
- var import_react5 = __toESM(require("react"), 1);
1148
- var import_jsx_runtime8 = require("react/jsx-runtime");
1258
+ var import_react6 = __toESM(require("react"), 1);
1259
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1149
1260
  function DeviceControlPanelImpl({
1150
1261
  binding,
1151
1262
  onClose,
@@ -1173,11 +1284,11 @@ function DeviceControlPanelImpl({
1173
1284
  showBuiltInToast = true,
1174
1285
  embedded = false
1175
1286
  }) {
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)(() => {
1287
+ const [localParameterValues, setLocalParameterValues] = (0, import_react6.useState)({});
1288
+ const [showModeModal, setShowModeModal] = (0, import_react6.useState)(false);
1289
+ const [pendingMode, setPendingMode] = (0, import_react6.useState)(null);
1290
+ const [showToast, setShowToast] = (0, import_react6.useState)(true);
1291
+ (0, import_react6.useEffect)(() => {
1181
1292
  if (binding) {
1182
1293
  const currentParams2 = binding.parameters[binding.state.currentMode] || [];
1183
1294
  const values = {};
@@ -1187,7 +1298,7 @@ function DeviceControlPanelImpl({
1187
1298
  setLocalParameterValues(values);
1188
1299
  }
1189
1300
  }, [binding, binding?.state.currentMode]);
1190
- (0, import_react5.useEffect)(() => {
1301
+ (0, import_react6.useEffect)(() => {
1191
1302
  if (binding?.state.lastCommandResult) {
1192
1303
  setShowToast(true);
1193
1304
  const timer = setTimeout(() => {
@@ -1225,6 +1336,7 @@ function DeviceControlPanelImpl({
1225
1336
  const selectedColor = "#b4d0fe";
1226
1337
  const statusEntry = resolveStatusColor(binding.state.status, binding.theme?.statusColors);
1227
1338
  const statusColor = statusEntry.bg;
1339
+ const isUnknownStatus = normalizeDeviceStatus(binding.state.status) === "unknown";
1228
1340
  const handleModeChange = (mode) => {
1229
1341
  onModeChange?.(mode);
1230
1342
  };
@@ -1279,9 +1391,9 @@ function DeviceControlPanelImpl({
1279
1391
  ...binding.display?.style
1280
1392
  };
1281
1393
  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)(
1394
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1395
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
1396
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1285
1397
  "div",
1286
1398
  {
1287
1399
  style: {
@@ -1293,8 +1405,8 @@ function DeviceControlPanelImpl({
1293
1405
  borderBottom: `2px solid ${borderColor}`
1294
1406
  },
1295
1407
  children: [
1296
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1297
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1408
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1409
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1298
1410
  "h3",
1299
1411
  {
1300
1412
  style: {
@@ -1314,7 +1426,7 @@ function DeviceControlPanelImpl({
1314
1426
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
1315
1427
  }
1316
1428
  ),
1317
- binding.deviceType && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1429
+ binding.deviceType && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1318
1430
  "div",
1319
1431
  {
1320
1432
  style: {
@@ -1327,8 +1439,8 @@ function DeviceControlPanelImpl({
1327
1439
  }
1328
1440
  )
1329
1441
  ] }),
1330
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1331
- showConfigButton && onOpenConfig && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1442
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1443
+ showConfigButton && onOpenConfig && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1332
1444
  "button",
1333
1445
  {
1334
1446
  onClick: onOpenConfig,
@@ -1349,7 +1461,7 @@ function DeviceControlPanelImpl({
1349
1461
  children: "\u2699"
1350
1462
  }
1351
1463
  ),
1352
- onUndock && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1464
+ onUndock && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1353
1465
  "button",
1354
1466
  {
1355
1467
  onClick: onUndock,
@@ -1370,7 +1482,7 @@ function DeviceControlPanelImpl({
1370
1482
  children: undockIcon
1371
1483
  }
1372
1484
  ),
1373
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1485
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1374
1486
  "button",
1375
1487
  {
1376
1488
  onClick: onClose,
@@ -1393,7 +1505,7 @@ function DeviceControlPanelImpl({
1393
1505
  ]
1394
1506
  }
1395
1507
  ),
1396
- binding.state.status && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1508
+ binding.state.status && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1397
1509
  "div",
1398
1510
  {
1399
1511
  style: {
@@ -1407,7 +1519,7 @@ function DeviceControlPanelImpl({
1407
1519
  marginBottom: spacing.marginBottom
1408
1520
  },
1409
1521
  children: [
1410
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1522
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1411
1523
  "div",
1412
1524
  {
1413
1525
  style: {
@@ -1415,12 +1527,17 @@ function DeviceControlPanelImpl({
1415
1527
  height: "10px",
1416
1528
  borderRadius: "50%",
1417
1529
  backgroundColor: statusColor,
1418
- border: "1px solid #333"
1419
- }
1530
+ border: "1px solid #333",
1531
+ // The shared helper positions this dot only while it shows
1532
+ // the unknown marker. The glyph then fills the dot with an
1533
+ // absolute inset, the same pattern StatusIndicator uses.
1534
+ ...unknownGlyphHostStyle(isUnknownStatus)
1535
+ },
1536
+ children: isUnknownStatus && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UnknownStatusGlyph, { size: "small", style: UNKNOWN_GLYPH_FILL_STYLE })
1420
1537
  }
1421
1538
  ),
1422
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1 }, children: [
1423
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1539
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1 }, children: [
1540
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1424
1541
  "div",
1425
1542
  {
1426
1543
  style: {
@@ -1434,7 +1551,7 @@ function DeviceControlPanelImpl({
1434
1551
  children: binding.state.status
1435
1552
  }
1436
1553
  ),
1437
- binding.state.statusMessage && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1554
+ binding.state.statusMessage && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1438
1555
  "div",
1439
1556
  {
1440
1557
  style: {
@@ -1447,28 +1564,36 @@ function DeviceControlPanelImpl({
1447
1564
  }
1448
1565
  )
1449
1566
  ] }),
1450
- binding.state.isRunning !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1567
+ binding.state.isRunning !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1451
1568
  "div",
1452
1569
  {
1453
1570
  style: {
1454
1571
  padding: "4px 10px",
1455
- backgroundColor: binding.state.isRunning ? selectedColor : surfaceColor,
1456
- border: `1px solid ${borderColor}`,
1572
+ // This badge shows the last published isRunning value. It
1573
+ // never re-derives that value here. When status is
1574
+ // unknown, the value may be stale. Muted colors carry that
1575
+ // warning alongside the word, so color is not the only
1576
+ // channel and the wording is not the only channel either.
1577
+ backgroundColor: isUnknownStatus ? statusEntry.bg : binding.state.isRunning ? selectedColor : surfaceColor,
1578
+ border: `1px solid ${isUnknownStatus ? statusEntry.border : borderColor}`,
1457
1579
  borderRadius: "2px",
1458
1580
  fontSize: "10px",
1459
1581
  fontWeight: 600,
1460
1582
  fontFamily: "Arial, sans-serif",
1461
1583
  letterSpacing: "0.5px",
1462
- color: textColor
1584
+ color: isUnknownStatus ? statusEntry.text : textColor
1463
1585
  },
1464
- children: binding.state.isRunning ? "RUNNING" : "STOPPED"
1586
+ children: [
1587
+ binding.state.isRunning ? "RUNNING" : "STOPPED",
1588
+ isUnknownStatus && " (unconfirmed)"
1589
+ ]
1465
1590
  }
1466
1591
  )
1467
1592
  ]
1468
1593
  }
1469
1594
  ),
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)(
1595
+ binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: "16px" }, children: [
1596
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1472
1597
  "label",
1473
1598
  {
1474
1599
  style: {
@@ -1484,7 +1609,7 @@ function DeviceControlPanelImpl({
1484
1609
  children: "Mode"
1485
1610
  }
1486
1611
  ),
1487
- modeSelectionStyle === "dropdown" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1612
+ modeSelectionStyle === "dropdown" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1488
1613
  "select",
1489
1614
  {
1490
1615
  value: currentMode,
@@ -1505,10 +1630,10 @@ function DeviceControlPanelImpl({
1505
1630
  paddingRight: "12px",
1506
1631
  cursor: "pointer"
1507
1632
  },
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))
1633
+ 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
1634
  }
1510
- ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1511
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1635
+ ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1636
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1512
1637
  "div",
1513
1638
  {
1514
1639
  onClick: () => {
@@ -1531,12 +1656,12 @@ function DeviceControlPanelImpl({
1531
1656
  alignItems: "center"
1532
1657
  },
1533
1658
  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" })
1659
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1660
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1536
1661
  ]
1537
1662
  }
1538
1663
  ),
1539
- showModeModal && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1664
+ showModeModal && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1540
1665
  "div",
1541
1666
  {
1542
1667
  style: {
@@ -1555,7 +1680,7 @@ function DeviceControlPanelImpl({
1555
1680
  setShowModeModal(false);
1556
1681
  setPendingMode(null);
1557
1682
  },
1558
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1683
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1559
1684
  "div",
1560
1685
  {
1561
1686
  onClick: (e) => e.stopPropagation(),
@@ -1568,7 +1693,7 @@ function DeviceControlPanelImpl({
1568
1693
  border: `2px solid ${borderColor}`
1569
1694
  },
1570
1695
  children: [
1571
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1696
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1572
1697
  "h3",
1573
1698
  {
1574
1699
  style: {
@@ -1581,7 +1706,7 @@ function DeviceControlPanelImpl({
1581
1706
  children: "Select Mode"
1582
1707
  }
1583
1708
  ),
1584
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1709
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1585
1710
  "div",
1586
1711
  {
1587
1712
  style: {
@@ -1595,7 +1720,7 @@ function DeviceControlPanelImpl({
1595
1720
  children: binding.display?.title || binding.deviceName || binding.tag || binding.nodeId
1596
1721
  }
1597
1722
  ),
1598
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1723
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1599
1724
  "select",
1600
1725
  {
1601
1726
  value: pendingMode || currentMode,
@@ -1617,7 +1742,7 @@ function DeviceControlPanelImpl({
1617
1742
  paddingRight: "12px",
1618
1743
  cursor: "pointer"
1619
1744
  },
1620
- children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1745
+ children: binding.modes.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1621
1746
  "option",
1622
1747
  {
1623
1748
  value: mode.value,
@@ -1632,7 +1757,7 @@ function DeviceControlPanelImpl({
1632
1757
  const selectedMode = binding.modes.find(
1633
1758
  (m) => m.value === (pendingMode || currentMode)
1634
1759
  );
1635
- return selectedMode?.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1760
+ return selectedMode?.description ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1636
1761
  "div",
1637
1762
  {
1638
1763
  style: {
@@ -1650,8 +1775,8 @@ function DeviceControlPanelImpl({
1650
1775
  }
1651
1776
  ) : null;
1652
1777
  })(),
1653
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [
1654
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1778
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [
1779
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1655
1780
  "button",
1656
1781
  {
1657
1782
  onClick: () => {
@@ -1679,7 +1804,7 @@ function DeviceControlPanelImpl({
1679
1804
  children: "Confirm"
1680
1805
  }
1681
1806
  ),
1682
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1807
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1683
1808
  "button",
1684
1809
  {
1685
1810
  onClick: () => {
@@ -1709,7 +1834,7 @@ function DeviceControlPanelImpl({
1709
1834
  )
1710
1835
  }
1711
1836
  )
1712
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1837
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1713
1838
  "div",
1714
1839
  {
1715
1840
  style: {
@@ -1725,7 +1850,7 @@ function DeviceControlPanelImpl({
1725
1850
  children: binding.modes.map((mode) => {
1726
1851
  const isSelected = mode.value === currentMode;
1727
1852
  const isEnabled = mode.enabled !== false;
1728
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1853
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1729
1854
  "button",
1730
1855
  {
1731
1856
  onClick: () => isEnabled && handleModeChange(mode.value),
@@ -1755,8 +1880,8 @@ function DeviceControlPanelImpl({
1755
1880
  }
1756
1881
  )
1757
1882
  ] }),
1758
- currentParams.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginBottom: spacing.marginBottom }, children: [
1759
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1883
+ currentParams.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginBottom: spacing.marginBottom }, children: [
1884
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1760
1885
  "label",
1761
1886
  {
1762
1887
  style: {
@@ -1772,7 +1897,7 @@ function DeviceControlPanelImpl({
1772
1897
  children: "Parameters"
1773
1898
  }
1774
1899
  ),
1775
- currentParams.map((param) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1900
+ currentParams.map((param) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1776
1901
  "div",
1777
1902
  {
1778
1903
  style: {
@@ -1783,7 +1908,7 @@ function DeviceControlPanelImpl({
1783
1908
  borderRadius: "6px"
1784
1909
  },
1785
1910
  children: [
1786
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1911
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1787
1912
  "div",
1788
1913
  {
1789
1914
  style: {
@@ -1792,7 +1917,7 @@ function DeviceControlPanelImpl({
1792
1917
  marginBottom: spacing.gap
1793
1918
  },
1794
1919
  children: [
1795
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1920
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1796
1921
  "span",
1797
1922
  {
1798
1923
  style: {
@@ -1808,7 +1933,7 @@ function DeviceControlPanelImpl({
1808
1933
  },
1809
1934
  children: [
1810
1935
  param.label,
1811
- param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1936
+ param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1812
1937
  "span",
1813
1938
  {
1814
1939
  "aria-label": "Forced",
@@ -1831,7 +1956,7 @@ function DeviceControlPanelImpl({
1831
1956
  ]
1832
1957
  }
1833
1958
  ),
1834
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1959
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1835
1960
  "span",
1836
1961
  {
1837
1962
  style: {
@@ -1843,14 +1968,14 @@ function DeviceControlPanelImpl({
1843
1968
  children: [
1844
1969
  localParameterValues[param.id] ?? param.value,
1845
1970
  " ",
1846
- param.unit && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1971
+ param.unit && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1847
1972
  ]
1848
1973
  }
1849
1974
  )
1850
1975
  ]
1851
1976
  }
1852
1977
  ),
1853
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1978
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1854
1979
  "div",
1855
1980
  {
1856
1981
  style: {
@@ -1871,7 +1996,7 @@ function DeviceControlPanelImpl({
1871
1996
  ]
1872
1997
  }
1873
1998
  ),
1874
- param.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1999
+ param.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1875
2000
  "button",
1876
2001
  {
1877
2002
  onClick: () => {
@@ -1896,7 +2021,7 @@ function DeviceControlPanelImpl({
1896
2021
  },
1897
2022
  children: localParameterValues[param.id] ? "ON" : "OFF"
1898
2023
  }
1899
- ) : param.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2024
+ ) : param.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1900
2025
  "select",
1901
2026
  {
1902
2027
  value: localParameterValues[param.id] || param.value,
@@ -1917,12 +2042,12 @@ function DeviceControlPanelImpl({
1917
2042
  fontFamily: "monospace",
1918
2043
  cursor: "pointer"
1919
2044
  },
1920
- children: param.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
2045
+ children: param.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1921
2046
  }
1922
2047
  ) : onParameterActivate && !param.readOnly ? (
1923
2048
  // Tappable value: defer editing to the consumer's editor (e.g. a
1924
2049
  // numpad dialog). Commit happens via onParameterChange.
1925
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2050
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1926
2051
  "button",
1927
2052
  {
1928
2053
  type: "button",
@@ -1949,7 +2074,7 @@ function DeviceControlPanelImpl({
1949
2074
  ]
1950
2075
  }
1951
2076
  )
1952
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2077
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1953
2078
  "input",
1954
2079
  {
1955
2080
  type: param.type === "number" ? "number" : "text",
@@ -1982,8 +2107,8 @@ function DeviceControlPanelImpl({
1982
2107
  param.id
1983
2108
  ))
1984
2109
  ] }),
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)(
2110
+ 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: [
2111
+ activeCapabilities?.canStart && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1987
2112
  "button",
1988
2113
  {
1989
2114
  onClick: onStart,
@@ -2004,7 +2129,7 @@ function DeviceControlPanelImpl({
2004
2129
  children: startPending ? "STARTING\u2026" : "START"
2005
2130
  }
2006
2131
  ),
2007
- activeCapabilities?.canStop && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2132
+ activeCapabilities?.canStop && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2008
2133
  "button",
2009
2134
  {
2010
2135
  onClick: onStop,
@@ -2026,9 +2151,9 @@ function DeviceControlPanelImpl({
2026
2151
  }
2027
2152
  )
2028
2153
  ] }),
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) => {
2154
+ 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
2155
  const actionDisabled = action.disabled === true;
2031
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2156
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2032
2157
  "button",
2033
2158
  {
2034
2159
  onClick: () => {
@@ -2054,7 +2179,7 @@ function DeviceControlPanelImpl({
2054
2179
  transition: "all 0.15s"
2055
2180
  },
2056
2181
  children: [
2057
- action.icon && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { marginRight: "6px" }, children: action.icon }),
2182
+ action.icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { marginRight: "6px" }, children: action.icon }),
2058
2183
  action.label
2059
2184
  ]
2060
2185
  },
@@ -2062,7 +2187,7 @@ function DeviceControlPanelImpl({
2062
2187
  );
2063
2188
  }) })
2064
2189
  ] }),
2065
- binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2190
+ binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2066
2191
  "div",
2067
2192
  {
2068
2193
  style: {
@@ -2086,7 +2211,7 @@ function DeviceControlPanelImpl({
2086
2211
  children: binding.state.lastCommandResult.message
2087
2212
  }
2088
2213
  ),
2089
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
2214
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
2090
2215
  @keyframes slideInToast {
2091
2216
  from {
2092
2217
  opacity: 0;
@@ -2118,11 +2243,11 @@ function DeviceControlPanelImpl({
2118
2243
  ` })
2119
2244
  ] });
2120
2245
  }
2121
- var DeviceControlPanel = import_react5.default.memo(DeviceControlPanelImpl);
2246
+ var DeviceControlPanel = import_react6.default.memo(DeviceControlPanelImpl);
2122
2247
 
2123
2248
  // src/components/NumpadDialog/NumpadDialog.tsx
2124
- var import_react6 = require("react");
2125
- var import_jsx_runtime9 = require("react/jsx-runtime");
2249
+ var import_react7 = require("react");
2250
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2126
2251
  var NumpadDialog = ({
2127
2252
  isOpen,
2128
2253
  onClose,
@@ -2136,24 +2261,24 @@ var NumpadDialog = ({
2136
2261
  currentValue = 0,
2137
2262
  touchOptimized = true
2138
2263
  }) => {
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)();
2264
+ const [inputValue, setInputValue] = (0, import_react7.useState)("");
2265
+ const [pristine, setPristine] = (0, import_react7.useState)(true);
2266
+ const dialogRef = (0, import_react7.useRef)(null);
2267
+ const titleId = (0, import_react7.useId)();
2143
2268
  const decimals = precision ?? 1;
2144
- (0, import_react6.useEffect)(() => {
2269
+ (0, import_react7.useEffect)(() => {
2145
2270
  if (isOpen) {
2146
2271
  setInputValue(Number(currentValue).toFixed(decimals));
2147
2272
  setPristine(true);
2148
2273
  }
2149
2274
  }, [isOpen, currentValue, decimals]);
2150
- (0, import_react6.useEffect)(() => {
2275
+ (0, import_react7.useEffect)(() => {
2151
2276
  if (!isOpen) return;
2152
2277
  const previouslyFocused = document.activeElement;
2153
2278
  dialogRef.current?.focus();
2154
2279
  return () => previouslyFocused?.focus?.();
2155
2280
  }, [isOpen]);
2156
- (0, import_react6.useEffect)(() => {
2281
+ (0, import_react7.useEffect)(() => {
2157
2282
  if (!isOpen) return;
2158
2283
  const prevOverflow = document.body.style.overflow;
2159
2284
  document.body.style.overflow = "hidden";
@@ -2161,13 +2286,13 @@ var NumpadDialog = ({
2161
2286
  document.body.style.overflow = prevOverflow;
2162
2287
  };
2163
2288
  }, [isOpen]);
2164
- const handleApply = (0, import_react6.useCallback)(() => {
2289
+ const handleApply = (0, import_react7.useCallback)(() => {
2165
2290
  const n = Number(inputValue);
2166
2291
  if (inputValue === "" || inputValue === "-" || inputValue === "." || inputValue === "-.") return;
2167
2292
  if (isNaN(n) || n < min || n > max) return;
2168
2293
  onApply(Number(n.toFixed(decimals)));
2169
2294
  }, [inputValue, min, max, onApply, decimals]);
2170
- const appendDigit = (0, import_react6.useCallback)(
2295
+ const appendDigit = (0, import_react7.useCallback)(
2171
2296
  (digit) => {
2172
2297
  setInputValue((prev) => {
2173
2298
  const base = pristine ? "" : prev;
@@ -2187,15 +2312,15 @@ var NumpadDialog = ({
2187
2312
  },
2188
2313
  [pristine, decimals]
2189
2314
  );
2190
- const handleBackspace = (0, import_react6.useCallback)(() => {
2315
+ const handleBackspace = (0, import_react7.useCallback)(() => {
2191
2316
  setPristine(false);
2192
2317
  setInputValue((prev) => prev.slice(0, -1));
2193
2318
  }, []);
2194
- const handleClear = (0, import_react6.useCallback)(() => {
2319
+ const handleClear = (0, import_react7.useCallback)(() => {
2195
2320
  setPristine(false);
2196
2321
  setInputValue("");
2197
2322
  }, []);
2198
- const handleToggleSign = (0, import_react6.useCallback)(() => {
2323
+ const handleToggleSign = (0, import_react7.useCallback)(() => {
2199
2324
  if (min >= 0) return;
2200
2325
  setPristine(false);
2201
2326
  setInputValue((prev) => {
@@ -2204,8 +2329,8 @@ var NumpadDialog = ({
2204
2329
  return "-" + prev;
2205
2330
  });
2206
2331
  }, [min]);
2207
- const bsTimer = (0, import_react6.useRef)(null);
2208
- const bsLongFired = (0, import_react6.useRef)(false);
2332
+ const bsTimer = (0, import_react7.useRef)(null);
2333
+ const bsLongFired = (0, import_react7.useRef)(false);
2209
2334
  const clearBsTimer = () => {
2210
2335
  if (bsTimer.current !== null) {
2211
2336
  clearTimeout(bsTimer.current);
@@ -2227,8 +2352,8 @@ var NumpadDialog = ({
2227
2352
  }
2228
2353
  handleBackspace();
2229
2354
  };
2230
- (0, import_react6.useEffect)(() => () => clearBsTimer(), []);
2231
- (0, import_react6.useEffect)(() => {
2355
+ (0, import_react7.useEffect)(() => () => clearBsTimer(), []);
2356
+ (0, import_react7.useEffect)(() => {
2232
2357
  if (!isOpen) return;
2233
2358
  const handler = (e) => {
2234
2359
  if (e.key === "Tab") {
@@ -2326,7 +2451,7 @@ var NumpadDialog = ({
2326
2451
  };
2327
2452
  const reason = belowMin ? `Below minimum of ${min} ${unit}` : aboveMax ? `Above maximum of ${max} ${unit}` : "Type or tap to change the value";
2328
2453
  const backspaceInGrid = min >= 0;
2329
- const BackspaceButton = ({ style, label }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2454
+ const BackspaceButton = ({ style, label }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2330
2455
  "button",
2331
2456
  {
2332
2457
  type: "button",
@@ -2343,7 +2468,7 @@ var NumpadDialog = ({
2343
2468
  );
2344
2469
  return (
2345
2470
  // Backdrop
2346
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2471
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2347
2472
  "div",
2348
2473
  {
2349
2474
  style: {
@@ -2360,14 +2485,14 @@ var NumpadDialog = ({
2360
2485
  },
2361
2486
  onClick: onClose,
2362
2487
  children: [
2363
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
2488
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: `
2364
2489
  .np-key { transition: background .1s, transform .05s; touch-action: manipulation; }
2365
2490
  .np-key:active:not(:disabled) { background:#e2e8f0; transform: translateY(1px); }
2366
2491
  .np-key:focus-visible, .np-action:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }
2367
2492
  @keyframes np-blink { 0%,49%{opacity:1} 50%,100%{opacity:0} }
2368
2493
  .np-caret { display:inline-block; width:2px; height:1.1em; background:#2563eb; animation: np-blink 1s step-end infinite; }
2369
2494
  ` }),
2370
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2495
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2371
2496
  "div",
2372
2497
  {
2373
2498
  ref: dialogRef,
@@ -2388,9 +2513,9 @@ var NumpadDialog = ({
2388
2513
  },
2389
2514
  onClick: (e) => e.stopPropagation(),
2390
2515
  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)(
2516
+ /* @__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 }) }),
2517
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { padding: 16, display: "flex", flexDirection: "column", gap: 10 }, children: [
2518
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2394
2519
  "div",
2395
2520
  {
2396
2521
  style: {
@@ -2400,24 +2525,24 @@ var NumpadDialog = ({
2400
2525
  color: "#64748b"
2401
2526
  },
2402
2527
  children: [
2403
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2528
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
2404
2529
  "Current: ",
2405
2530
  currentValue,
2406
2531
  " ",
2407
2532
  unit
2408
2533
  ] }),
2409
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2534
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
2410
2535
  "Range: ",
2411
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: limitStyle(belowMin), children: min }),
2536
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: limitStyle(belowMin), children: min }),
2412
2537
  "-",
2413
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: limitStyle(aboveMax), children: max }),
2538
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: limitStyle(aboveMax), children: max }),
2414
2539
  " ",
2415
2540
  unit
2416
2541
  ] })
2417
2542
  ]
2418
2543
  }
2419
2544
  ),
2420
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2545
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2421
2546
  "div",
2422
2547
  {
2423
2548
  "aria-live": "polite",
@@ -2439,13 +2564,13 @@ var NumpadDialog = ({
2439
2564
  border: outOfRange ? "1.5px solid #fca5a5" : "1.5px solid #e2e8f0"
2440
2565
  },
2441
2566
  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 })
2567
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: inputValue || "0" }),
2568
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "np-caret", "aria-hidden": "true" }),
2569
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: 14, color: "#94a3b8", fontWeight: 500 }, children: unit })
2445
2570
  ]
2446
2571
  }
2447
2572
  ),
2448
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2573
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2449
2574
  "div",
2450
2575
  {
2451
2576
  role: "status",
@@ -2460,8 +2585,8 @@ var NumpadDialog = ({
2460
2585
  children: reason
2461
2586
  }
2462
2587
  ),
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)(
2588
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 5 }, children: [
2589
+ ["7", "8", "9", "4", "5", "6", "1", "2", "3"].map((digit) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2465
2590
  "button",
2466
2591
  {
2467
2592
  type: "button",
@@ -2473,7 +2598,7 @@ var NumpadDialog = ({
2473
2598
  },
2474
2599
  digit
2475
2600
  )),
2476
- min < 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2601
+ min < 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2477
2602
  "button",
2478
2603
  {
2479
2604
  type: "button",
@@ -2484,9 +2609,9 @@ var NumpadDialog = ({
2484
2609
  onClick: handleToggleSign,
2485
2610
  children: "+/\u2212"
2486
2611
  }
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)(
2612
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BackspaceButton, { style: { ...keyStyle, fontSize: 20, background: "#f8fafc", color: "#64748b" }, label: "\u232B" }),
2613
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: keyStyle, onClick: () => appendDigit("0"), children: "0" }),
2614
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2490
2615
  "button",
2491
2616
  {
2492
2617
  type: "button",
@@ -2504,12 +2629,12 @@ var NumpadDialog = ({
2504
2629
  }
2505
2630
  )
2506
2631
  ] }),
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" })
2632
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", gap: 5 }, children: [
2633
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "np-key", tabIndex: -1, style: utilKeyStyle, onClick: handleClear, children: "Clear" }),
2634
+ !backspaceInGrid && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BackspaceButton, { style: utilKeyStyle, label: "Backspace" })
2510
2635
  ] }),
2511
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2512
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2636
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2513
2638
  "button",
2514
2639
  {
2515
2640
  type: "button",
@@ -2529,7 +2654,7 @@ var NumpadDialog = ({
2529
2654
  children: "Cancel"
2530
2655
  }
2531
2656
  ),
2532
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2657
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2533
2658
  "button",
2534
2659
  {
2535
2660
  type: "button",
@@ -2564,13 +2689,13 @@ var NumpadDialog = ({
2564
2689
  };
2565
2690
 
2566
2691
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
2567
- var import_react8 = __toESM(require("react"), 1);
2692
+ var import_react9 = __toESM(require("react"), 1);
2568
2693
  var import_material3 = require("@mui/material");
2569
2694
 
2570
2695
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
2571
2696
  var import_material = require("@mui/material");
2572
2697
  var import_styled = __toESM(require("@emotion/styled"), 1);
2573
- var import_jsx_runtime10 = require("react/jsx-runtime");
2698
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2574
2699
  var FullscreenContainer = (0, import_styled.default)(import_material.Box)(
2575
2700
  ({ leftCollapsed, rightCollapsed }) => {
2576
2701
  const getGridTemplateAreas = () => {
@@ -2695,7 +2820,7 @@ var DisplayModeToggle = (0, import_styled.default)(import_material.IconButton)((
2695
2820
  transform: "translateX(-50%) scale(1.05)"
2696
2821
  }
2697
2822
  }));
2698
- var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2823
+ var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2699
2824
  "div",
2700
2825
  {
2701
2826
  style: {
@@ -2707,7 +2832,7 @@ var ChevronLeft = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2707
2832
  }
2708
2833
  }
2709
2834
  );
2710
- var ChevronRight = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2835
+ var ChevronRight = () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2711
2836
  "div",
2712
2837
  {
2713
2838
  style: {
@@ -2818,10 +2943,10 @@ var ScrollableSVGWrapper = (0, import_styled.default)("div")({
2818
2943
  });
2819
2944
 
2820
2945
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx
2821
- var import_react7 = require("react");
2946
+ var import_react8 = require("react");
2822
2947
  var import_material2 = require("@mui/material");
2823
2948
  var import_styled2 = __toESM(require("@emotion/styled"), 1);
2824
- var import_jsx_runtime11 = require("react/jsx-runtime");
2949
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2825
2950
  var baseOverlayStyles = {
2826
2951
  tank: {
2827
2952
  background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
@@ -2883,8 +3008,8 @@ var SVGLockedOverlay = ({
2883
3008
  onClick,
2884
3009
  containerSelector = ".tff-svg-container"
2885
3010
  }) => {
2886
- const [svgOffset, setSvgOffset] = (0, import_react7.useState)({ x: 0, y: 0 });
2887
- (0, import_react7.useEffect)(() => {
3011
+ const [svgOffset, setSvgOffset] = (0, import_react8.useState)({ x: 0, y: 0 });
3012
+ (0, import_react8.useEffect)(() => {
2888
3013
  const updateSvgOffset = () => {
2889
3014
  const containerElement = document.querySelector(containerSelector);
2890
3015
  const svgElement = containerElement?.querySelector("svg");
@@ -2904,7 +3029,7 @@ var SVGLockedOverlay = ({
2904
3029
  const pixelX = svgX + svgOffset.x;
2905
3030
  const pixelY = svgY + svgOffset.y;
2906
3031
  const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
2907
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3032
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2908
3033
  import_material2.Box,
2909
3034
  {
2910
3035
  className: `svg-locked-overlay ${className}`.trim(),
@@ -2968,7 +3093,7 @@ var CardUnit = (0, import_styled2.default)("div")({
2968
3093
  });
2969
3094
 
2970
3095
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
2971
- var import_jsx_runtime12 = require("react/jsx-runtime");
3096
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2972
3097
  var forcedTagStyle = {
2973
3098
  position: "absolute",
2974
3099
  top: "-6px",
@@ -2996,7 +3121,7 @@ var TrendLine = ({
2996
3121
  forced = false
2997
3122
  }) => {
2998
3123
  if (!values || values.length < 2) {
2999
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3124
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3000
3125
  "div",
3001
3126
  {
3002
3127
  style: {
@@ -3010,8 +3135,8 @@ var TrendLine = ({
3010
3135
  justifyContent: "center"
3011
3136
  },
3012
3137
  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" })
3138
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
3139
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3015
3140
  ]
3016
3141
  }
3017
3142
  );
@@ -3024,7 +3149,7 @@ var TrendLine = ({
3024
3149
  const x = 4 + i / (values.length - 1) * (width - 8);
3025
3150
  return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
3026
3151
  }).join(" ");
3027
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3152
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3028
3153
  "div",
3029
3154
  {
3030
3155
  style: {
@@ -3036,14 +3161,14 @@ var TrendLine = ({
3036
3161
  overflow: "visible"
3037
3162
  },
3038
3163
  children: [
3039
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3164
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3040
3165
  "svg",
3041
3166
  {
3042
3167
  width,
3043
3168
  height,
3044
3169
  style: { position: "absolute", top: 0, left: 0, overflow: "hidden", borderRadius: "2px" },
3045
3170
  children: [
3046
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3171
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3047
3172
  "path",
3048
3173
  {
3049
3174
  d: pathData,
@@ -3054,7 +3179,7 @@ var TrendLine = ({
3054
3179
  strokeLinejoin: "round"
3055
3180
  }
3056
3181
  ),
3057
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3182
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3058
3183
  "circle",
3059
3184
  {
3060
3185
  cx: 4 + (width - 8),
@@ -3066,7 +3191,7 @@ var TrendLine = ({
3066
3191
  ]
3067
3192
  }
3068
3193
  ),
3069
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3194
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3070
3195
  ]
3071
3196
  }
3072
3197
  );
@@ -3098,7 +3223,7 @@ var CircularGauge = ({
3098
3223
  const borderColor = isHex ? hexToRgba(color, 0.9) : color;
3099
3224
  const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
3100
3225
  const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
3101
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3226
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3102
3227
  "div",
3103
3228
  {
3104
3229
  style: {
@@ -3107,7 +3232,7 @@ var CircularGauge = ({
3107
3232
  alignItems: "center"
3108
3233
  },
3109
3234
  children: [
3110
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3235
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3111
3236
  "div",
3112
3237
  {
3113
3238
  style: {
@@ -3119,8 +3244,8 @@ var CircularGauge = ({
3119
3244
  border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : `1px solid ${borderStrokeColor}`
3120
3245
  },
3121
3246
  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)(
3247
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
3248
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3124
3249
  "circle",
3125
3250
  {
3126
3251
  cx: size / 2,
@@ -3131,7 +3256,7 @@ var CircularGauge = ({
3131
3256
  strokeWidth: 1
3132
3257
  }
3133
3258
  ),
3134
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3259
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3135
3260
  "circle",
3136
3261
  {
3137
3262
  cx: size / 2,
@@ -3142,7 +3267,7 @@ var CircularGauge = ({
3142
3267
  fill: "transparent"
3143
3268
  }
3144
3269
  ),
3145
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3270
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3146
3271
  "circle",
3147
3272
  {
3148
3273
  cx: size / 2,
@@ -3158,7 +3283,7 @@ var CircularGauge = ({
3158
3283
  }
3159
3284
  )
3160
3285
  ] }),
3161
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3286
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3162
3287
  "div",
3163
3288
  {
3164
3289
  style: {
@@ -3174,14 +3299,14 @@ var CircularGauge = ({
3174
3299
  },
3175
3300
  children: [
3176
3301
  value.toFixed(1),
3177
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3302
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3178
3303
  ]
3179
3304
  }
3180
3305
  )
3181
3306
  ]
3182
3307
  }
3183
3308
  ),
3184
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3309
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3185
3310
  "div",
3186
3311
  {
3187
3312
  style: {
@@ -3193,7 +3318,7 @@ var CircularGauge = ({
3193
3318
  children: label
3194
3319
  }
3195
3320
  ),
3196
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3321
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3197
3322
  "span",
3198
3323
  {
3199
3324
  "aria-label": "Forced",
@@ -3214,7 +3339,7 @@ var CircularGauge = ({
3214
3339
  children: "F"
3215
3340
  }
3216
3341
  ),
3217
- forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3342
+ forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3218
3343
  "REAL ",
3219
3344
  realValue.toFixed(1),
3220
3345
  " ",
@@ -3239,7 +3364,7 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3239
3364
  const y = height - 8 - (value - min) / range * (height - 8);
3240
3365
  return `${x + 4},${y + 4}`;
3241
3366
  }).join(" ");
3242
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3367
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3243
3368
  "div",
3244
3369
  {
3245
3370
  style: {
@@ -3255,13 +3380,13 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3255
3380
  boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
3256
3381
  },
3257
3382
  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" })
3383
+ /* @__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" }) }),
3384
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3260
3385
  ]
3261
3386
  }
3262
3387
  );
3263
3388
  };
3264
- var EquipmentForcedBadge = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3389
+ var EquipmentForcedBadge = () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3265
3390
  "span",
3266
3391
  {
3267
3392
  "aria-label": "Forced",
@@ -3296,9 +3421,9 @@ var EquipmentIndicatorWithSparkline = ({
3296
3421
  forced = false
3297
3422
  }) => {
3298
3423
  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)(
3424
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3425
+ /* @__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: [
3426
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3302
3427
  "div",
3303
3428
  {
3304
3429
  style: {
@@ -3319,9 +3444,9 @@ var EquipmentIndicatorWithSparkline = ({
3319
3444
  children: label
3320
3445
  }
3321
3446
  ),
3322
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
3447
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EquipmentForcedBadge, {})
3323
3448
  ] }) }),
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 }) })
3449
+ 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
3450
  ] });
3326
3451
  };
3327
3452
  var EquipmentIndicator = ({
@@ -3335,8 +3460,8 @@ var EquipmentIndicator = ({
3335
3460
  forced = false
3336
3461
  }) => {
3337
3462
  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)(
3463
+ 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: [
3464
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3340
3465
  "div",
3341
3466
  {
3342
3467
  style: {
@@ -3357,12 +3482,12 @@ var EquipmentIndicator = ({
3357
3482
  children: label
3358
3483
  }
3359
3484
  ),
3360
- forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
3485
+ forced && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EquipmentForcedBadge, {})
3361
3486
  ] }) });
3362
3487
  };
3363
3488
 
3364
3489
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
3365
- var import_jsx_runtime13 = require("react/jsx-runtime");
3490
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3366
3491
  function FullscreenWorkspace({
3367
3492
  svgContent,
3368
3493
  overlays,
@@ -3390,10 +3515,10 @@ function FullscreenWorkspace({
3390
3515
  className = "",
3391
3516
  ...rest
3392
3517
  }) {
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(
3518
+ const [leftCollapsedState, setLeftCollapsedState] = import_react9.default.useState(defaultLeftCollapsed);
3519
+ const [rightCollapsedState, setRightCollapsedState] = import_react9.default.useState(defaultRightCollapsed);
3520
+ const [internalDisplayMode, setInternalDisplayMode] = import_react9.default.useState(displayMode ?? defaultDisplayMode);
3521
+ const [internalTab, setInternalTab] = import_react9.default.useState(
3397
3522
  tabs && tabs.length > 0 ? tabs[0].value : ""
3398
3523
  );
3399
3524
  const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
@@ -3401,10 +3526,10 @@ function FullscreenWorkspace({
3401
3526
  const isDisplayModeControlled = displayMode !== void 0;
3402
3527
  const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
3403
3528
  const isTabControlled = activeTab !== void 0 && activeTab !== null;
3404
- const resolvedTabs = import_react8.default.useMemo(() => tabs ?? [], [tabs]);
3529
+ const resolvedTabs = import_react9.default.useMemo(() => tabs ?? [], [tabs]);
3405
3530
  const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
3406
3531
  const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
3407
- import_react8.default.useEffect(() => {
3532
+ import_react9.default.useEffect(() => {
3408
3533
  if (resolvedTabs.length > 0) {
3409
3534
  const values = resolvedTabs.map((tab) => tab.value);
3410
3535
  if (!values.includes(currentTab)) {
@@ -3413,7 +3538,7 @@ function FullscreenWorkspace({
3413
3538
  }
3414
3539
  }
3415
3540
  }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
3416
- import_react8.default.useEffect(() => {
3541
+ import_react9.default.useEffect(() => {
3417
3542
  if (displayMode !== void 0) {
3418
3543
  setInternalDisplayMode(displayMode);
3419
3544
  }
@@ -3448,7 +3573,7 @@ function FullscreenWorkspace({
3448
3573
  const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
3449
3574
  const showLeftToggle = Boolean(leftPanel);
3450
3575
  const showRightToggle = Boolean(rightPanel);
3451
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3576
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3452
3577
  FullscreenContainer,
3453
3578
  {
3454
3579
  leftCollapsed,
@@ -3456,25 +3581,25 @@ function FullscreenWorkspace({
3456
3581
  className: `tff-svg-container ${className}`.trim(),
3457
3582
  ...rest,
3458
3583
  children: [
3459
- showLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3584
+ showLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3460
3585
  LeftToggleButton,
3461
3586
  {
3462
3587
  collapsed: leftCollapsed,
3463
3588
  onClick: handleLeftToggle,
3464
3589
  "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, {})
3590
+ children: leftCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRight, {}) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronLeft, {})
3466
3591
  }
3467
3592
  ),
3468
- showRightToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3593
+ showRightToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3469
3594
  RightToggleButton,
3470
3595
  {
3471
3596
  collapsed: rightCollapsed,
3472
3597
  onClick: handleRightToggle,
3473
3598
  "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, {})
3599
+ children: rightCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronLeft, {}) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChevronRight, {})
3475
3600
  }
3476
3601
  ),
3477
- showDisplayModeToggle && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3602
+ showDisplayModeToggle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3478
3603
  DisplayModeToggle,
3479
3604
  {
3480
3605
  mode: currentDisplayMode,
@@ -3483,9 +3608,9 @@ function FullscreenWorkspace({
3483
3608
  children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
3484
3609
  }
3485
3610
  ),
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)(
3611
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(SVGArea, { children: [
3612
+ showZoomControls && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(ZoomControls, { children: [
3613
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3489
3614
  ZoomButton,
3490
3615
  {
3491
3616
  onClick: onZoomIn,
@@ -3495,7 +3620,7 @@ function FullscreenWorkspace({
3495
3620
  children: "+"
3496
3621
  }
3497
3622
  ),
3498
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3623
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3499
3624
  ZoomButton,
3500
3625
  {
3501
3626
  onClick: onZoomOut,
@@ -3505,7 +3630,7 @@ function FullscreenWorkspace({
3505
3630
  children: "-"
3506
3631
  }
3507
3632
  ),
3508
- onResetZoom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3633
+ onResetZoom && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3509
3634
  ZoomButton,
3510
3635
  {
3511
3636
  onClick: onResetZoom,
@@ -3516,44 +3641,44 @@ function FullscreenWorkspace({
3516
3641
  }
3517
3642
  )
3518
3643
  ] }),
3519
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(FixedSVGContainer, { className: "svg-container", children: [
3644
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(FixedSVGContainer, { className: "svg-container", children: [
3520
3645
  svgContent,
3521
3646
  overlays
3522
3647
  ] }) })
3523
3648
  ] }),
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)(
3649
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3650
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3526
3651
  PanelTabs,
3527
3652
  {
3528
3653
  value: currentTab,
3529
3654
  onChange: handleTabChangeInternal,
3530
3655
  "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))
3656
+ children: resolvedTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_material3.Tab, { label: tab.label, value: tab.value }, tab.value))
3532
3657
  }
3533
3658
  ),
3534
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PanelContent, { children: currentTabContent })
3659
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PanelContent, { children: currentTabContent })
3535
3660
  ] }) : leftPanel }),
3536
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3537
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(FooterPanel, { children: footer })
3661
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3662
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(FooterPanel, { children: footer })
3538
3663
  ]
3539
3664
  }
3540
3665
  );
3541
3666
  }
3542
3667
 
3543
3668
  // 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);
3669
+ var import_react10 = require("react");
3670
+ var import_jsx_runtime15 = require("react/jsx-runtime");
3671
+ var ThemeContext = (0, import_react10.createContext)(void 0);
3547
3672
  var useTheme = () => {
3548
- const context = (0, import_react9.useContext)(ThemeContext);
3673
+ const context = (0, import_react10.useContext)(ThemeContext);
3549
3674
  if (!context) {
3550
3675
  throw new Error("useTheme must be used within a ThemeProvider");
3551
3676
  }
3552
3677
  return context;
3553
3678
  };
3554
3679
  var ThemeProvider = ({ children }) => {
3555
- const [theme, setThemeState] = (0, import_react9.useState)("modern");
3556
- (0, import_react9.useEffect)(() => {
3680
+ const [theme, setThemeState] = (0, import_react10.useState)("modern");
3681
+ (0, import_react10.useEffect)(() => {
3557
3682
  document.body.className = "";
3558
3683
  document.body.classList.add(`theme-${theme}`);
3559
3684
  document.documentElement.className = "";
@@ -3565,11 +3690,11 @@ var ThemeProvider = ({ children }) => {
3565
3690
  const setTheme = (newTheme) => {
3566
3691
  setThemeState(newTheme);
3567
3692
  };
3568
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3693
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3569
3694
  };
3570
3695
 
3571
3696
  // src/theme/ThemeToggle.tsx
3572
- var import_jsx_runtime15 = require("react/jsx-runtime");
3697
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3573
3698
  var ThemeToggle = ({
3574
3699
  size = "medium",
3575
3700
  position = "top-right",
@@ -3640,18 +3765,18 @@ var ThemeToggle = ({
3640
3765
  transition: "all 0.2s ease",
3641
3766
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
3642
3767
  };
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" })
3768
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
3769
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
3770
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: toggleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: thumbStyle }) }),
3771
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
3647
3772
  ] });
3648
3773
  };
3649
3774
 
3650
3775
  // src/components/PIDCanvas/PIDCanvas.tsx
3651
- var import_react21 = __toESM(require("react"), 1);
3776
+ var import_react22 = __toESM(require("react"), 1);
3652
3777
 
3653
3778
  // src/components/PIDCanvas/NodeRenderer.tsx
3654
- var import_react10 = __toESM(require("react"), 1);
3779
+ var import_react11 = __toESM(require("react"), 1);
3655
3780
 
3656
3781
  // src/diagram/symbols/mockSymbolLibrary.ts
3657
3782
  var mockSymbolLibrary = {
@@ -5026,8 +5151,14 @@ function writeAppearanceValue(node, field, value) {
5026
5151
  }
5027
5152
 
5028
5153
  // src/components/PIDCanvas/NodeRenderer.tsx
5029
- var import_jsx_runtime16 = require("react/jsx-runtime");
5030
- var HATCH_SIZE = 6;
5154
+ var import_jsx_runtime17 = require("react/jsx-runtime");
5155
+ var HATCH_TILE_SIZE = 7;
5156
+ var HATCH_STRIPE_WIDTH = 2;
5157
+ var HATCH_STRIPE_ANGLE = 135;
5158
+ var HATCH_STRIPE_OPACITY = 85 / 255;
5159
+ function isUnknownNode(node) {
5160
+ return node.positionUnknown === true || normalizeDeviceStatus(node.status) === "unknown";
5161
+ }
5031
5162
  function NodeRendererImpl({
5032
5163
  nodes: nodes2,
5033
5164
  selectedNodeIds,
@@ -5039,41 +5170,42 @@ function NodeRendererImpl({
5039
5170
  enableDrag = false,
5040
5171
  statusColorMap
5041
5172
  }) {
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)(
5173
+ const hatchPatternId = `node-unknown-hatch-${import_react11.default.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
5174
+ const visibleNodes = nodes2.filter((node) => node.visible !== false);
5175
+ const hasUnknownNode = visibleNodes.some(isUnknownNode);
5176
+ const unknownEntry = resolveStatusColor("unknown", statusColorMap);
5177
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { id: "layer-nodes", children: [
5178
+ hasUnknownNode && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5046
5179
  "pattern",
5047
5180
  {
5048
- id: hatchId,
5049
- "data-testid": "position-unknown-pattern",
5181
+ id: hatchPatternId,
5182
+ "data-testid": "unknown-hatch-pattern",
5050
5183
  patternUnits: "userSpaceOnUse",
5051
- width: HATCH_SIZE,
5052
- height: HATCH_SIZE,
5053
- patternTransform: "rotate(45)",
5184
+ width: HATCH_TILE_SIZE,
5185
+ height: HATCH_TILE_SIZE,
5186
+ patternTransform: `rotate(${HATCH_STRIPE_ANGLE})`,
5054
5187
  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",
5188
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("rect", { width: HATCH_TILE_SIZE, height: HATCH_TILE_SIZE, fill: unknownEntry.fill }),
5189
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5190
+ "rect",
5058
5191
  {
5059
- x1: "0",
5060
- y1: "0",
5061
- x2: "0",
5062
- y2: HATCH_SIZE,
5063
- stroke: UNKNOWN_MARK_COLOR.text,
5064
- strokeWidth: "2"
5192
+ x: HATCH_TILE_SIZE - HATCH_STRIPE_WIDTH,
5193
+ width: HATCH_STRIPE_WIDTH,
5194
+ height: HATCH_TILE_SIZE,
5195
+ fill: unknownEntry.stroke,
5196
+ fillOpacity: HATCH_STRIPE_OPACITY
5065
5197
  }
5066
5198
  )
5067
5199
  ]
5068
5200
  }
5069
5201
  ) }),
5070
- nodes2.filter((node) => node.visible !== false).map((node) => {
5202
+ visibleNodes.map((node) => {
5071
5203
  const symbol = getSymbolDefinition(node.symbolId);
5072
5204
  const isSelected = selectedNodeIds?.has(node.id) ?? false;
5073
5205
  const isDragging = draggingNodeId === node.id;
5074
5206
  if (!symbol) {
5075
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { children: [
5076
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5207
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { children: [
5208
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5077
5209
  "circle",
5078
5210
  {
5079
5211
  cx: node.transform.x,
@@ -5085,7 +5217,7 @@ function NodeRendererImpl({
5085
5217
  strokeWidth: "2"
5086
5218
  }
5087
5219
  ),
5088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5220
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5089
5221
  "text",
5090
5222
  {
5091
5223
  x: node.transform.x,
@@ -5125,9 +5257,9 @@ function NodeRendererImpl({
5125
5257
  );
5126
5258
  }
5127
5259
  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;
5260
+ const isUnknown = isUnknownNode(node);
5261
+ const fillColor = isUnknown ? `url(#${hatchPatternId})` : node.customColors?.fill ?? statusEntry.fill;
5262
+ const strokeColor = isUnknown ? unknownEntry.stroke : node.customColors?.stroke ?? statusEntry.stroke;
5131
5263
  const appearance = { ...getAppearanceDefaults(node.symbolId), ...node.metadata ?? {} };
5132
5264
  const ledStyle = {};
5133
5265
  if (appearance.shape !== void 0) {
@@ -5138,7 +5270,8 @@ function NodeRendererImpl({
5138
5270
  ledStyle["--led-bezel"] = appearance.led ? "2" : "0";
5139
5271
  }
5140
5272
  if (appearance.glow) {
5141
- ledStyle.filter = `drop-shadow(0 0 4px ${fillColor})`;
5273
+ const glowColor = isUnknown ? unknownEntry.stroke : fillColor;
5274
+ ledStyle.filter = `drop-shadow(0 0 4px ${glowColor})`;
5142
5275
  }
5143
5276
  const ledAnimation = typeof appearance.animation === "string" && appearance.animation !== "none" ? appearance.animation : void 0;
5144
5277
  const vb = symbol.viewBox;
@@ -5161,7 +5294,7 @@ function NodeRendererImpl({
5161
5294
  labelY = vb.height / 2 + oy;
5162
5295
  labelAnchor = "start";
5163
5296
  }
5164
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5297
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5165
5298
  "g",
5166
5299
  {
5167
5300
  "data-node-id": node.id,
@@ -5169,7 +5302,7 @@ function NodeRendererImpl({
5169
5302
  "data-selected": isSelected,
5170
5303
  "data-dragging": isDragging,
5171
5304
  "data-led-animation": ledAnimation,
5172
- "data-position-unknown": isUnknown ? "true" : void 0,
5305
+ "data-position-unknown": node.positionUnknown === true ? "true" : void 0,
5173
5306
  transform: transforms.join(" "),
5174
5307
  style: {
5175
5308
  "--symbol-fill": fillColor,
@@ -5197,7 +5330,7 @@ function NodeRendererImpl({
5197
5330
  }
5198
5331
  },
5199
5332
  children: [
5200
- isSelected && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5333
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5201
5334
  "rect",
5202
5335
  {
5203
5336
  x: "-5",
@@ -5212,7 +5345,7 @@ function NodeRendererImpl({
5212
5345
  pointerEvents: "none"
5213
5346
  }
5214
5347
  ),
5215
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5348
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5216
5349
  "g",
5217
5350
  {
5218
5351
  dangerouslySetInnerHTML: { __html: symbol.svgContent },
@@ -5220,7 +5353,7 @@ function NodeRendererImpl({
5220
5353
  style: { pointerEvents: "auto" }
5221
5354
  }
5222
5355
  ),
5223
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5356
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5224
5357
  "text",
5225
5358
  {
5226
5359
  x: labelX,
@@ -5240,11 +5373,11 @@ function NodeRendererImpl({
5240
5373
  })
5241
5374
  ] });
5242
5375
  }
5243
- var NodeRenderer = import_react10.default.memo(NodeRendererImpl);
5376
+ var NodeRenderer = import_react11.default.memo(NodeRendererImpl);
5244
5377
 
5245
5378
  // src/components/PIDCanvas/PipeRenderer.tsx
5246
- var import_react11 = __toESM(require("react"), 1);
5247
- var import_jsx_runtime17 = require("react/jsx-runtime");
5379
+ var import_react12 = __toESM(require("react"), 1);
5380
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5248
5381
  function PipeRendererImpl({
5249
5382
  pipes,
5250
5383
  selectedPipeIds,
@@ -5259,7 +5392,7 @@ function PipeRendererImpl({
5259
5392
  waypointDragOffset,
5260
5393
  onPipeSegmentClick
5261
5394
  }) {
5262
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5395
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5263
5396
  const isSelected = selectedPipeIds?.has(pipe.id) ?? false;
5264
5397
  const isEditing = enableWaypointEditing && editingPipeId === pipe.id;
5265
5398
  const showEditingControls = enableWaypointEditing && isSelected;
@@ -5278,7 +5411,7 @@ function PipeRendererImpl({
5278
5411
  const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
5279
5412
  const strokeDasharray = pipeStyle.strokeDasharray;
5280
5413
  const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
5281
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5414
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5282
5415
  "g",
5283
5416
  {
5284
5417
  "data-pipe-id": pipe.id,
@@ -5291,8 +5424,8 @@ function PipeRendererImpl({
5291
5424
  cursor: onPipeClick ? "pointer" : "default"
5292
5425
  },
5293
5426
  children: [
5294
- !enableWaypointEditing && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
5295
- onPipeClick && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5427
+ !enableWaypointEditing && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
5428
+ onPipeClick && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5296
5429
  "polyline",
5297
5430
  {
5298
5431
  points: pointsString,
@@ -5304,7 +5437,7 @@ function PipeRendererImpl({
5304
5437
  pointerEvents: "stroke"
5305
5438
  }
5306
5439
  ),
5307
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5440
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5308
5441
  "polyline",
5309
5442
  {
5310
5443
  points: pointsString,
@@ -5328,7 +5461,7 @@ function PipeRendererImpl({
5328
5461
  const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
5329
5462
  const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
5330
5463
  const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
5331
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5464
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5332
5465
  "circle",
5333
5466
  {
5334
5467
  cx: point.x,
@@ -5365,12 +5498,12 @@ function PipeRendererImpl({
5365
5498
  `${pipe.id}-point-${idx}`
5366
5499
  );
5367
5500
  }),
5368
- showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: displayPoints.slice(0, -1).map((point, idx) => {
5501
+ showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: displayPoints.slice(0, -1).map((point, idx) => {
5369
5502
  const nextPoint = displayPoints[idx + 1];
5370
5503
  const midX = (point.x + nextPoint.x) / 2;
5371
5504
  const midY = (point.y + nextPoint.y) / 2;
5372
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { children: [
5373
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5505
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { children: [
5506
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5374
5507
  "circle",
5375
5508
  {
5376
5509
  cx: midX,
@@ -5386,7 +5519,7 @@ function PipeRendererImpl({
5386
5519
  }
5387
5520
  }
5388
5521
  ),
5389
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5522
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5390
5523
  "circle",
5391
5524
  {
5392
5525
  cx: midX,
@@ -5402,7 +5535,7 @@ function PipeRendererImpl({
5402
5535
  )
5403
5536
  ] }, `${pipe.id}-segment-${idx}`);
5404
5537
  }) }),
5405
- pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5538
+ pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5406
5539
  "text",
5407
5540
  {
5408
5541
  x: pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x + (pipe.labelOffset?.x ?? 0),
@@ -5422,11 +5555,11 @@ function PipeRendererImpl({
5422
5555
  );
5423
5556
  }) });
5424
5557
  }
5425
- var PipeRenderer = import_react11.default.memo(PipeRendererImpl);
5558
+ var PipeRenderer = import_react12.default.memo(PipeRendererImpl);
5426
5559
 
5427
5560
  // src/components/PIDCanvas/DataOverlay.tsx
5428
- var import_react12 = __toESM(require("react"), 1);
5429
- var import_jsx_runtime18 = require("react/jsx-runtime");
5561
+ var import_react13 = __toESM(require("react"), 1);
5562
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5430
5563
  var PULSE_KEYFRAME_ID = "pid-data-overlay-pulse-keyframes";
5431
5564
  var PULSE_ANIMATION = "pid-data-overlay-pulse 1.5s ease-in-out infinite";
5432
5565
  function ensurePulseKeyframes() {
@@ -5437,9 +5570,10 @@ function ensurePulseKeyframes() {
5437
5570
  style.textContent = "@keyframes pid-data-overlay-pulse{0%{opacity:.9}50%{opacity:.3}100%{opacity:.9}}";
5438
5571
  document.head.appendChild(style);
5439
5572
  }
5440
- function renderStatusDot(cx, cy, scale, fill) {
5441
- ensurePulseKeyframes();
5442
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5573
+ function renderStatusDot(cx, cy, scale, fill, status) {
5574
+ const isUnknown = normalizeDeviceStatus(status) === "unknown";
5575
+ if (!isUnknown) ensurePulseKeyframes();
5576
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5443
5577
  "circle",
5444
5578
  {
5445
5579
  className: "pid-data-overlay-status-dot",
@@ -5447,7 +5581,7 @@ function renderStatusDot(cx, cy, scale, fill) {
5447
5581
  cy: cy - 18 * scale,
5448
5582
  r: 3 * scale,
5449
5583
  fill,
5450
- style: { animation: PULSE_ANIMATION }
5584
+ style: isUnknown ? void 0 : { animation: PULSE_ANIMATION }
5451
5585
  }
5452
5586
  );
5453
5587
  }
@@ -5473,7 +5607,7 @@ function DataOverlayImpl({
5473
5607
  const backgroundColor = display?.backgroundColor;
5474
5608
  const offsetX = display?.offsetX ?? 0;
5475
5609
  const offsetY = display?.offsetY ?? 0;
5476
- const sparklinePath = import_react12.default.useMemo(() => {
5610
+ const sparklinePath = import_react13.default.useMemo(() => {
5477
5611
  if (!showSparkline || !history || history.length < 2) return "";
5478
5612
  const width = 70 * scale;
5479
5613
  const height = 20 * scale;
@@ -5492,7 +5626,7 @@ function DataOverlayImpl({
5492
5626
  return `M ${points.join(" L ")}`;
5493
5627
  }, [showSparkline, history, scaling, scale]);
5494
5628
  if (!showValue) {
5495
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, {});
5629
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, {});
5496
5630
  }
5497
5631
  const formatValue = (val) => {
5498
5632
  if (typeof val === "number") {
@@ -5517,10 +5651,11 @@ function DataOverlayImpl({
5517
5651
  const extraMarkRows = realDisplayText ? 1 : 0;
5518
5652
  const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale + extraMarkRows * 9 * scale;
5519
5653
  const overlayWidth = 80 * scale;
5654
+ const isUnknownValue = normalizeDeviceStatus(value.status) === "unknown";
5520
5655
  const displayX = x + offsetX;
5521
5656
  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)(
5657
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
5658
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5524
5659
  "rect",
5525
5660
  {
5526
5661
  x: displayX - overlayWidth / 2,
@@ -5535,7 +5670,7 @@ function DataOverlayImpl({
5535
5670
  filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
5536
5671
  }
5537
5672
  ),
5538
- label && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5673
+ label && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5539
5674
  "text",
5540
5675
  {
5541
5676
  x: displayX,
@@ -5548,7 +5683,7 @@ function DataOverlayImpl({
5548
5683
  children: label
5549
5684
  }
5550
5685
  ),
5551
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5686
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5552
5687
  "text",
5553
5688
  {
5554
5689
  x: displayX,
@@ -5561,8 +5696,17 @@ function DataOverlayImpl({
5561
5696
  children: displayText
5562
5697
  }
5563
5698
  ),
5564
- showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor),
5565
- value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5699
+ showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor, value.status),
5700
+ showStatus && isUnknownValue && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5701
+ UnknownStatusGlyph,
5702
+ {
5703
+ x: displayX - overlayWidth / 2 + 2 * scale,
5704
+ y: displayY - 25 * scale - 6 * scale,
5705
+ width: 12 * scale,
5706
+ height: 12 * scale
5707
+ }
5708
+ ),
5709
+ value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5566
5710
  "text",
5567
5711
  {
5568
5712
  x: displayX,
@@ -5579,13 +5723,13 @@ function DataOverlayImpl({
5579
5723
  ]
5580
5724
  }
5581
5725
  ),
5582
- isForced && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5726
+ isForced && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5583
5727
  "g",
5584
5728
  {
5585
5729
  transform: `translate(${displayX + overlayWidth / 2}, ${displayY - 25 * scale})`,
5586
5730
  "aria-label": "Forced",
5587
5731
  children: [
5588
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5732
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5589
5733
  "circle",
5590
5734
  {
5591
5735
  r: 7 * scale,
@@ -5594,7 +5738,7 @@ function DataOverlayImpl({
5594
5738
  strokeWidth: 1.5 * scale
5595
5739
  }
5596
5740
  ),
5597
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5741
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5598
5742
  "text",
5599
5743
  {
5600
5744
  textAnchor: "middle",
@@ -5608,7 +5752,7 @@ function DataOverlayImpl({
5608
5752
  ]
5609
5753
  }
5610
5754
  ),
5611
- realDisplayText && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5755
+ realDisplayText && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5612
5756
  "text",
5613
5757
  {
5614
5758
  x: displayX,
@@ -5621,7 +5765,7 @@ function DataOverlayImpl({
5621
5765
  children: realDisplayText
5622
5766
  }
5623
5767
  ),
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)(
5768
+ 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
5769
  "path",
5626
5770
  {
5627
5771
  d: sparklinePath,
@@ -5635,11 +5779,11 @@ function DataOverlayImpl({
5635
5779
  ) })
5636
5780
  ] });
5637
5781
  }
5638
- var DataOverlay = import_react12.default.memo(DataOverlayImpl);
5782
+ var DataOverlay = import_react13.default.memo(DataOverlayImpl);
5639
5783
 
5640
5784
  // src/components/PIDCanvas/PositionPanel.tsx
5641
- var import_react13 = require("react");
5642
- var import_jsx_runtime19 = require("react/jsx-runtime");
5785
+ var import_react14 = require("react");
5786
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5643
5787
  function PositionPanel({
5644
5788
  selectedNode,
5645
5789
  selectedWaypoint,
@@ -5647,9 +5791,9 @@ function PositionPanel({
5647
5791
  onWaypointPositionChange,
5648
5792
  position = "top-right"
5649
5793
  }) {
5650
- const [x, setX] = (0, import_react13.useState)("");
5651
- const [y, setY] = (0, import_react13.useState)("");
5652
- (0, import_react13.useEffect)(() => {
5794
+ const [x, setX] = (0, import_react14.useState)("");
5795
+ const [y, setY] = (0, import_react14.useState)("");
5796
+ (0, import_react14.useEffect)(() => {
5653
5797
  if (selectedNode) {
5654
5798
  setX(selectedNode.transform.x.toFixed(2));
5655
5799
  setY(selectedNode.transform.y.toFixed(2));
@@ -5708,7 +5852,7 @@ function PositionPanel({
5708
5852
  "bottom-left": { bottom: 10, left: 10 },
5709
5853
  "bottom-right": { bottom: 10, right: 10 }
5710
5854
  };
5711
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5855
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5712
5856
  "div",
5713
5857
  {
5714
5858
  style: {
@@ -5725,11 +5869,11 @@ function PositionPanel({
5725
5869
  fontSize: "13px"
5726
5870
  },
5727
5871
  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)(
5872
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
5873
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
5874
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5875
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
5876
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5733
5877
  "input",
5734
5878
  {
5735
5879
  type: "number",
@@ -5747,9 +5891,9 @@ function PositionPanel({
5747
5891
  }
5748
5892
  )
5749
5893
  ] }),
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)(
5894
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5895
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
5896
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5753
5897
  "input",
5754
5898
  {
5755
5899
  type: "number",
@@ -5768,14 +5912,14 @@ function PositionPanel({
5768
5912
  )
5769
5913
  ] })
5770
5914
  ] }),
5771
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
5915
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
5772
5916
  ]
5773
5917
  }
5774
5918
  );
5775
5919
  }
5776
5920
 
5777
5921
  // src/diagram/hooks/useViewBox.ts
5778
- var import_react14 = require("react");
5922
+ var import_react15 = require("react");
5779
5923
  function useViewBox(options) {
5780
5924
  const {
5781
5925
  initialViewBox,
@@ -5786,16 +5930,16 @@ function useViewBox(options) {
5786
5930
  zoomSensitivity = 1e-3,
5787
5931
  allowLeftClickPan = true
5788
5932
  } = 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)(() => {
5933
+ const [viewBox, setViewBox] = (0, import_react15.useState)(initialViewBox);
5934
+ const svgRef = (0, import_react15.useRef)(null);
5935
+ const isPanningRef = (0, import_react15.useRef)(false);
5936
+ const lastMousePosRef = (0, import_react15.useRef)({ x: 0, y: 0 });
5937
+ const spaceKeyDownRef = (0, import_react15.useRef)(false);
5938
+ const lastTouchDistanceRef = (0, import_react15.useRef)(null);
5939
+ const resetViewBox = (0, import_react15.useCallback)(() => {
5796
5940
  setViewBox(initialViewBox);
5797
5941
  }, [initialViewBox]);
5798
- const zoomIn = (0, import_react14.useCallback)(() => {
5942
+ const zoomIn = (0, import_react15.useCallback)(() => {
5799
5943
  setViewBox((prev) => {
5800
5944
  const currentZoom = initialViewBox.width / prev.width;
5801
5945
  const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);
@@ -5812,7 +5956,7 @@ function useViewBox(options) {
5812
5956
  };
5813
5957
  });
5814
5958
  }, [initialViewBox, minZoom]);
5815
- const zoomOut = (0, import_react14.useCallback)(() => {
5959
+ const zoomOut = (0, import_react15.useCallback)(() => {
5816
5960
  setViewBox((prev) => {
5817
5961
  const currentZoom = initialViewBox.width / prev.width;
5818
5962
  const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);
@@ -5829,7 +5973,7 @@ function useViewBox(options) {
5829
5973
  };
5830
5974
  });
5831
5975
  }, [initialViewBox, maxZoom]);
5832
- const fitToContent = (0, import_react14.useCallback)((bounds, padding = 50) => {
5976
+ const fitToContent = (0, import_react15.useCallback)((bounds, padding = 50) => {
5833
5977
  const contentWidth = bounds.maxX - bounds.minX;
5834
5978
  const contentHeight = bounds.maxY - bounds.minY;
5835
5979
  if (contentWidth === 0 || contentHeight === 0) {
@@ -5857,7 +6001,7 @@ function useViewBox(options) {
5857
6001
  height: newHeight
5858
6002
  });
5859
6003
  }, [initialViewBox]);
5860
- (0, import_react14.useEffect)(() => {
6004
+ (0, import_react15.useEffect)(() => {
5861
6005
  if (!enableZoom || !svgRef.current) return;
5862
6006
  const svg = svgRef.current;
5863
6007
  const handleWheel = (e) => {
@@ -5890,7 +6034,7 @@ function useViewBox(options) {
5890
6034
  svg.addEventListener("wheel", handleWheel, { passive: false });
5891
6035
  return () => svg.removeEventListener("wheel", handleWheel);
5892
6036
  }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
5893
- (0, import_react14.useEffect)(() => {
6037
+ (0, import_react15.useEffect)(() => {
5894
6038
  if (!enablePan || !svgRef.current) return;
5895
6039
  const svg = svgRef.current;
5896
6040
  const handleMouseDown = (e) => {
@@ -5966,7 +6110,7 @@ function useViewBox(options) {
5966
6110
  window.removeEventListener("keyup", handleKeyUp);
5967
6111
  };
5968
6112
  }, [enablePan, allowLeftClickPan]);
5969
- (0, import_react14.useEffect)(() => {
6113
+ (0, import_react15.useEffect)(() => {
5970
6114
  if (!svgRef.current) return;
5971
6115
  if (!enablePan && !enableZoom) return;
5972
6116
  const svg = svgRef.current;
@@ -6057,7 +6201,7 @@ function useViewBox(options) {
6057
6201
  svg.removeEventListener("touchend", handleTouchEnd);
6058
6202
  };
6059
6203
  }, [enablePan, enableZoom, minZoom, initialViewBox]);
6060
- const screenToWorld = (0, import_react14.useCallback)(
6204
+ const screenToWorld = (0, import_react15.useCallback)(
6061
6205
  (screenX, screenY) => {
6062
6206
  const svg = svgRef.current;
6063
6207
  if (!svg) return { x: screenX, y: screenY };
@@ -6096,15 +6240,15 @@ function useViewBox(options) {
6096
6240
  }
6097
6241
 
6098
6242
  // src/diagram/hooks/useSelection.ts
6099
- var import_react15 = require("react");
6243
+ var import_react16 = require("react");
6100
6244
  function useSelection(options = {}) {
6101
6245
  const {
6102
6246
  multiSelect = true,
6103
6247
  initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
6104
6248
  onSelectionChange
6105
6249
  } = options;
6106
- const [selection, setSelection] = (0, import_react15.useState)(initialSelection);
6107
- const notifyChange = (0, import_react15.useCallback)(
6250
+ const [selection, setSelection] = (0, import_react16.useState)(initialSelection);
6251
+ const notifyChange = (0, import_react16.useCallback)(
6108
6252
  (newSelection) => {
6109
6253
  if (onSelectionChange) {
6110
6254
  onSelectionChange(newSelection);
@@ -6112,15 +6256,15 @@ function useSelection(options = {}) {
6112
6256
  },
6113
6257
  [onSelectionChange]
6114
6258
  );
6115
- const isNodeSelected = (0, import_react15.useCallback)(
6259
+ const isNodeSelected = (0, import_react16.useCallback)(
6116
6260
  (nodeId) => selection.selectedNodeIds.has(nodeId),
6117
6261
  [selection.selectedNodeIds]
6118
6262
  );
6119
- const isPipeSelected = (0, import_react15.useCallback)(
6263
+ const isPipeSelected = (0, import_react16.useCallback)(
6120
6264
  (pipeId) => selection.selectedPipeIds.has(pipeId),
6121
6265
  [selection.selectedPipeIds]
6122
6266
  );
6123
- const selectNode = (0, import_react15.useCallback)(
6267
+ const selectNode = (0, import_react16.useCallback)(
6124
6268
  (nodeId, isMultiSelect = false) => {
6125
6269
  setSelection((prev) => {
6126
6270
  const newNodeIds = new Set(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);
@@ -6139,7 +6283,7 @@ function useSelection(options = {}) {
6139
6283
  },
6140
6284
  [multiSelect, notifyChange]
6141
6285
  );
6142
- const selectPipe = (0, import_react15.useCallback)(
6286
+ const selectPipe = (0, import_react16.useCallback)(
6143
6287
  (pipeId, isMultiSelect = false) => {
6144
6288
  setSelection((prev) => {
6145
6289
  const newPipeIds = new Set(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);
@@ -6158,7 +6302,7 @@ function useSelection(options = {}) {
6158
6302
  },
6159
6303
  [multiSelect, notifyChange]
6160
6304
  );
6161
- const clearSelection = (0, import_react15.useCallback)(() => {
6305
+ const clearSelection = (0, import_react16.useCallback)(() => {
6162
6306
  const newSelection = {
6163
6307
  selectedNodeIds: /* @__PURE__ */ new Set(),
6164
6308
  selectedPipeIds: /* @__PURE__ */ new Set()
@@ -6166,7 +6310,7 @@ function useSelection(options = {}) {
6166
6310
  setSelection(newSelection);
6167
6311
  notifyChange(newSelection);
6168
6312
  }, [notifyChange]);
6169
- const selectNodes = (0, import_react15.useCallback)(
6313
+ const selectNodes = (0, import_react16.useCallback)(
6170
6314
  (nodeIds) => {
6171
6315
  const newSelection = {
6172
6316
  selectedNodeIds: new Set(nodeIds),
@@ -6177,7 +6321,7 @@ function useSelection(options = {}) {
6177
6321
  },
6178
6322
  [notifyChange]
6179
6323
  );
6180
- const selectPipes = (0, import_react15.useCallback)(
6324
+ const selectPipes = (0, import_react16.useCallback)(
6181
6325
  (pipeIds) => {
6182
6326
  const newSelection = {
6183
6327
  selectedNodeIds: /* @__PURE__ */ new Set(),
@@ -6201,23 +6345,23 @@ function useSelection(options = {}) {
6201
6345
  }
6202
6346
 
6203
6347
  // src/diagram/hooks/useTelemetry.ts
6204
- var import_react16 = require("react");
6348
+ var import_react17 = require("react");
6205
6349
  function useTelemetry(options = {}) {
6206
6350
  const {
6207
6351
  initialBindings = [],
6208
6352
  onTelemetryChange,
6209
6353
  refreshInterval = 0
6210
6354
  } = options;
6211
- const [telemetry, setTelemetry] = (0, import_react16.useState)(() => {
6355
+ const [telemetry, setTelemetry] = (0, import_react17.useState)(() => {
6212
6356
  const map = /* @__PURE__ */ new Map();
6213
6357
  initialBindings.forEach((binding) => {
6214
6358
  map.set(binding.nodeId, binding);
6215
6359
  });
6216
6360
  return map;
6217
6361
  });
6218
- const telemetryRef = (0, import_react16.useRef)(telemetry);
6362
+ const telemetryRef = (0, import_react17.useRef)(telemetry);
6219
6363
  telemetryRef.current = telemetry;
6220
- const notifyChange = (0, import_react16.useCallback)(
6364
+ const notifyChange = (0, import_react17.useCallback)(
6221
6365
  (newTelemetry) => {
6222
6366
  if (onTelemetryChange) {
6223
6367
  onTelemetryChange(newTelemetry);
@@ -6225,7 +6369,7 @@ function useTelemetry(options = {}) {
6225
6369
  },
6226
6370
  [onTelemetryChange]
6227
6371
  );
6228
- const updateTelemetry = (0, import_react16.useCallback)(
6372
+ const updateTelemetry = (0, import_react17.useCallback)(
6229
6373
  (nodeId, value) => {
6230
6374
  setTelemetry((prev) => {
6231
6375
  const newMap = new Map(prev);
@@ -6255,7 +6399,7 @@ function useTelemetry(options = {}) {
6255
6399
  },
6256
6400
  [notifyChange]
6257
6401
  );
6258
- const updateTelemetryBatch = (0, import_react16.useCallback)(
6402
+ const updateTelemetryBatch = (0, import_react17.useCallback)(
6259
6403
  (updates) => {
6260
6404
  setTelemetry((prev) => {
6261
6405
  const newMap = new Map(prev);
@@ -6309,16 +6453,16 @@ function useTelemetry(options = {}) {
6309
6453
  },
6310
6454
  [notifyChange]
6311
6455
  );
6312
- const getTelemetry = (0, import_react16.useCallback)(
6456
+ const getTelemetry = (0, import_react17.useCallback)(
6313
6457
  (nodeId) => telemetryRef.current.get(nodeId),
6314
6458
  []
6315
6459
  );
6316
- const clearTelemetry = (0, import_react16.useCallback)(() => {
6460
+ const clearTelemetry = (0, import_react17.useCallback)(() => {
6317
6461
  const newMap = /* @__PURE__ */ new Map();
6318
6462
  setTelemetry(newMap);
6319
6463
  notifyChange(newMap);
6320
6464
  }, [notifyChange]);
6321
- const setBindings = (0, import_react16.useCallback)(
6465
+ const setBindings = (0, import_react17.useCallback)(
6322
6466
  (bindings) => {
6323
6467
  const newMap = /* @__PURE__ */ new Map();
6324
6468
  bindings.forEach((binding) => {
@@ -6329,7 +6473,7 @@ function useTelemetry(options = {}) {
6329
6473
  },
6330
6474
  [notifyChange]
6331
6475
  );
6332
- (0, import_react16.useEffect)(() => {
6476
+ (0, import_react17.useEffect)(() => {
6333
6477
  if (refreshInterval <= 0) return;
6334
6478
  const intervalId = setInterval(() => {
6335
6479
  notifyChange(telemetryRef.current);
@@ -6347,10 +6491,10 @@ function useTelemetry(options = {}) {
6347
6491
  }
6348
6492
 
6349
6493
  // src/diagram/hooks/useTelemetryStatus.ts
6350
- var import_react17 = require("react");
6494
+ var import_react18 = require("react");
6351
6495
  function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6352
6496
  const { enabled = true, mapStatus } = options;
6353
- (0, import_react17.useEffect)(() => {
6497
+ (0, import_react18.useEffect)(() => {
6354
6498
  if (!enabled) return;
6355
6499
  const defaultMapStatus = (telemetryStatus) => {
6356
6500
  switch (telemetryStatus) {
@@ -6363,8 +6507,13 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6363
6507
  return "alarm";
6364
6508
  case "off":
6365
6509
  return "stopped";
6366
- default:
6510
+ case "unknown":
6511
+ return "unknown";
6512
+ default: {
6513
+ const exhaustive = telemetryStatus;
6514
+ void exhaustive;
6367
6515
  return "stopped";
6516
+ }
6368
6517
  }
6369
6518
  };
6370
6519
  const statusMapper = mapStatus || defaultMapStatus;
@@ -6389,10 +6538,10 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6389
6538
  }
6390
6539
 
6391
6540
  // src/diagram/hooks/useBooleanIndicators.ts
6392
- var import_react18 = require("react");
6541
+ var import_react19 = require("react");
6393
6542
  function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
6394
6543
  const { enabled = true, symbolId = "status-indicator" } = options;
6395
- (0, import_react18.useEffect)(() => {
6544
+ (0, import_react19.useEffect)(() => {
6396
6545
  if (!enabled) return;
6397
6546
  const tagIndex = /* @__PURE__ */ new Map();
6398
6547
  telemetry.forEach((binding) => {
@@ -6430,7 +6579,7 @@ function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
6430
6579
  }
6431
6580
 
6432
6581
  // src/diagram/hooks/useDrag.ts
6433
- var import_react19 = require("react");
6582
+ var import_react20 = require("react");
6434
6583
  function useDrag(options = {}) {
6435
6584
  const {
6436
6585
  onDragStart,
@@ -6440,23 +6589,23 @@ function useDrag(options = {}) {
6440
6589
  dragThreshold = 3,
6441
6590
  screenToWorld = (x, y) => ({ x, y })
6442
6591
  } = options;
6443
- const [dragState, setDragState] = (0, import_react19.useState)({
6592
+ const [dragState, setDragState] = (0, import_react20.useState)({
6444
6593
  isDragging: false,
6445
6594
  startPosition: null,
6446
6595
  offset: { x: 0, y: 0 },
6447
6596
  draggedId: null
6448
6597
  });
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)(
6598
+ const [isListening, setIsListening] = (0, import_react20.useState)(false);
6599
+ const dragStartRef = (0, import_react20.useRef)(null);
6600
+ const hasMovedRef = (0, import_react20.useRef)(false);
6601
+ const applySnap = (0, import_react20.useCallback)(
6453
6602
  (value) => {
6454
6603
  if (snapToGrid <= 0) return value;
6455
6604
  return Math.round(value / snapToGrid) * snapToGrid;
6456
6605
  },
6457
6606
  [snapToGrid]
6458
6607
  );
6459
- const handleMouseMove = (0, import_react19.useCallback)(
6608
+ const handleMouseMove = (0, import_react20.useCallback)(
6460
6609
  (event) => {
6461
6610
  if (!dragStartRef.current) return;
6462
6611
  const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;
@@ -6497,7 +6646,7 @@ function useDrag(options = {}) {
6497
6646
  },
6498
6647
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
6499
6648
  );
6500
- const handleMouseUp = (0, import_react19.useCallback)(
6649
+ const handleMouseUp = (0, import_react20.useCallback)(
6501
6650
  (event) => {
6502
6651
  if (!dragStartRef.current || !hasMovedRef.current) {
6503
6652
  dragStartRef.current = null;
@@ -6534,7 +6683,7 @@ function useDrag(options = {}) {
6534
6683
  },
6535
6684
  [screenToWorld, applySnap, onDragEnd]
6536
6685
  );
6537
- const handleTouchMove = (0, import_react19.useCallback)(
6686
+ const handleTouchMove = (0, import_react20.useCallback)(
6538
6687
  (event) => {
6539
6688
  if (!dragStartRef.current || event.touches.length !== 1) return;
6540
6689
  const touch = event.touches[0];
@@ -6577,7 +6726,7 @@ function useDrag(options = {}) {
6577
6726
  },
6578
6727
  [screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
6579
6728
  );
6580
- const handleTouchEnd = (0, import_react19.useCallback)(
6729
+ const handleTouchEnd = (0, import_react20.useCallback)(
6581
6730
  (event) => {
6582
6731
  if (!dragStartRef.current || !hasMovedRef.current) {
6583
6732
  dragStartRef.current = null;
@@ -6615,7 +6764,7 @@ function useDrag(options = {}) {
6615
6764
  },
6616
6765
  [screenToWorld, applySnap, onDragEnd]
6617
6766
  );
6618
- (0, import_react19.useEffect)(() => {
6767
+ (0, import_react20.useEffect)(() => {
6619
6768
  if (!isListening) return;
6620
6769
  document.addEventListener("mousemove", handleMouseMove);
6621
6770
  document.addEventListener("mouseup", handleMouseUp);
@@ -6630,7 +6779,7 @@ function useDrag(options = {}) {
6630
6779
  document.removeEventListener("touchcancel", handleTouchEnd);
6631
6780
  };
6632
6781
  }, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
6633
- const startDrag = (0, import_react19.useCallback)(
6782
+ const startDrag = (0, import_react20.useCallback)(
6634
6783
  (id, event, itemPosition) => {
6635
6784
  event.stopPropagation();
6636
6785
  let clientX;
@@ -6660,7 +6809,7 @@ function useDrag(options = {}) {
6660
6809
  },
6661
6810
  [screenToWorld]
6662
6811
  );
6663
- const cancelDrag = (0, import_react19.useCallback)(() => {
6812
+ const cancelDrag = (0, import_react20.useCallback)(() => {
6664
6813
  dragStartRef.current = null;
6665
6814
  hasMovedRef.current = false;
6666
6815
  setIsListening(false);
@@ -6671,7 +6820,7 @@ function useDrag(options = {}) {
6671
6820
  draggedId: null
6672
6821
  });
6673
6822
  }, []);
6674
- const isDraggingItem = (0, import_react19.useCallback)(
6823
+ const isDraggingItem = (0, import_react20.useCallback)(
6675
6824
  (id) => dragState.isDragging && dragState.draggedId === id,
6676
6825
  [dragState.isDragging, dragState.draggedId]
6677
6826
  );
@@ -6684,7 +6833,7 @@ function useDrag(options = {}) {
6684
6833
  }
6685
6834
 
6686
6835
  // src/diagram/hooks/useKeyboardShortcuts.ts
6687
- var import_react20 = require("react");
6836
+ var import_react21 = require("react");
6688
6837
  function useKeyboardShortcuts(options) {
6689
6838
  const {
6690
6839
  onDelete,
@@ -6695,7 +6844,7 @@ function useKeyboardShortcuts(options) {
6695
6844
  onSelectAll,
6696
6845
  enabled = true
6697
6846
  } = options;
6698
- (0, import_react20.useEffect)(() => {
6847
+ (0, import_react21.useEffect)(() => {
6699
6848
  if (!enabled) return;
6700
6849
  const handleKeyDown = (event) => {
6701
6850
  const target = event.target;
@@ -6804,7 +6953,7 @@ function nodeHasPort(node, portId) {
6804
6953
  }
6805
6954
 
6806
6955
  // src/components/PIDCanvas/PIDCanvas.tsx
6807
- var import_jsx_runtime20 = require("react/jsx-runtime");
6956
+ var import_jsx_runtime21 = require("react/jsx-runtime");
6808
6957
  var DEFAULT_FEATURES = {
6809
6958
  pan: true,
6810
6959
  zoom: true,
@@ -6833,21 +6982,21 @@ function PIDCanvasImpl({
6833
6982
  statusColorMap,
6834
6983
  ...props
6835
6984
  }) {
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)(() => {
6985
+ const [localDiagram, setLocalDiagram] = (0, import_react22.useState)(diagram);
6986
+ const [dragOverPosition, setDragOverPosition] = (0, import_react22.useState)(null);
6987
+ const [isConnecting, setIsConnecting] = (0, import_react22.useState)(false);
6988
+ const [connectionSource, setConnectionSource] = (0, import_react22.useState)(null);
6989
+ const [connectionSourcePort, setConnectionSourcePort] = (0, import_react22.useState)(null);
6990
+ const [connectionCursor, setConnectionCursor] = (0, import_react22.useState)(null);
6991
+ const [hoveredNode, setHoveredNode] = (0, import_react22.useState)(null);
6992
+ const [hoveredPort, setHoveredPort] = (0, import_react22.useState)(null);
6993
+ const [selectedWaypoint, setSelectedWaypoint] = (0, import_react22.useState)(null);
6994
+ const historyStack = (0, import_react22.useRef)([]);
6995
+ const redoStack = (0, import_react22.useRef)([]);
6996
+ const isUndoRedoAction = (0, import_react22.useRef)(false);
6997
+ const isInternalChange = (0, import_react22.useRef)(false);
6998
+ const lastInternalDiagram = (0, import_react22.useRef)(null);
6999
+ (0, import_react22.useEffect)(() => {
6851
7000
  const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
6852
7001
  if (isExternal) {
6853
7002
  setLocalDiagram(diagram);
@@ -6869,7 +7018,7 @@ function PIDCanvasImpl({
6869
7018
  enablePan: features.pan ?? true,
6870
7019
  enableZoom: features.zoom ?? true
6871
7020
  });
6872
- const calculateContentBounds = (0, import_react21.useCallback)(() => {
7021
+ const calculateContentBounds = (0, import_react22.useCallback)(() => {
6873
7022
  const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
6874
7023
  if (nodes2.length === 0) {
6875
7024
  return null;
@@ -6892,7 +7041,7 @@ function PIDCanvasImpl({
6892
7041
  });
6893
7042
  return { minX, minY, maxX, maxY };
6894
7043
  }, [localDiagram.nodes]);
6895
- (0, import_react21.useEffect)(() => {
7044
+ (0, import_react22.useEffect)(() => {
6896
7045
  if (onMounted) {
6897
7046
  const controls = {
6898
7047
  fitToContent: (padding = 50) => {
@@ -6933,8 +7082,8 @@ function PIDCanvasImpl({
6933
7082
  });
6934
7083
  const dragEnabled = features.dragNodes ?? false;
6935
7084
  const selectionEnabled = features.selection ?? false;
6936
- const containerRef = (0, import_react21.useRef)(null);
6937
- const pushToHistory = (0, import_react21.useCallback)((currentDiagram) => {
7085
+ const containerRef = (0, import_react22.useRef)(null);
7086
+ const pushToHistory = (0, import_react22.useCallback)((currentDiagram) => {
6938
7087
  if (isUndoRedoAction.current) return;
6939
7088
  const snapshot = JSON.parse(JSON.stringify(currentDiagram));
6940
7089
  historyStack.current.push(snapshot);
@@ -6943,7 +7092,7 @@ function PIDCanvasImpl({
6943
7092
  }
6944
7093
  redoStack.current = [];
6945
7094
  }, []);
6946
- const undo = (0, import_react21.useCallback)(() => {
7095
+ const undo = (0, import_react22.useCallback)(() => {
6947
7096
  if (historyStack.current.length === 0) return;
6948
7097
  isUndoRedoAction.current = true;
6949
7098
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6957,7 +7106,7 @@ function PIDCanvasImpl({
6957
7106
  isUndoRedoAction.current = false;
6958
7107
  }, 0);
6959
7108
  }, [localDiagram, onDiagramChange]);
6960
- const redo = (0, import_react21.useCallback)(() => {
7109
+ const redo = (0, import_react22.useCallback)(() => {
6961
7110
  if (redoStack.current.length === 0) return;
6962
7111
  isUndoRedoAction.current = true;
6963
7112
  const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
@@ -6971,7 +7120,7 @@ function PIDCanvasImpl({
6971
7120
  isUndoRedoAction.current = false;
6972
7121
  }, 0);
6973
7122
  }, [localDiagram, onDiagramChange]);
6974
- (0, import_react21.useEffect)(() => {
7123
+ (0, import_react22.useEffect)(() => {
6975
7124
  const handleKeyDown = (e) => {
6976
7125
  const isCtrlOrCmd = e.ctrlKey || e.metaKey;
6977
7126
  if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
@@ -6988,7 +7137,7 @@ function PIDCanvasImpl({
6988
7137
  window.addEventListener("keydown", handleKeyDown);
6989
7138
  return () => window.removeEventListener("keydown", handleKeyDown);
6990
7139
  }, [undo, redo]);
6991
- (0, import_react21.useEffect)(() => {
7140
+ (0, import_react22.useEffect)(() => {
6992
7141
  if (!features.dragNodes) return;
6993
7142
  const handleKeyDown = (e) => {
6994
7143
  if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
@@ -7073,7 +7222,7 @@ function PIDCanvasImpl({
7073
7222
  onNodeMove,
7074
7223
  pushToHistory
7075
7224
  ]);
7076
- const handlePositionChange = (0, import_react21.useCallback)(
7225
+ const handlePositionChange = (0, import_react22.useCallback)(
7077
7226
  (nodeId, x, y) => {
7078
7227
  pushToHistory(localDiagram);
7079
7228
  const updatedNodes = localDiagram.nodes.map(
@@ -7095,7 +7244,7 @@ function PIDCanvasImpl({
7095
7244
  },
7096
7245
  [localDiagram, onDiagramChange, onNodeMove, pushToHistory]
7097
7246
  );
7098
- const handleWaypointPositionChange = (0, import_react21.useCallback)(
7247
+ const handleWaypointPositionChange = (0, import_react22.useCallback)(
7099
7248
  (pipeId, pointIndex, x, y) => {
7100
7249
  pushToHistory(localDiagram);
7101
7250
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -7113,7 +7262,7 @@ function PIDCanvasImpl({
7113
7262
  },
7114
7263
  [localDiagram, onDiagramChange, pushToHistory]
7115
7264
  );
7116
- const handleDragEnd = (0, import_react21.useCallback)(
7265
+ const handleDragEnd = (0, import_react22.useCallback)(
7117
7266
  (nodeId, offset, finalPosition) => {
7118
7267
  const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
7119
7268
  if (dragDistance < 2) {
@@ -7194,7 +7343,7 @@ function PIDCanvasImpl({
7194
7343
  onDiagramChange?.(updatedDiagram);
7195
7344
  }
7196
7345
  });
7197
- const handleNodeDragStart = (0, import_react21.useCallback)(
7346
+ const handleNodeDragStart = (0, import_react22.useCallback)(
7198
7347
  (nodeId, event) => {
7199
7348
  const node = localDiagram.nodes.find((n) => n.id === nodeId);
7200
7349
  if (!node) return;
@@ -7202,7 +7351,7 @@ function PIDCanvasImpl({
7202
7351
  },
7203
7352
  [localDiagram.nodes, startDrag]
7204
7353
  );
7205
- const handleWaypointClick = (0, import_react21.useCallback)(
7354
+ const handleWaypointClick = (0, import_react22.useCallback)(
7206
7355
  (pipeId, pointIndex) => {
7207
7356
  setSelectedWaypoint({ pipeId, pointIndex });
7208
7357
  if (selectionEnabled) {
@@ -7211,7 +7360,7 @@ function PIDCanvasImpl({
7211
7360
  },
7212
7361
  [selectionEnabled, clearSelection]
7213
7362
  );
7214
- const handleWaypointDragStart = (0, import_react21.useCallback)(
7363
+ const handleWaypointDragStart = (0, import_react22.useCallback)(
7215
7364
  (pipeId, pointIndex, event) => {
7216
7365
  const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
7217
7366
  if (!pipe || pointIndex >= pipe.routePoints.length) return;
@@ -7220,7 +7369,7 @@ function PIDCanvasImpl({
7220
7369
  },
7221
7370
  [localDiagram.pipes, startWaypointDrag]
7222
7371
  );
7223
- const handlePipeSegmentClick = (0, import_react21.useCallback)(
7372
+ const handlePipeSegmentClick = (0, import_react22.useCallback)(
7224
7373
  (pipeId, position, segmentIndex) => {
7225
7374
  pushToHistory(localDiagram);
7226
7375
  const updatedPipes = localDiagram.pipes.map((pipe) => {
@@ -7239,7 +7388,7 @@ function PIDCanvasImpl({
7239
7388
  [localDiagram, onDiagramChange, pushToHistory]
7240
7389
  );
7241
7390
  const telemetryEnabled = features.telemetry ?? false;
7242
- const handleDelete = (0, import_react21.useCallback)(() => {
7391
+ const handleDelete = (0, import_react22.useCallback)(() => {
7243
7392
  if (!selectionEnabled) return;
7244
7393
  const { selectedNodeIds, selectedPipeIds } = selection;
7245
7394
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
@@ -7268,17 +7417,17 @@ function PIDCanvasImpl({
7268
7417
  onDelete,
7269
7418
  pushToHistory
7270
7419
  ]);
7271
- const handleCopy = (0, import_react21.useCallback)(() => {
7420
+ const handleCopy = (0, import_react22.useCallback)(() => {
7272
7421
  if (!selectionEnabled) return;
7273
7422
  const { selectedNodeIds, selectedPipeIds } = selection;
7274
7423
  if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
7275
7424
  onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
7276
7425
  }, [selection, selectionEnabled, onItemsCopied]);
7277
- const handlePaste = (0, import_react21.useCallback)(() => {
7426
+ const handlePaste = (0, import_react22.useCallback)(() => {
7278
7427
  if (!selectionEnabled) return;
7279
7428
  onPaste?.();
7280
7429
  }, [selectionEnabled, onPaste]);
7281
- const handleNodeDoubleClick = (0, import_react21.useCallback)(
7430
+ const handleNodeDoubleClick = (0, import_react22.useCallback)(
7282
7431
  (nodeId, event) => {
7283
7432
  if (!selectionEnabled) return;
7284
7433
  console.log("Node double-clicked:", nodeId);
@@ -7292,7 +7441,7 @@ function PIDCanvasImpl({
7292
7441
  onCopy: handleCopy,
7293
7442
  onPaste: handlePaste
7294
7443
  });
7295
- const handleNodeClick = (0, import_react21.useCallback)(
7444
+ const handleNodeClick = (0, import_react22.useCallback)(
7296
7445
  (nodeId, event) => {
7297
7446
  const connectionModeEnabled = features.connectionMode ?? false;
7298
7447
  if (connectionModeEnabled && isConnecting) {
@@ -7334,7 +7483,7 @@ function PIDCanvasImpl({
7334
7483
  onNodeClick
7335
7484
  ]
7336
7485
  );
7337
- const handlePipeClick = (0, import_react21.useCallback)(
7486
+ const handlePipeClick = (0, import_react22.useCallback)(
7338
7487
  (pipeId, event) => {
7339
7488
  if (selectionEnabled) {
7340
7489
  selectPipe(pipeId, event.ctrlKey || event.metaKey);
@@ -7353,7 +7502,7 @@ function PIDCanvasImpl({
7353
7502
  }
7354
7503
  setSelectedWaypoint(null);
7355
7504
  };
7356
- const handleDragOver = (0, import_react21.useCallback)(
7505
+ const handleDragOver = (0, import_react22.useCallback)(
7357
7506
  (event) => {
7358
7507
  if (!features.allowSymbolDrop) return;
7359
7508
  event.preventDefault();
@@ -7364,7 +7513,7 @@ function PIDCanvasImpl({
7364
7513
  },
7365
7514
  [features.allowSymbolDrop, screenToWorld, svgRef]
7366
7515
  );
7367
- const handleDrop = (0, import_react21.useCallback)(
7516
+ const handleDrop = (0, import_react22.useCallback)(
7368
7517
  (event) => {
7369
7518
  if (!features.allowSymbolDrop) return;
7370
7519
  event.preventDefault();
@@ -7377,10 +7526,10 @@ function PIDCanvasImpl({
7377
7526
  },
7378
7527
  [features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
7379
7528
  );
7380
- const handleDragLeave = (0, import_react21.useCallback)(() => {
7529
+ const handleDragLeave = (0, import_react22.useCallback)(() => {
7381
7530
  setDragOverPosition(null);
7382
7531
  }, []);
7383
- const handleMouseMove = (0, import_react21.useCallback)(
7532
+ const handleMouseMove = (0, import_react22.useCallback)(
7384
7533
  (event) => {
7385
7534
  const connectionModeEnabled = features.connectionMode ?? false;
7386
7535
  if (connectionModeEnabled) {
@@ -7417,7 +7566,7 @@ function PIDCanvasImpl({
7417
7566
  const viewBox = controlledViewBox;
7418
7567
  const displayDiagram = localDiagram;
7419
7568
  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)(
7569
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7421
7570
  "div",
7422
7571
  {
7423
7572
  ref: containerRef,
@@ -7432,7 +7581,7 @@ function PIDCanvasImpl({
7432
7581
  },
7433
7582
  ...props,
7434
7583
  children: [
7435
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7584
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7436
7585
  "svg",
7437
7586
  {
7438
7587
  ref: svgRef,
@@ -7451,15 +7600,15 @@ function PIDCanvasImpl({
7451
7600
  onDrop: handleDrop,
7452
7601
  onDragLeave: handleDragLeave,
7453
7602
  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" })
7603
+ features.showGrid !== false ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7604
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("defs", { children: [
7605
+ /* @__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" }) }),
7606
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
7607
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
7608
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
7460
7609
  ] })
7461
7610
  ] }),
7462
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7611
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7463
7612
  "rect",
7464
7613
  {
7465
7614
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7469,7 +7618,7 @@ function PIDCanvasImpl({
7469
7618
  fill: "url(#grid-major)"
7470
7619
  }
7471
7620
  )
7472
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7621
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7473
7622
  "rect",
7474
7623
  {
7475
7624
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7479,7 +7628,7 @@ function PIDCanvasImpl({
7479
7628
  fill: features.backgroundColor ?? "#ffffff"
7480
7629
  }
7481
7630
  ),
7482
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7631
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7483
7632
  PipeRenderer,
7484
7633
  {
7485
7634
  pipes: displayDiagram.pipes,
@@ -7493,7 +7642,7 @@ function PIDCanvasImpl({
7493
7642
  onPipeSegmentClick: void 0
7494
7643
  }
7495
7644
  ),
7496
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7645
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7497
7646
  NodeRenderer,
7498
7647
  {
7499
7648
  nodes: displayDiagram.nodes,
@@ -7507,7 +7656,7 @@ function PIDCanvasImpl({
7507
7656
  statusColorMap
7508
7657
  }
7509
7658
  ),
7510
- (features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7659
+ (features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7511
7660
  PipeRenderer,
7512
7661
  {
7513
7662
  pipes: displayDiagram.pipes,
@@ -7524,7 +7673,7 @@ function PIDCanvasImpl({
7524
7673
  onPipeSegmentClick: handlePipeSegmentClick
7525
7674
  }
7526
7675
  ),
7527
- telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7676
+ telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7528
7677
  if (node.symbolId === "status-indicator") return null;
7529
7678
  const binding = telemetry.get(node.id);
7530
7679
  if (!binding) return null;
@@ -7532,7 +7681,7 @@ function PIDCanvasImpl({
7532
7681
  if (!symbol) return null;
7533
7682
  const overlayX = node.transform.x + symbol.viewBox.width / 2;
7534
7683
  const overlayY = node.transform.y + symbol.viewBox.height + 50;
7535
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7684
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7536
7685
  DataOverlay,
7537
7686
  {
7538
7687
  nodeId: node.id,
@@ -7545,7 +7694,7 @@ function PIDCanvasImpl({
7545
7694
  `telemetry-${node.id}`
7546
7695
  );
7547
7696
  }) }),
7548
- dragOverPosition && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7697
+ dragOverPosition && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7549
7698
  "circle",
7550
7699
  {
7551
7700
  cx: dragOverPosition.x,
@@ -7558,7 +7707,7 @@ function PIDCanvasImpl({
7558
7707
  pointerEvents: "none"
7559
7708
  }
7560
7709
  ),
7561
- isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7710
+ isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7562
7711
  const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
7563
7712
  if (!sourceNode) return null;
7564
7713
  const symbol = getSymbolDefinition(sourceNode.symbolId);
@@ -7574,8 +7723,8 @@ function PIDCanvasImpl({
7574
7723
  }
7575
7724
  }
7576
7725
  }
7577
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
7578
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7726
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7727
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7579
7728
  "circle",
7580
7729
  {
7581
7730
  cx: lineStartX,
@@ -7587,7 +7736,7 @@ function PIDCanvasImpl({
7587
7736
  opacity: 0.6
7588
7737
  }
7589
7738
  ),
7590
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7739
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7591
7740
  "line",
7592
7741
  {
7593
7742
  x1: lineStartX,
@@ -7600,7 +7749,7 @@ function PIDCanvasImpl({
7600
7749
  opacity: 0.8
7601
7750
  }
7602
7751
  ),
7603
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7752
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7604
7753
  "circle",
7605
7754
  {
7606
7755
  cx: connectionCursor.x,
@@ -7612,7 +7761,7 @@ function PIDCanvasImpl({
7612
7761
  )
7613
7762
  ] });
7614
7763
  })() }),
7615
- features.connectionMode && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7764
+ features.connectionMode && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7616
7765
  const symbol = getSymbolDefinition(node.symbolId);
7617
7766
  if (!symbol?.ports) return null;
7618
7767
  return symbol.ports.map((port) => {
@@ -7620,8 +7769,8 @@ function PIDCanvasImpl({
7620
7769
  if (!portPos) return null;
7621
7770
  const isHovered = hoveredPort === port.id && hoveredNode === node.id;
7622
7771
  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)(
7772
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("g", { children: [
7773
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7625
7774
  "circle",
7626
7775
  {
7627
7776
  cx: portPos.x,
@@ -7654,7 +7803,7 @@ function PIDCanvasImpl({
7654
7803
  }
7655
7804
  }
7656
7805
  ),
7657
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7806
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7658
7807
  "circle",
7659
7808
  {
7660
7809
  cx: portPos.x,
@@ -7673,7 +7822,7 @@ function PIDCanvasImpl({
7673
7822
  ]
7674
7823
  }
7675
7824
  ),
7676
- features.dragNodes && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7825
+ features.dragNodes && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7677
7826
  PositionPanel,
7678
7827
  {
7679
7828
  selectedNode,
@@ -7691,19 +7840,19 @@ function PIDCanvasImpl({
7691
7840
  }
7692
7841
  );
7693
7842
  }
7694
- var PIDCanvas = import_react21.default.memo(PIDCanvasImpl);
7843
+ var PIDCanvas = import_react22.default.memo(PIDCanvasImpl);
7695
7844
 
7696
7845
  // src/components/SymbolLibrary/SymbolLibrary.tsx
7697
- var import_react22 = require("react");
7698
- var import_jsx_runtime21 = require("react/jsx-runtime");
7846
+ var import_react23 = require("react");
7847
+ var import_jsx_runtime22 = require("react/jsx-runtime");
7699
7848
  function SymbolLibrary({
7700
7849
  className = "",
7701
7850
  onSymbolDragStart,
7702
7851
  showCategories = true,
7703
7852
  categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
7704
7853
  }) {
7705
- const [selectedCategory, setSelectedCategory] = (0, import_react22.useState)("all");
7706
- const [searchQuery, setSearchQuery] = (0, import_react22.useState)("");
7854
+ const [selectedCategory, setSelectedCategory] = (0, import_react23.useState)("all");
7855
+ const [searchQuery, setSearchQuery] = (0, import_react23.useState)("");
7707
7856
  const symbolIds = getAvailableSymbols();
7708
7857
  const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
7709
7858
  const categoryMap = {
@@ -7724,9 +7873,9 @@ function SymbolLibrary({
7724
7873
  event.dataTransfer.effectAllowed = "copy";
7725
7874
  onSymbolDragStart?.(symbol.id, event);
7726
7875
  };
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)(
7876
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
7877
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: styles.title, children: "Symbol Library" }) }),
7878
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.searchContainer, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7730
7879
  "input",
7731
7880
  {
7732
7881
  type: "text",
@@ -7736,8 +7885,8 @@ function SymbolLibrary({
7736
7885
  style: styles.searchInput
7737
7886
  }
7738
7887
  ) }),
7739
- showCategories && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: styles.categories, children: [
7740
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7888
+ showCategories && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: styles.categories, children: [
7889
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7741
7890
  "button",
7742
7891
  {
7743
7892
  onClick: () => setSelectedCategory("all"),
@@ -7748,7 +7897,7 @@ function SymbolLibrary({
7748
7897
  children: "All"
7749
7898
  }
7750
7899
  ),
7751
- categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7900
+ categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7752
7901
  "button",
7753
7902
  {
7754
7903
  onClick: () => setSelectedCategory(category),
@@ -7761,7 +7910,7 @@ function SymbolLibrary({
7761
7910
  category
7762
7911
  ))
7763
7912
  ] }),
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)(
7913
+ /* @__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
7914
  "div",
7766
7915
  {
7767
7916
  draggable: true,
@@ -7769,15 +7918,15 @@ function SymbolLibrary({
7769
7918
  style: styles.symbolCard,
7770
7919
  title: symbol.metadata?.description || symbol.name,
7771
7920
  children: [
7772
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.symbolPreview, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7921
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.symbolPreview, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7773
7922
  "svg",
7774
7923
  {
7775
7924
  viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
7776
7925
  style: styles.symbolSvg,
7777
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
7926
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
7778
7927
  }
7779
7928
  ) }),
7780
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: styles.symbolName, children: symbol.name })
7929
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: styles.symbolName, children: symbol.name })
7781
7930
  ]
7782
7931
  },
7783
7932
  symbol.id
@@ -7886,7 +8035,7 @@ var styles = {
7886
8035
  };
7887
8036
 
7888
8037
  // src/components/NodeConfigPanel/NodeConfigPanel.tsx
7889
- var import_jsx_runtime22 = require("react/jsx-runtime");
8038
+ var import_jsx_runtime23 = require("react/jsx-runtime");
7890
8039
  function NodeConfigPanel({
7891
8040
  node,
7892
8041
  binding,
@@ -7909,15 +8058,15 @@ function NodeConfigPanel({
7909
8058
  };
7910
8059
  const appearanceFields = getAppearanceSchema(node.symbolId);
7911
8060
  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: [
8061
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, style: defaultStyle, children: [
8062
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
7914
8063
  "Configure: ",
7915
8064
  node.id
7916
8065
  ] }),
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)(
8066
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8067
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
8068
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
8069
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7921
8070
  "input",
7922
8071
  {
7923
8072
  type: "text",
@@ -7933,10 +8082,10 @@ function NodeConfigPanel({
7933
8082
  }
7934
8083
  }
7935
8084
  ),
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)(
8085
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8086
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8087
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
8088
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7940
8089
  "input",
7941
8090
  {
7942
8091
  type: "number",
@@ -7957,9 +8106,9 @@ function NodeConfigPanel({
7957
8106
  }
7958
8107
  )
7959
8108
  ] }),
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)(
8109
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8110
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
8111
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7963
8112
  "input",
7964
8113
  {
7965
8114
  type: "number",
@@ -7981,9 +8130,9 @@ function NodeConfigPanel({
7981
8130
  )
7982
8131
  ] })
7983
8132
  ] }),
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)(
8133
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8134
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
8135
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7987
8136
  "input",
7988
8137
  {
7989
8138
  type: "number",
@@ -8003,9 +8152,9 @@ function NodeConfigPanel({
8003
8152
  }
8004
8153
  )
8005
8154
  ] }),
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)(
8155
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8156
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
8157
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8009
8158
  "input",
8010
8159
  {
8011
8160
  type: "number",
@@ -8030,8 +8179,8 @@ function NodeConfigPanel({
8030
8179
  )
8031
8180
  ] })
8032
8181
  ] }),
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" }),
8182
+ appearanceFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8183
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
8035
8184
  appearanceFields.map((field) => {
8036
8185
  const value = readAppearanceValue(node, field);
8037
8186
  const fieldLabel = field.label ?? field.key;
@@ -8044,8 +8193,8 @@ function NodeConfigPanel({
8044
8193
  };
8045
8194
  let control;
8046
8195
  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)(
8196
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
8197
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8049
8198
  "input",
8050
8199
  {
8051
8200
  type: "checkbox",
@@ -8057,28 +8206,28 @@ function NodeConfigPanel({
8057
8206
  fieldLabel
8058
8207
  ] });
8059
8208
  } 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: [
8209
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8210
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8062
8211
  fieldLabel,
8063
8212
  ":"
8064
8213
  ] }),
8065
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8214
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8066
8215
  "select",
8067
8216
  {
8068
8217
  value: String(value),
8069
8218
  onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
8070
8219
  style: inputStyle,
8071
- children: field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: opt, children: opt }, opt))
8220
+ children: field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: opt, children: opt }, opt))
8072
8221
  }
8073
8222
  )
8074
8223
  ] });
8075
8224
  } 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: [
8225
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8226
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8078
8227
  fieldLabel,
8079
8228
  ":"
8080
8229
  ] }),
8081
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8230
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8082
8231
  "input",
8083
8232
  {
8084
8233
  type: "number",
@@ -8093,12 +8242,12 @@ function NodeConfigPanel({
8093
8242
  const listId = `tags-${node.id}-${field.key}`;
8094
8243
  const known = tagValue.length > 0 && availableTags.includes(tagValue);
8095
8244
  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: [
8245
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8246
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8098
8247
  fieldLabel,
8099
8248
  ":"
8100
8249
  ] }),
8101
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8250
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8102
8251
  "input",
8103
8252
  {
8104
8253
  type: "text",
@@ -8112,8 +8261,8 @@ function NodeConfigPanel({
8112
8261
  }
8113
8262
  }
8114
8263
  ),
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)(
8264
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: t }, t)) }),
8265
+ tagValue.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8117
8266
  "div",
8118
8267
  {
8119
8268
  style: {
@@ -8126,12 +8275,12 @@ function NodeConfigPanel({
8126
8275
  )
8127
8276
  ] });
8128
8277
  } 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: [
8278
+ control = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8279
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8131
8280
  fieldLabel,
8132
8281
  ":"
8133
8282
  ] }),
8134
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8283
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8135
8284
  "input",
8136
8285
  {
8137
8286
  type: "text",
@@ -8142,9 +8291,9 @@ function NodeConfigPanel({
8142
8291
  )
8143
8292
  ] });
8144
8293
  }
8145
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "10px" }, children: [
8294
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "10px" }, children: [
8146
8295
  control,
8147
- field.help && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8296
+ field.help && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8148
8297
  "div",
8149
8298
  {
8150
8299
  style: {
@@ -8159,9 +8308,9 @@ function NodeConfigPanel({
8159
8308
  ] }, field.key);
8160
8309
  })
8161
8310
  ] }),
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)(
8311
+ showGenericTelemetry && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8312
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
8313
+ !binding ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8165
8314
  "button",
8166
8315
  {
8167
8316
  onClick: () => {
@@ -8204,9 +8353,9 @@ function NodeConfigPanel({
8204
8353
  },
8205
8354
  children: "+ Add Telemetry"
8206
8355
  }
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)(
8356
+ ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8357
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
8358
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8210
8359
  "input",
8211
8360
  {
8212
8361
  type: "text",
@@ -8226,8 +8375,8 @@ function NodeConfigPanel({
8226
8375
  }
8227
8376
  }
8228
8377
  ),
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)(
8378
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
8379
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8231
8380
  "input",
8232
8381
  {
8233
8382
  type: "number",
@@ -8249,8 +8398,8 @@ function NodeConfigPanel({
8249
8398
  }
8250
8399
  }
8251
8400
  ),
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)(
8401
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
8402
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8254
8403
  "input",
8255
8404
  {
8256
8405
  type: "text",
@@ -8272,8 +8421,8 @@ function NodeConfigPanel({
8272
8421
  }
8273
8422
  }
8274
8423
  ),
8275
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8276
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8424
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8425
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8277
8426
  "input",
8278
8427
  {
8279
8428
  type: "checkbox",
@@ -8295,8 +8444,8 @@ function NodeConfigPanel({
8295
8444
  ),
8296
8445
  "Show Sparkline"
8297
8446
  ] }),
8298
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginTop: "12px" }, children: [
8299
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8447
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginTop: "12px" }, children: [
8448
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8300
8449
  "label",
8301
8450
  {
8302
8451
  style: {
@@ -8308,10 +8457,10 @@ function NodeConfigPanel({
8308
8457
  children: "Telemetry Position Offset:"
8309
8458
  }
8310
8459
  ),
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)(
8460
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8461
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8462
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
8463
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8315
8464
  "input",
8316
8465
  {
8317
8466
  type: "number",
@@ -8338,9 +8487,9 @@ function NodeConfigPanel({
8338
8487
  }
8339
8488
  )
8340
8489
  ] }),
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)(
8490
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
8491
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
8492
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8344
8493
  "input",
8345
8494
  {
8346
8495
  type: "number",
@@ -8368,8 +8517,8 @@ function NodeConfigPanel({
8368
8517
  )
8369
8518
  ] })
8370
8519
  ] }),
8371
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginTop: "16px" }, children: [
8372
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8520
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginTop: "16px" }, children: [
8521
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8373
8522
  "label",
8374
8523
  {
8375
8524
  style: {
@@ -8381,10 +8530,10 @@ function NodeConfigPanel({
8381
8530
  children: "Display Colors:"
8382
8531
  }
8383
8532
  ),
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)(
8533
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8534
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
8535
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8536
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8388
8537
  "input",
8389
8538
  {
8390
8539
  type: "color",
@@ -8410,7 +8559,7 @@ function NodeConfigPanel({
8410
8559
  }
8411
8560
  }
8412
8561
  ),
8413
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8562
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8414
8563
  "input",
8415
8564
  {
8416
8565
  type: "text",
@@ -8440,10 +8589,10 @@ function NodeConfigPanel({
8440
8589
  )
8441
8590
  ] })
8442
8591
  ] }),
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)(
8592
+ binding.display?.showSparkline && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8593
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
8594
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8595
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8447
8596
  "input",
8448
8597
  {
8449
8598
  type: "color",
@@ -8469,7 +8618,7 @@ function NodeConfigPanel({
8469
8618
  }
8470
8619
  }
8471
8620
  ),
8472
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8621
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8473
8622
  "input",
8474
8623
  {
8475
8624
  type: "text",
@@ -8499,9 +8648,9 @@ function NodeConfigPanel({
8499
8648
  )
8500
8649
  ] })
8501
8650
  ] }),
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)(
8651
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8652
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
8653
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8505
8654
  "input",
8506
8655
  {
8507
8656
  type: "text",
@@ -8529,12 +8678,12 @@ function NodeConfigPanel({
8529
8678
  }
8530
8679
  }
8531
8680
  ),
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" })
8681
+ /* @__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
8682
  ] })
8534
8683
  ] }),
8535
8684
  " "
8536
8685
  ] }),
8537
- onRemoveTelemetry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8686
+ onRemoveTelemetry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8538
8687
  "button",
8539
8688
  {
8540
8689
  onClick: onRemoveTelemetry,
@@ -8554,13 +8703,13 @@ function NodeConfigPanel({
8554
8703
  )
8555
8704
  ] })
8556
8705
  ] }),
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" }),
8706
+ showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8707
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
8559
8708
  ["highHigh", "high", "low", "lowLow"].map((key) => {
8560
8709
  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)(
8710
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8711
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
8712
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8564
8713
  "input",
8565
8714
  {
8566
8715
  type: "number",
@@ -8584,8 +8733,8 @@ function NodeConfigPanel({
8584
8733
  ] }, key);
8585
8734
  })
8586
8735
  ] }),
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" }),
8736
+ showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "20px" }, children: [
8737
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
8589
8738
  ["normal", "warning", "alarm", "fault", "off"].map((status) => {
8590
8739
  const defaultColors = {
8591
8740
  normal: "#10b981",
@@ -8595,13 +8744,13 @@ function NodeConfigPanel({
8595
8744
  off: "#6b7280"
8596
8745
  };
8597
8746
  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: [
8747
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { marginBottom: "8px" }, children: [
8748
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8600
8749
  label,
8601
8750
  ":"
8602
8751
  ] }),
8603
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8604
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8752
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8753
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8605
8754
  "input",
8606
8755
  {
8607
8756
  type: "color",
@@ -8622,7 +8771,7 @@ function NodeConfigPanel({
8622
8771
  }
8623
8772
  }
8624
8773
  ),
8625
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8774
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8626
8775
  "input",
8627
8776
  {
8628
8777
  type: "text",
@@ -8649,7 +8798,7 @@ function NodeConfigPanel({
8649
8798
  ] }, status);
8650
8799
  })
8651
8800
  ] }),
8652
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8801
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8653
8802
  "button",
8654
8803
  {
8655
8804
  onClick: onRemove,
@@ -8926,13 +9075,13 @@ function createControlBinding(nodeId, deviceConfig, actions) {
8926
9075
  }
8927
9076
 
8928
9077
  // src/hooks/useDeviceControls.ts
8929
- var import_react23 = require("react");
9078
+ var import_react24 = require("react");
8930
9079
  function commandKey(nodeId, kind, suffix) {
8931
9080
  return suffix ? `${nodeId}:${kind}:${suffix}` : `${nodeId}:${kind}`;
8932
9081
  }
8933
9082
  function useDeviceControls(initialBindings, options) {
8934
9083
  const { commandTimeoutMs } = options ?? {};
8935
- const [controls, setControls] = (0, import_react23.useState)(() => {
9084
+ const [controls, setControls] = (0, import_react24.useState)(() => {
8936
9085
  const map = /* @__PURE__ */ new Map();
8937
9086
  if (initialBindings) {
8938
9087
  initialBindings.forEach((binding) => {
@@ -8941,12 +9090,12 @@ function useDeviceControls(initialBindings, options) {
8941
9090
  }
8942
9091
  return map;
8943
9092
  });
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)(() => {
9093
+ const pendingRef = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
9094
+ const [pendingCommands, setPendingCommands] = (0, import_react24.useState)(() => /* @__PURE__ */ new Set());
9095
+ const syncPending = (0, import_react24.useCallback)(() => {
8947
9096
  setPendingCommands(new Set(pendingRef.current.keys()));
8948
9097
  }, []);
8949
- const updateControl = (0, import_react23.useCallback)((nodeId, updates) => {
9098
+ const updateControl = (0, import_react24.useCallback)((nodeId, updates) => {
8950
9099
  setControls((prev) => {
8951
9100
  const newMap = new Map(prev);
8952
9101
  const existing = newMap.get(nodeId);
@@ -8960,7 +9109,7 @@ function useDeviceControls(initialBindings, options) {
8960
9109
  return newMap;
8961
9110
  });
8962
9111
  }, []);
8963
- const updateControlBatch = (0, import_react23.useCallback)((updates) => {
9112
+ const updateControlBatch = (0, import_react24.useCallback)((updates) => {
8964
9113
  setControls((prev) => {
8965
9114
  const newMap = new Map(prev);
8966
9115
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -8972,7 +9121,7 @@ function useDeviceControls(initialBindings, options) {
8972
9121
  return newMap;
8973
9122
  });
8974
9123
  }, []);
8975
- const updateDeviceState = (0, import_react23.useCallback)(
9124
+ const updateDeviceState = (0, import_react24.useCallback)(
8976
9125
  (nodeId, stateUpdates) => {
8977
9126
  setControls((prev) => {
8978
9127
  const newMap = new Map(prev);
@@ -8988,7 +9137,7 @@ function useDeviceControls(initialBindings, options) {
8988
9137
  },
8989
9138
  []
8990
9139
  );
8991
- const updateParameter = (0, import_react23.useCallback)(
9140
+ const updateParameter = (0, import_react24.useCallback)(
8992
9141
  (nodeId, parameterId, value) => {
8993
9142
  setControls((prev) => {
8994
9143
  const newMap = new Map(prev);
@@ -9015,27 +9164,27 @@ function useDeviceControls(initialBindings, options) {
9015
9164
  },
9016
9165
  []
9017
9166
  );
9018
- const setControlBinding = (0, import_react23.useCallback)((binding) => {
9167
+ const setControlBinding = (0, import_react24.useCallback)((binding) => {
9019
9168
  setControls((prev) => {
9020
9169
  const newMap = new Map(prev);
9021
9170
  newMap.set(binding.nodeId, binding);
9022
9171
  return newMap;
9023
9172
  });
9024
9173
  }, []);
9025
- const removeControlBinding = (0, import_react23.useCallback)((nodeId) => {
9174
+ const removeControlBinding = (0, import_react24.useCallback)((nodeId) => {
9026
9175
  setControls((prev) => {
9027
9176
  const newMap = new Map(prev);
9028
9177
  newMap.delete(nodeId);
9029
9178
  return newMap;
9030
9179
  });
9031
9180
  }, []);
9032
- const getControlBinding = (0, import_react23.useCallback)(
9181
+ const getControlBinding = (0, import_react24.useCallback)(
9033
9182
  (nodeId) => {
9034
9183
  return controls.get(nodeId);
9035
9184
  },
9036
9185
  [controls]
9037
9186
  );
9038
- const isCommandPending = (0, import_react23.useCallback)(
9187
+ const isCommandPending = (0, import_react24.useCallback)(
9039
9188
  (nodeId, kind) => {
9040
9189
  if (kind) {
9041
9190
  const prefix2 = `${nodeId}:${kind}`;
@@ -9052,7 +9201,7 @@ function useDeviceControls(initialBindings, options) {
9052
9201
  },
9053
9202
  [pendingCommands]
9054
9203
  );
9055
- const markPending = (0, import_react23.useCallback)(
9204
+ const markPending = (0, import_react24.useCallback)(
9056
9205
  (key, delta) => {
9057
9206
  const next = (pendingRef.current.get(key) ?? 0) + delta;
9058
9207
  if (next > 0) pendingRef.current.set(key, next);
@@ -9061,7 +9210,7 @@ function useDeviceControls(initialBindings, options) {
9061
9210
  },
9062
9211
  [syncPending]
9063
9212
  );
9064
- const runCommand = (0, import_react23.useCallback)(
9213
+ const runCommand = (0, import_react24.useCallback)(
9065
9214
  async (nodeId, key, invoke, messages) => {
9066
9215
  const binding = controls.get(nodeId);
9067
9216
  if (!binding) return;
@@ -9101,7 +9250,7 @@ function useDeviceControls(initialBindings, options) {
9101
9250
  },
9102
9251
  [controls, updateDeviceState, markPending, commandTimeoutMs]
9103
9252
  );
9104
- const sendModeChange = (0, import_react23.useCallback)(
9253
+ const sendModeChange = (0, import_react24.useCallback)(
9105
9254
  (nodeId, mode) => runCommand(
9106
9255
  nodeId,
9107
9256
  commandKey(nodeId, "mode"),
@@ -9110,7 +9259,7 @@ function useDeviceControls(initialBindings, options) {
9110
9259
  ),
9111
9260
  [runCommand]
9112
9261
  );
9113
- const sendParameterChange = (0, import_react23.useCallback)(
9262
+ const sendParameterChange = (0, import_react24.useCallback)(
9114
9263
  (nodeId, parameterId, value) => runCommand(
9115
9264
  nodeId,
9116
9265
  commandKey(nodeId, "parameter", parameterId),
@@ -9119,21 +9268,21 @@ function useDeviceControls(initialBindings, options) {
9119
9268
  ),
9120
9269
  [runCommand]
9121
9270
  );
9122
- const sendStartCommand = (0, import_react23.useCallback)(
9271
+ const sendStartCommand = (0, import_react24.useCallback)(
9123
9272
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "start"), (binding) => binding.actions.onStart?.(), {
9124
9273
  success: "Start command sent",
9125
9274
  failure: "Start command failed"
9126
9275
  }),
9127
9276
  [runCommand]
9128
9277
  );
9129
- const sendStopCommand = (0, import_react23.useCallback)(
9278
+ const sendStopCommand = (0, import_react24.useCallback)(
9130
9279
  (nodeId) => runCommand(nodeId, commandKey(nodeId, "stop"), (binding) => binding.actions.onStop?.(), {
9131
9280
  success: "Stop command sent",
9132
9281
  failure: "Stop command failed"
9133
9282
  }),
9134
9283
  [runCommand]
9135
9284
  );
9136
- const sendCustomAction = (0, import_react23.useCallback)(
9285
+ const sendCustomAction = (0, import_react24.useCallback)(
9137
9286
  (nodeId, actionId) => runCommand(
9138
9287
  nodeId,
9139
9288
  commandKey(nodeId, "action", actionId),
@@ -9186,9 +9335,9 @@ function createConfigBinding(nodeId, tag, parameters, actions, options) {
9186
9335
  }
9187
9336
 
9188
9337
  // src/hooks/useDeviceConfigs.ts
9189
- var import_react24 = require("react");
9338
+ var import_react25 = require("react");
9190
9339
  function useDeviceConfigs(initialConfigs) {
9191
- const [configs, setConfigs] = (0, import_react24.useState)(() => {
9340
+ const [configs, setConfigs] = (0, import_react25.useState)(() => {
9192
9341
  const map = /* @__PURE__ */ new Map();
9193
9342
  if (initialConfigs) {
9194
9343
  initialConfigs.forEach((config) => {
@@ -9197,13 +9346,13 @@ function useDeviceConfigs(initialConfigs) {
9197
9346
  }
9198
9347
  return map;
9199
9348
  });
9200
- const getConfig = (0, import_react24.useCallback)(
9349
+ const getConfig = (0, import_react25.useCallback)(
9201
9350
  (nodeId) => {
9202
9351
  return configs.get(nodeId);
9203
9352
  },
9204
9353
  [configs]
9205
9354
  );
9206
- const updateConfig = (0, import_react24.useCallback)((nodeId, updates) => {
9355
+ const updateConfig = (0, import_react25.useCallback)((nodeId, updates) => {
9207
9356
  setConfigs((prev) => {
9208
9357
  const newMap = new Map(prev);
9209
9358
  const existing = newMap.get(nodeId);
@@ -9217,7 +9366,7 @@ function useDeviceConfigs(initialConfigs) {
9217
9366
  return newMap;
9218
9367
  });
9219
9368
  }, []);
9220
- const updateConfigState = (0, import_react24.useCallback)((nodeId, stateUpdates) => {
9369
+ const updateConfigState = (0, import_react25.useCallback)((nodeId, stateUpdates) => {
9221
9370
  setConfigs((prev) => {
9222
9371
  const newMap = new Map(prev);
9223
9372
  const existing = newMap.get(nodeId);
@@ -9230,7 +9379,7 @@ function useDeviceConfigs(initialConfigs) {
9230
9379
  return newMap;
9231
9380
  });
9232
9381
  }, []);
9233
- const updateConfigBatch = (0, import_react24.useCallback)((updates) => {
9382
+ const updateConfigBatch = (0, import_react25.useCallback)((updates) => {
9234
9383
  setConfigs((prev) => {
9235
9384
  const newMap = new Map(prev);
9236
9385
  Object.entries(updates).forEach(([nodeId, update]) => {
@@ -9242,7 +9391,7 @@ function useDeviceConfigs(initialConfigs) {
9242
9391
  return newMap;
9243
9392
  });
9244
9393
  }, []);
9245
- const updateParameterValue = (0, import_react24.useCallback)((nodeId, parameterId, value) => {
9394
+ const updateParameterValue = (0, import_react25.useCallback)((nodeId, parameterId, value) => {
9246
9395
  setConfigs((prev) => {
9247
9396
  const newMap = new Map(prev);
9248
9397
  const existing = newMap.get(nodeId);
@@ -9259,7 +9408,7 @@ function useDeviceConfigs(initialConfigs) {
9259
9408
  return newMap;
9260
9409
  });
9261
9410
  }, []);
9262
- const applyConfig = (0, import_react24.useCallback)(
9411
+ const applyConfig = (0, import_react25.useCallback)(
9263
9412
  async (nodeId) => {
9264
9413
  const config = configs.get(nodeId);
9265
9414
  if (!config || !config.actions.onApply) {
@@ -9292,7 +9441,7 @@ function useDeviceConfigs(initialConfigs) {
9292
9441
  },
9293
9442
  [configs, updateConfigState]
9294
9443
  );
9295
- const saveConfig = (0, import_react24.useCallback)(
9444
+ const saveConfig = (0, import_react25.useCallback)(
9296
9445
  async (nodeId) => {
9297
9446
  const config = configs.get(nodeId);
9298
9447
  if (!config || !config.actions.onSave) {
@@ -9326,7 +9475,7 @@ function useDeviceConfigs(initialConfigs) {
9326
9475
  },
9327
9476
  [configs, updateConfigState]
9328
9477
  );
9329
- const resetConfig = (0, import_react24.useCallback)(
9478
+ const resetConfig = (0, import_react25.useCallback)(
9330
9479
  async (nodeId) => {
9331
9480
  const config = configs.get(nodeId);
9332
9481
  if (!config) {
@@ -9356,7 +9505,7 @@ function useDeviceConfigs(initialConfigs) {
9356
9505
  },
9357
9506
  [configs, updateConfig, updateConfigState]
9358
9507
  );
9359
- const cancelConfig = (0, import_react24.useCallback)(
9508
+ const cancelConfig = (0, import_react25.useCallback)(
9360
9509
  (nodeId) => {
9361
9510
  const config = configs.get(nodeId);
9362
9511
  if (config?.actions.onCancel) {
@@ -9365,7 +9514,7 @@ function useDeviceConfigs(initialConfigs) {
9365
9514
  },
9366
9515
  [configs]
9367
9516
  );
9368
- const validateConfig = (0, import_react24.useCallback)(
9517
+ const validateConfig = (0, import_react25.useCallback)(
9369
9518
  (nodeId) => {
9370
9519
  const config = configs.get(nodeId);
9371
9520
  if (!config) {
@@ -9407,21 +9556,21 @@ function useDeviceConfigs(initialConfigs) {
9407
9556
  },
9408
9557
  [configs, updateConfigState]
9409
9558
  );
9410
- const setConfig = (0, import_react24.useCallback)((config) => {
9559
+ const setConfig = (0, import_react25.useCallback)((config) => {
9411
9560
  setConfigs((prev) => {
9412
9561
  const newMap = new Map(prev);
9413
9562
  newMap.set(config.nodeId, config);
9414
9563
  return newMap;
9415
9564
  });
9416
9565
  }, []);
9417
- const removeConfig = (0, import_react24.useCallback)((nodeId) => {
9566
+ const removeConfig = (0, import_react25.useCallback)((nodeId) => {
9418
9567
  setConfigs((prev) => {
9419
9568
  const newMap = new Map(prev);
9420
9569
  newMap.delete(nodeId);
9421
9570
  return newMap;
9422
9571
  });
9423
9572
  }, []);
9424
- const clearConfigs = (0, import_react24.useCallback)(() => {
9573
+ const clearConfigs = (0, import_react25.useCallback)(() => {
9425
9574
  setConfigs(/* @__PURE__ */ new Map());
9426
9575
  }, []);
9427
9576
  return {
@@ -9443,8 +9592,8 @@ function useDeviceConfigs(initialConfigs) {
9443
9592
  }
9444
9593
 
9445
9594
  // src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
9446
- var import_react25 = __toESM(require("react"), 1);
9447
- var import_jsx_runtime23 = require("react/jsx-runtime");
9595
+ var import_react26 = __toESM(require("react"), 1);
9596
+ var import_jsx_runtime24 = require("react/jsx-runtime");
9448
9597
  function DeviceConfigPanelImpl({
9449
9598
  binding,
9450
9599
  onClose,
@@ -9463,7 +9612,7 @@ function DeviceConfigPanelImpl({
9463
9612
  showBuiltInToast = true,
9464
9613
  embedded = false
9465
9614
  }) {
9466
- const [localValues, setLocalValues] = (0, import_react25.useState)(() => {
9615
+ const [localValues, setLocalValues] = (0, import_react26.useState)(() => {
9467
9616
  if (binding) {
9468
9617
  const values = {};
9469
9618
  binding.parameters.forEach((param) => {
@@ -9473,7 +9622,7 @@ function DeviceConfigPanelImpl({
9473
9622
  }
9474
9623
  return {};
9475
9624
  });
9476
- const [collapsedSections, setCollapsedSections] = (0, import_react25.useState)(() => {
9625
+ const [collapsedSections, setCollapsedSections] = (0, import_react26.useState)(() => {
9477
9626
  const collapsed = /* @__PURE__ */ new Set();
9478
9627
  if (binding?.sections) {
9479
9628
  binding.sections.forEach((section) => {
@@ -9484,9 +9633,9 @@ function DeviceConfigPanelImpl({
9484
9633
  }
9485
9634
  return collapsed;
9486
9635
  });
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);
9636
+ const [showToast, setShowToast] = (0, import_react26.useState)(true);
9637
+ const [bindingId, setBindingId] = (0, import_react26.useState)(binding?.nodeId || null);
9638
+ const lastResultTimestampRef = (0, import_react26.useRef)(0);
9490
9639
  if (binding && binding.nodeId !== bindingId) {
9491
9640
  const values = {};
9492
9641
  binding.parameters.forEach((param) => {
@@ -9502,7 +9651,7 @@ function DeviceConfigPanelImpl({
9502
9651
  setCollapsedSections(collapsed);
9503
9652
  setBindingId(binding.nodeId);
9504
9653
  }
9505
- (0, import_react25.useEffect)(() => {
9654
+ (0, import_react26.useEffect)(() => {
9506
9655
  const currentTimestamp = binding?.state.lastSaved || 0;
9507
9656
  if (binding?.state.lastSaveResult && currentTimestamp !== lastResultTimestampRef.current) {
9508
9657
  lastResultTimestampRef.current = currentTimestamp;
@@ -9519,7 +9668,7 @@ function DeviceConfigPanelImpl({
9519
9668
  };
9520
9669
  }
9521
9670
  }, [binding?.state.lastSaveResult, binding?.state.lastSaved, toastDuration]);
9522
- const parametersBySection = (0, import_react25.useMemo)(() => {
9671
+ const parametersBySection = (0, import_react26.useMemo)(() => {
9523
9672
  if (!binding) return { _unsectioned: [] };
9524
9673
  const groups = { _unsectioned: [] };
9525
9674
  binding.parameters.forEach((param) => {
@@ -9534,7 +9683,7 @@ function DeviceConfigPanelImpl({
9534
9683
  });
9535
9684
  return groups;
9536
9685
  }, [binding]);
9537
- const sortedSections = (0, import_react25.useMemo)(() => {
9686
+ const sortedSections = (0, import_react26.useMemo)(() => {
9538
9687
  if (!binding?.sections) return [];
9539
9688
  return [...binding.sections].sort((a, b) => (a.order || 0) - (b.order || 0));
9540
9689
  }, [binding]);
@@ -9610,14 +9759,14 @@ function DeviceConfigPanelImpl({
9610
9759
  const value = localValues[param.id];
9611
9760
  const error = binding.state.errors?.[param.id];
9612
9761
  const isDisabled = param.readOnly || param.enabled === false;
9613
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9762
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9614
9763
  "div",
9615
9764
  {
9616
9765
  style: {
9617
9766
  marginBottom: spacing.marginBottom
9618
9767
  },
9619
9768
  children: [
9620
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9769
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9621
9770
  "label",
9622
9771
  {
9623
9772
  style: {
@@ -9632,13 +9781,13 @@ function DeviceConfigPanelImpl({
9632
9781
  },
9633
9782
  children: [
9634
9783
  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: [
9784
+ param.required && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { color: errorColor }, children: " *" }),
9785
+ param.unit && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { style: { color: mutedTextColor, fontWeight: "normal" }, children: [
9637
9786
  " (",
9638
9787
  param.unit,
9639
9788
  ")"
9640
9789
  ] }),
9641
- param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9790
+ param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9642
9791
  "span",
9643
9792
  {
9644
9793
  "aria-label": "Forced",
@@ -9665,7 +9814,7 @@ function DeviceConfigPanelImpl({
9665
9814
  ]
9666
9815
  }
9667
9816
  ),
9668
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9817
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9669
9818
  "div",
9670
9819
  {
9671
9820
  style: {
@@ -9683,7 +9832,7 @@ function DeviceConfigPanelImpl({
9683
9832
  ]
9684
9833
  }
9685
9834
  ),
9686
- param.description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9835
+ param.description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9687
9836
  "div",
9688
9837
  {
9689
9838
  style: {
@@ -9695,7 +9844,7 @@ function DeviceConfigPanelImpl({
9695
9844
  children: param.description
9696
9845
  }
9697
9846
  ),
9698
- param.type === "number" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9847
+ param.type === "number" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9699
9848
  "input",
9700
9849
  {
9701
9850
  type: "number",
@@ -9719,7 +9868,7 @@ function DeviceConfigPanelImpl({
9719
9868
  }
9720
9869
  }
9721
9870
  ),
9722
- param.type === "string" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9871
+ param.type === "string" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9723
9872
  "input",
9724
9873
  {
9725
9874
  type: "text",
@@ -9740,7 +9889,7 @@ function DeviceConfigPanelImpl({
9740
9889
  }
9741
9890
  }
9742
9891
  ),
9743
- param.type === "boolean" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9892
+ param.type === "boolean" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9744
9893
  "label",
9745
9894
  {
9746
9895
  style: {
@@ -9750,7 +9899,7 @@ function DeviceConfigPanelImpl({
9750
9899
  cursor: isDisabled ? "not-allowed" : "pointer"
9751
9900
  },
9752
9901
  children: [
9753
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9902
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9754
9903
  "input",
9755
9904
  {
9756
9905
  type: "checkbox",
@@ -9764,11 +9913,11 @@ function DeviceConfigPanelImpl({
9764
9913
  }
9765
9914
  }
9766
9915
  ),
9767
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
9916
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
9768
9917
  ]
9769
9918
  }
9770
9919
  ),
9771
- param.type === "select" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9920
+ param.type === "select" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9772
9921
  "select",
9773
9922
  {
9774
9923
  value: value ?? "",
@@ -9786,10 +9935,10 @@ function DeviceConfigPanelImpl({
9786
9935
  borderRadius: "2px",
9787
9936
  outline: "none"
9788
9937
  },
9789
- children: param.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: option.value, children: option.label }, option.value))
9938
+ children: param.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: option.value, children: option.label }, option.value))
9790
9939
  }
9791
9940
  ),
9792
- error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9941
+ error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9793
9942
  "div",
9794
9943
  {
9795
9944
  style: {
@@ -9809,7 +9958,7 @@ function DeviceConfigPanelImpl({
9809
9958
  const renderSection = (section) => {
9810
9959
  const params = parametersBySection[section.id] || [];
9811
9960
  const isCollapsed = collapsedSections.has(section.id);
9812
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9961
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9813
9962
  "div",
9814
9963
  {
9815
9964
  style: {
@@ -9819,7 +9968,7 @@ function DeviceConfigPanelImpl({
9819
9968
  backgroundColor: surfaceColor
9820
9969
  },
9821
9970
  children: [
9822
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9971
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9823
9972
  "div",
9824
9973
  {
9825
9974
  onClick: () => section.collapsible && toggleSection(section.id),
@@ -9832,8 +9981,8 @@ function DeviceConfigPanelImpl({
9832
9981
  alignItems: "center"
9833
9982
  },
9834
9983
  children: [
9835
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
9836
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9984
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
9985
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9837
9986
  "div",
9838
9987
  {
9839
9988
  style: {
@@ -9845,12 +9994,12 @@ function DeviceConfigPanelImpl({
9845
9994
  letterSpacing: "0.5px"
9846
9995
  },
9847
9996
  children: [
9848
- section.icon && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { marginRight: "8px" }, children: section.icon }),
9997
+ section.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { marginRight: "8px" }, children: section.icon }),
9849
9998
  section.title
9850
9999
  ]
9851
10000
  }
9852
10001
  ),
9853
- section.description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10002
+ section.description && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9854
10003
  "div",
9855
10004
  {
9856
10005
  style: {
@@ -9863,11 +10012,11 @@ function DeviceConfigPanelImpl({
9863
10012
  }
9864
10013
  )
9865
10014
  ] }),
9866
- section.collapsible && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
10015
+ section.collapsible && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
9867
10016
  ]
9868
10017
  }
9869
10018
  ),
9870
- !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
10019
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
9871
10020
  ]
9872
10021
  },
9873
10022
  section.id
@@ -9926,9 +10075,9 @@ function DeviceConfigPanelImpl({
9926
10075
  const showSave = binding.display?.showSave !== false && binding.actions.onSave;
9927
10076
  const showReset = binding.display?.showReset !== false && binding.actions.onReset;
9928
10077
  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)(
10078
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
10079
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: panelStyle, className: binding.display?.className, children: [
10080
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9932
10081
  "div",
9933
10082
  {
9934
10083
  style: {
@@ -9940,8 +10089,8 @@ function DeviceConfigPanelImpl({
9940
10089
  borderBottom: `2px solid ${borderColor}`
9941
10090
  },
9942
10091
  children: [
9943
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
9944
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10092
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
10093
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9945
10094
  "h3",
9946
10095
  {
9947
10096
  style: {
@@ -9961,7 +10110,7 @@ function DeviceConfigPanelImpl({
9961
10110
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
9962
10111
  }
9963
10112
  ),
9964
- binding.display?.subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10113
+ binding.display?.subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9965
10114
  "div",
9966
10115
  {
9967
10116
  style: {
@@ -9974,8 +10123,8 @@ function DeviceConfigPanelImpl({
9974
10123
  }
9975
10124
  )
9976
10125
  ] }),
9977
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
9978
- showControlsButton && onOpenControls && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10126
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
10127
+ showControlsButton && onOpenControls && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9979
10128
  "button",
9980
10129
  {
9981
10130
  onClick: onOpenControls,
@@ -9998,7 +10147,7 @@ function DeviceConfigPanelImpl({
9998
10147
  children: "CTRL"
9999
10148
  }
10000
10149
  ),
10001
- onUndock && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10150
+ onUndock && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10002
10151
  "button",
10003
10152
  {
10004
10153
  onClick: onUndock,
@@ -10019,7 +10168,7 @@ function DeviceConfigPanelImpl({
10019
10168
  children: undockIcon
10020
10169
  }
10021
10170
  ),
10022
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10171
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10023
10172
  "button",
10024
10173
  {
10025
10174
  onClick: onClose,
@@ -10042,7 +10191,7 @@ function DeviceConfigPanelImpl({
10042
10191
  ]
10043
10192
  }
10044
10193
  ),
10045
- binding.state.isDirty && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10194
+ binding.state.isDirty && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10046
10195
  "div",
10047
10196
  {
10048
10197
  style: {
@@ -10057,11 +10206,11 @@ function DeviceConfigPanelImpl({
10057
10206
  children: "Unsaved changes"
10058
10207
  }
10059
10208
  ),
10060
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
10209
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
10061
10210
  /* Render unsectioned parameters */
10062
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
10211
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
10063
10212
  ) }),
10064
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
10213
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
10065
10214
  "div",
10066
10215
  {
10067
10216
  style: {
@@ -10072,7 +10221,7 @@ function DeviceConfigPanelImpl({
10072
10221
  flexWrap: "wrap"
10073
10222
  },
10074
10223
  children: [
10075
- showApply && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10224
+ showApply && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10076
10225
  "button",
10077
10226
  {
10078
10227
  onClick: handleApply,
@@ -10095,7 +10244,7 @@ function DeviceConfigPanelImpl({
10095
10244
  children: binding.state.isSaving ? "Applying..." : "Apply"
10096
10245
  }
10097
10246
  ),
10098
- showSave && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10247
+ showSave && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10099
10248
  "button",
10100
10249
  {
10101
10250
  onClick: handleSave,
@@ -10118,7 +10267,7 @@ function DeviceConfigPanelImpl({
10118
10267
  children: binding.state.isSaving ? "Saving..." : "Save"
10119
10268
  }
10120
10269
  ),
10121
- showReset && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10270
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10122
10271
  "button",
10123
10272
  {
10124
10273
  onClick: handleReset,
@@ -10141,7 +10290,7 @@ function DeviceConfigPanelImpl({
10141
10290
  children: "Reset"
10142
10291
  }
10143
10292
  ),
10144
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10293
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10145
10294
  "button",
10146
10295
  {
10147
10296
  onClick: handleCancel,
@@ -10168,7 +10317,7 @@ function DeviceConfigPanelImpl({
10168
10317
  }
10169
10318
  )
10170
10319
  ] }),
10171
- binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
10320
+ binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10172
10321
  "div",
10173
10322
  {
10174
10323
  style: {
@@ -10190,10 +10339,10 @@ function DeviceConfigPanelImpl({
10190
10339
  )
10191
10340
  ] });
10192
10341
  }
10193
- var DeviceConfigPanel = import_react25.default.memo(DeviceConfigPanelImpl);
10342
+ var DeviceConfigPanel = import_react26.default.memo(DeviceConfigPanelImpl);
10194
10343
 
10195
10344
  // src/diagram/hooks/useSimulation.ts
10196
- var import_react26 = require("react");
10345
+ var import_react27 = require("react");
10197
10346
  function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10198
10347
  const {
10199
10348
  interval = 2e3,
@@ -10204,7 +10353,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10204
10353
  historyLength = 10,
10205
10354
  generateValue
10206
10355
  } = options;
10207
- (0, import_react26.useEffect)(() => {
10356
+ (0, import_react27.useEffect)(() => {
10208
10357
  if (!enabled) return;
10209
10358
  const intervalId = setInterval(() => {
10210
10359
  const updates = [];
@@ -10274,6 +10423,8 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10274
10423
  FooterPanel,
10275
10424
  FullscreenContainer,
10276
10425
  FullscreenWorkspace,
10426
+ ISA_UNKNOWN,
10427
+ ISA_UNKNOWN_DARK,
10277
10428
  LeftPanel,
10278
10429
  LeftToggleButton,
10279
10430
  LegacyValueEntry,
@@ -10296,8 +10447,9 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10296
10447
  ThemeProvider,
10297
10448
  ThemeToggle,
10298
10449
  TrendLine,
10299
- UNKNOWN_MARK_COLOR,
10300
- UNKNOWN_MARK_COLOR_DARK,
10450
+ UNKNOWN_GLYPH_RING_DASH,
10451
+ UNKNOWN_STATUS_GLYPH_COLOR_VAR,
10452
+ UnknownStatusGlyph,
10301
10453
  ValueEntry,
10302
10454
  ZoomButton,
10303
10455
  ZoomControls,
@@ -10315,6 +10467,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
10315
10467
  importDiagram,
10316
10468
  mockSymbolLibrary,
10317
10469
  nodeHasPort,
10470
+ normalizeDeviceStatus,
10318
10471
  overlayStyles,
10319
10472
  readAppearanceValue,
10320
10473
  registerSymbol,