@2112-lab/central-plant 0.1.85 → 0.1.87
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/bundle/index.js +156 -44
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/sceneViewer.js +6 -0
- package/dist/cjs/src/managers/controls/transformControlsManager.js +44 -15
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +99 -28
- package/dist/cjs/src/managers/scene/sceneExportManager.js +6 -0
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/sceneViewer.js +6 -0
- package/dist/esm/src/managers/controls/transformControlsManager.js +44 -15
- package/dist/esm/src/managers/scene/componentTooltipManager.js +99 -28
- package/dist/esm/src/managers/scene/sceneExportManager.js +6 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -3817,7 +3817,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
3817
3817
|
onTransformEnd: null,
|
|
3818
3818
|
onModeChange: null,
|
|
3819
3819
|
onObjectRemoved: null,
|
|
3820
|
-
onSelectionChanged: null
|
|
3820
|
+
onSelectionChanged: null,
|
|
3821
|
+
onIODeviceClick: null
|
|
3821
3822
|
};
|
|
3822
3823
|
this.init();
|
|
3823
3824
|
}
|
|
@@ -3895,6 +3896,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
3895
3896
|
if (callbacks.onSelectionChanged) {
|
|
3896
3897
|
this.callbacks.onSelectionChanged = callbacks.onSelectionChanged;
|
|
3897
3898
|
}
|
|
3899
|
+
if (callbacks.onIODeviceClick) {
|
|
3900
|
+
this.callbacks.onIODeviceClick = callbacks.onIODeviceClick;
|
|
3901
|
+
}
|
|
3898
3902
|
console.log('🔗 Transform controls callbacks registered');
|
|
3899
3903
|
}
|
|
3900
3904
|
/**
|
|
@@ -4140,6 +4144,31 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4140
4144
|
_this4._calculateMousePosition(event, mouse);
|
|
4141
4145
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
4142
4146
|
|
|
4147
|
+
// Check for direct io-device mesh click (before bounding box selection)
|
|
4148
|
+
if (_this4.callbacks.onIODeviceClick) {
|
|
4149
|
+
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
4150
|
+
var _iterator = _createForOfIteratorHelper(allIntersects),
|
|
4151
|
+
_step;
|
|
4152
|
+
try {
|
|
4153
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
4154
|
+
var hit = _step.value;
|
|
4155
|
+
var obj = hit.object;
|
|
4156
|
+
while (obj) {
|
|
4157
|
+
var _obj$userData;
|
|
4158
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'io-device') {
|
|
4159
|
+
_this4.callbacks.onIODeviceClick(obj);
|
|
4160
|
+
return;
|
|
4161
|
+
}
|
|
4162
|
+
obj = obj.parent;
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
} catch (err) {
|
|
4166
|
+
_iterator.e(err);
|
|
4167
|
+
} finally {
|
|
4168
|
+
_iterator.f();
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4143
4172
|
// Find target object using appropriate selection method
|
|
4144
4173
|
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
4145
4174
|
|
|
@@ -4337,11 +4366,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4337
4366
|
var isNewSegmentHorizontal = this._isSegmentHorizontal(segment);
|
|
4338
4367
|
|
|
4339
4368
|
// Check if all existing segments have the same orientation
|
|
4340
|
-
var
|
|
4341
|
-
|
|
4369
|
+
var _iterator2 = _createForOfIteratorHelper(existingSegments),
|
|
4370
|
+
_step2;
|
|
4342
4371
|
try {
|
|
4343
|
-
for (
|
|
4344
|
-
var existingSegment =
|
|
4372
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
4373
|
+
var existingSegment = _step2.value;
|
|
4345
4374
|
var isExistingHorizontal = this._isSegmentHorizontal(existingSegment);
|
|
4346
4375
|
|
|
4347
4376
|
// Disallow mixing horizontal and vertical
|
|
@@ -4350,9 +4379,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4350
4379
|
}
|
|
4351
4380
|
}
|
|
4352
4381
|
} catch (err) {
|
|
4353
|
-
|
|
4382
|
+
_iterator2.e(err);
|
|
4354
4383
|
} finally {
|
|
4355
|
-
|
|
4384
|
+
_iterator2.f();
|
|
4356
4385
|
}
|
|
4357
4386
|
return true;
|
|
4358
4387
|
}
|
|
@@ -5166,11 +5195,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5166
5195
|
var objectFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
5167
5196
|
var objectsWithBounds = this.getSelectableObjectsWithBounds(objectFilter);
|
|
5168
5197
|
var intersections = [];
|
|
5169
|
-
var
|
|
5170
|
-
|
|
5198
|
+
var _iterator3 = _createForOfIteratorHelper(objectsWithBounds),
|
|
5199
|
+
_step3;
|
|
5171
5200
|
try {
|
|
5172
|
-
for (
|
|
5173
|
-
var item =
|
|
5201
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
5202
|
+
var item = _step3.value;
|
|
5174
5203
|
var object = item.object,
|
|
5175
5204
|
boundingBox = item.boundingBox;
|
|
5176
5205
|
|
|
@@ -5190,9 +5219,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5190
5219
|
|
|
5191
5220
|
// Sort by distance (closest first)
|
|
5192
5221
|
} catch (err) {
|
|
5193
|
-
|
|
5222
|
+
_iterator3.e(err);
|
|
5194
5223
|
} finally {
|
|
5195
|
-
|
|
5224
|
+
_iterator3.f();
|
|
5196
5225
|
}
|
|
5197
5226
|
intersections.sort(function (a, b) {
|
|
5198
5227
|
return a.distance - b.distance;
|
|
@@ -5578,8 +5607,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5578
5607
|
key: "_updateSegmentReference",
|
|
5579
5608
|
value: function _updateSegmentReference(oldSegment, newSegment, index) {
|
|
5580
5609
|
var selectedIndex = this.selectedObjects.findIndex(function (obj) {
|
|
5581
|
-
var _obj$
|
|
5582
|
-
return obj.uuid === oldSegment.uuid || ((_obj$
|
|
5610
|
+
var _obj$userData2;
|
|
5611
|
+
return obj.uuid === oldSegment.uuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === oldSegment.uuid;
|
|
5583
5612
|
});
|
|
5584
5613
|
if (selectedIndex !== -1 && newSegment) {
|
|
5585
5614
|
// Clear bounding box cache
|
|
@@ -11346,6 +11375,12 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
11346
11375
|
// Computed from geometry - not in input format
|
|
11347
11376
|
'name',
|
|
11348
11377
|
// Redundant with GLB node names - not in input format
|
|
11378
|
+
'addedTimestamp',
|
|
11379
|
+
// Internal tracking - not needed in export
|
|
11380
|
+
'addedBy',
|
|
11381
|
+
// Internal tracking - not needed in export
|
|
11382
|
+
'initialPosition',
|
|
11383
|
+
// Internal tracking - not needed in export
|
|
11349
11384
|
// Exclude internal segment tracking properties
|
|
11350
11385
|
'segmentId',
|
|
11351
11386
|
// Internal tracking
|
|
@@ -33753,6 +33788,52 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33753
33788
|
}
|
|
33754
33789
|
}
|
|
33755
33790
|
|
|
33791
|
+
/**
|
|
33792
|
+
* Toggle the first binary state on an io-device object.
|
|
33793
|
+
* Called when the user clicks directly on an io-device mesh in the 3D scene.
|
|
33794
|
+
* @param {THREE.Object3D} ioDeviceObject - The io-device Group/Mesh that was clicked
|
|
33795
|
+
*/
|
|
33796
|
+
}, {
|
|
33797
|
+
key: "toggleIODeviceBinaryState",
|
|
33798
|
+
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
33799
|
+
var _ref, _this$sceneViewer;
|
|
33800
|
+
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
33801
|
+
var ud = ioDeviceObject.userData;
|
|
33802
|
+
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
33803
|
+
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
33804
|
+
if (!attachmentId) return;
|
|
33805
|
+
|
|
33806
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
33807
|
+
var parentUuid = null;
|
|
33808
|
+
var obj = ioDeviceObject.parent;
|
|
33809
|
+
while (obj) {
|
|
33810
|
+
var _obj$userData;
|
|
33811
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'component') {
|
|
33812
|
+
parentUuid = obj.uuid;
|
|
33813
|
+
break;
|
|
33814
|
+
}
|
|
33815
|
+
obj = obj.parent;
|
|
33816
|
+
}
|
|
33817
|
+
|
|
33818
|
+
// Create a scoped attachment key to prevent state sharing between instances
|
|
33819
|
+
// of the same smart component that share the same attachmentId
|
|
33820
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
33821
|
+
|
|
33822
|
+
// Find the first binary state
|
|
33823
|
+
var binaryState = dataPoints.find(function (dp) {
|
|
33824
|
+
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
33825
|
+
});
|
|
33826
|
+
if (!binaryState) return;
|
|
33827
|
+
var dpId = binaryState.id;
|
|
33828
|
+
var storedVal = this._stateAdapter.getState(scopedAttachmentId, dpId);
|
|
33829
|
+
// Fall back to defaultValue when state is uninitialized (null/undefined)
|
|
33830
|
+
var currentVal = (_ref = storedVal !== null && storedVal !== void 0 ? storedVal : binaryState.defaultValue) !== null && _ref !== void 0 ? _ref : false;
|
|
33831
|
+
var newVal = !Boolean(currentVal);
|
|
33832
|
+
this._stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
33833
|
+
(_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.behaviorManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
33834
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
33835
|
+
}
|
|
33836
|
+
|
|
33756
33837
|
/**
|
|
33757
33838
|
* Should be called when an object is selected or deselected.
|
|
33758
33839
|
* @param {THREE.Object3D|null} object
|
|
@@ -33842,23 +33923,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33842
33923
|
this._styleInjected = false;
|
|
33843
33924
|
}
|
|
33844
33925
|
|
|
33926
|
+
/**
|
|
33927
|
+
* Generate a scoped attachment key that includes the parent component UUID.
|
|
33928
|
+
* This ensures each instance of a smart component has isolated IO device state.
|
|
33929
|
+
* @param {string} attachmentId - The original attachment ID from the component data
|
|
33930
|
+
* @param {string|null} parentUuid - The UUID of the parent smart component instance
|
|
33931
|
+
* @returns {string} A scoped key in the format "parentUuid::attachmentId" or just attachmentId if no parent
|
|
33932
|
+
* @private
|
|
33933
|
+
*/
|
|
33934
|
+
}, {
|
|
33935
|
+
key: "_getScopedAttachmentKey",
|
|
33936
|
+
value: function _getScopedAttachmentKey(attachmentId, parentUuid) {
|
|
33937
|
+
if (!parentUuid) return attachmentId;
|
|
33938
|
+
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
33939
|
+
}
|
|
33940
|
+
|
|
33845
33941
|
/**
|
|
33846
33942
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
33847
33943
|
* Returns richer data including attachmentId and data point definitions.
|
|
33848
|
-
* @param {THREE.Object3D} object
|
|
33849
|
-
* @returns {{ label: string, deviceId: string, attachmentId: string, dataPoints: Array }[]}
|
|
33944
|
+
* @param {THREE.Object3D} object - The parent component object
|
|
33945
|
+
* @returns {{ label: string, deviceId: string, attachmentId: string, scopedAttachmentId: string, dataPoints: Array }[]}
|
|
33850
33946
|
*/
|
|
33851
33947
|
}, {
|
|
33852
33948
|
key: "_getIODevices",
|
|
33853
33949
|
value: function _getIODevices(object) {
|
|
33950
|
+
var _this2 = this;
|
|
33854
33951
|
var devices = [];
|
|
33952
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
33855
33953
|
object.traverse(function (child) {
|
|
33856
33954
|
var _child$userData;
|
|
33857
33955
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
33956
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
33858
33957
|
devices.push({
|
|
33859
33958
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
33860
33959
|
deviceId: child.userData.deviceId || '',
|
|
33861
|
-
attachmentId:
|
|
33960
|
+
attachmentId: attachmentId,
|
|
33961
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
33862
33962
|
dataPoints: child.userData.dataPoints || [],
|
|
33863
33963
|
direction: child.userData.ioDirection || 'output'
|
|
33864
33964
|
});
|
|
@@ -33874,7 +33974,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33874
33974
|
}, {
|
|
33875
33975
|
key: "_buildTooltip",
|
|
33876
33976
|
value: function _buildTooltip(object) {
|
|
33877
|
-
var
|
|
33977
|
+
var _this3 = this;
|
|
33878
33978
|
// Remove any existing tooltip first
|
|
33879
33979
|
this.hide();
|
|
33880
33980
|
// Re-assign selected object since hide() clears it
|
|
@@ -33942,9 +34042,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33942
34042
|
list.appendChild(item);
|
|
33943
34043
|
|
|
33944
34044
|
// Data point rows (one per data point definition stored in userData)
|
|
33945
|
-
|
|
34045
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
34046
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
33946
34047
|
device.dataPoints.forEach(function (dp) {
|
|
33947
|
-
var row =
|
|
34048
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
33948
34049
|
list.appendChild(row);
|
|
33949
34050
|
});
|
|
33950
34051
|
}
|
|
@@ -33955,11 +34056,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33955
34056
|
// Hover expand/collapse
|
|
33956
34057
|
trigger.addEventListener('mouseenter', function () {
|
|
33957
34058
|
ioSection.classList.add('expanded');
|
|
33958
|
-
|
|
34059
|
+
_this3._ioExpanded = true;
|
|
33959
34060
|
});
|
|
33960
34061
|
ioSection.addEventListener('mouseleave', function () {
|
|
33961
34062
|
ioSection.classList.remove('expanded');
|
|
33962
|
-
|
|
34063
|
+
_this3._ioExpanded = false;
|
|
33963
34064
|
});
|
|
33964
34065
|
card.appendChild(ioSection);
|
|
33965
34066
|
} else {
|
|
@@ -34003,11 +34104,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34003
34104
|
}, {
|
|
34004
34105
|
key: "_positionTooltip",
|
|
34005
34106
|
value: function _positionTooltip() {
|
|
34006
|
-
var _this$
|
|
34107
|
+
var _this$sceneViewer2, _this$sceneViewer3;
|
|
34007
34108
|
if (!this.tooltipEl || !this.selectedObject) return;
|
|
34008
34109
|
var container = this._getContainer();
|
|
34009
|
-
var camera = (_this$
|
|
34010
|
-
var renderer = (_this$
|
|
34110
|
+
var camera = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.camera;
|
|
34111
|
+
var renderer = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.renderer;
|
|
34011
34112
|
if (!container || !camera || !renderer) return;
|
|
34012
34113
|
|
|
34013
34114
|
// Compute bounding box to position above the component
|
|
@@ -34044,8 +34145,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34044
34145
|
}, {
|
|
34045
34146
|
key: "_getContainer",
|
|
34046
34147
|
value: function _getContainer() {
|
|
34047
|
-
var _this$
|
|
34048
|
-
return ((_this$
|
|
34148
|
+
var _this$sceneViewer4;
|
|
34149
|
+
return ((_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.renderer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.domElement) === null || _this$sceneViewer4 === void 0 ? void 0 : _this$sceneViewer4.parentElement) || null;
|
|
34049
34150
|
}
|
|
34050
34151
|
|
|
34051
34152
|
// -----------------------------------------------------------------------
|
|
@@ -34058,18 +34159,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34058
34159
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
34059
34160
|
* Input / bidirectional → shows an interactive control.
|
|
34060
34161
|
*
|
|
34061
|
-
* @param {string} attachmentId
|
|
34162
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
34062
34163
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
34063
34164
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
34165
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
34064
34166
|
* @returns {HTMLElement}
|
|
34065
34167
|
*/
|
|
34066
34168
|
}, {
|
|
34067
34169
|
key: "_buildDataPointRow",
|
|
34068
|
-
value: function _buildDataPointRow(
|
|
34069
|
-
var
|
|
34170
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
34171
|
+
var _ref2,
|
|
34070
34172
|
_this$_stateAdapter$g,
|
|
34071
34173
|
_this$_stateAdapter,
|
|
34072
|
-
|
|
34174
|
+
_this4 = this;
|
|
34073
34175
|
var row = document.createElement('div');
|
|
34074
34176
|
row.className = 'cp-tooltip__dp-row';
|
|
34075
34177
|
var nameEl = document.createElement('span');
|
|
@@ -34077,20 +34179,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34077
34179
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
34078
34180
|
row.appendChild(nameEl);
|
|
34079
34181
|
var dpId = dp.id || dp.name;
|
|
34080
|
-
var key = "".concat(
|
|
34182
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
34081
34183
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
34082
34184
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
34083
34185
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
34084
|
-
var currentVal = (
|
|
34186
|
+
var currentVal = (_ref2 = (_this$_stateAdapter$g = (_this$_stateAdapter = this._stateAdapter) === null || _this$_stateAdapter === void 0 ? void 0 : _this$_stateAdapter.getState(scopedAttachmentId, dpId)) !== null && _this$_stateAdapter$g !== void 0 ? _this$_stateAdapter$g : dp.defaultValue) !== null && _ref2 !== void 0 ? _ref2 : null;
|
|
34085
34187
|
if (isInput) {
|
|
34086
34188
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
34087
|
-
var
|
|
34088
|
-
(
|
|
34189
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
34190
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
34089
34191
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
34090
34192
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
34091
34193
|
// don't bleed across clones that share the same attachmentId.
|
|
34092
|
-
|
|
34093
|
-
|
|
34194
|
+
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
34195
|
+
var parentUuid = ((_this4$selectedObject = _this4.selectedObject) === null || _this4$selectedObject === void 0 ? void 0 : _this4$selectedObject.uuid) || null;
|
|
34196
|
+
(_this4$sceneViewer = _this4.sceneViewer) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.managers) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.behaviorManager) === null || _this4$sceneViewer === void 0 || _this4$sceneViewer.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
34094
34197
|
});
|
|
34095
34198
|
row.appendChild(ctrl);
|
|
34096
34199
|
this._stateElements.set(key, {
|
|
@@ -34240,20 +34343,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34240
34343
|
/**
|
|
34241
34344
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
34242
34345
|
* Called each frame from update() — skips if no adapter is configured.
|
|
34346
|
+
* Key format is scopedAttachmentId::dataPointId where scopedAttachmentId
|
|
34347
|
+
* can be parentUuid::attachmentId, resulting in parentUuid::attachmentId::dataPointId
|
|
34243
34348
|
*/
|
|
34244
34349
|
}, {
|
|
34245
34350
|
key: "_refreshStateDisplays",
|
|
34246
34351
|
value: function _refreshStateDisplays() {
|
|
34247
|
-
var
|
|
34352
|
+
var _this5 = this;
|
|
34248
34353
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
34249
34354
|
this._stateElements.forEach(function (entry, key) {
|
|
34250
34355
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
34251
|
-
|
|
34356
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
34357
|
+
var sepIdx = key.lastIndexOf('::');
|
|
34252
34358
|
if (sepIdx === -1) return;
|
|
34253
|
-
var
|
|
34359
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
34254
34360
|
var dataPointId = key.slice(sepIdx + 2);
|
|
34255
|
-
var val =
|
|
34256
|
-
|
|
34361
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
34362
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
34257
34363
|
});
|
|
34258
34364
|
}
|
|
34259
34365
|
}]);
|
|
@@ -36665,7 +36771,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
36665
36771
|
* Initialize the CentralPlant manager
|
|
36666
36772
|
*
|
|
36667
36773
|
* @constructor
|
|
36668
|
-
* @version 0.1.
|
|
36774
|
+
* @version 0.1.87
|
|
36669
36775
|
* @updated 2025-10-22
|
|
36670
36776
|
*
|
|
36671
36777
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -39386,6 +39492,12 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
39386
39492
|
console.log("\uD83D\uDCE1 Emitting component-deselected");
|
|
39387
39493
|
_this4.emit('component-deselected');
|
|
39388
39494
|
}
|
|
39495
|
+
},
|
|
39496
|
+
onIODeviceClick: function onIODeviceClick(ioDeviceObject) {
|
|
39497
|
+
// Direct click on an io-device mesh in the scene → toggle its binary state
|
|
39498
|
+
if (_this4.componentTooltipManager) {
|
|
39499
|
+
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
39500
|
+
}
|
|
39389
39501
|
}
|
|
39390
39502
|
});
|
|
39391
39503
|
|
|
@@ -19,7 +19,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
19
19
|
* Initialize the CentralPlant manager
|
|
20
20
|
*
|
|
21
21
|
* @constructor
|
|
22
|
-
* @version 0.1.
|
|
22
|
+
* @version 0.1.87
|
|
23
23
|
* @updated 2025-10-22
|
|
24
24
|
*
|
|
25
25
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -409,6 +409,12 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
409
409
|
console.log("\uD83D\uDCE1 Emitting component-deselected");
|
|
410
410
|
_this4.emit('component-deselected');
|
|
411
411
|
}
|
|
412
|
+
},
|
|
413
|
+
onIODeviceClick: function onIODeviceClick(ioDeviceObject) {
|
|
414
|
+
// Direct click on an io-device mesh in the scene → toggle its binary state
|
|
415
|
+
if (_this4.componentTooltipManager) {
|
|
416
|
+
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
417
|
+
}
|
|
412
418
|
}
|
|
413
419
|
});
|
|
414
420
|
|
|
@@ -117,7 +117,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
117
117
|
onTransformEnd: null,
|
|
118
118
|
onModeChange: null,
|
|
119
119
|
onObjectRemoved: null,
|
|
120
|
-
onSelectionChanged: null
|
|
120
|
+
onSelectionChanged: null,
|
|
121
|
+
onIODeviceClick: null
|
|
121
122
|
};
|
|
122
123
|
this.init();
|
|
123
124
|
}
|
|
@@ -195,6 +196,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
195
196
|
if (callbacks.onSelectionChanged) {
|
|
196
197
|
this.callbacks.onSelectionChanged = callbacks.onSelectionChanged;
|
|
197
198
|
}
|
|
199
|
+
if (callbacks.onIODeviceClick) {
|
|
200
|
+
this.callbacks.onIODeviceClick = callbacks.onIODeviceClick;
|
|
201
|
+
}
|
|
198
202
|
console.log('🔗 Transform controls callbacks registered');
|
|
199
203
|
}
|
|
200
204
|
/**
|
|
@@ -440,6 +444,31 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
440
444
|
_this4._calculateMousePosition(event, mouse);
|
|
441
445
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
442
446
|
|
|
447
|
+
// Check for direct io-device mesh click (before bounding box selection)
|
|
448
|
+
if (_this4.callbacks.onIODeviceClick) {
|
|
449
|
+
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
450
|
+
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(allIntersects),
|
|
451
|
+
_step;
|
|
452
|
+
try {
|
|
453
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
454
|
+
var hit = _step.value;
|
|
455
|
+
var obj = hit.object;
|
|
456
|
+
while (obj) {
|
|
457
|
+
var _obj$userData;
|
|
458
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'io-device') {
|
|
459
|
+
_this4.callbacks.onIODeviceClick(obj);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
obj = obj.parent;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} catch (err) {
|
|
466
|
+
_iterator.e(err);
|
|
467
|
+
} finally {
|
|
468
|
+
_iterator.f();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
443
472
|
// Find target object using appropriate selection method
|
|
444
473
|
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
445
474
|
|
|
@@ -637,11 +666,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
637
666
|
var isNewSegmentHorizontal = this._isSegmentHorizontal(segment);
|
|
638
667
|
|
|
639
668
|
// Check if all existing segments have the same orientation
|
|
640
|
-
var
|
|
641
|
-
|
|
669
|
+
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(existingSegments),
|
|
670
|
+
_step2;
|
|
642
671
|
try {
|
|
643
|
-
for (
|
|
644
|
-
var existingSegment =
|
|
672
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
673
|
+
var existingSegment = _step2.value;
|
|
645
674
|
var isExistingHorizontal = this._isSegmentHorizontal(existingSegment);
|
|
646
675
|
|
|
647
676
|
// Disallow mixing horizontal and vertical
|
|
@@ -650,9 +679,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
650
679
|
}
|
|
651
680
|
}
|
|
652
681
|
} catch (err) {
|
|
653
|
-
|
|
682
|
+
_iterator2.e(err);
|
|
654
683
|
} finally {
|
|
655
|
-
|
|
684
|
+
_iterator2.f();
|
|
656
685
|
}
|
|
657
686
|
return true;
|
|
658
687
|
}
|
|
@@ -1466,11 +1495,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1466
1495
|
var objectFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
1467
1496
|
var objectsWithBounds = this.getSelectableObjectsWithBounds(objectFilter);
|
|
1468
1497
|
var intersections = [];
|
|
1469
|
-
var
|
|
1470
|
-
|
|
1498
|
+
var _iterator3 = _rollupPluginBabelHelpers.createForOfIteratorHelper(objectsWithBounds),
|
|
1499
|
+
_step3;
|
|
1471
1500
|
try {
|
|
1472
|
-
for (
|
|
1473
|
-
var item =
|
|
1501
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1502
|
+
var item = _step3.value;
|
|
1474
1503
|
var object = item.object,
|
|
1475
1504
|
boundingBox = item.boundingBox;
|
|
1476
1505
|
|
|
@@ -1490,9 +1519,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1490
1519
|
|
|
1491
1520
|
// Sort by distance (closest first)
|
|
1492
1521
|
} catch (err) {
|
|
1493
|
-
|
|
1522
|
+
_iterator3.e(err);
|
|
1494
1523
|
} finally {
|
|
1495
|
-
|
|
1524
|
+
_iterator3.f();
|
|
1496
1525
|
}
|
|
1497
1526
|
intersections.sort(function (a, b) {
|
|
1498
1527
|
return a.distance - b.distance;
|
|
@@ -1878,8 +1907,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1878
1907
|
key: "_updateSegmentReference",
|
|
1879
1908
|
value: function _updateSegmentReference(oldSegment, newSegment, index) {
|
|
1880
1909
|
var selectedIndex = this.selectedObjects.findIndex(function (obj) {
|
|
1881
|
-
var _obj$
|
|
1882
|
-
return obj.uuid === oldSegment.uuid || ((_obj$
|
|
1910
|
+
var _obj$userData2;
|
|
1911
|
+
return obj.uuid === oldSegment.uuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === oldSegment.uuid;
|
|
1883
1912
|
});
|
|
1884
1913
|
if (selectedIndex !== -1 && newSegment) {
|
|
1885
1914
|
// Clear bounding box cache
|
|
@@ -121,6 +121,52 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Toggle the first binary state on an io-device object.
|
|
126
|
+
* Called when the user clicks directly on an io-device mesh in the 3D scene.
|
|
127
|
+
* @param {THREE.Object3D} ioDeviceObject - The io-device Group/Mesh that was clicked
|
|
128
|
+
*/
|
|
129
|
+
}, {
|
|
130
|
+
key: "toggleIODeviceBinaryState",
|
|
131
|
+
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
132
|
+
var _ref, _this$sceneViewer;
|
|
133
|
+
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
134
|
+
var ud = ioDeviceObject.userData;
|
|
135
|
+
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
136
|
+
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
137
|
+
if (!attachmentId) return;
|
|
138
|
+
|
|
139
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
140
|
+
var parentUuid = null;
|
|
141
|
+
var obj = ioDeviceObject.parent;
|
|
142
|
+
while (obj) {
|
|
143
|
+
var _obj$userData;
|
|
144
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'component') {
|
|
145
|
+
parentUuid = obj.uuid;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
obj = obj.parent;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Create a scoped attachment key to prevent state sharing between instances
|
|
152
|
+
// of the same smart component that share the same attachmentId
|
|
153
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
154
|
+
|
|
155
|
+
// Find the first binary state
|
|
156
|
+
var binaryState = dataPoints.find(function (dp) {
|
|
157
|
+
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
158
|
+
});
|
|
159
|
+
if (!binaryState) return;
|
|
160
|
+
var dpId = binaryState.id;
|
|
161
|
+
var storedVal = this._stateAdapter.getState(scopedAttachmentId, dpId);
|
|
162
|
+
// Fall back to defaultValue when state is uninitialized (null/undefined)
|
|
163
|
+
var currentVal = (_ref = storedVal !== null && storedVal !== void 0 ? storedVal : binaryState.defaultValue) !== null && _ref !== void 0 ? _ref : false;
|
|
164
|
+
var newVal = !Boolean(currentVal);
|
|
165
|
+
this._stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
166
|
+
(_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.behaviorManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
167
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
168
|
+
}
|
|
169
|
+
|
|
124
170
|
/**
|
|
125
171
|
* Should be called when an object is selected or deselected.
|
|
126
172
|
* @param {THREE.Object3D|null} object
|
|
@@ -210,23 +256,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
210
256
|
this._styleInjected = false;
|
|
211
257
|
}
|
|
212
258
|
|
|
259
|
+
/**
|
|
260
|
+
* Generate a scoped attachment key that includes the parent component UUID.
|
|
261
|
+
* This ensures each instance of a smart component has isolated IO device state.
|
|
262
|
+
* @param {string} attachmentId - The original attachment ID from the component data
|
|
263
|
+
* @param {string|null} parentUuid - The UUID of the parent smart component instance
|
|
264
|
+
* @returns {string} A scoped key in the format "parentUuid::attachmentId" or just attachmentId if no parent
|
|
265
|
+
* @private
|
|
266
|
+
*/
|
|
267
|
+
}, {
|
|
268
|
+
key: "_getScopedAttachmentKey",
|
|
269
|
+
value: function _getScopedAttachmentKey(attachmentId, parentUuid) {
|
|
270
|
+
if (!parentUuid) return attachmentId;
|
|
271
|
+
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
272
|
+
}
|
|
273
|
+
|
|
213
274
|
/**
|
|
214
275
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
215
276
|
* Returns richer data including attachmentId and data point definitions.
|
|
216
|
-
* @param {THREE.Object3D} object
|
|
217
|
-
* @returns {{ label: string, deviceId: string, attachmentId: string, dataPoints: Array }[]}
|
|
277
|
+
* @param {THREE.Object3D} object - The parent component object
|
|
278
|
+
* @returns {{ label: string, deviceId: string, attachmentId: string, scopedAttachmentId: string, dataPoints: Array }[]}
|
|
218
279
|
*/
|
|
219
280
|
}, {
|
|
220
281
|
key: "_getIODevices",
|
|
221
282
|
value: function _getIODevices(object) {
|
|
283
|
+
var _this2 = this;
|
|
222
284
|
var devices = [];
|
|
285
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
223
286
|
object.traverse(function (child) {
|
|
224
287
|
var _child$userData;
|
|
225
288
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
289
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
226
290
|
devices.push({
|
|
227
291
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
228
292
|
deviceId: child.userData.deviceId || '',
|
|
229
|
-
attachmentId:
|
|
293
|
+
attachmentId: attachmentId,
|
|
294
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
230
295
|
dataPoints: child.userData.dataPoints || [],
|
|
231
296
|
direction: child.userData.ioDirection || 'output'
|
|
232
297
|
});
|
|
@@ -242,7 +307,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
242
307
|
}, {
|
|
243
308
|
key: "_buildTooltip",
|
|
244
309
|
value: function _buildTooltip(object) {
|
|
245
|
-
var
|
|
310
|
+
var _this3 = this;
|
|
246
311
|
// Remove any existing tooltip first
|
|
247
312
|
this.hide();
|
|
248
313
|
// Re-assign selected object since hide() clears it
|
|
@@ -310,9 +375,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
310
375
|
list.appendChild(item);
|
|
311
376
|
|
|
312
377
|
// Data point rows (one per data point definition stored in userData)
|
|
313
|
-
|
|
378
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
379
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
314
380
|
device.dataPoints.forEach(function (dp) {
|
|
315
|
-
var row =
|
|
381
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
316
382
|
list.appendChild(row);
|
|
317
383
|
});
|
|
318
384
|
}
|
|
@@ -323,11 +389,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
323
389
|
// Hover expand/collapse
|
|
324
390
|
trigger.addEventListener('mouseenter', function () {
|
|
325
391
|
ioSection.classList.add('expanded');
|
|
326
|
-
|
|
392
|
+
_this3._ioExpanded = true;
|
|
327
393
|
});
|
|
328
394
|
ioSection.addEventListener('mouseleave', function () {
|
|
329
395
|
ioSection.classList.remove('expanded');
|
|
330
|
-
|
|
396
|
+
_this3._ioExpanded = false;
|
|
331
397
|
});
|
|
332
398
|
card.appendChild(ioSection);
|
|
333
399
|
} else {
|
|
@@ -371,11 +437,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
371
437
|
}, {
|
|
372
438
|
key: "_positionTooltip",
|
|
373
439
|
value: function _positionTooltip() {
|
|
374
|
-
var _this$
|
|
440
|
+
var _this$sceneViewer2, _this$sceneViewer3;
|
|
375
441
|
if (!this.tooltipEl || !this.selectedObject) return;
|
|
376
442
|
var container = this._getContainer();
|
|
377
|
-
var camera = (_this$
|
|
378
|
-
var renderer = (_this$
|
|
443
|
+
var camera = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.camera;
|
|
444
|
+
var renderer = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.renderer;
|
|
379
445
|
if (!container || !camera || !renderer) return;
|
|
380
446
|
|
|
381
447
|
// Compute bounding box to position above the component
|
|
@@ -412,8 +478,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
412
478
|
}, {
|
|
413
479
|
key: "_getContainer",
|
|
414
480
|
value: function _getContainer() {
|
|
415
|
-
var _this$
|
|
416
|
-
return ((_this$
|
|
481
|
+
var _this$sceneViewer4;
|
|
482
|
+
return ((_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.renderer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.domElement) === null || _this$sceneViewer4 === void 0 ? void 0 : _this$sceneViewer4.parentElement) || null;
|
|
417
483
|
}
|
|
418
484
|
|
|
419
485
|
// -----------------------------------------------------------------------
|
|
@@ -426,18 +492,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
426
492
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
427
493
|
* Input / bidirectional → shows an interactive control.
|
|
428
494
|
*
|
|
429
|
-
* @param {string} attachmentId
|
|
495
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
430
496
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
431
497
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
498
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
432
499
|
* @returns {HTMLElement}
|
|
433
500
|
*/
|
|
434
501
|
}, {
|
|
435
502
|
key: "_buildDataPointRow",
|
|
436
|
-
value: function _buildDataPointRow(
|
|
437
|
-
var
|
|
503
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
504
|
+
var _ref2,
|
|
438
505
|
_this$_stateAdapter$g,
|
|
439
506
|
_this$_stateAdapter,
|
|
440
|
-
|
|
507
|
+
_this4 = this;
|
|
441
508
|
var row = document.createElement('div');
|
|
442
509
|
row.className = 'cp-tooltip__dp-row';
|
|
443
510
|
var nameEl = document.createElement('span');
|
|
@@ -445,20 +512,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
445
512
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
446
513
|
row.appendChild(nameEl);
|
|
447
514
|
var dpId = dp.id || dp.name;
|
|
448
|
-
var key = "".concat(
|
|
515
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
449
516
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
450
517
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
451
518
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
452
|
-
var currentVal = (
|
|
519
|
+
var currentVal = (_ref2 = (_this$_stateAdapter$g = (_this$_stateAdapter = this._stateAdapter) === null || _this$_stateAdapter === void 0 ? void 0 : _this$_stateAdapter.getState(scopedAttachmentId, dpId)) !== null && _this$_stateAdapter$g !== void 0 ? _this$_stateAdapter$g : dp.defaultValue) !== null && _ref2 !== void 0 ? _ref2 : null;
|
|
453
520
|
if (isInput) {
|
|
454
521
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
455
|
-
var
|
|
456
|
-
(
|
|
522
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
523
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
457
524
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
458
525
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
459
526
|
// don't bleed across clones that share the same attachmentId.
|
|
460
|
-
|
|
461
|
-
|
|
527
|
+
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
528
|
+
var parentUuid = ((_this4$selectedObject = _this4.selectedObject) === null || _this4$selectedObject === void 0 ? void 0 : _this4$selectedObject.uuid) || null;
|
|
529
|
+
(_this4$sceneViewer = _this4.sceneViewer) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.managers) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.behaviorManager) === null || _this4$sceneViewer === void 0 || _this4$sceneViewer.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
462
530
|
});
|
|
463
531
|
row.appendChild(ctrl);
|
|
464
532
|
this._stateElements.set(key, {
|
|
@@ -608,20 +676,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
608
676
|
/**
|
|
609
677
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
610
678
|
* Called each frame from update() — skips if no adapter is configured.
|
|
679
|
+
* Key format is scopedAttachmentId::dataPointId where scopedAttachmentId
|
|
680
|
+
* can be parentUuid::attachmentId, resulting in parentUuid::attachmentId::dataPointId
|
|
611
681
|
*/
|
|
612
682
|
}, {
|
|
613
683
|
key: "_refreshStateDisplays",
|
|
614
684
|
value: function _refreshStateDisplays() {
|
|
615
|
-
var
|
|
685
|
+
var _this5 = this;
|
|
616
686
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
617
687
|
this._stateElements.forEach(function (entry, key) {
|
|
618
688
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
619
|
-
|
|
689
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
690
|
+
var sepIdx = key.lastIndexOf('::');
|
|
620
691
|
if (sepIdx === -1) return;
|
|
621
|
-
var
|
|
692
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
622
693
|
var dataPointId = key.slice(sepIdx + 2);
|
|
623
|
-
var val =
|
|
624
|
-
|
|
694
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
695
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
625
696
|
});
|
|
626
697
|
}
|
|
627
698
|
}]);
|
|
@@ -160,6 +160,12 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
160
160
|
// Computed from geometry - not in input format
|
|
161
161
|
'name',
|
|
162
162
|
// Redundant with GLB node names - not in input format
|
|
163
|
+
'addedTimestamp',
|
|
164
|
+
// Internal tracking - not needed in export
|
|
165
|
+
'addedBy',
|
|
166
|
+
// Internal tracking - not needed in export
|
|
167
|
+
'initialPosition',
|
|
168
|
+
// Internal tracking - not needed in export
|
|
163
169
|
// Exclude internal segment tracking properties
|
|
164
170
|
'segmentId',
|
|
165
171
|
// Internal tracking
|
|
@@ -15,7 +15,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
15
15
|
* Initialize the CentralPlant manager
|
|
16
16
|
*
|
|
17
17
|
* @constructor
|
|
18
|
-
* @version 0.1.
|
|
18
|
+
* @version 0.1.87
|
|
19
19
|
* @updated 2025-10-22
|
|
20
20
|
*
|
|
21
21
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -405,6 +405,12 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
405
405
|
console.log("\uD83D\uDCE1 Emitting component-deselected");
|
|
406
406
|
_this4.emit('component-deselected');
|
|
407
407
|
}
|
|
408
|
+
},
|
|
409
|
+
onIODeviceClick: function onIODeviceClick(ioDeviceObject) {
|
|
410
|
+
// Direct click on an io-device mesh in the scene → toggle its binary state
|
|
411
|
+
if (_this4.componentTooltipManager) {
|
|
412
|
+
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
413
|
+
}
|
|
408
414
|
}
|
|
409
415
|
});
|
|
410
416
|
|
|
@@ -93,7 +93,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
93
93
|
onTransformEnd: null,
|
|
94
94
|
onModeChange: null,
|
|
95
95
|
onObjectRemoved: null,
|
|
96
|
-
onSelectionChanged: null
|
|
96
|
+
onSelectionChanged: null,
|
|
97
|
+
onIODeviceClick: null
|
|
97
98
|
};
|
|
98
99
|
this.init();
|
|
99
100
|
}
|
|
@@ -171,6 +172,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
171
172
|
if (callbacks.onSelectionChanged) {
|
|
172
173
|
this.callbacks.onSelectionChanged = callbacks.onSelectionChanged;
|
|
173
174
|
}
|
|
175
|
+
if (callbacks.onIODeviceClick) {
|
|
176
|
+
this.callbacks.onIODeviceClick = callbacks.onIODeviceClick;
|
|
177
|
+
}
|
|
174
178
|
console.log('🔗 Transform controls callbacks registered');
|
|
175
179
|
}
|
|
176
180
|
/**
|
|
@@ -416,6 +420,31 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
416
420
|
_this4._calculateMousePosition(event, mouse);
|
|
417
421
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
418
422
|
|
|
423
|
+
// Check for direct io-device mesh click (before bounding box selection)
|
|
424
|
+
if (_this4.callbacks.onIODeviceClick) {
|
|
425
|
+
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
426
|
+
var _iterator = _createForOfIteratorHelper(allIntersects),
|
|
427
|
+
_step;
|
|
428
|
+
try {
|
|
429
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
430
|
+
var hit = _step.value;
|
|
431
|
+
var obj = hit.object;
|
|
432
|
+
while (obj) {
|
|
433
|
+
var _obj$userData;
|
|
434
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'io-device') {
|
|
435
|
+
_this4.callbacks.onIODeviceClick(obj);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
obj = obj.parent;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} catch (err) {
|
|
442
|
+
_iterator.e(err);
|
|
443
|
+
} finally {
|
|
444
|
+
_iterator.f();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
419
448
|
// Find target object using appropriate selection method
|
|
420
449
|
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
421
450
|
|
|
@@ -613,11 +642,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
613
642
|
var isNewSegmentHorizontal = this._isSegmentHorizontal(segment);
|
|
614
643
|
|
|
615
644
|
// Check if all existing segments have the same orientation
|
|
616
|
-
var
|
|
617
|
-
|
|
645
|
+
var _iterator2 = _createForOfIteratorHelper(existingSegments),
|
|
646
|
+
_step2;
|
|
618
647
|
try {
|
|
619
|
-
for (
|
|
620
|
-
var existingSegment =
|
|
648
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
649
|
+
var existingSegment = _step2.value;
|
|
621
650
|
var isExistingHorizontal = this._isSegmentHorizontal(existingSegment);
|
|
622
651
|
|
|
623
652
|
// Disallow mixing horizontal and vertical
|
|
@@ -626,9 +655,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
626
655
|
}
|
|
627
656
|
}
|
|
628
657
|
} catch (err) {
|
|
629
|
-
|
|
658
|
+
_iterator2.e(err);
|
|
630
659
|
} finally {
|
|
631
|
-
|
|
660
|
+
_iterator2.f();
|
|
632
661
|
}
|
|
633
662
|
return true;
|
|
634
663
|
}
|
|
@@ -1442,11 +1471,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1442
1471
|
var objectFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
1443
1472
|
var objectsWithBounds = this.getSelectableObjectsWithBounds(objectFilter);
|
|
1444
1473
|
var intersections = [];
|
|
1445
|
-
var
|
|
1446
|
-
|
|
1474
|
+
var _iterator3 = _createForOfIteratorHelper(objectsWithBounds),
|
|
1475
|
+
_step3;
|
|
1447
1476
|
try {
|
|
1448
|
-
for (
|
|
1449
|
-
var item =
|
|
1477
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1478
|
+
var item = _step3.value;
|
|
1450
1479
|
var object = item.object,
|
|
1451
1480
|
boundingBox = item.boundingBox;
|
|
1452
1481
|
|
|
@@ -1466,9 +1495,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1466
1495
|
|
|
1467
1496
|
// Sort by distance (closest first)
|
|
1468
1497
|
} catch (err) {
|
|
1469
|
-
|
|
1498
|
+
_iterator3.e(err);
|
|
1470
1499
|
} finally {
|
|
1471
|
-
|
|
1500
|
+
_iterator3.f();
|
|
1472
1501
|
}
|
|
1473
1502
|
intersections.sort(function (a, b) {
|
|
1474
1503
|
return a.distance - b.distance;
|
|
@@ -1854,8 +1883,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1854
1883
|
key: "_updateSegmentReference",
|
|
1855
1884
|
value: function _updateSegmentReference(oldSegment, newSegment, index) {
|
|
1856
1885
|
var selectedIndex = this.selectedObjects.findIndex(function (obj) {
|
|
1857
|
-
var _obj$
|
|
1858
|
-
return obj.uuid === oldSegment.uuid || ((_obj$
|
|
1886
|
+
var _obj$userData2;
|
|
1887
|
+
return obj.uuid === oldSegment.uuid || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === oldSegment.uuid;
|
|
1859
1888
|
});
|
|
1860
1889
|
if (selectedIndex !== -1 && newSegment) {
|
|
1861
1890
|
// Clear bounding box cache
|
|
@@ -97,6 +97,52 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Toggle the first binary state on an io-device object.
|
|
102
|
+
* Called when the user clicks directly on an io-device mesh in the 3D scene.
|
|
103
|
+
* @param {THREE.Object3D} ioDeviceObject - The io-device Group/Mesh that was clicked
|
|
104
|
+
*/
|
|
105
|
+
}, {
|
|
106
|
+
key: "toggleIODeviceBinaryState",
|
|
107
|
+
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
108
|
+
var _ref, _this$sceneViewer;
|
|
109
|
+
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
110
|
+
var ud = ioDeviceObject.userData;
|
|
111
|
+
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
112
|
+
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
113
|
+
if (!attachmentId) return;
|
|
114
|
+
|
|
115
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
116
|
+
var parentUuid = null;
|
|
117
|
+
var obj = ioDeviceObject.parent;
|
|
118
|
+
while (obj) {
|
|
119
|
+
var _obj$userData;
|
|
120
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'component') {
|
|
121
|
+
parentUuid = obj.uuid;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
obj = obj.parent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Create a scoped attachment key to prevent state sharing between instances
|
|
128
|
+
// of the same smart component that share the same attachmentId
|
|
129
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
130
|
+
|
|
131
|
+
// Find the first binary state
|
|
132
|
+
var binaryState = dataPoints.find(function (dp) {
|
|
133
|
+
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
134
|
+
});
|
|
135
|
+
if (!binaryState) return;
|
|
136
|
+
var dpId = binaryState.id;
|
|
137
|
+
var storedVal = this._stateAdapter.getState(scopedAttachmentId, dpId);
|
|
138
|
+
// Fall back to defaultValue when state is uninitialized (null/undefined)
|
|
139
|
+
var currentVal = (_ref = storedVal !== null && storedVal !== void 0 ? storedVal : binaryState.defaultValue) !== null && _ref !== void 0 ? _ref : false;
|
|
140
|
+
var newVal = !Boolean(currentVal);
|
|
141
|
+
this._stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
142
|
+
(_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.behaviorManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
143
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
144
|
+
}
|
|
145
|
+
|
|
100
146
|
/**
|
|
101
147
|
* Should be called when an object is selected or deselected.
|
|
102
148
|
* @param {THREE.Object3D|null} object
|
|
@@ -186,23 +232,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
186
232
|
this._styleInjected = false;
|
|
187
233
|
}
|
|
188
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Generate a scoped attachment key that includes the parent component UUID.
|
|
237
|
+
* This ensures each instance of a smart component has isolated IO device state.
|
|
238
|
+
* @param {string} attachmentId - The original attachment ID from the component data
|
|
239
|
+
* @param {string|null} parentUuid - The UUID of the parent smart component instance
|
|
240
|
+
* @returns {string} A scoped key in the format "parentUuid::attachmentId" or just attachmentId if no parent
|
|
241
|
+
* @private
|
|
242
|
+
*/
|
|
243
|
+
}, {
|
|
244
|
+
key: "_getScopedAttachmentKey",
|
|
245
|
+
value: function _getScopedAttachmentKey(attachmentId, parentUuid) {
|
|
246
|
+
if (!parentUuid) return attachmentId;
|
|
247
|
+
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
248
|
+
}
|
|
249
|
+
|
|
189
250
|
/**
|
|
190
251
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
191
252
|
* Returns richer data including attachmentId and data point definitions.
|
|
192
|
-
* @param {THREE.Object3D} object
|
|
193
|
-
* @returns {{ label: string, deviceId: string, attachmentId: string, dataPoints: Array }[]}
|
|
253
|
+
* @param {THREE.Object3D} object - The parent component object
|
|
254
|
+
* @returns {{ label: string, deviceId: string, attachmentId: string, scopedAttachmentId: string, dataPoints: Array }[]}
|
|
194
255
|
*/
|
|
195
256
|
}, {
|
|
196
257
|
key: "_getIODevices",
|
|
197
258
|
value: function _getIODevices(object) {
|
|
259
|
+
var _this2 = this;
|
|
198
260
|
var devices = [];
|
|
261
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
199
262
|
object.traverse(function (child) {
|
|
200
263
|
var _child$userData;
|
|
201
264
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
265
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
202
266
|
devices.push({
|
|
203
267
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
204
268
|
deviceId: child.userData.deviceId || '',
|
|
205
|
-
attachmentId:
|
|
269
|
+
attachmentId: attachmentId,
|
|
270
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
206
271
|
dataPoints: child.userData.dataPoints || [],
|
|
207
272
|
direction: child.userData.ioDirection || 'output'
|
|
208
273
|
});
|
|
@@ -218,7 +283,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
218
283
|
}, {
|
|
219
284
|
key: "_buildTooltip",
|
|
220
285
|
value: function _buildTooltip(object) {
|
|
221
|
-
var
|
|
286
|
+
var _this3 = this;
|
|
222
287
|
// Remove any existing tooltip first
|
|
223
288
|
this.hide();
|
|
224
289
|
// Re-assign selected object since hide() clears it
|
|
@@ -286,9 +351,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
286
351
|
list.appendChild(item);
|
|
287
352
|
|
|
288
353
|
// Data point rows (one per data point definition stored in userData)
|
|
289
|
-
|
|
354
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
355
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
290
356
|
device.dataPoints.forEach(function (dp) {
|
|
291
|
-
var row =
|
|
357
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
292
358
|
list.appendChild(row);
|
|
293
359
|
});
|
|
294
360
|
}
|
|
@@ -299,11 +365,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
299
365
|
// Hover expand/collapse
|
|
300
366
|
trigger.addEventListener('mouseenter', function () {
|
|
301
367
|
ioSection.classList.add('expanded');
|
|
302
|
-
|
|
368
|
+
_this3._ioExpanded = true;
|
|
303
369
|
});
|
|
304
370
|
ioSection.addEventListener('mouseleave', function () {
|
|
305
371
|
ioSection.classList.remove('expanded');
|
|
306
|
-
|
|
372
|
+
_this3._ioExpanded = false;
|
|
307
373
|
});
|
|
308
374
|
card.appendChild(ioSection);
|
|
309
375
|
} else {
|
|
@@ -347,11 +413,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
347
413
|
}, {
|
|
348
414
|
key: "_positionTooltip",
|
|
349
415
|
value: function _positionTooltip() {
|
|
350
|
-
var _this$
|
|
416
|
+
var _this$sceneViewer2, _this$sceneViewer3;
|
|
351
417
|
if (!this.tooltipEl || !this.selectedObject) return;
|
|
352
418
|
var container = this._getContainer();
|
|
353
|
-
var camera = (_this$
|
|
354
|
-
var renderer = (_this$
|
|
419
|
+
var camera = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.camera;
|
|
420
|
+
var renderer = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.renderer;
|
|
355
421
|
if (!container || !camera || !renderer) return;
|
|
356
422
|
|
|
357
423
|
// Compute bounding box to position above the component
|
|
@@ -388,8 +454,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
388
454
|
}, {
|
|
389
455
|
key: "_getContainer",
|
|
390
456
|
value: function _getContainer() {
|
|
391
|
-
var _this$
|
|
392
|
-
return ((_this$
|
|
457
|
+
var _this$sceneViewer4;
|
|
458
|
+
return ((_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.renderer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.domElement) === null || _this$sceneViewer4 === void 0 ? void 0 : _this$sceneViewer4.parentElement) || null;
|
|
393
459
|
}
|
|
394
460
|
|
|
395
461
|
// -----------------------------------------------------------------------
|
|
@@ -402,18 +468,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
402
468
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
403
469
|
* Input / bidirectional → shows an interactive control.
|
|
404
470
|
*
|
|
405
|
-
* @param {string} attachmentId
|
|
471
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
406
472
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
407
473
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
474
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
408
475
|
* @returns {HTMLElement}
|
|
409
476
|
*/
|
|
410
477
|
}, {
|
|
411
478
|
key: "_buildDataPointRow",
|
|
412
|
-
value: function _buildDataPointRow(
|
|
413
|
-
var
|
|
479
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
480
|
+
var _ref2,
|
|
414
481
|
_this$_stateAdapter$g,
|
|
415
482
|
_this$_stateAdapter,
|
|
416
|
-
|
|
483
|
+
_this4 = this;
|
|
417
484
|
var row = document.createElement('div');
|
|
418
485
|
row.className = 'cp-tooltip__dp-row';
|
|
419
486
|
var nameEl = document.createElement('span');
|
|
@@ -421,20 +488,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
421
488
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
422
489
|
row.appendChild(nameEl);
|
|
423
490
|
var dpId = dp.id || dp.name;
|
|
424
|
-
var key = "".concat(
|
|
491
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
425
492
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
426
493
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
427
494
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
428
|
-
var currentVal = (
|
|
495
|
+
var currentVal = (_ref2 = (_this$_stateAdapter$g = (_this$_stateAdapter = this._stateAdapter) === null || _this$_stateAdapter === void 0 ? void 0 : _this$_stateAdapter.getState(scopedAttachmentId, dpId)) !== null && _this$_stateAdapter$g !== void 0 ? _this$_stateAdapter$g : dp.defaultValue) !== null && _ref2 !== void 0 ? _ref2 : null;
|
|
429
496
|
if (isInput) {
|
|
430
497
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
431
|
-
var
|
|
432
|
-
(
|
|
498
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
499
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
433
500
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
434
501
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
435
502
|
// don't bleed across clones that share the same attachmentId.
|
|
436
|
-
|
|
437
|
-
|
|
503
|
+
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
504
|
+
var parentUuid = ((_this4$selectedObject = _this4.selectedObject) === null || _this4$selectedObject === void 0 ? void 0 : _this4$selectedObject.uuid) || null;
|
|
505
|
+
(_this4$sceneViewer = _this4.sceneViewer) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.managers) === null || _this4$sceneViewer === void 0 || (_this4$sceneViewer = _this4$sceneViewer.behaviorManager) === null || _this4$sceneViewer === void 0 || _this4$sceneViewer.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
438
506
|
});
|
|
439
507
|
row.appendChild(ctrl);
|
|
440
508
|
this._stateElements.set(key, {
|
|
@@ -584,20 +652,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
584
652
|
/**
|
|
585
653
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
586
654
|
* Called each frame from update() — skips if no adapter is configured.
|
|
655
|
+
* Key format is scopedAttachmentId::dataPointId where scopedAttachmentId
|
|
656
|
+
* can be parentUuid::attachmentId, resulting in parentUuid::attachmentId::dataPointId
|
|
587
657
|
*/
|
|
588
658
|
}, {
|
|
589
659
|
key: "_refreshStateDisplays",
|
|
590
660
|
value: function _refreshStateDisplays() {
|
|
591
|
-
var
|
|
661
|
+
var _this5 = this;
|
|
592
662
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
593
663
|
this._stateElements.forEach(function (entry, key) {
|
|
594
664
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
595
|
-
|
|
665
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
666
|
+
var sepIdx = key.lastIndexOf('::');
|
|
596
667
|
if (sepIdx === -1) return;
|
|
597
|
-
var
|
|
668
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
598
669
|
var dataPointId = key.slice(sepIdx + 2);
|
|
599
|
-
var val =
|
|
600
|
-
|
|
670
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
671
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
601
672
|
});
|
|
602
673
|
}
|
|
603
674
|
}]);
|
|
@@ -138,6 +138,12 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
138
138
|
// Computed from geometry - not in input format
|
|
139
139
|
'name',
|
|
140
140
|
// Redundant with GLB node names - not in input format
|
|
141
|
+
'addedTimestamp',
|
|
142
|
+
// Internal tracking - not needed in export
|
|
143
|
+
'addedBy',
|
|
144
|
+
// Internal tracking - not needed in export
|
|
145
|
+
'initialPosition',
|
|
146
|
+
// Internal tracking - not needed in export
|
|
141
147
|
// Exclude internal segment tracking properties
|
|
142
148
|
'segmentId',
|
|
143
149
|
// Internal tracking
|