brep-io-kernel 1.0.0-ci.10

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.
Files changed (271) hide show
  1. package/LICENSE.md +32 -0
  2. package/README.md +157 -0
  3. package/dist-kernel/brep-kernel.js +74699 -0
  4. package/package.json +58 -0
  5. package/src/BREP/AssemblyComponent.js +42 -0
  6. package/src/BREP/BREP.js +43 -0
  7. package/src/BREP/BetterSolid.js +805 -0
  8. package/src/BREP/Edge.js +103 -0
  9. package/src/BREP/Extrude.js +403 -0
  10. package/src/BREP/Face.js +187 -0
  11. package/src/BREP/MeshRepairer.js +634 -0
  12. package/src/BREP/OffsetShellSolid.js +614 -0
  13. package/src/BREP/PointCloudWrap.js +302 -0
  14. package/src/BREP/Revolve.js +345 -0
  15. package/src/BREP/SolidMethods/authoring.js +112 -0
  16. package/src/BREP/SolidMethods/booleanOps.js +230 -0
  17. package/src/BREP/SolidMethods/chamfer.js +122 -0
  18. package/src/BREP/SolidMethods/edgeResolution.js +25 -0
  19. package/src/BREP/SolidMethods/fillet.js +792 -0
  20. package/src/BREP/SolidMethods/index.js +72 -0
  21. package/src/BREP/SolidMethods/io.js +105 -0
  22. package/src/BREP/SolidMethods/lifecycle.js +103 -0
  23. package/src/BREP/SolidMethods/manifoldOps.js +375 -0
  24. package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
  25. package/src/BREP/SolidMethods/meshQueries.js +264 -0
  26. package/src/BREP/SolidMethods/metadata.js +106 -0
  27. package/src/BREP/SolidMethods/metrics.js +51 -0
  28. package/src/BREP/SolidMethods/transforms.js +361 -0
  29. package/src/BREP/SolidMethods/visualize.js +508 -0
  30. package/src/BREP/SolidShared.js +26 -0
  31. package/src/BREP/Sweep.js +1596 -0
  32. package/src/BREP/Tube.js +857 -0
  33. package/src/BREP/Vertex.js +43 -0
  34. package/src/BREP/applyBooleanOperation.js +704 -0
  35. package/src/BREP/boundsUtils.js +48 -0
  36. package/src/BREP/chamfer.js +551 -0
  37. package/src/BREP/edgePolylineUtils.js +85 -0
  38. package/src/BREP/fillets/common.js +388 -0
  39. package/src/BREP/fillets/fillet.js +1422 -0
  40. package/src/BREP/fillets/filletGeometry.js +15 -0
  41. package/src/BREP/fillets/inset.js +389 -0
  42. package/src/BREP/fillets/offsetHelper.js +143 -0
  43. package/src/BREP/fillets/outset.js +88 -0
  44. package/src/BREP/helix.js +193 -0
  45. package/src/BREP/meshToBrep.js +234 -0
  46. package/src/BREP/primitives.js +279 -0
  47. package/src/BREP/setupManifold.js +71 -0
  48. package/src/BREP/threadGeometry.js +1120 -0
  49. package/src/BREP/triangleUtils.js +8 -0
  50. package/src/BREP/triangulate.js +608 -0
  51. package/src/FeatureRegistry.js +183 -0
  52. package/src/PartHistory.js +1132 -0
  53. package/src/UI/AccordionWidget.js +292 -0
  54. package/src/UI/CADmaterials.js +850 -0
  55. package/src/UI/EnvMonacoEditor.js +522 -0
  56. package/src/UI/FloatingWindow.js +396 -0
  57. package/src/UI/HistoryWidget.js +457 -0
  58. package/src/UI/MainToolbar.js +131 -0
  59. package/src/UI/ModelLibraryView.js +194 -0
  60. package/src/UI/OrthoCameraIdle.js +206 -0
  61. package/src/UI/PluginsWidget.js +280 -0
  62. package/src/UI/SceneListing.js +606 -0
  63. package/src/UI/SelectionFilter.js +629 -0
  64. package/src/UI/ViewCube.js +389 -0
  65. package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
  66. package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
  67. package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
  68. package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
  69. package/src/UI/assembly/constraintFaceUtils.js +115 -0
  70. package/src/UI/assembly/constraintHighlightUtils.js +70 -0
  71. package/src/UI/assembly/constraintLabelUtils.js +31 -0
  72. package/src/UI/assembly/constraintPointUtils.js +64 -0
  73. package/src/UI/assembly/constraintSelectionUtils.js +185 -0
  74. package/src/UI/assembly/constraintStatusUtils.js +142 -0
  75. package/src/UI/componentSelectorModal.js +240 -0
  76. package/src/UI/controls/CombinedTransformControls.js +386 -0
  77. package/src/UI/dialogs.js +351 -0
  78. package/src/UI/expressionsManager.js +100 -0
  79. package/src/UI/featureDialogWidgets/booleanField.js +25 -0
  80. package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
  81. package/src/UI/featureDialogWidgets/buttonField.js +45 -0
  82. package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
  83. package/src/UI/featureDialogWidgets/defaultField.js +23 -0
  84. package/src/UI/featureDialogWidgets/fileField.js +66 -0
  85. package/src/UI/featureDialogWidgets/index.js +34 -0
  86. package/src/UI/featureDialogWidgets/numberField.js +165 -0
  87. package/src/UI/featureDialogWidgets/optionsField.js +33 -0
  88. package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
  89. package/src/UI/featureDialogWidgets/stringField.js +24 -0
  90. package/src/UI/featureDialogWidgets/textareaField.js +28 -0
  91. package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
  92. package/src/UI/featureDialogWidgets/transformField.js +252 -0
  93. package/src/UI/featureDialogWidgets/utils.js +43 -0
  94. package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
  95. package/src/UI/featureDialogs.js +1414 -0
  96. package/src/UI/fileManagerWidget.js +615 -0
  97. package/src/UI/history/HistoryCollectionWidget.js +1294 -0
  98. package/src/UI/history/historyCollectionWidget.css.js +257 -0
  99. package/src/UI/history/historyDisplayInfo.js +133 -0
  100. package/src/UI/mobile.js +28 -0
  101. package/src/UI/objectDump.js +442 -0
  102. package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
  103. package/src/UI/pmi/AnnotationHistory.js +353 -0
  104. package/src/UI/pmi/AnnotationRegistry.js +90 -0
  105. package/src/UI/pmi/BaseAnnotation.js +269 -0
  106. package/src/UI/pmi/LabelOverlay.css +102 -0
  107. package/src/UI/pmi/LabelOverlay.js +191 -0
  108. package/src/UI/pmi/PMIMode.js +1550 -0
  109. package/src/UI/pmi/PMIViewsWidget.js +1098 -0
  110. package/src/UI/pmi/annUtils.js +729 -0
  111. package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
  112. package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
  113. package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
  114. package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
  115. package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
  116. package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
  117. package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
  118. package/src/UI/pmi/pmiStyle.js +44 -0
  119. package/src/UI/sketcher/SketchMode3D.js +4095 -0
  120. package/src/UI/sketcher/dimensions.js +674 -0
  121. package/src/UI/sketcher/glyphs.js +236 -0
  122. package/src/UI/sketcher/highlights.js +60 -0
  123. package/src/UI/toolbarButtons/aboutButton.js +5 -0
  124. package/src/UI/toolbarButtons/exportButton.js +609 -0
  125. package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
  126. package/src/UI/toolbarButtons/importButton.js +160 -0
  127. package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
  128. package/src/UI/toolbarButtons/metadataButton.js +1063 -0
  129. package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
  130. package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
  131. package/src/UI/toolbarButtons/saveButton.js +99 -0
  132. package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
  133. package/src/UI/toolbarButtons/testsButton.js +26 -0
  134. package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
  135. package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
  136. package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
  137. package/src/UI/triangleDebuggerWindow.js +945 -0
  138. package/src/UI/viewer.js +4228 -0
  139. package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
  140. package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
  141. package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
  142. package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
  143. package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
  144. package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
  145. package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
  146. package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
  147. package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
  148. package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
  149. package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
  150. package/src/core/entities/HistoryCollectionBase.js +72 -0
  151. package/src/core/entities/ListEntityBase.js +109 -0
  152. package/src/core/entities/schemaProcesser.js +121 -0
  153. package/src/exporters/sheetMetalFlatPattern.js +659 -0
  154. package/src/exporters/sheetMetalUnfold.js +862 -0
  155. package/src/exporters/step.js +1135 -0
  156. package/src/exporters/threeMF.js +575 -0
  157. package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
  158. package/src/features/boolean/BooleanFeature.js +94 -0
  159. package/src/features/chamfer/ChamferFeature.js +116 -0
  160. package/src/features/datium/DatiumFeature.js +80 -0
  161. package/src/features/edgeFeatureUtils.js +41 -0
  162. package/src/features/extrude/ExtrudeFeature.js +143 -0
  163. package/src/features/fillet/FilletFeature.js +197 -0
  164. package/src/features/helix/HelixFeature.js +405 -0
  165. package/src/features/hole/HoleFeature.js +1050 -0
  166. package/src/features/hole/screwClearance.js +86 -0
  167. package/src/features/hole/threadDesignationCatalog.js +149 -0
  168. package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
  169. package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
  170. package/src/features/imageToFace/imageEditor.js +1270 -0
  171. package/src/features/imageToFace/traceUtils.js +971 -0
  172. package/src/features/import3dModel/Import3dModelFeature.js +151 -0
  173. package/src/features/loft/LoftFeature.js +605 -0
  174. package/src/features/mirror/MirrorFeature.js +151 -0
  175. package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
  176. package/src/features/offsetShell/OffsetShellFeature.js +89 -0
  177. package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
  178. package/src/features/pattern/PatternFeature.js +275 -0
  179. package/src/features/patternLinear/PatternLinearFeature.js +120 -0
  180. package/src/features/patternRadial/PatternRadialFeature.js +186 -0
  181. package/src/features/plane/PlaneFeature.js +154 -0
  182. package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
  183. package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
  184. package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
  185. package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
  186. package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
  187. package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
  188. package/src/features/remesh/RemeshFeature.js +97 -0
  189. package/src/features/revolve/RevolveFeature.js +111 -0
  190. package/src/features/selectionUtils.js +118 -0
  191. package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
  192. package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
  193. package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
  194. package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
  195. package/src/features/sheetMetal/SheetMetalObject.js +141 -0
  196. package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
  197. package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
  198. package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
  199. package/src/features/sheetMetal/profileUtils.js +25 -0
  200. package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
  201. package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
  202. package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
  203. package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
  204. package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
  205. package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
  206. package/src/features/sheetMetal/sheetMetalTree.js +210 -0
  207. package/src/features/sketch/SketchFeature.js +955 -0
  208. package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
  209. package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
  210. package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
  211. package/src/features/spline/SplineEditorSession.js +988 -0
  212. package/src/features/spline/SplineFeature.js +1388 -0
  213. package/src/features/spline/splineUtils.js +218 -0
  214. package/src/features/sweep/SweepFeature.js +110 -0
  215. package/src/features/transform/TransformFeature.js +152 -0
  216. package/src/features/tube/TubeFeature.js +635 -0
  217. package/src/fs.proxy.js +625 -0
  218. package/src/idbStorage.js +254 -0
  219. package/src/index.js +12 -0
  220. package/src/main.js +15 -0
  221. package/src/metadataManager.js +64 -0
  222. package/src/path.proxy.js +277 -0
  223. package/src/plugins/ghLoader.worker.js +151 -0
  224. package/src/plugins/pluginManager.js +286 -0
  225. package/src/pmi/PMIViewsManager.js +134 -0
  226. package/src/services/componentLibrary.js +198 -0
  227. package/src/tests/ConsoleCapture.js +189 -0
  228. package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
  229. package/src/tests/browserTests.js +597 -0
  230. package/src/tests/debugBoolean.js +225 -0
  231. package/src/tests/partFiles/badBoolean.json +957 -0
  232. package/src/tests/partFiles/extrudeTest.json +88 -0
  233. package/src/tests/partFiles/filletFail.json +58 -0
  234. package/src/tests/partFiles/import_TEst.part.part.json +646 -0
  235. package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
  236. package/src/tests/test_boolean_subtract.js +27 -0
  237. package/src/tests/test_chamfer.js +17 -0
  238. package/src/tests/test_extrudeFace.js +24 -0
  239. package/src/tests/test_fillet.js +17 -0
  240. package/src/tests/test_fillet_nonClosed.js +45 -0
  241. package/src/tests/test_filletsMoreDifficult.js +46 -0
  242. package/src/tests/test_history_features_basic.js +149 -0
  243. package/src/tests/test_hole.js +282 -0
  244. package/src/tests/test_mirror.js +16 -0
  245. package/src/tests/test_offsetShellGrouping.js +85 -0
  246. package/src/tests/test_plane.js +4 -0
  247. package/src/tests/test_primitiveCone.js +11 -0
  248. package/src/tests/test_primitiveCube.js +7 -0
  249. package/src/tests/test_primitiveCylinder.js +8 -0
  250. package/src/tests/test_primitivePyramid.js +9 -0
  251. package/src/tests/test_primitiveSphere.js +17 -0
  252. package/src/tests/test_primitiveTorus.js +21 -0
  253. package/src/tests/test_pushFace.js +126 -0
  254. package/src/tests/test_sheetMetalContourFlange.js +125 -0
  255. package/src/tests/test_sheetMetal_features.js +80 -0
  256. package/src/tests/test_sketch_openLoop.js +45 -0
  257. package/src/tests/test_solidMetrics.js +58 -0
  258. package/src/tests/test_stlLoader.js +1889 -0
  259. package/src/tests/test_sweepFace.js +55 -0
  260. package/src/tests/test_tube.js +45 -0
  261. package/src/tests/test_tube_closedLoop.js +67 -0
  262. package/src/tests/tests.js +493 -0
  263. package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
  264. package/src/tools/dialogCapturePageFactory.js +227 -0
  265. package/src/tools/featureDialogCapturePage.js +47 -0
  266. package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
  267. package/src/utils/axisHelpers.js +99 -0
  268. package/src/utils/deepClone.js +69 -0
  269. package/src/utils/geometryTolerance.js +37 -0
  270. package/src/utils/normalizeTypeString.js +8 -0
  271. package/src/utils/xformMath.js +51 -0
