@procaaso/alphinity-ui-components 1.0.6 → 1.0.8

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
@@ -707,14 +707,723 @@ var StatusIndicator = ({
707
707
  ] });
708
708
  };
709
709
 
710
+ // src/components/NodeControlsPanel/NodeControlsPanel.tsx
711
+ import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
712
+ var NodeControlsPanel = ({
713
+ config,
714
+ onClose,
715
+ position = "bottom",
716
+ touchOptimized = true,
717
+ className = "",
718
+ style,
719
+ ...props
720
+ }) => {
721
+ if (!config) return null;
722
+ const isBottom = position === "bottom";
723
+ const touchClass = touchOptimized ? "touch-optimized" : "";
724
+ const containerStyle = {
725
+ position: "fixed",
726
+ zIndex: 9999,
727
+ background: "white",
728
+ boxShadow: "0 -4px 16px rgba(0, 0, 0, 0.15)",
729
+ borderRadius: isBottom ? "16px 16px 0 0" : "0",
730
+ animation: isBottom ? "slideUp 0.3s ease-out" : "slideInRight 0.3s ease-out",
731
+ display: "flex",
732
+ flexDirection: "column",
733
+ ...isBottom ? {
734
+ left: 0,
735
+ right: 0,
736
+ bottom: 0,
737
+ maxHeight: "70vh",
738
+ borderTop: "1px solid #e5e7eb"
739
+ } : {
740
+ right: 0,
741
+ top: 0,
742
+ bottom: 0,
743
+ width: touchOptimized ? "400px" : "320px",
744
+ borderLeft: "1px solid #e5e7eb"
745
+ },
746
+ ...style
747
+ };
748
+ const headerStyle = {
749
+ display: "flex",
750
+ alignItems: "center",
751
+ justifyContent: "space-between",
752
+ padding: touchOptimized ? "1.25rem 1.5rem" : "1rem",
753
+ borderBottom: "2px solid #e5e7eb",
754
+ background: "#f9fafb",
755
+ flexShrink: 0
756
+ };
757
+ const titleStyle = {
758
+ margin: 0,
759
+ fontSize: touchOptimized ? "1.5rem" : "1.25rem",
760
+ fontWeight: 600,
761
+ color: "#111827"
762
+ };
763
+ const closeButtonStyle = {
764
+ background: "#ef4444",
765
+ color: "white",
766
+ border: "none",
767
+ borderRadius: "8px",
768
+ width: touchOptimized ? "56px" : "44px",
769
+ height: touchOptimized ? "56px" : "44px",
770
+ fontSize: touchOptimized ? "1.75rem" : "1.5rem",
771
+ fontWeight: "bold",
772
+ cursor: "pointer",
773
+ display: "flex",
774
+ alignItems: "center",
775
+ justifyContent: "center",
776
+ transition: "all 0.2s ease",
777
+ flexShrink: 0
778
+ };
779
+ const contentStyle = {
780
+ padding: touchOptimized ? "1.5rem" : "1rem",
781
+ overflowY: "auto",
782
+ flex: 1
783
+ };
784
+ return /* @__PURE__ */ jsxs6(Fragment, { children: [
785
+ /* @__PURE__ */ jsx7(
786
+ "div",
787
+ {
788
+ style: {
789
+ position: "fixed",
790
+ inset: 0,
791
+ background: "rgba(0, 0, 0, 0.3)",
792
+ zIndex: 9998,
793
+ animation: "fadeIn 0.3s ease-out"
794
+ },
795
+ onClick: onClose
796
+ }
797
+ ),
798
+ /* @__PURE__ */ jsxs6(
799
+ "div",
800
+ {
801
+ className: `node-controls-panel ${touchClass} ${className}`.trim(),
802
+ style: containerStyle,
803
+ ...props,
804
+ children: [
805
+ /* @__PURE__ */ jsxs6("div", { style: headerStyle, children: [
806
+ /* @__PURE__ */ jsx7("h2", { style: titleStyle, children: config.title }),
807
+ /* @__PURE__ */ jsx7(
808
+ "button",
809
+ {
810
+ style: closeButtonStyle,
811
+ onClick: onClose,
812
+ onMouseEnter: (e) => {
813
+ e.currentTarget.style.background = "#dc2626";
814
+ e.currentTarget.style.transform = "scale(1.05)";
815
+ },
816
+ onMouseLeave: (e) => {
817
+ e.currentTarget.style.background = "#ef4444";
818
+ e.currentTarget.style.transform = "scale(1)";
819
+ },
820
+ "aria-label": "Close",
821
+ children: "\u2715"
822
+ }
823
+ )
824
+ ] }),
825
+ /* @__PURE__ */ jsx7("div", { style: contentStyle, children: /* @__PURE__ */ jsx7(
826
+ ControlPanel,
827
+ {
828
+ title: config.nodeId,
829
+ selectedMode: config.currentMode,
830
+ modeOptions: config.modes,
831
+ onModeChange: config.onModeChange,
832
+ setpointValue: config.setpoint,
833
+ onSetpointChange: config.onSetpointChange,
834
+ secondSetpointValue: config.secondSetpoint,
835
+ onSecondSetpointChange: config.onSecondSetpointChange,
836
+ modeConfigs: config.modeConfigs,
837
+ status: config.status,
838
+ setpointReadOnly: config.readOnly,
839
+ showStartStopButtons: !!(config.onStart || config.onStop),
840
+ isRunning: config.isRunning,
841
+ onStart: config.onStart,
842
+ onStop: config.onStop,
843
+ startButtonText: config.startButtonText,
844
+ stopButtonText: config.stopButtonText,
845
+ size: touchOptimized ? "large" : "medium"
846
+ }
847
+ ) })
848
+ ]
849
+ }
850
+ ),
851
+ /* @__PURE__ */ jsx7("style", { children: `
852
+ @keyframes slideUp {
853
+ from {
854
+ transform: translateY(100%);
855
+ opacity: 0;
856
+ }
857
+ to {
858
+ transform: translateY(0);
859
+ opacity: 1;
860
+ }
861
+ }
862
+
863
+ @keyframes slideInRight {
864
+ from {
865
+ transform: translateX(100%);
866
+ opacity: 0;
867
+ }
868
+ to {
869
+ transform: translateX(0);
870
+ opacity: 1;
871
+ }
872
+ }
873
+
874
+ @keyframes fadeIn {
875
+ from {
876
+ opacity: 0;
877
+ }
878
+ to {
879
+ opacity: 1;
880
+ }
881
+ }
882
+
883
+ .node-controls-panel.touch-optimized button {
884
+ min-height: 56px;
885
+ font-size: 1.125rem;
886
+ }
887
+
888
+ .node-controls-panel.touch-optimized input {
889
+ min-height: 56px;
890
+ font-size: 1.125rem;
891
+ }
892
+ ` })
893
+ ] });
894
+ };
895
+
896
+ // src/components/DeviceControlPanel/DeviceControlPanel.tsx
897
+ import { useState as useState5, useEffect as useEffect2 } from "react";
898
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
899
+ function DeviceControlPanel({
900
+ binding,
901
+ onClose,
902
+ position = "bottom",
903
+ touchOptimized = true,
904
+ onModeChange,
905
+ onParameterChange,
906
+ onStart,
907
+ onStop,
908
+ onCustomAction
909
+ }) {
910
+ const [localParameterValues, setLocalParameterValues] = useState5({});
911
+ useEffect2(() => {
912
+ if (binding) {
913
+ const currentParams2 = binding.parameters[binding.state.currentMode] || [];
914
+ const values = {};
915
+ currentParams2.forEach((param) => {
916
+ values[param.id] = param.value;
917
+ });
918
+ setLocalParameterValues(values);
919
+ }
920
+ }, [binding, binding?.state.currentMode]);
921
+ if (!binding) return null;
922
+ const currentMode = binding.state.currentMode;
923
+ const currentParams = binding.parameters[currentMode] || [];
924
+ const touchSize = touchOptimized ? 56 : 40;
925
+ const currentModeObj = binding.modes.find((m) => m.value === currentMode);
926
+ const activeCapabilities = currentModeObj?.capabilities ?? binding.capabilities ?? {};
927
+ const backgroundColor = binding.theme?.backgroundColor || "#edeeef";
928
+ const surfaceColor = "#f5f6f7";
929
+ const borderColor = "#d2d2d2";
930
+ const textColor = binding.theme?.textColor || "#000000";
931
+ const mutedTextColor = "#666666";
932
+ const selectedColor = "#b4d0fe";
933
+ const statusColors = {
934
+ normal: binding.theme?.statusColors?.normal || "#888888",
935
+ // Gray (no alarm)
936
+ warning: binding.theme?.statusColors?.warning || "#FFD700",
937
+ // Yellow
938
+ alarm: binding.theme?.statusColors?.alarm || "#FF0000",
939
+ // Red
940
+ fault: binding.theme?.statusColors?.fault || "#FF0000",
941
+ // Red
942
+ off: binding.theme?.statusColors?.off || "#666666",
943
+ // Dark gray
944
+ starting: binding.theme?.statusColors?.starting || "#90EE90",
945
+ // Light green
946
+ stopping: binding.theme?.statusColors?.stopping || "#FFD700"
947
+ // Yellow
948
+ };
949
+ const statusColor = statusColors[binding.state.status || "normal"];
950
+ const handleModeChange = (mode) => {
951
+ onModeChange?.(mode);
952
+ };
953
+ const handleParameterCommit = (parameterId, value) => {
954
+ onParameterChange?.(parameterId, value);
955
+ };
956
+ const handleParameterInput = (parameterId, value) => {
957
+ setLocalParameterValues((prev) => ({ ...prev, [parameterId]: value }));
958
+ };
959
+ const panelStyle = {
960
+ position: "fixed",
961
+ ...position === "bottom" ? {
962
+ bottom: 0,
963
+ left: 0,
964
+ right: 0,
965
+ animation: "slideUp 0.3s ease-out"
966
+ } : {
967
+ right: 0,
968
+ top: 0,
969
+ bottom: 0,
970
+ width: "400px",
971
+ animation: "slideIn 0.3s ease-out"
972
+ },
973
+ backgroundColor,
974
+ color: textColor,
975
+ borderRadius: position === "bottom" ? "8px 8px 0 0" : "8px 0 0 8px",
976
+ boxShadow: "none",
977
+ border: `2px solid ${borderColor}`,
978
+ padding: "20px",
979
+ zIndex: 9999,
980
+ maxHeight: position === "bottom" ? "70vh" : "100vh",
981
+ overflowY: "auto",
982
+ ...binding.display?.style
983
+ };
984
+ const titleText = binding.display?.title || binding.deviceName || binding.tag || binding.nodeId;
985
+ return /* @__PURE__ */ jsx8(Fragment2, { children: /* @__PURE__ */ jsxs7("div", { style: panelStyle, className: binding.display?.className, children: [
986
+ /* @__PURE__ */ jsxs7(
987
+ "div",
988
+ {
989
+ style: {
990
+ display: "flex",
991
+ justifyContent: "space-between",
992
+ alignItems: "center",
993
+ marginBottom: "16px",
994
+ paddingBottom: "12px",
995
+ borderBottom: `2px solid ${borderColor}`
996
+ },
997
+ children: [
998
+ /* @__PURE__ */ jsxs7("div", { children: [
999
+ /* @__PURE__ */ jsx8(
1000
+ "h3",
1001
+ {
1002
+ style: {
1003
+ margin: 0,
1004
+ fontSize: "14px",
1005
+ fontWeight: 600,
1006
+ fontFamily: "Arial, sans-serif",
1007
+ letterSpacing: "0.5px",
1008
+ textTransform: "uppercase",
1009
+ color: textColor
1010
+ },
1011
+ children: titleText
1012
+ }
1013
+ ),
1014
+ binding.deviceType && /* @__PURE__ */ jsx8(
1015
+ "div",
1016
+ {
1017
+ style: {
1018
+ fontSize: "11px",
1019
+ color: mutedTextColor,
1020
+ marginTop: "4px",
1021
+ fontFamily: "Arial, sans-serif"
1022
+ },
1023
+ children: binding.deviceType
1024
+ }
1025
+ )
1026
+ ] }),
1027
+ /* @__PURE__ */ jsx8(
1028
+ "button",
1029
+ {
1030
+ onClick: onClose,
1031
+ style: {
1032
+ width: touchSize * 0.7,
1033
+ height: touchSize * 0.7,
1034
+ backgroundColor: surfaceColor,
1035
+ color: textColor,
1036
+ border: `2px solid ${borderColor}`,
1037
+ borderRadius: "2px",
1038
+ fontSize: "18px",
1039
+ cursor: "pointer",
1040
+ fontWeight: "bold",
1041
+ fontFamily: "Arial, sans-serif"
1042
+ },
1043
+ children: "\xD7"
1044
+ }
1045
+ )
1046
+ ]
1047
+ }
1048
+ ),
1049
+ binding.state.status && /* @__PURE__ */ jsxs7(
1050
+ "div",
1051
+ {
1052
+ style: {
1053
+ display: "flex",
1054
+ alignItems: "center",
1055
+ gap: "12px",
1056
+ padding: "10px 12px",
1057
+ backgroundColor: surfaceColor,
1058
+ border: `1px solid ${borderColor}`,
1059
+ borderRadius: "6px",
1060
+ marginBottom: "16px"
1061
+ },
1062
+ children: [
1063
+ /* @__PURE__ */ jsx8(
1064
+ "div",
1065
+ {
1066
+ style: {
1067
+ width: "10px",
1068
+ height: "10px",
1069
+ borderRadius: "50%",
1070
+ backgroundColor: statusColor,
1071
+ border: "1px solid #333"
1072
+ }
1073
+ }
1074
+ ),
1075
+ /* @__PURE__ */ jsxs7("div", { style: { flex: 1 }, children: [
1076
+ /* @__PURE__ */ jsx8(
1077
+ "div",
1078
+ {
1079
+ style: {
1080
+ fontWeight: 600,
1081
+ textTransform: "uppercase",
1082
+ fontSize: "11px",
1083
+ fontFamily: "Arial, sans-serif",
1084
+ letterSpacing: "0.5px",
1085
+ color: textColor
1086
+ },
1087
+ children: binding.state.status
1088
+ }
1089
+ ),
1090
+ binding.state.statusMessage && /* @__PURE__ */ jsx8(
1091
+ "div",
1092
+ {
1093
+ style: {
1094
+ fontSize: "10px",
1095
+ color: mutedTextColor,
1096
+ marginTop: "2px",
1097
+ fontFamily: "Arial, sans-serif"
1098
+ },
1099
+ children: binding.state.statusMessage
1100
+ }
1101
+ )
1102
+ ] }),
1103
+ binding.state.isRunning !== void 0 && /* @__PURE__ */ jsx8(
1104
+ "div",
1105
+ {
1106
+ style: {
1107
+ padding: "4px 10px",
1108
+ backgroundColor: binding.state.isRunning ? selectedColor : surfaceColor,
1109
+ border: `1px solid ${borderColor}`,
1110
+ borderRadius: "2px",
1111
+ fontSize: "10px",
1112
+ fontWeight: 600,
1113
+ fontFamily: "Arial, sans-serif",
1114
+ letterSpacing: "0.5px",
1115
+ color: textColor
1116
+ },
1117
+ children: binding.state.isRunning ? "RUNNING" : "STOPPED"
1118
+ }
1119
+ )
1120
+ ]
1121
+ }
1122
+ ),
1123
+ binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: "16px" }, children: [
1124
+ /* @__PURE__ */ jsx8(
1125
+ "label",
1126
+ {
1127
+ style: {
1128
+ display: "block",
1129
+ marginBottom: "8px",
1130
+ fontSize: "11px",
1131
+ fontWeight: 600,
1132
+ textTransform: "uppercase",
1133
+ letterSpacing: "0.5px",
1134
+ fontFamily: "Arial, sans-serif",
1135
+ color: mutedTextColor
1136
+ },
1137
+ children: "Mode"
1138
+ }
1139
+ ),
1140
+ /* @__PURE__ */ jsx8("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: binding.modes.map((mode) => {
1141
+ const isSelected = mode.value === currentMode;
1142
+ const isEnabled = mode.enabled !== false;
1143
+ return /* @__PURE__ */ jsx8(
1144
+ "button",
1145
+ {
1146
+ onClick: () => isEnabled && handleModeChange(mode.value),
1147
+ disabled: !isEnabled,
1148
+ style: {
1149
+ flex: 1,
1150
+ minWidth: "80px",
1151
+ height: touchSize,
1152
+ backgroundColor: isSelected ? selectedColor : surfaceColor,
1153
+ color: isSelected ? "#000000" : textColor,
1154
+ border: `1px solid ${isSelected ? "#b4d0fe" : borderColor}`,
1155
+ borderRadius: "6px",
1156
+ fontSize: "11px",
1157
+ fontWeight: 600,
1158
+ fontFamily: "Arial, sans-serif",
1159
+ letterSpacing: "0.5px",
1160
+ textTransform: "uppercase",
1161
+ cursor: isEnabled ? "pointer" : "not-allowed",
1162
+ opacity: isEnabled ? 1 : 0.4
1163
+ },
1164
+ children: mode.label
1165
+ },
1166
+ mode.value
1167
+ );
1168
+ }) })
1169
+ ] }),
1170
+ currentParams.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: "16px" }, children: [
1171
+ /* @__PURE__ */ jsx8(
1172
+ "label",
1173
+ {
1174
+ style: {
1175
+ display: "block",
1176
+ marginBottom: "8px",
1177
+ fontSize: "11px",
1178
+ fontWeight: 600,
1179
+ textTransform: "uppercase",
1180
+ letterSpacing: "0.5px",
1181
+ fontFamily: "Arial, sans-serif",
1182
+ color: mutedTextColor
1183
+ },
1184
+ children: "Parameters"
1185
+ }
1186
+ ),
1187
+ currentParams.map((param) => /* @__PURE__ */ jsxs7(
1188
+ "div",
1189
+ {
1190
+ style: {
1191
+ marginBottom: "10px",
1192
+ padding: "10px",
1193
+ backgroundColor: surfaceColor,
1194
+ border: `1px solid ${borderColor}`,
1195
+ borderRadius: "6px"
1196
+ },
1197
+ children: [
1198
+ /* @__PURE__ */ jsxs7(
1199
+ "div",
1200
+ {
1201
+ style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" },
1202
+ children: [
1203
+ /* @__PURE__ */ jsx8(
1204
+ "span",
1205
+ {
1206
+ style: {
1207
+ fontSize: "11px",
1208
+ fontWeight: 600,
1209
+ textTransform: "uppercase",
1210
+ letterSpacing: "0.5px",
1211
+ fontFamily: "Arial, sans-serif",
1212
+ color: mutedTextColor
1213
+ },
1214
+ children: param.label
1215
+ }
1216
+ ),
1217
+ /* @__PURE__ */ jsxs7(
1218
+ "span",
1219
+ {
1220
+ style: {
1221
+ fontSize: "13px",
1222
+ fontWeight: 700,
1223
+ fontFamily: "Arial, sans-serif",
1224
+ color: textColor
1225
+ },
1226
+ children: [
1227
+ localParameterValues[param.id] ?? param.value,
1228
+ " ",
1229
+ param.unit && /* @__PURE__ */ jsx8("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
1230
+ ]
1231
+ }
1232
+ )
1233
+ ]
1234
+ }
1235
+ ),
1236
+ param.type === "boolean" ? /* @__PURE__ */ jsx8(
1237
+ "button",
1238
+ {
1239
+ onClick: () => {
1240
+ const newValue = !localParameterValues[param.id];
1241
+ handleParameterInput(param.id, newValue);
1242
+ handleParameterCommit(param.id, newValue);
1243
+ },
1244
+ disabled: param.readOnly,
1245
+ style: {
1246
+ width: "100%",
1247
+ height: touchSize,
1248
+ backgroundColor: localParameterValues[param.id] ? "#3f3f46" : surfaceColor,
1249
+ color: localParameterValues[param.id] ? textColor : mutedTextColor,
1250
+ border: `1px solid ${localParameterValues[param.id] ? "#52525b" : borderColor}`,
1251
+ borderRadius: "4px",
1252
+ fontSize: "12px",
1253
+ fontWeight: 600,
1254
+ fontFamily: "monospace",
1255
+ letterSpacing: "0.5px",
1256
+ cursor: param.readOnly ? "not-allowed" : "pointer",
1257
+ transition: "all 0.15s"
1258
+ },
1259
+ children: localParameterValues[param.id] ? "ON" : "OFF"
1260
+ }
1261
+ ) : param.type === "select" ? /* @__PURE__ */ jsx8(
1262
+ "select",
1263
+ {
1264
+ value: localParameterValues[param.id] || param.value,
1265
+ onChange: (e) => {
1266
+ handleParameterInput(param.id, e.target.value);
1267
+ handleParameterCommit(param.id, e.target.value);
1268
+ },
1269
+ disabled: param.readOnly,
1270
+ style: {
1271
+ width: "100%",
1272
+ height: touchSize,
1273
+ backgroundColor: surfaceColor,
1274
+ color: textColor,
1275
+ border: `1px solid ${borderColor}`,
1276
+ borderRadius: "4px",
1277
+ padding: "0 12px",
1278
+ fontSize: "12px",
1279
+ fontFamily: "monospace",
1280
+ cursor: "pointer"
1281
+ },
1282
+ children: param.options?.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
1283
+ }
1284
+ ) : /* @__PURE__ */ jsx8(
1285
+ "input",
1286
+ {
1287
+ type: param.type === "number" ? "number" : "text",
1288
+ value: localParameterValues[param.id] ?? param.value,
1289
+ onChange: (e) => handleParameterInput(
1290
+ param.id,
1291
+ param.type === "number" ? +e.target.value : e.target.value
1292
+ ),
1293
+ onBlur: () => handleParameterCommit(param.id, localParameterValues[param.id]),
1294
+ disabled: param.readOnly,
1295
+ min: param.min,
1296
+ max: param.max,
1297
+ step: param.step,
1298
+ style: {
1299
+ width: "100%",
1300
+ height: touchSize,
1301
+ backgroundColor: "#ffffff",
1302
+ color: textColor,
1303
+ border: `1px solid ${borderColor}`,
1304
+ borderRadius: "6px",
1305
+ padding: "0 12px",
1306
+ fontSize: "14px",
1307
+ fontFamily: "Arial, sans-serif",
1308
+ fontWeight: 600
1309
+ }
1310
+ }
1311
+ )
1312
+ ]
1313
+ },
1314
+ param.id
1315
+ ))
1316
+ ] }),
1317
+ binding.display?.showStartStop !== false && (activeCapabilities?.canStart || activeCapabilities?.canStop) && /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "8px", marginBottom: "16px" }, children: [
1318
+ activeCapabilities?.canStart && /* @__PURE__ */ jsx8(
1319
+ "button",
1320
+ {
1321
+ onClick: onStart,
1322
+ disabled: binding.state.isRunning,
1323
+ style: {
1324
+ flex: 1,
1325
+ height: touchSize,
1326
+ backgroundColor: binding.state.isRunning ? "#a3a3a3" : "#10b981",
1327
+ color: "#ffffff",
1328
+ border: "none",
1329
+ borderRadius: "6px",
1330
+ fontSize: "12px",
1331
+ fontWeight: 700,
1332
+ fontFamily: "Arial, sans-serif",
1333
+ letterSpacing: "0.5px",
1334
+ cursor: binding.state.isRunning ? "not-allowed" : "pointer",
1335
+ opacity: binding.state.isRunning ? 0.5 : 1
1336
+ },
1337
+ children: "START"
1338
+ }
1339
+ ),
1340
+ activeCapabilities?.canStop && /* @__PURE__ */ jsx8(
1341
+ "button",
1342
+ {
1343
+ onClick: onStop,
1344
+ disabled: !binding.state.isRunning,
1345
+ style: {
1346
+ flex: 1,
1347
+ height: touchSize,
1348
+ backgroundColor: !binding.state.isRunning ? "#a3a3a3" : "#ef4444",
1349
+ color: "#ffffff",
1350
+ border: "none",
1351
+ borderRadius: "6px",
1352
+ fontSize: "12px",
1353
+ fontWeight: 700,
1354
+ fontFamily: "Arial, sans-serif",
1355
+ letterSpacing: "0.5px",
1356
+ cursor: !binding.state.isRunning ? "not-allowed" : "pointer",
1357
+ opacity: !binding.state.isRunning ? 0.5 : 1
1358
+ },
1359
+ children: "STOP"
1360
+ }
1361
+ )
1362
+ ] }),
1363
+ activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ jsx8("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => /* @__PURE__ */ jsxs7(
1364
+ "button",
1365
+ {
1366
+ onClick: () => onCustomAction?.(action.id),
1367
+ style: {
1368
+ flex: 1,
1369
+ minWidth: "120px",
1370
+ height: touchSize,
1371
+ backgroundColor: surfaceColor,
1372
+ color: textColor,
1373
+ border: `1px solid ${borderColor}`,
1374
+ borderRadius: "6px",
1375
+ fontSize: "11px",
1376
+ fontWeight: 600,
1377
+ fontFamily: "monospace",
1378
+ letterSpacing: "0.5px",
1379
+ textTransform: "uppercase",
1380
+ cursor: "pointer",
1381
+ transition: "all 0.15s"
1382
+ },
1383
+ children: [
1384
+ action.icon && /* @__PURE__ */ jsx8("span", { style: { marginRight: "6px" }, children: action.icon }),
1385
+ action.label
1386
+ ]
1387
+ },
1388
+ action.id
1389
+ )) }),
1390
+ binding.state.lastCommandResult && /* @__PURE__ */ jsx8(
1391
+ "div",
1392
+ {
1393
+ style: {
1394
+ marginTop: "16px",
1395
+ padding: "10px 12px",
1396
+ backgroundColor: surfaceColor,
1397
+ border: `1px solid ${binding.state.lastCommandResult.success ? "#52525b" : borderColor}`,
1398
+ borderRadius: "4px",
1399
+ fontSize: "11px",
1400
+ fontFamily: "monospace",
1401
+ color: binding.state.lastCommandResult.success ? textColor : mutedTextColor
1402
+ },
1403
+ children: binding.state.lastCommandResult.message
1404
+ }
1405
+ ),
1406
+ /* @__PURE__ */ jsx8("style", { children: `
1407
+ @keyframes slideUp {
1408
+ from { transform: translateY(100%); }
1409
+ to { transform: translateY(0); }
1410
+ }
1411
+ @keyframes slideIn {
1412
+ from { transform: translateX(100%); }
1413
+ to { transform: translateX(0); }
1414
+ }
1415
+ ` })
1416
+ ] }) });
1417
+ }
1418
+
710
1419
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
711
- import React5 from "react";
1420
+ import React6 from "react";
712
1421
  import { Tab } from "@mui/material";
