@2112-lab/central-plant 0.1.86 → 0.1.88
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 +78 -38
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/managers/components/componentDataManager.js +4 -1
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +67 -36
- package/dist/cjs/src/managers/scene/sceneExportManager.js +6 -0
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/managers/components/componentDataManager.js +4 -1
- package/dist/esm/src/managers/scene/componentTooltipManager.js +67 -36
- package/dist/esm/src/managers/scene/sceneExportManager.js +6 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -11375,6 +11375,12 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
11375
11375
|
// Computed from geometry - not in input format
|
|
11376
11376
|
'name',
|
|
11377
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
|
|
11378
11384
|
// Exclude internal segment tracking properties
|
|
11379
11385
|
'segmentId',
|
|
11380
11386
|
// Internal tracking
|
|
@@ -19786,6 +19792,7 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
19786
19792
|
id: key,
|
|
19787
19793
|
name: component.name,
|
|
19788
19794
|
type: ((_component$metadata = component.metadata) === null || _component$metadata === void 0 ? void 0 : _component$metadata.type) || 'Component',
|
|
19795
|
+
assetType: component.assetType || null,
|
|
19789
19796
|
category: component.category,
|
|
19790
19797
|
modelKey: component.modelKey,
|
|
19791
19798
|
modelType: component.modelType,
|
|
@@ -19794,10 +19801,12 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
19794
19801
|
// Preserve S3 metadata
|
|
19795
19802
|
isS3Component: component.isS3Component,
|
|
19796
19803
|
s3Path: component.s3Path,
|
|
19797
|
-
preLoad: component.preLoad
|
|
19804
|
+
preLoad: component.preLoad,
|
|
19805
|
+
preCache: component.preCache
|
|
19798
19806
|
};
|
|
19799
19807
|
return _objectSpread2(_objectSpread2({}, baseData), {}, {
|
|
19800
19808
|
metadata: component.metadata || {},
|
|
19809
|
+
ioConfig: component.ioConfig || null,
|
|
19801
19810
|
boundingBox: component.boundingBox || null,
|
|
19802
19811
|
adaptedBoundingBox: component.adaptedBoundingBox || null,
|
|
19803
19812
|
children: component.children || [],
|
|
@@ -33790,24 +33799,14 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33790
33799
|
}, {
|
|
33791
33800
|
key: "toggleIODeviceBinaryState",
|
|
33792
33801
|
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
33793
|
-
var _this$sceneViewer;
|
|
33802
|
+
var _ref, _this$sceneViewer;
|
|
33794
33803
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
33795
33804
|
var ud = ioDeviceObject.userData;
|
|
33796
33805
|
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
33797
33806
|
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
33798
33807
|
if (!attachmentId) return;
|
|
33799
33808
|
|
|
33800
|
-
//
|
|
33801
|
-
var binaryState = dataPoints.find(function (dp) {
|
|
33802
|
-
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
33803
|
-
});
|
|
33804
|
-
if (!binaryState) return;
|
|
33805
|
-
var dpId = binaryState.id;
|
|
33806
|
-
var currentVal = this._stateAdapter.getState(attachmentId, dpId);
|
|
33807
|
-
var newVal = !Boolean(currentVal);
|
|
33808
|
-
this._stateAdapter.setState(attachmentId, dpId, newVal);
|
|
33809
|
-
|
|
33810
|
-
// Walk up to find parent component UUID for scoped behavior triggering
|
|
33809
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
33811
33810
|
var parentUuid = null;
|
|
33812
33811
|
var obj = ioDeviceObject.parent;
|
|
33813
33812
|
while (obj) {
|
|
@@ -33818,8 +33817,24 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33818
33817
|
}
|
|
33819
33818
|
obj = obj.parent;
|
|
33820
33819
|
}
|
|
33820
|
+
|
|
33821
|
+
// Create a scoped attachment key to prevent state sharing between instances
|
|
33822
|
+
// of the same smart component that share the same attachmentId
|
|
33823
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
33824
|
+
|
|
33825
|
+
// Find the first binary state
|
|
33826
|
+
var binaryState = dataPoints.find(function (dp) {
|
|
33827
|
+
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
33828
|
+
});
|
|
33829
|
+
if (!binaryState) return;
|
|
33830
|
+
var dpId = binaryState.id;
|
|
33831
|
+
var storedVal = this._stateAdapter.getState(scopedAttachmentId, dpId);
|
|
33832
|
+
// Fall back to defaultValue when state is uninitialized (null/undefined)
|
|
33833
|
+
var currentVal = (_ref = storedVal !== null && storedVal !== void 0 ? storedVal : binaryState.defaultValue) !== null && _ref !== void 0 ? _ref : false;
|
|
33834
|
+
var newVal = !Boolean(currentVal);
|
|
33835
|
+
this._stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
33821
33836
|
(_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);
|
|
33822
|
-
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(
|
|
33837
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
33823
33838
|
}
|
|
33824
33839
|
|
|
33825
33840
|
/**
|
|
@@ -33911,23 +33926,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33911
33926
|
this._styleInjected = false;
|
|
33912
33927
|
}
|
|
33913
33928
|
|
|
33929
|
+
/**
|
|
33930
|
+
* Generate a scoped attachment key that includes the parent component UUID.
|
|
33931
|
+
* This ensures each instance of a smart component has isolated IO device state.
|
|
33932
|
+
* @param {string} attachmentId - The original attachment ID from the component data
|
|
33933
|
+
* @param {string|null} parentUuid - The UUID of the parent smart component instance
|
|
33934
|
+
* @returns {string} A scoped key in the format "parentUuid::attachmentId" or just attachmentId if no parent
|
|
33935
|
+
* @private
|
|
33936
|
+
*/
|
|
33937
|
+
}, {
|
|
33938
|
+
key: "_getScopedAttachmentKey",
|
|
33939
|
+
value: function _getScopedAttachmentKey(attachmentId, parentUuid) {
|
|
33940
|
+
if (!parentUuid) return attachmentId;
|
|
33941
|
+
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
33942
|
+
}
|
|
33943
|
+
|
|
33914
33944
|
/**
|
|
33915
33945
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
33916
33946
|
* Returns richer data including attachmentId and data point definitions.
|
|
33917
|
-
* @param {THREE.Object3D} object
|
|
33918
|
-
* @returns {{ label: string, deviceId: string, attachmentId: string, dataPoints: Array }[]}
|
|
33947
|
+
* @param {THREE.Object3D} object - The parent component object
|
|
33948
|
+
* @returns {{ label: string, deviceId: string, attachmentId: string, scopedAttachmentId: string, dataPoints: Array }[]}
|
|
33919
33949
|
*/
|
|
33920
33950
|
}, {
|
|
33921
33951
|
key: "_getIODevices",
|
|
33922
33952
|
value: function _getIODevices(object) {
|
|
33953
|
+
var _this2 = this;
|
|
33923
33954
|
var devices = [];
|
|
33955
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
33924
33956
|
object.traverse(function (child) {
|
|
33925
33957
|
var _child$userData;
|
|
33926
33958
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
33959
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
33927
33960
|
devices.push({
|
|
33928
33961
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
33929
33962
|
deviceId: child.userData.deviceId || '',
|
|
33930
|
-
attachmentId:
|
|
33963
|
+
attachmentId: attachmentId,
|
|
33964
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
33931
33965
|
dataPoints: child.userData.dataPoints || [],
|
|
33932
33966
|
direction: child.userData.ioDirection || 'output'
|
|
33933
33967
|
});
|
|
@@ -33943,7 +33977,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
33943
33977
|
}, {
|
|
33944
33978
|
key: "_buildTooltip",
|
|
33945
33979
|
value: function _buildTooltip(object) {
|
|
33946
|
-
var
|
|
33980
|
+
var _this3 = this;
|
|
33947
33981
|
// Remove any existing tooltip first
|
|
33948
33982
|
this.hide();
|
|
33949
33983
|
// Re-assign selected object since hide() clears it
|
|
@@ -34011,9 +34045,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34011
34045
|
list.appendChild(item);
|
|
34012
34046
|
|
|
34013
34047
|
// Data point rows (one per data point definition stored in userData)
|
|
34014
|
-
|
|
34048
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
34049
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
34015
34050
|
device.dataPoints.forEach(function (dp) {
|
|
34016
|
-
var row =
|
|
34051
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
34017
34052
|
list.appendChild(row);
|
|
34018
34053
|
});
|
|
34019
34054
|
}
|
|
@@ -34024,11 +34059,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34024
34059
|
// Hover expand/collapse
|
|
34025
34060
|
trigger.addEventListener('mouseenter', function () {
|
|
34026
34061
|
ioSection.classList.add('expanded');
|
|
34027
|
-
|
|
34062
|
+
_this3._ioExpanded = true;
|
|
34028
34063
|
});
|
|
34029
34064
|
ioSection.addEventListener('mouseleave', function () {
|
|
34030
34065
|
ioSection.classList.remove('expanded');
|
|
34031
|
-
|
|
34066
|
+
_this3._ioExpanded = false;
|
|
34032
34067
|
});
|
|
34033
34068
|
card.appendChild(ioSection);
|
|
34034
34069
|
} else {
|
|
@@ -34127,18 +34162,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34127
34162
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
34128
34163
|
* Input / bidirectional → shows an interactive control.
|
|
34129
34164
|
*
|
|
34130
|
-
* @param {string} attachmentId
|
|
34165
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
34131
34166
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
34132
34167
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
34168
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
34133
34169
|
* @returns {HTMLElement}
|
|
34134
34170
|
*/
|
|
34135
34171
|
}, {
|
|
34136
34172
|
key: "_buildDataPointRow",
|
|
34137
|
-
value: function _buildDataPointRow(
|
|
34138
|
-
var
|
|
34173
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
34174
|
+
var _ref2,
|
|
34139
34175
|
_this$_stateAdapter$g,
|
|
34140
34176
|
_this$_stateAdapter,
|
|
34141
|
-
|
|
34177
|
+
_this4 = this;
|
|
34142
34178
|
var row = document.createElement('div');
|
|
34143
34179
|
row.className = 'cp-tooltip__dp-row';
|
|
34144
34180
|
var nameEl = document.createElement('span');
|
|
@@ -34146,20 +34182,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34146
34182
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
34147
34183
|
row.appendChild(nameEl);
|
|
34148
34184
|
var dpId = dp.id || dp.name;
|
|
34149
|
-
var key = "".concat(
|
|
34185
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
34150
34186
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
34151
34187
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
34152
34188
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
34153
|
-
var currentVal = (
|
|
34189
|
+
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;
|
|
34154
34190
|
if (isInput) {
|
|
34155
34191
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
34156
|
-
var
|
|
34157
|
-
(
|
|
34192
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
34193
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
34158
34194
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
34159
34195
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
34160
34196
|
// don't bleed across clones that share the same attachmentId.
|
|
34161
|
-
|
|
34162
|
-
|
|
34197
|
+
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
34198
|
+
var parentUuid = ((_this4$selectedObject = _this4.selectedObject) === null || _this4$selectedObject === void 0 ? void 0 : _this4$selectedObject.uuid) || null;
|
|
34199
|
+
(_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);
|
|
34163
34200
|
});
|
|
34164
34201
|
row.appendChild(ctrl);
|
|
34165
34202
|
this._stateElements.set(key, {
|
|
@@ -34309,20 +34346,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34309
34346
|
/**
|
|
34310
34347
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
34311
34348
|
* Called each frame from update() — skips if no adapter is configured.
|
|
34349
|
+
* Key format is scopedAttachmentId::dataPointId where scopedAttachmentId
|
|
34350
|
+
* can be parentUuid::attachmentId, resulting in parentUuid::attachmentId::dataPointId
|
|
34312
34351
|
*/
|
|
34313
34352
|
}, {
|
|
34314
34353
|
key: "_refreshStateDisplays",
|
|
34315
34354
|
value: function _refreshStateDisplays() {
|
|
34316
|
-
var
|
|
34355
|
+
var _this5 = this;
|
|
34317
34356
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
34318
34357
|
this._stateElements.forEach(function (entry, key) {
|
|
34319
34358
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
34320
|
-
|
|
34359
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
34360
|
+
var sepIdx = key.lastIndexOf('::');
|
|
34321
34361
|
if (sepIdx === -1) return;
|
|
34322
|
-
var
|
|
34362
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
34323
34363
|
var dataPointId = key.slice(sepIdx + 2);
|
|
34324
|
-
var val =
|
|
34325
|
-
|
|
34364
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
34365
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
34326
34366
|
});
|
|
34327
34367
|
}
|
|
34328
34368
|
}]);
|
|
@@ -36734,7 +36774,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
36734
36774
|
* Initialize the CentralPlant manager
|
|
36735
36775
|
*
|
|
36736
36776
|
* @constructor
|
|
36737
|
-
* @version 0.1.
|
|
36777
|
+
* @version 0.1.88
|
|
36738
36778
|
* @updated 2025-10-22
|
|
36739
36779
|
*
|
|
36740
36780
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -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.88
|
|
23
23
|
* @updated 2025-10-22
|
|
24
24
|
*
|
|
25
25
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -845,6 +845,7 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
845
845
|
id: key,
|
|
846
846
|
name: component.name,
|
|
847
847
|
type: ((_component$metadata = component.metadata) === null || _component$metadata === void 0 ? void 0 : _component$metadata.type) || 'Component',
|
|
848
|
+
assetType: component.assetType || null,
|
|
848
849
|
category: component.category,
|
|
849
850
|
modelKey: component.modelKey,
|
|
850
851
|
modelType: component.modelType,
|
|
@@ -853,10 +854,12 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
853
854
|
// Preserve S3 metadata
|
|
854
855
|
isS3Component: component.isS3Component,
|
|
855
856
|
s3Path: component.s3Path,
|
|
856
|
-
preLoad: component.preLoad
|
|
857
|
+
preLoad: component.preLoad,
|
|
858
|
+
preCache: component.preCache
|
|
857
859
|
};
|
|
858
860
|
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, baseData), {}, {
|
|
859
861
|
metadata: component.metadata || {},
|
|
862
|
+
ioConfig: component.ioConfig || null,
|
|
860
863
|
boundingBox: component.boundingBox || null,
|
|
861
864
|
adaptedBoundingBox: component.adaptedBoundingBox || null,
|
|
862
865
|
children: component.children || [],
|
|
@@ -129,24 +129,14 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
129
129
|
}, {
|
|
130
130
|
key: "toggleIODeviceBinaryState",
|
|
131
131
|
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
132
|
-
var _this$sceneViewer;
|
|
132
|
+
var _ref, _this$sceneViewer;
|
|
133
133
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
134
134
|
var ud = ioDeviceObject.userData;
|
|
135
135
|
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
136
136
|
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
137
137
|
if (!attachmentId) return;
|
|
138
138
|
|
|
139
|
-
//
|
|
140
|
-
var binaryState = dataPoints.find(function (dp) {
|
|
141
|
-
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
142
|
-
});
|
|
143
|
-
if (!binaryState) return;
|
|
144
|
-
var dpId = binaryState.id;
|
|
145
|
-
var currentVal = this._stateAdapter.getState(attachmentId, dpId);
|
|
146
|
-
var newVal = !Boolean(currentVal);
|
|
147
|
-
this._stateAdapter.setState(attachmentId, dpId, newVal);
|
|
148
|
-
|
|
149
|
-
// Walk up to find parent component UUID for scoped behavior triggering
|
|
139
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
150
140
|
var parentUuid = null;
|
|
151
141
|
var obj = ioDeviceObject.parent;
|
|
152
142
|
while (obj) {
|
|
@@ -157,8 +147,24 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
157
147
|
}
|
|
158
148
|
obj = obj.parent;
|
|
159
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);
|
|
160
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);
|
|
161
|
-
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(
|
|
167
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
/**
|
|
@@ -250,23 +256,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
250
256
|
this._styleInjected = false;
|
|
251
257
|
}
|
|
252
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
|
+
|
|
253
274
|
/**
|
|
254
275
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
255
276
|
* Returns richer data including attachmentId and data point definitions.
|
|
256
|
-
* @param {THREE.Object3D} object
|
|
257
|
-
* @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 }[]}
|
|
258
279
|
*/
|
|
259
280
|
}, {
|
|
260
281
|
key: "_getIODevices",
|
|
261
282
|
value: function _getIODevices(object) {
|
|
283
|
+
var _this2 = this;
|
|
262
284
|
var devices = [];
|
|
285
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
263
286
|
object.traverse(function (child) {
|
|
264
287
|
var _child$userData;
|
|
265
288
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
289
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
266
290
|
devices.push({
|
|
267
291
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
268
292
|
deviceId: child.userData.deviceId || '',
|
|
269
|
-
attachmentId:
|
|
293
|
+
attachmentId: attachmentId,
|
|
294
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
270
295
|
dataPoints: child.userData.dataPoints || [],
|
|
271
296
|
direction: child.userData.ioDirection || 'output'
|
|
272
297
|
});
|
|
@@ -282,7 +307,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
282
307
|
}, {
|
|
283
308
|
key: "_buildTooltip",
|
|
284
309
|
value: function _buildTooltip(object) {
|
|
285
|
-
var
|
|
310
|
+
var _this3 = this;
|
|
286
311
|
// Remove any existing tooltip first
|
|
287
312
|
this.hide();
|
|
288
313
|
// Re-assign selected object since hide() clears it
|
|
@@ -350,9 +375,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
350
375
|
list.appendChild(item);
|
|
351
376
|
|
|
352
377
|
// Data point rows (one per data point definition stored in userData)
|
|
353
|
-
|
|
378
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
379
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
354
380
|
device.dataPoints.forEach(function (dp) {
|
|
355
|
-
var row =
|
|
381
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
356
382
|
list.appendChild(row);
|
|
357
383
|
});
|
|
358
384
|
}
|
|
@@ -363,11 +389,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
363
389
|
// Hover expand/collapse
|
|
364
390
|
trigger.addEventListener('mouseenter', function () {
|
|
365
391
|
ioSection.classList.add('expanded');
|
|
366
|
-
|
|
392
|
+
_this3._ioExpanded = true;
|
|
367
393
|
});
|
|
368
394
|
ioSection.addEventListener('mouseleave', function () {
|
|
369
395
|
ioSection.classList.remove('expanded');
|
|
370
|
-
|
|
396
|
+
_this3._ioExpanded = false;
|
|
371
397
|
});
|
|
372
398
|
card.appendChild(ioSection);
|
|
373
399
|
} else {
|
|
@@ -466,18 +492,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
466
492
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
467
493
|
* Input / bidirectional → shows an interactive control.
|
|
468
494
|
*
|
|
469
|
-
* @param {string} attachmentId
|
|
495
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
470
496
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
471
497
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
498
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
472
499
|
* @returns {HTMLElement}
|
|
473
500
|
*/
|
|
474
501
|
}, {
|
|
475
502
|
key: "_buildDataPointRow",
|
|
476
|
-
value: function _buildDataPointRow(
|
|
477
|
-
var
|
|
503
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
504
|
+
var _ref2,
|
|
478
505
|
_this$_stateAdapter$g,
|
|
479
506
|
_this$_stateAdapter,
|
|
480
|
-
|
|
507
|
+
_this4 = this;
|
|
481
508
|
var row = document.createElement('div');
|
|
482
509
|
row.className = 'cp-tooltip__dp-row';
|
|
483
510
|
var nameEl = document.createElement('span');
|
|
@@ -485,20 +512,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
485
512
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
486
513
|
row.appendChild(nameEl);
|
|
487
514
|
var dpId = dp.id || dp.name;
|
|
488
|
-
var key = "".concat(
|
|
515
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
489
516
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
490
517
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
491
518
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
492
|
-
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;
|
|
493
520
|
if (isInput) {
|
|
494
521
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
495
|
-
var
|
|
496
|
-
(
|
|
522
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
523
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
497
524
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
498
525
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
499
526
|
// don't bleed across clones that share the same attachmentId.
|
|
500
|
-
|
|
501
|
-
|
|
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);
|
|
502
530
|
});
|
|
503
531
|
row.appendChild(ctrl);
|
|
504
532
|
this._stateElements.set(key, {
|
|
@@ -648,20 +676,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
648
676
|
/**
|
|
649
677
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
650
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
|
|
651
681
|
*/
|
|
652
682
|
}, {
|
|
653
683
|
key: "_refreshStateDisplays",
|
|
654
684
|
value: function _refreshStateDisplays() {
|
|
655
|
-
var
|
|
685
|
+
var _this5 = this;
|
|
656
686
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
657
687
|
this._stateElements.forEach(function (entry, key) {
|
|
658
688
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
659
|
-
|
|
689
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
690
|
+
var sepIdx = key.lastIndexOf('::');
|
|
660
691
|
if (sepIdx === -1) return;
|
|
661
|
-
var
|
|
692
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
662
693
|
var dataPointId = key.slice(sepIdx + 2);
|
|
663
|
-
var val =
|
|
664
|
-
|
|
694
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
695
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
665
696
|
});
|
|
666
697
|
}
|
|
667
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.88
|
|
19
19
|
* @updated 2025-10-22
|
|
20
20
|
*
|
|
21
21
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -821,6 +821,7 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
821
821
|
id: key,
|
|
822
822
|
name: component.name,
|
|
823
823
|
type: ((_component$metadata = component.metadata) === null || _component$metadata === void 0 ? void 0 : _component$metadata.type) || 'Component',
|
|
824
|
+
assetType: component.assetType || null,
|
|
824
825
|
category: component.category,
|
|
825
826
|
modelKey: component.modelKey,
|
|
826
827
|
modelType: component.modelType,
|
|
@@ -829,10 +830,12 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
829
830
|
// Preserve S3 metadata
|
|
830
831
|
isS3Component: component.isS3Component,
|
|
831
832
|
s3Path: component.s3Path,
|
|
832
|
-
preLoad: component.preLoad
|
|
833
|
+
preLoad: component.preLoad,
|
|
834
|
+
preCache: component.preCache
|
|
833
835
|
};
|
|
834
836
|
return _objectSpread2(_objectSpread2({}, baseData), {}, {
|
|
835
837
|
metadata: component.metadata || {},
|
|
838
|
+
ioConfig: component.ioConfig || null,
|
|
836
839
|
boundingBox: component.boundingBox || null,
|
|
837
840
|
adaptedBoundingBox: component.adaptedBoundingBox || null,
|
|
838
841
|
children: component.children || [],
|
|
@@ -105,24 +105,14 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
105
105
|
}, {
|
|
106
106
|
key: "toggleIODeviceBinaryState",
|
|
107
107
|
value: function toggleIODeviceBinaryState(ioDeviceObject) {
|
|
108
|
-
var _this$sceneViewer;
|
|
108
|
+
var _ref, _this$sceneViewer;
|
|
109
109
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
110
110
|
var ud = ioDeviceObject.userData;
|
|
111
111
|
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
112
112
|
var dataPoints = (ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [];
|
|
113
113
|
if (!attachmentId) return;
|
|
114
114
|
|
|
115
|
-
//
|
|
116
|
-
var binaryState = dataPoints.find(function (dp) {
|
|
117
|
-
return dp.stateType === 'binary' || dp.type === 'binary';
|
|
118
|
-
});
|
|
119
|
-
if (!binaryState) return;
|
|
120
|
-
var dpId = binaryState.id;
|
|
121
|
-
var currentVal = this._stateAdapter.getState(attachmentId, dpId);
|
|
122
|
-
var newVal = !Boolean(currentVal);
|
|
123
|
-
this._stateAdapter.setState(attachmentId, dpId, newVal);
|
|
124
|
-
|
|
125
|
-
// Walk up to find parent component UUID for scoped behavior triggering
|
|
115
|
+
// Walk up to find parent component UUID for scoped state/behavior handling
|
|
126
116
|
var parentUuid = null;
|
|
127
117
|
var obj = ioDeviceObject.parent;
|
|
128
118
|
while (obj) {
|
|
@@ -133,8 +123,24 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
133
123
|
}
|
|
134
124
|
obj = obj.parent;
|
|
135
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);
|
|
136
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);
|
|
137
|
-
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(
|
|
143
|
+
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
138
144
|
}
|
|
139
145
|
|
|
140
146
|
/**
|
|
@@ -226,23 +232,42 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
226
232
|
this._styleInjected = false;
|
|
227
233
|
}
|
|
228
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
|
+
|
|
229
250
|
/**
|
|
230
251
|
* Gather I/O device children from a component's Three.js hierarchy.
|
|
231
252
|
* Returns richer data including attachmentId and data point definitions.
|
|
232
|
-
* @param {THREE.Object3D} object
|
|
233
|
-
* @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 }[]}
|
|
234
255
|
*/
|
|
235
256
|
}, {
|
|
236
257
|
key: "_getIODevices",
|
|
237
258
|
value: function _getIODevices(object) {
|
|
259
|
+
var _this2 = this;
|
|
238
260
|
var devices = [];
|
|
261
|
+
var parentUuid = object.uuid; // The component's own UUID
|
|
239
262
|
object.traverse(function (child) {
|
|
240
263
|
var _child$userData;
|
|
241
264
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
265
|
+
var attachmentId = child.userData.attachmentId || '';
|
|
242
266
|
devices.push({
|
|
243
267
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
244
268
|
deviceId: child.userData.deviceId || '',
|
|
245
|
-
attachmentId:
|
|
269
|
+
attachmentId: attachmentId,
|
|
270
|
+
scopedAttachmentId: _this2._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
246
271
|
dataPoints: child.userData.dataPoints || [],
|
|
247
272
|
direction: child.userData.ioDirection || 'output'
|
|
248
273
|
});
|
|
@@ -258,7 +283,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
258
283
|
}, {
|
|
259
284
|
key: "_buildTooltip",
|
|
260
285
|
value: function _buildTooltip(object) {
|
|
261
|
-
var
|
|
286
|
+
var _this3 = this;
|
|
262
287
|
// Remove any existing tooltip first
|
|
263
288
|
this.hide();
|
|
264
289
|
// Re-assign selected object since hide() clears it
|
|
@@ -326,9 +351,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
326
351
|
list.appendChild(item);
|
|
327
352
|
|
|
328
353
|
// Data point rows (one per data point definition stored in userData)
|
|
329
|
-
|
|
354
|
+
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
355
|
+
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
330
356
|
device.dataPoints.forEach(function (dp) {
|
|
331
|
-
var row =
|
|
357
|
+
var row = _this3._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
332
358
|
list.appendChild(row);
|
|
333
359
|
});
|
|
334
360
|
}
|
|
@@ -339,11 +365,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
339
365
|
// Hover expand/collapse
|
|
340
366
|
trigger.addEventListener('mouseenter', function () {
|
|
341
367
|
ioSection.classList.add('expanded');
|
|
342
|
-
|
|
368
|
+
_this3._ioExpanded = true;
|
|
343
369
|
});
|
|
344
370
|
ioSection.addEventListener('mouseleave', function () {
|
|
345
371
|
ioSection.classList.remove('expanded');
|
|
346
|
-
|
|
372
|
+
_this3._ioExpanded = false;
|
|
347
373
|
});
|
|
348
374
|
card.appendChild(ioSection);
|
|
349
375
|
} else {
|
|
@@ -442,18 +468,19 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
442
468
|
* Output / read-only direction → shows a state badge (updated each frame).
|
|
443
469
|
* Input / bidirectional → shows an interactive control.
|
|
444
470
|
*
|
|
445
|
-
* @param {string} attachmentId
|
|
471
|
+
* @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
|
|
446
472
|
* @param {Object} dp - data point definition from ioConfig.dataPoints
|
|
447
473
|
* @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
|
|
474
|
+
* @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
|
|
448
475
|
* @returns {HTMLElement}
|
|
449
476
|
*/
|
|
450
477
|
}, {
|
|
451
478
|
key: "_buildDataPointRow",
|
|
452
|
-
value: function _buildDataPointRow(
|
|
453
|
-
var
|
|
479
|
+
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
480
|
+
var _ref2,
|
|
454
481
|
_this$_stateAdapter$g,
|
|
455
482
|
_this$_stateAdapter,
|
|
456
|
-
|
|
483
|
+
_this4 = this;
|
|
457
484
|
var row = document.createElement('div');
|
|
458
485
|
row.className = 'cp-tooltip__dp-row';
|
|
459
486
|
var nameEl = document.createElement('span');
|
|
@@ -461,20 +488,21 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
461
488
|
nameEl.textContent = dp.name || dp.id || '?';
|
|
462
489
|
row.appendChild(nameEl);
|
|
463
490
|
var dpId = dp.id || dp.name;
|
|
464
|
-
var key = "".concat(
|
|
491
|
+
var key = "".concat(scopedAttachmentId, "::").concat(dpId);
|
|
465
492
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
466
493
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
467
494
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
468
|
-
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;
|
|
469
496
|
if (isInput) {
|
|
470
497
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
471
|
-
var
|
|
472
|
-
(
|
|
498
|
+
var _this4$_stateAdapter, _this4$selectedObject, _this4$sceneViewer;
|
|
499
|
+
(_this4$_stateAdapter = _this4._stateAdapter) === null || _this4$_stateAdapter === void 0 || _this4$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
473
500
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
474
501
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
475
502
|
// don't bleed across clones that share the same attachmentId.
|
|
476
|
-
|
|
477
|
-
|
|
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);
|
|
478
506
|
});
|
|
479
507
|
row.appendChild(ctrl);
|
|
480
508
|
this._stateElements.set(key, {
|
|
@@ -624,20 +652,23 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
624
652
|
/**
|
|
625
653
|
* Re-read all tracked read-only badge values from the state adapter.
|
|
626
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
|
|
627
657
|
*/
|
|
628
658
|
}, {
|
|
629
659
|
key: "_refreshStateDisplays",
|
|
630
660
|
value: function _refreshStateDisplays() {
|
|
631
|
-
var
|
|
661
|
+
var _this5 = this;
|
|
632
662
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
633
663
|
this._stateElements.forEach(function (entry, key) {
|
|
634
664
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
635
|
-
|
|
665
|
+
// Use lastIndexOf since scopedAttachmentId may contain '::' (parentUuid::attachmentId)
|
|
666
|
+
var sepIdx = key.lastIndexOf('::');
|
|
636
667
|
if (sepIdx === -1) return;
|
|
637
|
-
var
|
|
668
|
+
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
638
669
|
var dataPointId = key.slice(sepIdx + 2);
|
|
639
|
-
var val =
|
|
640
|
-
|
|
670
|
+
var val = _this5._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
671
|
+
_this5._applyBadgeValue(entry.el, val, entry.dp);
|
|
641
672
|
});
|
|
642
673
|
}
|
|
643
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
|