@2112-lab/central-plant 0.3.9 → 0.3.11

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.
@@ -36199,14 +36199,26 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36199
36199
  var deltaZ = newPosition.z - currentPos.z;
36200
36200
  if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
36201
36201
  var success = true;
36202
- if (Math.abs(deltaX) > 0.01) {
36203
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
36204
- }
36205
- if (Math.abs(deltaY) > 0.01) {
36206
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
36207
- }
36208
- if (Math.abs(deltaZ) > 0.01) {
36209
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
36202
+
36203
+ // Suppress per-axis path updates so the pathfinder only runs once,
36204
+ // after ALL axes have been translated, with the final combined position.
36205
+ // Running updatePaths() after each individual axis (the default
36206
+ // translateComponent behaviour) produces intermediate wrong results on
36207
+ // the first drag because no cached fingerprint exists yet to skip them.
36208
+ var wasAutoUpdate = _this6.sceneViewer.shouldUpdatePaths;
36209
+ _this6.sceneViewer.shouldUpdatePaths = false;
36210
+ try {
36211
+ if (Math.abs(deltaX) > 0.01) {
36212
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
36213
+ }
36214
+ if (Math.abs(deltaY) > 0.01) {
36215
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
36216
+ }
36217
+ if (Math.abs(deltaZ) > 0.01) {
36218
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
36219
+ }
36220
+ } finally {
36221
+ _this6.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
36210
36222
  }
36211
36223
  if (!success && _this6.dragStartPosition) {
36212
36224
  console.warn('⚠️ Failed to translate component, reverting position');
@@ -36214,8 +36226,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
36214
36226
  } else {
36215
36227
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
36216
36228
 
36217
- // Auto-update paths if enabled
36218
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
36229
+ // Single path update with the final combined position
36230
+ if (wasAutoUpdate && _this6.sceneViewer) {
36219
36231
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
36220
36232
  try {
36221
36233
  _this6.sceneViewer.updatePaths();
@@ -37716,39 +37728,152 @@ var CentralPlantInternals = /*#__PURE__*/function () {
37716
37728
  return false;
37717
37729
  }
37718
37730
  try {
37731
+ var _this$centralPlant$sc0, _this$centralPlant$sc1, _sceneData$scene2, _sceneData$scene3;
37719
37732
  console.log("\uD83D\uDDD1\uFE0F deleteComponent(): Deleting component ".concat(componentId));
37733
+ var threeScene = (_this$centralPlant$sc0 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc0 === void 0 ? void 0 : _this$centralPlant$sc0.scene;
37734
+ var sceneData = (_this$centralPlant$sc1 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc1 === void 0 ? void 0 : _this$centralPlant$sc1.currentSceneData;
37735
+
37736
+ // Step 1: Resolve the actual Three.js UUID from componentId.
37737
+ // The UI emits object.name (e.g. "Pump (PUMP-1)") as the selection ID, but
37738
+ // sceneData.scene.children stores the raw uuid (e.g. "PUMP-1"). We must
37739
+ // find the live Three.js object first so we can use its true .uuid for all
37740
+ // sceneData lookups.
37741
+ var resolvedUuid = componentId;
37742
+ if (threeScene) {
37743
+ var threeObj = findObjectByHardcodedUuid(threeScene, componentId);
37744
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('uuid', componentId);
37745
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('name', componentId);
37746
+ if (threeObj) {
37747
+ var _threeObj$userData;
37748
+ resolvedUuid = ((_threeObj$userData = threeObj.userData) === null || _threeObj$userData === void 0 ? void 0 : _threeObj$userData.originalUuid) || threeObj.uuid || componentId;
37749
+ console.log("\uD83D\uDD0D deleteComponent(): Resolved UUID \"".concat(componentId, "\" \u2192 \"").concat(resolvedUuid, "\""));
37750
+ }
37751
+ }
37752
+
37753
+ // Step 2: Collect connector UUIDs from sceneData.scene.children FIRST.
37754
+ var connectorIds = new Set();
37755
+ var sceneDataComponentIndex = -1;
37756
+ if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene2 = sceneData.scene) !== null && _sceneData$scene2 !== void 0 && _sceneData$scene2.children) {
37757
+ sceneDataComponentIndex = sceneData.scene.children.findIndex(function (c) {
37758
+ var _c$userData2;
37759
+ return c.uuid === resolvedUuid || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === resolvedUuid;
37760
+ });
37761
+ if (sceneDataComponentIndex !== -1) {
37762
+ var componentNode = sceneData.scene.children[sceneDataComponentIndex];
37763
+ if (Array.isArray(componentNode.children)) {
37764
+ componentNode.children.forEach(function (child) {
37765
+ var _child$userData2;
37766
+ if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector' && child.uuid) {
37767
+ connectorIds.add(child.uuid);
37768
+ }
37769
+ });
37770
+ }
37771
+ }
37772
+ }
37773
+
37774
+ // Fallback: also traverse the live Three.js scene in case sceneData is missing
37775
+ // the component (e.g., dynamically added but not yet synced to sceneData)
37776
+ if (connectorIds.size === 0 && threeScene) {
37777
+ threeScene.traverse(function (obj) {
37778
+ var _obj$userData2, _obj$userData3;
37779
+ if ((obj.uuid === resolvedUuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === resolvedUuid) && ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.objectType) === 'component') {
37780
+ obj.children.forEach(function (child) {
37781
+ var _child$userData3;
37782
+ if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'connector') {
37783
+ connectorIds.add(child.uuid);
37784
+ }
37785
+ });
37786
+ }
37787
+ });
37788
+ }
37789
+ console.log("\uD83D\uDD0C deleteComponent(): Found ".concat(connectorIds.size, " connector(s) for component ").concat(componentId));
37790
+
37791
+ // Step 3: Remove connections from sceneData BEFORE removing from Three.js
37792
+ // so the pathfinder fingerprint reflects the updated state on next updatePaths() call.
37793
+ if (connectorIds.size > 0 && sceneData && Array.isArray(sceneData.connections)) {
37794
+ var beforeCount = sceneData.connections.length;
37795
+ sceneData.connections = sceneData.connections.filter(function (conn) {
37796
+ return !connectorIds.has(conn.from) && !connectorIds.has(conn.to);
37797
+ });
37798
+ var removedCount = beforeCount - sceneData.connections.length;
37799
+ if (removedCount > 0) {
37800
+ console.log("\uD83D\uDD17 deleteComponent(): Removed ".concat(removedCount, " connection(s) for deleted component"));
37801
+ }
37802
+ }
37803
+
37804
+ // Step 4: Remove component from sceneData.scene.children BEFORE removing from Three.js
37805
+ if (sceneDataComponentIndex !== -1) {
37806
+ sceneData.scene.children.splice(sceneDataComponentIndex, 1);
37807
+ console.log('✅ Removed component from sceneData.scene.children');
37808
+ } else if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene3 = sceneData.scene) !== null && _sceneData$scene3 !== void 0 && _sceneData$scene3.children) {
37809
+ // Retry in case findIndex above didn't run (e.g. no sceneData at that point)
37810
+ var retryIndex = sceneData.scene.children.findIndex(function (c) {
37811
+ var _c$userData3;
37812
+ return c.uuid === resolvedUuid || ((_c$userData3 = c.userData) === null || _c$userData3 === void 0 ? void 0 : _c$userData3.originalUuid) === resolvedUuid;
37813
+ });
37814
+ if (retryIndex !== -1) {
37815
+ sceneData.scene.children.splice(retryIndex, 1);
37816
+ console.log('✅ Removed component from sceneData.scene.children (retry)');
37817
+ }
37818
+ }
37720
37819
 