713
1422
 
714
1423
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
715
1424
  import { Box, IconButton, Tabs } from "@mui/material";
716
1425
  import styled from "@emotion/styled";
717
- import { jsx as jsx7 } from "react/jsx-runtime";
1426
+ import { jsx as jsx9 } from "react/jsx-runtime";
718
1427
  var FullscreenContainer = styled(Box)(
719
1428
  ({ leftCollapsed, rightCollapsed }) => {
720
1429
  const getGridTemplateAreas = () => {
@@ -839,7 +1548,7 @@ var DisplayModeToggle = styled(IconButton)(({ mode }) => ({
839
1548
  transform: "translateX(-50%) scale(1.05)"
840
1549
  }
841
1550
  }));
842
- var ChevronLeft = () => /* @__PURE__ */ jsx7(
1551
+ var ChevronLeft = () => /* @__PURE__ */ jsx9(
843
1552
  "div",
844
1553
  {
845
1554
  style: {
@@ -851,7 +1560,7 @@ var ChevronLeft = () => /* @__PURE__ */ jsx7(
851
1560
  }
852
1561
  }
853
1562
  );
854
- var ChevronRight = () => /* @__PURE__ */ jsx7(
1563
+ var ChevronRight = () => /* @__PURE__ */ jsx9(
855
1564
  "div",
856
1565
  {
857
1566
  style: {
@@ -962,10 +1671,10 @@ var ScrollableSVGWrapper = styled("div")({
962
1671
  });
963
1672
 
964
1673
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx
965
- import { useEffect as useEffect2, useState as useState5 } from "react";
1674
+ import { useEffect as useEffect3, useState as useState6 } from "react";
966
1675
  import { Box as Box2 } from "@mui/material";
967
1676
  import styled2 from "@emotion/styled";
968
- import { jsx as jsx8 } from "react/jsx-runtime";
1677
+ import { jsx as jsx10 } from "react/jsx-runtime";
969
1678
  var baseOverlayStyles = {
970
1679
  tank: {
971
1680
  background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
@@ -1027,8 +1736,8 @@ var SVGLockedOverlay = ({
1027
1736
  onClick,
1028
1737
  containerSelector = ".tff-svg-container"
1029
1738
  }) => {
1030
- const [svgOffset, setSvgOffset] = useState5({ x: 0, y: 0 });
1031
- useEffect2(() => {
1739
+ const [svgOffset, setSvgOffset] = useState6({ x: 0, y: 0 });
1740
+ useEffect3(() => {
1032
1741
  const updateSvgOffset = () => {
1033
1742
  const containerElement = document.querySelector(containerSelector);
1034
1743
  const svgElement = containerElement?.querySelector("svg");
@@ -1048,7 +1757,7 @@ var SVGLockedOverlay = ({
1048
1757
  const pixelX = svgX + svgOffset.x;
1049
1758
  const pixelY = svgY + svgOffset.y;
1050
1759
  const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
1051
- return /* @__PURE__ */ jsx8(
1760
+ return /* @__PURE__ */ jsx10(
1052
1761
  Box2,
1053
1762
  {
1054
1763
  className: `svg-locked-overlay ${className}`.trim(),
@@ -1112,7 +1821,7 @@ var CardUnit = styled2("div")({
1112
1821
  });
1113
1822
 
1114
1823
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
1115
- import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1824
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1116
1825
  var TrendLine = ({
1117
1826
  values,
1118
1827
  width = 60,
@@ -1122,7 +1831,7 @@ var TrendLine = ({
1122
1831
  backgroundColor = "rgba(255, 255, 255, 0.1)"
1123
1832
  }) => {
1124
1833
  if (!values || values.length < 2) {
1125
- return /* @__PURE__ */ jsx9(
1834
+ return /* @__PURE__ */ jsx11(
1126
1835
  "div",
1127
1836
  {
1128
1837
  style: {
@@ -1134,7 +1843,7 @@ var TrendLine = ({
1134
1843
  alignItems: "center",
1135
1844
  justifyContent: "center"
1136
1845
  },
1137
- children: /* @__PURE__ */ jsx9("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" })
1846
+ children: /* @__PURE__ */ jsx11("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" })
1138
1847
  }
1139
1848
  );
1140
1849
  }
@@ -1146,7 +1855,7 @@ var TrendLine = ({
1146
1855
  const x = 4 + i / (values.length - 1) * (width - 8);
1147
1856
  return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
1148
1857
  }).join(" ");
1149
- return /* @__PURE__ */ jsx9(
1858
+ return /* @__PURE__ */ jsx11(
1150
1859
  "div",
1151
1860
  {
1152
1861
  style: {
@@ -1157,8 +1866,8 @@ var TrendLine = ({
1157
1866
  position: "relative",
1158
1867
  overflow: "hidden"
1159
1868
  },
1160
- children: /* @__PURE__ */ jsxs6("svg", { width, height, style: { position: "absolute", top: 0, left: 0 }, children: [
1161
- /* @__PURE__ */ jsx9(
1869
+ children: /* @__PURE__ */ jsxs8("svg", { width, height, style: { position: "absolute", top: 0, left: 0 }, children: [
1870
+ /* @__PURE__ */ jsx11(
1162
1871
  "path",
1163
1872
  {
1164
1873
  d: pathData,
@@ -1169,7 +1878,7 @@ var TrendLine = ({
1169
1878
  strokeLinejoin: "round"
1170
1879
  }
1171
1880
  ),
1172
- /* @__PURE__ */ jsx9(
1881
+ /* @__PURE__ */ jsx11(
1173
1882
  "circle",
1174
1883
  {
1175
1884
  cx: 4 + (width - 8),
@@ -1207,7 +1916,7 @@ var CircularGauge = ({
1207
1916
  const borderColor = isHex ? hexToRgba(color, 0.9) : color;
1208
1917
  const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
1209
1918
  const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
1210
- return /* @__PURE__ */ jsxs6(
1919
+ return /* @__PURE__ */ jsxs8(
1211
1920
  "div",
1212
1921
  {
1213
1922
  style: {
@@ -1216,7 +1925,7 @@ var CircularGauge = ({
1216
1925
  alignItems: "center"
1217
1926
  },
1218
1927
  children: [
1219
- /* @__PURE__ */ jsxs6(
1928
+ /* @__PURE__ */ jsxs8(
1220
1929
  "div",
1221
1930
  {
1222
1931
  style: {
@@ -1228,8 +1937,8 @@ var CircularGauge = ({
1228
1937
  border: `1px solid ${borderStrokeColor}`
1229
1938
  },
1230
1939
  children: [
1231
- /* @__PURE__ */ jsxs6("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
1232
- /* @__PURE__ */ jsx9(
1940
+ /* @__PURE__ */ jsxs8("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
1941
+ /* @__PURE__ */ jsx11(
1233
1942
  "circle",
1234
1943
  {
1235
1944
  cx: size / 2,
@@ -1240,7 +1949,7 @@ var CircularGauge = ({
1240
1949
  strokeWidth: 1
1241
1950
  }
1242
1951
  ),
1243
- /* @__PURE__ */ jsx9(
1952
+ /* @__PURE__ */ jsx11(
1244
1953
  "circle",
1245
1954
  {
1246
1955
  cx: size / 2,
@@ -1251,7 +1960,7 @@ var CircularGauge = ({
1251
1960
  fill: "transparent"
1252
1961
  }
1253
1962
  ),
1254
- /* @__PURE__ */ jsx9(
1963
+ /* @__PURE__ */ jsx11(
1255
1964
  "circle",
1256
1965
  {
1257
1966
  cx: size / 2,
@@ -1267,7 +1976,7 @@ var CircularGauge = ({
1267
1976
  }
1268
1977
  )
1269
1978
  ] }),
1270
- /* @__PURE__ */ jsxs6(
1979
+ /* @__PURE__ */ jsxs8(
1271
1980
  "div",
1272
1981
  {
1273
1982
  style: {
@@ -1283,14 +1992,14 @@ var CircularGauge = ({
1283
1992
  },
1284
1993
  children: [
1285
1994
  value.toFixed(1),
1286
- /* @__PURE__ */ jsx9("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
1995
+ /* @__PURE__ */ jsx11("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
1287
1996
  ]
1288
1997
  }
1289
1998
  )
1290
1999
  ]
1291
2000
  }
1292
2001
  ),
1293
- /* @__PURE__ */ jsx9(
2002
+ /* @__PURE__ */ jsx11(
1294
2003
  "div",
1295
2004
  {
1296
2005
  style: {
@@ -1321,7 +2030,7 @@ var Sparkline = ({ data, width, height, color }) => {
1321
2030
  const y = height - 8 - (value - min) / range * (height - 8);
1322
2031
  return `${x + 4},${y + 4}`;
1323
2032
  }).join(" ");
1324
- return /* @__PURE__ */ jsx9(
2033
+ return /* @__PURE__ */ jsx11(
1325
2034
  "div",
1326
2035
  {
1327
2036
  style: {
@@ -1335,7 +2044,7 @@ var Sparkline = ({ data, width, height, color }) => {
1335
2044
  justifyContent: "center",
1336
2045
  boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
1337
2046
  },
1338
- children: /* @__PURE__ */ jsx9("svg", { width, height, children: /* @__PURE__ */ jsx9("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) })
2047
+ children: /* @__PURE__ */ jsx11("svg", { width, height, children: /* @__PURE__ */ jsx11("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) })
1339
2048
  }
1340
2049
  );
1341
2050
  };
@@ -1349,8 +2058,8 @@ var EquipmentIndicatorWithSparkline = ({
1349
2058
  sparklineOffset = { x: 40, y: 0 }
1350
2059
  }) => {
1351
2060
  const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
1352
- return /* @__PURE__ */ jsxs6(Fragment, { children: [
1353
- /* @__PURE__ */ jsx9(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsx9(
2061
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
2062
+ /* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsx11(
1354
2063
  "div",
1355
2064
  {
1356
2065
  style: {
@@ -1371,7 +2080,7 @@ var EquipmentIndicatorWithSparkline = ({
1371
2080
  children: label
1372
2081
  }
1373
2082
  ) }),
1374
- hasSparkline && /* @__PURE__ */ jsx9(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx9(Sparkline, { data: sparklineData, width: 60, height: 20, color }) })
2083
+ hasSparkline && /* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx11(Sparkline, { data: sparklineData, width: 60, height: 20, color }) })
1375
2084
  ] });
1376
2085
  };
1377
2086
  var EquipmentIndicator = ({
@@ -1384,7 +2093,7 @@ var EquipmentIndicator = ({
1384
2093
  className
1385
2094
  }) => {
1386
2095
  const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
1387
- return /* @__PURE__ */ jsx9(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsx9(
2096
+ return /* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsx11(
1388
2097
  "div",
1389
2098
  {
1390
2099
  style: {
@@ -1408,7 +2117,7 @@ var EquipmentIndicator = ({
1408
2117
  };
1409
2118
 
1410
2119
  // src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
1411
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2120
+ import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1412
2121
  function FullscreenWorkspace({
1413
2122
  svgContent,
1414
2123
  overlays,
@@ -1436,10 +2145,10 @@ function FullscreenWorkspace({
1436
2145
  className = "",
1437
2146
  ...rest
1438
2147
  }) {
1439
- const [leftCollapsedState, setLeftCollapsedState] = React5.useState(defaultLeftCollapsed);
1440
- const [rightCollapsedState, setRightCollapsedState] = React5.useState(defaultRightCollapsed);
1441
- const [internalDisplayMode, setInternalDisplayMode] = React5.useState(displayMode ?? defaultDisplayMode);
1442
- const [internalTab, setInternalTab] = React5.useState(
2148
+ const [leftCollapsedState, setLeftCollapsedState] = React6.useState(defaultLeftCollapsed);
2149
+ const [rightCollapsedState, setRightCollapsedState] = React6.useState(defaultRightCollapsed);
2150
+ const [internalDisplayMode, setInternalDisplayMode] = React6.useState(displayMode ?? defaultDisplayMode);
2151
+ const [internalTab, setInternalTab] = React6.useState(
1443
2152
  tabs && tabs.length > 0 ? tabs[0].value : ""
1444
2153
  );
1445
2154
  const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
@@ -1447,10 +2156,10 @@ function FullscreenWorkspace({
1447
2156
  const isDisplayModeControlled = displayMode !== void 0;
1448
2157
  const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
1449
2158
  const isTabControlled = activeTab !== void 0 && activeTab !== null;
1450
- const resolvedTabs = React5.useMemo(() => tabs ?? [], [tabs]);
2159
+ const resolvedTabs = React6.useMemo(() => tabs ?? [], [tabs]);
1451
2160
  const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
1452
2161
  const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
1453
- React5.useEffect(() => {
2162
+ React6.useEffect(() => {
1454
2163
  if (resolvedTabs.length > 0) {
1455
2164
  const values = resolvedTabs.map((tab) => tab.value);
1456
2165
  if (!values.includes(currentTab)) {
@@ -1459,7 +2168,7 @@ function FullscreenWorkspace({
1459
2168
  }
1460
2169
  }
1461
2170
  }, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
1462
- React5.useEffect(() => {
2171
+ React6.useEffect(() => {
1463
2172
  if (displayMode !== void 0) {
1464
2173
  setInternalDisplayMode(displayMode);
1465
2174
  }
@@ -1494,7 +2203,7 @@ function FullscreenWorkspace({
1494
2203
  const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
1495
2204
  const showLeftToggle = Boolean(leftPanel);
1496
2205
  const showRightToggle = Boolean(rightPanel);
1497
- return /* @__PURE__ */ jsxs7(
2206
+ return /* @__PURE__ */ jsxs9(
1498
2207
  FullscreenContainer,
1499
2208
  {
1500
2209
  leftCollapsed,
@@ -1502,25 +2211,25 @@ function FullscreenWorkspace({
1502
2211
  className: `tff-svg-container ${className}`.trim(),
1503
2212
  ...rest,
1504
2213
  children: [
1505
- showLeftToggle && /* @__PURE__ */ jsx10(
2214
+ showLeftToggle && /* @__PURE__ */ jsx12(
1506
2215
  LeftToggleButton,
1507
2216
  {
1508
2217
  collapsed: leftCollapsed,
1509
2218
  onClick: handleLeftToggle,
1510
2219
  "aria-label": leftCollapsed ? "Expand left panel" : "Collapse left panel",
1511
- children: leftCollapsed ? /* @__PURE__ */ jsx10(ChevronRight, {}) : /* @__PURE__ */ jsx10(ChevronLeft, {})
2220
+ children: leftCollapsed ? /* @__PURE__ */ jsx12(ChevronRight, {}) : /* @__PURE__ */ jsx12(ChevronLeft, {})
1512
2221
  }
1513
2222
  ),
1514
- showRightToggle && /* @__PURE__ */ jsx10(
2223
+ showRightToggle && /* @__PURE__ */ jsx12(
1515
2224
  RightToggleButton,
1516
2225
  {
1517
2226
  collapsed: rightCollapsed,
1518
2227
  onClick: handleRightToggle,
1519
2228
  "aria-label": rightCollapsed ? "Expand right panel" : "Collapse right panel",
1520
- children: rightCollapsed ? /* @__PURE__ */ jsx10(ChevronLeft, {}) : /* @__PURE__ */ jsx10(ChevronRight, {})
2229
+ children: rightCollapsed ? /* @__PURE__ */ jsx12(ChevronLeft, {}) : /* @__PURE__ */ jsx12(ChevronRight, {})
1521
2230
  }
1522
2231
  ),
1523
- showDisplayModeToggle && /* @__PURE__ */ jsx10(
2232
+ showDisplayModeToggle && /* @__PURE__ */ jsx12(
1524
2233
  DisplayModeToggle,
1525
2234
  {
1526
2235
  mode: currentDisplayMode,
@@ -1529,9 +2238,9 @@ function FullscreenWorkspace({
1529
2238
  children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
1530
2239
  }
1531
2240
  ),
1532
- /* @__PURE__ */ jsxs7(SVGArea, { children: [
1533
- showZoomControls && /* @__PURE__ */ jsxs7(ZoomControls, { children: [
1534
- /* @__PURE__ */ jsx10(
2241
+ /* @__PURE__ */ jsxs9(SVGArea, { children: [
2242
+ showZoomControls && /* @__PURE__ */ jsxs9(ZoomControls, { children: [
2243
+ /* @__PURE__ */ jsx12(
1535
2244
  ZoomButton,
1536
2245
  {
1537
2246
  onClick: onZoomIn,
@@ -1541,7 +2250,7 @@ function FullscreenWorkspace({
1541
2250
  children: "+"
1542
2251
  }
1543
2252
  ),
1544
- /* @__PURE__ */ jsx10(
2253
+ /* @__PURE__ */ jsx12(
1545
2254
  ZoomButton,
1546
2255
  {
1547
2256
  onClick: onZoomOut,
@@ -1551,7 +2260,7 @@ function FullscreenWorkspace({
1551
2260
  children: "-"
1552
2261
  }
1553
2262
  ),
1554
- onResetZoom && /* @__PURE__ */ jsx10(
2263
+ onResetZoom && /* @__PURE__ */ jsx12(
1555
2264
  ZoomButton,
1556
2265
  {
1557
2266
  onClick: onResetZoom,
@@ -1562,33 +2271,33 @@ function FullscreenWorkspace({
1562
2271
  }
1563
2272
  )
1564
2273
  ] }),
1565
- /* @__PURE__ */ jsx10(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ jsxs7(FixedSVGContainer, { className: "svg-container", children: [
2274
+ /* @__PURE__ */ jsx12(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ jsxs9(FixedSVGContainer, { className: "svg-container", children: [
1566
2275
  svgContent,
1567
2276
  overlays
1568
2277
  ] }) })
1569
2278
  ] }),
1570
- /* @__PURE__ */ jsx10(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1571
- /* @__PURE__ */ jsx10(
2279
+ /* @__PURE__ */ jsx12(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
2280
+ /* @__PURE__ */ jsx12(
1572
2281
  PanelTabs,
1573
2282
  {
1574
2283
  value: currentTab,
1575
2284
  onChange: handleTabChangeInternal,
1576
2285
  "aria-label": "Left panel tabs",
1577
- children: resolvedTabs.map((tab) => /* @__PURE__ */ jsx10(Tab, { label: tab.label, value: tab.value }, tab.value))
2286
+ children: resolvedTabs.map((tab) => /* @__PURE__ */ jsx12(Tab, { label: tab.label, value: tab.value }, tab.value))
1578
2287
  }
1579
2288
  ),
1580
- /* @__PURE__ */ jsx10(PanelContent, { children: currentTabContent })
2289
+ /* @__PURE__ */ jsx12(PanelContent, { children: currentTabContent })
1581
2290
  ] }) : leftPanel }),
1582
- /* @__PURE__ */ jsx10(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
1583
- /* @__PURE__ */ jsx10(FooterPanel, { children: footer })
2291
+ /* @__PURE__ */ jsx12(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
2292
+ /* @__PURE__ */ jsx12(FooterPanel, { children: footer })
1584
2293
  ]
1585
2294
  }
1586
2295
  );
1587
2296
  }
1588
2297
 
1589
2298
  // src/theme/ThemeContext.tsx
1590
- import { createContext, useContext, useState as useState6, useEffect as useEffect3 } from "react";
1591
- import { jsx as jsx11 } from "react/jsx-runtime";
2299
+ import { createContext, useContext, useState as useState7, useEffect as useEffect4 } from "react";
2300
+ import { jsx as jsx13 } from "react/jsx-runtime";
1592
2301
  var ThemeContext = createContext(void 0);
1593
2302
  var useTheme = () => {
1594
2303
  const context = useContext(ThemeContext);
@@ -1598,8 +2307,8 @@ var useTheme = () => {
1598
2307
  return context;
1599
2308
  };
1600
2309
  var ThemeProvider = ({ children }) => {
1601
- const [theme, setThemeState] = useState6("modern");
1602
- useEffect3(() => {
2310
+ const [theme, setThemeState] = useState7("modern");
2311
+ useEffect4(() => {
1603
2312
  document.body.className = "";
1604
2313
  document.body.classList.add(`theme-${theme}`);
1605
2314
  document.documentElement.className = "";
@@ -1611,11 +2320,11 @@ var ThemeProvider = ({ children }) => {
1611
2320
  const setTheme = (newTheme) => {
1612
2321
  setThemeState(newTheme);
1613
2322
  };
1614
- return /* @__PURE__ */ jsx11(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
2323
+ return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
1615
2324
  };
1616
2325
 
1617
2326
  // src/theme/ThemeToggle.tsx
1618
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2327
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1619
2328
  var ThemeToggle = ({
1620
2329
  size = "medium",
1621
2330
  position = "top-right",
@@ -1686,15 +2395,15 @@ var ThemeToggle = ({
1686
2395
  transition: "all 0.2s ease",
1687
2396
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
1688
2397
  };
1689
- return /* @__PURE__ */ jsxs8("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
1690
- /* @__PURE__ */ jsx12("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
1691
- /* @__PURE__ */ jsx12("div", { style: toggleStyle, children: /* @__PURE__ */ jsx12("div", { style: thumbStyle }) }),
1692
- /* @__PURE__ */ jsx12("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
2398
+ return /* @__PURE__ */ jsxs10("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
2399
+ /* @__PURE__ */ jsx14("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
2400
+ /* @__PURE__ */ jsx14("div", { style: toggleStyle, children: /* @__PURE__ */ jsx14("div", { style: thumbStyle }) }),
2401
+ /* @__PURE__ */ jsx14("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
1693
2402
  ] });
1694
2403
  };
1695
2404
 
1696
2405
  // src/components/PIDCanvas/PIDCanvas.tsx
1697
- import { useCallback as useCallback7, useState as useState12, useEffect as useEffect10, useRef as useRef5 } from "react";
2406
+ import { useCallback as useCallback7, useState as useState13, useEffect as useEffect11, useRef as useRef5 } from "react";
1698
2407
 
1699
2408
  // src/diagram/symbols/mockSymbolLibrary.ts
1700
2409
  var mockSymbolLibrary = {
@@ -2915,7 +3624,7 @@ function getAvailableSymbols() {
2915
3624
  }
2916
3625
 
2917
3626
  // src/components/PIDCanvas/NodeRenderer.tsx
2918
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
3627
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
2919
3628
  function NodeRenderer({
2920
3629
  nodes: nodes2,
2921
3630
  selectedNodeIds,
@@ -2926,13 +3635,13 @@ function NodeRenderer({
2926
3635
  dragOffset = { x: 0, y: 0 },
2927
3636
  enableDrag = false
2928
3637
  }) {
2929
- return /* @__PURE__ */ jsx13("g", { id: "layer-nodes", children: nodes2.filter((node) => node.visible !== false).map((node) => {
3638
+ return /* @__PURE__ */ jsx15("g", { id: "layer-nodes", children: nodes2.filter((node) => node.visible !== false).map((node) => {
2930
3639
  const symbol = getSymbolDefinition(node.symbolId);
2931
3640
  const isSelected = selectedNodeIds?.has(node.id) ?? false;
2932
3641
  const isDragging = draggingNodeId === node.id;
2933
3642
  if (!symbol) {
2934
- return /* @__PURE__ */ jsxs9("g", { children: [
2935
- /* @__PURE__ */ jsx13(
3643
+ return /* @__PURE__ */ jsxs11("g", { children: [
3644
+ /* @__PURE__ */ jsx15(
2936
3645
  "circle",
2937
3646
  {
2938
3647
  cx: node.transform.x,
@@ -2944,7 +3653,7 @@ function NodeRenderer({
2944
3653
  strokeWidth: "2"
2945
3654
  }
2946
3655
  ),
2947
- /* @__PURE__ */ jsx13(
3656
+ /* @__PURE__ */ jsx15(
2948
3657
  "text",
2949
3658
  {
2950
3659
  x: node.transform.x,
@@ -3001,7 +3710,7 @@ function NodeRenderer({
3001
3710
  };
3002
3711
  const fillColor = node.customColors?.fill ?? getStatusColor(node.status);
3003
3712
  const strokeColor = node.customColors?.stroke ?? "rgb(0, 0, 0)";
3004
- return /* @__PURE__ */ jsxs9(
3713
+ return /* @__PURE__ */ jsxs11(
3005
3714
  "g",
3006
3715
  {
3007
3716
  "data-node-id": node.id,
@@ -3034,7 +3743,7 @@ function NodeRenderer({
3034
3743
  }
3035
3744
  },
3036
3745
  children: [
3037
- isSelected && /* @__PURE__ */ jsx13(
3746
+ isSelected && /* @__PURE__ */ jsx15(
3038
3747
  "rect",
3039
3748
  {
3040
3749
  x: "-5",
@@ -3049,7 +3758,7 @@ function NodeRenderer({
3049
3758
  pointerEvents: "none"
3050
3759
  }
3051
3760
  ),
3052
- /* @__PURE__ */ jsx13(
3761
+ /* @__PURE__ */ jsx15(
3053
3762
  "g",
3054
3763
  {
3055
3764
  dangerouslySetInnerHTML: { __html: symbol.svgContent },
@@ -3057,7 +3766,7 @@ function NodeRenderer({
3057
3766
  style: { pointerEvents: "auto" }
3058
3767
  }
3059
3768
  ),
3060
- /* @__PURE__ */ jsx13(
3769
+ /* @__PURE__ */ jsx15(
3061
3770
  "text",
3062
3771
  {
3063
3772
  x: symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0),
@@ -3078,7 +3787,7 @@ function NodeRenderer({
3078
3787
  }
3079
3788
 
3080
3789
  // src/components/PIDCanvas/PipeRenderer.tsx
3081
- import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3790
+ import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
3082
3791
  function PipeRenderer({
3083
3792
  pipes,
3084
3793
  selectedPipeIds,
@@ -3093,7 +3802,7 @@ function PipeRenderer({
3093
3802
  waypointDragOffset,
3094
3803
  onPipeSegmentClick
3095
3804
  }) {
3096
- return /* @__PURE__ */ jsx14("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
3805
+ return /* @__PURE__ */ jsx16("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
3097
3806
  const isSelected = selectedPipeIds?.has(pipe.id) ?? false;
3098
3807
  const isEditing = enableWaypointEditing && editingPipeId === pipe.id;
3099
3808
  const showEditingControls = enableWaypointEditing && isSelected;
@@ -3112,7 +3821,7 @@ function PipeRenderer({
3112
3821
  const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
3113
3822
  const strokeDasharray = pipeStyle.strokeDasharray;
3114
3823
  const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
3115
- return /* @__PURE__ */ jsxs10(
3824
+ return /* @__PURE__ */ jsxs12(
3116
3825
  "g",
3117
3826
  {
3118
3827
  "data-pipe-id": pipe.id,
@@ -3125,8 +3834,8 @@ function PipeRenderer({
3125
3834
  cursor: onPipeClick ? "pointer" : "default"
3126
3835
  },
3127
3836
  children: [
3128
- !enableWaypointEditing && /* @__PURE__ */ jsxs10(Fragment3, { children: [
3129
- onPipeClick && /* @__PURE__ */ jsx14(
3837
+ !enableWaypointEditing && /* @__PURE__ */ jsxs12(Fragment5, { children: [
3838
+ onPipeClick && /* @__PURE__ */ jsx16(
3130
3839
  "polyline",
3131
3840
  {
3132
3841
  points: pointsString,
@@ -3138,7 +3847,7 @@ function PipeRenderer({
3138
3847
  pointerEvents: "stroke"
3139
3848
  }
3140
3849
  ),
3141
- /* @__PURE__ */ jsx14(
3850
+ /* @__PURE__ */ jsx16(
3142
3851
  "polyline",
3143
3852
  {
3144
3853
  points: pointsString,
@@ -3162,7 +3871,7 @@ function PipeRenderer({
3162
3871
  const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
3163
3872
  const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
3164
3873
  const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
3165
- return /* @__PURE__ */ jsx14(
3874
+ return /* @__PURE__ */ jsx16(
3166
3875
  "circle",
3167
3876
  {
3168
3877
  cx: point.x,
@@ -3199,12 +3908,12 @@ function PipeRenderer({
3199
3908
  `${pipe.id}-point-${idx}`
3200
3909
  );
3201
3910
  }),
3202
- showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ jsx14(Fragment3, { children: displayPoints.slice(0, -1).map((point, idx) => {
3911
+ showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ jsx16(Fragment5, { children: displayPoints.slice(0, -1).map((point, idx) => {
3203
3912
  const nextPoint = displayPoints[idx + 1];
3204
3913
  const midX = (point.x + nextPoint.x) / 2;
3205
3914
  const midY = (point.y + nextPoint.y) / 2;
3206
- return /* @__PURE__ */ jsxs10("g", { children: [
3207
- /* @__PURE__ */ jsx14(
3915
+ return /* @__PURE__ */ jsxs12("g", { children: [
3916
+ /* @__PURE__ */ jsx16(
3208
3917
  "circle",
3209
3918
  {
3210
3919
  cx: midX,
@@ -3220,7 +3929,7 @@ function PipeRenderer({
3220
3929
  }
3221
3930
  }
3222
3931
  ),
3223
- /* @__PURE__ */ jsx14(
3932
+ /* @__PURE__ */ jsx16(
3224
3933
  "circle",
3225
3934
  {
3226
3935
  cx: midX,
@@ -3236,7 +3945,7 @@ function PipeRenderer({
3236
3945
  )
3237
3946
  ] }, `${pipe.id}-segment-${idx}`);
3238
3947
  }) }),
3239
- pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ jsx14(
3948
+ pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ jsx16(
3240
3949
  "text",
3241
3950
  {
3242
3951
  x: pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x + (pipe.labelOffset?.x ?? 0),
@@ -3258,7 +3967,7 @@ function PipeRenderer({
3258
3967
  }
3259
3968
 
3260
3969
  // src/components/PIDCanvas/DataOverlay.tsx
3261
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3970
+ import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
3262
3971
  function DataOverlay({
3263
3972
  nodeId,
3264
3973
  x,
@@ -3278,7 +3987,7 @@ function DataOverlay({
3278
3987
  const offsetX = display?.offsetX ?? 0;
3279
3988
  const offsetY = display?.offsetY ?? 0;
3280
3989
  if (!showValue) {
3281
- return /* @__PURE__ */ jsx15(Fragment4, {});
3990
+ return /* @__PURE__ */ jsx17(Fragment6, {});
3282
3991
  }
3283
3992
  const formatValue = (val) => {
3284
3993
  if (typeof val === "number") {
@@ -3296,9 +4005,14 @@ function DataOverlay({
3296
4005
  fault: { bg: "#dc2626", text: "#ffffff", border: "#b91c1c" },
3297
4006
  off: { bg: "#6b7280", text: "#ffffff", border: "#4b5563" }
3298
4007
  };
3299
- const customColor = telemetry.statusColors?.[value.status];
3300
- const defaultColorSet = defaultStatusColors[value.status] || defaultStatusColors.normal;
3301
- const statusColors = customColor ? { bg: customColor, text: "#ffffff", border: customColor } : defaultColorSet;
4008
+ const getStatusColors = () => {
4009
+ const customColor = telemetry.statusColors?.[value.status];
4010
+ if (customColor) {
4011
+ return { bg: customColor, text: "#ffffff", border: customColor };
4012
+ }
4013
+ return defaultStatusColors[value.status] || defaultStatusColors.normal;
4014
+ };
4015
+ const statusColors = getStatusColors();
3302
4016
  const colors = backgroundColor && backgroundColor !== "status" ? { bg: backgroundColor, text: textColor || "#ffffff", border: backgroundColor } : statusColors;
3303
4017
  const finalTextColor = textColor || colors.text;
3304
4018
  const formattedValue = formatValue(value.value);
@@ -3325,8 +4039,8 @@ function DataOverlay({
3325
4039
  const overlayWidth = 80 * scale;
3326
4040
  const displayX = x + offsetX;
3327
4041
  const displayY = y + offsetY;
3328
- return /* @__PURE__ */ jsxs11("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
3329
- /* @__PURE__ */ jsx15(
4042
+ return /* @__PURE__ */ jsxs13("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
4043
+ /* @__PURE__ */ jsx17(
3330
4044
  "rect",
3331
4045
  {
3332
4046
  x: displayX - overlayWidth / 2,
@@ -3341,7 +4055,7 @@ function DataOverlay({
3341
4055
  filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
3342
4056
  }
3343
4057
  ),
3344
- label && /* @__PURE__ */ jsx15(
4058
+ label && /* @__PURE__ */ jsx17(
3345
4059
  "text",
3346
4060
  {
3347
4061
  x: displayX,
@@ -3354,7 +4068,7 @@ function DataOverlay({
3354
4068
  children: label
3355
4069
  }
3356
4070
  ),
3357
- /* @__PURE__ */ jsx15(
4071
+ /* @__PURE__ */ jsx17(
3358
4072
  "text",
3359
4073
  {
3360
4074
  x: displayX,
@@ -3367,7 +4081,7 @@ function DataOverlay({
3367
4081
  children: displayText
3368
4082
  }
3369
4083
  ),
3370
- showStatus && value.status !== "normal" && /* @__PURE__ */ jsx15(
4084
+ showStatus && value.status !== "normal" && /* @__PURE__ */ jsx17(
3371
4085
  "circle",
3372
4086
  {
3373
4087
  cx: displayX + 35 * scale,
@@ -3375,7 +4089,7 @@ function DataOverlay({
3375
4089
  r: 3 * scale,
3376
4090
  fill: finalTextColor,
3377
4091
  opacity: "0.9",
3378
- children: /* @__PURE__ */ jsx15(
4092
+ children: /* @__PURE__ */ jsx17(
3379
4093
  "animate",
3380
4094
  {
3381
4095
  attributeName: "opacity",
@@ -3386,7 +4100,7 @@ function DataOverlay({
3386
4100
  )
3387
4101
  }
3388
4102
  ),
3389
- value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs11(
4103
+ value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs13(
3390
4104
  "text",
3391
4105
  {
3392
4106
  x: displayX,
@@ -3403,7 +4117,7 @@ function DataOverlay({
3403
4117
  ]
3404
4118
  }
3405
4119
  ),
3406
- hasSparkline && /* @__PURE__ */ jsx15("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx15(
4120
+ hasSparkline && /* @__PURE__ */ jsx17("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx17(
3407
4121
  "path",
3408
4122
  {
3409
4123
  d: sparklinePath,
@@ -3419,8 +4133,8 @@ function DataOverlay({
3419
4133
  }
3420
4134
 
3421
4135
  // src/components/PIDCanvas/PositionPanel.tsx
3422
- import { useState as useState7, useEffect as useEffect4 } from "react";
3423
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
4136
+ import { useState as useState8, useEffect as useEffect5 } from "react";
4137
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
3424
4138
  function PositionPanel({
3425
4139
  selectedNode,
3426
4140
  selectedWaypoint,
@@ -3428,9 +4142,9 @@ function PositionPanel({
3428
4142
  onWaypointPositionChange,
3429
4143
  position = "top-right"
3430
4144
  }) {
3431
- const [x, setX] = useState7("");
3432
- const [y, setY] = useState7("");
3433
- useEffect4(() => {
4145
+ const [x, setX] = useState8("");
4146
+ const [y, setY] = useState8("");
4147
+ useEffect5(() => {
3434
4148
  if (selectedNode) {
3435
4149
  setX(selectedNode.transform.x.toFixed(2));
3436
4150
  setY(selectedNode.transform.y.toFixed(2));
@@ -3489,7 +4203,7 @@ function PositionPanel({
3489
4203
  "bottom-left": { bottom: 10, left: 10 },
3490
4204
  "bottom-right": { bottom: 10, right: 10 }
3491
4205
  };
3492
- return /* @__PURE__ */ jsxs12(
4206
+ return /* @__PURE__ */ jsxs14(
3493
4207
  "div",
3494
4208
  {
3495
4209
  style: {
@@ -3506,11 +4220,11 @@ function PositionPanel({
3506
4220
  fontSize: "13px"
3507
4221
  },
3508
4222
  children: [
3509
- /* @__PURE__ */ jsx16("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
3510
- /* @__PURE__ */ jsxs12("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
3511
- /* @__PURE__ */ jsxs12("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
3512
- /* @__PURE__ */ jsx16("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
3513
- /* @__PURE__ */ jsx16(
4223
+ /* @__PURE__ */ jsx18("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
4224
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
4225
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
4226
+ /* @__PURE__ */ jsx18("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
4227
+ /* @__PURE__ */ jsx18(
3514
4228
  "input",
3515
4229
  {
3516
4230
  type: "number",
@@ -3528,9 +4242,9 @@ function PositionPanel({
3528
4242
  }
3529
4243
  )
3530
4244
  ] }),
3531
- /* @__PURE__ */ jsxs12("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
3532
- /* @__PURE__ */ jsx16("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
3533
- /* @__PURE__ */ jsx16(
4245
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
4246
+ /* @__PURE__ */ jsx18("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
4247
+ /* @__PURE__ */ jsx18(
3534
4248
  "input",
3535
4249
  {
3536
4250
  type: "number",
@@ -3549,14 +4263,14 @@ function PositionPanel({
3549
4263
  )
3550
4264
  ] })
3551
4265
  ] }),
3552
- /* @__PURE__ */ jsx16("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
4266
+ /* @__PURE__ */ jsx18("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
3553
4267
  ]
3554
4268
  }
3555
4269
  );
3556
4270
  }
3557
4271
 
3558
4272
  // src/diagram/hooks/useViewBox.ts
3559
- import { useState as useState8, useCallback as useCallback3, useRef as useRef2, useEffect as useEffect5 } from "react";
4273
+ import { useState as useState9, useCallback as useCallback3, useRef as useRef2, useEffect as useEffect6 } from "react";
3560
4274
  function useViewBox(options) {
3561
4275
  const {
3562
4276
  initialViewBox,
@@ -3567,7 +4281,7 @@ function useViewBox(options) {
3567
4281
  zoomSensitivity = 1e-3,
3568
4282
  allowLeftClickPan = true
3569
4283
  } = options;
3570
- const [viewBox, setViewBox] = useState8(initialViewBox);
4284
+ const [viewBox, setViewBox] = useState9(initialViewBox);
3571
4285
  const svgRef = useRef2(null);
3572
4286
  const isPanningRef = useRef2(false);
3573
4287
  const lastMousePosRef = useRef2({ x: 0, y: 0 });
@@ -3638,7 +4352,7 @@ function useViewBox(options) {
3638
4352
  height: newHeight
3639
4353
  });
3640
4354
  }, [initialViewBox]);
3641
- useEffect5(() => {
4355
+ useEffect6(() => {
3642
4356
  if (!enableZoom || !svgRef.current) return;
3643
4357
  const svg = svgRef.current;
3644
4358
  const handleWheel = (e) => {
@@ -3671,7 +4385,7 @@ function useViewBox(options) {
3671
4385
  svg.addEventListener("wheel", handleWheel, { passive: false });
3672
4386
  return () => svg.removeEventListener("wheel", handleWheel);
3673
4387
  }, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
3674
- useEffect5(() => {
4388
+ useEffect6(() => {
3675
4389
  if (!enablePan || !svgRef.current) return;
3676
4390
  const svg = svgRef.current;
3677
4391
  const handleMouseDown = (e) => {
@@ -3747,7 +4461,7 @@ function useViewBox(options) {
3747
4461
  window.removeEventListener("keyup", handleKeyUp);
3748
4462
  };
3749
4463
  }, [enablePan, allowLeftClickPan]);
3750
- useEffect5(() => {
4464
+ useEffect6(() => {
3751
4465
  if (!svgRef.current) return;
3752
4466
  if (!enablePan && !enableZoom) return;
3753
4467
  const svg = svgRef.current;
@@ -3877,14 +4591,14 @@ function useViewBox(options) {
3877
4591
  }
3878
4592
 
3879
4593
  // src/diagram/hooks/useSelection.ts
3880
- import { useState as useState9, useCallback as useCallback4 } from "react";
4594
+ import { useState as useState10, useCallback as useCallback4 } from "react";
3881
4595
  function useSelection(options = {}) {
3882
4596
  const {
3883
4597
  multiSelect = true,
3884
4598
  initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
3885
4599
  onSelectionChange
3886
4600
  } = options;
3887
- const [selection, setSelection] = useState9(initialSelection);
4601
+ const [selection, setSelection] = useState10(initialSelection);
3888
4602
  const notifyChange = useCallback4(
3889
4603
  (newSelection) => {
3890
4604
  if (onSelectionChange) {
@@ -3982,14 +4696,14 @@ function useSelection(options = {}) {
3982
4696
  }
3983
4697
 
3984
4698
  // src/diagram/hooks/useTelemetry.ts
3985
- import { useState as useState10, useCallback as useCallback5, useEffect as useEffect6, useRef as useRef3 } from "react";
4699
+ import { useState as useState11, useCallback as useCallback5, useEffect as useEffect7, useRef as useRef3 } from "react";
3986
4700
  function useTelemetry(options = {}) {
3987
4701
  const {
3988
4702
  initialBindings = [],
3989
4703
  onTelemetryChange,
3990
4704
  refreshInterval = 0
3991
4705
  } = options;
3992
- const [telemetry, setTelemetry] = useState10(() => {
4706
+ const [telemetry, setTelemetry] = useState11(() => {
3993
4707
  const map = /* @__PURE__ */ new Map();
3994
4708
  initialBindings.forEach((binding) => {
3995
4709
  map.set(binding.nodeId, binding);
@@ -4110,7 +4824,7 @@ function useTelemetry(options = {}) {
4110
4824
  },
4111
4825
  [notifyChange]
4112
4826
  );
4113
- useEffect6(() => {
4827
+ useEffect7(() => {
4114
4828
  if (refreshInterval <= 0) return;
4115
4829
  const intervalId = setInterval(() => {
4116
4830
  notifyChange(telemetryRef.current);
@@ -4128,10 +4842,10 @@ function useTelemetry(options = {}) {
4128
4842
  }
4129
4843
 
4130
4844
  // src/diagram/hooks/useTelemetryStatus.ts
4131
- import { useEffect as useEffect7 } from "react";
4845
+ import { useEffect as useEffect8 } from "react";
4132
4846
  function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
4133
4847
  const { enabled = true, mapStatus } = options;
4134
- useEffect7(() => {
4848
+ useEffect8(() => {
4135
4849
  if (!enabled) return;
4136
4850
  const defaultMapStatus = (telemetryStatus) => {
4137
4851
  switch (telemetryStatus) {
@@ -4170,7 +4884,7 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
4170
4884
  }
4171
4885
 
4172
4886
  // src/diagram/hooks/useDrag.ts
4173
- import { useState as useState11, useCallback as useCallback6, useRef as useRef4, useEffect as useEffect8 } from "react";
4887
+ import { useState as useState12, useCallback as useCallback6, useRef as useRef4, useEffect as useEffect9 } from "react";
4174
4888
  function useDrag(options = {}) {
4175
4889
  const {
4176
4890
  onDragStart,
@@ -4180,13 +4894,13 @@ function useDrag(options = {}) {
4180
4894
  dragThreshold = 3,
4181
4895
  screenToWorld = (x, y) => ({ x, y })
4182
4896
  } = options;
4183
- const [dragState, setDragState] = useState11({
4897
+ const [dragState, setDragState] = useState12({
4184
4898
  isDragging: false,
4185
4899
  startPosition: null,
4186
4900
  offset: { x: 0, y: 0 },
4187
4901
  draggedId: null
4188
4902
  });
4189
- const [isListening, setIsListening] = useState11(false);
4903
+ const [isListening, setIsListening] = useState12(false);
4190
4904
  const dragStartRef = useRef4(null);
4191
4905
  const hasMovedRef = useRef4(false);
4192
4906
  const applySnap = useCallback6(
@@ -4355,7 +5069,7 @@ function useDrag(options = {}) {
4355
5069
  },
4356
5070
  [screenToWorld, applySnap, onDragEnd]
4357
5071
  );
4358
- useEffect8(() => {
5072
+ useEffect9(() => {
4359
5073
  if (!isListening) return;
4360
5074
  document.addEventListener("mousemove", handleMouseMove);
4361
5075
  document.addEventListener("mouseup", handleMouseUp);
@@ -4424,7 +5138,7 @@ function useDrag(options = {}) {
4424
5138
  }
4425
5139
 
4426
5140
  // src/diagram/hooks/useKeyboardShortcuts.ts
4427
- import { useEffect as useEffect9 } from "react";
5141
+ import { useEffect as useEffect10 } from "react";
4428
5142
  function useKeyboardShortcuts(options) {
4429
5143
  const {
4430
5144
  onDelete,
@@ -4435,7 +5149,7 @@ function useKeyboardShortcuts(options) {
4435
5149
  onSelectAll,
4436
5150
  enabled = true
4437
5151
  } = options;
4438
- useEffect9(() => {
5152
+ useEffect10(() => {
4439
5153
  if (!enabled) return;
4440
5154
  const handleKeyDown = (event) => {
4441
5155
  const target = event.target;
@@ -4544,7 +5258,7 @@ function nodeHasPort(node, portId) {
4544
5258
  }
4545
5259
 
4546
5260
  // src/components/PIDCanvas/PIDCanvas.tsx
4547
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
5261
+ import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
4548
5262
  function PIDCanvas({
4549
5263
  diagram,
4550
5264
  className = "",
@@ -4571,21 +5285,21 @@ function PIDCanvas({
4571
5285
  telemetry,
4572
5286
  ...props
4573
5287
  }) {
4574
- const [localDiagram, setLocalDiagram] = useState12(diagram);
4575
- const [dragOverPosition, setDragOverPosition] = useState12(null);
4576
- const [isConnecting, setIsConnecting] = useState12(false);
4577
- const [connectionSource, setConnectionSource] = useState12(null);
4578
- const [connectionSourcePort, setConnectionSourcePort] = useState12(null);
4579
- const [connectionCursor, setConnectionCursor] = useState12(null);
4580
- const [hoveredNode, setHoveredNode] = useState12(null);
4581
- const [hoveredPort, setHoveredPort] = useState12(null);
4582
- const [selectedWaypoint, setSelectedWaypoint] = useState12(null);
5288
+ const [localDiagram, setLocalDiagram] = useState13(diagram);
5289
+ const [dragOverPosition, setDragOverPosition] = useState13(null);
5290
+ const [isConnecting, setIsConnecting] = useState13(false);
5291
+ const [connectionSource, setConnectionSource] = useState13(null);
5292
+ const [connectionSourcePort, setConnectionSourcePort] = useState13(null);
5293
+ const [connectionCursor, setConnectionCursor] = useState13(null);
5294
+ const [hoveredNode, setHoveredNode] = useState13(null);
5295
+ const [hoveredPort, setHoveredPort] = useState13(null);
5296
+ const [selectedWaypoint, setSelectedWaypoint] = useState13(null);
4583
5297
  const historyStack = useRef5([]);
4584
5298
  const redoStack = useRef5([]);
4585
5299
  const isUndoRedoAction = useRef5(false);
4586
5300
  const isInternalChange = useRef5(false);
4587
5301
  const lastInternalDiagram = useRef5(null);
4588
- useEffect10(() => {
5302
+ useEffect11(() => {
4589
5303
  const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
4590
5304
  if (isExternal) {
4591
5305
  setLocalDiagram(diagram);
@@ -4630,7 +5344,7 @@ function PIDCanvas({
4630
5344
  });
4631
5345
  return { minX, minY, maxX, maxY };
4632
5346
  }, [localDiagram.nodes]);
4633
- useEffect10(() => {
5347
+ useEffect11(() => {
4634
5348
  if (onMounted) {
4635
5349
  const controls = {
4636
5350
  fitToContent: (padding = 50) => {
@@ -4709,7 +5423,7 @@ function PIDCanvas({
4709
5423
  isUndoRedoAction.current = false;
4710
5424
  }, 0);
4711
5425
  }, [localDiagram, onDiagramChange]);
4712
- useEffect10(() => {
5426
+ useEffect11(() => {
4713
5427
  const handleKeyDown = (e) => {
4714
5428
  const isCtrlOrCmd = e.ctrlKey || e.metaKey;
4715
5429
  if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
@@ -4726,7 +5440,7 @@ function PIDCanvas({
4726
5440
  window.addEventListener("keydown", handleKeyDown);
4727
5441
  return () => window.removeEventListener("keydown", handleKeyDown);
4728
5442
  }, [undo, redo]);
4729
- useEffect10(() => {
5443
+ useEffect11(() => {
4730
5444
  if (!features.dragNodes) return;
4731
5445
  const handleKeyDown = (e) => {
4732
5446
  if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
@@ -5136,7 +5850,7 @@ function PIDCanvas({
5136
5850
  const viewBox = controlledViewBox;
5137
5851
  const displayDiagram = localDiagram;
5138
5852
  const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
5139
- return /* @__PURE__ */ jsxs13(
5853
+ return /* @__PURE__ */ jsxs15(
5140
5854
  "div",
5141
5855
  {
5142
5856
  ref: containerRef,
@@ -5151,7 +5865,7 @@ function PIDCanvas({
5151
5865
  },
5152
5866
  ...props,
5153
5867
  children: [
5154
- /* @__PURE__ */ jsxs13(
5868
+ /* @__PURE__ */ jsxs15(
5155
5869
  "svg",
5156
5870
  {
5157
5871
  ref: svgRef,
@@ -5170,15 +5884,15 @@ function PIDCanvas({
5170
5884
  onDrop: handleDrop,
5171
5885
  onDragLeave: handleDragLeave,
5172
5886
  children: [
5173
- features.showGrid !== false ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
5174
- /* @__PURE__ */ jsxs13("defs", { children: [
5175
- /* @__PURE__ */ jsx17("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx17("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
5176
- /* @__PURE__ */ jsxs13("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
5177
- /* @__PURE__ */ jsx17("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
5178
- /* @__PURE__ */ jsx17("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
5887
+ features.showGrid !== false ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
5888
+ /* @__PURE__ */ jsxs15("defs", { children: [
5889
+ /* @__PURE__ */ jsx19("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx19("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
5890
+ /* @__PURE__ */ jsxs15("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
5891
+ /* @__PURE__ */ jsx19("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
5892
+ /* @__PURE__ */ jsx19("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
5179
5893
  ] })
5180
5894
  ] }),
5181
- /* @__PURE__ */ jsx17(
5895
+ /* @__PURE__ */ jsx19(
5182
5896
  "rect",
5183
5897
  {
5184
5898
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -5188,7 +5902,7 @@ function PIDCanvas({
5188
5902
  fill: "url(#grid-major)"
5189
5903
  }
5190
5904
  )
5191
- ] }) : /* @__PURE__ */ jsx17(
5905
+ ] }) : /* @__PURE__ */ jsx19(
5192
5906
  "rect",
5193
5907
  {
5194
5908
  x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
@@ -5198,7 +5912,7 @@ function PIDCanvas({
5198
5912
  fill: features.backgroundColor ?? "#ffffff"
5199
5913
  }
5200
5914
  ),
5201
- /* @__PURE__ */ jsx17(
5915
+ /* @__PURE__ */ jsx19(
5202
5916
  PipeRenderer,
5203
5917
  {
5204
5918
  pipes: displayDiagram.pipes,
@@ -5212,12 +5926,12 @@ function PIDCanvas({
5212
5926
  onPipeSegmentClick: void 0
5213
5927
  }
5214
5928
  ),
5215
- /* @__PURE__ */ jsx17(
5929
+ /* @__PURE__ */ jsx19(
5216
5930
  NodeRenderer,
5217
5931
  {
5218
5932
  nodes: displayDiagram.nodes,
5219
5933
  selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
5220
- onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
5934
+ onNodeClick: onNodeClick ? handleNodeClick : selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
5221
5935
  onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
5222
5936
  enableDrag: dragEnabled && !isConnecting,
5223
5937
  onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
@@ -5225,7 +5939,7 @@ function PIDCanvas({
5225
5939
  dragOffset: dragState.offset
5226
5940
  }
5227
5941
  ),
5228
- (features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx17(
5942
+ (features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx19(
5229
5943
  PipeRenderer,
5230
5944
  {
5231
5945
  pipes: displayDiagram.pipes,
@@ -5242,14 +5956,14 @@ function PIDCanvas({
5242
5956
  onPipeSegmentClick: handlePipeSegmentClick
5243
5957
  }
5244
5958
  ),
5245
- telemetryEnabled && telemetry && /* @__PURE__ */ jsx17("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
5959
+ telemetryEnabled && telemetry && /* @__PURE__ */ jsx19("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
5246
5960
  const binding = telemetry.get(node.id);
5247
5961
  if (!binding) return null;
5248
5962
  const symbol = getSymbolDefinition(node.symbolId);
5249
5963
  if (!symbol) return null;
5250
5964
  const overlayX = node.transform.x + symbol.viewBox.width / 2;
5251
5965
  const overlayY = node.transform.y + symbol.viewBox.height + 50;
5252
- return /* @__PURE__ */ jsx17(
5966
+ return /* @__PURE__ */ jsx19(
5253
5967
  DataOverlay,
5254
5968
  {
5255
5969
  nodeId: node.id,
@@ -5261,7 +5975,7 @@ function PIDCanvas({
5261
5975
  `telemetry-${node.id}`
5262
5976
  );
5263
5977
  }) }),
5264
- dragOverPosition && /* @__PURE__ */ jsx17(
5978
+ dragOverPosition && /* @__PURE__ */ jsx19(
5265
5979
  "circle",
5266
5980
  {
5267
5981
  cx: dragOverPosition.x,
@@ -5274,7 +5988,7 @@ function PIDCanvas({
5274
5988
  pointerEvents: "none"
5275
5989
  }
5276
5990
  ),
5277
- isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx17("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
5991
+ isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx19("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
5278
5992
  const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
5279
5993
  if (!sourceNode) return null;
5280
5994
  const symbol = getSymbolDefinition(sourceNode.symbolId);
@@ -5290,8 +6004,8 @@ function PIDCanvas({
5290
6004
  }
5291
6005
  }
5292
6006
  }
5293
- return /* @__PURE__ */ jsxs13(Fragment5, { children: [
5294
- /* @__PURE__ */ jsx17(
6007
+ return /* @__PURE__ */ jsxs15(Fragment7, { children: [
6008
+ /* @__PURE__ */ jsx19(
5295
6009
  "circle",
5296
6010
  {
5297
6011
  cx: lineStartX,
@@ -5303,7 +6017,7 @@ function PIDCanvas({
5303
6017
  opacity: 0.6
5304
6018
  }
5305
6019
  ),
5306
- /* @__PURE__ */ jsx17(
6020
+ /* @__PURE__ */ jsx19(
5307
6021
  "line",
5308
6022
  {
5309
6023
  x1: lineStartX,
@@ -5316,7 +6030,7 @@ function PIDCanvas({
5316
6030
  opacity: 0.8
5317
6031
  }
5318
6032
  ),
5319
- /* @__PURE__ */ jsx17(
6033
+ /* @__PURE__ */ jsx19(
5320
6034
  "circle",
5321
6035
  {
5322
6036
  cx: connectionCursor.x,
@@ -5328,7 +6042,7 @@ function PIDCanvas({
5328
6042
  )
5329
6043
  ] });
5330
6044
  })() }),
5331
- features.connectionMode && /* @__PURE__ */ jsx17("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
6045
+ features.connectionMode && /* @__PURE__ */ jsx19("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
5332
6046
  const symbol = getSymbolDefinition(node.symbolId);
5333
6047
  if (!symbol?.ports) return null;
5334
6048
  return symbol.ports.map((port) => {
@@ -5336,8 +6050,8 @@ function PIDCanvas({
5336
6050
  if (!portPos) return null;
5337
6051
  const isHovered = hoveredPort === port.id && hoveredNode === node.id;
5338
6052
  const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
5339
- return /* @__PURE__ */ jsxs13("g", { children: [
5340
- /* @__PURE__ */ jsx17(
6053
+ return /* @__PURE__ */ jsxs15("g", { children: [
6054
+ /* @__PURE__ */ jsx19(
5341
6055
  "circle",
5342
6056
  {
5343
6057
  cx: portPos.x,
@@ -5370,7 +6084,7 @@ function PIDCanvas({
5370
6084
  }
5371
6085
  }
5372
6086
  ),
5373
- /* @__PURE__ */ jsx17(
6087
+ /* @__PURE__ */ jsx19(
5374
6088
  "circle",
5375
6089
  {
5376
6090
  cx: portPos.x,
@@ -5389,7 +6103,7 @@ function PIDCanvas({
5389
6103
  ]
5390
6104
  }
5391
6105
  ),
5392
- features.dragNodes && /* @__PURE__ */ jsx17(
6106
+ features.dragNodes && /* @__PURE__ */ jsx19(
5393
6107
  PositionPanel,
5394
6108
  {
5395
6109
  selectedNode,
@@ -5409,16 +6123,16 @@ function PIDCanvas({
5409
6123
  }
5410
6124
 
5411
6125
  // src/components/SymbolLibrary/SymbolLibrary.tsx
5412
- import { useState as useState13 } from "react";
5413
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
6126
+ import { useState as useState14 } from "react";
6127
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
5414
6128
  function SymbolLibrary({
5415
6129
  className = "",
5416
6130
  onSymbolDragStart,
5417
6131
  showCategories = true,
5418
6132
  categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
5419
6133
  }) {
5420
- const [selectedCategory, setSelectedCategory] = useState13("all");
5421
- const [searchQuery, setSearchQuery] = useState13("");
6134
+ const [selectedCategory, setSelectedCategory] = useState14("all");
6135
+ const [searchQuery, setSearchQuery] = useState14("");
5422
6136
  const symbolIds = getAvailableSymbols();
5423
6137
  const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
5424
6138
  const categoryMap = {
@@ -5439,9 +6153,9 @@ function SymbolLibrary({
5439
6153
  event.dataTransfer.effectAllowed = "copy";
5440
6154
  onSymbolDragStart?.(symbol.id, event);
5441
6155
  };
5442
- return /* @__PURE__ */ jsxs14("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
5443
- /* @__PURE__ */ jsx18("div", { style: styles.header, children: /* @__PURE__ */ jsx18("h3", { style: styles.title, children: "Symbol Library" }) }),
5444
- /* @__PURE__ */ jsx18("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx18(
6156
+ return /* @__PURE__ */ jsxs16("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
6157
+ /* @__PURE__ */ jsx20("div", { style: styles.header, children: /* @__PURE__ */ jsx20("h3", { style: styles.title, children: "Symbol Library" }) }),
6158
+ /* @__PURE__ */ jsx20("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx20(
5445
6159
  "input",
5446
6160
  {
5447
6161
  type: "text",
@@ -5451,8 +6165,8 @@ function SymbolLibrary({
5451
6165
  style: styles.searchInput
5452
6166
  }
5453
6167
  ) }),
5454
- showCategories && /* @__PURE__ */ jsxs14("div", { style: styles.categories, children: [
5455
- /* @__PURE__ */ jsx18(
6168
+ showCategories && /* @__PURE__ */ jsxs16("div", { style: styles.categories, children: [
6169
+ /* @__PURE__ */ jsx20(
5456
6170
  "button",
5457
6171
  {
5458
6172
  onClick: () => setSelectedCategory("all"),
@@ -5463,7 +6177,7 @@ function SymbolLibrary({
5463
6177
  children: "All"
5464
6178
  }
5465
6179
  ),
5466
- categories.map((category) => /* @__PURE__ */ jsx18(
6180
+ categories.map((category) => /* @__PURE__ */ jsx20(
5467
6181
  "button",
5468
6182
  {
5469
6183
  onClick: () => setSelectedCategory(category),
@@ -5476,7 +6190,7 @@ function SymbolLibrary({
5476
6190
  category
5477
6191
  ))
5478
6192
  ] }),
5479
- /* @__PURE__ */ jsx18("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx18("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs14(
6193
+ /* @__PURE__ */ jsx20("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx20("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs16(
5480
6194
  "div",
5481
6195
  {
5482
6196
  draggable: true,
@@ -5484,15 +6198,15 @@ function SymbolLibrary({
5484
6198
  style: styles.symbolCard,
5485
6199
  title: symbol.metadata?.description || symbol.name,
5486
6200
  children: [
5487
- /* @__PURE__ */ jsx18("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx18(
6201
+ /* @__PURE__ */ jsx20("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx20(
5488
6202
  "svg",
5489
6203
  {
5490
6204
  viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
5491
6205
  style: styles.symbolSvg,
5492
- children: /* @__PURE__ */ jsx18("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
6206
+ children: /* @__PURE__ */ jsx20("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
5493
6207
  }
5494
6208
  ) }),
5495
- /* @__PURE__ */ jsx18("div", { style: styles.symbolName, children: symbol.name })
6209
+ /* @__PURE__ */ jsx20("div", { style: styles.symbolName, children: symbol.name })
5496
6210
  ]
5497
6211
  },
5498
6212
  symbol.id
@@ -5601,7 +6315,7 @@ var styles = {
5601
6315
  };
5602
6316
 
5603
6317
  // src/components/NodeConfigPanel/NodeConfigPanel.tsx
5604
- import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
6318
+ import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
5605
6319
  function NodeConfigPanel({
5606
6320
  node,
5607
6321
  binding,
@@ -5620,15 +6334,15 @@ function NodeConfigPanel({
5620
6334
  padding: "20px",
5621
6335
  ...style
5622
6336
  };
5623
- return /* @__PURE__ */ jsxs15("div", { className, style: defaultStyle, children: [
5624
- /* @__PURE__ */ jsxs15("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
6337
+ return /* @__PURE__ */ jsxs17("div", { className, style: defaultStyle, children: [
6338
+ /* @__PURE__ */ jsxs17("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
5625
6339
  "Configure: ",
5626
6340
  node.id
5627
6341
  ] }),
5628
- /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
5629
- /* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
5630
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
5631
- /* @__PURE__ */ jsx19(
6342
+ /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
6343
+ /* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
6344
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
6345
+ /* @__PURE__ */ jsx21(
5632
6346
  "input",
5633
6347
  {
5634
6348
  type: "text",
@@ -5644,10 +6358,10 @@ function NodeConfigPanel({
5644
6358
  }
5645
6359
  }
5646
6360
  ),
5647
- /* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
5648
- /* @__PURE__ */ jsxs15("div", { children: [
5649
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
5650
- /* @__PURE__ */ jsx19(
6361
+ /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
6362
+ /* @__PURE__ */ jsxs17("div", { children: [
6363
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
6364
+ /* @__PURE__ */ jsx21(
5651
6365
  "input",
5652
6366
  {
5653
6367
  type: "number",
@@ -5668,9 +6382,9 @@ function NodeConfigPanel({
5668
6382
  }
5669
6383
  )
5670
6384
  ] }),
5671
- /* @__PURE__ */ jsxs15("div", { children: [
5672
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
5673
- /* @__PURE__ */ jsx19(
6385
+ /* @__PURE__ */ jsxs17("div", { children: [
6386
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
6387
+ /* @__PURE__ */ jsx21(
5674
6388
  "input",
5675
6389
  {
5676
6390
  type: "number",
@@ -5692,9 +6406,9 @@ function NodeConfigPanel({
5692
6406
  )
5693
6407
  ] })
5694
6408
  ] }),
5695
- /* @__PURE__ */ jsxs15("div", { children: [
5696
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
5697
- /* @__PURE__ */ jsx19(
6409
+ /* @__PURE__ */ jsxs17("div", { children: [
6410
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
6411
+ /* @__PURE__ */ jsx21(
5698
6412
  "input",
5699
6413
  {
5700
6414
  type: "number",
@@ -5714,9 +6428,9 @@ function NodeConfigPanel({
5714
6428
  }
5715
6429
  )
5716
6430
  ] }),
5717
- /* @__PURE__ */ jsxs15("div", { children: [
5718
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
5719
- /* @__PURE__ */ jsx19(
6431
+ /* @__PURE__ */ jsxs17("div", { children: [
6432
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
6433
+ /* @__PURE__ */ jsx21(
5720
6434
  "input",
5721
6435
  {
5722
6436
  type: "number",
@@ -5741,9 +6455,9 @@ function NodeConfigPanel({
5741
6455
  )
5742
6456
  ] })
5743
6457
  ] }),
5744
- /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
5745
- /* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
5746
- !binding ? /* @__PURE__ */ jsx19(
6458
+ /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
6459
+ /* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
6460
+ !binding ? /* @__PURE__ */ jsx21(
5747
6461
  "button",
5748
6462
  {
5749
6463
  onClick: () => {
@@ -5786,9 +6500,9 @@ function NodeConfigPanel({
5786
6500
  },
5787
6501
  children: "+ Add Telemetry"
5788
6502
  }
5789
- ) : /* @__PURE__ */ jsxs15(Fragment6, { children: [
5790
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
5791
- /* @__PURE__ */ jsx19(
6503
+ ) : /* @__PURE__ */ jsxs17(Fragment8, { children: [
6504
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
6505
+ /* @__PURE__ */ jsx21(
5792
6506
  "input",
5793
6507
  {
5794
6508
  type: "number",
@@ -5810,8 +6524,8 @@ function NodeConfigPanel({
5810
6524
  }
5811
6525
  }
5812
6526
  ),
5813
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
5814
- /* @__PURE__ */ jsx19(
6527
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
6528
+ /* @__PURE__ */ jsx21(
5815
6529
  "input",
5816
6530
  {
5817
6531
  type: "text",
@@ -5833,8 +6547,8 @@ function NodeConfigPanel({
5833
6547
  }
5834
6548
  }
5835
6549
  ),
5836
- /* @__PURE__ */ jsxs15("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
5837
- /* @__PURE__ */ jsx19(
6550
+ /* @__PURE__ */ jsxs17("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
6551
+ /* @__PURE__ */ jsx21(
5838
6552
  "input",
5839
6553
  {
5840
6554
  type: "checkbox",
@@ -5856,8 +6570,8 @@ function NodeConfigPanel({
5856
6570
  ),
5857
6571
  "Show Sparkline"
5858
6572
  ] }),
5859
- /* @__PURE__ */ jsxs15("div", { style: { marginTop: "12px" }, children: [
5860
- /* @__PURE__ */ jsx19(
6573
+ /* @__PURE__ */ jsxs17("div", { style: { marginTop: "12px" }, children: [
6574
+ /* @__PURE__ */ jsx21(
5861
6575
  "label",
5862
6576
  {
5863
6577
  style: {
@@ -5869,10 +6583,10 @@ function NodeConfigPanel({
5869
6583
  children: "Telemetry Position Offset:"
5870
6584
  }
5871
6585
  ),
5872
- /* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
5873
- /* @__PURE__ */ jsxs15("div", { children: [
5874
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
5875
- /* @__PURE__ */ jsx19(
6586
+ /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
6587
+ /* @__PURE__ */ jsxs17("div", { children: [
6588
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
6589
+ /* @__PURE__ */ jsx21(
5876
6590
  "input",
5877
6591
  {
5878
6592
  type: "number",
@@ -5899,9 +6613,9 @@ function NodeConfigPanel({
5899
6613
  }
5900
6614
  )
5901
6615
  ] }),
5902
- /* @__PURE__ */ jsxs15("div", { children: [
5903
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
5904
- /* @__PURE__ */ jsx19(
6616
+ /* @__PURE__ */ jsxs17("div", { children: [
6617
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
6618
+ /* @__PURE__ */ jsx21(
5905
6619
  "input",
5906
6620
  {
5907
6621
  type: "number",
@@ -5929,8 +6643,8 @@ function NodeConfigPanel({
5929
6643
  )
5930
6644
  ] })
5931
6645
  ] }),
5932
- /* @__PURE__ */ jsxs15("div", { style: { marginTop: "16px" }, children: [
5933
- /* @__PURE__ */ jsx19(
6646
+ /* @__PURE__ */ jsxs17("div", { style: { marginTop: "16px" }, children: [
6647
+ /* @__PURE__ */ jsx21(
5934
6648
  "label",
5935
6649
  {
5936
6650
  style: {
@@ -5942,10 +6656,10 @@ function NodeConfigPanel({
5942
6656
  children: "Display Colors:"
5943
6657
  }
5944
6658
  ),
5945
- /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
5946
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
5947
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
5948
- /* @__PURE__ */ jsx19(
6659
+ /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
6660
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
6661
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
6662
+ /* @__PURE__ */ jsx21(
5949
6663
  "input",
5950
6664
  {
5951
6665
  type: "color",
@@ -5971,7 +6685,7 @@ function NodeConfigPanel({
5971
6685
  }
5972
6686
  }
5973
6687
  ),
5974
- /* @__PURE__ */ jsx19(
6688
+ /* @__PURE__ */ jsx21(
5975
6689
  "input",
5976
6690
  {
5977
6691
  type: "text",
@@ -6001,10 +6715,10 @@ function NodeConfigPanel({
6001
6715
  )
6002
6716
  ] })
6003
6717
  ] }),
6004
- binding.display?.showSparkline && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
6005
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
6006
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
6007
- /* @__PURE__ */ jsx19(
6718
+ binding.display?.showSparkline && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
6719
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
6720
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
6721
+ /* @__PURE__ */ jsx21(
6008
6722
  "input",
6009
6723
  {
6010
6724
  type: "color",
@@ -6030,7 +6744,7 @@ function NodeConfigPanel({
6030
6744
  }
6031
6745
  }
6032
6746
  ),
6033
- /* @__PURE__ */ jsx19(
6747
+ /* @__PURE__ */ jsx21(
6034
6748
  "input",
6035
6749
  {
6036
6750
  type: "text",
@@ -6060,9 +6774,9 @@ function NodeConfigPanel({
6060
6774
  )
6061
6775
  ] })
6062
6776
  ] }),
6063
- /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
6064
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
6065
- /* @__PURE__ */ jsx19(
6777
+ /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
6778
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
6779
+ /* @__PURE__ */ jsx21(
6066
6780
  "input",
6067
6781
  {
6068
6782
  type: "text",
@@ -6090,20 +6804,20 @@ function NodeConfigPanel({
6090
6804
  }
6091
6805
  }
6092
6806
  ),
6093
- /* @__PURE__ */ jsx19("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
6807
+ /* @__PURE__ */ jsx21("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
6094
6808
  ] })
6095
6809
  ] }),
6096
6810
  " "
6097
6811
  ] })
6098
6812
  ] })
6099
6813
  ] }),
6100
- binding && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
6101
- /* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
6814
+ binding && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
6815
+ /* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
6102
6816
  ["highHigh", "high", "low", "lowLow"].map((key) => {
6103
6817
  const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
6104
- return /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
6105
- /* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
6106
- /* @__PURE__ */ jsx19(
6818
+ return /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
6819
+ /* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
6820
+ /* @__PURE__ */ jsx21(
6107
6821
  "input",
6108
6822
  {
6109
6823
  type: "number",
@@ -6127,8 +6841,8 @@ function NodeConfigPanel({
6127
6841
  ] }, key);
6128
6842
  })
6129
6843
  ] }),
6130
- binding && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
6131
- /* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
6844
+ binding && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
6845
+ /* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
6132
6846
  ["normal", "warning", "alarm", "fault", "off"].map((status) => {
6133
6847
  const defaultColors = {
6134
6848
  normal: "#10b981",
@@ -6138,13 +6852,13 @@ function NodeConfigPanel({
6138
6852
  off: "#6b7280"
6139
6853
  };
6140
6854
  const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
6141
- return /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
6142
- /* @__PURE__ */ jsxs15("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
6855
+ return /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
6856
+ /* @__PURE__ */ jsxs17("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
6143
6857
  label,
6144
6858
  ":"
6145
6859
  ] }),
6146
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
6147
- /* @__PURE__ */ jsx19(
6860
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
6861
+ /* @__PURE__ */ jsx21(
6148
6862
  "input",
6149
6863
  {
6150
6864
  type: "color",
@@ -6165,7 +6879,7 @@ function NodeConfigPanel({
6165
6879
  }
6166
6880
  }
6167
6881
  ),
6168
- /* @__PURE__ */ jsx19(
6882
+ /* @__PURE__ */ jsx21(
6169
6883
  "input",
6170
6884
  {
6171
6885
  type: "text",
@@ -6192,7 +6906,7 @@ function NodeConfigPanel({
6192
6906
  ] }, status);
6193
6907
  })
6194
6908
  ] }),
6195
- /* @__PURE__ */ jsx19("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx19(
6909
+ /* @__PURE__ */ jsx21("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx21(
6196
6910
  "button",
6197
6911
  {
6198
6912
  onClick: onRemove,
@@ -6431,8 +7145,280 @@ var DEFAULT_THRESHOLDS = {
6431
7145
  lowLow: 15
6432
7146
  };
6433
7147
 
7148
+ // src/diagram/schema/DeviceControlBinding.ts
7149
+ function createControlBinding(nodeId, deviceConfig, actions) {
7150
+ const parametersByMode = {};
7151
+ deviceConfig.parameters.forEach((param) => {
7152
+ const modes = param.modes || deviceConfig.modes.map((m) => m.value);
7153
+ modes.forEach((mode) => {
7154
+ if (!parametersByMode[mode]) {
7155
+ parametersByMode[mode] = [];
7156
+ }
7157
+ parametersByMode[mode].push({
7158
+ id: param.id,
7159
+ label: param.label,
7160
+ unit: param.unit,
7161
+ min: param.min,
7162
+ max: param.max,
7163
+ value: param.value,
7164
+ type: typeof param.value === "number" ? "number" : "string"
7165
+ });
7166
+ });
7167
+ });
7168
+ return {
7169
+ nodeId,
7170
+ tag: deviceConfig.tag,
7171
+ deviceName: deviceConfig.name,
7172
+ deviceType: deviceConfig.type,
7173
+ modes: deviceConfig.modes,
7174
+ state: {
7175
+ currentMode: deviceConfig.currentMode,
7176
+ isRunning: deviceConfig.isRunning,
7177
+ status: deviceConfig.status
7178
+ },
7179
+ parameters: parametersByMode,
7180
+ capabilities: deviceConfig.capabilities,
7181
+ actions
7182
+ };
7183
+ }
7184
+
7185
+ // src/hooks/useDeviceControls.ts
7186
+ import { useState as useState15, useCallback as useCallback8 } from "react";
7187
+ function useDeviceControls(initialBindings) {
7188
+ const [controls, setControls] = useState15(() => {
7189
+ const map = /* @__PURE__ */ new Map();
7190
+ if (initialBindings) {
7191
+ initialBindings.forEach((binding) => {
7192
+ map.set(binding.nodeId, binding);
7193
+ });
7194
+ }
7195
+ return map;
7196
+ });
7197
+ const updateControl = useCallback8((nodeId, updates) => {
7198
+ setControls((prev) => {
7199
+ const newMap = new Map(prev);
7200
+ const existing = newMap.get(nodeId);
7201
+ if (existing) {
7202
+ newMap.set(nodeId, { ...existing, ...updates });
7203
+ } else {
7204
+ if ("tag" in updates && "modes" in updates && "state" in updates && "parameters" in updates && "actions" in updates) {
7205
+ newMap.set(nodeId, { nodeId, ...updates });
7206
+ }
7207
+ }
7208
+ return newMap;
7209
+ });
7210
+ }, []);
7211
+ const updateControlBatch = useCallback8((updates) => {
7212
+ setControls((prev) => {
7213
+ const newMap = new Map(prev);
7214
+ Object.entries(updates).forEach(([nodeId, update]) => {
7215
+ const existing = newMap.get(nodeId);
7216
+ if (existing) {
7217
+ newMap.set(nodeId, { ...existing, ...update });
7218
+ }
7219
+ });
7220
+ return newMap;
7221
+ });
7222
+ }, []);
7223
+ const updateDeviceState = useCallback8(
7224
+ (nodeId, stateUpdates) => {
7225
+ setControls((prev) => {
7226
+ const newMap = new Map(prev);
7227
+ const existing = newMap.get(nodeId);
7228
+ if (existing) {
7229
+ newMap.set(nodeId, {
7230
+ ...existing,
7231
+ state: { ...existing.state, ...stateUpdates }
7232
+ });
7233
+ }
7234
+ return newMap;
7235
+ });
7236
+ },
7237
+ []
7238
+ );
7239
+ const updateParameter = useCallback8(
7240
+ (nodeId, parameterId, value) => {
7241
+ setControls((prev) => {
7242
+ const newMap = new Map(prev);
7243
+ const existing = newMap.get(nodeId);
7244
+ if (existing) {
7245
+ const updatedParameters = { ...existing.parameters };
7246
+ Object.keys(updatedParameters).forEach((mode) => {
7247
+ const paramIndex = updatedParameters[mode].findIndex((p) => p.id === parameterId);
7248
+ if (paramIndex !== -1) {
7249
+ updatedParameters[mode] = [...updatedParameters[mode]];
7250
+ updatedParameters[mode][paramIndex] = {
7251
+ ...updatedParameters[mode][paramIndex],
7252
+ value
7253
+ };
7254
+ }
7255
+ });
7256
+ newMap.set(nodeId, {
7257
+ ...existing,
7258
+ parameters: updatedParameters
7259
+ });
7260
+ }
7261
+ return newMap;
7262
+ });
7263
+ },
7264
+ []
7265
+ );
7266
+ const setControlBinding = useCallback8((binding) => {
7267
+ setControls((prev) => {
7268
+ const newMap = new Map(prev);
7269
+ newMap.set(binding.nodeId, binding);
7270
+ return newMap;
7271
+ });
7272
+ }, []);
7273
+ const removeControlBinding = useCallback8((nodeId) => {
7274
+ setControls((prev) => {
7275
+ const newMap = new Map(prev);
7276
+ newMap.delete(nodeId);
7277
+ return newMap;
7278
+ });
7279
+ }, []);
7280
+ const getControlBinding = useCallback8(
7281
+ (nodeId) => {
7282
+ return controls.get(nodeId);
7283
+ },
7284
+ [controls]
7285
+ );
7286
+ const sendModeChange = useCallback8(
7287
+ async (nodeId, mode) => {
7288
+ const binding = controls.get(nodeId);
7289
+ if (!binding) return;
7290
+ updateDeviceState(nodeId, { currentMode: mode });
7291
+ try {
7292
+ await binding.actions.onModeChange?.(mode);
7293
+ updateDeviceState(nodeId, {
7294
+ lastCommandTime: Date.now(),
7295
+ lastCommandResult: { success: true, message: `Mode changed to ${mode}` }
7296
+ });
7297
+ } catch (error) {
7298
+ updateDeviceState(nodeId, {
7299
+ currentMode: binding.state.currentMode,
7300
+ lastCommandResult: {
7301
+ success: false,
7302
+ message: error instanceof Error ? error.message : "Mode change failed"
7303
+ }
7304
+ });
7305
+ }
7306
+ },
7307
+ [controls, updateDeviceState]
7308
+ );
7309
+ const sendParameterChange = useCallback8(
7310
+ async (nodeId, parameterId, value) => {
7311
+ const binding = controls.get(nodeId);
7312
+ if (!binding) return;
7313
+ updateParameter(nodeId, parameterId, value);
7314
+ try {
7315
+ await binding.actions.onParameterChange?.(parameterId, value);
7316
+ updateDeviceState(nodeId, {
7317
+ lastCommandTime: Date.now(),
7318
+ lastCommandResult: { success: true, message: `Parameter ${parameterId} updated` }
7319
+ });
7320
+ } catch (error) {
7321
+ updateDeviceState(nodeId, {
7322
+ lastCommandResult: {
7323
+ success: false,
7324
+ message: error instanceof Error ? error.message : "Parameter change failed"
7325
+ }
7326
+ });
7327
+ }
7328
+ },
7329
+ [controls, updateParameter, updateDeviceState]
7330
+ );
7331
+ const sendStartCommand = useCallback8(
7332
+ async (nodeId) => {
7333
+ const binding = controls.get(nodeId);
7334
+ if (!binding) return;
7335
+ updateDeviceState(nodeId, { isRunning: true, status: "starting" });
7336
+ try {
7337
+ await binding.actions.onStart?.();
7338
+ updateDeviceState(nodeId, {
7339
+ status: "normal",
7340
+ lastCommandTime: Date.now(),
7341
+ lastCommandResult: { success: true, message: "Device started" }
7342
+ });
7343
+ } catch (error) {
7344
+ updateDeviceState(nodeId, {
7345
+ isRunning: false,
7346
+ status: "fault",
7347
+ lastCommandResult: {
7348
+ success: false,
7349
+ message: error instanceof Error ? error.message : "Start failed"
7350
+ }
7351
+ });
7352
+ }
7353
+ },
7354
+ [controls, updateDeviceState]
7355
+ );
7356
+ const sendStopCommand = useCallback8(
7357
+ async (nodeId) => {
7358
+ const binding = controls.get(nodeId);
7359
+ if (!binding) return;
7360
+ updateDeviceState(nodeId, { isRunning: false, status: "stopping" });
7361
+ try {
7362
+ await binding.actions.onStop?.();
7363
+ updateDeviceState(nodeId, {
7364
+ status: "off",
7365
+ lastCommandTime: Date.now(),
7366
+ lastCommandResult: { success: true, message: "Device stopped" }
7367
+ });
7368
+ } catch (error) {
7369
+ updateDeviceState(nodeId, {
7370
+ isRunning: true,
7371
+ status: "fault",
7372
+ lastCommandResult: {
7373
+ success: false,
7374
+ message: error instanceof Error ? error.message : "Stop failed"
7375
+ }
7376
+ });
7377
+ }
7378
+ },
7379
+ [controls, updateDeviceState]
7380
+ );
7381
+ const sendCustomAction = useCallback8(
7382
+ async (nodeId, actionId) => {
7383
+ const binding = controls.get(nodeId);
7384
+ if (!binding) return;
7385
+ try {
7386
+ await binding.actions.onCustomAction?.(actionId);
7387
+ updateDeviceState(nodeId, {
7388
+ lastCommandTime: Date.now(),
7389
+ lastCommandResult: { success: true, message: `Action ${actionId} executed` }
7390
+ });
7391
+ } catch (error) {
7392
+ updateDeviceState(nodeId, {
7393
+ lastCommandResult: {
7394
+ success: false,
7395
+ message: error instanceof Error ? error.message : "Action failed"
7396
+ }
7397
+ });
7398
+ }
7399
+ },
7400
+ [controls, updateDeviceState]
7401
+ );
7402
+ return {
7403
+ controls,
7404
+ updateControl,
7405
+ updateControlBatch,
7406
+ updateDeviceState,
7407
+ updateParameter,
7408
+ setControlBinding,
7409
+ removeControlBinding,
7410
+ getControlBinding,
7411
+ // Command helpers
7412
+ sendModeChange,
7413
+ sendParameterChange,
7414
+ sendStartCommand,
7415
+ sendStopCommand,
7416
+ sendCustomAction
7417
+ };
7418
+ }
7419
+
6434
7420
  // src/diagram/hooks/useSimulation.ts
6435
- import { useEffect as useEffect11 } from "react";
7421
+ import { useEffect as useEffect12 } from "react";
6436
7422
  function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
6437
7423
  const {
6438
7424
  interval = 2e3,
@@ -6443,7 +7429,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
6443
7429
  historyLength = 10,
6444
7430
  generateValue
6445
7431
  } = options;
6446
- useEffect11(() => {
7432
+ useEffect12(() => {
6447
7433
  if (!enabled) return;
6448
7434
  const intervalId = setInterval(() => {
6449
7435
  const updates = [];
@@ -6500,6 +7486,7 @@ export {
6500
7486
  ControlPanel,
6501
7487
  DEFAULT_THRESHOLDS,
6502
7488
  DashboardCard,
7489
+ DeviceControlPanel,
6503
7490
  DisplayModeToggle,
6504
7491
  EquipmentIndicator,
6505
7492
  EquipmentIndicatorWithSparkline,
@@ -6511,6 +7498,7 @@ export {
6511
7498
  LeftToggleButton,
6512
7499
  LegacyValueEntry,
6513
7500
  NodeConfigPanel,
7501
+ NodeControlsPanel,
6514
7502
  PIDCanvas,
6515
7503
  PanelContent,
6516
7504
  PanelTabs,
@@ -6530,6 +7518,7 @@ export {
6530
7518
  ZoomButton,
6531
7519
  ZoomControls,
6532
7520
  calculateThresholdStatus,
7521
+ createControlBinding,
6533
7522
  exampleDiagram,
6534
7523
  exportDiagram,
6535
7524
  generateRoutePoints,
@@ -6542,6 +7531,7 @@ export {
6542
7531
  overlayStyles,
6543
7532
  registerSymbol,
6544
7533
  registerSymbols,
7534
+ useDeviceControls,
6545
7535
  useDrag,
6546
7536
  useKeyboardShortcuts,
6547
7537
  useSelection,