@procaaso/alphinity-ui-components 1.11.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -267,6 +267,16 @@ var ValueEntry = ({
267
267
  import { useState as useState3, useCallback as useCallback2 } from "react";
268
268
 
269
269
  // src/theme/statusColors.ts
270
+ var ISA_UNKNOWN = {
271
+ fg: "#4f4f8a",
272
+ bg: "#ebebf5",
273
+ border: "#8f8fc2"
274
+ };
275
+ var ISA_UNKNOWN_DARK = {
276
+ fg: "#b9bbdb",
277
+ bg: "#23263a",
278
+ border: "#6f74a3"
279
+ };
270
280
  var DEFAULT_STATUS_COLORS = {
271
281
  normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
272
282
  warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
@@ -274,7 +284,8 @@ var DEFAULT_STATUS_COLORS = {
274
284
  fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
275
285
  off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
276
286
  starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
277
- stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
287
+ stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
288
+ unknown: { fill: ISA_UNKNOWN.bg, stroke: ISA_UNKNOWN.border, bg: ISA_UNKNOWN.bg, text: ISA_UNKNOWN.fg, border: ISA_UNKNOWN.border }
278
289
  };
279
290
  var FORCED_MARK_COLOR = {
280
291
  fill: "#ede9fe",
@@ -283,27 +294,16 @@ var FORCED_MARK_COLOR = {
283
294
  text: "#5b21b6",
284
295
  border: "#7c3aed"
285
296
  };
286
- var UNKNOWN_MARK_COLOR = {
287
- fill: "#ebebf5",
288
- stroke: "#8f8fc2",
289
- bg: "#ebebf5",
290
- text: "#4f4f8a",
291
- border: "#8f8fc2"
292
- };
293
- var UNKNOWN_MARK_COLOR_DARK = {
294
- fill: "#23263a",
295
- stroke: "#6f74a3",
296
- bg: "#23263a",
297
- text: "#b9bbdb",
298
- border: "#6f74a3"
299
- };
300
297
  var STATUS_ALIASES = {
301
298
  running: "normal",
302
299
  stopped: "off"
303
300
  };
304
- function resolveStatusColor(status, customMap) {
301
+ function normalizeDeviceStatus(status) {
305
302
  const raw = (status || "off").toLowerCase();
306
- const key = STATUS_ALIASES[raw] ?? raw;
303
+ return STATUS_ALIASES[raw] ?? raw;
304
+ }
305
+ function resolveStatusColor(status, customMap) {
306
+ const key = normalizeDeviceStatus(status);
307
307
  const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
308
308
  const overrides = customMap?.[key];
309
309
  if (!overrides) return defaults;
@@ -743,7 +743,79 @@ var ControlPanel = ({
743
743
  };
744
744
 
745
745
  // src/components/StatusIndicator/StatusIndicator.tsx
746
+ import React5 from "react";
747
+
748
+ // src/theme/unknownStatusGlyph.tsx
746
749
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
750
+ var UNKNOWN_STATUS_GLYPH_COLOR_VAR = "--ui-status-indicator-unknown-glyph-color";
751
+ var UNKNOWN_GLYPH_STROKE_WEIGHTS = {
752
+ small: { ring: 4.5, ringDash: "7 6", mark: 5, dot: 2.9 },
753
+ medium: { ring: 4, ringDash: "6.5 5.5", mark: 4.5, dot: 2.7 },
754
+ large: { ring: 3.5, ringDash: "6.5 5.5", mark: 4, dot: 2.5 }
755
+ };
756
+ var UNKNOWN_GLYPH_RING_DASH = UNKNOWN_GLYPH_STROKE_WEIGHTS.medium.ringDash;
757
+ var UNKNOWN_GLYPH_FILL_STYLE = {
758
+ position: "absolute",
759
+ inset: 0,
760
+ width: "100%",
761
+ height: "100%"
762
+ };
763
+ function unknownGlyphHostStyle(isUnknown, style) {
764
+ return isUnknown ? { position: "relative", ...style } : style;
765
+ }
766
+ function UnknownStatusGlyph({
767
+ size = "medium",
768
+ counterRotate = false,
769
+ style,
770
+ ...rest
771
+ }) {
772
+ const weights = UNKNOWN_GLYPH_STROKE_WEIGHTS[size];
773
+ return /* @__PURE__ */ jsxs5(
774
+ "svg",
775
+ {
776
+ viewBox: "0 0 48 48",
777
+ "aria-hidden": "true",
778
+ focusable: "false",
779
+ style: {
780
+ display: "block",
781
+ color: `var(${UNKNOWN_STATUS_GLYPH_COLOR_VAR}, currentColor)`,
782
+ transform: counterRotate ? "rotate(-45deg)" : void 0,
783
+ ...style
784
+ },
785
+ ...rest,
786
+ children: [
787
+ /* @__PURE__ */ jsx6(
788
+ "circle",
789
+ {
790
+ cx: 24,
791
+ cy: 24,
792
+ r: 20,
793
+ fill: "none",
794
+ stroke: "currentColor",
795
+ strokeDasharray: weights.ringDash,
796
+ strokeLinecap: "round",
797
+ strokeWidth: weights.ring
798
+ }
799
+ ),
800
+ /* @__PURE__ */ jsx6(
801
+ "path",
802
+ {
803
+ d: "M18.4 18.6a5.8 5.8 0 1 1 6.4 8.1v3.1",
804
+ fill: "none",
805
+ stroke: "currentColor",
806
+ strokeLinecap: "round",
807
+ strokeLinejoin: "round",
808
+ strokeWidth: weights.mark
809
+ }
810
+ ),
811
+ /* @__PURE__ */ jsx6("circle", { cx: 24.6, cy: 35.4, r: weights.dot, fill: "currentColor" })
812
+ ]
813
+ }
814
+ );
815
+ }
816
+
817
+ // src/components/StatusIndicator/StatusIndicator.tsx
818
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
747
819
  var getStatusDescription = (status) => {
748
820
  switch (status) {
749
821
  case "alarm":
@@ -758,10 +830,23 @@ var getStatusDescription = (status) => {
758
830
  return "Operating normally";
759
831
  case "off":
760
832
  return "Equipment is off";
833
+ case "unknown":
834
+ return "Device state cannot be confirmed. Check the link or the wiring.";
761
835
  default:
762
836
  return "";
763
837
  }
764
838
  };
839
+ var visuallyHiddenStyle = {
840
+ position: "absolute",
841
+ width: "1px",
842
+ height: "1px",
843
+ padding: 0,
844
+ margin: "-1px",
845
+ overflow: "hidden",
846
+ clip: "rect(0, 0, 0, 0)",
847
+ whiteSpace: "nowrap",
848
+ border: 0
849
+ };
765
850
  var StatusIndicator = ({
766
851
  status,
767
852
  size = "medium",
@@ -774,17 +859,25 @@ var StatusIndicator = ({
774
859
  forced = false,
775
860
  realValue,
776
861
  className = "",
862
+ style,
863
+ "aria-describedby": consumerDescribedBy,
864
+ children,
777
865
  ...props
778
866
  }) => {
867
+ const generatedDescriptionId = `${React5.useId()}-status-description`;
779
868
  if (!visible) {
780
869
  return null;
781
870
  }
871
+ const describedBy = consumerDescribedBy ? `${consumerDescribedBy} ${generatedDescriptionId}` : generatedDescriptionId;
872
+ const description = getStatusDescription(status);
782
873
  const baseClass = "ui-status-indicator";
783
874
  const statusClass = status ? `ui-status-indicator--${status}` : "";
784
875
  const sizeClass = size ? `ui-status-indicator--${size}` : "";
785
876
  const shapeClass = shape ? `ui-status-indicator--${shape}` : "";
786
877
  const animationClass = animation ? `ui-status-indicator--${animation}` : "";
787
878
  const ledClass = led ? "ui-status-indicator--led" : "";
879
+ const isUnknown = status === "unknown";
880
+ const indicatorStyle = unknownGlyphHostStyle(isUnknown, style);
788
881
  const getContainerLayout = () => {
789
882
  switch (labelPosition) {
790
883
  case "left":
@@ -801,19 +894,20 @@ var StatusIndicator = ({
801
894
  };
802
895
  const forcedClass = forced ? "ui-status-indicator--forced" : "";
803
896
  const hasRealValue = forced && realValue !== void 0;
804
- return /* @__PURE__ */ jsxs5("span", { className: getContainerLayout(), children: [
805
- label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-label", children: label }),
806
- hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsxs5("span", { className: "ui-status-indicator-real-value", children: [
897
+ return /* @__PURE__ */ jsxs6("span", { className: getContainerLayout(), children: [
898
+ label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsx7("span", { className: "ui-status-indicator-label", children: label }),
899
+ hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsxs6("span", { className: "ui-status-indicator-real-value", children: [
807
900
  "REAL ",
808
901
  realValue
809
902
  ] }),
810
- /* @__PURE__ */ jsxs5("span", { style: { position: "relative", display: "inline-flex" }, children: [
811
- /* @__PURE__ */ jsx6(
903
+ /* @__PURE__ */ jsxs6("span", { style: { position: "relative", display: "inline-flex" }, children: [
904
+ /* @__PURE__ */ jsxs6(
812
905
  "span",
813
906
  {
814
907
  role: "status",
815
908
  "aria-label": label || `Status: ${status}`,
816
- "aria-description": getStatusDescription(status),
909
+ "aria-description": description,
910
+ "aria-describedby": describedBy,
817
911
  "data-status": status,
818
912
  "data-forced": forced,
819
913
  className: `
@@ -826,13 +920,26 @@ var StatusIndicator = ({
826
920
  ${forcedClass}
827
921
  ${className}
828
922
  `.replace(/\s+/g, " ").trim(),
829
- ...props
923
+ style: indicatorStyle,
924
+ ...props,
925
+ children: [
926
+ isUnknown && /* @__PURE__ */ jsx7(
927
+ UnknownStatusGlyph,
928
+ {
929
+ size,
930
+ counterRotate: shape === "diamond",
931
+ style: UNKNOWN_GLYPH_FILL_STYLE
932
+ }
933
+ ),
934
+ children,
935
+ /* @__PURE__ */ jsx7("span", { id: generatedDescriptionId, style: visuallyHiddenStyle, children: description })
936
+ ]
830
937
  }
831
938
  ),
832
- forced && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
939
+ forced && /* @__PURE__ */ jsx7("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
833
940
  ] }),
834
- label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-label", children: label }),
835
- hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsxs5("span", { className: "ui-status-indicator-real-value", children: [
941
+ label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsx7("span", { className: "ui-status-indicator-label", children: label }),
942
+ hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsxs6("span", { className: "ui-status-indicator-real-value", children: [
836
943
  "REAL ",
837
944
  realValue
838
945
  ] })
@@ -840,7 +947,7 @@ var StatusIndicator = ({
840
947
  };
841
948
 
842
949
  // src/components/NodeControlsPanel/NodeControlsPanel.tsx
843
- import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
950
+ import { Fragment, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
844
951
  var NodeControlsPanel = ({
845
952
  config,
846
953
  onClose,
@@ -913,8 +1020,8 @@ var NodeControlsPanel = ({
913
1020
  overflowY: "auto",
914
1021
  flex: 1
915
1022
  };
916
- return /* @__PURE__ */ jsxs6(Fragment, { children: [
917
- /* @__PURE__ */ jsx7(
1023
+ return /* @__PURE__ */ jsxs7(Fragment, { children: [
1024
+ /* @__PURE__ */ jsx8(
918
1025
  "div",
919
1026
  {
920
1027
  style: {
@@ -927,16 +1034,16 @@ var NodeControlsPanel = ({
927
1034
  onClick: onClose
928
1035
  }
929
1036
  ),
930
- /* @__PURE__ */ jsxs6(
1037
+ /* @__PURE__ */ jsxs7(
931
1038
  "div",
932
1039
  {
933
1040
  className: `node-controls-panel ${touchClass} ${className}`.trim(),
934
1041
  style: containerStyle,
935
1042
  ...props,
936
1043
  children: [
937
- /* @__PURE__ */ jsxs6("div", { style: headerStyle, children: [
938
- /* @__PURE__ */ jsx7("h2", { style: titleStyle, children: config.title }),
939
- /* @__PURE__ */ jsx7(
1044
+ /* @__PURE__ */ jsxs7("div", { style: headerStyle, children: [
1045
+ /* @__PURE__ */ jsx8("h2", { style: titleStyle, children: config.title }),
1046
+ /* @__PURE__ */ jsx8(
940
1047
  "button",
941
1048
  {
942
1049
  style: closeButtonStyle,
@@ -954,7 +1061,7 @@ var NodeControlsPanel = ({
954
1061
  }
955
1062
  )
956
1063
  ] }),
957
- /* @__PURE__ */ jsx7("div", { style: contentStyle, children: /* @__PURE__ */ jsx7(
1064
+ /* @__PURE__ */ jsx8("div", { style: contentStyle, children: /* @__PURE__ */ jsx8(
958
1065
  ControlPanel,
959
1066
  {
960
1067
  title: config.nodeId,
@@ -983,7 +1090,7 @@ var NodeControlsPanel = ({
983
1090
  ]
984
1091
  }
985
1092
  ),
986
- /* @__PURE__ */ jsx7("style", { children: `
1093
+ /* @__PURE__ */ jsx8("style", { children: `
987
1094
  @keyframes slideUp {
988
1095
  from {
989
1096
  transform: translateY(100%);
@@ -1029,8 +1136,8 @@ var NodeControlsPanel = ({
1029
1136
  };
1030
1137
 
1031
1138
  // src/components/DeviceControlPanel/DeviceControlPanel.tsx
1032
- import React5, { useState as useState5, useEffect as useEffect2 } from "react";
1033
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1139
+ import React6, { useState as useState5, useEffect as useEffect2 } from "react";
1140
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1034
1141
  function DeviceControlPanelImpl({
1035
1142
  binding,
1036
1143
  onClose,
@@ -1110,6 +1217,7 @@ function DeviceControlPanelImpl({
1110
1217
  const selectedColor = "#b4d0fe";
1111
1218
  const statusEntry = resolveStatusColor(binding.state.status, binding.theme?.statusColors);
1112
1219
  const statusColor = statusEntry.bg;
1220
+ const isUnknownStatus = normalizeDeviceStatus(binding.state.status) === "unknown";
1113
1221
  const handleModeChange = (mode) => {
1114
1222
  onModeChange?.(mode);
1115
1223
  };
@@ -1164,9 +1272,9 @@ function DeviceControlPanelImpl({
1164
1272
  ...binding.display?.style
1165
1273
  };
1166
1274
  const titleText = binding.display?.title || binding.deviceName || binding.tag || binding.nodeId;
1167
- return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1168
- /* @__PURE__ */ jsxs7("div", { style: panelStyle, className: binding.display?.className, children: [
1169
- /* @__PURE__ */ jsxs7(
1275
+ return /* @__PURE__ */ jsxs8(Fragment2, { children: [
1276
+ /* @__PURE__ */ jsxs8("div", { style: panelStyle, className: binding.display?.className, children: [
1277
+ /* @__PURE__ */ jsxs8(
1170
1278
  "div",
1171
1279
  {
1172
1280
  style: {
@@ -1178,8 +1286,8 @@ function DeviceControlPanelImpl({
1178
1286
  borderBottom: `2px solid ${borderColor}`
1179
1287
  },
1180
1288
  children: [
1181
- /* @__PURE__ */ jsxs7("div", { children: [
1182
- /* @__PURE__ */ jsx8(
1289
+ /* @__PURE__ */ jsxs8("div", { children: [
1290
+ /* @__PURE__ */ jsx9(
1183
1291
  "h3",
1184
1292
  {
1185
1293
  style: {
@@ -1199,7 +1307,7 @@ function DeviceControlPanelImpl({
1199
1307
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
1200
1308
  }
1201
1309
  ),
1202
- binding.deviceType && /* @__PURE__ */ jsx8(
1310
+ binding.deviceType && /* @__PURE__ */ jsx9(
1203
1311
  "div",
1204
1312
  {
1205
1313
  style: {
@@ -1212,8 +1320,8 @@ function DeviceControlPanelImpl({
1212
1320
  }
1213
1321
  )
1214
1322
  ] }),
1215
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "8px" }, children: [
1216
- showConfigButton && onOpenConfig && /* @__PURE__ */ jsx8(
1323
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: "8px" }, children: [
1324
+ showConfigButton && onOpenConfig && /* @__PURE__ */ jsx9(
1217
1325
  "button",
1218
1326
  {
1219
1327
  onClick: onOpenConfig,
@@ -1234,7 +1342,7 @@ function DeviceControlPanelImpl({
1234
1342
  children: "\u2699"
1235
1343
  }
1236
1344
  ),
1237
- onUndock && /* @__PURE__ */ jsx8(
1345
+ onUndock && /* @__PURE__ */ jsx9(
1238
1346
  "button",
1239
1347
  {
1240
1348
  onClick: onUndock,
@@ -1255,7 +1363,7 @@ function DeviceControlPanelImpl({
1255
1363
  children: undockIcon
1256
1364
  }
1257
1365
  ),
1258
- /* @__PURE__ */ jsx8(
1366
+ /* @__PURE__ */ jsx9(
1259
1367
  "button",
1260
1368
  {
1261
1369
  onClick: onClose,
@@ -1278,7 +1386,7 @@ function DeviceControlPanelImpl({
1278
1386
  ]
1279
1387
  }
1280
1388
  ),
1281
- binding.state.status && /* @__PURE__ */ jsxs7(
1389
+ binding.state.status && /* @__PURE__ */ jsxs8(
1282
1390
  "div",
1283
1391
  {
1284
1392
  style: {
@@ -1292,7 +1400,7 @@ function DeviceControlPanelImpl({
1292
1400
  marginBottom: spacing.marginBottom
1293
1401
  },
1294
1402
  children: [
1295
- /* @__PURE__ */ jsx8(
1403
+ /* @__PURE__ */ jsx9(
1296
1404
  "div",
1297
1405
  {
1298
1406
  style: {
@@ -1300,12 +1408,17 @@ function DeviceControlPanelImpl({
1300
1408
  height: "10px",
1301
1409
  borderRadius: "50%",
1302
1410
  backgroundColor: statusColor,
1303
- border: "1px solid #333"
1304
- }
1411
+ border: "1px solid #333",
1412
+ // The shared helper positions this dot only while it shows
1413
+ // the unknown marker. The glyph then fills the dot with an
1414
+ // absolute inset, the same pattern StatusIndicator uses.
1415
+ ...unknownGlyphHostStyle(isUnknownStatus)
1416
+ },
1417
+ children: isUnknownStatus && /* @__PURE__ */ jsx9(UnknownStatusGlyph, { size: "small", style: UNKNOWN_GLYPH_FILL_STYLE })
1305
1418
  }
1306
1419
  ),
1307
- /* @__PURE__ */ jsxs7("div", { style: { flex: 1 }, children: [
1308
- /* @__PURE__ */ jsx8(
1420
+ /* @__PURE__ */ jsxs8("div", { style: { flex: 1 }, children: [
1421
+ /* @__PURE__ */ jsx9(
1309
1422
  "div",
1310
1423
  {
1311
1424
  style: {
@@ -1319,7 +1432,7 @@ function DeviceControlPanelImpl({
1319
1432
  children: binding.state.status
1320
1433
  }
1321
1434
  ),
1322
- binding.state.statusMessage && /* @__PURE__ */ jsx8(
1435
+ binding.state.statusMessage && /* @__PURE__ */ jsx9(
1323
1436
  "div",
1324
1437
  {
1325
1438
  style: {
@@ -1332,28 +1445,36 @@ function DeviceControlPanelImpl({
1332
1445
  }
1333
1446
  )
1334
1447
  ] }),
1335
- binding.state.isRunning !== void 0 && /* @__PURE__ */ jsx8(
1448
+ binding.state.isRunning !== void 0 && /* @__PURE__ */ jsxs8(
1336
1449
  "div",
1337
1450
  {
1338
1451
  style: {
1339
1452
  padding: "4px 10px",
1340
- backgroundColor: binding.state.isRunning ? selectedColor : surfaceColor,
1341
- border: `1px solid ${borderColor}`,
1453
+ // This badge shows the last published isRunning value. It
1454
+ // never re-derives that value here. When status is
1455
+ // unknown, the value may be stale. Muted colors carry that
1456
+ // warning alongside the word, so color is not the only
1457
+ // channel and the wording is not the only channel either.
1458
+ backgroundColor: isUnknownStatus ? statusEntry.bg : binding.state.isRunning ? selectedColor : surfaceColor,
1459
+ border: `1px solid ${isUnknownStatus ? statusEntry.border : borderColor}`,
1342
1460
  borderRadius: "2px",
1343
1461
  fontSize: "10px",
1344
1462
  fontWeight: 600,
1345
1463
  fontFamily: "Arial, sans-serif",
1346
1464
  letterSpacing: "0.5px",
1347
- color: textColor
1465
+ color: isUnknownStatus ? statusEntry.text : textColor
1348
1466
  },
1349
- children: binding.state.isRunning ? "RUNNING" : "STOPPED"
1467
+ children: [
1468
+ binding.state.isRunning ? "RUNNING" : "STOPPED",
1469
+ isUnknownStatus && " (unconfirmed)"
1470
+ ]
1350
1471
  }
1351
1472
  )
1352
1473
  ]
1353
1474
  }
1354
1475
  ),
1355
- binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: "16px" }, children: [
1356
- /* @__PURE__ */ jsx8(
1476
+ binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ jsxs8("div", { style: { marginBottom: "16px" }, children: [
1477
+ /* @__PURE__ */ jsx9(
1357
1478
  "label",
1358
1479
  {
1359
1480
  style: {
@@ -1369,7 +1490,7 @@ function DeviceControlPanelImpl({
1369
1490
  children: "Mode"
1370
1491
  }
1371
1492
  ),
1372
- modeSelectionStyle === "dropdown" ? /* @__PURE__ */ jsx8(
1493
+ modeSelectionStyle === "dropdown" ? /* @__PURE__ */ jsx9(
1373
1494
  "select",
1374
1495
  {
1375
1496
  value: currentMode,
@@ -1390,10 +1511,10 @@ function DeviceControlPanelImpl({
1390
1511
  paddingRight: "12px",
1391
1512
  cursor: "pointer"
1392
1513
  },
1393
- children: binding.modes.map((mode) => /* @__PURE__ */ jsx8("option", { value: mode.value, disabled: mode.enabled === false, children: mode.label }, mode.value))
1514
+ children: binding.modes.map((mode) => /* @__PURE__ */ jsx9("option", { value: mode.value, disabled: mode.enabled === false, children: mode.label }, mode.value))
1394
1515
  }
1395
- ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1396
- /* @__PURE__ */ jsxs7(
1516
+ ) : modeSelectionStyle === "modal" ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
1517
+ /* @__PURE__ */ jsxs8(
1397
1518
  "div",
1398
1519
  {
1399
1520
  onClick: () => {
@@ -1416,12 +1537,12 @@ function DeviceControlPanelImpl({
1416
1537
  alignItems: "center"
1417
1538
  },
1418
1539
  children: [
1419
- /* @__PURE__ */ jsx8("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1420
- /* @__PURE__ */ jsx8("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1540
+ /* @__PURE__ */ jsx9("span", { children: binding.modes.find((m) => m.value === currentMode)?.label || currentMode }),
1541
+ /* @__PURE__ */ jsx9("span", { style: { fontSize: "20px", marginLeft: "8px" }, children: "\u25BC" })
1421
1542
  ]
1422
1543
  }
1423
1544
  ),
1424
- showModeModal && /* @__PURE__ */ jsx8(
1545
+ showModeModal && /* @__PURE__ */ jsx9(
1425
1546
  "div",
1426
1547
  {
1427
1548
  style: {
@@ -1440,7 +1561,7 @@ function DeviceControlPanelImpl({
1440
1561
  setShowModeModal(false);
1441
1562
  setPendingMode(null);
1442
1563
  },
1443
- children: /* @__PURE__ */ jsxs7(
1564
+ children: /* @__PURE__ */ jsxs8(
1444
1565
  "div",
1445
1566
  {
1446
1567
  onClick: (e) => e.stopPropagation(),
@@ -1453,7 +1574,7 @@ function DeviceControlPanelImpl({
1453
1574
  border: `2px solid ${borderColor}`
1454
1575
  },
1455
1576
  children: [
1456
- /* @__PURE__ */ jsx8(
1577
+ /* @__PURE__ */ jsx9(
1457
1578
  "h3",
1458
1579
  {
1459
1580
  style: {
@@ -1466,7 +1587,7 @@ function DeviceControlPanelImpl({
1466
1587
  children: "Select Mode"
1467
1588
  }
1468
1589
  ),
1469
- /* @__PURE__ */ jsx8(
1590
+ /* @__PURE__ */ jsx9(
1470
1591
  "div",
1471
1592
  {
1472
1593
  style: {
@@ -1480,7 +1601,7 @@ function DeviceControlPanelImpl({
1480
1601
  children: binding.display?.title || binding.deviceName || binding.tag || binding.nodeId
1481
1602
  }
1482
1603
  ),
1483
- /* @__PURE__ */ jsx8(
1604
+ /* @__PURE__ */ jsx9(
1484
1605
  "select",
1485
1606
  {
1486
1607
  value: pendingMode || currentMode,
@@ -1502,7 +1623,7 @@ function DeviceControlPanelImpl({
1502
1623
  paddingRight: "12px",
1503
1624
  cursor: "pointer"
1504
1625
  },
1505
- children: binding.modes.map((mode) => /* @__PURE__ */ jsx8(
1626
+ children: binding.modes.map((mode) => /* @__PURE__ */ jsx9(
1506
1627
  "option",
1507
1628
  {
1508
1629
  value: mode.value,
@@ -1517,7 +1638,7 @@ function DeviceControlPanelImpl({
1517
1638
  const selectedMode = binding.modes.find(
1518
1639
  (m) => m.value === (pendingMode || currentMode)
1519
1640
  );
1520
- return selectedMode?.description ? /* @__PURE__ */ jsx8(
1641
+ return selectedMode?.description ? /* @__PURE__ */ jsx9(
1521
1642
  "div",
1522
1643
  {
1523
1644
  style: {
@@ -1535,8 +1656,8 @@ function DeviceControlPanelImpl({
1535
1656
  }
1536
1657
  ) : null;
1537
1658
  })(),
1538
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "12px" }, children: [
1539
- /* @__PURE__ */ jsx8(
1659
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: "12px" }, children: [
1660
+ /* @__PURE__ */ jsx9(
1540
1661
  "button",
1541
1662
  {
1542
1663
  onClick: () => {
@@ -1564,7 +1685,7 @@ function DeviceControlPanelImpl({
1564
1685
  children: "Confirm"
1565
1686
  }
1566
1687
  ),
1567
- /* @__PURE__ */ jsx8(
1688
+ /* @__PURE__ */ jsx9(
1568
1689
  "button",
1569
1690
  {
1570
1691
  onClick: () => {
@@ -1594,7 +1715,7 @@ function DeviceControlPanelImpl({
1594
1715
  )
1595
1716
  }
1596
1717
  )
1597
- ] }) : /* @__PURE__ */ jsx8(
1718
+ ] }) : /* @__PURE__ */ jsx9(
1598
1719
  "div",
1599
1720
  {
1600
1721
  style: {
@@ -1610,7 +1731,7 @@ function DeviceControlPanelImpl({
1610
1731
  children: binding.modes.map((mode) => {
1611
1732
  const isSelected = mode.value === currentMode;
1612
1733
  const isEnabled = mode.enabled !== false;
1613
- return /* @__PURE__ */ jsx8(
1734
+ return /* @__PURE__ */ jsx9(
1614
1735
  "button",
1615
1736
  {
1616
1737
  onClick: () => isEnabled && handleModeChange(mode.value),
@@ -1640,8 +1761,8 @@ function DeviceControlPanelImpl({
1640
1761
  }
1641
1762
  )
1642
1763
  ] }),
1643
- currentParams.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: spacing.marginBottom }, children: [
1644
- /* @__PURE__ */ jsx8(
1764
+ currentParams.length > 0 && /* @__PURE__ */ jsxs8("div", { style: { marginBottom: spacing.marginBottom }, children: [
1765
+ /* @__PURE__ */ jsx9(
1645
1766
  "label",
1646
1767
  {
1647
1768
  style: {
@@ -1657,7 +1778,7 @@ function DeviceControlPanelImpl({
1657
1778
  children: "Parameters"
1658
1779
  }
1659
1780
  ),
1660
- currentParams.map((param) => /* @__PURE__ */ jsxs7(
1781
+ currentParams.map((param) => /* @__PURE__ */ jsxs8(
1661
1782
  "div",
1662
1783
  {
1663
1784
  style: {
@@ -1668,7 +1789,7 @@ function DeviceControlPanelImpl({
1668
1789
  borderRadius: "6px"
1669
1790
  },
1670
1791
  children: [
1671
- /* @__PURE__ */ jsxs7(
1792
+ /* @__PURE__ */ jsxs8(
1672
1793
  "div",
1673
1794
  {
1674
1795
  style: {
@@ -1677,7 +1798,7 @@ function DeviceControlPanelImpl({
1677
1798
  marginBottom: spacing.gap
1678
1799
  },
1679
1800
  children: [
1680
- /* @__PURE__ */ jsxs7(
1801
+ /* @__PURE__ */ jsxs8(
1681
1802
  "span",
1682
1803
  {
1683
1804
  style: {
@@ -1693,7 +1814,7 @@ function DeviceControlPanelImpl({
1693
1814
  },
1694
1815
  children: [
1695
1816
  param.label,
1696
- param.forced?.active && /* @__PURE__ */ jsx8(
1817
+ param.forced?.active && /* @__PURE__ */ jsx9(
1697
1818
  "span",
1698
1819
  {
1699
1820
  "aria-label": "Forced",
@@ -1716,7 +1837,7 @@ function DeviceControlPanelImpl({
1716
1837
  ]
1717
1838
  }
1718
1839
  ),
1719
- /* @__PURE__ */ jsxs7(
1840
+ /* @__PURE__ */ jsxs8(
1720
1841
  "span",
1721
1842
  {
1722
1843
  style: {
@@ -1728,14 +1849,14 @@ function DeviceControlPanelImpl({
1728
1849
  children: [
1729
1850
  localParameterValues[param.id] ?? param.value,
1730
1851
  " ",
1731
- param.unit && /* @__PURE__ */ jsx8("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1852
+ param.unit && /* @__PURE__ */ jsx9("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1732
1853
  ]
1733
1854
  }
1734
1855
  )
1735
1856
  ]
1736
1857
  }
1737
1858
  ),
1738
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs7(
1859
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs8(
1739
1860
  "div",
1740
1861
  {
1741
1862
  style: {
@@ -1756,7 +1877,7 @@ function DeviceControlPanelImpl({
1756
1877
  ]
1757
1878
  }
1758
1879
  ),
1759
- param.type === "boolean" ? /* @__PURE__ */ jsx8(
1880
+ param.type === "boolean" ? /* @__PURE__ */ jsx9(
1760
1881
  "button",
1761
1882
  {
1762
1883
  onClick: () => {
@@ -1781,7 +1902,7 @@ function DeviceControlPanelImpl({
1781
1902
  },
1782
1903
  children: localParameterValues[param.id] ? "ON" : "OFF"
1783
1904
  }
1784
- ) : param.type === "select" ? /* @__PURE__ */ jsx8(
1905
+ ) : param.type === "select" ? /* @__PURE__ */ jsx9(
1785
1906
  "select",
1786
1907
  {
1787
1908
  value: localParameterValues[param.id] || param.value,
@@ -1802,12 +1923,12 @@ function DeviceControlPanelImpl({
1802
1923
  fontFamily: "monospace",
1803
1924
  cursor: "pointer"
1804
1925
  },
1805
- children: param.options?.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
1926
+ children: param.options?.map((opt) => /* @__PURE__ */ jsx9("option", { value: opt.value, children: opt.label }, opt.value))
1806
1927
  }
1807
1928
  ) : onParameterActivate && !param.readOnly ? (
1808
1929
  // Tappable value: defer editing to the consumer's editor (e.g. a
1809
1930
  // numpad dialog). Commit happens via onParameterChange.
1810
- /* @__PURE__ */ jsxs7(
1931
+ /* @__PURE__ */ jsxs8(
1811
1932
  "button",
1812
1933
  {
1813
1934
  type: "button",
@@ -1834,7 +1955,7 @@ function DeviceControlPanelImpl({
1834
1955
  ]
1835
1956
  }
1836
1957
  )
1837
- ) : /* @__PURE__ */ jsx8(
1958
+ ) : /* @__PURE__ */ jsx9(
1838
1959
  "input",
1839
1960
  {
1840
1961
  type: param.type === "number" ? "number" : "text",
@@ -1867,8 +1988,8 @@ function DeviceControlPanelImpl({
1867
1988
  param.id
1868
1989
  ))
1869
1990
  ] }),
1870
- binding.display?.showStartStop !== false && (activeCapabilities?.canStart || activeCapabilities?.canStop) && /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: spacing.gap, marginBottom: spacing.marginBottom }, children: [
1871
- activeCapabilities?.canStart && /* @__PURE__ */ jsx8(
1991
+ binding.display?.showStartStop !== false && (activeCapabilities?.canStart || activeCapabilities?.canStop) && /* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: spacing.gap, marginBottom: spacing.marginBottom }, children: [
1992
+ activeCapabilities?.canStart && /* @__PURE__ */ jsx9(
1872
1993
  "button",
1873
1994
  {
1874
1995
  onClick: onStart,
@@ -1889,7 +2010,7 @@ function DeviceControlPanelImpl({
1889
2010
  children: startPending ? "STARTING\u2026" : "START"
1890
2011
  }
1891
2012
  ),
1892
- activeCapabilities?.canStop && /* @__PURE__ */ jsx8(
2013
+ activeCapabilities?.canStop && /* @__PURE__ */ jsx9(
1893
2014
  "button",
1894
2015
  {
1895
2016
  onClick: onStop,
@@ -1911,9 +2032,9 @@ function DeviceControlPanelImpl({
1911
2032
  }
1912
2033
  )
1913
2034
  ] }),
1914
- activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ jsx8("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => {
2035
+ activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ jsx9("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => {
1915
2036
  const actionDisabled = action.disabled === true;
1916
- return /* @__PURE__ */ jsxs7(
2037
+ return /* @__PURE__ */ jsxs8(
1917
2038
  "button",
1918
2039
  {
1919
2040
  onClick: () => {
@@ -1939,7 +2060,7 @@ function DeviceControlPanelImpl({
1939
2060
  transition: "all 0.15s"
1940
2061
  },
1941
2062
  children: [
1942
- action.icon && /* @__PURE__ */ jsx8("span", { style: { marginRight: "6px" }, children: action.icon }),
2063
+ action.icon && /* @__PURE__ */ jsx9("span", { style: { marginRight: "6px" }, children: action.icon }),
1943
2064
  action.label
1944
2065
  ]
1945
2066
  },
@@ -1947,7 +2068,7 @@ function DeviceControlPanelImpl({
1947
2068
  );
1948
2069
  }) })
1949
2070
  ] }),
1950
- binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ jsx8(
2071
+ binding.state.lastCommandResult && showToast && showBuiltInToast && /* @__PURE__ */ jsx9(
1951
2072
  "div",
1952
2073
  {
1953
2074
  style: {
@@ -1971,7 +2092,7 @@ function DeviceControlPanelImpl({
1971
2092
  children: binding.state.lastCommandResult.message
1972
2093
  }
1973
2094
  ),
1974
- /* @__PURE__ */ jsx8("style", { children: `
2095
+ /* @__PURE__ */ jsx9("style", { children: `
1975
2096
  @keyframes slideInToast {
1976
2097
  from {
1977
2098
  opacity: 0;
@@ -2003,11 +2124,11 @@ function DeviceControlPanelImpl({
2003
2124
  ` })
2004
2125
  ] });
2005
2126
  }
2006
- var DeviceControlPanel = React5.memo(DeviceControlPanelImpl);
2127
+ var DeviceControlPanel = React6.memo(DeviceControlPanelImpl);
2007
2128
 
2008
2129
  // src/components/NumpadDialog/NumpadDialog.tsx
2009
2130
  import { useState as useState6, useEffect as useEffect3, useCallback as useCallback3, useRef as useRef2, useId } from "react";
2010
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2131
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2011
2132
  var NumpadDialog = ({
2012
2133
  isOpen,
2013
2134
  onClose,
@@ -2211,7 +2332,7 @@ var NumpadDialog = ({
2211
2332
  };
2212
2333
  const reason = belowMin ? `Below minimum of ${min} ${unit}` : aboveMax ? `Above maximum of ${max} ${unit}` : "Type or tap to change the value";
2213
2334
  const backspaceInGrid = min >= 0;
2214
- const BackspaceButton = ({ style, label }) => /* @__PURE__ */ jsx9(
2335
+ const BackspaceButton = ({ style, label }) => /* @__PURE__ */ jsx10(
2215
2336
  "button",
2216
2337
  {
2217
2338
  type: "button",
@@ -2228,7 +2349,7 @@ var NumpadDialog = ({
2228
2349
  );
2229
2350
  return (
2230
2351
  // Backdrop
2231
- /* @__PURE__ */ jsxs8(
2352
+ /* @__PURE__ */ jsxs9(
2232
2353
  "div",
2233
2354
  {
2234
2355
  style: {
@@ -2245,14 +2366,14 @@ var NumpadDialog = ({
2245
2366
  },
2246
2367
  onClick: onClose,
2247
2368
  children: [
2248
- /* @__PURE__ */ jsx9("style", { children: `
2369
+ /* @__PURE__ */ jsx10("style", { children: `
2249
2370
  .np-key { transition: background .1s, transform .05s; touch-action: manipulation; }
2250
2371
  .np-key:active:not(:disabled) { background:#e2e8f0; transform: translateY(1px); }
2251
2372
  .np-key:focus-visible, .np-action:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }
2252
2373
  @keyframes np-blink { 0%,49%{opacity:1} 50%,100%{opacity:0} }
2253
2374
  .np-caret { display:inline-block; width:2px; height:1.1em; background:#2563eb; animation: np-blink 1s step-end infinite; }
2254
2375
  ` }),
2255
- /* @__PURE__ */ jsxs8(
2376
+ /* @__PURE__ */ jsxs9(
2256
2377
  "div",
2257
2378
  {
2258
2379
  ref: dialogRef,
@@ -2273,9 +2394,9 @@ var NumpadDialog = ({
2273
2394
  },
2274
2395
  onClick: (e) => e.stopPropagation(),
2275
2396
  children: [
2276
- /* @__PURE__ */ jsx9("div", { style: { padding: "14px 16px 0 16px" }, children: /* @__PURE__ */ jsx9("h3", { id: titleId, style: { margin: 0, fontSize: 15, fontWeight: 700, color: "#0f172a" }, children: deviceName ? `${deviceName} - ${parameterLabel}` : parameterLabel }) }),
2277
- /* @__PURE__ */ jsxs8("div", { style: { padding: 16, display: "flex", flexDirection: "column", gap: 10 }, children: [
2278
- /* @__PURE__ */ jsxs8(
2397
+ /* @__PURE__ */ jsx10("div", { style: { padding: "14px 16px 0 16px" }, children: /* @__PURE__ */ jsx10("h3", { id: titleId, style: { margin: 0, fontSize: 15, fontWeight: 700, color: "#0f172a" }, children: deviceName ? `${deviceName} - ${parameterLabel}` : parameterLabel }) }),
2398
+ /* @__PURE__ */ jsxs9("div", { style: { padding: 16, display: "flex", flexDirection: "column", gap: 10 }, children: [
2399
+ /* @__PURE__ */ jsxs9(
2279
2400
  "div",
2280
2401
  {
2281
2402
  style: {
@@ -2285,24 +2406,24 @@ var NumpadDialog = ({
2285
2406
  color: "#64748b"
2286
2407
  },
2287
2408
  children: [
2288
- /* @__PURE__ */ jsxs8("span", { children: [
2409
+ /* @__PURE__ */ jsxs9("span", { children: [
2289
2410
  "Current: ",
2290
2411
  currentValue,
2291
2412
  " ",
2292
2413
  unit
2293
2414
  ] }),
2294
- /* @__PURE__ */ jsxs8("span", { children: [
2415
+ /* @__PURE__ */ jsxs9("span", { children: [
2295
2416
  "Range: ",
2296
- /* @__PURE__ */ jsx9("span", { style: limitStyle(belowMin), children: min }),
2417
+ /* @__PURE__ */ jsx10("span", { style: limitStyle(belowMin), children: min }),
2297
2418
  "-",
2298
- /* @__PURE__ */ jsx9("span", { style: limitStyle(aboveMax), children: max }),
2419
+ /* @__PURE__ */ jsx10("span", { style: limitStyle(aboveMax), children: max }),
2299
2420
  " ",
2300
2421
  unit
2301
2422
  ] })
2302
2423
  ]
2303
2424
  }
2304
2425
  ),
2305
- /* @__PURE__ */ jsxs8(
2426
+ /* @__PURE__ */ jsxs9(
2306
2427
  "div",
2307
2428
  {
2308
2429
  "aria-live": "polite",
@@ -2324,13 +2445,13 @@ var NumpadDialog = ({
2324
2445
  border: outOfRange ? "1.5px solid #fca5a5" : "1.5px solid #e2e8f0"
2325
2446
  },
2326
2447
  children: [
2327
- /* @__PURE__ */ jsx9("span", { children: inputValue || "0" }),
2328
- /* @__PURE__ */ jsx9("span", { className: "np-caret", "aria-hidden": "true" }),
2329
- /* @__PURE__ */ jsx9("span", { style: { fontSize: 14, color: "#94a3b8", fontWeight: 500 }, children: unit })
2448
+ /* @__PURE__ */ jsx10("span", { children: inputValue || "0" }),
2449
+ /* @__PURE__ */ jsx10("span", { className: "np-caret", "aria-hidden": "true" }),
2450
+ /* @__PURE__ */ jsx10("span", { style: { fontSize: 14, color: "#94a3b8", fontWeight: 500 }, children: unit })
2330
2451
  ]
2331
2452
  }
2332
2453
  ),
2333
- /* @__PURE__ */ jsx9(
2454
+ /* @__PURE__ */ jsx10(
2334
2455
  "div",
2335
2456
  {
2336
2457
  role: "status",
@@ -2345,8 +2466,8 @@ var NumpadDialog = ({
2345
2466
  children: reason
2346
2467
  }
2347
2468
  ),
2348
- /* @__PURE__ */ jsxs8("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 5 }, children: [
2349
- ["7", "8", "9", "4", "5", "6", "1", "2", "3"].map((digit) => /* @__PURE__ */ jsx9(
2469
+ /* @__PURE__ */ jsxs9("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 5 }, children: [
2470
+ ["7", "8", "9", "4", "5", "6", "1", "2", "3"].map((digit) => /* @__PURE__ */ jsx10(
2350
2471
  "button",
2351
2472
  {
2352
2473
  type: "button",
@@ -2358,7 +2479,7 @@ var NumpadDialog = ({
2358
2479
  },
2359
2480
  digit
2360
2481
  )),
2361
- min < 0 ? /* @__PURE__ */ jsx9(
2482
+ min < 0 ? /* @__PURE__ */ jsx10(
2362
2483
  "button",
2363
2484
  {
2364
2485
  type: "button",
@@ -2369,9 +2490,9 @@ var NumpadDialog = ({
2369
2490
  onClick: handleToggleSign,
2370
2491
  children: "+/\u2212"
2371
2492
  }
2372
- ) : /* @__PURE__ */ jsx9(BackspaceButton, { style: { ...keyStyle, fontSize: 20, background: "#f8fafc", color: "#64748b" }, label: "\u232B" }),
2373
- /* @__PURE__ */ jsx9("button", { type: "button", className: "np-key", tabIndex: -1, style: keyStyle, onClick: () => appendDigit("0"), children: "0" }),
2374
- /* @__PURE__ */ jsx9(
2493
+ ) : /* @__PURE__ */ jsx10(BackspaceButton, { style: { ...keyStyle, fontSize: 20, background: "#f8fafc", color: "#64748b" }, label: "\u232B" }),
2494
+ /* @__PURE__ */ jsx10("button", { type: "button", className: "np-key", tabIndex: -1, style: keyStyle, onClick: () => appendDigit("0"), children: "0" }),
2495
+ /* @__PURE__ */ jsx10(
2375
2496
  "button",
2376
2497
  {
2377
2498
  type: "button",
@@ -2389,12 +2510,12 @@ var NumpadDialog = ({
2389
2510
  }
2390
2511
  )
2391
2512
  ] }),
2392
- /* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: 5 }, children: [
2393
- /* @__PURE__ */ jsx9("button", { type: "button", className: "np-key", tabIndex: -1, style: utilKeyStyle, onClick: handleClear, children: "Clear" }),
2394
- !backspaceInGrid && /* @__PURE__ */ jsx9(BackspaceButton, { style: utilKeyStyle, label: "Backspace" })
2513
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: 5 }, children: [
2514
+ /* @__PURE__ */ jsx10("button", { type: "button", className: "np-key", tabIndex: -1, style: utilKeyStyle, onClick: handleClear, children: "Clear" }),
2515
+ !backspaceInGrid && /* @__PURE__ */ jsx10(BackspaceButton, { style: utilKeyStyle, label: "Backspace" })
2395
2516
  ] }),
2396
- /* @__PURE__ */ jsxs8("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2397
- /* @__PURE__ */ jsx9(
2517
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", gap: 8, marginTop: 2 }, children: [
2518
+ /* @__PURE__ */ jsx10(
2398
2519
  "button",
2399
2520
  {
2400
2521
  type: "button",
@@ -2414,7 +2535,7 @@ var NumpadDialog = ({
2414
2535
  children: "Cancel"
2415
2536
  }
2416
2537
  ),
2417
- /* @__PURE__ */ jsx9(
2538
+ /* @__PURE__ */ jsx10(
2418
2539
  "button",
2419
2540
  {
2420
2541
  type: "button",
@@ -2449,13 +2570,13 @@ var NumpadDialog = ({
2449
2570
  };
2450
2571
 
2451
2572
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
2452
- import React7 from "react";
2573
+ import React8 from "react";
2453
2574
  import { Tab } from "@mui/material";
2454
2575
 
2455
2576
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
2456
2577
  import { Box, IconButton, Tabs } from "@mui/material";
2457
2578
  import styled from "@emotion/styled";
2458
- import { jsx as jsx10 } from "react/jsx-runtime";
2579
+ import { jsx as jsx11 } from "react/jsx-runtime";
2459
2580
  var FullscreenContainer = styled(Box)(
2460
2581
  ({ leftCollapsed, rightCollapsed }) => {
2461
2582
  const getGridTemplateAreas = () => {
@@ -2580,7 +2701,7 @@ var DisplayModeToggle = styled(IconButton)(({ mode }) => ({
2580
2701
  transform: "translateX(-50%) scale(1.05)"
2581
2702
  }
2582
2703
  }));
2583
- var ChevronLeft = () => /* @__PURE__ */ jsx10(
2704
+ var ChevronLeft = () => /* @__PURE__ */ jsx11(
2584
2705
  "div",
2585
2706
  {
2586
2707
  style: {
@@ -2592,7 +2713,7 @@ var ChevronLeft = () => /* @__PURE__ */ jsx10(
2592
2713
  }
2593
2714
  }
2594
2715
  );
2595
- var ChevronRight = () => /* @__PURE__ */ jsx10(
2716
+ var ChevronRight = () => /* @__PURE__ */ jsx11(
2596
2717
  "div",
2597
2718
  {
2598
2719
  style: {
@@ -2706,7 +2827,7 @@ var ScrollableSVGWrapper = styled("div")({
2706
2827
  import { useEffect as useEffect4, useState as useState7 } from "react";
2707
2828
  import { Box as Box2 } from "@mui/material";
2708
2829
  import styled2 from "@emotion/styled";
2709
- import { jsx as jsx11 } from "react/jsx-runtime";
2830
+ import { jsx as jsx12 } from "react/jsx-runtime";
2710
2831
  var baseOverlayStyles = {
2711
2832
  tank: {
2712
2833
  background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
@@ -2789,7 +2910,7 @@ var SVGLockedOverlay = ({
2789
2910
  const pixelX = svgX + svgOffset.x;
2790
2911
  const pixelY = svgY + svgOffset.y;
2791
2912
  const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
2792
- return /* @__PURE__ */ jsx11(
2913
+ return /* @__PURE__ */ jsx12(
2793
2914
  Box2,
2794
2915
  {
2795
2916
  className: `svg-locked-overlay ${className}`.trim(),
@@ -2853,7 +2974,7 @@ var CardUnit = styled2("div")({
2853
2974
  });
2854
2975
 
2855
2976
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
2856
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2977
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2857
2978
  var forcedTagStyle = {
2858
2979
  position: "absolute",
2859
2980
  top: "-6px",
@@ -2881,7 +3002,7 @@ var TrendLine = ({
2881
3002
  forced = false
2882
3003
  }) => {
2883
3004
  if (!values || values.length < 2) {
2884
- return /* @__PURE__ */ jsxs9(
3005
+ return /* @__PURE__ */ jsxs10(
2885
3006
  "div",
2886
3007
  {
2887
3008
  style: {
@@ -2895,8 +3016,8 @@ var TrendLine = ({
2895
3016
  justifyContent: "center"
2896
3017
  },
2897
3018
  children: [
2898
- /* @__PURE__ */ jsx12("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
2899
- forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3019
+ /* @__PURE__ */ jsx13("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
3020
+ forced && /* @__PURE__ */ jsx13("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
2900
3021
  ]
2901
3022
  }
2902
3023
  );
@@ -2909,7 +3030,7 @@ var TrendLine = ({
2909
3030
  const x = 4 + i / (values.length - 1) * (width - 8);
2910
3031
  return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
2911
3032
  }).join(" ");
2912
- return /* @__PURE__ */ jsxs9(
3033
+ return /* @__PURE__ */ jsxs10(
2913
3034
  "div",
2914
3035
  {
2915
3036
  style: {
@@ -2921,14 +3042,14 @@ var TrendLine = ({
2921
3042
  overflow: "visible"
2922
3043
  },
2923
3044
  children: [
2924
- /* @__PURE__ */ jsxs9(
3045
+ /* @__PURE__ */ jsxs10(
2925
3046
  "svg",
2926
3047
  {
2927
3048
  width,
2928
3049
  height,
2929
3050
  style: { position: "absolute", top: 0, left: 0, overflow: "hidden", borderRadius: "2px" },
2930
3051
  children: [
2931
- /* @__PURE__ */ jsx12(
3052
+ /* @__PURE__ */ jsx13(
2932
3053
  "path",
2933
3054
  {
2934
3055
  d: pathData,
@@ -2939,7 +3060,7 @@ var TrendLine = ({
2939
3060
  strokeLinejoin: "round"
2940
3061
  }
2941
3062
  ),
2942
- /* @__PURE__ */ jsx12(
3063
+ /* @__PURE__ */ jsx13(
2943
3064
  "circle",
2944
3065
  {
2945
3066
  cx: 4 + (width - 8),
@@ -2951,7 +3072,7 @@ var TrendLine = ({
2951
3072
  ]
2952
3073
  }
2953
3074
  ),
2954
- forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3075
+ forced && /* @__PURE__ */ jsx13("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
2955
3076
  ]
2956
3077
  }
2957
3078
  );
@@ -2983,7 +3104,7 @@ var CircularGauge = ({
2983
3104
  const borderColor = isHex ? hexToRgba(color, 0.9) : color;
2984
3105
  const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
2985
3106
  const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
2986
- return /* @__PURE__ */ jsxs9(
3107
+ return /* @__PURE__ */ jsxs10(
2987
3108
  "div",
2988
3109
  {
2989
3110
  style: {
@@ -2992,7 +3113,7 @@ var CircularGauge = ({
2992
3113
  alignItems: "center"
2993
3114
  },
2994
3115
  children: [
2995
- /* @__PURE__ */ jsxs9(
3116
+ /* @__PURE__ */ jsxs10(
2996
3117
  "div",
2997
3118
  {
2998
3119
  style: {
@@ -3004,8 +3125,8 @@ var CircularGauge = ({
3004
3125
  border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : `1px solid ${borderStrokeColor}`
3005
3126
  },
3006
3127
  children: [
3007
- /* @__PURE__ */ jsxs9("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
3008
- /* @__PURE__ */ jsx12(
3128
+ /* @__PURE__ */ jsxs10("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
3129
+ /* @__PURE__ */ jsx13(
3009
3130
  "circle",
3010
3131
  {
3011
3132
  cx: size / 2,
@@ -3016,7 +3137,7 @@ var CircularGauge = ({
3016
3137
  strokeWidth: 1
3017
3138
  }
3018
3139
  ),
3019
- /* @__PURE__ */ jsx12(
3140
+ /* @__PURE__ */ jsx13(
3020
3141
  "circle",
3021
3142
  {
3022
3143
  cx: size / 2,
@@ -3027,7 +3148,7 @@ var CircularGauge = ({
3027
3148
  fill: "transparent"
3028
3149
  }
3029
3150
  ),
3030
- /* @__PURE__ */ jsx12(
3151
+ /* @__PURE__ */ jsx13(
3031
3152
  "circle",
3032
3153
  {
3033
3154
  cx: size / 2,
@@ -3043,7 +3164,7 @@ var CircularGauge = ({
3043
3164
  }
3044
3165
  )
3045
3166
  ] }),
3046
- /* @__PURE__ */ jsxs9(
3167
+ /* @__PURE__ */ jsxs10(
3047
3168
  "div",
3048
3169
  {
3049
3170
  style: {
@@ -3059,14 +3180,14 @@ var CircularGauge = ({
3059
3180
  },
3060
3181
  children: [
3061
3182
  value.toFixed(1),
3062
- /* @__PURE__ */ jsx12("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3183
+ /* @__PURE__ */ jsx13("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
3063
3184
  ]
3064
3185
  }
3065
3186
  )
3066
3187
  ]
3067
3188
  }
3068
3189
  ),
3069
- /* @__PURE__ */ jsx12(
3190
+ /* @__PURE__ */ jsx13(
3070
3191
  "div",
3071
3192
  {
3072
3193
  style: {
@@ -3078,7 +3199,7 @@ var CircularGauge = ({
3078
3199
  children: label
3079
3200
  }
3080
3201
  ),
3081
- forced && /* @__PURE__ */ jsx12(
3202
+ forced && /* @__PURE__ */ jsx13(
3082
3203
  "span",
3083
3204
  {
3084
3205
  "aria-label": "Forced",
@@ -3099,7 +3220,7 @@ var CircularGauge = ({
3099
3220
  children: "F"
3100
3221
  }
3101
3222
  ),
3102
- forced && realValue !== void 0 && /* @__PURE__ */ jsxs9("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3223
+ forced && realValue !== void 0 && /* @__PURE__ */ jsxs10("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
3103
3224
  "REAL ",
3104
3225
  realValue.toFixed(1),
3105
3226
  " ",
@@ -3124,7 +3245,7 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3124
3245
  const y = height - 8 - (value - min) / range * (height - 8);
3125
3246
  return `${x + 4},${y + 4}`;
3126
3247
  }).join(" ");
3127
- return /* @__PURE__ */ jsxs9(
3248
+ return /* @__PURE__ */ jsxs10(
3128
3249
  "div",
3129
3250
  {
3130
3251
  style: {
@@ -3140,13 +3261,13 @@ var Sparkline = ({ data, width, height, color, forced = false }) => {
3140
3261
  boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
3141
3262
  },
3142
3263
  children: [
3143
- /* @__PURE__ */ jsx12("svg", { width, height, children: /* @__PURE__ */ jsx12("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
3144
- forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3264
+ /* @__PURE__ */ jsx13("svg", { width, height, children: /* @__PURE__ */ jsx13("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
3265
+ forced && /* @__PURE__ */ jsx13("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
3145
3266
  ]
3146
3267
  }
3147
3268
  );
3148
3269
  };
3149
- var EquipmentForcedBadge = () => /* @__PURE__ */ jsx12(
3270
+ var EquipmentForcedBadge = () => /* @__PURE__ */ jsx13(
3150
3271
  "span",
3151
3272
  {
3152
3273
  "aria-label": "Forced",
@@ -3181,9 +3302,9 @@ var EquipmentIndicatorWithSparkline = ({
3181
3302
  forced = false
3182
3303
  }) => {
3183
3304
  const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
3184
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
3185
- /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsxs9("div", { style: { position: "relative", width: size, height: size }, children: [
3186
- /* @__PURE__ */ jsx12(
3305
+ return /* @__PURE__ */ jsxs10(Fragment3, { children: [
3306
+ /* @__PURE__ */ jsx13(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsxs10("div", { style: { position: "relative", width: size, height: size }, children: [
3307
+ /* @__PURE__ */ jsx13(
3187
3308
  "div",
3188
3309
  {
3189
3310
  style: {
@@ -3204,9 +3325,9 @@ var EquipmentIndicatorWithSparkline = ({
3204
3325
  children: label
3205
3326
  }
3206
3327
  ),
3207
- forced && /* @__PURE__ */ jsx12(EquipmentForcedBadge, {})
3328
+ forced && /* @__PURE__ */ jsx13(EquipmentForcedBadge, {})
3208
3329
  ] }) }),
3209
- hasSparkline && /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx12(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
3330
+ hasSparkline && /* @__PURE__ */ jsx13(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx13(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
3210
3331
  ] });
3211
3332
  };
3212
3333
  var EquipmentIndicator = ({
@@ -3220,8 +3341,8 @@ var EquipmentIndicator = ({
3220
3341
  forced = false
3221
3342
  }) => {
3222
3343
  const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
3223
- return /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsxs9("div", { style: { position: "relative", width: size, height: size }, children: [
3224
- /* @__PURE__ */ jsx12(
3344
+ return /* @__PURE__ */ jsx13(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsxs10("div", { style: { position: "relative", width: size, height: size }, children: [
3345
+ /* @__PURE__ */ jsx13(
3225
3346
  "div",
3226
3347
  {
3227
3348
  style: {
@@ -3242,12 +3363,12 @@ var EquipmentIndicator = ({
3242
3363
  children: label
3243
3364
  }
3244
3365
  ),
3245
- forced && /* @__PURE__ */ jsx12(EquipmentForcedBadge, {})
3366
+ forced && /* @__PURE__ */ jsx13(EquipmentForcedBadge, {})
3246
3367
  ] }) });
3247
3368
  };
3248
3369
 
3249
3370
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
3250
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3371
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
3251
3372
  function FullscreenWorkspace({
3252
3373
  svgContent,
3253
3374
  overlays,
@@ -3275,10 +3396,10 @@ function FullscreenWorkspace({
3275
3396
  className = "",
3276
3397
  ...rest
3277
3398
  }) {
3278
- const [leftCollapsedState, setLeftCollapsedState] = React7.useState(defaultLeftCollapsed);
3279
- const [rightCollapsedState, setRightCollapsedState] = React7.useState(defaultRightCollapsed);
3280
- const [internalDisplayMode, setInternalDisplayMode] = React7.useState(displayMode ?? defaultDisplayMode);
3281
- const [internalTab, setInternalTab] = React7.useState(
3399
+ const [leftCollapsedState, setLeftCollapsedState] = React8.useState(defaultLeftCollapsed);
3400
+ const [rightCollapsedState, setRightCollapsedState] = React8.useState(defaultRightCollapsed);
3401
+ const [internalDisplayMode, setInternalDisplayMode] = React8.useState(displayMode ?? defaultDisplayMode);
3402
+ const [internalTab, setInternalTab] = React8.useState(
3282
3403
  tabs && tabs.length > 0 ? tabs[0].value : ""
3283
3404
  );
3284
3405
  const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
@@ -3286,10 +3407,10 @@ function FullscreenWorkspace({
3286
3407
  const isDisplayModeControlled = displayMode !== void 0;
3287
3408
  const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
3288
3409
  const isTabControlled = activeTab !== void 0 && activeTab !== null;
3289
- const resolvedTabs = React7.useMemo(() => tabs ?? [], [tabs]);
3410
+ const resolvedTabs = React8.useMemo(() => tabs ?? [], [tabs]);
3290
3411
  const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
3291
3412
  const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
3292
- React7.useEffect(() => {
3413
+ React8.useEffect(() => {
3293
3414
  if (resolvedTabs.length > 0) {
3294
3415
  const values = resolvedTabs.map((tab) => tab.value);
3295
3416
  if (!values.includes(currentTab)) {
@@ -3298,7 +3419,7 @@ function FullscreenWorkspace({
3298
3419
  }
3299
3420
  }
3300
3421
  }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
3301
- React7.useEffect(() => {
3422
+ React8.useEffect(() => {
3302
3423
  if (displayMode !== void 0) {
3303
3424
  setInternalDisplayMode(displayMode);
3304
3425
  }
@@ -3333,7 +3454,7 @@ function FullscreenWorkspace({
3333
3454
  const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
3334
3455
  const showLeftToggle = Boolean(leftPanel);
3335
3456
  const showRightToggle = Boolean(rightPanel);
3336
- return /* @__PURE__ */ jsxs10(
3457
+ return /* @__PURE__ */ jsxs11(
3337
3458
  FullscreenContainer,
3338
3459
  {
3339
3460
  leftCollapsed,
@@ -3341,25 +3462,25 @@ function FullscreenWorkspace({
3341
3462
  className: `tff-svg-container ${className}`.trim(),
3342
3463
  ...rest,
3343
3464
  children: [
3344
- showLeftToggle && /* @__PURE__ */ jsx13(
3465
+ showLeftToggle && /* @__PURE__ */ jsx14(
3345
3466
  LeftToggleButton,
3346
3467
  {
3347
3468
  collapsed: leftCollapsed,
3348
3469
  onClick: handleLeftToggle,
3349
3470
  "aria-label": leftCollapsed ? "Expand left panel" : "Collapse left panel",
3350
- children: leftCollapsed ? /* @__PURE__ */ jsx13(ChevronRight, {}) : /* @__PURE__ */ jsx13(ChevronLeft, {})
3471
+ children: leftCollapsed ? /* @__PURE__ */ jsx14(ChevronRight, {}) : /* @__PURE__ */ jsx14(ChevronLeft, {})
3351
3472
  }
3352
3473
  ),
3353
- showRightToggle && /* @__PURE__ */ jsx13(
3474
+ showRightToggle && /* @__PURE__ */ jsx14(
3354
3475
  RightToggleButton,
3355
3476
  {
3356
3477
  collapsed: rightCollapsed,
3357
3478
  onClick: handleRightToggle,
3358
3479
  "aria-label": rightCollapsed ? "Expand right panel" : "Collapse right panel",
3359
- children: rightCollapsed ? /* @__PURE__ */ jsx13(ChevronLeft, {}) : /* @__PURE__ */ jsx13(ChevronRight, {})
3480
+ children: rightCollapsed ? /* @__PURE__ */ jsx14(ChevronLeft, {}) : /* @__PURE__ */ jsx14(ChevronRight, {})
3360
3481
  }
3361
3482
  ),
3362
- showDisplayModeToggle && /* @__PURE__ */ jsx13(
3483
+ showDisplayModeToggle && /* @__PURE__ */ jsx14(
3363
3484
  DisplayModeToggle,
3364
3485
  {
3365
3486
  mode: currentDisplayMode,
@@ -3368,9 +3489,9 @@ function FullscreenWorkspace({
3368
3489
  children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
3369
3490
  }
3370
3491
  ),
3371
- /* @__PURE__ */ jsxs10(SVGArea, { children: [
3372
- showZoomControls && /* @__PURE__ */ jsxs10(ZoomControls, { children: [
3373
- /* @__PURE__ */ jsx13(
3492
+ /* @__PURE__ */ jsxs11(SVGArea, { children: [
3493
+ showZoomControls && /* @__PURE__ */ jsxs11(ZoomControls, { children: [
3494
+ /* @__PURE__ */ jsx14(
3374
3495
  ZoomButton,
3375
3496
  {
3376
3497
  onClick: onZoomIn,
@@ -3380,7 +3501,7 @@ function FullscreenWorkspace({
3380
3501
  children: "+"
3381
3502
  }
3382
3503
  ),
3383
- /* @__PURE__ */ jsx13(
3504
+ /* @__PURE__ */ jsx14(
3384
3505
  ZoomButton,
3385
3506
  {
3386
3507
  onClick: onZoomOut,
@@ -3390,7 +3511,7 @@ function FullscreenWorkspace({
3390
3511
  children: "-"
3391
3512
  }
3392
3513
  ),
3393
- onResetZoom && /* @__PURE__ */ jsx13(
3514
+ onResetZoom && /* @__PURE__ */ jsx14(
3394
3515
  ZoomButton,
3395
3516
  {
3396
3517
  onClick: onResetZoom,
@@ -3401,25 +3522,25 @@ function FullscreenWorkspace({
3401
3522
  }
3402
3523
  )
3403
3524
  ] }),
3404
- /* @__PURE__ */ jsx13(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ jsxs10(FixedSVGContainer, { className: "svg-container", children: [
3525
+ /* @__PURE__ */ jsx14(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ jsxs11(FixedSVGContainer, { className: "svg-container", children: [
3405
3526
  svgContent,
3406
3527
  overlays
3407
3528
  ] }) })
3408
3529
  ] }),
3409
- /* @__PURE__ */ jsx13(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
3410
- /* @__PURE__ */ jsx13(
3530
+ /* @__PURE__ */ jsx14(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
3531
+ /* @__PURE__ */ jsx14(
3411
3532
  PanelTabs,
3412
3533
  {
3413
3534
  value: currentTab,
3414
3535
  onChange: handleTabChangeInternal,
3415
3536
  "aria-label": "Left panel tabs",
3416
- children: resolvedTabs.map((tab) => /* @__PURE__ */ jsx13(Tab, { label: tab.label, value: tab.value }, tab.value))
3537
+ children: resolvedTabs.map((tab) => /* @__PURE__ */ jsx14(Tab, { label: tab.label, value: tab.value }, tab.value))
3417
3538
  }
3418
3539
  ),
3419
- /* @__PURE__ */ jsx13(PanelContent, { children: currentTabContent })
3540
+ /* @__PURE__ */ jsx14(PanelContent, { children: currentTabContent })
3420
3541
  ] }) : leftPanel }),
3421
- /* @__PURE__ */ jsx13(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3422
- /* @__PURE__ */ jsx13(FooterPanel, { children: footer })
3542
+ /* @__PURE__ */ jsx14(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
3543
+ /* @__PURE__ */ jsx14(FooterPanel, { children: footer })
3423
3544
  ]
3424
3545
  }
3425
3546
  );
@@ -3427,7 +3548,7 @@ function FullscreenWorkspace({
3427
3548
 
3428
3549
  // src/theme/ThemeContext.tsx
3429
3550
  import { createContext, useContext, useState as useState8, useEffect as useEffect5 } from "react";
3430
- import { jsx as jsx14 } from "react/jsx-runtime";
3551
+ import { jsx as jsx15 } from "react/jsx-runtime";
3431
3552
  var ThemeContext = createContext(void 0);
3432
3553
  var useTheme = () => {
3433
3554
  const context = useContext(ThemeContext);
@@ -3450,11 +3571,11 @@ var ThemeProvider = ({ children }) => {
3450
3571
  const setTheme = (newTheme) => {
3451
3572
  setThemeState(newTheme);
3452
3573
  };
3453
- return /* @__PURE__ */ jsx14(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3574
+ return /* @__PURE__ */ jsx15(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
3454
3575
  };
3455
3576
 
3456
3577
  // src/theme/ThemeToggle.tsx
3457
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3578
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
3458
3579
  var ThemeToggle = ({
3459
3580
  size = "medium",
3460
3581
  position = "top-right",
@@ -3525,18 +3646,18 @@ var ThemeToggle = ({
3525
3646
  transition: "all 0.2s ease",
3526
3647
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
3527
3648
  };
3528
- return /* @__PURE__ */ jsxs11("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
3529
- /* @__PURE__ */ jsx15("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
3530
- /* @__PURE__ */ jsx15("div", { style: toggleStyle, children: /* @__PURE__ */ jsx15("div", { style: thumbStyle }) }),
3531
- /* @__PURE__ */ jsx15("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
3649
+ return /* @__PURE__ */ jsxs12("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
3650
+ /* @__PURE__ */ jsx16("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
3651
+ /* @__PURE__ */ jsx16("div", { style: toggleStyle, children: /* @__PURE__ */ jsx16("div", { style: thumbStyle }) }),
3652
+ /* @__PURE__ */ jsx16("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
3532
3653
  ] });
3533
3654
  };
3534
3655
 
3535
3656
  // src/components/PIDCanvas/PIDCanvas.tsx
3536
- import React13, { useCallback as useCallback8, useState as useState14, useEffect as useEffect13, useRef as useRef6 } from "react";
3657
+ import React14, { useCallback as useCallback8, useState as useState14, useEffect as useEffect13, useRef as useRef6 } from "react";
3537
3658
 
3538
3659
  // src/components/PIDCanvas/NodeRenderer.tsx
3539
- import React9 from "react";
3660
+ import React10 from "react";
3540
3661
 
3541
3662
  // src/diagram/symbols/mockSymbolLibrary.ts
3542
3663
  var mockSymbolLibrary = {
@@ -4910,9 +5031,110 @@ function writeAppearanceValue(node, field, value) {
4910
5031
  return { metadata: { ...node.metadata, [field.key]: value } };
4911
5032
  }
4912
5033
 
5034
+ // src/diagram/badges/nodeBadgeGlyphs.ts
5035
+ var PROHIBIT_GLYPH = {
5036
+ id: "prohibit",
5037
+ svgContent: '<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2.4"/><line x1="5.6" y1="18.4" x2="18.4" y2="5.6" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/>'
5038
+ };
5039
+ var builtInBadgeGlyphs = {
5040
+ [PROHIBIT_GLYPH.id]: PROHIBIT_GLYPH
5041
+ };
5042
+ var customBadgeGlyphs = {};
5043
+ function registerBadgeGlyph(glyph) {
5044
+ customBadgeGlyphs[glyph.id] = glyph;
5045
+ }
5046
+ function registerBadgeGlyphs(glyphs) {
5047
+ if (Array.isArray(glyphs)) {
5048
+ glyphs.forEach((glyph) => registerBadgeGlyph(glyph));
5049
+ } else {
5050
+ Object.values(glyphs).forEach((glyph) => registerBadgeGlyph(glyph));
5051
+ }
5052
+ }
5053
+ function getBadgeGlyph(glyphId) {
5054
+ return customBadgeGlyphs[glyphId] ?? builtInBadgeGlyphs[glyphId];
5055
+ }
5056
+ function getAvailableBadgeGlyphs() {
5057
+ return [...Object.keys(customBadgeGlyphs), ...Object.keys(builtInBadgeGlyphs)];
5058
+ }
5059
+
4913
5060
  // src/components/PIDCanvas/NodeRenderer.tsx
4914
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
4915
- var HATCH_SIZE = 6;
5061
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
5062
+ var HATCH_TILE_SIZE = 7;
5063
+ var HATCH_STRIPE_WIDTH = 2;
5064
+ var HATCH_STRIPE_ANGLE = 135;
5065
+ var HATCH_STRIPE_OPACITY = 85 / 255;
5066
+ function isUnknownNode(node) {
5067
+ return node.positionUnknown === true || normalizeDeviceStatus(node.status) === "unknown";
5068
+ }
5069
+ var DEFAULT_BADGE_CORNER = "top-right";
5070
+ var DEFAULT_BADGE_SIZE = 14;
5071
+ var DEFAULT_BADGE_COLOR = "#111827";
5072
+ var DEFAULT_BADGE_BACKGROUND = "#d1d5db";
5073
+ var BADGE_GLYPH_BOX = 24;
5074
+ var BADGE_BLINK_KEYFRAME_ID = "pid-node-badge-blink-keyframes";
5075
+ var BADGE_BLINK_KEYFRAME_NAME = "pid-node-badge-blink";
5076
+ function ensureBadgeBlinkKeyframes() {
5077
+ if (typeof document === "undefined") return;
5078
+ if (document.getElementById(BADGE_BLINK_KEYFRAME_ID)) return;
5079
+ const style = document.createElement("style");
5080
+ style.id = BADGE_BLINK_KEYFRAME_ID;
5081
+ style.textContent = `@keyframes ${BADGE_BLINK_KEYFRAME_NAME}{0%{opacity:1}50%{opacity:.15}100%{opacity:1}}`;
5082
+ document.head.appendChild(style);
5083
+ }
5084
+ function badgeCenter(corner, vb, size) {
5085
+ const margin = size / 4;
5086
+ switch (corner) {
5087
+ case "top-left":
5088
+ return { x: -margin, y: -margin };
5089
+ case "bottom-left":
5090
+ return { x: -margin, y: vb.height + margin };
5091
+ case "bottom-right":
5092
+ return { x: vb.width + margin, y: vb.height + margin };
5093
+ case "top-right":
5094
+ default:
5095
+ return { x: vb.width + margin, y: -margin };
5096
+ }
5097
+ }
5098
+ function renderNodeBadge(badge, vb, rotation) {
5099
+ const glyphDef = getBadgeGlyph(badge.glyph);
5100
+ const size = badge.size ?? DEFAULT_BADGE_SIZE;
5101
+ const color = badge.color ?? DEFAULT_BADGE_COLOR;
5102
+ const backgroundColor = badge.backgroundColor ?? DEFAULT_BADGE_BACKGROUND;
5103
+ const corner = badge.corner ?? DEFAULT_BADGE_CORNER;
5104
+ const { x: cx, y: cy } = badgeCenter(corner, vb, size);
5105
+ const radius = size / 2;
5106
+ const glyphScale = size / BADGE_GLYPH_BOX;
5107
+ let blinkStyle;
5108
+ if (badge.blink) {
5109
+ ensureBadgeBlinkKeyframes();
5110
+ blinkStyle = {
5111
+ animation: `${BADGE_BLINK_KEYFRAME_NAME} ${badge.blinkPeriodMs}ms ease-in-out infinite`
5112
+ };
5113
+ }
5114
+ return /* @__PURE__ */ jsxs13(
5115
+ "g",
5116
+ {
5117
+ "data-node-badge": badge.glyph,
5118
+ "data-badge-corner": corner,
5119
+ "data-badge-blink": badge.blink ? "true" : "false",
5120
+ "aria-label": badge.label,
5121
+ role: badge.label ? "img" : void 0,
5122
+ transform: rotation ? `translate(${cx}, ${cy}) rotate(${-rotation})` : `translate(${cx}, ${cy})`,
5123
+ style: blinkStyle,
5124
+ children: [
5125
+ /* @__PURE__ */ jsx17("circle", { r: radius, fill: backgroundColor }),
5126
+ glyphDef && /* @__PURE__ */ jsx17(
5127
+ "g",
5128
+ {
5129
+ color,
5130
+ transform: `scale(${glyphScale}) translate(${-BADGE_GLYPH_BOX / 2}, ${-BADGE_GLYPH_BOX / 2})`,
5131
+ dangerouslySetInnerHTML: { __html: glyphDef.svgContent }
5132
+ }
5133
+ )
5134
+ ]
5135
+ }
5136
+ );
5137
+ }
4916
5138
  function NodeRendererImpl({
4917
5139
  nodes: nodes2,
4918
5140
  selectedNodeIds,
@@ -4924,41 +5146,42 @@ function NodeRendererImpl({
4924
5146
  enableDrag = false,
4925
5147
  statusColorMap
4926
5148
  }) {
4927
- const hatchId = `pid-unknown-hatch-${React9.useId().replace(/[^A-Za-z0-9_-]/g, "")}`;
4928
- const hasUnknown = nodes2.some((n) => n.positionUnknown === true && n.visible !== false);
4929
- return /* @__PURE__ */ jsxs12("g", { id: "layer-nodes", children: [
4930
- hasUnknown && /* @__PURE__ */ jsx16("defs", { children: /* @__PURE__ */ jsxs12(
5149
+ const hatchPatternId = `node-unknown-hatch-${React10.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
5150
+ const visibleNodes = nodes2.filter((node) => node.visible !== false);
5151
+ const hasUnknownNode = visibleNodes.some(isUnknownNode);
5152
+ const unknownEntry = resolveStatusColor("unknown", statusColorMap);
5153
+ return /* @__PURE__ */ jsxs13("g", { id: "layer-nodes", children: [
5154
+ hasUnknownNode && /* @__PURE__ */ jsx17("defs", { children: /* @__PURE__ */ jsxs13(
4931
5155
  "pattern",
4932
5156
  {
4933
- id: hatchId,
4934
- "data-testid": "position-unknown-pattern",
5157
+ id: hatchPatternId,
5158
+ "data-testid": "unknown-hatch-pattern",
4935
5159
  patternUnits: "userSpaceOnUse",
4936
- width: HATCH_SIZE,
4937
- height: HATCH_SIZE,
4938
- patternTransform: "rotate(45)",
5160
+ width: HATCH_TILE_SIZE,
5161
+ height: HATCH_TILE_SIZE,
5162
+ patternTransform: `rotate(${HATCH_STRIPE_ANGLE})`,
4939
5163
  children: [
4940
- /* @__PURE__ */ jsx16("rect", { width: HATCH_SIZE, height: HATCH_SIZE, fill: UNKNOWN_MARK_COLOR.fill }),
4941
- /* @__PURE__ */ jsx16(
4942
- "line",
5164
+ /* @__PURE__ */ jsx17("rect", { width: HATCH_TILE_SIZE, height: HATCH_TILE_SIZE, fill: unknownEntry.fill }),
5165
+ /* @__PURE__ */ jsx17(
5166
+ "rect",
4943
5167
  {
4944
- x1: "0",
4945
- y1: "0",
4946
- x2: "0",
4947
- y2: HATCH_SIZE,
4948
- stroke: UNKNOWN_MARK_COLOR.text,
4949
- strokeWidth: "2"
5168
+ x: HATCH_TILE_SIZE - HATCH_STRIPE_WIDTH,
5169
+ width: HATCH_STRIPE_WIDTH,
5170
+ height: HATCH_TILE_SIZE,
5171
+ fill: unknownEntry.stroke,
5172
+ fillOpacity: HATCH_STRIPE_OPACITY
4950
5173
  }
4951
5174
  )
4952
5175
  ]
4953
5176
  }
4954
5177
  ) }),
4955
- nodes2.filter((node) => node.visible !== false).map((node) => {
5178
+ visibleNodes.map((node) => {
4956
5179
  const symbol = getSymbolDefinition(node.symbolId);
4957
5180
  const isSelected = selectedNodeIds?.has(node.id) ?? false;
4958
5181
  const isDragging = draggingNodeId === node.id;
4959
5182
  if (!symbol) {
4960
- return /* @__PURE__ */ jsxs12("g", { children: [
4961
- /* @__PURE__ */ jsx16(
5183
+ return /* @__PURE__ */ jsxs13("g", { children: [
5184
+ /* @__PURE__ */ jsx17(
4962
5185
  "circle",
4963
5186
  {
4964
5187
  cx: node.transform.x,
@@ -4970,7 +5193,7 @@ function NodeRendererImpl({
4970
5193
  strokeWidth: "2"
4971
5194
  }
4972
5195
  ),
4973
- /* @__PURE__ */ jsx16(
5196
+ /* @__PURE__ */ jsx17(
4974
5197
  "text",
4975
5198
  {
4976
5199
  x: node.transform.x,
@@ -5010,9 +5233,9 @@ function NodeRendererImpl({
5010
5233
  );
5011
5234
  }
5012
5235
  const statusEntry = resolveStatusColor(node.status, statusColorMap);
5013
- const isUnknown = node.positionUnknown === true;
5014
- const fillColor = isUnknown ? `url(#${hatchId})` : node.customColors?.fill ?? statusEntry.fill;
5015
- const strokeColor = isUnknown ? UNKNOWN_MARK_COLOR.stroke : node.customColors?.stroke ?? statusEntry.stroke;
5236
+ const isUnknown = isUnknownNode(node);
5237
+ const fillColor = isUnknown ? `url(#${hatchPatternId})` : node.customColors?.fill ?? statusEntry.fill;
5238
+ const strokeColor = isUnknown ? unknownEntry.stroke : node.customColors?.stroke ?? statusEntry.stroke;
5016
5239
  const appearance = { ...getAppearanceDefaults(node.symbolId), ...node.metadata ?? {} };
5017
5240
  const ledStyle = {};
5018
5241
  if (appearance.shape !== void 0) {
@@ -5023,7 +5246,8 @@ function NodeRendererImpl({
5023
5246
  ledStyle["--led-bezel"] = appearance.led ? "2" : "0";
5024
5247
  }
5025
5248
  if (appearance.glow) {
5026
- ledStyle.filter = `drop-shadow(0 0 4px ${fillColor})`;
5249
+ const glowColor = isUnknown ? unknownEntry.stroke : fillColor;
5250
+ ledStyle.filter = `drop-shadow(0 0 4px ${glowColor})`;
5027
5251
  }
5028
5252
  const ledAnimation = typeof appearance.animation === "string" && appearance.animation !== "none" ? appearance.animation : void 0;
5029
5253
  const vb = symbol.viewBox;
@@ -5046,7 +5270,7 @@ function NodeRendererImpl({
5046
5270
  labelY = vb.height / 2 + oy;
5047
5271
  labelAnchor = "start";
5048
5272
  }
5049
- return /* @__PURE__ */ jsxs12(
5273
+ return /* @__PURE__ */ jsxs13(
5050
5274
  "g",
5051
5275
  {
5052
5276
  "data-node-id": node.id,
@@ -5054,7 +5278,7 @@ function NodeRendererImpl({
5054
5278
  "data-selected": isSelected,
5055
5279
  "data-dragging": isDragging,
5056
5280
  "data-led-animation": ledAnimation,
5057
- "data-position-unknown": isUnknown ? "true" : void 0,
5281
+ "data-position-unknown": node.positionUnknown === true ? "true" : void 0,
5058
5282
  transform: transforms.join(" "),
5059
5283
  style: {
5060
5284
  "--symbol-fill": fillColor,
@@ -5082,7 +5306,7 @@ function NodeRendererImpl({
5082
5306
  }
5083
5307
  },
5084
5308
  children: [
5085
- isSelected && /* @__PURE__ */ jsx16(
5309
+ isSelected && /* @__PURE__ */ jsx17(
5086
5310
  "rect",
5087
5311
  {
5088
5312
  x: "-5",
@@ -5097,7 +5321,7 @@ function NodeRendererImpl({
5097
5321
  pointerEvents: "none"
5098
5322
  }
5099
5323
  ),
5100
- /* @__PURE__ */ jsx16(
5324
+ /* @__PURE__ */ jsx17(
5101
5325
  "g",
5102
5326
  {
5103
5327
  dangerouslySetInnerHTML: { __html: symbol.svgContent },
@@ -5105,7 +5329,7 @@ function NodeRendererImpl({
5105
5329
  style: { pointerEvents: "auto" }
5106
5330
  }
5107
5331
  ),
5108
- /* @__PURE__ */ jsx16(
5332
+ /* @__PURE__ */ jsx17(
5109
5333
  "text",
5110
5334
  {
5111
5335
  x: labelX,
@@ -5117,7 +5341,8 @@ function NodeRendererImpl({
5117
5341
  transform: node.transform.rotation ? `rotate(${-node.transform.rotation}, ${labelX}, ${labelY})` : void 0,
5118
5342
  children: node.label || node.id
5119
5343
  }
5120
- )
5344
+ ),
5345
+ node.badge && renderNodeBadge(node.badge, vb, node.transform.rotation)
5121
5346
  ]
5122
5347
  },
5123
5348
  node.id
@@ -5125,11 +5350,11 @@ function NodeRendererImpl({
5125
5350
  })
5126
5351
  ] });
5127
5352
  }
5128
- var NodeRenderer = React9.memo(NodeRendererImpl);
5353
+ var NodeRenderer = React10.memo(NodeRendererImpl);
5129
5354
 
5130
5355
  // src/components/PIDCanvas/PipeRenderer.tsx
5131
- import React10 from "react";
5132
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
5356
+ import React11 from "react";
5357
+ import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
5133
5358
  function PipeRendererImpl({
5134
5359
  pipes,
5135
5360
  selectedPipeIds,
@@ -5144,7 +5369,7 @@ function PipeRendererImpl({
5144
5369
  waypointDragOffset,
5145
5370
  onPipeSegmentClick
5146
5371
  }) {
5147
- return /* @__PURE__ */ jsx17("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5372
+ return /* @__PURE__ */ jsx18("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
5148
5373
  const isSelected = selectedPipeIds?.has(pipe.id) ?? false;
5149
5374
  const isEditing = enableWaypointEditing && editingPipeId === pipe.id;
5150
5375
  const showEditingControls = enableWaypointEditing && isSelected;
@@ -5163,7 +5388,7 @@ function PipeRendererImpl({
5163
5388
  const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
5164
5389
  const strokeDasharray = pipeStyle.strokeDasharray;
5165
5390
  const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
5166
- return /* @__PURE__ */ jsxs13(
5391
+ return /* @__PURE__ */ jsxs14(
5167
5392
  "g",
5168
5393
  {
5169
5394
  "data-pipe-id": pipe.id,
@@ -5176,8 +5401,8 @@ function PipeRendererImpl({
5176
5401
  cursor: onPipeClick ? "pointer" : "default"
5177
5402
  },
5178
5403
  children: [
5179
- !enableWaypointEditing && /* @__PURE__ */ jsxs13(Fragment5, { children: [
5180
- onPipeClick && /* @__PURE__ */ jsx17(
5404
+ !enableWaypointEditing && /* @__PURE__ */ jsxs14(Fragment5, { children: [
5405
+ onPipeClick && /* @__PURE__ */ jsx18(
5181
5406
  "polyline",
5182
5407
  {
5183
5408
  points: pointsString,
@@ -5189,7 +5414,7 @@ function PipeRendererImpl({
5189
5414
  pointerEvents: "stroke"
5190
5415
  }
5191
5416
  ),
5192
- /* @__PURE__ */ jsx17(
5417
+ /* @__PURE__ */ jsx18(
5193
5418
  "polyline",
5194
5419
  {
5195
5420
  points: pointsString,
@@ -5213,7 +5438,7 @@ function PipeRendererImpl({
5213
5438
  const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
5214
5439
  const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
5215
5440
  const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
5216
- return /* @__PURE__ */ jsx17(
5441
+ return /* @__PURE__ */ jsx18(
5217
5442
  "circle",
5218
5443
  {
5219
5444
  cx: point.x,
@@ -5250,12 +5475,12 @@ function PipeRendererImpl({
5250
5475
  `${pipe.id}-point-${idx}`
5251
5476
  );
5252
5477
  }),
5253
- showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ jsx17(Fragment5, { children: displayPoints.slice(0, -1).map((point, idx) => {
5478
+ showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ jsx18(Fragment5, { children: displayPoints.slice(0, -1).map((point, idx) => {
5254
5479
  const nextPoint = displayPoints[idx + 1];
5255
5480
  const midX = (point.x + nextPoint.x) / 2;
5256
5481
  const midY = (point.y + nextPoint.y) / 2;
5257
- return /* @__PURE__ */ jsxs13("g", { children: [
5258
- /* @__PURE__ */ jsx17(
5482
+ return /* @__PURE__ */ jsxs14("g", { children: [
5483
+ /* @__PURE__ */ jsx18(
5259
5484
  "circle",
5260
5485
  {
5261
5486
  cx: midX,
@@ -5271,7 +5496,7 @@ function PipeRendererImpl({
5271
5496
  }
5272
5497
  }
5273
5498
  ),
5274
- /* @__PURE__ */ jsx17(
5499
+ /* @__PURE__ */ jsx18(
5275
5500
  "circle",
5276
5501
  {
5277
5502
  cx: midX,
@@ -5287,7 +5512,7 @@ function PipeRendererImpl({
5287
5512
  )
5288
5513
  ] }, `${pipe.id}-segment-${idx}`);
5289
5514
  }) }),
5290
- pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ jsx17(
5515
+ pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ jsx18(
5291
5516
  "text",
5292
5517
  {
5293
5518
  x: pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x + (pipe.labelOffset?.x ?? 0),
@@ -5307,11 +5532,11 @@ function PipeRendererImpl({
5307
5532
  );
5308
5533
  }) });
5309
5534
  }
5310
- var PipeRenderer = React10.memo(PipeRendererImpl);
5535
+ var PipeRenderer = React11.memo(PipeRendererImpl);
5311
5536
 
5312
5537
  // src/components/PIDCanvas/DataOverlay.tsx
5313
- import React11 from "react";
5314
- import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
5538
+ import React12 from "react";
5539
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
5315
5540
  var PULSE_KEYFRAME_ID = "pid-data-overlay-pulse-keyframes";
5316
5541
  var PULSE_ANIMATION = "pid-data-overlay-pulse 1.5s ease-in-out infinite";
5317
5542
  function ensurePulseKeyframes() {
@@ -5322,9 +5547,10 @@ function ensurePulseKeyframes() {
5322
5547
  style.textContent = "@keyframes pid-data-overlay-pulse{0%{opacity:.9}50%{opacity:.3}100%{opacity:.9}}";
5323
5548
  document.head.appendChild(style);
5324
5549
  }
5325
- function renderStatusDot(cx, cy, scale, fill) {
5326
- ensurePulseKeyframes();
5327
- return /* @__PURE__ */ jsx18(
5550
+ function renderStatusDot(cx, cy, scale, fill, status) {
5551
+ const isUnknown = normalizeDeviceStatus(status) === "unknown";
5552
+ if (!isUnknown) ensurePulseKeyframes();
5553
+ return /* @__PURE__ */ jsx19(
5328
5554
  "circle",
5329
5555
  {
5330
5556
  className: "pid-data-overlay-status-dot",
@@ -5332,7 +5558,7 @@ function renderStatusDot(cx, cy, scale, fill) {
5332
5558
  cy: cy - 18 * scale,
5333
5559
  r: 3 * scale,
5334
5560
  fill,
5335
- style: { animation: PULSE_ANIMATION }
5561
+ style: isUnknown ? void 0 : { animation: PULSE_ANIMATION }
5336
5562
  }
5337
5563
  );
5338
5564
  }
@@ -5358,7 +5584,7 @@ function DataOverlayImpl({
5358
5584
  const backgroundColor = display?.backgroundColor;
5359
5585
  const offsetX = display?.offsetX ?? 0;
5360
5586
  const offsetY = display?.offsetY ?? 0;
5361
- const sparklinePath = React11.useMemo(() => {
5587
+ const sparklinePath = React12.useMemo(() => {
5362
5588
  if (!showSparkline || !history || history.length < 2) return "";
5363
5589
  const width = 70 * scale;
5364
5590
  const height = 20 * scale;
@@ -5377,7 +5603,7 @@ function DataOverlayImpl({
5377
5603
  return `M ${points.join(" L ")}`;
5378
5604
  }, [showSparkline, history, scaling, scale]);
5379
5605
  if (!showValue) {
5380
- return /* @__PURE__ */ jsx18(Fragment6, {});
5606
+ return /* @__PURE__ */ jsx19(Fragment6, {});
5381
5607
  }
5382
5608
  const formatValue = (val) => {
5383
5609
  if (typeof val === "number") {
@@ -5402,10 +5628,11 @@ function DataOverlayImpl({
5402
5628
  const extraMarkRows = realDisplayText ? 1 : 0;
5403
5629
  const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale + extraMarkRows * 9 * scale;
5404
5630
  const overlayWidth = 80 * scale;
5631
+ const isUnknownValue = normalizeDeviceStatus(value.status) === "unknown";
5405
5632
  const displayX = x + offsetX;
5406
5633
  const displayY = y + offsetY;
5407
- return /* @__PURE__ */ jsxs14("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
5408
- /* @__PURE__ */ jsx18(
5634
+ return /* @__PURE__ */ jsxs15("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
5635
+ /* @__PURE__ */ jsx19(
5409
5636
  "rect",
5410
5637
  {
5411
5638
  x: displayX - overlayWidth / 2,
@@ -5420,7 +5647,7 @@ function DataOverlayImpl({
5420
5647
  filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
5421
5648
  }
5422
5649
  ),
5423
- label && /* @__PURE__ */ jsx18(
5650
+ label && /* @__PURE__ */ jsx19(
5424
5651
  "text",
5425
5652
  {
5426
5653
  x: displayX,
@@ -5433,7 +5660,7 @@ function DataOverlayImpl({
5433
5660
  children: label
5434
5661
  }
5435
5662
  ),
5436
- /* @__PURE__ */ jsx18(
5663
+ /* @__PURE__ */ jsx19(
5437
5664
  "text",
5438
5665
  {
5439
5666
  x: displayX,
@@ -5446,8 +5673,17 @@ function DataOverlayImpl({
5446
5673
  children: displayText
5447
5674
  }
5448
5675
  ),
5449
- showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor),
5450
- value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs14(
5676
+ showStatus && value.status !== "normal" && renderStatusDot(displayX, displayY, scale, finalTextColor, value.status),
5677
+ showStatus && isUnknownValue && /* @__PURE__ */ jsx19(
5678
+ UnknownStatusGlyph,
5679
+ {
5680
+ x: displayX - overlayWidth / 2 + 2 * scale,
5681
+ y: displayY - 25 * scale - 6 * scale,
5682
+ width: 12 * scale,
5683
+ height: 12 * scale
5684
+ }
5685
+ ),
5686
+ value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs15(
5451
5687
  "text",
5452
5688
  {
5453
5689
  x: displayX,
@@ -5464,13 +5700,13 @@ function DataOverlayImpl({
5464
5700
  ]
5465
5701
  }
5466
5702
  ),
5467
- isForced && /* @__PURE__ */ jsxs14(
5703
+ isForced && /* @__PURE__ */ jsxs15(
5468
5704
  "g",
5469
5705
  {
5470
5706
  transform: `translate(${displayX + overlayWidth / 2}, ${displayY - 25 * scale})`,
5471
5707
  "aria-label": "Forced",
5472
5708
  children: [
5473
- /* @__PURE__ */ jsx18(
5709
+ /* @__PURE__ */ jsx19(
5474
5710
  "circle",
5475
5711
  {
5476
5712
  r: 7 * scale,
@@ -5479,7 +5715,7 @@ function DataOverlayImpl({
5479
5715
  strokeWidth: 1.5 * scale
5480
5716
  }
5481
5717
  ),
5482
- /* @__PURE__ */ jsx18(
5718
+ /* @__PURE__ */ jsx19(
5483
5719
  "text",
5484
5720
  {
5485
5721
  textAnchor: "middle",
@@ -5493,7 +5729,7 @@ function DataOverlayImpl({
5493
5729
  ]
5494
5730
  }
5495
5731
  ),
5496
- realDisplayText && /* @__PURE__ */ jsx18(
5732
+ realDisplayText && /* @__PURE__ */ jsx19(
5497
5733
  "text",
5498
5734
  {
5499
5735
  x: displayX,
@@ -5506,7 +5742,7 @@ function DataOverlayImpl({
5506
5742
  children: realDisplayText
5507
5743
  }
5508
5744
  ),
5509
- hasSparkline && /* @__PURE__ */ jsx18("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx18(
5745
+ hasSparkline && /* @__PURE__ */ jsx19("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx19(
5510
5746
  "path",
5511
5747
  {
5512
5748
  d: sparklinePath,
@@ -5520,11 +5756,11 @@ function DataOverlayImpl({
5520
5756
  ) })
5521
5757
  ] });
5522
5758
  }
5523
- var DataOverlay = React11.memo(DataOverlayImpl);
5759
+ var DataOverlay = React12.memo(DataOverlayImpl);
5524
5760
 
5525
5761
  // src/components/PIDCanvas/PositionPanel.tsx
5526
5762
  import { useState as useState9, useEffect as useEffect6 } from "react";
5527
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
5763
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
5528
5764
  function PositionPanel({
5529
5765
  selectedNode,
5530
5766
  selectedWaypoint,
@@ -5593,7 +5829,7 @@ function PositionPanel({
5593
5829
  "bottom-left": { bottom: 10, left: 10 },
5594
5830
  "bottom-right": { bottom: 10, right: 10 }
5595
5831
  };
5596
- return /* @__PURE__ */ jsxs15(
5832
+ return /* @__PURE__ */ jsxs16(
5597
5833
  "div",
5598
5834
  {
5599
5835
  style: {
@@ -5610,11 +5846,11 @@ function PositionPanel({
5610
5846
  fontSize: "13px"
5611
5847
  },
5612
5848
  children: [
5613
- /* @__PURE__ */ jsx19("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
5614
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
5615
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5616
- /* @__PURE__ */ jsx19("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
5617
- /* @__PURE__ */ jsx19(
5849
+ /* @__PURE__ */ jsx20("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
5850
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
5851
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5852
+ /* @__PURE__ */ jsx20("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
5853
+ /* @__PURE__ */ jsx20(
5618
5854
  "input",
5619
5855
  {
5620
5856
  type: "number",
@@ -5632,9 +5868,9 @@ function PositionPanel({
5632
5868
  }
5633
5869
  )
5634
5870
  ] }),
5635
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5636
- /* @__PURE__ */ jsx19("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
5637
- /* @__PURE__ */ jsx19(
5871
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
5872
+ /* @__PURE__ */ jsx20("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
5873
+ /* @__PURE__ */ jsx20(
5638
5874
  "input",
5639
5875
  {
5640
5876
  type: "number",
@@ -5653,7 +5889,7 @@ function PositionPanel({
5653
5889
  )
5654
5890
  ] })
5655
5891
  ] }),
5656
- /* @__PURE__ */ jsx19("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
5892
+ /* @__PURE__ */ jsx20("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
5657
5893
  ]
5658
5894
  }
5659
5895
  );
@@ -6248,8 +6484,13 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
6248
6484
  return "alarm";
6249
6485
  case "off":
6250
6486
  return "stopped";
6251
- default:
6487
+ case "unknown":
6488
+ return "unknown";
6489
+ default: {
6490
+ const exhaustive = telemetryStatus;
6491
+ void exhaustive;
6252
6492
  return "stopped";
6493
+ }
6253
6494
  }
6254
6495
  };
6255
6496
  const statusMapper = mapStatus || defaultMapStatus;
@@ -6689,7 +6930,7 @@ function nodeHasPort(node, portId) {
6689
6930
  }
6690
6931
 
6691
6932
  // src/components/PIDCanvas/PIDCanvas.tsx
6692
- import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
6933
+ import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
6693
6934
  var DEFAULT_FEATURES = {
6694
6935
  pan: true,
6695
6936
  zoom: true,
@@ -7302,7 +7543,7 @@ function PIDCanvasImpl({
7302
7543
  const viewBox = controlledViewBox;
7303
7544
  const displayDiagram = localDiagram;
7304
7545
  const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
7305
- return /* @__PURE__ */ jsxs16(
7546
+ return /* @__PURE__ */ jsxs17(
7306
7547
  "div",
7307
7548
  {
7308
7549
  ref: containerRef,
@@ -7317,7 +7558,7 @@ function PIDCanvasImpl({
7317
7558
  },
7318
7559
  ...props,
7319
7560
  children: [
7320
- /* @__PURE__ */ jsxs16(
7561
+ /* @__PURE__ */ jsxs17(
7321
7562
  "svg",
7322
7563
  {
7323
7564
  ref: svgRef,
@@ -7336,15 +7577,15 @@ function PIDCanvasImpl({
7336
7577
  onDrop: handleDrop,
7337
7578
  onDragLeave: handleDragLeave,
7338
7579
  children: [
7339
- features.showGrid !== false ? /* @__PURE__ */ jsxs16(Fragment7, { children: [
7340
- /* @__PURE__ */ jsxs16("defs", { children: [
7341
- /* @__PURE__ */ jsx20("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx20("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
7342
- /* @__PURE__ */ jsxs16("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
7343
- /* @__PURE__ */ jsx20("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
7344
- /* @__PURE__ */ jsx20("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
7580
+ features.showGrid !== false ? /* @__PURE__ */ jsxs17(Fragment7, { children: [
7581
+ /* @__PURE__ */ jsxs17("defs", { children: [
7582
+ /* @__PURE__ */ jsx21("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx21("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
7583
+ /* @__PURE__ */ jsxs17("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
7584
+ /* @__PURE__ */ jsx21("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
7585
+ /* @__PURE__ */ jsx21("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
7345
7586
  ] })
7346
7587
  ] }),
7347
- /* @__PURE__ */ jsx20(
7588
+ /* @__PURE__ */ jsx21(
7348
7589
  "rect",
7349
7590
  {
7350
7591
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7354,7 +7595,7 @@ function PIDCanvasImpl({
7354
7595
  fill: "url(#grid-major)"
7355
7596
  }
7356
7597
  )
7357
- ] }) : /* @__PURE__ */ jsx20(
7598
+ ] }) : /* @__PURE__ */ jsx21(
7358
7599
  "rect",
7359
7600
  {
7360
7601
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -7364,7 +7605,7 @@ function PIDCanvasImpl({
7364
7605
  fill: features.backgroundColor ?? "#ffffff"
7365
7606
  }
7366
7607
  ),
7367
- /* @__PURE__ */ jsx20(
7608
+ /* @__PURE__ */ jsx21(
7368
7609
  PipeRenderer,
7369
7610
  {
7370
7611
  pipes: displayDiagram.pipes,
@@ -7378,7 +7619,7 @@ function PIDCanvasImpl({
7378
7619
  onPipeSegmentClick: void 0
7379
7620
  }
7380
7621
  ),
7381
- /* @__PURE__ */ jsx20(
7622
+ /* @__PURE__ */ jsx21(
7382
7623
  NodeRenderer,
7383
7624
  {
7384
7625
  nodes: displayDiagram.nodes,
@@ -7392,7 +7633,7 @@ function PIDCanvasImpl({
7392
7633
  statusColorMap
7393
7634
  }
7394
7635
  ),
7395
- (features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx20(
7636
+ (features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx21(
7396
7637
  PipeRenderer,
7397
7638
  {
7398
7639
  pipes: displayDiagram.pipes,
@@ -7409,7 +7650,7 @@ function PIDCanvasImpl({
7409
7650
  onPipeSegmentClick: handlePipeSegmentClick
7410
7651
  }
7411
7652
  ),
7412
- telemetryEnabled && telemetry && /* @__PURE__ */ jsx20("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7653
+ telemetryEnabled && telemetry && /* @__PURE__ */ jsx21("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
7413
7654
  if (node.symbolId === "status-indicator") return null;
7414
7655
  const binding = telemetry.get(node.id);
7415
7656
  if (!binding) return null;
@@ -7417,7 +7658,7 @@ function PIDCanvasImpl({
7417
7658
  if (!symbol) return null;
7418
7659
  const overlayX = node.transform.x + symbol.viewBox.width / 2;
7419
7660
  const overlayY = node.transform.y + symbol.viewBox.height + 50;
7420
- return /* @__PURE__ */ jsx20(
7661
+ return /* @__PURE__ */ jsx21(
7421
7662
  DataOverlay,
7422
7663
  {
7423
7664
  nodeId: node.id,
@@ -7430,7 +7671,7 @@ function PIDCanvasImpl({
7430
7671
  `telemetry-${node.id}`
7431
7672
  );
7432
7673
  }) }),
7433
- dragOverPosition && /* @__PURE__ */ jsx20(
7674
+ dragOverPosition && /* @__PURE__ */ jsx21(
7434
7675
  "circle",
7435
7676
  {
7436
7677
  cx: dragOverPosition.x,
@@ -7443,7 +7684,7 @@ function PIDCanvasImpl({
7443
7684
  pointerEvents: "none"
7444
7685
  }
7445
7686
  ),
7446
- isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx20("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7687
+ isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx21("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
7447
7688
  const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
7448
7689
  if (!sourceNode) return null;
7449
7690
  const symbol = getSymbolDefinition(sourceNode.symbolId);
@@ -7459,8 +7700,8 @@ function PIDCanvasImpl({
7459
7700
  }
7460
7701
  }
7461
7702
  }
7462
- return /* @__PURE__ */ jsxs16(Fragment7, { children: [
7463
- /* @__PURE__ */ jsx20(
7703
+ return /* @__PURE__ */ jsxs17(Fragment7, { children: [
7704
+ /* @__PURE__ */ jsx21(
7464
7705
  "circle",
7465
7706
  {
7466
7707
  cx: lineStartX,
@@ -7472,7 +7713,7 @@ function PIDCanvasImpl({
7472
7713
  opacity: 0.6
7473
7714
  }
7474
7715
  ),
7475
- /* @__PURE__ */ jsx20(
7716
+ /* @__PURE__ */ jsx21(
7476
7717
  "line",
7477
7718
  {
7478
7719
  x1: lineStartX,
@@ -7485,7 +7726,7 @@ function PIDCanvasImpl({
7485
7726
  opacity: 0.8
7486
7727
  }
7487
7728
  ),
7488
- /* @__PURE__ */ jsx20(
7729
+ /* @__PURE__ */ jsx21(
7489
7730
  "circle",
7490
7731
  {
7491
7732
  cx: connectionCursor.x,
@@ -7497,7 +7738,7 @@ function PIDCanvasImpl({
7497
7738
  )
7498
7739
  ] });
7499
7740
  })() }),
7500
- features.connectionMode && /* @__PURE__ */ jsx20("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7741
+ features.connectionMode && /* @__PURE__ */ jsx21("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
7501
7742
  const symbol = getSymbolDefinition(node.symbolId);
7502
7743
  if (!symbol?.ports) return null;
7503
7744
  return symbol.ports.map((port) => {
@@ -7505,8 +7746,8 @@ function PIDCanvasImpl({
7505
7746
  if (!portPos) return null;
7506
7747
  const isHovered = hoveredPort === port.id && hoveredNode === node.id;
7507
7748
  const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
7508
- return /* @__PURE__ */ jsxs16("g", { children: [
7509
- /* @__PURE__ */ jsx20(
7749
+ return /* @__PURE__ */ jsxs17("g", { children: [
7750
+ /* @__PURE__ */ jsx21(
7510
7751
  "circle",
7511
7752
  {
7512
7753
  cx: portPos.x,
@@ -7539,7 +7780,7 @@ function PIDCanvasImpl({
7539
7780
  }
7540
7781
  }
7541
7782
  ),
7542
- /* @__PURE__ */ jsx20(
7783
+ /* @__PURE__ */ jsx21(
7543
7784
  "circle",
7544
7785
  {
7545
7786
  cx: portPos.x,
@@ -7558,7 +7799,7 @@ function PIDCanvasImpl({
7558
7799
  ]
7559
7800
  }
7560
7801
  ),
7561
- features.dragNodes && /* @__PURE__ */ jsx20(
7802
+ features.dragNodes && /* @__PURE__ */ jsx21(
7562
7803
  PositionPanel,
7563
7804
  {
7564
7805
  selectedNode,
@@ -7576,11 +7817,11 @@ function PIDCanvasImpl({
7576
7817
  }
7577
7818
  );
7578
7819
  }
7579
- var PIDCanvas = React13.memo(PIDCanvasImpl);
7820
+ var PIDCanvas = React14.memo(PIDCanvasImpl);
7580
7821
 
7581
7822
  // src/components/SymbolLibrary/SymbolLibrary.tsx
7582
7823
  import { useState as useState15 } from "react";
7583
- import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
7824
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
7584
7825
  function SymbolLibrary({
7585
7826
  className = "",
7586
7827
  onSymbolDragStart,
@@ -7609,9 +7850,9 @@ function SymbolLibrary({
7609
7850
  event.dataTransfer.effectAllowed = "copy";
7610
7851
  onSymbolDragStart?.(symbol.id, event);
7611
7852
  };
7612
- return /* @__PURE__ */ jsxs17("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
7613
- /* @__PURE__ */ jsx21("div", { style: styles.header, children: /* @__PURE__ */ jsx21("h3", { style: styles.title, children: "Symbol Library" }) }),
7614
- /* @__PURE__ */ jsx21("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx21(
7853
+ return /* @__PURE__ */ jsxs18("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
7854
+ /* @__PURE__ */ jsx22("div", { style: styles.header, children: /* @__PURE__ */ jsx22("h3", { style: styles.title, children: "Symbol Library" }) }),
7855
+ /* @__PURE__ */ jsx22("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx22(
7615
7856
  "input",
7616
7857
  {
7617
7858
  type: "text",
@@ -7621,8 +7862,8 @@ function SymbolLibrary({
7621
7862
  style: styles.searchInput
7622
7863
  }
7623
7864
  ) }),
7624
- showCategories && /* @__PURE__ */ jsxs17("div", { style: styles.categories, children: [
7625
- /* @__PURE__ */ jsx21(
7865
+ showCategories && /* @__PURE__ */ jsxs18("div", { style: styles.categories, children: [
7866
+ /* @__PURE__ */ jsx22(
7626
7867
  "button",
7627
7868
  {
7628
7869
  onClick: () => setSelectedCategory("all"),
@@ -7633,7 +7874,7 @@ function SymbolLibrary({
7633
7874
  children: "All"
7634
7875
  }
7635
7876
  ),
7636
- categories.map((category) => /* @__PURE__ */ jsx21(
7877
+ categories.map((category) => /* @__PURE__ */ jsx22(
7637
7878
  "button",
7638
7879
  {
7639
7880
  onClick: () => setSelectedCategory(category),
@@ -7646,7 +7887,7 @@ function SymbolLibrary({
7646
7887
  category
7647
7888
  ))
7648
7889
  ] }),
7649
- /* @__PURE__ */ jsx21("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx21("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs17(
7890
+ /* @__PURE__ */ jsx22("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx22("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs18(
7650
7891
  "div",
7651
7892
  {
7652
7893
  draggable: true,
@@ -7654,15 +7895,15 @@ function SymbolLibrary({
7654
7895
  style: styles.symbolCard,
7655
7896
  title: symbol.metadata?.description || symbol.name,
7656
7897
  children: [
7657
- /* @__PURE__ */ jsx21("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx21(
7898
+ /* @__PURE__ */ jsx22("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx22(
7658
7899
  "svg",
7659
7900
  {
7660
7901
  viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
7661
7902
  style: styles.symbolSvg,
7662
- children: /* @__PURE__ */ jsx21("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
7903
+ children: /* @__PURE__ */ jsx22("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
7663
7904
  }
7664
7905
  ) }),
7665
- /* @__PURE__ */ jsx21("div", { style: styles.symbolName, children: symbol.name })
7906
+ /* @__PURE__ */ jsx22("div", { style: styles.symbolName, children: symbol.name })
7666
7907
  ]
7667
7908
  },
7668
7909
  symbol.id
@@ -7771,7 +8012,7 @@ var styles = {
7771
8012
  };
7772
8013
 
7773
8014
  // src/components/NodeConfigPanel/NodeConfigPanel.tsx
7774
- import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
8015
+ import { Fragment as Fragment8, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
7775
8016
  function NodeConfigPanel({
7776
8017
  node,
7777
8018
  binding,
@@ -7794,15 +8035,15 @@ function NodeConfigPanel({
7794
8035
  };
7795
8036
  const appearanceFields = getAppearanceSchema(node.symbolId);
7796
8037
  const showGenericTelemetry = appearanceFields.length === 0;
7797
- return /* @__PURE__ */ jsxs18("div", { className, style: defaultStyle, children: [
7798
- /* @__PURE__ */ jsxs18("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
8038
+ return /* @__PURE__ */ jsxs19("div", { className, style: defaultStyle, children: [
8039
+ /* @__PURE__ */ jsxs19("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
7799
8040
  "Configure: ",
7800
8041
  node.id
7801
8042
  ] }),
7802
- /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
7803
- /* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
7804
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
7805
- /* @__PURE__ */ jsx22(
8043
+ /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "20px" }, children: [
8044
+ /* @__PURE__ */ jsx23("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
8045
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
8046
+ /* @__PURE__ */ jsx23(
7806
8047
  "input",
7807
8048
  {
7808
8049
  type: "text",
@@ -7818,10 +8059,10 @@ function NodeConfigPanel({
7818
8059
  }
7819
8060
  }
7820
8061
  ),
7821
- /* @__PURE__ */ jsxs18("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
7822
- /* @__PURE__ */ jsxs18("div", { children: [
7823
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
7824
- /* @__PURE__ */ jsx22(
8062
+ /* @__PURE__ */ jsxs19("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8063
+ /* @__PURE__ */ jsxs19("div", { children: [
8064
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
8065
+ /* @__PURE__ */ jsx23(
7825
8066
  "input",
7826
8067
  {
7827
8068
  type: "number",
@@ -7842,9 +8083,9 @@ function NodeConfigPanel({
7842
8083
  }
7843
8084
  )
7844
8085
  ] }),
7845
- /* @__PURE__ */ jsxs18("div", { children: [
7846
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
7847
- /* @__PURE__ */ jsx22(
8086
+ /* @__PURE__ */ jsxs19("div", { children: [
8087
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
8088
+ /* @__PURE__ */ jsx23(
7848
8089
  "input",
7849
8090
  {
7850
8091
  type: "number",
@@ -7866,9 +8107,9 @@ function NodeConfigPanel({
7866
8107
  )
7867
8108
  ] })
7868
8109
  ] }),
7869
- /* @__PURE__ */ jsxs18("div", { children: [
7870
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
7871
- /* @__PURE__ */ jsx22(
8110
+ /* @__PURE__ */ jsxs19("div", { children: [
8111
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
8112
+ /* @__PURE__ */ jsx23(
7872
8113
  "input",
7873
8114
  {
7874
8115
  type: "number",
@@ -7888,9 +8129,9 @@ function NodeConfigPanel({
7888
8129
  }
7889
8130
  )
7890
8131
  ] }),
7891
- /* @__PURE__ */ jsxs18("div", { children: [
7892
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
7893
- /* @__PURE__ */ jsx22(
8132
+ /* @__PURE__ */ jsxs19("div", { children: [
8133
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
8134
+ /* @__PURE__ */ jsx23(
7894
8135
  "input",
7895
8136
  {
7896
8137
  type: "number",
@@ -7915,8 +8156,8 @@ function NodeConfigPanel({
7915
8156
  )
7916
8157
  ] })
7917
8158
  ] }),
7918
- appearanceFields.length > 0 && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
7919
- /* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
8159
+ appearanceFields.length > 0 && /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "20px" }, children: [
8160
+ /* @__PURE__ */ jsx23("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
7920
8161
  appearanceFields.map((field) => {
7921
8162
  const value = readAppearanceValue(node, field);
7922
8163
  const fieldLabel = field.label ?? field.key;
@@ -7929,8 +8170,8 @@ function NodeConfigPanel({
7929
8170
  };
7930
8171
  let control;
7931
8172
  if (field.kind === "boolean") {
7932
- control = /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
7933
- /* @__PURE__ */ jsx22(
8173
+ control = /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
8174
+ /* @__PURE__ */ jsx23(
7934
8175
  "input",
7935
8176
  {
7936
8177
  type: "checkbox",
@@ -7942,28 +8183,28 @@ function NodeConfigPanel({
7942
8183
  fieldLabel
7943
8184
  ] });
7944
8185
  } else if (field.kind === "select") {
7945
- control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
7946
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8186
+ control = /* @__PURE__ */ jsxs19(Fragment8, { children: [
8187
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
7947
8188
  fieldLabel,
7948
8189
  ":"
7949
8190
  ] }),
7950
- /* @__PURE__ */ jsx22(
8191
+ /* @__PURE__ */ jsx23(
7951
8192
  "select",
7952
8193
  {
7953
8194
  value: String(value),
7954
8195
  onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
7955
8196
  style: inputStyle,
7956
- children: field.options?.map((opt) => /* @__PURE__ */ jsx22("option", { value: opt, children: opt }, opt))
8197
+ children: field.options?.map((opt) => /* @__PURE__ */ jsx23("option", { value: opt, children: opt }, opt))
7957
8198
  }
7958
8199
  )
7959
8200
  ] });
7960
8201
  } else if (field.kind === "number") {
7961
- control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
7962
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8202
+ control = /* @__PURE__ */ jsxs19(Fragment8, { children: [
8203
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
7963
8204
  fieldLabel,
7964
8205
  ":"
7965
8206
  ] }),
7966
- /* @__PURE__ */ jsx22(
8207
+ /* @__PURE__ */ jsx23(
7967
8208
  "input",
7968
8209
  {
7969
8210
  type: "number",
@@ -7978,12 +8219,12 @@ function NodeConfigPanel({
7978
8219
  const listId = `tags-${node.id}-${field.key}`;
7979
8220
  const known = tagValue.length > 0 && availableTags.includes(tagValue);
7980
8221
  const unknown = tagValue.length > 0 && !known;
7981
- control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
7982
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8222
+ control = /* @__PURE__ */ jsxs19(Fragment8, { children: [
8223
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
7983
8224
  fieldLabel,
7984
8225
  ":"
7985
8226
  ] }),
7986
- /* @__PURE__ */ jsx22(
8227
+ /* @__PURE__ */ jsx23(
7987
8228
  "input",
7988
8229
  {
7989
8230
  type: "text",
@@ -7997,8 +8238,8 @@ function NodeConfigPanel({
7997
8238
  }
7998
8239
  }
7999
8240
  ),
8000
- /* @__PURE__ */ jsx22("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ jsx22("option", { value: t }, t)) }),
8001
- tagValue.length > 0 && /* @__PURE__ */ jsx22(
8241
+ /* @__PURE__ */ jsx23("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ jsx23("option", { value: t }, t)) }),
8242
+ tagValue.length > 0 && /* @__PURE__ */ jsx23(
8002
8243
  "div",
8003
8244
  {
8004
8245
  style: {
@@ -8011,12 +8252,12 @@ function NodeConfigPanel({
8011
8252
  )
8012
8253
  ] });
8013
8254
  } else {
8014
- control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
8015
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8255
+ control = /* @__PURE__ */ jsxs19(Fragment8, { children: [
8256
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8016
8257
  fieldLabel,
8017
8258
  ":"
8018
8259
  ] }),
8019
- /* @__PURE__ */ jsx22(
8260
+ /* @__PURE__ */ jsx23(
8020
8261
  "input",
8021
8262
  {
8022
8263
  type: "text",
@@ -8027,9 +8268,9 @@ function NodeConfigPanel({
8027
8268
  )
8028
8269
  ] });
8029
8270
  }
8030
- return /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "10px" }, children: [
8271
+ return /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "10px" }, children: [
8031
8272
  control,
8032
- field.help && /* @__PURE__ */ jsx22(
8273
+ field.help && /* @__PURE__ */ jsx23(
8033
8274
  "div",
8034
8275
  {
8035
8276
  style: {
@@ -8044,9 +8285,9 @@ function NodeConfigPanel({
8044
8285
  ] }, field.key);
8045
8286
  })
8046
8287
  ] }),
8047
- showGenericTelemetry && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
8048
- /* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
8049
- !binding ? /* @__PURE__ */ jsx22(
8288
+ showGenericTelemetry && /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "20px" }, children: [
8289
+ /* @__PURE__ */ jsx23("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
8290
+ !binding ? /* @__PURE__ */ jsx23(
8050
8291
  "button",
8051
8292
  {
8052
8293
  onClick: () => {
@@ -8089,9 +8330,9 @@ function NodeConfigPanel({
8089
8330
  },
8090
8331
  children: "+ Add Telemetry"
8091
8332
  }
8092
- ) : /* @__PURE__ */ jsxs18(Fragment8, { children: [
8093
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
8094
- /* @__PURE__ */ jsx22(
8333
+ ) : /* @__PURE__ */ jsxs19(Fragment8, { children: [
8334
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
8335
+ /* @__PURE__ */ jsx23(
8095
8336
  "input",
8096
8337
  {
8097
8338
  type: "text",
@@ -8111,8 +8352,8 @@ function NodeConfigPanel({
8111
8352
  }
8112
8353
  }
8113
8354
  ),
8114
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
8115
- /* @__PURE__ */ jsx22(
8355
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
8356
+ /* @__PURE__ */ jsx23(
8116
8357
  "input",
8117
8358
  {
8118
8359
  type: "number",
@@ -8134,8 +8375,8 @@ function NodeConfigPanel({
8134
8375
  }
8135
8376
  }
8136
8377
  ),
8137
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
8138
- /* @__PURE__ */ jsx22(
8378
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
8379
+ /* @__PURE__ */ jsx23(
8139
8380
  "input",
8140
8381
  {
8141
8382
  type: "text",
@@ -8157,8 +8398,8 @@ function NodeConfigPanel({
8157
8398
  }
8158
8399
  }
8159
8400
  ),
8160
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8161
- /* @__PURE__ */ jsx22(
8401
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8402
+ /* @__PURE__ */ jsx23(
8162
8403
  "input",
8163
8404
  {
8164
8405
  type: "checkbox",
@@ -8180,8 +8421,8 @@ function NodeConfigPanel({
8180
8421
  ),
8181
8422
  "Show Sparkline"
8182
8423
  ] }),
8183
- /* @__PURE__ */ jsxs18("div", { style: { marginTop: "12px" }, children: [
8184
- /* @__PURE__ */ jsx22(
8424
+ /* @__PURE__ */ jsxs19("div", { style: { marginTop: "12px" }, children: [
8425
+ /* @__PURE__ */ jsx23(
8185
8426
  "label",
8186
8427
  {
8187
8428
  style: {
@@ -8193,10 +8434,10 @@ function NodeConfigPanel({
8193
8434
  children: "Telemetry Position Offset:"
8194
8435
  }
8195
8436
  ),
8196
- /* @__PURE__ */ jsxs18("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8197
- /* @__PURE__ */ jsxs18("div", { children: [
8198
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
8199
- /* @__PURE__ */ jsx22(
8437
+ /* @__PURE__ */ jsxs19("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
8438
+ /* @__PURE__ */ jsxs19("div", { children: [
8439
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
8440
+ /* @__PURE__ */ jsx23(
8200
8441
  "input",
8201
8442
  {
8202
8443
  type: "number",
@@ -8223,9 +8464,9 @@ function NodeConfigPanel({
8223
8464
  }
8224
8465
  )
8225
8466
  ] }),
8226
- /* @__PURE__ */ jsxs18("div", { children: [
8227
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
8228
- /* @__PURE__ */ jsx22(
8467
+ /* @__PURE__ */ jsxs19("div", { children: [
8468
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
8469
+ /* @__PURE__ */ jsx23(
8229
8470
  "input",
8230
8471
  {
8231
8472
  type: "number",
@@ -8253,8 +8494,8 @@ function NodeConfigPanel({
8253
8494
  )
8254
8495
  ] })
8255
8496
  ] }),
8256
- /* @__PURE__ */ jsxs18("div", { style: { marginTop: "16px" }, children: [
8257
- /* @__PURE__ */ jsx22(
8497
+ /* @__PURE__ */ jsxs19("div", { style: { marginTop: "16px" }, children: [
8498
+ /* @__PURE__ */ jsx23(
8258
8499
  "label",
8259
8500
  {
8260
8501
  style: {
@@ -8266,10 +8507,10 @@ function NodeConfigPanel({
8266
8507
  children: "Display Colors:"
8267
8508
  }
8268
8509
  ),
8269
- /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "8px" }, children: [
8270
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
8271
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8272
- /* @__PURE__ */ jsx22(
8510
+ /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "8px" }, children: [
8511
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
8512
+ /* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8513
+ /* @__PURE__ */ jsx23(
8273
8514
  "input",
8274
8515
  {
8275
8516
  type: "color",
@@ -8295,7 +8536,7 @@ function NodeConfigPanel({
8295
8536
  }
8296
8537
  }
8297
8538
  ),
8298
- /* @__PURE__ */ jsx22(
8539
+ /* @__PURE__ */ jsx23(
8299
8540
  "input",
8300
8541
  {
8301
8542
  type: "text",
@@ -8325,10 +8566,10 @@ function NodeConfigPanel({
8325
8566
  )
8326
8567
  ] })
8327
8568
  ] }),
8328
- binding.display?.showSparkline && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "8px" }, children: [
8329
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
8330
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8331
- /* @__PURE__ */ jsx22(
8569
+ binding.display?.showSparkline && /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "8px" }, children: [
8570
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
8571
+ /* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8572
+ /* @__PURE__ */ jsx23(
8332
8573
  "input",
8333
8574
  {
8334
8575
  type: "color",
@@ -8354,7 +8595,7 @@ function NodeConfigPanel({
8354
8595
  }
8355
8596
  }
8356
8597
  ),
8357
- /* @__PURE__ */ jsx22(
8598
+ /* @__PURE__ */ jsx23(
8358
8599
  "input",
8359
8600
  {
8360
8601
  type: "text",
@@ -8384,9 +8625,9 @@ function NodeConfigPanel({
8384
8625
  )
8385
8626
  ] })
8386
8627
  ] }),
8387
- /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "8px" }, children: [
8388
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
8389
- /* @__PURE__ */ jsx22(
8628
+ /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "8px" }, children: [
8629
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
8630
+ /* @__PURE__ */ jsx23(
8390
8631
  "input",
8391
8632
  {
8392
8633
  type: "text",
@@ -8414,12 +8655,12 @@ function NodeConfigPanel({
8414
8655
  }
8415
8656
  }
8416
8657
  ),
8417
- /* @__PURE__ */ jsx22("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
8658
+ /* @__PURE__ */ jsx23("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
8418
8659
  ] })
8419
8660
  ] }),
8420
8661
  " "
8421
8662
  ] }),
8422
- onRemoveTelemetry && /* @__PURE__ */ jsx22(
8663
+ onRemoveTelemetry && /* @__PURE__ */ jsx23(
8423
8664
  "button",
8424
8665
  {
8425
8666
  onClick: onRemoveTelemetry,
@@ -8439,13 +8680,13 @@ function NodeConfigPanel({
8439
8680
  )
8440
8681
  ] })
8441
8682
  ] }),
8442
- showGenericTelemetry && binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
8443
- /* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
8683
+ showGenericTelemetry && binding && /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "20px" }, children: [
8684
+ /* @__PURE__ */ jsx23("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
8444
8685
  ["highHigh", "high", "low", "lowLow"].map((key) => {
8445
8686
  const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
8446
- return /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "8px" }, children: [
8447
- /* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
8448
- /* @__PURE__ */ jsx22(
8687
+ return /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "8px" }, children: [
8688
+ /* @__PURE__ */ jsx23("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
8689
+ /* @__PURE__ */ jsx23(
8449
8690
  "input",
8450
8691
  {
8451
8692
  type: "number",
@@ -8469,8 +8710,8 @@ function NodeConfigPanel({
8469
8710
  ] }, key);
8470
8711
  })
8471
8712
  ] }),
8472
- showGenericTelemetry && binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
8473
- /* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
8713
+ showGenericTelemetry && binding && /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "20px" }, children: [
8714
+ /* @__PURE__ */ jsx23("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
8474
8715
  ["normal", "warning", "alarm", "fault", "off"].map((status) => {
8475
8716
  const defaultColors = {
8476
8717
  normal: "#10b981",
@@ -8480,13 +8721,13 @@ function NodeConfigPanel({
8480
8721
  off: "#6b7280"
8481
8722
  };
8482
8723
  const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
8483
- return /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "8px" }, children: [
8484
- /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8724
+ return /* @__PURE__ */ jsxs19("div", { style: { marginBottom: "8px" }, children: [
8725
+ /* @__PURE__ */ jsxs19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
8485
8726
  label,
8486
8727
  ":"
8487
8728
  ] }),
8488
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8489
- /* @__PURE__ */ jsx22(
8729
+ /* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
8730
+ /* @__PURE__ */ jsx23(
8490
8731
  "input",
8491
8732
  {
8492
8733
  type: "color",
@@ -8507,7 +8748,7 @@ function NodeConfigPanel({
8507
8748
  }
8508
8749
  }
8509
8750
  ),
8510
- /* @__PURE__ */ jsx22(
8751
+ /* @__PURE__ */ jsx23(
8511
8752
  "input",
8512
8753
  {
8513
8754
  type: "text",
@@ -8534,7 +8775,7 @@ function NodeConfigPanel({
8534
8775
  ] }, status);
8535
8776
  })
8536
8777
  ] }),
8537
- /* @__PURE__ */ jsx22("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx22(
8778
+ /* @__PURE__ */ jsx23("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx23(
8538
8779
  "button",
8539
8780
  {
8540
8781
  onClick: onRemove,
@@ -9328,8 +9569,8 @@ function useDeviceConfigs(initialConfigs) {
9328
9569
  }
9329
9570
 
9330
9571
  // src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
9331
- import React15, { useState as useState18, useEffect as useEffect14, useMemo, useRef as useRef8 } from "react";
9332
- import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
9572
+ import React16, { useState as useState18, useEffect as useEffect14, useMemo, useRef as useRef8 } from "react";
9573
+ import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
9333
9574
  function DeviceConfigPanelImpl({
9334
9575
  binding,
9335
9576
  onClose,
@@ -9495,14 +9736,14 @@ function DeviceConfigPanelImpl({
9495
9736
  const value = localValues[param.id];
9496
9737
  const error = binding.state.errors?.[param.id];
9497
9738
  const isDisabled = param.readOnly || param.enabled === false;
9498
- return /* @__PURE__ */ jsxs19(
9739
+ return /* @__PURE__ */ jsxs20(
9499
9740
  "div",
9500
9741
  {
9501
9742
  style: {
9502
9743
  marginBottom: spacing.marginBottom
9503
9744
  },
9504
9745
  children: [
9505
- /* @__PURE__ */ jsxs19(
9746
+ /* @__PURE__ */ jsxs20(
9506
9747
  "label",
9507
9748
  {
9508
9749
  style: {
@@ -9517,13 +9758,13 @@ function DeviceConfigPanelImpl({
9517
9758
  },
9518
9759
  children: [
9519
9760
  param.label,
9520
- param.required && /* @__PURE__ */ jsx23("span", { style: { color: errorColor }, children: " *" }),
9521
- param.unit && /* @__PURE__ */ jsxs19("span", { style: { color: mutedTextColor, fontWeight: "normal" }, children: [
9761
+ param.required && /* @__PURE__ */ jsx24("span", { style: { color: errorColor }, children: " *" }),
9762
+ param.unit && /* @__PURE__ */ jsxs20("span", { style: { color: mutedTextColor, fontWeight: "normal" }, children: [
9522
9763
  " (",
9523
9764
  param.unit,
9524
9765
  ")"
9525
9766
  ] }),
9526
- param.forced?.active && /* @__PURE__ */ jsx23(
9767
+ param.forced?.active && /* @__PURE__ */ jsx24(
9527
9768
  "span",
9528
9769
  {
9529
9770
  "aria-label": "Forced",
@@ -9550,7 +9791,7 @@ function DeviceConfigPanelImpl({
9550
9791
  ]
9551
9792
  }
9552
9793
  ),
9553
- param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs19(
9794
+ param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs20(
9554
9795
  "div",
9555
9796
  {
9556
9797
  style: {
@@ -9568,7 +9809,7 @@ function DeviceConfigPanelImpl({
9568
9809
  ]
9569
9810
  }
9570
9811
  ),
9571
- param.description && /* @__PURE__ */ jsx23(
9812
+ param.description && /* @__PURE__ */ jsx24(
9572
9813
  "div",
9573
9814
  {
9574
9815
  style: {
@@ -9580,7 +9821,7 @@ function DeviceConfigPanelImpl({
9580
9821
  children: param.description
9581
9822
  }
9582
9823
  ),
9583
- param.type === "number" && /* @__PURE__ */ jsx23(
9824
+ param.type === "number" && /* @__PURE__ */ jsx24(
9584
9825
  "input",
9585
9826
  {
9586
9827
  type: "number",
@@ -9604,7 +9845,7 @@ function DeviceConfigPanelImpl({
9604
9845
  }
9605
9846
  }
9606
9847
  ),
9607
- param.type === "string" && /* @__PURE__ */ jsx23(
9848
+ param.type === "string" && /* @__PURE__ */ jsx24(
9608
9849
  "input",
9609
9850
  {
9610
9851
  type: "text",
@@ -9625,7 +9866,7 @@ function DeviceConfigPanelImpl({
9625
9866
  }
9626
9867
  }
9627
9868
  ),
9628
- param.type === "boolean" && /* @__PURE__ */ jsxs19(
9869
+ param.type === "boolean" && /* @__PURE__ */ jsxs20(
9629
9870
  "label",
9630
9871
  {
9631
9872
  style: {
@@ -9635,7 +9876,7 @@ function DeviceConfigPanelImpl({
9635
9876
  cursor: isDisabled ? "not-allowed" : "pointer"
9636
9877
  },
9637
9878
  children: [
9638
- /* @__PURE__ */ jsx23(
9879
+ /* @__PURE__ */ jsx24(
9639
9880
  "input",
9640
9881
  {
9641
9882
  type: "checkbox",
@@ -9649,11 +9890,11 @@ function DeviceConfigPanelImpl({
9649
9890
  }
9650
9891
  }
9651
9892
  ),
9652
- /* @__PURE__ */ jsx23("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
9893
+ /* @__PURE__ */ jsx24("span", { style: { fontSize: `${fontSize.value}px`, color: textColor }, children: value ? "Enabled" : "Disabled" })
9653
9894
  ]
9654
9895
  }
9655
9896
  ),
9656
- param.type === "select" && /* @__PURE__ */ jsx23(
9897
+ param.type === "select" && /* @__PURE__ */ jsx24(
9657
9898
  "select",
9658
9899
  {
9659
9900
  value: value ?? "",
@@ -9671,10 +9912,10 @@ function DeviceConfigPanelImpl({
9671
9912
  borderRadius: "2px",
9672
9913
  outline: "none"
9673
9914
  },
9674
- children: param.options?.map((option) => /* @__PURE__ */ jsx23("option", { value: option.value, children: option.label }, option.value))
9915
+ children: param.options?.map((option) => /* @__PURE__ */ jsx24("option", { value: option.value, children: option.label }, option.value))
9675
9916
  }
9676
9917
  ),
9677
- error && /* @__PURE__ */ jsx23(
9918
+ error && /* @__PURE__ */ jsx24(
9678
9919
  "div",
9679
9920
  {
9680
9921
  style: {
@@ -9694,7 +9935,7 @@ function DeviceConfigPanelImpl({
9694
9935
  const renderSection = (section) => {
9695
9936
  const params = parametersBySection[section.id] || [];
9696
9937
  const isCollapsed = collapsedSections.has(section.id);
9697
- return /* @__PURE__ */ jsxs19(
9938
+ return /* @__PURE__ */ jsxs20(
9698
9939
  "div",
9699
9940
  {
9700
9941
  style: {
@@ -9704,7 +9945,7 @@ function DeviceConfigPanelImpl({
9704
9945
  backgroundColor: surfaceColor
9705
9946
  },
9706
9947
  children: [
9707
- /* @__PURE__ */ jsxs19(
9948
+ /* @__PURE__ */ jsxs20(
9708
9949
  "div",
9709
9950
  {
9710
9951
  onClick: () => section.collapsible && toggleSection(section.id),
@@ -9717,8 +9958,8 @@ function DeviceConfigPanelImpl({
9717
9958
  alignItems: "center"
9718
9959
  },
9719
9960
  children: [
9720
- /* @__PURE__ */ jsxs19("div", { children: [
9721
- /* @__PURE__ */ jsxs19(
9961
+ /* @__PURE__ */ jsxs20("div", { children: [
9962
+ /* @__PURE__ */ jsxs20(
9722
9963
  "div",
9723
9964
  {
9724
9965
  style: {
@@ -9730,12 +9971,12 @@ function DeviceConfigPanelImpl({
9730
9971
  letterSpacing: "0.5px"
9731
9972
  },
9732
9973
  children: [
9733
- section.icon && /* @__PURE__ */ jsx23("span", { style: { marginRight: "8px" }, children: section.icon }),
9974
+ section.icon && /* @__PURE__ */ jsx24("span", { style: { marginRight: "8px" }, children: section.icon }),
9734
9975
  section.title
9735
9976
  ]
9736
9977
  }
9737
9978
  ),
9738
- section.description && /* @__PURE__ */ jsx23(
9979
+ section.description && /* @__PURE__ */ jsx24(
9739
9980
  "div",
9740
9981
  {
9741
9982
  style: {
@@ -9748,11 +9989,11 @@ function DeviceConfigPanelImpl({
9748
9989
  }
9749
9990
  )
9750
9991
  ] }),
9751
- section.collapsible && /* @__PURE__ */ jsx23("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
9992
+ section.collapsible && /* @__PURE__ */ jsx24("span", { style: { fontSize: "16px", color: mutedTextColor }, children: isCollapsed ? "\u25BC" : "\u25B2" })
9752
9993
  ]
9753
9994
  }
9754
9995
  ),
9755
- !isCollapsed && /* @__PURE__ */ jsx23("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
9996
+ !isCollapsed && /* @__PURE__ */ jsx24("div", { style: { padding: spacing.padding }, children: params.map(renderParameter) })
9756
9997
  ]
9757
9998
  },
9758
9999
  section.id
@@ -9811,9 +10052,9 @@ function DeviceConfigPanelImpl({
9811
10052
  const showSave = binding.display?.showSave !== false && binding.actions.onSave;
9812
10053
  const showReset = binding.display?.showReset !== false && binding.actions.onReset;
9813
10054
  const showCancel = binding.display?.showCancel !== false;
9814
- return /* @__PURE__ */ jsxs19(Fragment9, { children: [
9815
- /* @__PURE__ */ jsxs19("div", { style: panelStyle, className: binding.display?.className, children: [
9816
- /* @__PURE__ */ jsxs19(
10055
+ return /* @__PURE__ */ jsxs20(Fragment9, { children: [
10056
+ /* @__PURE__ */ jsxs20("div", { style: panelStyle, className: binding.display?.className, children: [
10057
+ /* @__PURE__ */ jsxs20(
9817
10058
  "div",
9818
10059
  {
9819
10060
  style: {
@@ -9825,8 +10066,8 @@ function DeviceConfigPanelImpl({
9825
10066
  borderBottom: `2px solid ${borderColor}`
9826
10067
  },
9827
10068
  children: [
9828
- /* @__PURE__ */ jsxs19("div", { children: [
9829
- /* @__PURE__ */ jsx23(
10069
+ /* @__PURE__ */ jsxs20("div", { children: [
10070
+ /* @__PURE__ */ jsx24(
9830
10071
  "h3",
9831
10072
  {
9832
10073
  style: {
@@ -9846,7 +10087,7 @@ function DeviceConfigPanelImpl({
9846
10087
  children: titleText.length > 25 ? titleText.slice(0, 25) + "..." : titleText
9847
10088
  }
9848
10089
  ),
9849
- binding.display?.subtitle && /* @__PURE__ */ jsx23(
10090
+ binding.display?.subtitle && /* @__PURE__ */ jsx24(
9850
10091
  "div",
9851
10092
  {
9852
10093
  style: {
@@ -9859,8 +10100,8 @@ function DeviceConfigPanelImpl({
9859
10100
  }
9860
10101
  )
9861
10102
  ] }),
9862
- /* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: "8px" }, children: [
9863
- showControlsButton && onOpenControls && /* @__PURE__ */ jsx23(
10103
+ /* @__PURE__ */ jsxs20("div", { style: { display: "flex", gap: "8px" }, children: [
10104
+ showControlsButton && onOpenControls && /* @__PURE__ */ jsx24(
9864
10105
  "button",
9865
10106
  {
9866
10107
  onClick: onOpenControls,
@@ -9883,7 +10124,7 @@ function DeviceConfigPanelImpl({
9883
10124
  children: "CTRL"
9884
10125
  }
9885
10126
  ),
9886
- onUndock && /* @__PURE__ */ jsx23(
10127
+ onUndock && /* @__PURE__ */ jsx24(
9887
10128
  "button",
9888
10129
  {
9889
10130
  onClick: onUndock,
@@ -9904,7 +10145,7 @@ function DeviceConfigPanelImpl({
9904
10145
  children: undockIcon
9905
10146
  }
9906
10147
  ),
9907
- /* @__PURE__ */ jsx23(
10148
+ /* @__PURE__ */ jsx24(
9908
10149
  "button",
9909
10150
  {
9910
10151
  onClick: onClose,
@@ -9927,7 +10168,7 @@ function DeviceConfigPanelImpl({
9927
10168
  ]
9928
10169
  }
9929
10170
  ),
9930
- binding.state.isDirty && /* @__PURE__ */ jsx23(
10171
+ binding.state.isDirty && /* @__PURE__ */ jsx24(
9931
10172
  "div",
9932
10173
  {
9933
10174
  style: {
@@ -9942,11 +10183,11 @@ function DeviceConfigPanelImpl({
9942
10183
  children: "Unsaved changes"
9943
10184
  }
9944
10185
  ),
9945
- /* @__PURE__ */ jsx23("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
10186
+ /* @__PURE__ */ jsx24("div", { style: { flex: 1, overflowY: "auto", marginBottom: spacing.marginBottom }, children: sortedSections.length > 0 ? sortedSections.map(renderSection) : (
9946
10187
  /* Render unsectioned parameters */
9947
- /* @__PURE__ */ jsx23("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
10188
+ /* @__PURE__ */ jsx24("div", { children: parametersBySection._unsectioned?.map(renderParameter) })
9948
10189
  ) }),
9949
- /* @__PURE__ */ jsxs19(
10190
+ /* @__PURE__ */ jsxs20(
9950
10191
  "div",
9951
10192
  {
9952
10193
  style: {
@@ -9957,7 +10198,7 @@ function DeviceConfigPanelImpl({
9957
10198
  flexWrap: "wrap"
9958
10199
  },
9959
10200
  children: [
9960
- showApply && /* @__PURE__ */ jsx23(
10201
+ showApply && /* @__PURE__ */ jsx24(
9961
10202
  "button",
9962
10203
  {
9963
10204
  onClick: handleApply,
@@ -9980,7 +10221,7 @@ function DeviceConfigPanelImpl({
9980
10221
  children: binding.state.isSaving ? "Applying..." : "Apply"
9981
10222
  }
9982
10223
  ),
9983
- showSave && /* @__PURE__ */ jsx23(
10224
+ showSave && /* @__PURE__ */ jsx24(
9984
10225
  "button",
9985
10226
  {
9986
10227
  onClick: handleSave,
@@ -10003,7 +10244,7 @@ function DeviceConfigPanelImpl({
10003
10244
  children: binding.state.isSaving ? "Saving..." : "Save"
10004
10245
  }
10005
10246
  ),
10006
- showReset && /* @__PURE__ */ jsx23(
10247
+ showReset && /* @__PURE__ */ jsx24(
10007
10248
  "button",
10008
10249
  {
10009
10250
  onClick: handleReset,
@@ -10026,7 +10267,7 @@ function DeviceConfigPanelImpl({
10026
10267
  children: "Reset"
10027
10268
  }
10028
10269
  ),
10029
- showCancel && /* @__PURE__ */ jsx23(
10270
+ showCancel && /* @__PURE__ */ jsx24(
10030
10271
  "button",
10031
10272
  {
10032
10273
  onClick: handleCancel,
@@ -10053,7 +10294,7 @@ function DeviceConfigPanelImpl({
10053
10294
  }
10054
10295
  )
10055
10296
  ] }),
10056
- binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ jsx23(
10297
+ binding.state.lastSaveResult && showToast && showBuiltInToast && /* @__PURE__ */ jsx24(
10057
10298
  "div",
10058
10299
  {
10059
10300
  style: {
@@ -10075,7 +10316,7 @@ function DeviceConfigPanelImpl({
10075
10316
  )
10076
10317
  ] });
10077
10318
  }
10078
- var DeviceConfigPanel = React15.memo(DeviceConfigPanelImpl);
10319
+ var DeviceConfigPanel = React16.memo(DeviceConfigPanelImpl);
10079
10320
 
10080
10321
  // src/diagram/hooks/useSimulation.ts
10081
10322
  import { useEffect as useEffect15 } from "react";
@@ -10158,6 +10399,8 @@ export {
10158
10399
  FooterPanel,
10159
10400
  FullscreenContainer,
10160
10401
  FullscreenWorkspace,
10402
+ ISA_UNKNOWN,
10403
+ ISA_UNKNOWN_DARK,
10161
10404
  LeftPanel,
10162
10405
  LeftToggleButton,
10163
10406
  LegacyValueEntry,
@@ -10180,8 +10423,9 @@ export {
10180
10423
  ThemeProvider,
10181
10424
  ThemeToggle,
10182
10425
  TrendLine,
10183
- UNKNOWN_MARK_COLOR,
10184
- UNKNOWN_MARK_COLOR_DARK,
10426
+ UNKNOWN_GLYPH_RING_DASH,
10427
+ UNKNOWN_STATUS_GLYPH_COLOR_VAR,
10428
+ UnknownStatusGlyph,
10185
10429
  ValueEntry,
10186
10430
  ZoomButton,
10187
10431
  ZoomControls,
@@ -10193,14 +10437,19 @@ export {
10193
10437
  generateRoutePoints,
10194
10438
  getAppearanceDefaults,
10195
10439
  getAppearanceSchema,
10440
+ getAvailableBadgeGlyphs,
10196
10441
  getAvailableSymbols,
10442
+ getBadgeGlyph,
10197
10443
  getPortWorldPosition,
10198
10444
  getSymbolDefinition,
10199
10445
  importDiagram,
10200
10446
  mockSymbolLibrary,
10201
10447
  nodeHasPort,
10448
+ normalizeDeviceStatus,
10202
10449
  overlayStyles,
10203
10450
  readAppearanceValue,
10451
+ registerBadgeGlyph,
10452
+ registerBadgeGlyphs,
10204
10453
  registerSymbol,
10205
10454
  registerSymbols,
10206
10455
  resolvePresetColor,