@pascal-app/nodes 1.0.0-beta.4 → 1.0.0

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 (863) hide show
  1. package/LICENSE +21 -0
  2. package/dist/block/commands.d.ts +68 -0
  3. package/dist/block/commands.d.ts.map +1 -0
  4. package/dist/block/commands.js +1144 -0
  5. package/dist/block/contextual-help.d.ts +3 -0
  6. package/dist/block/contextual-help.d.ts.map +1 -0
  7. package/dist/block/contextual-help.js +38 -0
  8. package/dist/block/definition.d.ts +8 -0
  9. package/dist/block/definition.d.ts.map +1 -0
  10. package/dist/block/definition.js +126 -0
  11. package/dist/block/edit-session.d.ts +16 -0
  12. package/dist/block/edit-session.d.ts.map +1 -0
  13. package/dist/block/edit-session.js +32 -0
  14. package/dist/block/face-host.d.ts +3 -0
  15. package/dist/block/face-host.d.ts.map +1 -0
  16. package/dist/block/face-host.js +178 -0
  17. package/dist/block/floorplan.d.ts +3 -0
  18. package/dist/block/floorplan.d.ts.map +1 -0
  19. package/dist/block/floorplan.js +43 -0
  20. package/dist/block/geometry-snap.d.ts +18 -0
  21. package/dist/block/geometry-snap.d.ts.map +1 -0
  22. package/dist/block/geometry-snap.js +137 -0
  23. package/dist/block/geometry.d.ts +11 -0
  24. package/dist/block/geometry.d.ts.map +1 -0
  25. package/dist/block/geometry.js +146 -0
  26. package/dist/block/gesture-wheel.d.ts +8 -0
  27. package/dist/block/gesture-wheel.d.ts.map +1 -0
  28. package/dist/block/gesture-wheel.js +7 -0
  29. package/dist/block/interaction-sfx.d.ts +3 -0
  30. package/dist/block/interaction-sfx.d.ts.map +1 -0
  31. package/dist/block/interaction-sfx.js +16 -0
  32. package/dist/block/last-operation.d.ts +48 -0
  33. package/dist/block/last-operation.d.ts.map +1 -0
  34. package/dist/block/last-operation.js +120 -0
  35. package/dist/block/loop-cut-interaction.d.ts +5 -0
  36. package/dist/block/loop-cut-interaction.d.ts.map +1 -0
  37. package/dist/block/loop-cut-interaction.js +13 -0
  38. package/dist/block/material-slots.d.ts +61 -0
  39. package/dist/block/material-slots.d.ts.map +1 -0
  40. package/dist/block/material-slots.js +131 -0
  41. package/dist/block/modal-face-operation.d.ts +13 -0
  42. package/dist/block/modal-face-operation.d.ts.map +1 -0
  43. package/dist/block/modal-face-operation.js +40 -0
  44. package/dist/block/modal-session.d.ts +15 -0
  45. package/dist/block/modal-session.d.ts.map +1 -0
  46. package/dist/block/modal-session.js +40 -0
  47. package/dist/block/modal-transform.d.ts +30 -0
  48. package/dist/block/modal-transform.d.ts.map +1 -0
  49. package/dist/block/modal-transform.js +144 -0
  50. package/dist/block/paint.d.ts +3 -0
  51. package/dist/block/paint.d.ts.map +1 -0
  52. package/dist/block/paint.js +136 -0
  53. package/dist/block/panel.d.ts +2 -0
  54. package/dist/block/panel.d.ts.map +1 -0
  55. package/dist/block/panel.js +234 -0
  56. package/dist/block/parametrics.d.ts +4 -0
  57. package/dist/block/parametrics.d.ts.map +1 -0
  58. package/dist/block/parametrics.js +9 -0
  59. package/dist/block/preview.d.ts +6 -0
  60. package/dist/block/preview.d.ts.map +1 -0
  61. package/dist/block/preview.js +46 -0
  62. package/dist/block/rotation-drag.d.ts +5 -0
  63. package/dist/block/rotation-drag.d.ts.map +1 -0
  64. package/dist/block/rotation-drag.js +18 -0
  65. package/dist/block/schema.d.ts +2 -0
  66. package/dist/block/schema.d.ts.map +1 -0
  67. package/dist/block/schema.js +1 -0
  68. package/dist/block/selection-geometry.d.ts +9 -0
  69. package/dist/block/selection-geometry.d.ts.map +1 -0
  70. package/dist/block/selection-geometry.js +31 -0
  71. package/dist/block/selection-model.d.ts +17 -0
  72. package/dist/block/selection-model.d.ts.map +1 -0
  73. package/dist/block/selection-model.js +84 -0
  74. package/dist/block/selection.d.ts +4 -0
  75. package/dist/block/selection.d.ts.map +1 -0
  76. package/dist/block/selection.js +2570 -0
  77. package/dist/block/slots.d.ts +4 -0
  78. package/dist/block/slots.d.ts.map +1 -0
  79. package/dist/block/slots.js +17 -0
  80. package/dist/block/tool.d.ts +3 -0
  81. package/dist/block/tool.d.ts.map +1 -0
  82. package/dist/block/tool.js +174 -0
  83. package/dist/block/toolbar-state.d.ts +46 -0
  84. package/dist/block/toolbar-state.d.ts.map +1 -0
  85. package/dist/block/toolbar-state.js +67 -0
  86. package/dist/block/use-block-face-operation.d.ts +39 -0
  87. package/dist/block/use-block-face-operation.d.ts.map +1 -0
  88. package/dist/block/use-block-face-operation.js +218 -0
  89. package/dist/box-vent/definition.d.ts.map +1 -1
  90. package/dist/box-vent/definition.js +8 -5
  91. package/dist/box-vent/geometry.d.ts +4 -0
  92. package/dist/box-vent/geometry.d.ts.map +1 -1
  93. package/dist/box-vent/geometry.js +76 -44
  94. package/dist/box-vent/paint.d.ts +4 -0
  95. package/dist/box-vent/paint.d.ts.map +1 -0
  96. package/dist/box-vent/paint.js +40 -0
  97. package/dist/box-vent/panel.js +1 -1
  98. package/dist/box-vent/parametrics.js +3 -3
  99. package/dist/box-vent/renderer.d.ts.map +1 -1
  100. package/dist/box-vent/renderer.js +29 -10
  101. package/dist/cabinet/compartment-card.d.ts.map +1 -1
  102. package/dist/cabinet/compartment-card.js +11 -3
  103. package/dist/cabinet/continuous-placement.d.ts +3 -0
  104. package/dist/cabinet/continuous-placement.d.ts.map +1 -1
  105. package/dist/cabinet/continuous-placement.js +6 -0
  106. package/dist/cabinet/definition.d.ts.map +1 -1
  107. package/dist/cabinet/definition.js +400 -54
  108. package/dist/cabinet/flame-index.d.ts +3 -0
  109. package/dist/cabinet/flame-index.d.ts.map +1 -0
  110. package/dist/cabinet/flame-index.js +13 -0
  111. package/dist/cabinet/floorplan-move.d.ts.map +1 -1
  112. package/dist/cabinet/floorplan-move.js +91 -22
  113. package/dist/cabinet/geometry/fridge.d.ts.map +1 -1
  114. package/dist/cabinet/geometry/fridge.js +25 -1
  115. package/dist/cabinet/geometry/fronts.d.ts +4 -0
  116. package/dist/cabinet/geometry/fronts.d.ts.map +1 -1
  117. package/dist/cabinet/geometry/fronts.js +1 -1
  118. package/dist/cabinet/geometry/run.d.ts.map +1 -1
  119. package/dist/cabinet/geometry/run.js +19 -1
  120. package/dist/cabinet/geometry.d.ts.map +1 -1
  121. package/dist/cabinet/geometry.js +63 -1
  122. package/dist/cabinet/index.d.ts +1 -0
  123. package/dist/cabinet/index.d.ts.map +1 -1
  124. package/dist/cabinet/index.js +1 -0
  125. package/dist/cabinet/insertion.d.ts +19 -0
  126. package/dist/cabinet/insertion.d.ts.map +1 -0
  127. package/dist/cabinet/insertion.js +49 -0
  128. package/dist/cabinet/move-frame.d.ts.map +1 -1
  129. package/dist/cabinet/move-frame.js +68 -2
  130. package/dist/cabinet/panel-context.d.ts +7 -0
  131. package/dist/cabinet/panel-context.d.ts.map +1 -0
  132. package/dist/cabinet/panel-context.js +16 -0
  133. package/dist/cabinet/panel-visibility.d.ts +9 -0
  134. package/dist/cabinet/panel-visibility.d.ts.map +1 -0
  135. package/dist/cabinet/panel-visibility.js +26 -0
  136. package/dist/cabinet/panel.d.ts.map +1 -1
  137. package/dist/cabinet/panel.js +221 -37
  138. package/dist/cabinet/placement-dimensions.d.ts +42 -0
  139. package/dist/cabinet/placement-dimensions.d.ts.map +1 -0
  140. package/dist/cabinet/placement-dimensions.js +227 -0
  141. package/dist/cabinet/placement-snap.d.ts +21 -1
  142. package/dist/cabinet/placement-snap.d.ts.map +1 -1
  143. package/dist/cabinet/placement-snap.js +48 -6
  144. package/dist/cabinet/preset-width-debt.d.ts +7 -0
  145. package/dist/cabinet/preset-width-debt.d.ts.map +1 -0
  146. package/dist/cabinet/preset-width-debt.js +45 -0
  147. package/dist/cabinet/presets.d.ts.map +1 -1
  148. package/dist/cabinet/presets.js +14 -13
  149. package/dist/cabinet/profiles.d.ts +14 -0
  150. package/dist/cabinet/profiles.d.ts.map +1 -0
  151. package/dist/cabinet/profiles.js +30 -0
  152. package/dist/cabinet/quick-actions.d.ts.map +1 -1
  153. package/dist/cabinet/quick-actions.js +8 -24
  154. package/dist/cabinet/reveals.d.ts +37 -0
  155. package/dist/cabinet/reveals.d.ts.map +1 -0
  156. package/dist/cabinet/reveals.js +13 -0
  157. package/dist/cabinet/run-layout.d.ts +90 -4
  158. package/dist/cabinet/run-layout.d.ts.map +1 -1
  159. package/dist/cabinet/run-layout.js +408 -23
  160. package/dist/cabinet/run-ops.d.ts +202 -10
  161. package/dist/cabinet/run-ops.d.ts.map +1 -1
  162. package/dist/cabinet/run-ops.js +520 -33
  163. package/dist/cabinet/run-panel.d.ts +6 -2
  164. package/dist/cabinet/run-panel.d.ts.map +1 -1
  165. package/dist/cabinet/run-panel.js +285 -108
  166. package/dist/cabinet/stack-transitions.d.ts.map +1 -1
  167. package/dist/cabinet/stack-transitions.js +35 -24
  168. package/dist/cabinet/stack.d.ts +169 -1
  169. package/dist/cabinet/stack.d.ts.map +1 -1
  170. package/dist/cabinet/stack.js +57 -18
  171. package/dist/cabinet/system.d.ts +2 -0
  172. package/dist/cabinet/system.d.ts.map +1 -1
  173. package/dist/cabinet/system.js +28 -8
  174. package/dist/cabinet/tool.d.ts.map +1 -1
  175. package/dist/cabinet/tool.js +616 -91
  176. package/dist/cabinet/validation.d.ts +27 -0
  177. package/dist/cabinet/validation.d.ts.map +1 -0
  178. package/dist/cabinet/validation.js +56 -0
  179. package/dist/cabinet/wall-height-presets.d.ts +12 -0
  180. package/dist/cabinet/wall-height-presets.d.ts.map +1 -0
  181. package/dist/cabinet/wall-height-presets.js +15 -0
  182. package/dist/cabinet/wall-snap.d.ts +27 -3
  183. package/dist/cabinet/wall-snap.d.ts.map +1 -1
  184. package/dist/cabinet/wall-snap.js +278 -62
  185. package/dist/cabinet/widths.d.ts +10 -0
  186. package/dist/cabinet/widths.d.ts.map +1 -0
  187. package/dist/cabinet/widths.js +13 -0
  188. package/dist/ceiling/definition.d.ts.map +1 -1
  189. package/dist/ceiling/definition.js +7 -1
  190. package/dist/ceiling/floorplan-affordances.d.ts +8 -8
  191. package/dist/ceiling/materials.d.ts.map +1 -1
  192. package/dist/ceiling/materials.js +0 -1
  193. package/dist/ceiling/panel.d.ts.map +1 -1
  194. package/dist/ceiling/panel.js +8 -2
  195. package/dist/ceiling/parametrics.js +1 -1
  196. package/dist/chimney/definition.js +1 -1
  197. package/dist/chimney/panel.js +1 -1
  198. package/dist/chimney/parametrics.js +3 -3
  199. package/dist/column/definition.d.ts.map +1 -1
  200. package/dist/column/definition.js +22 -4
  201. package/dist/column/panel.d.ts.map +1 -1
  202. package/dist/column/panel.js +37 -7
  203. package/dist/column/parametrics.d.ts.map +1 -1
  204. package/dist/column/parametrics.js +5 -3
  205. package/dist/column/tool.d.ts.map +1 -1
  206. package/dist/column/tool.js +50 -14
  207. package/dist/cupola/definition.d.ts.map +1 -1
  208. package/dist/cupola/definition.js +15 -6
  209. package/dist/cupola/geometry.d.ts +6 -0
  210. package/dist/cupola/geometry.d.ts.map +1 -1
  211. package/dist/cupola/geometry.js +60 -13
  212. package/dist/cupola/paint.d.ts +4 -0
  213. package/dist/cupola/paint.d.ts.map +1 -0
  214. package/dist/cupola/paint.js +39 -0
  215. package/dist/cupola/panel.js +1 -1
  216. package/dist/cupola/parametrics.js +3 -3
  217. package/dist/cupola/renderer.d.ts.map +1 -1
  218. package/dist/cupola/renderer.js +27 -8
  219. package/dist/door/floorplan-move.d.ts.map +1 -1
  220. package/dist/door/floorplan-move.js +1 -1
  221. package/dist/door/move-tool.d.ts.map +1 -1
  222. package/dist/door/move-tool.js +86 -32
  223. package/dist/door/panel.d.ts.map +1 -1
  224. package/dist/door/panel.js +1 -1
  225. package/dist/door/parametrics.js +2 -2
  226. package/dist/door/tool.d.ts.map +1 -1
  227. package/dist/door/tool.js +16 -4
  228. package/dist/dormer/csg-geometry.d.ts +6 -42
  229. package/dist/dormer/csg-geometry.d.ts.map +1 -1
  230. package/dist/dormer/csg-geometry.js +38 -209
  231. package/dist/dormer/definition.d.ts +4 -12
  232. package/dist/dormer/definition.d.ts.map +1 -1
  233. package/dist/dormer/definition.js +18 -193
  234. package/dist/dormer/floorplan.d.ts +3 -3
  235. package/dist/dormer/floorplan.d.ts.map +1 -1
  236. package/dist/dormer/floorplan.js +6 -17
  237. package/dist/dormer/geometry.d.ts +5 -24
  238. package/dist/dormer/geometry.d.ts.map +1 -1
  239. package/dist/dormer/geometry.js +64 -41
  240. package/dist/dormer/index.d.ts +1 -1
  241. package/dist/dormer/index.d.ts.map +1 -1
  242. package/dist/dormer/index.js +1 -1
  243. package/dist/dormer/move-tool.d.ts.map +1 -1
  244. package/dist/dormer/move-tool.js +31 -3
  245. package/dist/dormer/panel-windows-section.d.ts +9 -0
  246. package/dist/dormer/panel-windows-section.d.ts.map +1 -0
  247. package/dist/dormer/panel-windows-section.js +7 -0
  248. package/dist/dormer/panel.d.ts.map +1 -1
  249. package/dist/dormer/panel.js +100 -18
  250. package/dist/dormer/parametrics.d.ts.map +1 -1
  251. package/dist/dormer/parametrics.js +8 -77
  252. package/dist/dormer/placement-guides.d.ts.map +1 -1
  253. package/dist/dormer/placement-guides.js +5 -4
  254. package/dist/dormer/preview.d.ts.map +1 -1
  255. package/dist/dormer/preview.js +9 -1
  256. package/dist/dormer/renderer.d.ts.map +1 -1
  257. package/dist/dormer/renderer.js +24 -26
  258. package/dist/dormer/tool.d.ts.map +1 -1
  259. package/dist/dormer/tool.js +3 -1
  260. package/dist/dormer/window-layout.d.ts +15 -0
  261. package/dist/dormer/window-layout.d.ts.map +1 -0
  262. package/dist/dormer/window-layout.js +59 -0
  263. package/dist/downspout/definition.d.ts.map +1 -1
  264. package/dist/downspout/definition.js +17 -4
  265. package/dist/downspout/geometry.d.ts.map +1 -1
  266. package/dist/downspout/geometry.js +10 -0
  267. package/dist/downspout/inspector-editors.d.ts.map +1 -1
  268. package/dist/downspout/inspector-editors.js +9 -1
  269. package/dist/downspout/parametrics.d.ts.map +1 -1
  270. package/dist/downspout/parametrics.js +2 -1
  271. package/dist/downspout/renderer.d.ts.map +1 -1
  272. package/dist/downspout/renderer.js +19 -3
  273. package/dist/downspout/system.d.ts +7 -0
  274. package/dist/downspout/system.d.ts.map +1 -0
  275. package/dist/downspout/system.js +114 -0
  276. package/dist/duct-fitting/accessory-geometry.d.ts +4 -0
  277. package/dist/duct-fitting/accessory-geometry.d.ts.map +1 -0
  278. package/dist/duct-fitting/accessory-geometry.js +47 -0
  279. package/dist/duct-fitting/definition.d.ts.map +1 -1
  280. package/dist/duct-fitting/definition.js +11 -1
  281. package/dist/duct-fitting/floorplan.d.ts.map +1 -1
  282. package/dist/duct-fitting/floorplan.js +8 -0
  283. package/dist/duct-fitting/geometry.d.ts.map +1 -1
  284. package/dist/duct-fitting/geometry.js +52 -38
  285. package/dist/duct-fitting/parametrics.d.ts.map +1 -1
  286. package/dist/duct-fitting/parametrics.js +78 -15
  287. package/dist/duct-fitting/ports.d.ts +1 -0
  288. package/dist/duct-fitting/ports.d.ts.map +1 -1
  289. package/dist/duct-fitting/ports.js +46 -0
  290. package/dist/duct-fitting/tool.d.ts +19 -0
  291. package/dist/duct-fitting/tool.d.ts.map +1 -1
  292. package/dist/duct-fitting/tool.js +126 -34
  293. package/dist/duct-segment/continuation.d.ts +21 -0
  294. package/dist/duct-segment/continuation.d.ts.map +1 -0
  295. package/dist/duct-segment/continuation.js +167 -0
  296. package/dist/duct-segment/definition.d.ts.map +1 -1
  297. package/dist/duct-segment/definition.js +19 -18
  298. package/dist/duct-segment/floorplan.d.ts.map +1 -1
  299. package/dist/duct-segment/floorplan.js +43 -0
  300. package/dist/duct-segment/geometry.d.ts.map +1 -1
  301. package/dist/duct-segment/geometry.js +3 -0
  302. package/dist/duct-segment/move-tool.d.ts.map +1 -1
  303. package/dist/duct-segment/move-tool.js +33 -6
  304. package/dist/duct-segment/parametrics.d.ts.map +1 -1
  305. package/dist/duct-segment/parametrics.js +45 -1
  306. package/dist/duct-segment/selection.d.ts +3 -4
  307. package/dist/duct-segment/selection.d.ts.map +1 -1
  308. package/dist/duct-segment/selection.js +186 -158
  309. package/dist/duct-segment/tool.d.ts +37 -0
  310. package/dist/duct-segment/tool.d.ts.map +1 -1
  311. package/dist/duct-segment/tool.js +305 -678
  312. package/dist/duct-terminal/parametrics.js +2 -2
  313. package/dist/duct-terminal/tool.d.ts.map +1 -1
  314. package/dist/duct-terminal/tool.js +37 -7
  315. package/dist/elevator/definition.d.ts.map +1 -1
  316. package/dist/elevator/definition.js +2 -0
  317. package/dist/elevator/panel.d.ts.map +1 -1
  318. package/dist/elevator/panel.js +7 -7
  319. package/dist/elevator/system.d.ts.map +1 -1
  320. package/dist/elevator/system.js +10 -1
  321. package/dist/eyebrow-vent/definition.d.ts.map +1 -1
  322. package/dist/eyebrow-vent/definition.js +8 -5
  323. package/dist/eyebrow-vent/geometry.d.ts +4 -0
  324. package/dist/eyebrow-vent/geometry.d.ts.map +1 -1
  325. package/dist/eyebrow-vent/geometry.js +60 -15
  326. package/dist/eyebrow-vent/paint.d.ts +4 -0
  327. package/dist/eyebrow-vent/paint.d.ts.map +1 -0
  328. package/dist/eyebrow-vent/paint.js +33 -0
  329. package/dist/eyebrow-vent/panel.js +1 -1
  330. package/dist/eyebrow-vent/parametrics.js +3 -3
  331. package/dist/eyebrow-vent/renderer.d.ts.map +1 -1
  332. package/dist/eyebrow-vent/renderer.js +27 -8
  333. package/dist/fence/curve-tool.d.ts.map +1 -1
  334. package/dist/fence/curve-tool.js +14 -9
  335. package/dist/fence/definition.d.ts.map +1 -1
  336. package/dist/fence/definition.js +2 -1
  337. package/dist/fence/floorplan-affordances.d.ts +1 -0
  338. package/dist/fence/floorplan-affordances.d.ts.map +1 -1
  339. package/dist/fence/floorplan-affordances.js +30 -1
  340. package/dist/fence/floorplan.d.ts.map +1 -1
  341. package/dist/fence/floorplan.js +14 -0
  342. package/dist/fence/move-control-point-tool.d.ts.map +1 -1
  343. package/dist/fence/move-control-point-tool.js +13 -8
  344. package/dist/fence/move-tangent-tool.d.ts.map +1 -1
  345. package/dist/fence/move-tangent-tool.js +13 -8
  346. package/dist/fence/parametrics.js +3 -3
  347. package/dist/fence/tool.d.ts.map +1 -1
  348. package/dist/fence/tool.js +55 -31
  349. package/dist/gutter/corner-mitre.d.ts.map +1 -1
  350. package/dist/gutter/corner-mitre.js +47 -7
  351. package/dist/gutter/definition.d.ts.map +1 -1
  352. package/dist/gutter/definition.js +23 -13
  353. package/dist/gutter/eave-align.d.ts.map +1 -1
  354. package/dist/gutter/eave-align.js +10 -0
  355. package/dist/gutter/eave-snap.d.ts +1 -1
  356. package/dist/gutter/eave-snap.d.ts.map +1 -1
  357. package/dist/gutter/eave-snap.js +10 -23
  358. package/dist/gutter/geometry.d.ts.map +1 -1
  359. package/dist/gutter/geometry.js +126 -8
  360. package/dist/gutter/outlet-lookup.d.ts.map +1 -1
  361. package/dist/gutter/outlet-lookup.js +22 -1
  362. package/dist/gutter/paint.d.ts +3 -0
  363. package/dist/gutter/paint.d.ts.map +1 -0
  364. package/dist/gutter/paint.js +6 -0
  365. package/dist/gutter/parametrics.d.ts.map +1 -1
  366. package/dist/gutter/parametrics.js +4 -1
  367. package/dist/gutter/renderer.d.ts.map +1 -1
  368. package/dist/gutter/renderer.js +63 -7
  369. package/dist/gutter/trim-clip.d.ts +3 -0
  370. package/dist/gutter/trim-clip.d.ts.map +1 -0
  371. package/dist/gutter/trim-clip.js +5 -0
  372. package/dist/hvac-equipment/parametrics.js +3 -3
  373. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  374. package/dist/hvac-equipment/tool.js +12 -2
  375. package/dist/index.d.ts +5 -2
  376. package/dist/index.d.ts.map +1 -1
  377. package/dist/index.js +9 -2
  378. package/dist/item/definition.d.ts.map +1 -1
  379. package/dist/item/definition.js +10 -2
  380. package/dist/item/floorplan-move.d.ts.map +1 -1
  381. package/dist/item/floorplan-move.js +20 -1
  382. package/dist/item/floorplan.d.ts.map +1 -1
  383. package/dist/item/floorplan.js +22 -1
  384. package/dist/item/move-tool.d.ts +28 -1
  385. package/dist/item/move-tool.d.ts.map +1 -1
  386. package/dist/item/move-tool.js +14 -2
  387. package/dist/item/renderer.d.ts.map +1 -1
  388. package/dist/item/renderer.js +16 -6
  389. package/dist/item/system.d.ts +5 -0
  390. package/dist/item/system.d.ts.map +1 -1
  391. package/dist/item/system.js +7 -1
  392. package/dist/lean-to-extension/arc.d.ts +14 -0
  393. package/dist/lean-to-extension/arc.d.ts.map +1 -0
  394. package/dist/lean-to-extension/arc.js +56 -0
  395. package/dist/lean-to-extension/assembly.d.ts +61 -0
  396. package/dist/lean-to-extension/assembly.d.ts.map +1 -0
  397. package/dist/lean-to-extension/assembly.js +761 -0
  398. package/dist/lean-to-extension/canopy-joint.d.ts +35 -0
  399. package/dist/lean-to-extension/canopy-joint.d.ts.map +1 -0
  400. package/dist/lean-to-extension/canopy-joint.js +234 -0
  401. package/dist/lean-to-extension/conical-host.d.ts +15 -0
  402. package/dist/lean-to-extension/conical-host.d.ts.map +1 -0
  403. package/dist/lean-to-extension/conical-host.js +113 -0
  404. package/dist/lean-to-extension/corner-joint.d.ts +29 -0
  405. package/dist/lean-to-extension/corner-joint.d.ts.map +1 -0
  406. package/dist/lean-to-extension/corner-joint.js +1202 -0
  407. package/dist/lean-to-extension/definition.d.ts +4 -0
  408. package/dist/lean-to-extension/definition.d.ts.map +1 -0
  409. package/dist/lean-to-extension/definition.js +433 -0
  410. package/dist/lean-to-extension/floorplan-affordances.d.ts +4 -0
  411. package/dist/lean-to-extension/floorplan-affordances.d.ts.map +1 -0
  412. package/dist/lean-to-extension/floorplan-affordances.js +144 -0
  413. package/dist/lean-to-extension/floorplan-move.d.ts +3 -0
  414. package/dist/lean-to-extension/floorplan-move.d.ts.map +1 -0
  415. package/dist/lean-to-extension/floorplan-move.js +157 -0
  416. package/dist/lean-to-extension/floorplan-tool.d.ts +4 -0
  417. package/dist/lean-to-extension/floorplan-tool.d.ts.map +1 -0
  418. package/dist/lean-to-extension/floorplan-tool.js +385 -0
  419. package/dist/lean-to-extension/floorplan.d.ts +3 -0
  420. package/dist/lean-to-extension/floorplan.d.ts.map +1 -0
  421. package/dist/lean-to-extension/floorplan.js +373 -0
  422. package/dist/lean-to-extension/geometry.d.ts +7 -0
  423. package/dist/lean-to-extension/geometry.d.ts.map +1 -0
  424. package/dist/lean-to-extension/geometry.js +662 -0
  425. package/dist/lean-to-extension/index.d.ts +8 -0
  426. package/dist/lean-to-extension/index.d.ts.map +1 -0
  427. package/dist/lean-to-extension/index.js +7 -0
  428. package/dist/lean-to-extension/layout.d.ts +108 -0
  429. package/dist/lean-to-extension/layout.d.ts.map +1 -0
  430. package/dist/lean-to-extension/layout.js +477 -0
  431. package/dist/lean-to-extension/managed-preview.d.ts +3 -0
  432. package/dist/lean-to-extension/managed-preview.d.ts.map +1 -0
  433. package/dist/lean-to-extension/managed-preview.js +93 -0
  434. package/dist/lean-to-extension/move-tool.d.ts +8 -0
  435. package/dist/lean-to-extension/move-tool.d.ts.map +1 -0
  436. package/dist/lean-to-extension/move-tool.js +202 -0
  437. package/dist/lean-to-extension/paint.d.ts +2 -0
  438. package/dist/lean-to-extension/paint.d.ts.map +1 -0
  439. package/dist/lean-to-extension/paint.js +16 -0
  440. package/dist/lean-to-extension/parametrics.d.ts +4 -0
  441. package/dist/lean-to-extension/parametrics.d.ts.map +1 -0
  442. package/dist/lean-to-extension/parametrics.js +570 -0
  443. package/dist/lean-to-extension/placement-scope.d.ts +3 -0
  444. package/dist/lean-to-extension/placement-scope.d.ts.map +1 -0
  445. package/dist/lean-to-extension/placement-scope.js +4 -0
  446. package/dist/lean-to-extension/placement-validation.d.ts +4 -0
  447. package/dist/lean-to-extension/placement-validation.d.ts.map +1 -0
  448. package/dist/lean-to-extension/placement-validation.js +324 -0
  449. package/dist/lean-to-extension/placement.d.ts +59 -0
  450. package/dist/lean-to-extension/placement.d.ts.map +1 -0
  451. package/dist/lean-to-extension/placement.js +331 -0
  452. package/dist/lean-to-extension/plan-footprint.d.ts +10 -0
  453. package/dist/lean-to-extension/plan-footprint.d.ts.map +1 -0
  454. package/dist/lean-to-extension/plan-footprint.js +27 -0
  455. package/dist/lean-to-extension/preview-geometry.d.ts +7 -0
  456. package/dist/lean-to-extension/preview-geometry.d.ts.map +1 -0
  457. package/dist/lean-to-extension/preview-geometry.js +40 -0
  458. package/dist/lean-to-extension/preview.d.ts +7 -0
  459. package/dist/lean-to-extension/preview.d.ts.map +1 -0
  460. package/dist/lean-to-extension/preview.js +20 -0
  461. package/dist/lean-to-extension/renderer.d.ts +6 -0
  462. package/dist/lean-to-extension/renderer.d.ts.map +1 -0
  463. package/dist/lean-to-extension/renderer.js +34 -0
  464. package/dist/lean-to-extension/roof-attachment.d.ts +28 -0
  465. package/dist/lean-to-extension/roof-attachment.d.ts.map +1 -0
  466. package/dist/lean-to-extension/roof-attachment.js +376 -0
  467. package/dist/lean-to-extension/schema.d.ts +2 -0
  468. package/dist/lean-to-extension/schema.d.ts.map +1 -0
  469. package/dist/lean-to-extension/schema.js +1 -0
  470. package/dist/lean-to-extension/slots.d.ts +5 -0
  471. package/dist/lean-to-extension/slots.d.ts.map +1 -0
  472. package/dist/lean-to-extension/slots.js +15 -0
  473. package/dist/lean-to-extension/system.d.ts +7 -0
  474. package/dist/lean-to-extension/system.d.ts.map +1 -0
  475. package/dist/lean-to-extension/system.js +726 -0
  476. package/dist/lean-to-extension/tool.d.ts +3 -0
  477. package/dist/lean-to-extension/tool.d.ts.map +1 -0
  478. package/dist/lean-to-extension/tool.js +580 -0
  479. package/dist/lean-to-extension/wall-target.d.ts +10 -0
  480. package/dist/lean-to-extension/wall-target.d.ts.map +1 -0
  481. package/dist/lean-to-extension/wall-target.js +29 -0
  482. package/dist/lineset/definition.d.ts.map +1 -1
  483. package/dist/lineset/definition.js +1 -0
  484. package/dist/liquid-line/definition.d.ts.map +1 -1
  485. package/dist/liquid-line/definition.js +1 -0
  486. package/dist/measurement/renderer.d.ts.map +1 -1
  487. package/dist/measurement/renderer.js +6 -5
  488. package/dist/measurement/surface-query.js +5 -5
  489. package/dist/measurement/tool.d.ts.map +1 -1
  490. package/dist/measurement/tool.js +7 -5
  491. package/dist/pipe-fitting/definition.d.ts.map +1 -1
  492. package/dist/pipe-fitting/definition.js +16 -2
  493. package/dist/pipe-fitting/floorplan.d.ts.map +1 -1
  494. package/dist/pipe-fitting/floorplan.js +4 -0
  495. package/dist/pipe-fitting/geometry.d.ts +3 -5
  496. package/dist/pipe-fitting/geometry.d.ts.map +1 -1
  497. package/dist/pipe-fitting/geometry.js +154 -21
  498. package/dist/pipe-fitting/inline-insertion.d.ts +13 -0
  499. package/dist/pipe-fitting/inline-insertion.d.ts.map +1 -0
  500. package/dist/pipe-fitting/inline-insertion.js +96 -0
  501. package/dist/pipe-fitting/parametrics.d.ts.map +1 -1
  502. package/dist/pipe-fitting/parametrics.js +17 -3
  503. package/dist/pipe-fitting/ports.d.ts.map +1 -1
  504. package/dist/pipe-fitting/ports.js +8 -1
  505. package/dist/pipe-fitting/tool.d.ts +26 -0
  506. package/dist/pipe-fitting/tool.d.ts.map +1 -1
  507. package/dist/pipe-fitting/tool.js +182 -37
  508. package/dist/pipe-segment/continuation.d.ts +22 -0
  509. package/dist/pipe-segment/continuation.d.ts.map +1 -0
  510. package/dist/pipe-segment/continuation.js +146 -0
  511. package/dist/pipe-segment/definition.d.ts.map +1 -1
  512. package/dist/pipe-segment/definition.js +23 -7
  513. package/dist/pipe-segment/floorplan.d.ts.map +1 -1
  514. package/dist/pipe-segment/floorplan.js +42 -0
  515. package/dist/pipe-segment/geometry.d.ts +2 -1
  516. package/dist/pipe-segment/geometry.d.ts.map +1 -1
  517. package/dist/pipe-segment/geometry.js +4 -1
  518. package/dist/pipe-segment/move-tool.d.ts.map +1 -1
  519. package/dist/pipe-segment/move-tool.js +25 -5
  520. package/dist/pipe-segment/parametrics.d.ts.map +1 -1
  521. package/dist/pipe-segment/parametrics.js +45 -0
  522. package/dist/pipe-segment/selection.d.ts +3 -4
  523. package/dist/pipe-segment/selection.d.ts.map +1 -1
  524. package/dist/pipe-segment/selection.js +169 -105
  525. package/dist/pipe-segment/slope.d.ts +5 -0
  526. package/dist/pipe-segment/slope.d.ts.map +1 -0
  527. package/dist/pipe-segment/slope.js +10 -0
  528. package/dist/pipe-segment/tool.d.ts.map +1 -1
  529. package/dist/pipe-segment/tool.js +325 -545
  530. package/dist/pipe-trap/tool.d.ts.map +1 -1
  531. package/dist/pipe-trap/tool.js +15 -2
  532. package/dist/ridge-vent/definition.js +1 -1
  533. package/dist/ridge-vent/panel.d.ts.map +1 -1
  534. package/dist/ridge-vent/panel.js +2 -2
  535. package/dist/ridge-vent/parametrics.js +1 -1
  536. package/dist/ridge-vent/renderer.d.ts.map +1 -1
  537. package/dist/ridge-vent/renderer.js +2 -2
  538. package/dist/roof/conical-roof-placement.d.ts +36 -0
  539. package/dist/roof/conical-roof-placement.d.ts.map +1 -0
  540. package/dist/roof/conical-roof-placement.js +134 -0
  541. package/dist/roof/conical-roof.d.ts +3 -0
  542. package/dist/roof/conical-roof.d.ts.map +1 -0
  543. package/dist/roof/conical-roof.js +53 -0
  544. package/dist/roof/definition.d.ts +3 -10
  545. package/dist/roof/definition.d.ts.map +1 -1
  546. package/dist/roof/definition.js +83 -13
  547. package/dist/roof/floorplan.d.ts +3 -10
  548. package/dist/roof/floorplan.d.ts.map +1 -1
  549. package/dist/roof/floorplan.js +139 -165
  550. package/dist/roof/index.d.ts +1 -0
  551. package/dist/roof/index.d.ts.map +1 -1
  552. package/dist/roof/index.js +1 -0
  553. package/dist/roof/panel.d.ts.map +1 -1
  554. package/dist/roof/panel.js +22 -23
  555. package/dist/roof/renderer.d.ts.map +1 -1
  556. package/dist/roof/roof-footprint-source.d.ts +16 -0
  557. package/dist/roof/roof-footprint-source.d.ts.map +1 -0
  558. package/dist/roof/roof-footprint-source.js +14 -0
  559. package/dist/roof/roof-footprint.d.ts +25 -0
  560. package/dist/roof/roof-footprint.d.ts.map +1 -0
  561. package/dist/roof/roof-footprint.js +94 -0
  562. package/dist/roof/roof-placement-mode.d.ts +18 -0
  563. package/dist/roof/roof-placement-mode.d.ts.map +1 -0
  564. package/dist/roof/roof-placement-mode.js +24 -0
  565. package/dist/roof/tool.d.ts +10 -0
  566. package/dist/roof/tool.d.ts.map +1 -0
  567. package/dist/roof/tool.js +922 -0
  568. package/dist/roof-segment/definition.d.ts.map +1 -1
  569. package/dist/roof-segment/definition.js +52 -8
  570. package/dist/roof-segment/floorplan-affordances.d.ts +5 -6
  571. package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
  572. package/dist/roof-segment/floorplan-affordances.js +64 -18
  573. package/dist/roof-segment/floorplan.d.ts +3 -2
  574. package/dist/roof-segment/floorplan.d.ts.map +1 -1
  575. package/dist/roof-segment/floorplan.js +95 -46
  576. package/dist/roof-segment/panel.d.ts.map +1 -1
  577. package/dist/roof-segment/panel.js +122 -27
  578. package/dist/scan/definition.d.ts +2 -3
  579. package/dist/scan/definition.d.ts.map +1 -1
  580. package/dist/scan/definition.js +9 -7
  581. package/dist/scan/parametrics.d.ts.map +1 -1
  582. package/dist/scan/parametrics.js +13 -1
  583. package/dist/scan/renderer.d.ts.map +1 -1
  584. package/dist/scan/renderer.js +8 -2
  585. package/dist/shared/accessory-cursor.d.ts +7 -0
  586. package/dist/shared/accessory-cursor.d.ts.map +1 -0
  587. package/dist/shared/accessory-cursor.js +83 -0
  588. package/dist/shared/accessory-floorplan.d.ts +4 -0
  589. package/dist/shared/accessory-floorplan.d.ts.map +1 -0
  590. package/dist/shared/accessory-floorplan.js +51 -0
  591. package/dist/shared/accessory-geometry.d.ts +7 -0
  592. package/dist/shared/accessory-geometry.d.ts.map +1 -0
  593. package/dist/shared/accessory-geometry.js +79 -0
  594. package/dist/shared/accessory-placement.d.ts +10 -0
  595. package/dist/shared/accessory-placement.d.ts.map +1 -0
  596. package/dist/shared/accessory-placement.js +126 -0
  597. package/dist/shared/accessory-snapping.d.ts +5 -0
  598. package/dist/shared/accessory-snapping.d.ts.map +1 -0
  599. package/dist/shared/accessory-snapping.js +40 -0
  600. package/dist/shared/automatic-run-end-cap.d.ts +11 -0
  601. package/dist/shared/automatic-run-end-cap.d.ts.map +1 -0
  602. package/dist/shared/automatic-run-end-cap.js +159 -0
  603. package/dist/shared/block-face-host.d.ts +15 -0
  604. package/dist/shared/block-face-host.d.ts.map +1 -0
  605. package/dist/shared/block-face-host.js +36 -0
  606. package/dist/shared/connection-compatibility.d.ts +8 -0
  607. package/dist/shared/connection-compatibility.d.ts.map +1 -0
  608. package/dist/shared/connection-compatibility.js +28 -0
  609. package/dist/shared/connection-feedback.d.ts +10 -0
  610. package/dist/shared/connection-feedback.d.ts.map +1 -0
  611. package/dist/shared/connection-feedback.js +17 -0
  612. package/dist/shared/distribution-run-contract.d.ts +49 -0
  613. package/dist/shared/distribution-run-contract.d.ts.map +1 -0
  614. package/dist/shared/distribution-run-contract.js +30 -0
  615. package/dist/shared/distribution-run-tool.d.ts +107 -0
  616. package/dist/shared/distribution-run-tool.d.ts.map +1 -0
  617. package/dist/shared/distribution-run-tool.js +941 -0
  618. package/dist/shared/dormer-wall-opening-placement.d.ts +21 -0
  619. package/dist/shared/dormer-wall-opening-placement.d.ts.map +1 -0
  620. package/dist/shared/dormer-wall-opening-placement.js +101 -0
  621. package/dist/shared/duct-adapter.d.ts +10 -0
  622. package/dist/shared/duct-adapter.d.ts.map +1 -0
  623. package/dist/shared/duct-adapter.js +43 -0
  624. package/dist/shared/elbow-branch-continuation.d.ts +20 -0
  625. package/dist/shared/elbow-branch-continuation.d.ts.map +1 -0
  626. package/dist/shared/elbow-branch-continuation.js +200 -0
  627. package/dist/shared/fitting-clearance.d.ts +5 -0
  628. package/dist/shared/fitting-clearance.d.ts.map +1 -0
  629. package/dist/shared/fitting-clearance.js +11 -0
  630. package/dist/shared/fitting-deletion-cleanup.d.ts +14 -0
  631. package/dist/shared/fitting-deletion-cleanup.d.ts.map +1 -0
  632. package/dist/shared/fitting-deletion-cleanup.js +297 -0
  633. package/dist/shared/fitting-surface-support.d.ts +5 -0
  634. package/dist/shared/fitting-surface-support.d.ts.map +1 -0
  635. package/dist/shared/fitting-surface-support.js +42 -0
  636. package/dist/shared/fitting-tool-options.d.ts +4 -0
  637. package/dist/shared/fitting-tool-options.d.ts.map +1 -0
  638. package/dist/shared/fitting-tool-options.js +175 -0
  639. package/dist/shared/floor-placement.d.ts +1 -1
  640. package/dist/shared/floor-placement.d.ts.map +1 -1
  641. package/dist/shared/floor-placement.js +13 -33
  642. package/dist/shared/ghost-materials.d.ts.map +1 -1
  643. package/dist/shared/ghost-materials.js +2 -1
  644. package/dist/shared/lean-to-post-omissions.d.ts +8 -0
  645. package/dist/shared/lean-to-post-omissions.d.ts.map +1 -0
  646. package/dist/shared/lean-to-post-omissions.js +51 -0
  647. package/dist/shared/mep-fitting-actions.d.ts +5 -0
  648. package/dist/shared/mep-fitting-actions.d.ts.map +1 -0
  649. package/dist/shared/mep-fitting-actions.js +16 -0
  650. package/dist/shared/mep-ghost.d.ts.map +1 -1
  651. package/dist/shared/mep-ghost.js +19 -1
  652. package/dist/shared/mep-presets.d.ts +11 -0
  653. package/dist/shared/mep-presets.d.ts.map +1 -0
  654. package/dist/shared/mep-presets.js +34 -0
  655. package/dist/shared/node-batch/candidates.d.ts +29 -0
  656. package/dist/shared/node-batch/candidates.d.ts.map +1 -0
  657. package/dist/shared/node-batch/candidates.js +260 -0
  658. package/dist/shared/node-batch/store.d.ts +26 -0
  659. package/dist/shared/node-batch/store.d.ts.map +1 -0
  660. package/dist/shared/node-batch/store.js +319 -0
  661. package/dist/shared/node-batch/system.d.ts +8 -0
  662. package/dist/shared/node-batch/system.d.ts.map +1 -0
  663. package/dist/shared/node-batch/system.js +569 -0
  664. package/dist/shared/node-batch/types.d.ts +99 -0
  665. package/dist/shared/node-batch/types.d.ts.map +1 -0
  666. package/dist/shared/node-batch/types.js +4 -0
  667. package/dist/shared/opening-move-history.d.ts +47 -0
  668. package/dist/shared/opening-move-history.d.ts.map +1 -0
  669. package/dist/shared/opening-move-history.js +18 -0
  670. package/dist/shared/opening-move-wall-gate.d.ts +55 -0
  671. package/dist/shared/opening-move-wall-gate.d.ts.map +1 -0
  672. package/dist/shared/opening-move-wall-gate.js +44 -0
  673. package/dist/shared/path-point-affordance.d.ts +2 -2
  674. package/dist/shared/path-point-affordance.d.ts.map +1 -1
  675. package/dist/shared/path-point-affordance.js +30 -6
  676. package/dist/shared/placeholder-geometry.d.ts.map +1 -1
  677. package/dist/shared/placeholder-geometry.js +4 -0
  678. package/dist/shared/ports.d.ts +20 -3
  679. package/dist/shared/ports.d.ts.map +1 -1
  680. package/dist/shared/ports.js +148 -7
  681. package/dist/shared/primitive-uv.d.ts +17 -0
  682. package/dist/shared/primitive-uv.d.ts.map +1 -0
  683. package/dist/shared/primitive-uv.js +107 -0
  684. package/dist/shared/reducer-size.d.ts +2 -0
  685. package/dist/shared/reducer-size.d.ts.map +1 -0
  686. package/dist/shared/reducer-size.js +12 -0
  687. package/dist/shared/ridge-snap.js +1 -1
  688. package/dist/shared/roof-surface.d.ts.map +1 -1
  689. package/dist/shared/roof-surface.js +17 -2
  690. package/dist/shared/run-cursor.d.ts +22 -0
  691. package/dist/shared/run-cursor.d.ts.map +1 -0
  692. package/dist/shared/run-cursor.js +19 -0
  693. package/dist/shared/run-direction-feedback.d.ts +20 -0
  694. package/dist/shared/run-direction-feedback.d.ts.map +1 -0
  695. package/dist/shared/run-direction-feedback.js +139 -0
  696. package/dist/shared/run-hanger-controls.d.ts +7 -0
  697. package/dist/shared/run-hanger-controls.d.ts.map +1 -0
  698. package/dist/shared/run-hanger-controls.js +44 -0
  699. package/dist/shared/run-hanger-inspector.d.ts +5 -0
  700. package/dist/shared/run-hanger-inspector.d.ts.map +1 -0
  701. package/dist/shared/run-hanger-inspector.js +43 -0
  702. package/dist/shared/run-hanger-mode.d.ts +11 -0
  703. package/dist/shared/run-hanger-mode.d.ts.map +1 -0
  704. package/dist/shared/run-hanger-mode.js +32 -0
  705. package/dist/shared/run-hanger-system.d.ts +3 -0
  706. package/dist/shared/run-hanger-system.d.ts.map +1 -0
  707. package/dist/shared/run-hanger-system.js +39 -0
  708. package/dist/shared/run-hangers.d.ts +25 -0
  709. package/dist/shared/run-hangers.d.ts.map +1 -0
  710. package/dist/shared/run-hangers.js +261 -0
  711. package/dist/shared/run-port-snap.d.ts +11 -0
  712. package/dist/shared/run-port-snap.d.ts.map +1 -0
  713. package/dist/shared/run-port-snap.js +19 -0
  714. package/dist/shared/run-screen-direction.d.ts +5 -0
  715. package/dist/shared/run-screen-direction.d.ts.map +1 -0
  716. package/dist/shared/run-screen-direction.js +24 -0
  717. package/dist/shared/selection-handles.d.ts +4 -0
  718. package/dist/shared/selection-handles.d.ts.map +1 -1
  719. package/dist/shared/selection-handles.js +10 -0
  720. package/dist/shared/slot-paint.d.ts +8 -1
  721. package/dist/shared/slot-paint.d.ts.map +1 -1
  722. package/dist/shared/slot-paint.js +120 -27
  723. package/dist/shared/surface-paint.d.ts +1 -2
  724. package/dist/shared/surface-paint.d.ts.map +1 -1
  725. package/dist/shared/surface-paint.js +9 -20
  726. package/dist/shared/system-check-panel.d.ts +6 -0
  727. package/dist/shared/system-check-panel.d.ts.map +1 -0
  728. package/dist/shared/system-check-panel.js +62 -0
  729. package/dist/shared/system-checks.d.ts +9 -0
  730. package/dist/shared/system-checks.d.ts.map +1 -0
  731. package/dist/shared/system-checks.js +131 -0
  732. package/dist/shared/wall-attach-target.d.ts +14 -2
  733. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  734. package/dist/shared/wall-attach-target.js +108 -4
  735. package/dist/shared/wall-opening-clearance.d.ts +19 -0
  736. package/dist/shared/wall-opening-clearance.d.ts.map +1 -0
  737. package/dist/shared/wall-opening-clearance.js +28 -0
  738. package/dist/shared/wall-run-move.d.ts +17 -0
  739. package/dist/shared/wall-run-move.d.ts.map +1 -0
  740. package/dist/shared/wall-run-move.js +56 -0
  741. package/dist/shelf/parametrics.js +4 -4
  742. package/dist/site/renderer.d.ts.map +1 -1
  743. package/dist/site/renderer.js +40 -28
  744. package/dist/site/terrain-geometry.d.ts +1 -1
  745. package/dist/site/terrain-geometry.d.ts.map +1 -1
  746. package/dist/site/terrain-geometry.js +35 -9
  747. package/dist/site/terrain-mesh.d.ts +5 -0
  748. package/dist/site/terrain-mesh.d.ts.map +1 -1
  749. package/dist/site/terrain-mesh.js +63 -34
  750. package/dist/skylight/definition.js +1 -1
  751. package/dist/skylight/panel.js +1 -1
  752. package/dist/skylight/parametrics.js +2 -2
  753. package/dist/slab/definition.d.ts.map +1 -1
  754. package/dist/slab/definition.js +6 -1
  755. package/dist/slab/dependency-tracker.d.ts +3 -0
  756. package/dist/slab/dependency-tracker.d.ts.map +1 -0
  757. package/dist/slab/dependency-tracker.js +104 -0
  758. package/dist/slab/floorplan-affordances.d.ts +8 -8
  759. package/dist/slab/geometry.d.ts.map +1 -1
  760. package/dist/slab/geometry.js +16 -2
  761. package/dist/slab/panel.d.ts.map +1 -1
  762. package/dist/slab/panel.js +1 -1
  763. package/dist/slab/parametrics.js +1 -1
  764. package/dist/slab/system.d.ts.map +1 -1
  765. package/dist/slab/system.js +8 -64
  766. package/dist/solar-panel/definition.js +1 -1
  767. package/dist/solar-panel/panel.js +1 -1
  768. package/dist/solar-panel/parametrics.js +2 -2
  769. package/dist/stair/panel.d.ts.map +1 -1
  770. package/dist/stair/panel.js +18 -13
  771. package/dist/stair/stair-type.d.ts +18 -0
  772. package/dist/stair/stair-type.d.ts.map +1 -0
  773. package/dist/stair/stair-type.js +25 -0
  774. package/dist/stair-segment/panel.d.ts.map +1 -1
  775. package/dist/stair-segment/panel.js +44 -5
  776. package/dist/turbine-vent/definition.d.ts.map +1 -1
  777. package/dist/turbine-vent/definition.js +8 -5
  778. package/dist/turbine-vent/geometry.d.ts.map +1 -1
  779. package/dist/turbine-vent/geometry.js +48 -18
  780. package/dist/turbine-vent/paint.d.ts +4 -0
  781. package/dist/turbine-vent/paint.d.ts.map +1 -0
  782. package/dist/turbine-vent/paint.js +35 -0
  783. package/dist/turbine-vent/panel.js +1 -1
  784. package/dist/turbine-vent/parametrics.js +2 -2
  785. package/dist/turbine-vent/renderer.d.ts.map +1 -1
  786. package/dist/turbine-vent/renderer.js +31 -9
  787. package/dist/wall/curve-eligibility.d.ts +3 -0
  788. package/dist/wall/curve-eligibility.d.ts.map +1 -0
  789. package/dist/wall/curve-eligibility.js +10 -0
  790. package/dist/wall/curve-tool.d.ts +3 -4
  791. package/dist/wall/curve-tool.d.ts.map +1 -1
  792. package/dist/wall/curve-tool.js +24 -23
  793. package/dist/wall/definition.d.ts +1 -1
  794. package/dist/wall/definition.d.ts.map +1 -1
  795. package/dist/wall/definition.js +36 -13
  796. package/dist/wall/floorplan-affordances.d.ts +1 -0
  797. package/dist/wall/floorplan-affordances.d.ts.map +1 -1
  798. package/dist/wall/floorplan-affordances.js +46 -7
  799. package/dist/wall/floorplan-move.d.ts +3 -4
  800. package/dist/wall/floorplan-move.d.ts.map +1 -1
  801. package/dist/wall/floorplan-move.js +122 -9
  802. package/dist/wall/floorplan.d.ts.map +1 -1
  803. package/dist/wall/floorplan.js +19 -23
  804. package/dist/wall/move-shared.d.ts.map +1 -1
  805. package/dist/wall/move-shared.js +10 -7
  806. package/dist/wall/paint.d.ts.map +1 -1
  807. package/dist/wall/paint.js +2 -0
  808. package/dist/wall/panel.d.ts.map +1 -1
  809. package/dist/wall/panel.js +62 -27
  810. package/dist/wall/parametrics.js +2 -2
  811. package/dist/wall/pointer-transparency.d.ts +128 -0
  812. package/dist/wall/pointer-transparency.d.ts.map +1 -0
  813. package/dist/wall/pointer-transparency.js +147 -0
  814. package/dist/wall/renderer.d.ts.map +1 -1
  815. package/dist/wall/renderer.js +65 -8
  816. package/dist/wall/selection-hit-owner.d.ts +53 -0
  817. package/dist/wall/selection-hit-owner.d.ts.map +1 -0
  818. package/dist/wall/selection-hit-owner.js +79 -0
  819. package/dist/wall/system.d.ts +5 -0
  820. package/dist/wall/system.d.ts.map +1 -1
  821. package/dist/wall/system.js +71 -26
  822. package/dist/wall/tool.d.ts.map +1 -1
  823. package/dist/wall/tool.js +29 -27
  824. package/dist/wall/treatment-level-data.d.ts +6 -1
  825. package/dist/wall/treatment-level-data.d.ts.map +1 -1
  826. package/dist/wall/treatment-level-data.js +82 -5
  827. package/dist/wall/treatments.d.ts +1 -0
  828. package/dist/wall/treatments.d.ts.map +1 -1
  829. package/dist/wall/treatments.js +5 -0
  830. package/dist/wall/wall-batch-system.d.ts +55 -0
  831. package/dist/wall/wall-batch-system.d.ts.map +1 -0
  832. package/dist/wall/wall-batch-system.js +486 -0
  833. package/dist/wall/wall-batch.d.ts +66 -0
  834. package/dist/wall/wall-batch.d.ts.map +1 -0
  835. package/dist/wall/wall-batch.js +169 -0
  836. package/dist/window/definition.d.ts +2 -1
  837. package/dist/window/definition.d.ts.map +1 -1
  838. package/dist/window/definition.js +51 -24
  839. package/dist/window/floorplan-move.d.ts.map +1 -1
  840. package/dist/window/floorplan-move.js +1 -1
  841. package/dist/window/move-tool.d.ts +7 -5
  842. package/dist/window/move-tool.d.ts.map +1 -1
  843. package/dist/window/move-tool.js +344 -58
  844. package/dist/window/panel.d.ts.map +1 -1
  845. package/dist/window/panel.js +2 -0
  846. package/dist/window/parametrics.js +2 -2
  847. package/dist/window/renderer.d.ts.map +1 -1
  848. package/dist/window/renderer.js +5 -7
  849. package/dist/window/tool.d.ts.map +1 -1
  850. package/dist/window/tool.js +227 -13
  851. package/dist/zone/floorplan-affordances.d.ts +12 -12
  852. package/dist/zone/quantities-panel.d.ts.map +1 -1
  853. package/dist/zone/quantities-panel.js +4 -3
  854. package/package.json +11 -9
  855. package/dist/dormer/panel-window-section.d.ts +0 -14
  856. package/dist/dormer/panel-window-section.d.ts.map +0 -1
  857. package/dist/dormer/panel-window-section.js +0 -59
  858. package/dist/dormer/window-assembly.d.ts +0 -22
  859. package/dist/dormer/window-assembly.d.ts.map +0 -1
  860. package/dist/dormer/window-assembly.js +0 -111
  861. package/dist/dormer/window-frame.d.ts +0 -24
  862. package/dist/dormer/window-frame.d.ts.map +0 -1
  863. package/dist/dormer/window-frame.js +0 -100
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { CabinetModuleNode, CabinetNode, collectAlignmentAnchors, createSceneApi, emitter, getFloorPlacedFootprints, getWallThickness, isCurvedWall, movingFootprintAnchors, nodeRegistry, resolveAlignment, resolveSupportSlabPatch, spatialGridManager, useScene, } from '@pascal-app/core';
4
- import { clearPlacementSurface, getFloorStackPreviewPosition, getSideFromNormal, isAlignmentGuideActive, isGridSnapActive, isMagneticSnapActive, isValidWallSideFace, markToolCancelConsumed, movementSfxStepKey, PlacementBox, publishPlacementSurface, triggerSFX, useAlignmentGuides, useEditor, useFacingPose, usePlacementPreview, } from '@pascal-app/editor';
4
+ import { clearPlacementSurface, EDITOR_LAYER, getFloorStackPreviewPosition, getSideFromNormal, isAlignmentGuideActive, isGridSnapActive, isMagneticSnapActive, isValidWallSideFace, markToolCancelConsumed, movementSfxStepKey, PlacementBox, PlacementDimensionGuides, parseMeasurement, publishPlacementSurface, triggerSFX, useAlignmentGuides, useEditor, useFacingPose, usePlacementPreview, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Html } from '@react-three/drei';
7
7
  import { useFrame } from '@react-three/fiber';