37721
- // Use componentManager to remove the component
37820
+ // Step 5: Remove the component from the Three.js scene
37722
37821
  var success = componentManager.removeComponentFromScene(componentId);
37723
37822
  if (success) {
37724
- // Also remove from scene data if available
37725
- if (this.centralPlant.sceneViewer.sceneOperationsManager && this.centralPlant.sceneViewer.currentSceneData) {
37726
- // Note: componentManager.removeComponentFromScene might not update sceneData
37727
- // We should verify if sceneOperationsManager has a method for this or if we need to manually update
37728
- // For now, assuming componentManager handles the scene object removal,
37729
- // we might need to update the data structure manually if componentManager doesn't.
37730
-
37731
- // Let's implement a safe removal from sceneData here just in case
37732
- var sceneData = this.centralPlant.sceneViewer.currentSceneData;
37733
- if (sceneData.scene && sceneData.scene.children) {
37734
- var index = sceneData.scene.children.findIndex(function (c) {
37735
- var _c$userData2;
37736
- return c.uuid === componentId || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === componentId;
37823
+ // Step 6: Directly remove SEGMENT-* and Gateway objects from Three.js whose
37824
+ // pathFrom/pathTo references one of this component's connectors.
37825
+ // This is surgical cleanup that works regardless of shouldUpdatePaths.
37826
+ if (connectorIds.size > 0 && threeScene) {
37827
+ var objectsToRemove = [];
37828
+ threeScene.traverse(function (obj) {
37829
+ var _obj$uuid, _obj$userData4, _obj$uuid2, _obj$userData5;
37830
+ var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.isDeclared) !== true;
37831
+ var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
37832
+ if (isComputedSegment || isComputedGateway) {
37833
+ var _obj$userData6, _obj$userData7;
37834
+ if (connectorIds.has((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.pathFrom) || connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathTo)) {
37835
+ objectsToRemove.push(obj);
37836
+ }
37837
+ }
37838
+ });
37839
+ objectsToRemove.forEach(function (obj) {
37840
+ var _obj$geometry;
37841
+ var childrenCopy = _toConsumableArray(obj.children);
37842
+ childrenCopy.forEach(function (child) {
37843
+ var _child$geometry;
37844
+ obj.remove(child);
37845
+ (_child$geometry = child.geometry) === null || _child$geometry === void 0 || _child$geometry.dispose();
37846
+ if (Array.isArray(child.material)) {
37847
+ child.material.forEach(function (m) {
37848
+ return m === null || m === void 0 ? void 0 : m.dispose();
37849
+ });
37850
+ } else {
37851
+ var _child$material;
37852
+ (_child$material = child.material) === null || _child$material === void 0 || _child$material.dispose();
37853
+ }
37737
37854
  });
37738
- if (index !== -1) {
37739
- sceneData.scene.children.splice(index, 1);
37740
- console.log('✅ Removed component from sceneData');
37855
+ threeScene.remove(obj);
37856
+ (_obj$geometry = obj.geometry) === null || _obj$geometry === void 0 || _obj$geometry.dispose();
37857
+ if (Array.isArray(obj.material)) {
37858
+ obj.material.forEach(function (m) {
37859
+ return m === null || m === void 0 ? void 0 : m.dispose();
37860
+ });
37861
+ } else {
37862
+ var _obj$material;
37863
+ (_obj$material = obj.material) === null || _obj$material === void 0 || _obj$material.dispose();
37741
37864
  }
37865
+ });
37866
+ if (objectsToRemove.length > 0) {
37867
+ console.log("\uD83D\uDEBF deleteComponent(): Removed ".concat(objectsToRemove.length, " pipe segment(s)/gateway(s) for deleted component"));
37742
37868
  }
37743
37869
  }
37744
37870
 
37745
37871
  // Deselect if the deleted component was selected
37746
- // We check if the selected object matches the deleted ID, OR if the selected object is now detached from the scene (parent is null)
37747
37872
  var transformManager = this.centralPlant.sceneViewer.transformManager;
37748
37873
  if (transformManager && transformManager.selectedObjectForTransform) {
37749
37874
  var _selectedObj$userData;
37750
37875
  var selectedObj = transformManager.selectedObjectForTransform;
37751
- if (selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === componentId || selectedObj.parent === null) {
37876
+ if (selectedObj.uuid === resolvedUuid || selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === resolvedUuid || selectedObj.parent === null) {
37752
37877
  console.log('🎯 deleteComponent(): Deselecting deleted object');
37753
37878
  transformManager.deselectObject();
37754
37879
  }
@@ -37761,14 +37886,6 @@ var CentralPlantInternals = /*#__PURE__*/function () {
37761
37886
  });
37762
37887
  console.log("\uD83D\uDCE1 Emitted 'component-removed' event for ".concat(componentId));
37763
37888
  }
37764
-
37765
- // Auto-update paths if enabled (mirrors behaviour of transformOperationsManager)
37766
- if (this.centralPlant.sceneViewer.shouldUpdatePaths) {
37767
- if (typeof this.centralPlant.sceneViewer.updatePaths === 'function') {
37768
- console.log('🔄 deleteComponent(): Auto-updating paths after delete...');
37769
- this.centralPlant.sceneViewer.updatePaths();
37770
- }
37771
- }
37772
37889
  console.log("\u2705 deleteComponent(): Component ".concat(componentId, " deleted successfully"));
37773
37890
  return true;
37774
37891
  } else {
@@ -37793,8 +37910,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
37793
37910
  }
37794
37911
  var componentIds = [];
37795
37912
  this.centralPlant.sceneViewer.scene.traverse(function (child) {
37796
- var _child$userData2;
37797
- if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
37913
+ var _child$userData4;
37914
+ if (((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) === 'component') {
37798
37915
  componentIds.push(child.uuid || child.userData.originalUuid);
37799
37916
  }
37800
37917
  });
@@ -37829,7 +37946,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
37829
37946
  * Initialize the CentralPlant manager
37830
37947
  *
37831
37948
  * @constructor
37832
- * @version 0.3.9
37949
+ * @version 0.3.11
37833
37950
  * @updated 2025-10-22
37834
37951
  *
37835
37952
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -35,7 +35,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
35
35
  * Initialize the CentralPlant manager
36
36
  *
37
37
  * @constructor
38
- * @version 0.3.9
38
+ * @version 0.3.11
39
39
  * @updated 2025-10-22
40
40
  *
41
41
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -1223,39 +1223,152 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1223
1223
  return false;
1224
1224
  }
1225
1225
  try {
1226
+ var _this$centralPlant$sc0, _this$centralPlant$sc1, _sceneData$scene2, _sceneData$scene3;
1226
1227
  console.log("\uD83D\uDDD1\uFE0F deleteComponent(): Deleting component ".concat(componentId));
1228
+ var threeScene = (_this$centralPlant$sc0 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc0 === void 0 ? void 0 : _this$centralPlant$sc0.scene;
1229
+ var sceneData = (_this$centralPlant$sc1 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc1 === void 0 ? void 0 : _this$centralPlant$sc1.currentSceneData;
1230
+
1231
+ // Step 1: Resolve the actual Three.js UUID from componentId.
1232
+ // The UI emits object.name (e.g. "Pump (PUMP-1)") as the selection ID, but
1233
+ // sceneData.scene.children stores the raw uuid (e.g. "PUMP-1"). We must
1234
+ // find the live Three.js object first so we can use its true .uuid for all
1235
+ // sceneData lookups.
1236
+ var resolvedUuid = componentId;
1237
+ if (threeScene) {
1238
+ var threeObj = nameUtils.findObjectByHardcodedUuid(threeScene, componentId);
1239
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('uuid', componentId);
1240
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('name', componentId);
1241
+ if (threeObj) {
1242
+ var _threeObj$userData;
1243
+ resolvedUuid = ((_threeObj$userData = threeObj.userData) === null || _threeObj$userData === void 0 ? void 0 : _threeObj$userData.originalUuid) || threeObj.uuid || componentId;
1244
+ console.log("\uD83D\uDD0D deleteComponent(): Resolved UUID \"".concat(componentId, "\" \u2192 \"").concat(resolvedUuid, "\""));
1245
+ }
1246
+ }
1247
+
1248
+ // Step 2: Collect connector UUIDs from sceneData.scene.children FIRST.
1249
+ var connectorIds = new Set();
1250
+ var sceneDataComponentIndex = -1;
1251
+ if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene2 = sceneData.scene) !== null && _sceneData$scene2 !== void 0 && _sceneData$scene2.children) {
1252
+ sceneDataComponentIndex = sceneData.scene.children.findIndex(function (c) {
1253
+ var _c$userData2;
1254
+ return c.uuid === resolvedUuid || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === resolvedUuid;
1255
+ });
1256
+ if (sceneDataComponentIndex !== -1) {
1257
+ var componentNode = sceneData.scene.children[sceneDataComponentIndex];
1258
+ if (Array.isArray(componentNode.children)) {
1259
+ componentNode.children.forEach(function (child) {
1260
+ var _child$userData2;
1261
+ if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector' && child.uuid) {
1262
+ connectorIds.add(child.uuid);
1263
+ }
1264
+ });
1265
+ }
1266
+ }
1267
+ }
1268
+
1269
+ // Fallback: also traverse the live Three.js scene in case sceneData is missing
1270
+ // the component (e.g., dynamically added but not yet synced to sceneData)
1271
+ if (connectorIds.size === 0 && threeScene) {
1272
+ threeScene.traverse(function (obj) {
1273
+ var _obj$userData2, _obj$userData3;
1274
+ if ((obj.uuid === resolvedUuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === resolvedUuid) && ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.objectType) === 'component') {
1275
+ obj.children.forEach(function (child) {
1276
+ var _child$userData3;
1277
+ if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'connector') {
1278
+ connectorIds.add(child.uuid);
1279
+ }
1280
+ });
1281
+ }
1282
+ });
1283
+ }
1284
+ console.log("\uD83D\uDD0C deleteComponent(): Found ".concat(connectorIds.size, " connector(s) for component ").concat(componentId));
1285
+
1286
+ // Step 3: Remove connections from sceneData BEFORE removing from Three.js
1287
+ // so the pathfinder fingerprint reflects the updated state on next updatePaths() call.
1288
+ if (connectorIds.size > 0 && sceneData && Array.isArray(sceneData.connections)) {
1289
+ var beforeCount = sceneData.connections.length;
1290
+ sceneData.connections = sceneData.connections.filter(function (conn) {
1291
+ return !connectorIds.has(conn.from) && !connectorIds.has(conn.to);
1292
+ });
1293
+ var removedCount = beforeCount - sceneData.connections.length;
1294
+ if (removedCount > 0) {
1295
+ console.log("\uD83D\uDD17 deleteComponent(): Removed ".concat(removedCount, " connection(s) for deleted component"));
1296
+ }
1297
+ }
1298
+
1299
+ // Step 4: Remove component from sceneData.scene.children BEFORE removing from Three.js
1300
+ if (sceneDataComponentIndex !== -1) {
1301
+ sceneData.scene.children.splice(sceneDataComponentIndex, 1);
1302
+ console.log('✅ Removed component from sceneData.scene.children');
1303
+ } else if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene3 = sceneData.scene) !== null && _sceneData$scene3 !== void 0 && _sceneData$scene3.children) {
1304
+ // Retry in case findIndex above didn't run (e.g. no sceneData at that point)
1305
+ var retryIndex = sceneData.scene.children.findIndex(function (c) {
1306
+ var _c$userData3;
1307
+ return c.uuid === resolvedUuid || ((_c$userData3 = c.userData) === null || _c$userData3 === void 0 ? void 0 : _c$userData3.originalUuid) === resolvedUuid;
1308
+ });
1309
+ if (retryIndex !== -1) {
1310
+ sceneData.scene.children.splice(retryIndex, 1);
1311
+ console.log('✅ Removed component from sceneData.scene.children (retry)');
1312
+ }
1313
+ }
1227
1314
 