@@ -0,0 +1,160 @@
1
+ import { getThreadDesignationOptions, normalizeThreadStandard } from '../../features/hole/threadDesignationCatalog.js';
2
+
3
+ const CUSTOM_VALUE = '__custom__';
4
+
5
+ export function renderThreadDesignationField({ ui, key, def, id }) {
6
+ const wrap = document.createElement('div');
7
+ wrap.className = 'thread-designation-field';
8
+ wrap.dataset.role = 'thread-designation-wrap';
9
+
10
+ const select = document.createElement('select');
11
+ select.id = id;
12
+ select.className = 'select';
13
+ select.dataset.role = 'thread-designation';
14
+ wrap.appendChild(select);
15
+
16
+ const customInput = document.createElement('input');
17
+ customInput.type = 'text';
18
+ customInput.className = 'input';
19
+ customInput.dataset.role = 'thread-designation-custom';
20
+ customInput.placeholder = def?.hint || 'Enter thread designation';
21
+ customInput.style.display = 'none';
22
+ customInput.style.marginTop = '6px';
23
+ wrap.appendChild(customInput);
24
+
25
+ const standardKey = def?.standardField || 'threadStandard';
26
+ const getStandard = () => normalizeThreadStandard(ui?.params?.[standardKey] || 'NONE');
27
+ let lastStandard = getStandard();
28
+ let lastValue = ui.params[key] ?? ui._pickInitialValue(key, def);
29
+
30
+ const setValue = (value, emit = true) => {
31
+ const next = value == null ? '' : String(value);
32
+ ui.params[key] = next;
33
+ if (emit && next !== lastValue) {
34
+ lastValue = next;
35
+ ui._emitParamsChange(key, next);
36
+ } else {
37
+ lastValue = next;
38
+ }
39
+ };
40
+
41
+ const toggleCustom = (show) => {
42
+ customInput.style.display = show ? 'block' : 'none';
43
+ };
44
+
45
+ const buildOptions = (std) => {
46
+ const options = getThreadDesignationOptions(std);
47
+ select.textContent = '';
48
+ if (options.length) {
49
+ for (const opt of options) {
50
+ const el = document.createElement('option');
51
+ el.value = opt.value;
52
+ el.textContent = opt.label || opt.value;
53
+ select.appendChild(el);
54
+ }
55
+ const customOpt = document.createElement('option');
56
+ customOpt.value = CUSTOM_VALUE;
57
+ customOpt.textContent = 'Custom...';
58
+ select.appendChild(customOpt);
59
+ } else {
60
+ const customOpt = document.createElement('option');
61
+ customOpt.value = CUSTOM_VALUE;
62
+ customOpt.textContent = std === 'NONE'
63
+ ? 'Select a thread standard or type custom'
64
+ : 'Custom designation';
65
+ select.appendChild(customOpt);
66
+ }
67
+ return options;
68
+ };
69
+
70
+ const syncSelection = (emit = false, preferPreset = false) => {
71
+ const std = getStandard();
72
+ lastStandard = std;
73
+ const options = buildOptions(std);
74
+ const current = ui.params[key] ?? ui._pickInitialValue(key, def);
75
+ const match = options.find((o) => o.value === current);
76
+ if (match) {
77
+ select.value = match.value;
78
+ toggleCustom(false);
79
+ setValue(match.value, emit);
80
+ return;
81
+ }
82
+ if ((preferPreset || !current) && options.length) {
83
+ const fallback = options[0];
84
+ select.value = fallback.value;
85
+ toggleCustom(false);
86
+ setValue(fallback.value, emit);
87
+ return;
88
+ }
89
+ select.value = CUSTOM_VALUE;
90
+ toggleCustom(true);
91
+ customInput.value = current || customInput.value || '';
92
+ setValue(customInput.value, emit);
93
+ };
94
+
95
+ const handleSelectChange = () => {
96
+ if (select.value === CUSTOM_VALUE) {
97
+ toggleCustom(true);
98
+ setValue(customInput.value || '', true);
99
+ customInput.focus();
100
+ } else {
101
+ toggleCustom(false);
102
+ setValue(select.value, true);
103
+ }
104
+ };
105
+
106
+ const handleCustomInput = () => {
107
+ setValue(customInput.value, false);
108
+ };
109
+
110
+ const handleCustomCommit = () => {
111
+ setValue(customInput.value, true);
112
+ };
113
+
114
+ select.addEventListener('change', handleSelectChange);
115
+ customInput.addEventListener('input', handleCustomInput);
116
+ customInput.addEventListener('change', handleCustomCommit);
117
+ customInput.addEventListener('blur', handleCustomCommit);
118
+
119
+ let cleanupStandardListener = null;
120
+ const standardInput = ui?._inputs?.get?.(standardKey);
121
+ if (standardInput && typeof standardInput.addEventListener === 'function') {
122
+ const onStandardChange = () => {
123
+ const nextStd = getStandard();
124
+ const shouldEmit = nextStd !== lastStandard;
125
+ syncSelection(shouldEmit, true);
126
+ };
127
+ standardInput.addEventListener('change', onStandardChange);
128
+ cleanupStandardListener = () => standardInput.removeEventListener('change', onStandardChange);
129
+ }
130
+
131
+ syncSelection(false);
132
+
133
+ return {
134
+ inputEl: wrap,
135
+ inputRegistered: true,
136
+ skipDefaultRefresh: true,
137
+ activate() {
138
+ if (select.value === CUSTOM_VALUE) {
139
+ customInput.focus();
140
+ } else {
141
+ select.focus();
142
+ }
143
+ },
144
+ readValue() {
145
+ return ui.params[key];
146
+ },
147
+ refreshFromParams(value) {
148
+ if (value !== undefined) ui.params[key] = value;
149
+ const stdChanged = getStandard() !== lastStandard;
150
+ syncSelection(false, stdChanged);
151
+ },
152
+ destroy() {
153
+ if (cleanupStandardListener) cleanupStandardListener();
154
+ select.removeEventListener('change', handleSelectChange);
155
+ customInput.removeEventListener('input', handleCustomInput);
156
+ customInput.removeEventListener('change', handleCustomCommit);
157
+ customInput.removeEventListener('blur', handleCustomCommit);
158
+ },
159
+ };
160
+ }
@@ -0,0 +1,252 @@
1
+ import * as THREE from 'three';
2
+ import { combineBaseWithDeltaDeg } from '../../utils/xformMath.js';
3
+
4
+ export function renderTransformField({ ui, key, def, id, controlWrap, valueAdapter = null }) {
5
+ const inputEl = document.createElement('input');
6
+ inputEl.type = 'hidden';
7
+ inputEl.id = id;
8
+
9
+ const wrap = document.createElement('div');
10
+ wrap.className = 'transform-wrap';
11
+
12
+ const adapter = (valueAdapter && typeof valueAdapter === 'object') ? valueAdapter : null;
13
+ const activationKey = (adapter && typeof adapter.activationKey === 'string') ? adapter.activationKey : key;
14
+ const clone3 = (arr, fallback) => {
15
+ const copy = Array.isArray(arr) ? arr.slice(0, 3) : [];
16
+ while (copy.length < 3) copy.push(fallback);
17
+ return copy;
18
+ };
19
+ const sanitizeTRS = (raw) => {
20
+ const obj = (raw && typeof raw === 'object') ? raw : {};
21
+ return {
22
+ position: clone3(obj.position, 0),
23
+ rotationEuler: clone3(obj.rotationEuler, 0),
24
+ scale: clone3(obj.scale, 1),
25
+ };
26
+ };
27
+ const readTRS = () => {
28
+ if (adapter && typeof adapter.get === 'function') {
29
+ try { return sanitizeTRS(adapter.get()); } catch (_) { return sanitizeTRS(null); }
30
+ }
31
+ return sanitizeTRS(ui._pickInitialValue(key, def));
32
+ };
33
+ const writeTRS = (next) => {
34
+ const sanitized = sanitizeTRS(next);
35
+ if (adapter && typeof adapter.set === 'function') {
36
+ try {
37
+ adapter.set({
38
+ position: sanitized.position.slice(0, 3),
39
+ rotationEuler: sanitized.rotationEuler.slice(0, 3),
40
+ scale: sanitized.scale.slice(0, 3),
41
+ });
42
+ } catch (_) { /* ignore adapter errors */ }
43
+ } else {
44
+ ui.params[key] = {
45
+ position: sanitized.position.slice(0, 3),
46
+ rotationEuler: sanitized.rotationEuler.slice(0, 3),
47
+ scale: sanitized.scale.slice(0, 3),
48
+ };
49
+ }
50
+ return sanitized;
51
+ };
52
+ const emitChange = (value) => {
53
+ if (adapter && typeof adapter.emit === 'function') {
54
+ try { adapter.emit(value); return; } catch (_) { return; }
55
+ }
56
+ ui._emitParamsChange(activationKey, value);
57
+ };
58
+
59
+ const btn = document.createElement('button');
60
+ btn.type = 'button';
61
+ btn.className = 'btn';
62
+ btn.textContent = String(def.label || 'Position in 3D…');
63
+
64
+ const info = document.createElement('div');
65
+ info.className = 'transform-info';
66
+ const fmt = (n) => {
67
+ const v = Number(n);
68
+ if (!Number.isFinite(v)) return '0';
69
+ const a = Math.abs(v);
70
+ const prec = a >= 100 ? 0 : (a >= 10 ? 1 : 2);
71
+ return String(v.toFixed(prec));
72
+ };
73
+ const updateInfo = (value = null) => {
74
+ const v = value ? sanitizeTRS(value) : readTRS();
75
+ const p = Array.isArray(v.position) ? v.position : [0, 0, 0];
76
+ const r = Array.isArray(v.rotationEuler) ? v.rotationEuler : [0, 0, 0];
77
+ info.textContent = `pos(${fmt(p[0])}, ${fmt(p[1])}, ${fmt(p[2])}) rot(${fmt(r[0])}, ${fmt(r[1])}, ${fmt(r[2])})`;
78
+ };
79
+ updateInfo();
80
+
81
+ const modes = document.createElement('div');
82
+ modes.className = 'transform-modes';
83
+
84
+ const getTRS = () => readTRS();
85
+ const setTRS = (next, applyTarget = true, options = {}) => {
86
+ const { skipWrite = false } = options;
87
+ const sanitized = skipWrite ? sanitizeTRS(next) : writeTRS(next);
88
+ try { updateInfo(sanitized); } catch (_) {}
89
+ try {
90
+ const row = ui._fieldsWrap.querySelector(`[data-key="${key}"]`);
91
+ const scope = row || wrap;
92
+ const map = [
93
+ ['.tf-pos-x', sanitized.position[0]],
94
+ ['.tf-pos-y', sanitized.position[1]],
95
+ ['.tf-pos-z', sanitized.position[2]],
96
+ ['.tf-rot-x', sanitized.rotationEuler[0]],
97
+ ['.tf-rot-y', sanitized.rotationEuler[1]],
98
+ ['.tf-rot-z', sanitized.rotationEuler[2]],
99
+ ];
100
+ for (const [sel, val] of map) {
101
+ const el = scope ? scope.querySelector(sel) : null;
102
+ if (el) ui._setInputValue(el, 'number', val);
103
+ }
104
+ } catch (_) {}
105
+ if (applyTarget) {
106
+ try {
107
+ const active = ui.activeTransform;
108
+ if (active && active.inputEl === inputEl && active.target) {
109
+ const base = active.baseTransform || { position: [0,0,0], quaternion: [0,0,0,1], scale: [1,1,1] };
110
+ const Mabs = combineBaseWithDeltaDeg(base, sanitized, THREE);
111
+ const pos = new THREE.Vector3();
112
+ const quat = new THREE.Quaternion();
113
+ const scl = new THREE.Vector3();
114
+ Mabs.decompose(pos, quat, scl);
115
+ active.target.position.copy(pos);
116
+ active.target.quaternion.copy(quat);
117
+ active.target.scale.copy(scl);
118
+ }
119
+ } catch (_) { }
120
+ }
121
+ return sanitized;
122
+ };
123
+
124
+ const grid = document.createElement('div');
125
+ grid.className = 'transform-grid';
126
+ const addRow = (labelTxt, clsPrefix, valuesArr) => {
127
+ const rowEl = document.createElement('div');
128
+ rowEl.className = 'transform-row';
129
+ const lab = document.createElement('div');
130
+ lab.className = 'transform-label';
131
+ lab.textContent = labelTxt;
132
+ const inputs = document.createElement('div');
133
+ inputs.className = 'transform-inputs';
134
+ const axes = ['x', 'y', 'z'];
135
+ for (let i = 0; i < 3; i++) {
136
+ const inp = document.createElement('input');
137
+ inp.className = 'input transform-input ' + `tf-${clsPrefix}-${axes[i]}`;
138
+ inp.type = 'number';
139
+ inp.step = 'any';
140
+ ui._setInputValue(inp, 'number', valuesArr[i] ?? 0);
141
+ const numericPatternLocal = /^-?\d*\.?\d*$/;
142
+ const isNumericLikeLocal = (value) => {
143
+ if (value === '' || value == null) return true;
144
+ return numericPatternLocal.test(String(value));
145
+ };
146
+ const onFocusToggleTypeLocal = (el) => {
147
+ try {
148
+ if (isNumericLikeLocal(el.value)) {
149
+ el.type = 'number';
150
+ } else {
151
+ el.type = 'text';
152
+ }
153
+ } catch (_) { }
154
+ };
155
+ inp.addEventListener('focus', () => {
156
+ onFocusToggleTypeLocal(inp);
157
+ ui._stopActiveReferenceSelection();
158
+ });
159
+ inp.addEventListener('beforeinput', (e) => {
160
+ try {
161
+ const nextVal = String(inp.value || '') + String(e.data || '');
162
+ if (!isNumericLikeLocal(nextVal)) {
163
+ if (inp.type !== 'text') inp.type = 'text';
164
+ } else if (inp.type !== 'number') {
165
+ inp.type = 'number';
166
+ }
167
+ } catch (_) { }
168
+ });
169
+ inp.addEventListener('change', () => {
170
+ const cur = getTRS();
171
+ const val = inp.value;
172
+ if (clsPrefix === 'pos') cur.position[i] = val;
173
+ else cur.rotationEuler[i] = val;
174
+ const updated = setTRS(cur, true);
175
+ emitChange(updated);
176
+ });
177
+ inputs.appendChild(inp);
178
+ }
179
+ rowEl.appendChild(lab);
180
+ rowEl.appendChild(inputs);
181
+ grid.appendChild(rowEl);
182
+ };
183
+ const curTRS = getTRS();
184
+ addRow('Position', 'pos', curTRS.position);
185
+ addRow('Rotation (deg)', 'rot', curTRS.rotationEuler);
186
+
187
+ const resetBtn = document.createElement('button');
188
+ resetBtn.type = 'button';
189
+ resetBtn.className = 'btn btn-slim';
190
+ resetBtn.textContent = 'Reset';
191
+ resetBtn.title = 'Reset translation and rotation to 0';
192
+ resetBtn.addEventListener('click', () => {
193
+ const cur = getTRS();
194
+ const next = { position: [0, 0, 0], rotationEuler: [0, 0, 0], scale: cur.scale };
195
+ const updated = setTRS(next, true);
196
+ emitChange(updated);
197
+ const featureID = (ui.params && Object.prototype.hasOwnProperty.call(ui.params, 'featureID'))
198
+ ? ui.params.featureID
199
+ : (ui.params?.id ?? null);
200
+ if (typeof ui.options.onChange === 'function') ui.options.onChange(featureID);
201
+ });
202
+ modes.appendChild(resetBtn);
203
+
204
+ const buildTransformAdapter = () => {
205
+ if (!adapter) return null;
206
+ const wrapper = {};
207
+ if (typeof adapter.stepId === 'string') wrapper.stepId = adapter.stepId;
208
+ wrapper.get = () => {
209
+ if (typeof adapter.get === 'function') {
210
+ try { return sanitizeTRS(adapter.get()); } catch (_) { return readTRS(); }
211
+ }
212
+ return readTRS();
213
+ };
214
+ wrapper.set = (value) => {
215
+ const sanitized = sanitizeTRS(value);
216
+ if (typeof adapter.set === 'function') {
217
+ try { adapter.set(sanitized); } catch (_) { }
218
+ setTRS(sanitized, true, { skipWrite: true });
219
+ } else {
220
+ setTRS(sanitized, true);
221
+ }
222
+ emitChange(sanitized);
223
+ };
224
+ if (typeof adapter.getBase === 'function') {
225
+ wrapper.getBase = () => {
226
+ try { return adapter.getBase(); } catch (_) { return null; }
227
+ };
228
+ }
229
+ return wrapper;
230
+ };
231
+ const transformValueAdapter = buildTransformAdapter();
232
+ const activate = () => ui._activateTransformWidget({ inputEl, wrapEl: wrap, key: activationKey, def, valueAdapter: transformValueAdapter });
233
+ btn.addEventListener('click', activate);
234
+
235
+ wrap.appendChild(btn);
236
+ const details = document.createElement('div');
237
+ details.className = 'transform-details';
238
+ details.appendChild(modes);
239
+ details.appendChild(grid);
240
+ details.appendChild(info);
241
+ wrap.appendChild(details);
242
+ wrap.appendChild(inputEl);
243
+ controlWrap.appendChild(wrap);
244
+
245
+ return {
246
+ inputEl,
247
+ activate,
248
+ readValue() {
249
+ return readTRS();
250
+ },
251
+ };
252
+ }
@@ -0,0 +1,43 @@
1
+ export function normalizeReferenceName(value) {
2
+ if (value == null) return null;
3
+
4
+ if (typeof value === 'string') {
5
+ const trimmed = value.trim();
6
+ if (!trimmed) return null;
7
+ try {
8
+ const parsed = JSON.parse(trimmed);
9
+ if (parsed && typeof parsed === 'object') {
10
+ const parsedName = typeof parsed.name === 'string' ? parsed.name.trim() : '';
11
+ if (parsedName) return parsedName;
12
+ const parsedId = typeof parsed.id === 'string' ? parsed.id.trim() : '';
13
+ if (parsedId) return parsedId;
14
+ }
15
+ } catch (_) { /* not JSON */ }
16
+ return trimmed;
17
+ }
18
+
19
+ if (typeof value === 'object') {
20
+ if (typeof value.name === 'string' && value.name.trim()) return value.name.trim();
21
+ if (typeof value.id === 'string' && value.id.trim()) return value.id.trim();
22
+ if (Array.isArray(value.path)) {
23
+ const joined = value.path.filter(Boolean).map(String).join(' › ');
24
+ if (joined) return joined;
25
+ }
26
+ }
27
+
28
+ const asString = String(value);
29
+ return asString.trim() || null;
30
+ }
31
+
32
+ export function normalizeReferenceList(values) {
33
+ if (!Array.isArray(values)) return [];
34
+ const seen = new Set();
35
+ const out = [];
36
+ for (const item of values) {
37
+ const normalized = normalizeReferenceName(item);
38
+ if (!normalized || seen.has(normalized)) continue;
39
+ seen.add(normalized);
40
+ out.push(normalized);
41
+ }
42
+ return out;
43
+ }
@@ -0,0 +1,133 @@
1
+ export function renderVec3Field({ ui, key, def }) {
2
+ const inputEl = document.createElement('div');
3
+ inputEl.className = 'transform-grid';
4
+
5
+ const showUniform = Boolean(def && (def.uniformToggle === true));
6
+ let uniformChecked = Boolean(def && (def.uniformDefault === true));
7
+ let uniformCb = null;
8
+ if (showUniform) {
9
+ const uniformWrap = document.createElement('div');
10
+ uniformWrap.className = 'transform-row';
11
+ const spacer = document.createElement('div');
12
+ spacer.className = 'transform-label';
13
+ spacer.textContent = '';
14
+ const controls = document.createElement('div');
15
+ controls.className = 'transform-inputs';
16
+ const cbLabel = document.createElement('label');
17
+ cbLabel.style.display = 'inline-flex';
18
+ cbLabel.style.alignItems = 'center';
19
+ cbLabel.style.gap = '6px';
20
+ uniformCb = document.createElement('input');
21
+ uniformCb.type = 'checkbox';
22
+ uniformCb.checked = uniformChecked;
23
+ const txt = document.createElement('span');
24
+ txt.textContent = String(def.uniformLockLabel || 'Uniform');
25
+ cbLabel.appendChild(uniformCb);
26
+ cbLabel.appendChild(txt);
27
+ controls.appendChild(cbLabel);
28
+ uniformWrap.appendChild(spacer);
29
+ uniformWrap.appendChild(controls);
30
+ inputEl.appendChild(uniformWrap);
31
+ }
32
+
33
+ const mkRow = (labelText) => {
34
+ const rowEl = document.createElement('div');
35
+ rowEl.className = 'transform-row';
36
+ const lab = document.createElement('div');
37
+ lab.className = 'transform-label';
38
+ lab.textContent = labelText;
39
+ const inputsWrap = document.createElement('div');
40
+ inputsWrap.className = 'transform-inputs';
41
+ rowEl.appendChild(lab);
42
+ rowEl.appendChild(inputsWrap);
43
+ return { rowEl, inputsWrap };
44
+ };
45
+
46
+ const { rowEl, inputsWrap } = mkRow('XYZ');
47
+ inputEl.appendChild(rowEl);
48
+
49
+ const valuesArr = (() => {
50
+ const v = ui._pickInitialValue(key, def);
51
+ if (Array.isArray(v)) return [v[0] ?? 0, v[1] ?? 0, v[2] ?? 0];
52
+ if (v && typeof v === 'object') return [v.x ?? 0, v.y ?? 0, v.z ?? 0];
53
+ return [0, 0, 0];
54
+ })();
55
+
56
+ const stepStr = (def && (def.step != null)) ? String(def.step) : 'any';
57
+
58
+ const setParamFromInputs = () => {
59
+ const inps = Array.from(inputsWrap.querySelectorAll('input'));
60
+ const arr = inps.map((el) => el.value);
61
+ ui.params[key] = [arr[0], arr[1], arr[2]];
62
+ ui._emitParamsChange(key, ui.params[key]);
63
+ };
64
+
65
+ const inputs = [];
66
+ const numericPattern = /^-?\d*\.?\d*$/;
67
+ const isNumericLike = (value) => {
68
+ if (value === '' || value == null) return true;
69
+ return numericPattern.test(String(value));
70
+ };
71
+ const toggleTypeForContent = (el) => {
72
+ try {
73
+ if (isNumericLike(el.value)) el.type = 'number';
74
+ else el.type = 'text';
75
+ } catch (_) { }
76
+ };
77
+
78
+ for (let i = 0; i < 3; i++) {
79
+ const inp = document.createElement('input');
80
+ inp.type = 'number';
81
+ inp.className = 'input transform-input';
82
+ inp.step = stepStr;
83
+ ui._setInputValue(inp, 'number', valuesArr[i] ?? 0);
84
+ inp.addEventListener('focus', () => toggleTypeForContent(inp));
85
+ inp.addEventListener('beforeinput', (e) => {
86
+ try {
87
+ const nextVal = String(inp.value || '') + String(e.data || '');
88
+ if (!isNumericLike(nextVal)) {
89
+ if (inp.type !== 'text') inp.type = 'text';
90
+ } else if (inp.type !== 'number') {
91
+ inp.type = 'number';
92
+ }
93
+ } catch (_) { }
94
+ });
95
+ inp.addEventListener('change', () => {
96
+ if (showUniform && uniformCb && uniformCb.checked) {
97
+ const v = inp.value;
98
+ for (const other of inputsWrap.querySelectorAll('input')) other.value = v;
99
+ }
100
+ setParamFromInputs();
101
+ });
102
+ inputsWrap.appendChild(inp);
103
+ inputs.push(inp);
104
+ }
105
+
106
+ if (showUniform && uniformCb) {
107
+ const enforceUniformNow = () => {
108
+ if (uniformCb.checked && inputs.length) {
109
+ const v = inputs[0].value;
110
+ for (let i = 0; i < inputs.length; i++) inputs[i].value = String(v);
111
+ setParamFromInputs();
112
+ }
113
+ };
114
+ uniformCb.addEventListener('change', () => enforceUniformNow());
115
+ if (uniformChecked) enforceUniformNow();
116
+ }
117
+
118
+ return {
119
+ inputEl,
120
+ activate() {
121
+ const first = inputEl.querySelector('input');
122
+ if (first) first.focus();
123
+ },
124
+ readValue() {
125
+ const current = ui.params[key];
126
+ if (Array.isArray(current)) return current.slice(0, 3);
127
+ if (current && typeof current === 'object') {
128
+ return [current.x ?? 0, current.y ?? 0, current.z ?? 0];
129
+ }
130
+ return [0, 0, 0];
131
+ },
132
+ };
133
+ }