@@ -9,21 +9,93 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
9
9
  import { Mesh, Quaternion, Vector3 } from 'three';
10
10
  import { FLOOR_PLACEMENT_ALIGNMENT_THRESHOLD_M, getLevelLocalSnappedPosition, stopPlacementCommitPropagation, subscribeFloorPlacementClicks, subscribeFloorPlacementDoubleClicks, } from '../shared/floor-placement';
11
11
  import { LevelOffsetGroup } from '../shared/level-offset-group';
12
- import { findClosestWallInPlan } from '../shared/wall-attach-target';
12
+ import { findWallOpeningConflicts } from '../shared/wall-opening-clearance';
13
13
  import { cabinetStretchExitSide, chooseCabinetContinuousAnchor, createCabinetContinuousContinuation, isCabinetContinuousFollowUpClick, isForcePlacementEvent, planCabinetContinuousStretch, resolveCabinetContinuousValidity, } from './continuous-placement';
14
14
  import { bumpCabinetRunsNear, cabinetDefinition, cabinetModuleDefinition, cabinetRunFootprint, } from './definition';
15
15
  import { buildCabinetGeometry } from './geometry';
16
- import { resolveCabinetGridPosition } from './placement-snap';
16
+ import { applyCabinetModuleInsertion, cabinetModuleForRunInsertion } from './insertion';
17
+ import { buildCabinetPlacementSizeDimensions, resolveCabinetPlacementDimensionPosition, resolveCabinetPlacementDimensions, } from './placement-dimensions';
18
+ import { resolveCabinetGridPosition, resolveCabinetGridPositionInFrame, resolveCabinetLevelPlanFrame, } from './placement-snap';
17
19
  import useCabinetPlacementStatus from './placement-status';