1228
- // Use componentManager to remove the component
1315
+ // Step 5: Remove the component from the Three.js scene
1229
1316
  var success = componentManager.removeComponentFromScene(componentId);
1230
1317
  if (success) {
1231
- // Also remove from scene data if available
1232
- if (this.centralPlant.sceneViewer.sceneOperationsManager && this.centralPlant.sceneViewer.currentSceneData) {
1233
- // Note: componentManager.removeComponentFromScene might not update sceneData
1234
- // We should verify if sceneOperationsManager has a method for this or if we need to manually update
1235
- // For now, assuming componentManager handles the scene object removal,
1236
- // we might need to update the data structure manually if componentManager doesn't.
1237
-
1238
- // Let's implement a safe removal from sceneData here just in case
1239
- var sceneData = this.centralPlant.sceneViewer.currentSceneData;
1240
- if (sceneData.scene && sceneData.scene.children) {
1241
- var index = sceneData.scene.children.findIndex(function (c) {
1242
- var _c$userData2;
1243
- return c.uuid === componentId || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === componentId;
1318
+ // Step 6: Directly remove SEGMENT-* and Gateway objects from Three.js whose
1319
+ // pathFrom/pathTo references one of this component's connectors.
1320
+ // This is surgical cleanup that works regardless of shouldUpdatePaths.
1321
+ if (connectorIds.size > 0 && threeScene) {
1322
+ var objectsToRemove = [];
1323
+ threeScene.traverse(function (obj) {
1324
+ var _obj$uuid, _obj$userData4, _obj$uuid2, _obj$userData5;
1325
+ var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.isDeclared) !== true;
1326
+ var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
1327
+ if (isComputedSegment || isComputedGateway) {
1328
+ var _obj$userData6, _obj$userData7;
1329
+ if (connectorIds.has((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.pathFrom) || connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathTo)) {
1330
+ objectsToRemove.push(obj);
1331
+ }
1332
+ }
1333
+ });
1334
+ objectsToRemove.forEach(function (obj) {
1335
+ var _obj$geometry;
1336
+ var childrenCopy = _rollupPluginBabelHelpers.toConsumableArray(obj.children);
1337
+ childrenCopy.forEach(function (child) {
1338
+ var _child$geometry;
1339
+ obj.remove(child);
1340
+ (_child$geometry = child.geometry) === null || _child$geometry === void 0 || _child$geometry.dispose();
1341
+ if (Array.isArray(child.material)) {
1342
+ child.material.forEach(function (m) {
1343
+ return m === null || m === void 0 ? void 0 : m.dispose();
1344
+ });
1345
+ } else {
1346
+ var _child$material;
1347
+ (_child$material = child.material) === null || _child$material === void 0 || _child$material.dispose();
1348
+ }
1244
1349
  });
1245
- if (index !== -1) {
1246
- sceneData.scene.children.splice(index, 1);
1247
- console.log('✅ Removed component from sceneData');
1350
+ threeScene.remove(obj);
1351
+ (_obj$geometry = obj.geometry) === null || _obj$geometry === void 0 || _obj$geometry.dispose();
1352
+ if (Array.isArray(obj.material)) {
1353
+ obj.material.forEach(function (m) {
1354
+ return m === null || m === void 0 ? void 0 : m.dispose();
1355
+ });
1356
+ } else {
1357
+ var _obj$material;
1358
+ (_obj$material = obj.material) === null || _obj$material === void 0 || _obj$material.dispose();
1248
1359
  }
1360
+ });
1361
+ if (objectsToRemove.length > 0) {
1362
+ console.log("\uD83D\uDEBF deleteComponent(): Removed ".concat(objectsToRemove.length, " pipe segment(s)/gateway(s) for deleted component"));
1249
1363
  }
1250
1364
  }
1251
1365
 
1252
1366
  // Deselect if the deleted component was selected
1253
- // We check if the selected object matches the deleted ID, OR if the selected object is now detached from the scene (parent is null)
1254
1367
  var transformManager = this.centralPlant.sceneViewer.transformManager;
1255
1368
  if (transformManager && transformManager.selectedObjectForTransform) {
1256
1369
  var _selectedObj$userData;
1257
1370
  var selectedObj = transformManager.selectedObjectForTransform;
1258
- if (selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === componentId || selectedObj.parent === null) {
1371
+ if (selectedObj.uuid === resolvedUuid || selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === resolvedUuid || selectedObj.parent === null) {
1259
1372
  console.log('🎯 deleteComponent(): Deselecting deleted object');
1260
1373
  transformManager.deselectObject();
1261
1374
  }
@@ -1268,14 +1381,6 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1268
1381
  });
1269
1382
  console.log("\uD83D\uDCE1 Emitted 'component-removed' event for ".concat(componentId));
1270
1383
  }
1271
-
1272
- // Auto-update paths if enabled (mirrors behaviour of transformOperationsManager)
1273
- if (this.centralPlant.sceneViewer.shouldUpdatePaths) {
1274
- if (typeof this.centralPlant.sceneViewer.updatePaths === 'function') {
1275
- console.log('🔄 deleteComponent(): Auto-updating paths after delete...');
1276
- this.centralPlant.sceneViewer.updatePaths();
1277
- }
1278
- }
1279
1384
  console.log("\u2705 deleteComponent(): Component ".concat(componentId, " deleted successfully"));
1280
1385
  return true;
1281
1386
  } else {
@@ -1300,8 +1405,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1300
1405
  }
1301
1406
  var componentIds = [];
1302
1407
  this.centralPlant.sceneViewer.scene.traverse(function (child) {
1303
- var _child$userData2;
1304
- if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
1408
+ var _child$userData4;
1409
+ if (((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) === 'component') {
1305
1410
  componentIds.push(child.uuid || child.userData.originalUuid);
1306
1411
  }
1307
1412
  });
@@ -882,14 +882,26 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
882
882
  var deltaZ = newPosition.z - currentPos.z;
883
883
  if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
884
884
  var success = true;
885
- if (Math.abs(deltaX) > 0.01) {
886
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
887
- }
888
- if (Math.abs(deltaY) > 0.01) {
889
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
890
- }
891
- if (Math.abs(deltaZ) > 0.01) {
892
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
885
+
886
+ // Suppress per-axis path updates so the pathfinder only runs once,
887
+ // after ALL axes have been translated, with the final combined position.
888
+ // Running updatePaths() after each individual axis (the default
889
+ // translateComponent behaviour) produces intermediate wrong results on
890
+ // the first drag because no cached fingerprint exists yet to skip them.
891
+ var wasAutoUpdate = _this6.sceneViewer.shouldUpdatePaths;
892
+ _this6.sceneViewer.shouldUpdatePaths = false;
893
+ try {
894
+ if (Math.abs(deltaX) > 0.01) {
895
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
896
+ }
897
+ if (Math.abs(deltaY) > 0.01) {
898
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
899
+ }
900
+ if (Math.abs(deltaZ) > 0.01) {
901
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
902
+ }
903
+ } finally {
904
+ _this6.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
893
905
  }
894
906
  if (!success && _this6.dragStartPosition) {
895
907
  console.warn('⚠️ Failed to translate component, reverting position');
@@ -897,8 +909,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
897
909
  } else {
898
910
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
899
911
 
900
- // Auto-update paths if enabled
901
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
912
+ // Single path update with the final combined position
913
+ if (wasAutoUpdate && _this6.sceneViewer) {
902
914
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
903
915
  try {
904
916
  _this6.sceneViewer.updatePaths();
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
31
31
  * Initialize the CentralPlant manager
32
32
  *
33
33
  * @constructor
34
- * @version 0.3.9
34
+ * @version 0.3.11
35
35
  * @updated 2025-10-22
36
36
  *
37
37
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -1,4 +1,4 @@
1
- import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
  import { CentralPlantValidator } from './centralPlantValidator.js';
4
4
  import { createTransformControls } from '../managers/controls/transformControlsManager.js';
@@ -1199,39 +1199,152 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1199
1199
  return false;
1200
1200
  }
1201
1201
  try {
1202
+ var _this$centralPlant$sc0, _this$centralPlant$sc1, _sceneData$scene2, _sceneData$scene3;
1202
1203
  console.log("\uD83D\uDDD1\uFE0F deleteComponent(): Deleting component ".concat(componentId));
1204
+ var threeScene = (_this$centralPlant$sc0 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc0 === void 0 ? void 0 : _this$centralPlant$sc0.scene;
1205
+ var sceneData = (_this$centralPlant$sc1 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc1 === void 0 ? void 0 : _this$centralPlant$sc1.currentSceneData;
1206
+
1207
+ // Step 1: Resolve the actual Three.js UUID from componentId.
1208
+ // The UI emits object.name (e.g. "Pump (PUMP-1)") as the selection ID, but
1209
+ // sceneData.scene.children stores the raw uuid (e.g. "PUMP-1"). We must
1210
+ // find the live Three.js object first so we can use its true .uuid for all
1211
+ // sceneData lookups.
1212
+ var resolvedUuid = componentId;
1213
+ if (threeScene) {
1214
+ var threeObj = findObjectByHardcodedUuid(threeScene, componentId);
1215
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('uuid', componentId);
1216
+ if (!threeObj) threeObj = threeScene.getObjectByProperty('name', componentId);
1217
+ if (threeObj) {
1218
+ var _threeObj$userData;
1219
+ resolvedUuid = ((_threeObj$userData = threeObj.userData) === null || _threeObj$userData === void 0 ? void 0 : _threeObj$userData.originalUuid) || threeObj.uuid || componentId;
1220
+ console.log("\uD83D\uDD0D deleteComponent(): Resolved UUID \"".concat(componentId, "\" \u2192 \"").concat(resolvedUuid, "\""));
1221
+ }
1222
+ }
1223
+
1224
+ // Step 2: Collect connector UUIDs from sceneData.scene.children FIRST.
1225
+ var connectorIds = new Set();
1226
+ var sceneDataComponentIndex = -1;
1227
+ if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene2 = sceneData.scene) !== null && _sceneData$scene2 !== void 0 && _sceneData$scene2.children) {
1228
+ sceneDataComponentIndex = sceneData.scene.children.findIndex(function (c) {
1229
+ var _c$userData2;
1230
+ return c.uuid === resolvedUuid || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === resolvedUuid;
1231
+ });
1232
+ if (sceneDataComponentIndex !== -1) {
1233
+ var componentNode = sceneData.scene.children[sceneDataComponentIndex];
1234
+ if (Array.isArray(componentNode.children)) {
1235
+ componentNode.children.forEach(function (child) {
1236
+ var _child$userData2;
1237
+ if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector' && child.uuid) {
1238
+ connectorIds.add(child.uuid);
1239
+ }
1240
+ });
1241
+ }
1242
+ }
1243
+ }
1244
+
1245
+ // Fallback: also traverse the live Three.js scene in case sceneData is missing
1246
+ // the component (e.g., dynamically added but not yet synced to sceneData)
1247
+ if (connectorIds.size === 0 && threeScene) {
1248
+ threeScene.traverse(function (obj) {
1249
+ var _obj$userData2, _obj$userData3;
1250
+ if ((obj.uuid === resolvedUuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === resolvedUuid) && ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.objectType) === 'component') {
1251
+ obj.children.forEach(function (child) {
1252
+ var _child$userData3;
1253
+ if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'connector') {
1254
+ connectorIds.add(child.uuid);
1255
+ }
1256
+ });
1257
+ }
1258
+ });
1259
+ }
1260
+ console.log("\uD83D\uDD0C deleteComponent(): Found ".concat(connectorIds.size, " connector(s) for component ").concat(componentId));
1261
+
1262
+ // Step 3: Remove connections from sceneData BEFORE removing from Three.js
1263
+ // so the pathfinder fingerprint reflects the updated state on next updatePaths() call.
1264
+ if (connectorIds.size > 0 && sceneData && Array.isArray(sceneData.connections)) {
1265
+ var beforeCount = sceneData.connections.length;
1266
+ sceneData.connections = sceneData.connections.filter(function (conn) {
1267
+ return !connectorIds.has(conn.from) && !connectorIds.has(conn.to);
1268
+ });
1269
+ var removedCount = beforeCount - sceneData.connections.length;
1270
+ if (removedCount > 0) {
1271
+ console.log("\uD83D\uDD17 deleteComponent(): Removed ".concat(removedCount, " connection(s) for deleted component"));
1272
+ }
1273
+ }
1274
+
1275
+ // Step 4: Remove component from sceneData.scene.children BEFORE removing from Three.js
1276
+ if (sceneDataComponentIndex !== -1) {
1277
+ sceneData.scene.children.splice(sceneDataComponentIndex, 1);
1278
+ console.log('✅ Removed component from sceneData.scene.children');
1279
+ } else if (sceneData !== null && sceneData !== void 0 && (_sceneData$scene3 = sceneData.scene) !== null && _sceneData$scene3 !== void 0 && _sceneData$scene3.children) {
1280
+ // Retry in case findIndex above didn't run (e.g. no sceneData at that point)
1281
+ var retryIndex = sceneData.scene.children.findIndex(function (c) {
1282
+ var _c$userData3;
1283
+ return c.uuid === resolvedUuid || ((_c$userData3 = c.userData) === null || _c$userData3 === void 0 ? void 0 : _c$userData3.originalUuid) === resolvedUuid;
1284
+ });
1285
+ if (retryIndex !== -1) {
1286
+ sceneData.scene.children.splice(retryIndex, 1);
1287
+ console.log('✅ Removed component from sceneData.scene.children (retry)');
1288
+ }
1289
+ }
1203
1290
 
1204
- // Use componentManager to remove the component
1291
+ // Step 5: Remove the component from the Three.js scene
1205
1292
  var success = componentManager.removeComponentFromScene(componentId);
1206
1293
  if (success) {
1207
- // Also remove from scene data if available
1208
- if (this.centralPlant.sceneViewer.sceneOperationsManager && this.centralPlant.sceneViewer.currentSceneData) {
1209
- // Note: componentManager.removeComponentFromScene might not update sceneData
1210
- // We should verify if sceneOperationsManager has a method for this or if we need to manually update
1211
- // For now, assuming componentManager handles the scene object removal,
1212
- // we might need to update the data structure manually if componentManager doesn't.
1213
-
1214
- // Let's implement a safe removal from sceneData here just in case
1215
- var sceneData = this.centralPlant.sceneViewer.currentSceneData;
1216
- if (sceneData.scene && sceneData.scene.children) {
1217
- var index = sceneData.scene.children.findIndex(function (c) {
1218
- var _c$userData2;
1219
- return c.uuid === componentId || ((_c$userData2 = c.userData) === null || _c$userData2 === void 0 ? void 0 : _c$userData2.originalUuid) === componentId;
1294
+ // Step 6: Directly remove SEGMENT-* and Gateway objects from Three.js whose
1295
+ // pathFrom/pathTo references one of this component's connectors.
1296
+ // This is surgical cleanup that works regardless of shouldUpdatePaths.
1297
+ if (connectorIds.size > 0 && threeScene) {
1298
+ var objectsToRemove = [];
1299
+ threeScene.traverse(function (obj) {
1300
+ var _obj$uuid, _obj$userData4, _obj$uuid2, _obj$userData5;
1301
+ var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.isDeclared) !== true;
1302
+ var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
1303
+ if (isComputedSegment || isComputedGateway) {
1304
+ var _obj$userData6, _obj$userData7;
1305
+ if (connectorIds.has((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.pathFrom) || connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathTo)) {
1306
+ objectsToRemove.push(obj);
1307
+ }
1308
+ }
1309
+ });
1310
+ objectsToRemove.forEach(function (obj) {
1311
+ var _obj$geometry;
1312
+ var childrenCopy = _toConsumableArray(obj.children);
1313
+ childrenCopy.forEach(function (child) {
1314
+ var _child$geometry;
1315
+ obj.remove(child);
1316
+ (_child$geometry = child.geometry) === null || _child$geometry === void 0 || _child$geometry.dispose();
1317
+ if (Array.isArray(child.material)) {
1318
+ child.material.forEach(function (m) {
1319
+ return m === null || m === void 0 ? void 0 : m.dispose();
1320
+ });
1321
+ } else {
1322
+ var _child$material;
1323
+ (_child$material = child.material) === null || _child$material === void 0 || _child$material.dispose();
1324
+ }
1220
1325
  });
1221
- if (index !== -1) {
1222
- sceneData.scene.children.splice(index, 1);
1223
- console.log('✅ Removed component from sceneData');
1326
+ threeScene.remove(obj);
1327
+ (_obj$geometry = obj.geometry) === null || _obj$geometry === void 0 || _obj$geometry.dispose();
1328
+ if (Array.isArray(obj.material)) {
1329
+ obj.material.forEach(function (m) {
1330
+ return m === null || m === void 0 ? void 0 : m.dispose();
1331
+ });
1332
+ } else {
1333
+ var _obj$material;
1334
+ (_obj$material = obj.material) === null || _obj$material === void 0 || _obj$material.dispose();
1224
1335
  }
1336
+ });
1337
+ if (objectsToRemove.length > 0) {
1338
+ console.log("\uD83D\uDEBF deleteComponent(): Removed ".concat(objectsToRemove.length, " pipe segment(s)/gateway(s) for deleted component"));
1225
1339
  }
1226
1340
  }
1227
1341
 
1228
1342
  // Deselect if the deleted component was selected
1229
- // We check if the selected object matches the deleted ID, OR if the selected object is now detached from the scene (parent is null)
1230
1343
  var transformManager = this.centralPlant.sceneViewer.transformManager;
1231
1344
  if (transformManager && transformManager.selectedObjectForTransform) {
1232
1345
  var _selectedObj$userData;
1233
1346
  var selectedObj = transformManager.selectedObjectForTransform;
1234
- if (selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === componentId || selectedObj.parent === null) {
1347
+ if (selectedObj.uuid === resolvedUuid || selectedObj.uuid === componentId || selectedObj.name === componentId || ((_selectedObj$userData = selectedObj.userData) === null || _selectedObj$userData === void 0 ? void 0 : _selectedObj$userData.originalUuid) === resolvedUuid || selectedObj.parent === null) {
1235
1348
  console.log('🎯 deleteComponent(): Deselecting deleted object');
1236
1349
  transformManager.deselectObject();
1237
1350
  }
@@ -1244,14 +1357,6 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1244
1357
  });
1245
1358
  console.log("\uD83D\uDCE1 Emitted 'component-removed' event for ".concat(componentId));
1246
1359
  }
1247
-
1248
- // Auto-update paths if enabled (mirrors behaviour of transformOperationsManager)
1249
- if (this.centralPlant.sceneViewer.shouldUpdatePaths) {
1250
- if (typeof this.centralPlant.sceneViewer.updatePaths === 'function') {
1251
- console.log('🔄 deleteComponent(): Auto-updating paths after delete...');
1252
- this.centralPlant.sceneViewer.updatePaths();
1253
- }
1254
- }
1255
1360
  console.log("\u2705 deleteComponent(): Component ".concat(componentId, " deleted successfully"));
1256
1361
  return true;
1257
1362
  } else {
@@ -1276,8 +1381,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
1276
1381
  }
1277
1382
  var componentIds = [];
1278
1383
  this.centralPlant.sceneViewer.scene.traverse(function (child) {
1279
- var _child$userData2;
1280
- if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
1384
+ var _child$userData4;
1385
+ if (((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) === 'component') {
1281
1386
  componentIds.push(child.uuid || child.userData.originalUuid);
1282
1387
  }
1283
1388
  });
@@ -858,14 +858,26 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
858
858
  var deltaZ = newPosition.z - currentPos.z;
859
859
  if ((_this6$sceneViewer2 = _this6.sceneViewer) !== null && _this6$sceneViewer2 !== void 0 && _this6$sceneViewer2.centralPlant && component.uuid) {
860
860
  var success = true;
861
- if (Math.abs(deltaX) > 0.01) {
862
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
863
- }
864
- if (Math.abs(deltaY) > 0.01) {
865
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
866
- }
867
- if (Math.abs(deltaZ) > 0.01) {
868
- success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
861
+
862
+ // Suppress per-axis path updates so the pathfinder only runs once,
863
+ // after ALL axes have been translated, with the final combined position.
864
+ // Running updatePaths() after each individual axis (the default
865
+ // translateComponent behaviour) produces intermediate wrong results on
866
+ // the first drag because no cached fingerprint exists yet to skip them.
867
+ var wasAutoUpdate = _this6.sceneViewer.shouldUpdatePaths;
868
+ _this6.sceneViewer.shouldUpdatePaths = false;
869
+ try {
870
+ if (Math.abs(deltaX) > 0.01) {
871
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'x', deltaX);
872
+ }
873
+ if (Math.abs(deltaY) > 0.01) {
874
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'y', deltaY);
875
+ }
876
+ if (Math.abs(deltaZ) > 0.01) {
877
+ success = success && _this6.sceneViewer.centralPlant.translate(component.uuid, 'z', deltaZ);
878
+ }
879
+ } finally {
880
+ _this6.sceneViewer.shouldUpdatePaths = wasAutoUpdate;
869
881
  }
870
882
  if (!success && _this6.dragStartPosition) {
871
883
  console.warn('⚠️ Failed to translate component, reverting position');
@@ -873,8 +885,8 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
873
885
  } else {
874
886
  console.log("\u2705 Component ".concat(component.name, " translated successfully in 2D viewport"));
875
887
 
876
- // Auto-update paths if enabled
877
- if (_this6.sceneViewer && _this6.sceneViewer.shouldUpdatePaths) {
888
+ // Single path update with the final combined position
889
+ if (wasAutoUpdate && _this6.sceneViewer) {
878
890
  console.log('🔄 Auto-updating paths after 2D viewport translation...');
879
891
  try {
880
892
  _this6.sceneViewer.updatePaths();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/src/index.js",