brep-io-kernel 1.0.18 → 1.0.20
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-kernel/brep-kernel.js +9157 -8530
- package/package.json +1 -1
- package/src/FeatureRegistry.js +3 -0
- package/src/PartHistory.js +35 -0
- package/src/UI/SelectionFilter.js +262 -18
- package/src/UI/featureDialogs.js +268 -21
- package/src/UI/history/HistoryCollectionWidget.js +20 -1
- package/src/UI/pmi/AnnotationRegistry.js +3 -0
- package/src/assemblyConstraints/AssemblyConstraintRegistry.js +3 -0
- package/src/features/boolean/BooleanFeature.js +15 -0
- package/src/features/chamfer/ChamferFeature.js +12 -0
- package/src/features/extrude/ExtrudeFeature.js +11 -0
- package/src/features/fillet/FilletFeature.js +12 -0
- package/src/features/hole/HoleFeature.js +15 -0
- package/src/features/loft/LoftFeature.js +17 -0
- package/src/features/mirror/MirrorFeature.js +14 -0
- package/src/features/patternLinear/PatternLinearFeature.js +9 -0
- package/src/features/patternRadial/PatternRadialFeature.js +13 -0
- package/src/features/plane/PlaneFeature.js +10 -0
- package/src/features/revolve/RevolveFeature.js +15 -0
- package/src/features/sketch/SketchFeature.js +11 -0
- package/src/features/sweep/SweepFeature.js +17 -0
- package/src/features/transform/TransformFeature.js +12 -0
- package/src/features/tube/TubeFeature.js +69 -14
package/src/UI/featureDialogs.js
CHANGED
|
@@ -205,6 +205,7 @@ export class SchemaForm {
|
|
|
205
205
|
// If target is inside the same active element (e.g., clicking within the input), skip
|
|
206
206
|
if (target && typeof target.closest === 'function') {
|
|
207
207
|
if (target.closest('[active-reference-selection]')) return;
|
|
208
|
+
if (target.closest('.ref-active')) return;
|
|
208
209
|
}
|
|
209
210
|
this._stopActiveReferenceSelection();
|
|
210
211
|
} catch (_) { }
|
|
@@ -632,7 +633,7 @@ export class SchemaForm {
|
|
|
632
633
|
}
|
|
633
634
|
if (!mat) {
|
|
634
635
|
try {
|
|
635
|
-
mat = new LineMaterial({ color: colorHex, linewidth: 3, transparent: true, opacity: 0.95, worldUnits: false });
|
|
636
|
+
mat = new LineMaterial({ color: colorHex, linewidth: 3, transparent: true, opacity: 0.95, worldUnits: false, dashed: false });
|
|
636
637
|
} catch (_) { mat = null; }
|
|
637
638
|
}
|
|
638
639
|
if (mat && mat.color && typeof mat.color.set === 'function') {
|
|
@@ -643,6 +644,10 @@ export class SchemaForm {
|
|
|
643
644
|
try { mat.opacity = Number.isFinite(mat.opacity) ? Math.min(0.95, mat.opacity) : 0.95; } catch (_) { }
|
|
644
645
|
try { mat.depthTest = false; } catch (_) { }
|
|
645
646
|
try { mat.depthWrite = false; } catch (_) { }
|
|
647
|
+
try { if (typeof mat.dashed !== 'undefined') mat.dashed = false; } catch (_) { }
|
|
648
|
+
try { if (typeof mat.dashScale !== 'undefined') mat.dashScale = 1; } catch (_) { }
|
|
649
|
+
try { if (typeof mat.dashSize !== 'undefined') mat.dashSize = 1; } catch (_) { }
|
|
650
|
+
try { if (typeof mat.gapSize !== 'undefined') mat.gapSize = 0; } catch (_) { }
|
|
646
651
|
try { this._syncPreviewLineResolution(mat); } catch (_) { }
|
|
647
652
|
}
|
|
648
653
|
return mat;
|
|
@@ -724,6 +729,7 @@ export class SchemaForm {
|
|
|
724
729
|
child.userData = child.userData || {};
|
|
725
730
|
child.userData.refPreview = true;
|
|
726
731
|
child.userData.refName = refName;
|
|
732
|
+
if (!child.userData.previewType && child.type) child.userData.previewType = child.type;
|
|
727
733
|
} catch (_) { }
|
|
728
734
|
});
|
|
729
735
|
} catch (_) { }
|
|
@@ -741,20 +747,54 @@ export class SchemaForm {
|
|
|
741
747
|
return null;
|
|
742
748
|
}
|
|
743
749
|
|
|
750
|
+
_buildEdgePreviewFromObject(obj, refName, colorHex = REF_PREVIEW_COLORS.EDGE) {
|
|
751
|
+
if (!obj) return null;
|
|
752
|
+
const positions = this._extractEdgeWorldPositions(obj);
|
|
753
|
+
if (!positions || positions.length < 6) return null;
|
|
754
|
+
const geom = new LineGeometry();
|
|
755
|
+
geom.setPositions(positions);
|
|
756
|
+
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
757
|
+
const mat = this._createPreviewLineMaterial(obj.material, colorHex);
|
|
758
|
+
const line = new Line2(geom, mat || undefined);
|
|
759
|
+
try { line.computeLineDistances?.(); } catch (_) { }
|
|
760
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
761
|
+
line.type = 'REF_PREVIEW_EDGE';
|
|
762
|
+
return this._configurePreviewObject(line, refName, 'EDGE');
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
_extractFaceEdgePositions(face) {
|
|
766
|
+
if (!face) return [];
|
|
767
|
+
const out = [];
|
|
768
|
+
const addEdge = (edge) => {
|
|
769
|
+
const positions = this._extractEdgeWorldPositions(edge);
|
|
770
|
+
if (positions && positions.length >= 6) out.push(positions);
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
if (Array.isArray(face.edges) && face.edges.length) {
|
|
774
|
+
for (const edge of face.edges) addEdge(edge);
|
|
775
|
+
return out;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const faceName = face?.name || face?.userData?.faceName || null;
|
|
779
|
+
const parentSolid = face?.parentSolid || face?.userData?.parentSolid || face?.parent || null;
|
|
780
|
+
if (!faceName || !parentSolid || !Array.isArray(parentSolid.children)) return out;
|
|
781
|
+
|
|
782
|
+
for (const child of parentSolid.children) {
|
|
783
|
+
if (!child || child.type !== SelectionFilter.EDGE) continue;
|
|
784
|
+
const faceA = child?.userData?.faceA || null;
|
|
785
|
+
const faceB = child?.userData?.faceB || null;
|
|
786
|
+
if (faceA === faceName || faceB === faceName) {
|
|
787
|
+
addEdge(child);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return out;
|
|
791
|
+
}
|
|
792
|
+
|
|
744
793
|
_buildReferencePreviewObject(obj, refName) {
|
|
745
794
|
if (!obj) return null;
|
|
746
795
|
const type = String(obj.type || '').toUpperCase();
|
|
747
796
|
if (type === SelectionFilter.EDGE || type === 'EDGE') {
|
|
748
|
-
|
|
749
|
-
if (!positions || positions.length < 6) return null;
|
|
750
|
-
const geom = new LineGeometry();
|
|
751
|
-
geom.setPositions(positions);
|
|
752
|
-
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
753
|
-
const mat = this._createPreviewLineMaterial(obj.material, REF_PREVIEW_COLORS.EDGE);
|
|
754
|
-
const line = new Line2(geom, mat || undefined);
|
|
755
|
-
try { line.computeLineDistances?.(); } catch (_) { }
|
|
756
|
-
line.type = 'REF_PREVIEW_EDGE';
|
|
757
|
-
return this._configurePreviewObject(line, refName, 'EDGE');
|
|
797
|
+
return this._buildEdgePreviewFromObject(obj, refName, REF_PREVIEW_COLORS.EDGE);
|
|
758
798
|
}
|
|
759
799
|
if (type === SelectionFilter.FACE || type === SelectionFilter.PLANE || type === 'FACE' || type === 'PLANE') {
|
|
760
800
|
const geom = obj.geometry && typeof obj.geometry.clone === 'function' ? obj.geometry.clone() : null;
|
|
@@ -765,6 +805,20 @@ export class SchemaForm {
|
|
|
765
805
|
const mesh = new THREE.Mesh(geom, mat || undefined);
|
|
766
806
|
mesh.type = (type === SelectionFilter.PLANE || type === 'PLANE') ? 'REF_PREVIEW_PLANE' : 'REF_PREVIEW_FACE';
|
|
767
807
|
try { mesh.matrixAutoUpdate = false; } catch (_) { }
|
|
808
|
+
const edges = Array.isArray(obj.edges) ? obj.edges : [];
|
|
809
|
+
if (edges.length) {
|
|
810
|
+
const group = new THREE.Group();
|
|
811
|
+
group.type = mesh.type;
|
|
812
|
+
try { group.userData = group.userData || {}; } catch (_) { }
|
|
813
|
+
try { group.userData.previewHasEdges = true; } catch (_) { }
|
|
814
|
+
try { group.userData.previewHasFace = true; } catch (_) { }
|
|
815
|
+
group.add(mesh);
|
|
816
|
+
for (const edge of edges) {
|
|
817
|
+
const edgePreview = this._buildEdgePreviewFromObject(edge, refName, REF_PREVIEW_COLORS.EDGE);
|
|
818
|
+
if (edgePreview) group.add(edgePreview);
|
|
819
|
+
}
|
|
820
|
+
return this._configurePreviewObject(group, refName, mesh.type);
|
|
821
|
+
}
|
|
768
822
|
return this._configurePreviewObject(mesh, refName, mesh.type);
|
|
769
823
|
}
|
|
770
824
|
if (type === SelectionFilter.VERTEX || type === 'VERTEX') {
|
|
@@ -796,9 +850,32 @@ export class SchemaForm {
|
|
|
796
850
|
const mat = this._createPreviewLineMaterial(null, REF_PREVIEW_COLORS.EDGE);
|
|
797
851
|
const line = new Line2(geom, mat || undefined);
|
|
798
852
|
try { line.computeLineDistances?.(); } catch (_) { }
|
|
853
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
799
854
|
line.type = 'REF_PREVIEW_EDGE';
|
|
800
855
|
return this._configurePreviewObject(line, refName, 'EDGE');
|
|
801
856
|
}
|
|
857
|
+
if (type === 'FACE' || type === 'PLANE') {
|
|
858
|
+
const group = new THREE.Group();
|
|
859
|
+
group.type = type === 'PLANE' ? 'REF_PREVIEW_PLANE' : 'REF_PREVIEW_FACE';
|
|
860
|
+
try { group.userData = group.userData || {}; } catch (_) { }
|
|
861
|
+
try { group.userData.previewHasEdges = true; } catch (_) { }
|
|
862
|
+
const edges = Array.isArray(snapshot.edgePositions) ? snapshot.edgePositions : [];
|
|
863
|
+
for (const positions of edges) {
|
|
864
|
+
if (!Array.isArray(positions) || positions.length < 6) continue;
|
|
865
|
+
const geom = new LineGeometry();
|
|
866
|
+
geom.setPositions(positions);
|
|
867
|
+
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
868
|
+
const mat = this._createPreviewLineMaterial(null, REF_PREVIEW_COLORS.EDGE);
|
|
869
|
+
const line = new Line2(geom, mat || undefined);
|
|
870
|
+
try { line.computeLineDistances?.(); } catch (_) { }
|
|
871
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
872
|
+
line.type = 'REF_PREVIEW_EDGE';
|
|
873
|
+
this._configurePreviewObject(line, refName, 'EDGE');
|
|
874
|
+
group.add(line);
|
|
875
|
+
}
|
|
876
|
+
if (group.children.length === 0) return null;
|
|
877
|
+
return this._configurePreviewObject(group, refName, group.type);
|
|
878
|
+
}
|
|
802
879
|
if (type === 'VERTEX') {
|
|
803
880
|
const pos = snapshot.position;
|
|
804
881
|
if (!Array.isArray(pos) || pos.length < 3) return null;
|
|
@@ -881,8 +958,26 @@ export class SchemaForm {
|
|
|
881
958
|
originalPresent = !!real;
|
|
882
959
|
}
|
|
883
960
|
if (originalPresent) {
|
|
884
|
-
|
|
885
|
-
|
|
961
|
+
const keepGhost = !!(entry?.showWhenOriginalPresent || ghost?.userData?.previewHasEdges);
|
|
962
|
+
if (!keepGhost) {
|
|
963
|
+
if (ghost.parent === group) {
|
|
964
|
+
try { group.remove(ghost); } catch (_) { }
|
|
965
|
+
}
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
ghost.traverse?.((child) => {
|
|
970
|
+
if (!child || !child.userData?.refPreview) return;
|
|
971
|
+
const pType = String(child.userData.previewType || child.type || '').toUpperCase();
|
|
972
|
+
if (pType.includes('REF_PREVIEW_FACE') || pType.includes('REF_PREVIEW_PLANE')) {
|
|
973
|
+
child.visible = false;
|
|
974
|
+
} else if (child.type === 'REF_PREVIEW_EDGE') {
|
|
975
|
+
child.visible = true;
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
} catch (_) { }
|
|
979
|
+
if (ghost.parent !== group) {
|
|
980
|
+
try { group.add(ghost); } catch (_) { }
|
|
886
981
|
}
|
|
887
982
|
continue;
|
|
888
983
|
}
|
|
@@ -904,7 +999,34 @@ export class SchemaForm {
|
|
|
904
999
|
if (!cache) return;
|
|
905
1000
|
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
906
1001
|
for (const name of list) {
|
|
907
|
-
if (!name
|
|
1002
|
+
if (!name) continue;
|
|
1003
|
+
const existing = cache.get(name) || null;
|
|
1004
|
+
const snapshot = store ? store[name] : null;
|
|
1005
|
+
if (snapshot) {
|
|
1006
|
+
const snapType = String(snapshot.type || '').toUpperCase();
|
|
1007
|
+
const snapEdges = Array.isArray(snapshot.edgePositions) ? snapshot.edgePositions : null;
|
|
1008
|
+
const isFaceSnap = (snapType === 'FACE' || snapType === 'PLANE') && snapEdges && snapEdges.length;
|
|
1009
|
+
const isEdgeSnap = snapType === 'EDGE' && Array.isArray(snapshot.positions) && snapshot.positions.length >= 6;
|
|
1010
|
+
const isVertexSnap = snapType === 'VERTEX' && Array.isArray(snapshot.position) && snapshot.position.length >= 3;
|
|
1011
|
+
if (isFaceSnap || isEdgeSnap || isVertexSnap) {
|
|
1012
|
+
const shouldOverride = !existing || !existing.fromSnapshot || isFaceSnap;
|
|
1013
|
+
if (shouldOverride) {
|
|
1014
|
+
const ghost = this._buildReferencePreviewFromSnapshot(name, snapshot);
|
|
1015
|
+
if (ghost) {
|
|
1016
|
+
cache.set(name, {
|
|
1017
|
+
object: ghost,
|
|
1018
|
+
type: snapshot.type || null,
|
|
1019
|
+
sourceUuid: snapshot.sourceUuid || null,
|
|
1020
|
+
sourceFeatureId: snapshot.sourceFeatureId || null,
|
|
1021
|
+
showWhenOriginalPresent: isFaceSnap || !!ghost?.userData?.previewHasEdges,
|
|
1022
|
+
fromSnapshot: true,
|
|
1023
|
+
});
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (cache.has(name)) continue;
|
|
908
1030
|
const obj = scene.getObjectByName(name);
|
|
909
1031
|
if (obj && !obj?.userData?.refPreview) {
|
|
910
1032
|
this._storeReferencePreviewSnapshot(inputEl, def, obj);
|
|
@@ -919,6 +1041,8 @@ export class SchemaForm {
|
|
|
919
1041
|
type: snapshot.type || null,
|
|
920
1042
|
sourceUuid: snapshot.sourceUuid || null,
|
|
921
1043
|
sourceFeatureId: snapshot.sourceFeatureId || null,
|
|
1044
|
+
showWhenOriginalPresent: String(snapshot.type || '').toUpperCase() === 'FACE' || String(snapshot.type || '').toUpperCase() === 'PLANE' || !!ghost?.userData?.previewHasEdges,
|
|
1045
|
+
fromSnapshot: true,
|
|
922
1046
|
});
|
|
923
1047
|
}
|
|
924
1048
|
}
|
|
@@ -941,6 +1065,7 @@ export class SchemaForm {
|
|
|
941
1065
|
type: obj.type || null,
|
|
942
1066
|
sourceUuid,
|
|
943
1067
|
sourceFeatureId,
|
|
1068
|
+
showWhenOriginalPresent: !!ghost?.userData?.previewHasEdges,
|
|
944
1069
|
});
|
|
945
1070
|
try {
|
|
946
1071
|
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
@@ -1043,13 +1168,78 @@ export class SchemaForm {
|
|
|
1043
1168
|
} catch (_) { }
|
|
1044
1169
|
}
|
|
1045
1170
|
|
|
1171
|
+
_ensureReferencePreviewSnapshots(inputEl, def) {
|
|
1172
|
+
try {
|
|
1173
|
+
if (!inputEl) return;
|
|
1174
|
+
if (inputEl.__refPreviewBackfillPromise) return;
|
|
1175
|
+
const names = this._collectReferenceSelectionNames(inputEl, def);
|
|
1176
|
+
if (!names.length) return;
|
|
1177
|
+
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
1178
|
+
let missing = false;
|
|
1179
|
+
if (!store) missing = true;
|
|
1180
|
+
if (!missing) {
|
|
1181
|
+
for (const name of names) {
|
|
1182
|
+
const snap = store ? store[name] : null;
|
|
1183
|
+
const type = String(snap?.type || '').toUpperCase();
|
|
1184
|
+
if (!snap) { missing = true; break; }
|
|
1185
|
+
if (type === 'EDGE') {
|
|
1186
|
+
if (!Array.isArray(snap.positions) || snap.positions.length < 6) { missing = true; break; }
|
|
1187
|
+
} else if (type === 'VERTEX') {
|
|
1188
|
+
if (!Array.isArray(snap.position) || snap.position.length < 3) { missing = true; break; }
|
|
1189
|
+
} else if (type === 'FACE' || type === 'PLANE') {
|
|
1190
|
+
if (!Array.isArray(snap.edgePositions) || snap.edgePositions.length === 0) { missing = true; break; }
|
|
1191
|
+
} else {
|
|
1192
|
+
missing = true;
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
if (!missing) return;
|
|
1198
|
+
|
|
1199
|
+
const partHistory = this.options?.partHistory || this.options?.viewer?.partHistory || null;
|
|
1200
|
+
if (!partHistory || typeof partHistory.runHistory !== 'function') return;
|
|
1201
|
+
|
|
1202
|
+
const prevStep = partHistory.currentHistoryStepId;
|
|
1203
|
+
const featureId = this.params?.id ?? this.params?.featureID ?? this.params?.featureId ?? null;
|
|
1204
|
+
if (featureId != null) {
|
|
1205
|
+
try { partHistory.currentHistoryStepId = String(featureId); } catch (_) { }
|
|
1206
|
+
}
|
|
1207
|
+
inputEl.__refPreviewBackfillPromise = Promise.resolve()
|
|
1208
|
+
.then(() => partHistory.runHistory())
|
|
1209
|
+
.catch(() => { /* ignore */ })
|
|
1210
|
+
.then(() => {
|
|
1211
|
+
if (featureId != null) {
|
|
1212
|
+
try { partHistory.currentHistoryStepId = prevStep; } catch (_) { }
|
|
1213
|
+
}
|
|
1214
|
+
})
|
|
1215
|
+
.then(() => {
|
|
1216
|
+
inputEl.__refPreviewBackfillPromise = null;
|
|
1217
|
+
if (SchemaForm.__activeRefInput !== inputEl) return;
|
|
1218
|
+
const scene = this._getReferenceSelectionScene();
|
|
1219
|
+
const latest = this._collectReferenceSelectionNames(inputEl, def);
|
|
1220
|
+
try { this._seedReferencePreviewCacheFromScene(inputEl, def, latest, scene); } catch (_) { }
|
|
1221
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1222
|
+
})
|
|
1223
|
+
.finally(() => {
|
|
1224
|
+
inputEl.__refPreviewBackfillPromise = null;
|
|
1225
|
+
});
|
|
1226
|
+
} catch (_) { }
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1046
1229
|
_hoverReferenceSelectionItem(inputEl, def, name) {
|
|
1047
1230
|
try {
|
|
1048
|
-
if (!inputEl
|
|
1231
|
+
if (!inputEl) return;
|
|
1232
|
+
const activeInput = SchemaForm.__activeRefInput || null;
|
|
1233
|
+
if (activeInput !== inputEl) {
|
|
1234
|
+
const wrap = inputEl.closest?.('.ref-active') || null;
|
|
1235
|
+
if (!wrap) return;
|
|
1236
|
+
}
|
|
1049
1237
|
const normalized = normalizeReferenceName(name);
|
|
1050
1238
|
if (!normalized) return;
|
|
1051
1239
|
const scene = this._getReferenceSelectionScene();
|
|
1052
1240
|
if (!scene) return;
|
|
1241
|
+
try { console.log('[ReferenceSelection] Hover', { name: normalized }); } catch (_) { }
|
|
1242
|
+
try { this._ensureReferencePreviewSnapshots(inputEl, def); } catch (_) { }
|
|
1053
1243
|
try { this._seedReferencePreviewCacheFromScene(inputEl, def, [normalized], scene); } catch (_) { }
|
|
1054
1244
|
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1055
1245
|
|
|
@@ -1064,6 +1254,24 @@ export class SchemaForm {
|
|
|
1064
1254
|
try { target = scene.getObjectByName(`__refPreview__${normalized}`); } catch (_) { target = null; }
|
|
1065
1255
|
}
|
|
1066
1256
|
if (!target) return;
|
|
1257
|
+
if (!target.material && target.traverse) {
|
|
1258
|
+
let candidate = null;
|
|
1259
|
+
try {
|
|
1260
|
+
target.traverse((child) => {
|
|
1261
|
+
if (!child || candidate) return;
|
|
1262
|
+
if (child.type === 'REF_PREVIEW_EDGE') { candidate = child; return; }
|
|
1263
|
+
if (child.material) candidate = child;
|
|
1264
|
+
});
|
|
1265
|
+
} catch (_) { }
|
|
1266
|
+
if (candidate) target = candidate;
|
|
1267
|
+
}
|
|
1268
|
+
try {
|
|
1269
|
+
console.log('[ReferenceSelection] Hover target', {
|
|
1270
|
+
name: normalized,
|
|
1271
|
+
target: target || null,
|
|
1272
|
+
inScene: !!(target && target.parent),
|
|
1273
|
+
});
|
|
1274
|
+
} catch (_) { }
|
|
1067
1275
|
inputEl.__refChipHoverActive = true;
|
|
1068
1276
|
try { SelectionFilter.setHoverObject(target, { ignoreFilter: true }); } catch (_) { }
|
|
1069
1277
|
} catch (_) { }
|
|
@@ -1146,6 +1354,7 @@ export class SchemaForm {
|
|
|
1146
1354
|
|
|
1147
1355
|
// Highlight existing selections while this reference field is active
|
|
1148
1356
|
try { this._syncActiveReferenceSelectionHighlight(inputEl, def); } catch (_) { }
|
|
1357
|
+
try { this._ensureReferencePreviewSnapshots(inputEl, def); } catch (_) { }
|
|
1149
1358
|
try {
|
|
1150
1359
|
if (typeof inputEl.__captureReferencePreview !== 'function') {
|
|
1151
1360
|
inputEl.__captureReferencePreview = (obj) => this._storeReferencePreviewSnapshot(inputEl, def, obj);
|
|
@@ -1647,8 +1856,41 @@ export class SchemaForm {
|
|
|
1647
1856
|
chipsWrap.textContent = '';
|
|
1648
1857
|
const arr = Array.isArray(values) ? values : [];
|
|
1649
1858
|
const normalizedValues = normalizeReferenceList(arr);
|
|
1650
|
-
|
|
1651
|
-
const
|
|
1859
|
+
let inputEl = (this._inputs && typeof this._inputs.get === 'function') ? this._inputs.get(key) : null;
|
|
1860
|
+
const resolveInput = () => {
|
|
1861
|
+
if (inputEl) return inputEl;
|
|
1862
|
+
const wrap = chipsWrap?.closest?.('.ref-multi-wrap, .ref-single-wrap') || null;
|
|
1863
|
+
const hidden = wrap ? wrap.querySelector('input[type="hidden"]') : null;
|
|
1864
|
+
if (hidden) inputEl = hidden;
|
|
1865
|
+
return inputEl;
|
|
1866
|
+
};
|
|
1867
|
+
const resolveDef = () => {
|
|
1868
|
+
const el = resolveInput();
|
|
1869
|
+
return (el && el.__refSelectionDef) || (this.schema ? (this.schema[key] || null) : null);
|
|
1870
|
+
};
|
|
1871
|
+
const def = resolveDef();
|
|
1872
|
+
if (chipsWrap && !chipsWrap.__refHoverBound) {
|
|
1873
|
+
chipsWrap.__refHoverBound = true;
|
|
1874
|
+
chipsWrap.__refHoverName = null;
|
|
1875
|
+
chipsWrap.addEventListener('mousemove', (ev) => {
|
|
1876
|
+
try {
|
|
1877
|
+
const chip = ev.target?.closest?.('.ref-chip');
|
|
1878
|
+
const refName = chip?.dataset?.refName || null;
|
|
1879
|
+
if (!refName) {
|
|
1880
|
+
chipsWrap.__refHoverName = null;
|
|
1881
|
+
this._clearReferenceSelectionHover(resolveInput());
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
if (chipsWrap.__refHoverName === refName) return;
|
|
1885
|
+
chipsWrap.__refHoverName = refName;
|
|
1886
|
+
this._hoverReferenceSelectionItem(resolveInput(), resolveDef(), refName);
|
|
1887
|
+
} catch (_) { }
|
|
1888
|
+
});
|
|
1889
|
+
chipsWrap.addEventListener('mouseleave', () => {
|
|
1890
|
+
chipsWrap.__refHoverName = null;
|
|
1891
|
+
this._clearReferenceSelectionHover(resolveInput());
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1652
1894
|
if (inputEl) {
|
|
1653
1895
|
if (typeof inputEl.__updateSelectionMetadata === 'function') {
|
|
1654
1896
|
try { inputEl.__updateSelectionMetadata(normalizedValues); } catch (_) { }
|
|
@@ -1665,6 +1907,7 @@ export class SchemaForm {
|
|
|
1665
1907
|
for (const name of normalizedValues) {
|
|
1666
1908
|
const chip = document.createElement('span');
|
|
1667
1909
|
chip.className = 'ref-chip';
|
|
1910
|
+
try { chip.dataset.refName = name; } catch (_) { }
|
|
1668
1911
|
|
|
1669
1912
|
const label = document.createElement('span');
|
|
1670
1913
|
label.className = 'ref-chip-label';
|
|
@@ -1673,15 +1916,19 @@ export class SchemaForm {
|
|
|
1673
1916
|
|
|
1674
1917
|
// Hover highlight on chip hover
|
|
1675
1918
|
chip.addEventListener('mouseenter', () => {
|
|
1676
|
-
|
|
1677
|
-
|
|
1919
|
+
const liveInput = resolveInput();
|
|
1920
|
+
const liveDef = resolveDef();
|
|
1921
|
+
if (liveDef && liveDef.type === 'reference_selection') {
|
|
1922
|
+
this._hoverReferenceSelectionItem(liveInput, liveDef, name);
|
|
1678
1923
|
return;
|
|
1679
1924
|
}
|
|
1680
1925
|
try { SelectionFilter.setHoverByName(this.options?.scene || null, name); } catch (_) { }
|
|
1681
1926
|
});
|
|
1682
1927
|
chip.addEventListener('mouseleave', () => {
|
|
1683
|
-
|
|
1684
|
-
|
|
1928
|
+
const liveInput = resolveInput();
|
|
1929
|
+
const liveDef = resolveDef();
|
|
1930
|
+
if (liveDef && liveDef.type === 'reference_selection') {
|
|
1931
|
+
this._clearReferenceSelectionHover(liveInput);
|
|
1685
1932
|
return;
|
|
1686
1933
|
}
|
|
1687
1934
|
try { SelectionFilter.clearHover(); } catch (_) { }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SchemaForm } from '../featureDialogs.js';
|
|
2
|
+
import { SelectionFilter } from '../SelectionFilter.js';
|
|
2
3
|
import { resolveEntryId, resolveHistoryDisplayInfo } from './historyDisplayInfo.js';
|
|
3
4
|
import { HISTORY_COLLECTION_WIDGET_CSS } from './historyCollectionWidget.css.js';
|
|
4
5
|
|
|
@@ -43,6 +44,8 @@ export class HistoryCollectionWidget {
|
|
|
43
44
|
this._addMenu = null;
|
|
44
45
|
this._onGlobalClick = null;
|
|
45
46
|
this._globalRefreshHandler = null;
|
|
47
|
+
this._contextSuppressKey = `hc-${Math.random().toString(36).slice(2, 9)}`;
|
|
48
|
+
this._contextSuppressActive = false;
|
|
46
49
|
|
|
47
50
|
this.uiElement = document.createElement('div');
|
|
48
51
|
this.uiElement.className = 'history-collection-widget-host';
|
|
@@ -100,6 +103,7 @@ export class HistoryCollectionWidget {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
dispose() {
|
|
106
|
+
this._setContextSuppression(false);
|
|
103
107
|
if (typeof this._listenerUnsub === 'function') {
|
|
104
108
|
try { this._listenerUnsub(); } catch (_) {}
|
|
105
109
|
}
|
|
@@ -152,6 +156,7 @@ export class HistoryCollectionWidget {
|
|
|
152
156
|
this._listEl.textContent = '';
|
|
153
157
|
|
|
154
158
|
if (!entries.length) {
|
|
159
|
+
this._setContextSuppression(false);
|
|
155
160
|
const empty = document.createElement('div');
|
|
156
161
|
empty.className = 'hc-empty';
|
|
157
162
|
empty.textContent = 'No entries yet.';
|
|
@@ -185,6 +190,7 @@ export class HistoryCollectionWidget {
|
|
|
185
190
|
targetId = null;
|
|
186
191
|
}
|
|
187
192
|
this._expandedId = targetId;
|
|
193
|
+
this._setContextSuppression(!!this._expandedId);
|
|
188
194
|
|
|
189
195
|
for (let i = 0; i < entries.length; i++) {
|
|
190
196
|
const entry = entries[i];
|
|
@@ -589,12 +595,24 @@ export class HistoryCollectionWidget {
|
|
|
589
595
|
}
|
|
590
596
|
|
|
591
597
|
_notifyEntryToggle(entry, isOpen) {
|
|
598
|
+
this._setContextSuppression(!!isOpen);
|
|
592
599
|
if (!this._onEntryToggle) return;
|
|
593
600
|
try {
|
|
594
601
|
this._onEntryToggle(entry || null, isOpen);
|
|
595
602
|
} catch (_) { /* ignore toggle hook errors */ }
|
|
596
603
|
}
|
|
597
604
|
|
|
605
|
+
_setContextSuppression(isOpen) {
|
|
606
|
+
const next = !!isOpen;
|
|
607
|
+
if (this._contextSuppressActive === next) return;
|
|
608
|
+
this._contextSuppressActive = next;
|
|
609
|
+
if (SelectionFilter && typeof SelectionFilter.setContextBarSuppressed === 'function') {
|
|
610
|
+
try {
|
|
611
|
+
SelectionFilter.setContextBarSuppressed(this._contextSuppressKey, next);
|
|
612
|
+
} catch (_) { /* ignore */ }
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
598
616
|
async _moveEntry(id, delta) {
|
|
599
617
|
if (!id) return;
|
|
600
618
|
const entries = this._getEntries();
|
|
@@ -659,7 +677,7 @@ export class HistoryCollectionWidget {
|
|
|
659
677
|
this.render();
|
|
660
678
|
this._emitCollectionChange('add', entry);
|
|
661
679
|
this._deferScrollToEntry(createdEntryId);
|
|
662
|
-
return;
|
|
680
|
+
return entry;
|
|
663
681
|
}
|
|
664
682
|
const entry = await this._instantiateEntryForType(typeStr);
|
|
665
683
|
if (!entry) return;
|
|
@@ -680,6 +698,7 @@ export class HistoryCollectionWidget {
|
|
|
680
698
|
this.render();
|
|
681
699
|
this._emitCollectionChange('add', entry);
|
|
682
700
|
this._deferScrollToEntry(createdEntryId);
|
|
701
|
+
return entry;
|
|
683
702
|
}
|
|
684
703
|
|
|
685
704
|
_handleSchemaChange(id, entry, details) {
|
|
@@ -29,6 +29,9 @@ class AnnotationRegistry {
|
|
|
29
29
|
if (!ctor.longName) {
|
|
30
30
|
ctor.longName = ctor.featureName || ctor.name || ctor.shortName || ctor.type || 'Annotation';
|
|
31
31
|
}
|
|
32
|
+
if (typeof ctor.showContexButton !== 'function') {
|
|
33
|
+
ctor.showContexButton = () => false;
|
|
34
|
+
}
|
|
32
35
|
}
|
|
33
36
|
const typeKey = normalizeKey(
|
|
34
37
|
handler.type
|
|
@@ -54,6 +54,9 @@ export class AssemblyConstraintRegistry {
|
|
|
54
54
|
if (!ConstraintClass.longName) {
|
|
55
55
|
ConstraintClass.longName = ConstraintClass.constraintName || ConstraintClass.name || ConstraintClass.shortName || 'Constraint';
|
|
56
56
|
}
|
|
57
|
+
if (typeof ConstraintClass.showContexButton !== 'function') {
|
|
58
|
+
ConstraintClass.showContexButton = () => false;
|
|
59
|
+
}
|
|
57
60
|
const keys = this.#collectKeys(ConstraintClass);
|
|
58
61
|
if (!keys.typeKey) return;
|
|
59
62
|
|
|
@@ -25,6 +25,21 @@ export class BooleanFeature {
|
|
|
25
25
|
static shortName = "B";
|
|
26
26
|
static longName = "Boolean";
|
|
27
27
|
static inputParamsSchema = inputParamsSchema;
|
|
28
|
+
static showContexButton(selectedItems) {
|
|
29
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
30
|
+
const solids = items
|
|
31
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'SOLID')
|
|
32
|
+
.map((it) => it?.name)
|
|
33
|
+
.filter((name) => !!name);
|
|
34
|
+
if (solids.length < 2) return false;
|
|
35
|
+
const [targetSolid, ...tools] = solids;
|
|
36
|
+
return {
|
|
37
|
+
params: {
|
|
38
|
+
targetSolid,
|
|
39
|
+
boolean: { operation: 'UNION', targets: tools },
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
28
43
|
|
|
29
44
|
constructor() {
|
|
30
45
|
this.inputParams = {};
|
|
@@ -46,6 +46,18 @@ export class ChamferFeature {
|
|
|
46
46
|
static shortName = "CH";
|
|
47
47
|
static longName = "Chamfer";
|
|
48
48
|
static inputParamsSchema = inputParamsSchema;
|
|
49
|
+
static showContexButton(selectedItems) {
|
|
50
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
51
|
+
const edges = items
|
|
52
|
+
.filter((it) => {
|
|
53
|
+
const type = String(it?.type || '').toUpperCase();
|
|
54
|
+
return type === 'EDGE' || type === 'FACE';
|
|
55
|
+
})
|
|
56
|
+
.map((it) => it?.name || it?.userData?.edgeName || it?.userData?.faceName)
|
|
57
|
+
.filter((name) => !!name);
|
|
58
|
+
if (!edges.length) return false;
|
|
59
|
+
return { params: { edges } };
|
|
60
|
+
}
|
|
49
61
|
|
|
50
62
|
constructor() {
|
|
51
63
|
this.inputParams = {};
|
|
@@ -41,6 +41,17 @@ export class ExtrudeFeature {
|
|
|
41
41
|
static shortName = "E";
|
|
42
42
|
static longName = "Extrude";
|
|
43
43
|
static inputParamsSchema = inputParamsSchema;
|
|
44
|
+
static showContexButton(selectedItems) {
|
|
45
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
46
|
+
const pick = items.find((it) => {
|
|
47
|
+
const type = String(it?.type || '').toUpperCase();
|
|
48
|
+
return type === 'FACE' || type === 'SKETCH';
|
|
49
|
+
});
|
|
50
|
+
if (!pick) return false;
|
|
51
|
+
const name = pick?.name || pick?.userData?.faceName || pick?.userData?.edgeName || null;
|
|
52
|
+
if (!name) return false;
|
|
53
|
+
return { field: 'profile', value: name };
|
|
54
|
+
}
|
|
44
55
|
|
|
45
56
|
constructor() {
|
|
46
57
|
this.inputParams = {};
|
|
@@ -63,6 +63,18 @@ export class FilletFeature {
|
|
|
63
63
|
static shortName = "F";
|
|
64
64
|
static longName = "Fillet";
|
|
65
65
|
static inputParamsSchema = inputParamsSchema;
|
|
66
|
+
static showContexButton(selectedItems) {
|
|
67
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
68
|
+
const edges = items
|
|
69
|
+
.filter((it) => {
|
|
70
|
+
const type = String(it?.type || '').toUpperCase();
|
|
71
|
+
return type === 'EDGE' || type === 'FACE';
|
|
72
|
+
})
|
|
73
|
+
.map((it) => it?.name || it?.userData?.edgeName || it?.userData?.faceName)
|
|
74
|
+
.filter((name) => !!name);
|
|
75
|
+
if (!edges.length) return false;
|
|
76
|
+
return { params: { edges } };
|
|
77
|
+
}
|
|
66
78
|
|
|
67
79
|
constructor() {
|
|
68
80
|
this.inputParams = {};
|
|
@@ -569,6 +569,21 @@ export class HoleFeature {
|
|
|
569
569
|
static shortName = 'H';
|
|
570
570
|
static longName = 'Hole';
|
|
571
571
|
static inputParamsSchema = inputParamsSchema;
|
|
572
|
+
static showContexButton(selectedItems) {
|
|
573
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
574
|
+
const sketch = items.find((it) => {
|
|
575
|
+
const type = String(it?.type || '').toUpperCase();
|
|
576
|
+
if (type === 'SKETCH') return true;
|
|
577
|
+
if (it?.parent && String(it.parent.type || '').toUpperCase() === 'SKETCH') return true;
|
|
578
|
+
return false;
|
|
579
|
+
});
|
|
580
|
+
if (!sketch) return false;
|
|
581
|
+
const name = (String(sketch?.type || '').toUpperCase() === 'SKETCH')
|
|
582
|
+
? sketch.name
|
|
583
|
+
: sketch.parent?.name;
|
|
584
|
+
if (!name) return false;
|
|
585
|
+
return { field: 'face', value: name };
|
|
586
|
+
}
|
|
572
587
|
|
|
573
588
|
constructor() {
|
|
574
589
|
this.inputParams = {};
|
|
@@ -58,6 +58,23 @@ export class LoftFeature {
|
|
|
58
58
|
static shortName = "LOFT";
|
|
59
59
|
static longName = "Loft";
|
|
60
60
|
static inputParamsSchema = inputParamsSchema;
|
|
61
|
+
static showContexButton(selectedItems) {
|
|
62
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
63
|
+
const profiles = items
|
|
64
|
+
.filter((it) => {
|
|
65
|
+
const type = String(it?.type || '').toUpperCase();
|
|
66
|
+
return type === 'FACE' || type === 'SKETCH';
|
|
67
|
+
})
|
|
68
|
+
.map((it) => {
|
|
69
|
+
if (!it) return null;
|
|
70
|
+
if (String(it.type || '').toUpperCase() === 'SKETCH') return it.name || null;
|
|
71
|
+
if (it.parent && String(it.parent.type || '').toUpperCase() === 'SKETCH') return it.parent.name || null;
|
|
72
|
+
return it.name || it.userData?.faceName || null;
|
|
73
|
+
})
|
|
74
|
+
.filter((name) => !!name);
|
|
75
|
+
if (profiles.length < 2) return false;
|
|
76
|
+
return { params: { profiles } };
|
|
77
|
+
}
|
|
61
78
|
|
|
62
79
|
constructor() {
|
|
63
80
|
this.inputParams = {};
|
|
@@ -35,6 +35,20 @@ export class MirrorFeature {
|
|
|
35
35
|
static longName = "Mirror";
|
|
36
36
|
|
|
37
37
|
static inputParamsSchema = inputParamsSchema;
|
|
38
|
+
static showContexButton(selectedItems) {
|
|
39
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
40
|
+
const solids = items
|
|
41
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'SOLID')
|
|
42
|
+
.map((it) => it?.name)
|
|
43
|
+
.filter((name) => !!name);
|
|
44
|
+
const plane = items.find((it) => {
|
|
45
|
+
const type = String(it?.type || '').toUpperCase();
|
|
46
|
+
return type === 'FACE' || type === 'PLANE';
|
|
47
|
+
});
|
|
48
|
+
const planeName = plane?.name || plane?.userData?.faceName || null;
|
|
49
|
+
if (!solids.length || !planeName) return false;
|
|
50
|
+
return { params: { solids, mirrorPlane: planeName } };
|
|
51
|
+
}
|
|
38
52
|
|
|
39
53
|
constructor() {
|
|
40
54
|
this.inputParams = {};
|