18
20
  import useCabinetPlacementType from './placement-type';
19
21
  import { cabinetPresetById } from './presets';
20
- import { runLocalToPlan } from './run-layout';
21
- import { addCabinetModuleSide, addCornerRun, previewCornerAdditionLayout } from './run-ops';
22
- import { collectCabinetWallSnapNeighbors, resolveCabinetWallFaceOffset, resolveCabinetWallSnapPlacement, } from './wall-snap';
22
+ import { moduleMaxX, planRunModuleInsertion, planToRunLocal, runLocalToPlan, runWallConstraints, sortRunModules, } from './run-layout';
23
+ import { addCabinetModuleSide, addCornerRun, cabinetModulesForRun, cornerPinnedEndsForRun, previewCornerAdditionLayout, syncCornerRunsFromRunSources, } from './run-ops';
24
+ import { findClosestCabinetWallInPlan, resolveCabinetWallSnapPlacementInScene, } from './wall-snap';
23
25
  const PREVIEW_OPACITY = 0.55;
24
26
  const ROTATE_STEP_RAD = Math.PI / 4;
25
27
  const DEFAULT_PLACEMENT_PRESET = cabinetPresetById('base-door');
26
28
  const ISLAND_SEATING_OVERHANG = 0.3;
29
+ function angleDelta(a, b) {
30
+ return Math.atan2(Math.sin(a - b), Math.cos(a - b));
31
+ }
32
+ function resolveCabinetRunInsertion({ hit, insertionId, nodes, placement, parentLevelId, width, }) {
33
+ if (isCurvedWall(hit.wall))
34
+ return null;
35
+ const candidates = Object.values(nodes).filter((node) => node?.type === 'cabinet' && node.parentId === parentLevelId && node.rotation != null);
36
+ let best;
37
+ for (const run of candidates) {
38
+ if (Math.abs(angleDelta(run.rotation, placement.yaw)) > 0.08)
39
+ continue;
40
+ const modules = cabinetModulesForRun(run, nodes);
41
+ if (modules.length < 2)
42
+ continue;
43
+ const local = planToRunLocal(run, placement.position[0], 0, placement.position[2]);
44
+ const sorted = sortRunModules(modules);
45
+ const insertionIndex = sorted.findIndex((module) => moduleMaxX(module) > local[0] + 1e-4);
46
+ if (insertionIndex <= 0 || insertionIndex >= sorted.length)
47
+ continue;
48
+ const left = sorted[insertionIndex - 1];
49
+ const right = sorted[insertionIndex];
50
+ if (local[0] < moduleMaxX(left) - 0.15 ||
51
+ local[0] > right.position[0] - right.width / 2 + 0.15) {
52
+ continue;
53
+ }
54
+ const distance = Math.abs(local[2] - (left.position[2] + right.position[2]) / 2);
55
+ if (!best || distance < best.distance)
56
+ best = { distance, run, modules, localX: local[0] };
57
+ }
58
+ if (!best)
59
+ return null;
60
+ const { run, modules, localX } = best;
61
+ const sorted = sortRunModules(modules);
62
+ const insertionModule = sorted.find((module) => moduleMaxX(module) > localX + 1e-4);
63
+ const insertionY = insertionModule?.position[1] ?? sorted[0].position[1];
64
+ const insertionZ = insertionModule?.position[2] ?? sorted[0].position[2];
65
+ const preserveEnds = cornerPinnedEndsForRun(modules);
66
+ const result = planRunModuleInsertion({
67
+ modules,
68
+ insertion: {
69
+ id: insertionId,
70
+ position: [localX, insertionY, insertionZ],
71
+ width,
72
+ },
73
+ wallConstraints: runWallConstraints(run, modules, nodes),
74
+ fillerIds: new Set(modules.filter((module) => module.moduleKind === 'corner-filler').map((module) => module.id)),
75
+ preserveEnds,
76
+ anchorInsertionSide: preserveEnds.right ? 'right' : 'left',
77
+ });
78
+ if (!result.ok)
79
+ return { kind: 'blocked', reason: 'no-space', runId: run.id };
80
+ return {
81
+ kind: 'preview',
82
+ runId: run.id,
83
+ plan: {
84
+ runId: run.id,
85
+ runPosition: [...run.position],
86
+ runYaw: run.rotation,
87
+ modules: result.modules.map((module) => ({
88
+ id: module.id,
89
+ position: [...module.position],
90
+ width: module.width,
91
+ })),
92
+ inserted: {
93
+ position: [...result.inserted.position],
94
+ width: result.inserted.width,
95
+ },
96
+ },
97
+ };
98
+ }
27
99
  function isStretchContinuation(anchor) {
28
100
  return 'straightAnchor' in anchor;
29
101
  }
@@ -122,6 +194,9 @@ function wallHitFromWallEvent(event) {
122
194
  const CabinetTool = () => {
123
195
  const activeLevelId = useViewer((s) => s.selection.levelId);
124
196
  const unit = useViewer((s) => s.unit);
197
+ const metricNotation = useViewer((s) => s.metricNotation);
198
+ const activeDimensionId = usePlacementPreview((s) => s.activeDimensionId);
199
+ const dimensionInput = usePlacementPreview((s) => s.dimensionInput);
125
200
  const [placement, setPlacement] = useState(null);
126
201
  const [draftSegments, setDraftSegments] = useState([]);
127
202
  const [yaw, setYaw] = useState(0);
@@ -146,7 +221,7 @@ const CabinetTool = () => {
146
221
  const surfaceQuatRef = useRef(new Quaternion());
147
222
  const surfaceForwardRef = useRef(new Vector3(0, 0, 1));
148
223
  const facingPointRef = useRef(new Vector3());
149
- const previewNode = useMemo(() => {
224
+ const previewNodeTemplate = useMemo(() => {
150
225
  const runDefaults = cabinetDefinition.defaults();
151
226
  return CabinetModuleNode.parse({
152
227
  ...cabinetModuleDefinition.defaults(),
@@ -160,6 +235,19 @@ const CabinetTool = () => {
160
235
  countertopBackOverhang: runDefaults.countertopBackOverhang,
161
236
  });
162
237
  }, []);
238
+ const [previewSize, setPreviewSize] = useState(() => ({
239
+ depth: previewNodeTemplate.depth,
240
+ height: previewNodeTemplate.carcassHeight,
241
+ width: previewNodeTemplate.width,
242
+ }));
243
+ const previewNode = useMemo(() => CabinetModuleNode.parse({
244
+ ...previewNodeTemplate,
245
+ carcassHeight: previewSize.height,
246
+ depth: previewSize.depth,
247
+ width: previewSize.width,
248
+ }), [previewNodeTemplate, previewSize]);
249
+ const previewNodeRef = useRef(previewNode);
250
+ previewNodeRef.current = previewNode;
163
251
  const placementDimensions = useMemo(() => {
164
252
  const defaults = cabinetDefinition.defaults();
165
253
  return [
@@ -170,6 +258,22 @@ const CabinetTool = () => {
170
258
  previewNode.depth + (islandMode ? ISLAND_SEATING_OVERHANG : 0),
171
259
  ];
172
260
  }, [previewNode, islandMode]);
261
+ const placementDimensionsRef = useRef(placementDimensions);
262
+ placementDimensionsRef.current = placementDimensions;
263
+ const placementSnapFootprint = useMemo(() => {
264
+ const sideAndFrontOverhang = previewNode.withCountertop ? previewNode.countertopOverhang : 0;
265
+ const backOverhang = islandMode ? ISLAND_SEATING_OVERHANG : 0;
266
+ return {
267
+ dimensions: [
268
+ previewNode.width + sideAndFrontOverhang * 2,
269
+ placementDimensions[1],
270
+ previewNode.depth + sideAndFrontOverhang + backOverhang,
271
+ ],
272
+ offset: [0, (sideAndFrontOverhang - backOverhang) / 2],
273
+ };
274
+ }, [islandMode, placementDimensions, previewNode]);
275
+ const placementSnapFootprintRef = useRef(placementSnapFootprint);
276
+ placementSnapFootprintRef.current = placementSnapFootprint;
173
277
  const ghost = useMemo(() => {
174
278
  const group = buildCabinetGeometry(previewNode);
175
279
  group.traverse((child) => {
@@ -182,6 +286,26 @@ const CabinetTool = () => {
182
286
  });
183
287
  return group;
184
288
  }, [previewNode]);
289
+ const insertionGhost = useMemo(() => {
290
+ const node = CabinetModuleNode.parse({
291
+ ...previewNode,
292
+ plinthHeight: 0,
293
+ showPlinth: false,
294
+ countertopThickness: 0,
295
+ withCountertop: false,
296
+ });
297
+ const group = buildCabinetGeometry(node);
298
+ group.traverse((child) => {
299
+ child.layers.set(EDITOR_LAYER);
300
+ if (child instanceof Mesh) {
301
+ child.material = child.material.clone();
302
+ child.material.transparent = true;
303
+ child.material.opacity = PREVIEW_OPACITY;
304
+ child.raycast = () => { };
305
+ }
306
+ });
307
+ return group;
308
+ }, [previewNode]);
185
309
  // The stretched span renders one ghost per module — the same Object3D can't
186
310
  // appear twice in the scene, so extra modules reuse pooled clones (geometry
187
311
  // and materials stay shared) instead of cloning on every pointer move.
@@ -194,23 +318,87 @@ const CabinetTool = () => {
194
318
  pool.push(ghost.clone());
195
319
  return pool[index - 1];
196
320
  }, [ghost]);
321
+ const insertionGhostPoolRef = useRef([]);
322
+ const insertionGhostForIndex = useCallback((index) => {
323
+ if (index === 0)
324
+ return insertionGhost;
325
+ const pool = insertionGhostPoolRef.current;
326
+ while (pool.length < index)
327
+ pool.push(insertionGhost.clone());
328
+ return pool[index - 1];
329
+ }, [insertionGhost]);
197
330
  const publishFloorplanPreview = useCallback((next, island = islandModeRef.current) => {
198
331
  const stretch = next.stretch;
332
+ const previewPosition = stretch
333
+ ? runLocalToPlan({ position: next.position, rotation: next.yaw }, [
334
+ stretch.centerLocalX,
335
+ 0,
336
+ 0,
337
+ ])
338
+ : next.position;
339
+ const livePreviewNode = previewNodeRef.current;
199
340
  const node = buildCabinetPlacementPreviewNode({
200
341
  island,
201
- position: stretch
202
- ? runLocalToPlan({ position: next.position, rotation: next.yaw }, [
203
- stretch.centerLocalX,
204
- 0,
205
- 0,
206
- ])
207
- : next.position,
208
- previewModule: previewNode,
342
+ position: previewPosition,
343
+ previewModule: livePreviewNode,
209
344
  yaw: next.yaw,
210
345
  });
346
+ let floorplanNode = stretch ? { ...node, width: stretch.length } : node;
347
+ let floorplanContextNodes = [];
348
+ if (next.insertionPreview) {
349
+ const liveRun = useScene.getState().nodes[next.insertionPreview.runId];
350
+ if (liveRun?.type === 'cabinet') {
351
+ const insertedId = livePreviewNode.id;
352
+ const previewModules = [
353
+ ...next.insertionPreview.modules.map((planned) => {
354
+ const liveModule = useScene.getState().nodes[planned.id];
355
+ return liveModule?.type === 'cabinet-module'
356
+ ? {
357
+ ...liveModule,
358
+ position: planned.position,
359
+ width: planned.width,
360
+ }
361
+ : null;
362
+ }),
363
+ CabinetModuleNode.parse({
364
+ ...cabinetModuleForRunInsertion(livePreviewNode, liveRun),
365
+ id: insertedId,
366
+ position: next.insertionPreview.inserted.position,
367
+ width: next.insertionPreview.inserted.width,
368
+ }),
369
+ ].filter((previewModule) => previewModule != null);
370
+ floorplanNode = CabinetNode.parse({
371
+ ...liveRun,
372
+ children: previewModules.map((previewModule) => previewModule.id),
373
+ });
374
+ floorplanContextNodes = previewModules;
375
+ }
376
+ }
377
+ const placementDimensions = activeLevelId && !island
378
+ ? resolveCabinetPlacementDimensions({
379
+ depth: livePreviewNode.depth,
380
+ levelId: activeLevelId,
381
+ nodes: useScene.getState().nodes,
382
+ position: previewPosition,
383
+ rotation: next.yaw,
384
+ wallId: next.wallId,
385
+ width: stretch?.length ?? livePreviewNode.width,
386
+ })
387
+ : [];
388
+ const sizeDimensions = !stretch && !island
389
+ ? buildCabinetPlacementSizeDimensions({
390
+ depth: livePreviewNode.depth,
391
+ height: livePreviewNode.carcassHeight,
392
+ position: previewPosition,
393
+ rotation: next.yaw,
394
+ width: livePreviewNode.width,
395
+ })
396
+ : [];
211
397
  // A stretched span can exceed the schema's width cap — override post-parse.
212
- usePlacementPreview.getState().set(stretch ? { ...node, width: stretch.length } : node);
213
- }, [previewNode]);
398
+ usePlacementPreview
399
+ .getState()
400
+ .set(floorplanNode, null, [...placementDimensions, ...sizeDimensions], floorplanContextNodes);
401
+ }, [activeLevelId]);
214
402
  useFrame(() => {
215
403
  const ghostGroup = activeGhostRef.current;
216
404
  const current = placementRef.current;
@@ -259,7 +447,7 @@ const CabinetTool = () => {
259
447
  previousWasWallSnapRef.current = false;
260
448
  previousTickFrameRef.current = -1;
261
449
  draftAnchorRef.current = null;
262
- let alignmentCandidates = collectAlignmentAnchors(useScene.getState().nodes, previewNode.id, activeLevelId);
450
+ let alignmentCandidates = collectAlignmentAnchors(useScene.getState().nodes, previewNodeRef.current.id, activeLevelId);
263
451
  let lastWallEventTime = -1;
264
452
  let wallOwnedPointerAt = Number.NEGATIVE_INFINITY;
265
453
  const WALL_OWNS_POINTER_MS = 64;
@@ -322,9 +510,21 @@ const CabinetTool = () => {
322
510
  };
323
511
  const resolveGridPosition = (raw, bypassGrid = false) => {
324
512
  const step = !bypassGrid && isGridSnapActive() ? useEditor.getState().gridSnapStep : 0;
513
+ if (step > 0) {
514
+ const frame = resolveCabinetLevelPlanFrame(activeLevelId, useScene.getState().nodes);
515
+ return resolveCabinetGridPositionInFrame({
516
+ raw,
517
+ dimensions: placementSnapFootprintRef.current.dimensions,
518
+ footprintOffset: placementSnapFootprintRef.current.offset,
519
+ yaw: yawRef.current,
520
+ step,
521
+ frame,
522
+ });
523
+ }
325
524
  return resolveCabinetGridPosition({
326
525
  raw,
327
- dimensions: placementDimensions,
526
+ dimensions: placementSnapFootprintRef.current.dimensions,
527
+ footprintOffset: placementSnapFootprintRef.current.offset,
328
528
  yaw: yawRef.current,
329
529
  step,
330
530
  });
@@ -337,7 +537,7 @@ const CabinetTool = () => {
337
537
  const alignmentNode = buildCabinetPlacementPreviewNode({
338
538
  island: islandModeRef.current,
339
539
  position,
340
- previewModule: previewNode,
540
+ previewModule: previewNodeRef.current,
341
541
  yaw,
342
542
  });
343
543
  const moving = movingFootprintAnchors({
@@ -359,60 +559,83 @@ const CabinetTool = () => {
359
559
  return [position[0] + result.snap.dx, position[1], position[2] + result.snap.dz];
360
560
  };
361
561
  const withPlacementValidity = (next, bypassCollision) => {
362
- if (bypassCollision)
363
- return { ...next, conflictIds: [], valid: true };
364
- const floorPlaced = nodeRegistry.get(previewNode.type)?.capabilities?.floorPlaced;
562
+ if (bypassCollision) {
563
+ return { ...next, conflictIds: [], valid: !next.insertionFailure };
564
+ }
565
+ const livePreviewNode = previewNodeRef.current;
566
+ const livePlacementDimensions = placementDimensionsRef.current;
567
+ const floorPlaced = nodeRegistry.get(livePreviewNode.type)?.capabilities?.floorPlaced;
365
568
  const effectiveNode = {
366
- ...previewNode,
569
+ ...livePreviewNode,
367
570
  position: next.position,
368
571
  rotation: next.yaw,
369
572
  };
573
+ const ignoreIds = next.insertionPreview ? [next.insertionPreview.runId] : undefined;
370
574
  const footprints = floorPlaced
371
575
  ? getFloorPlacedFootprints(floorPlaced, effectiveNode, {
372
576
  nodes: useScene.getState().nodes,
373
577
  }).filter((footprint) => footprint.position != null)
374
578
  : [];
375
579
  const result = footprints.length > 0
376
- ? spatialGridManager.canPlaceOnFloorFootprints(activeLevelId, footprints)
377
- : spatialGridManager.canPlaceOnFloor(activeLevelId, next.position, placementDimensions, [
378
- 0,
379
- next.yaw,
380
- 0,
381
- ]);
382
- return { ...next, conflictIds: result.conflictIds, valid: result.valid };
580
+ ? spatialGridManager.canPlaceOnFloorFootprints(activeLevelId, footprints, ignoreIds)
581
+ : spatialGridManager.canPlaceOnFloor(activeLevelId, next.position, livePlacementDimensions, [0, next.yaw, 0], ignoreIds);
582
+ const wall = next.wallId ? useScene.getState().nodes[next.wallId] : undefined;
583
+ const openingConflictIds = wall?.type === 'wall' && next.wallLocalX != null
584
+ ? findWallOpeningConflicts({
585
+ bottom: 0,
586
+ height: livePlacementDimensions[1],
587
+ localX: next.wallLocalX,
588
+ nodes: useScene.getState().nodes,
589
+ wall,
590
+ width: livePreviewNode.width,
591
+ })
592
+ : [];
593
+ const conflictIds = [...new Set([...result.conflictIds, ...openingConflictIds])];
594
+ return {
595
+ ...next,
596
+ conflictIds,
597
+ valid: !next.insertionFailure && result.valid && openingConflictIds.length === 0,
598
+ };
383
599
  };
384
600
  const resolveWallHitPlacement = (hit) => {
385
601
  if (!isWallSnapEligible())
386
602
  return null;
387
603
  const nodes = useScene.getState().nodes;
388
- const neighbors = collectCabinetWallSnapNeighbors({
604
+ const wallPlacement = resolveCabinetWallSnapPlacementInScene({
605
+ depth: previewNodeRef.current.depth,
606
+ gridStep: isGridSnapActive() ? useEditor.getState().gridSnapStep : 0,
389
607
  hit,
390
608
  nodes,
391
609
  parentLevelId: activeLevelId,
392
- width: previewNode.width,
610
+ width: previewNodeRef.current.width,
393
611
  });
394
- const faceOffset = resolveCabinetWallFaceOffset({
612
+ if (!wallPlacement)
613
+ return null;
614
+ const wallSurfaceNormal = [Math.sin(wallPlacement.yaw), 0, Math.cos(wallPlacement.yaw)];
615
+ const insertion = resolveCabinetRunInsertion({
395
616
  hit,
617
+ insertionId: previewNodeRef.current.id,
396
618
  nodes,
619
+ placement: wallPlacement,
397
620
  parentLevelId: activeLevelId,
621
+ width: previewNodeRef.current.width,
398
622
  });
399
- const wallPlacement = resolveCabinetWallSnapPlacement({
400
- depth: previewNode.depth,
401
- faceOffset,
402
- gridStep: isGridSnapActive() ? useEditor.getState().gridSnapStep : 0,
403
- hit,
404
- neighbors,
405
- width: previewNode.width,
406
- });
407
- if (!wallPlacement)
408
- return null;
409
- const wallSurfaceNormal = [Math.sin(wallPlacement.yaw), 0, Math.cos(wallPlacement.yaw)];
623
+ const insertionPreview = insertion?.kind === 'preview' ? insertion.plan : undefined;
624
+ const insertionFailure = insertion?.kind === 'blocked'
625
+ ? { runId: insertion.runId, reason: insertion.reason }
626
+ : undefined;
627
+ const insertionPosition = insertionPreview
628
+ ? runLocalToPlan({ position: insertionPreview.runPosition, rotation: insertionPreview.runYaw }, insertionPreview.inserted.position)
629
+ : wallPlacement.position;
410
630
  return {
411
631
  conflictIds: [],
412
632
  guide: wallPlacement.guide,
413
- position: wallPlacement.position,
633
+ ...(insertionFailure ? { insertionFailure } : {}),
634
+ ...(insertionPreview ? { insertionPreview } : {}),
635
+ position: insertionPosition,
414
636
  snapReason: wallPlacement.snapReason,
415
637
  valid: true,
638
+ wallId: hit.wall.id,
416
639
  wallLocalX: wallPlacement.localX,
417
640
  wallSurfaceNormal,
418
641
  yaw: wallPlacement.yaw,
@@ -423,7 +646,12 @@ const CabinetTool = () => {
423
646
  if (!isWallSnapEligible())
424
647
  return null;
425
648
  const nodes = useScene.getState().nodes;
426
- const hit = findClosestWallInPlan([raw[0], raw[2]], nodes, activeLevelId);
649
+ const hit = findClosestCabinetWallInPlan({
650
+ excludeIds: [],
651
+ nodes,
652
+ parentLevelId: activeLevelId,
653
+ planPoint: [raw[0], raw[2]],
654
+ });
427
655
  if (!hit)
428
656
  return null;
429
657
  return resolveWallHitPlacement(hit);
@@ -454,6 +682,44 @@ const CabinetTool = () => {
454
682
  snappedToWall: false,
455
683
  }, forcePlacement);
456
684
  };
685
+ const resolveStretchedValidity = (anchor, stretch, forcePlace) => {
686
+ const spanCenter = runLocalToPlan({ position: anchor.position, rotation: anchor.yaw }, [
687
+ stretch.centerLocalX,
688
+ 0,
689
+ 0,
690
+ ]);
691
+ const ignoreIds = chainRootRunRef.current
692
+ ? [chainRootRunRef.current.id]
693
+ : undefined;
694
+ return resolveCabinetContinuousValidity((() => {
695
+ const floorResult = spatialGridManager.canPlaceOnFloor(activeLevelId, spanCenter, [stretch.length, placementDimensionsRef.current[1], placementDimensionsRef.current[2]], [0, anchor.yaw, 0], ignoreIds);
696
+ const nodes = useScene.getState().nodes;
697
+ const wall = anchor.wallId ? nodes[anchor.wallId] : undefined;
698
+ const wallHit = wall?.type === 'wall' && anchor.wallLocalX != null
699
+ ? { wall, localX: anchor.wallLocalX + stretch.centerLocalX }
700
+ : findClosestCabinetWallInPlan({
701
+ excludeIds: [],
702
+ nodes,
703
+ parentLevelId: activeLevelId,
704
+ planPoint: [spanCenter[0], spanCenter[2]],
705
+ yaw: anchor.yaw,
706
+ });
707
+ const openingConflictIds = wallHit && (wallHit.localX ?? null) != null
708
+ ? findWallOpeningConflicts({
709
+ bottom: 0,
710
+ height: placementDimensionsRef.current[1],
711
+ localX: wallHit.localX,
712
+ nodes,
713
+ wall: wallHit.wall,
714
+ width: stretch.length,
715
+ })
716
+ : [];
717
+ return {
718
+ conflictIds: [...new Set([...floorResult.conflictIds, ...openingConflictIds])],
719
+ valid: floorResult.valid && openingConflictIds.length === 0,
720
+ };
721
+ })(), forcePlace);
722
+ };
457
723
  // While stretching, the run is pinned at the anchored first module and
458
724
  // grows toward the cursor — the far end tracks the pointer smoothly.
459
725
  const resolveStretchedPlacement = (anchor, event) => {
@@ -461,7 +727,7 @@ const CabinetTool = () => {
461
727
  const raw = resolveRawPosition(event);
462
728
  let stretch = planCabinetContinuousStretch({
463
729
  anchor,
464
- previewWidth: previewNode.width,
730
+ previewWidth: previewNodeRef.current.width,
465
731
  rawPlanPosition: raw,
466
732
  });
467
733
  if (anchor.leadingWidth != null &&
@@ -479,6 +745,8 @@ const CabinetTool = () => {
479
745
  position: anchor.position,
480
746
  yaw: anchor.yaw,
481
747
  snappedToWall: anchor.snappedToWall,
748
+ wallId: anchor.wallId,
749
+ wallLocalX: anchor.wallLocalX,
482
750
  wallSurfaceNormal: anchor.wallSurfaceNormal,
483
751
  valid: false,
484
752
  conflictIds: [],
@@ -488,19 +756,13 @@ const CabinetTool = () => {
488
756
  }
489
757
  stretch = stretchWithAdjustedConnectedWidth(stretch, preview.connectedWidth);
490
758
  }
491
- const spanCenter = runLocalToPlan({ position: anchor.position, rotation: anchor.yaw }, [
492
- stretch.centerLocalX,
493
- 0,
494
- 0,
495
- ]);
496
- const ignoreIds = chainRootRunRef.current
497
- ? [chainRootRunRef.current.id]
498
- : undefined;
499
- const result = resolveCabinetContinuousValidity(spatialGridManager.canPlaceOnFloor(activeLevelId, spanCenter, [stretch.length, placementDimensions[1], placementDimensions[2]], [0, anchor.yaw, 0], ignoreIds), isForcePlacementEvent(event));
759
+ const result = resolveStretchedValidity(anchor, stretch, isForcePlacementEvent(event));
500
760
  return {
501
761
  position: anchor.position,
502
762
  yaw: anchor.yaw,
503
763
  snappedToWall: anchor.snappedToWall,
764
+ wallId: anchor.wallId,
765
+ wallLocalX: anchor.wallLocalX,
504
766
  wallSurfaceNormal: anchor.wallSurfaceNormal,
505
767
  valid: result.valid,
506
768
  conflictIds: result.conflictIds,
@@ -692,6 +954,86 @@ const CabinetTool = () => {
692
954
  }
693
955
  return { anchor: currentPlacement.stretchAnchor, stretch: currentPlacement.stretch };
694
956
  };
957
+ const commitInsertion = (next) => {
958
+ const insertionPreview = next.insertionPreview;
959
+ if (!insertionPreview)
960
+ return null;
961
+ const sceneApi = createSceneApi(useScene);
962
+ const run = sceneApi.get(insertionPreview.runId);
963
+ if (!run)
964
+ return null;
965
+ const module = cabinetModuleForRunInsertion(CabinetModuleNode.parse({
966
+ ...previewNodeRef.current,
967
+ position: insertionPreview.inserted.position,
968
+ width: insertionPreview.inserted.width,
969
+ }), run);
970
+ sceneApi.pauseHistory();
971
+ try {
972
+ const id = applyCabinetModuleInsertion({
973
+ module,
974
+ plan: insertionPreview,
975
+ run,
976
+ sceneApi,
977
+ });
978
+ if (!id)
979
+ throw new Error('Unable to apply cabinet insertion');
980
+ const liveRun = sceneApi.get(run.id);
981
+ if (!liveRun)
982
+ throw new Error('Unable to resolve inserted cabinet run');
983
+ sceneApi.update(liveRun.id, resolveSupportSlabPatch(liveRun, sceneApi.nodes()));
984
+ syncCornerRunsFromRunSources({
985
+ run: sceneApi.get(liveRun.id) ?? liveRun,
986
+ sceneApi,
987
+ });
988
+ const updatedRun = sceneApi.get(liveRun.id) ?? liveRun;
989
+ bumpCabinetRunsNear(sceneApi, [cabinetRunFootprint(updatedRun, sceneApi.nodes())], new Set([updatedRun.id]));
990
+ sceneApi.resumeHistory();
991
+ return id;
992
+ }
993
+ catch {
994
+ sceneApi.restoreAll();
995
+ sceneApi.resumeHistory();
996
+ return null;
997
+ }
998
+ };
999
+ const updatePreviewSize = (field, value) => {
1000
+ const nextPreviewNode = CabinetModuleNode.parse({
1001
+ ...previewNodeRef.current,
1002
+ carcassHeight: field === 'height' ? value : previewNodeRef.current.carcassHeight,
1003
+ depth: field === 'depth' ? value : previewNodeRef.current.depth,
1004
+ width: field === 'width' ? value : previewNodeRef.current.width,
1005
+ });
1006
+ previewNodeRef.current = nextPreviewNode;
1007
+ setPreviewSize({
1008
+ depth: nextPreviewNode.depth,
1009
+ height: nextPreviewNode.carcassHeight,
1010
+ width: nextPreviewNode.width,
1011
+ });
1012
+ const nextPlacementDimensions = [
1013
+ nextPreviewNode.width,
1014
+ (nextPreviewNode.showPlinth ? nextPreviewNode.plinthHeight : 0) +
1015
+ nextPreviewNode.carcassHeight +
1016
+ (nextPreviewNode.withCountertop ? nextPreviewNode.countertopThickness : 0),
1017
+ nextPreviewNode.depth + (islandModeRef.current ? ISLAND_SEATING_OVERHANG : 0),
1018
+ ];
1019
+ placementDimensionsRef.current = nextPlacementDimensions;
1020
+ const sideAndFrontOverhang = nextPreviewNode.withCountertop
1021
+ ? nextPreviewNode.countertopOverhang
1022
+ : 0;
1023
+ placementSnapFootprintRef.current = {
1024
+ dimensions: [
1025
+ nextPreviewNode.width + sideAndFrontOverhang * 2,
1026
+ nextPlacementDimensions[1],
1027
+ nextPreviewNode.depth +
1028
+ sideAndFrontOverhang +
1029
+ (islandModeRef.current ? ISLAND_SEATING_OVERHANG : 0),
1030
+ ],
1031
+ offset: [
1032
+ 0,
1033
+ (sideAndFrontOverhang - (islandModeRef.current ? ISLAND_SEATING_OVERHANG : 0)) / 2,
1034
+ ],
1035
+ };
1036
+ };
695
1037
  const onDoubleClick = (event) => {
696
1038
  const anchor = resolveDraftAnchor();
697
1039
  if (!anchor)
@@ -734,8 +1076,8 @@ const CabinetTool = () => {
734
1076
  chainCornerSideRef.current = cabinetStretchExitSide(segment.stretch);
735
1077
  draftAnchorRef.current = createCabinetContinuousContinuation({
736
1078
  anchor: segment.anchor,
737
- previewDepth: previewNode.depth,
738
- previewWidth: previewNode.width,
1079
+ previewDepth: previewNodeRef.current.depth,
1080
+ previewWidth: previewNodeRef.current.width,
739
1081
  stretch: segment.stretch,
740
1082
  });
741
1083
  publishPlacement(resolveActiveStretchPlacement(draftAnchorRef.current, event));
@@ -750,6 +1092,22 @@ const CabinetTool = () => {
750
1092
  stopPlacementCommitPropagation(event);
751
1093
  return;
752
1094
  }
1095
+ if (next.insertionPreview) {
1096
+ const insertedId = commitInsertion(next);
1097
+ if (!insertedId) {
1098
+ stopPlacementCommitPropagation(event);
1099
+ return;
1100
+ }
1101
+ useViewer.getState().setSelection({ selectedIds: [insertedId] });
1102
+ useEditor.getState().setMode('select');
1103
+ triggerSFX('sfx:item-place');
1104
+ useAlignmentGuides.getState().clear();
1105
+ usePlacementPreview.getState().clear();
1106
+ clearPlacementSurface();
1107
+ useFacingPose.getState().clear();
1108
+ stopPlacementCommitPropagation(event);
1109
+ return;
1110
+ }
753
1111
  if (useEditor.getState().getContinuation('cabinet') === 'continuous') {
754
1112
  draftSegmentsRef.current = [];
755
1113
  setDraftSegments([]);
@@ -761,6 +1119,8 @@ const CabinetTool = () => {
761
1119
  position: next.position,
762
1120
  yaw: next.yaw,
763
1121
  snappedToWall: next.snappedToWall,
1122
+ wallId: next.wallId,
1123
+ wallLocalX: next.wallLocalX,
764
1124
  wallSurfaceNormal: next.wallSurfaceNormal,
765
1125
  };
766
1126
  publishPlacement(resolveStretchedPlacement(draftAnchorRef.current, event));
@@ -769,7 +1129,7 @@ const CabinetTool = () => {
769
1129
  return;
770
1130
  }
771
1131
  const { cabinet, buildModule } = buildRunNodes(next.position, next.yaw);
772
- const module = buildModule(0, previewNode.width, 0);
1132
+ const module = buildModule(0, previewNodeRef.current.width, 0);
773
1133
  const nodes = { ...useScene.getState().nodes, [cabinet.id]: cabinet, [module.id]: module };
774
1134
  const committedCabinet = CabinetNode.parse({
775
1135
  ...cabinet,
@@ -789,10 +1149,182 @@ const CabinetTool = () => {
789
1149
  useFacingPose.getState().clear();
790
1150
  stopPlacementCommitPropagation(event);
791
1151
  };
1152
+ const applyTypedDimension = () => {
1153
+ const editor = usePlacementPreview.getState();
1154
+ const current = placementRef.current;
1155
+ if (!editor.activeDimensionId || !editor.dimensionInput || !current) {
1156
+ return false;
1157
+ }
1158
+ const value = parseMeasurement(editor.dimensionInput, { kind: 'length', unitId: 'm' }, {
1159
+ bareUnit: unit === 'imperial' ? 'in' : metricNotation === 'millimeters' ? 'mm' : 'm',
1160
+ system: unit === 'imperial' ? 'imperial' : 'metric',
1161
+ });
1162
+ if (value === null)
1163
+ return false;
1164
+ if (!current.stretch) {
1165
+ const sizeField = editor.activeDimensionId === 'cabinet-width'
1166
+ ? 'width'
1167
+ : editor.activeDimensionId === 'cabinet-depth'
1168
+ ? 'depth'
1169
+ : editor.activeDimensionId === 'cabinet-height'
1170
+ ? 'height'
1171
+ : null;
1172
+ if (sizeField) {
1173
+ const limits = sizeField === 'width'
1174
+ ? { max: 3, min: 0.3 }
1175
+ : sizeField === 'depth'
1176
+ ? { max: 1.2, min: 0.3 }
1177
+ : { max: 1.4, min: 0.4 };
1178
+ const nextValue = Math.min(limits.max, Math.max(limits.min, value));
1179
+ updatePreviewSize(sizeField, nextValue);
1180
+ let position = current.position;
1181
+ let wallLocalX = current.wallLocalX;
1182
+ if (current.snappedToWall && current.wallId) {
1183
+ const resolvedWallPosition = resolveCabinetPlacementDimensionPosition({
1184
+ depth: previewNodeRef.current.depth,
1185
+ dimensionId: 'wall-clearance',
1186
+ levelId: activeLevelId,
1187
+ nodes: useScene.getState().nodes,
1188
+ position: current.position,
1189
+ rotation: current.yaw,
1190
+ wallId: current.wallId,
1191
+ value: 0,
1192
+ width: previewNodeRef.current.width,
1193
+ });
1194
+ if (resolvedWallPosition) {
1195
+ position = resolvedWallPosition.position;
1196
+ wallLocalX = resolvedWallPosition.wallLocalX;
1197
+ }
1198
+ }
1199
+ const { conflictIds: _conflictIds, valid: _valid, ...placementBase } = current;
1200
+ const next = withPlacementValidity({
1201
+ ...placementBase,
1202
+ position,
1203
+ ...(wallLocalX != null ? { wallLocalX } : {}),
1204
+ }, false);
1205
+ placementRef.current = next;
1206
+ setPlacement(next);
1207
+ publishFloorplanPreview(next);
1208
+ editor.clearDimensionEditor();
1209
+ return true;
1210
+ }
1211
+ }
1212
+ if (current.stretch && current.stretchAnchor) {
1213
+ const spanPosition = runLocalToPlan({ position: current.position, rotation: current.yaw }, [
1214
+ current.stretch.centerLocalX,
1215
+ 0,
1216
+ 0,
1217
+ ]);
1218
+ const resolved = resolveCabinetPlacementDimensionPosition({
1219
+ depth: previewNodeRef.current.depth,
1220
+ dimensionId: editor.activeDimensionId,
1221
+ levelId: activeLevelId,
1222
+ nodes: useScene.getState().nodes,
1223
+ position: spanPosition,
1224
+ rotation: current.yaw,
1225
+ wallId: current.wallId,
1226
+ value,
1227
+ width: current.stretch.length,
1228
+ });
1229
+ if (!resolved)
1230
+ return false;
1231
+ const anchorPosition = runLocalToPlan({ position: resolved.position, rotation: current.yaw }, [-current.stretch.centerLocalX, 0, 0]);
1232
+ const nextAnchor = {
1233
+ ...current.stretchAnchor,
1234
+ position: anchorPosition,
1235
+ ...(current.wallId && current.wallLocalX != null
1236
+ ? { wallLocalX: resolved.wallLocalX - current.stretch.centerLocalX }
1237
+ : {}),
1238
+ };
1239
+ const validity = resolveStretchedValidity(nextAnchor, current.stretch, false);
1240
+ const next = {
1241
+ ...current,
1242
+ conflictIds: validity.conflictIds,
1243
+ position: anchorPosition,
1244
+ stretchAnchor: nextAnchor,
1245
+ valid: validity.valid,
1246
+ ...(current.wallId && current.wallLocalX != null
1247
+ ? { wallLocalX: resolved.wallLocalX - current.stretch.centerLocalX }
1248
+ : {}),
1249
+ };
1250
+ placementRef.current = next;
1251
+ setPlacement(next);
1252
+ publishFloorplanPreview(next);
1253
+ editor.clearDimensionEditor();
1254
+ return true;
1255
+ }
1256
+ const resolved = resolveCabinetPlacementDimensionPosition({
1257
+ depth: previewNodeRef.current.depth,
1258
+ dimensionId: editor.activeDimensionId,
1259
+ levelId: activeLevelId,
1260
+ nodes: useScene.getState().nodes,
1261
+ position: current.position,
1262
+ rotation: current.yaw,
1263
+ wallId: current.wallId,
1264
+ value,
1265
+ width: previewNodeRef.current.width,
1266
+ });
1267
+ if (!resolved)
1268
+ return false;
1269
+ const { conflictIds: _conflictIds, valid: _valid, ...placementBase } = current;
1270
+ const next = withPlacementValidity({
1271
+ ...placementBase,
1272
+ position: resolved.position,
1273
+ wallLocalX: resolved.wallLocalX,
1274
+ }, false);
1275
+ placementRef.current = next;
1276
+ setPlacement(next);
1277
+ publishFloorplanPreview(next);
1278
+ editor.clearDimensionEditor();
1279
+ return true;
1280
+ };
792
1281
  const onKeyDown = (event) => {
793
1282
  const tag = event.target?.tagName;
794
1283
  if (tag === 'INPUT' || tag === 'TEXTAREA')
795
1284
  return;
1285
+ const dimensionEditor = usePlacementPreview.getState();
1286
+ if (event.key === 'Tab' && dimensionEditor.dimensions.length > 0) {
1287
+ const currentIndex = dimensionEditor.dimensions.findIndex((dimension) => dimension.id === dimensionEditor.activeDimensionId);
1288
+ const direction = event.shiftKey ? -1 : 1;
1289
+ const nextIndex = (currentIndex + direction + dimensionEditor.dimensions.length) %
1290
+ dimensionEditor.dimensions.length;
1291
+ dimensionEditor.selectDimension(dimensionEditor.dimensions[nextIndex].id);
1292
+ event.preventDefault();
1293
+ event.stopPropagation();
1294
+ return;
1295
+ }
1296
+ if (dimensionEditor.activeDimensionId && placementRef.current) {
1297
+ if (event.key === 'Enter') {
1298
+ applyTypedDimension();
1299
+ event.preventDefault();
1300
+ event.stopPropagation();
1301
+ return;
1302
+ }
1303
+ if (event.key === 'Escape') {
1304
+ dimensionEditor.clearDimensionEditor();
1305
+ event.preventDefault();
1306
+ event.stopPropagation();
1307
+ return;
1308
+ }
1309
+ if (event.key === 'Backspace' || event.key === 'Delete') {
1310
+ dimensionEditor.setDimensionInput(event.key === 'Delete'
1311
+ ? ''
1312
+ : dimensionEditor.dimensionInput.slice(0, Math.max(0, dimensionEditor.dimensionInput.length - 1)));
1313
+ event.preventDefault();
1314
+ event.stopPropagation();
1315
+ return;
1316
+ }
1317
+ if (event.key.length === 1 &&
1318
+ !event.metaKey &&
1319
+ !event.ctrlKey &&
1320
+ !event.altKey &&
1321
+ /^[0-9a-zA-Z.'"+\- ]$/.test(event.key)) {
1322
+ dimensionEditor.setDimensionInput(dimensionEditor.dimensionInput + event.key);
1323
+ event.preventDefault();
1324
+ event.stopPropagation();
1325
+ return;
1326
+ }
1327
+ }
796
1328
  if (event.key === 'i' || event.key === 'I') {
797
1329
  event.preventDefault();
798
1330
  event.stopPropagation();
@@ -815,12 +1347,7 @@ const CabinetTool = () => {
815
1347
  const raw = lastRawPositionRef.current ?? current.position;
816
1348
  const position = resolveAlignedCabinetPosition({
817
1349
  applyAlignmentSnap: isMagneticSnapActive(),
818
- position: resolveCabinetGridPosition({
819
- raw,
820
- dimensions: placementDimensions,
821
- yaw: yawRef.current,
822
- step: isGridSnapActive() ? useEditor.getState().gridSnapStep : 0,
823
- }),
1350
+ position: resolveGridPosition(raw),
824
1351
  yaw: yawRef.current,
825
1352
  });
826
1353
  const next = withPlacementValidity({ ...placementBase, position, yaw: yawRef.current }, false);
@@ -860,7 +1387,7 @@ const CabinetTool = () => {
860
1387
  useAlignmentGuides.getState().clear();
861
1388
  useCabinetPlacementStatus.getState().setBlocked(false);
862
1389
  };
863
- }, [activeLevelId, placementDimensions, previewNode, publishFloorplanPreview]);
1390
+ }, [activeLevelId, metricNotation, publishFloorplanPreview, unit]);
864
1391
  if (!activeLevelId || !placement)
865
1392
  return null;
866
1393
  const stretch = placement.stretch;
@@ -868,19 +1395,21 @@ const CabinetTool = () => {
868
1395
  .slice(0, segmentIndex)
869
1396
  .reduce((sum, previous) => sum + previous.stretch.modules.length, 0));
870
1397
  const activeStretchGhostOffset = draftSegments.reduce((sum, segment) => sum + segment.stretch.modules.length, 0);
871
- const placementLabel = stretch
872
- ? placement.valid
873
- ? `${draftSegments.length + 1} leg${draftSegments.length + 1 === 1 ? '' : 's'} · ${stretch.modules.length} module${stretch.modules.length === 1 ? '' : 's'} · Click to continue · Double-click/Esc to finish`
874
- : null
875
- : !placement.valid
876
- ? null
877
- : placement.snappedToWall
878
- ? placement.snapReason === 'cabinet-edge'
879
- ? 'Edge snap'
880
- : placement.snapReason === 'corner'
881
- ? 'Corner snap'
882
- : 'Wall snap'
883
- : null;
1398
+ const placementLabel = placement.insertionFailure
1399
+ ? 'No space in this run to insert this cabinet'
1400
+ : stretch
1401
+ ? placement.valid
1402
+ ? `${draftSegments.length + 1} leg${draftSegments.length + 1 === 1 ? '' : 's'} · ${stretch.modules.length} module${stretch.modules.length === 1 ? '' : 's'} · Click to continue · Double-click/Esc to finish`
1403
+ : null
1404
+ : !placement.valid
1405
+ ? null
1406
+ : placement.snappedToWall
1407
+ ? placement.snapReason === 'cabinet-edge'
1408
+ ? 'Edge snap'
1409
+ : placement.snapReason === 'corner'
1410
+ ? 'Corner snap'
1411
+ : 'Wall snap'
1412
+ : null;
884
1413
  const labelPosition = stretch
885
1414
  ? runLocalToPlan({ position: placement.position, rotation: placement.yaw }, [
886
1415
  stretch.centerLocalX,
@@ -901,23 +1430,19 @@ const CabinetTool = () => {
901
1430
  });
902
1431
  const placementRotationY = placement.snappedToWall || stretch ? placement.yaw : yaw;
903
1432
  const placementBoxDimensions = [
904
- stretch ? stretch.length : placementDimensions[0],
905
- placementDimensions[1],
906
- placementDimensions[2],
1433
+ stretch
1434
+ ? stretch.length + (previewNode.withCountertop ? previewNode.countertopOverhang * 2 : 0)
1435
+ : placementSnapFootprint.dimensions[0],
1436
+ placementSnapFootprint.dimensions[1],
1437
+ placementSnapFootprint.dimensions[2],
907
1438
  ];
908
- const placementBoxPlanPosition = stretch
909
- ? runLocalToPlan({ position: placement.position, rotation: placement.yaw }, [
910
- stretch.centerLocalX,
911
- 0,
912
- 0,
913
- ])
914
- : placement.position;
1439
+ const placementBoxPlanPosition = runLocalToPlan({ position: placement.position, rotation: placement.yaw }, [stretch?.centerLocalX ?? 0, 0, placementSnapFootprint.offset[1]]);
915
1440
  const placementBoxPosition = [
916
1441
  placementBoxPlanPosition[0],
917
1442
  visualPosition[1],
918
1443
  placementBoxPlanPosition[2],
919
1444
  ];
920
- return (_jsxs(LevelOffsetGroup, { children: [placement.guide && _jsx(WallSnapGuide, { blocked: !placement.valid, guide: placement.guide }), _jsx(PlacementBox, { dimensions: placementBoxDimensions, measurements: { unit }, position: placementBoxPosition, rotationY: placementRotationY, valid: placement.valid }), draftSegments.map((segment, segmentIndex) => (_jsx("group", { position: segment.anchor.position, rotation: [0, segment.anchor.yaw, 0], children: segment.stretch.modules.map((module, index) => (_jsx("group", { position: [module.x, 0, 0], scale: [module.width / previewNode.width, 1, 1], children: _jsx("primitive", { object: ghostForIndex(draftModuleOffsets[segmentIndex] + index) }) }, `${segmentIndex}-${index}`))) }, `draft-${segmentIndex}`))), _jsx("group", { ref: activeGhostRef, position: visualPosition, rotation: [0, placementRotationY, 0], children: stretch ? (stretch.modules.map((module, index) => (_jsx("group", { position: [module.x, 0, 0], scale: [module.width / previewNode.width, 1, 1], children: _jsx("primitive", { object: ghostForIndex(activeStretchGhostOffset + index) }) }, index)))) : (_jsx("primitive", { object: ghost })) }), placementLabel ? (_jsx(Html, { center: true, position: [
1445
+ return (_jsxs(LevelOffsetGroup, { children: [placement.guide && _jsx(WallSnapGuide, { blocked: !placement.valid, guide: placement.guide }), _jsx(PlacementBox, { activeDimensionId: stretch ? null : activeDimensionId, dimensions: placementBoxDimensions, dimensionInput: dimensionInput, measurements: { unit, metricNotation }, measurementValues: stretch ? undefined : [previewNode.width, previewNode.carcassHeight, previewNode.depth], onDimensionSelect: stretch ? undefined : (id) => usePlacementPreview.getState().selectDimension(id), position: placementBoxPosition, rotationY: placementRotationY, valid: placement.valid }), _jsx(PlacementDimensionGuides, {}), draftSegments.map((segment, segmentIndex) => (_jsx("group", { position: segment.anchor.position, rotation: [0, segment.anchor.yaw, 0], children: segment.stretch.modules.map((module, index) => (_jsx("group", { position: [module.x, 0, 0], scale: [module.width / previewNode.width, 1, 1], children: _jsx("primitive", { object: ghostForIndex(draftModuleOffsets[segmentIndex] + index) }) }, `${segmentIndex}-${index}`))) }, `draft-${segmentIndex}`))), _jsx("group", { ref: activeGhostRef, position: visualPosition, rotation: [0, placementRotationY, 0], children: placement.insertionPreview ? (_jsx("primitive", { object: insertionGhost })) : stretch ? (stretch.modules.map((module, index) => (_jsx("group", { position: [module.x, 0, 0], scale: [module.width / previewNode.width, 1, 1], children: _jsx("primitive", { object: ghostForIndex(activeStretchGhostOffset + index) }) }, index)))) : (_jsx("primitive", { object: ghost })) }), placement.insertionPreview ? (_jsx("group", { position: placement.insertionPreview.runPosition, rotation: [0, placement.insertionPreview.runYaw, 0], children: placement.insertionPreview.modules.map((module, index) => (_jsx("group", { position: module.position, scale: [module.width / previewNode.width, 1, 1], children: _jsx("primitive", { object: insertionGhostForIndex(index + 1) }) }, module.id))) })) : null, placementLabel ? (_jsx(Html, { center: true, position: [
921
1446
  labelPosition[0],
922
1447
  previewNode.plinthHeight + previewNode.carcassHeight + 0.35,
923
1448
  labelPosition[2],