@pascal-app/nodes 1.0.5 → 1.0.7

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 (566) hide show
  1. package/README.md +1 -0
  2. package/dist/beam/actions/move-endpoint.d.ts +24 -0
  3. package/dist/beam/actions/move-endpoint.d.ts.map +1 -0
  4. package/dist/beam/actions/move-endpoint.js +54 -0
  5. package/dist/beam/definition.d.ts +14 -0
  6. package/dist/beam/definition.d.ts.map +1 -0
  7. package/dist/beam/definition.js +173 -0
  8. package/dist/beam/draft-settings.d.ts +17 -0
  9. package/dist/beam/draft-settings.d.ts.map +1 -0
  10. package/dist/beam/draft-settings.js +81 -0
  11. package/dist/beam/drafting.d.ts +35 -0
  12. package/dist/beam/drafting.d.ts.map +1 -0
  13. package/dist/beam/drafting.js +103 -0
  14. package/dist/beam/floorplan-affordances.d.ts +8 -0
  15. package/dist/beam/floorplan-affordances.d.ts.map +1 -0
  16. package/dist/beam/floorplan-affordances.js +40 -0
  17. package/dist/beam/floorplan-move.d.ts +11 -0
  18. package/dist/beam/floorplan-move.d.ts.map +1 -0
  19. package/dist/beam/floorplan-move.js +54 -0
  20. package/dist/beam/floorplan.d.ts +11 -0
  21. package/dist/beam/floorplan.d.ts.map +1 -0
  22. package/dist/beam/floorplan.js +91 -0
  23. package/dist/beam/geometry.d.ts +19 -0
  24. package/dist/beam/geometry.d.ts.map +1 -0
  25. package/dist/beam/geometry.js +63 -0
  26. package/dist/beam/index.d.ts +3 -0
  27. package/dist/beam/index.d.ts.map +1 -0
  28. package/dist/beam/index.js +2 -0
  29. package/dist/beam/move-endpoint-tool.d.ts +21 -0
  30. package/dist/beam/move-endpoint-tool.d.ts.map +1 -0
  31. package/dist/beam/move-endpoint-tool.js +49 -0
  32. package/dist/beam/move-tool.d.ts +12 -0
  33. package/dist/beam/move-tool.d.ts.map +1 -0
  34. package/dist/beam/move-tool.js +114 -0
  35. package/dist/beam/panel-model.d.ts +28 -0
  36. package/dist/beam/panel-model.d.ts.map +1 -0
  37. package/dist/beam/panel-model.js +123 -0
  38. package/dist/beam/panel.d.ts +13 -0
  39. package/dist/beam/panel.d.ts.map +1 -0
  40. package/dist/beam/panel.js +107 -0
  41. package/dist/beam/parametrics.d.ts +3 -0
  42. package/dist/beam/parametrics.d.ts.map +1 -0
  43. package/dist/beam/parametrics.js +4 -0
  44. package/dist/beam/renderer.d.ts +13 -0
  45. package/dist/beam/renderer.d.ts.map +1 -0
  46. package/dist/beam/renderer.js +36 -0
  47. package/dist/beam/schema.d.ts +2 -0
  48. package/dist/beam/schema.d.ts.map +1 -0
  49. package/dist/beam/schema.js +1 -0
  50. package/dist/beam/tool.d.ts +13 -0
  51. package/dist/beam/tool.d.ts.map +1 -0
  52. package/dist/beam/tool.js +152 -0
  53. package/dist/box-vent/panel.d.ts.map +1 -1
  54. package/dist/box-vent/panel.js +8 -7
  55. package/dist/cabinet/batchable.d.ts +10 -0
  56. package/dist/cabinet/batchable.d.ts.map +1 -0
  57. package/dist/cabinet/batchable.js +12 -0
  58. package/dist/cabinet/compartment-card.d.ts.map +1 -1
  59. package/dist/cabinet/compartment-card.js +142 -46
  60. package/dist/cabinet/countertop-layout.d.ts +5 -0
  61. package/dist/cabinet/countertop-layout.d.ts.map +1 -1
  62. package/dist/cabinet/definition.d.ts.map +1 -1
  63. package/dist/cabinet/definition.js +3 -0
  64. package/dist/cabinet/dimension-input.d.ts +6 -0
  65. package/dist/cabinet/dimension-input.d.ts.map +1 -0
  66. package/dist/cabinet/dimension-input.js +8 -0
  67. package/dist/cabinet/essential-controls.d.ts.map +1 -1
  68. package/dist/cabinet/essential-controls.js +82 -17
  69. package/dist/cabinet/index.d.ts +1 -1
  70. package/dist/cabinet/index.d.ts.map +1 -1
  71. package/dist/cabinet/index.js +1 -1
  72. package/dist/cabinet/kitchen-catalog.d.ts +17 -4
  73. package/dist/cabinet/kitchen-catalog.d.ts.map +1 -1
  74. package/dist/cabinet/kitchen-catalog.js +45 -7
  75. package/dist/cabinet/kitchen-collection.d.ts.map +1 -1
  76. package/dist/cabinet/kitchen-collection.js +21 -5
  77. package/dist/cabinet/kitchen-module-actions.d.ts.map +1 -1
  78. package/dist/cabinet/kitchen-module-actions.js +107 -14
  79. package/dist/cabinet/neighbor-placement.d.ts +10 -0
  80. package/dist/cabinet/neighbor-placement.d.ts.map +1 -1
  81. package/dist/cabinet/panel.d.ts.map +1 -1
  82. package/dist/cabinet/panel.js +127 -50
  83. package/dist/cabinet/run-finishing.d.ts +5 -0
  84. package/dist/cabinet/run-finishing.d.ts.map +1 -1
  85. package/dist/cabinet/run-ops.d.ts +5 -0
  86. package/dist/cabinet/run-ops.d.ts.map +1 -1
  87. package/dist/cabinet/run-panel.d.ts.map +1 -1
  88. package/dist/cabinet/run-panel.js +203 -52
  89. package/dist/cabinet/tool.d.ts.map +1 -1
  90. package/dist/cabinet/tool.js +8 -5
  91. package/dist/ceiling/build-up-section.d.ts +7 -0
  92. package/dist/ceiling/build-up-section.d.ts.map +1 -0
  93. package/dist/ceiling/build-up-section.js +57 -0
  94. package/dist/ceiling/definition.d.ts.map +1 -1
  95. package/dist/ceiling/definition.js +3 -1
  96. package/dist/ceiling/floorplan-affordances.d.ts +112 -0
  97. package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
  98. package/dist/ceiling/materials.d.ts +5 -0
  99. package/dist/ceiling/materials.d.ts.map +1 -1
  100. package/dist/ceiling/materials.js +17 -0
  101. package/dist/ceiling/panel-model.d.ts +13 -0
  102. package/dist/ceiling/panel-model.d.ts.map +1 -0
  103. package/dist/ceiling/panel-model.js +49 -0
  104. package/dist/ceiling/panel.d.ts.map +1 -1
  105. package/dist/ceiling/panel.js +82 -18
  106. package/dist/ceiling/renderer.d.ts.map +1 -1
  107. package/dist/ceiling/renderer.js +10 -4
  108. package/dist/ceiling/tool.d.ts.map +1 -1
  109. package/dist/ceiling/tool.js +24 -4
  110. package/dist/chimney/panel.d.ts.map +1 -1
  111. package/dist/chimney/panel.js +113 -41
  112. package/dist/column/definition.d.ts.map +1 -1
  113. package/dist/column/definition.js +3 -0
  114. package/dist/column/floorplan.d.ts.map +1 -1
  115. package/dist/column/floorplan.js +17 -0
  116. package/dist/column/hosted-resize.d.ts +28 -1
  117. package/dist/column/hosted-resize.d.ts.map +1 -1
  118. package/dist/column/panel.d.ts.map +1 -1
  119. package/dist/column/panel.js +125 -37
  120. package/dist/column/post-options.d.ts +10 -0
  121. package/dist/column/post-options.d.ts.map +1 -0
  122. package/dist/column/post-options.js +71 -0
  123. package/dist/column/post-placement.d.ts +78 -0
  124. package/dist/column/post-placement.d.ts.map +1 -0
  125. package/dist/column/post-placement.js +157 -0
  126. package/dist/column/post-section.d.ts +17 -0
  127. package/dist/column/post-section.d.ts.map +1 -0
  128. package/dist/column/post-section.js +95 -0
  129. package/dist/column/post-tool.d.ts +11 -0
  130. package/dist/column/post-tool.d.ts.map +1 -0
  131. package/dist/column/post-tool.js +94 -0
  132. package/dist/column/tool.d.ts +3 -10
  133. package/dist/column/tool.d.ts.map +1 -1
  134. package/dist/column/tool.js +13 -1
  135. package/dist/cupola/panel.d.ts.map +1 -1
  136. package/dist/cupola/panel.js +14 -7
  137. package/dist/door/actions.d.ts +7 -0
  138. package/dist/door/actions.d.ts.map +1 -0
  139. package/dist/door/actions.js +32 -0
  140. package/dist/door/contextual-dimensions.d.ts.map +1 -1
  141. package/dist/door/contextual-dimensions.js +11 -1
  142. package/dist/door/definition.d.ts.map +1 -1
  143. package/dist/door/definition.js +34 -7
  144. package/dist/door/floorplan-affordances.d.ts.map +1 -1
  145. package/dist/door/floorplan-affordances.js +5 -2
  146. package/dist/door/floorplan-move.d.ts.map +1 -1
  147. package/dist/door/floorplan-move.js +28 -6
  148. package/dist/door/floorplan.d.ts +2 -0
  149. package/dist/door/floorplan.d.ts.map +1 -1
  150. package/dist/door/floorplan.js +89 -16
  151. package/dist/door/move-tool.d.ts.map +1 -1
  152. package/dist/door/move-tool.js +60 -16
  153. package/dist/door/paint.d.ts +2 -7
  154. package/dist/door/paint.d.ts.map +1 -1
  155. package/dist/door/paint.js +26 -2
  156. package/dist/door/panel.d.ts.map +1 -1
  157. package/dist/door/panel.js +242 -90
  158. package/dist/door/parametrics.js +1 -1
  159. package/dist/door/placement.d.ts.map +1 -1
  160. package/dist/door/placement.js +9 -2
  161. package/dist/door/swing.d.ts +22 -0
  162. package/dist/door/swing.d.ts.map +1 -0
  163. package/dist/door/swing.js +36 -0
  164. package/dist/door/tool.d.ts.map +1 -1
  165. package/dist/door/tool.js +76 -29
  166. package/dist/dormer/panel-actions-section.d.ts.map +1 -1
  167. package/dist/dormer/panel-actions-section.js +3 -1
  168. package/dist/dormer/panel-position-section.d.ts.map +1 -1
  169. package/dist/dormer/panel-position-section.js +4 -3
  170. package/dist/dormer/panel-windows-section.d.ts.map +1 -1
  171. package/dist/dormer/panel-windows-section.js +38 -1
  172. package/dist/dormer/panel.d.ts.map +1 -1
  173. package/dist/dormer/panel.js +24 -18
  174. package/dist/downspout/inspector-editors.d.ts.map +1 -1
  175. package/dist/downspout/inspector-editors.js +3 -2
  176. package/dist/duct-fitting/inspector-editors.d.ts.map +1 -1
  177. package/dist/duct-fitting/inspector-editors.js +6 -1
  178. package/dist/duct-fitting/tool.d.ts.map +1 -1
  179. package/dist/duct-fitting/tool.js +11 -2
  180. package/dist/duct-terminal/tool.d.ts.map +1 -1
  181. package/dist/duct-terminal/tool.js +11 -2
  182. package/dist/elevator/panel.d.ts.map +1 -1
  183. package/dist/elevator/panel.js +41 -18
  184. package/dist/eyebrow-vent/panel.d.ts.map +1 -1
  185. package/dist/eyebrow-vent/panel.js +16 -6
  186. package/dist/fence/drafting.d.ts +2 -3
  187. package/dist/fence/drafting.d.ts.map +1 -1
  188. package/dist/fence/drafting.js +2 -3
  189. package/dist/fence/inspector-editors.d.ts.map +1 -1
  190. package/dist/fence/inspector-editors.js +64 -21
  191. package/dist/fence/move-endpoint-tool.d.ts.map +1 -1
  192. package/dist/fence/move-endpoint-tool.js +11 -2
  193. package/dist/fence/system.d.ts.map +1 -1
  194. package/dist/fence/system.js +13 -0
  195. package/dist/fence-feature/actions.d.ts.map +1 -1
  196. package/dist/fence-feature/actions.js +5 -2
  197. package/dist/fence-feature/inspector.d.ts.map +1 -1
  198. package/dist/fence-feature/inspector.js +150 -34
  199. package/dist/fence-feature/move-session.d.ts +1 -1
  200. package/dist/floor-opening/floorplan.d.ts +29 -6
  201. package/dist/floor-opening/floorplan.d.ts.map +1 -1
  202. package/dist/floor-opening/floorplan.js +172 -14
  203. package/dist/gutter/downspouts-panel.d.ts.map +1 -1
  204. package/dist/gutter/downspouts-panel.js +14 -2
  205. package/dist/hvac-equipment/tool.d.ts.map +1 -1
  206. package/dist/hvac-equipment/tool.js +3 -2
  207. package/dist/i18n/definition-messages.d.ts +5 -0
  208. package/dist/i18n/definition-messages.d.ts.map +1 -0
  209. package/dist/i18n/definition-messages.js +771 -0
  210. package/dist/index.d.ts +4 -1
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +6 -1
  213. package/dist/item/authored-params.d.ts.map +1 -1
  214. package/dist/item/authored-params.js +19 -4
  215. package/dist/item/floorplan.d.ts +1 -1
  216. package/dist/item/floorplan.d.ts.map +1 -1
  217. package/dist/item/panel.d.ts.map +1 -1
  218. package/dist/item/panel.js +9 -7
  219. package/dist/liquid-line/tool.d.ts.map +1 -1
  220. package/dist/liquid-line/tool.js +10 -3
  221. package/dist/measurement/tool.d.ts +1 -1
  222. package/dist/measurement/tool.d.ts.map +1 -1
  223. package/dist/measurement/tool.js +8 -8
  224. package/dist/pipe-fitting/tool.d.ts.map +1 -1
  225. package/dist/pipe-fitting/tool.js +3 -2
  226. package/dist/pipe-trap/tool.d.ts.map +1 -1
  227. package/dist/pipe-trap/tool.js +7 -2
  228. package/dist/procedural-item/renderer.d.ts.map +1 -1
  229. package/dist/procedural-item/renderer.js +8 -1
  230. package/dist/ridge-vent/panel.d.ts.map +1 -1
  231. package/dist/ridge-vent/panel.js +22 -9
  232. package/dist/roof/barrel-panel.d.ts.map +1 -1
  233. package/dist/roof/barrel-panel.js +7 -3
  234. package/dist/roof/definition.d.ts.map +1 -1
  235. package/dist/roof/definition.js +33 -3
  236. package/dist/roof/floorplan-overrides.d.ts +22 -0
  237. package/dist/roof/floorplan-overrides.d.ts.map +1 -0
  238. package/dist/roof/floorplan-overrides.js +46 -0
  239. package/dist/roof/floorplan-tool.d.ts +9 -0
  240. package/dist/roof/floorplan-tool.d.ts.map +1 -0
  241. package/dist/roof/floorplan-tool.js +168 -0
  242. package/dist/roof/floorplan.d.ts.map +1 -1
  243. package/dist/roof/floorplan.js +131 -41
  244. package/dist/roof/glazing-controls.d.ts +2 -1
  245. package/dist/roof/glazing-controls.d.ts.map +1 -1
  246. package/dist/roof/glazing-controls.js +51 -13
  247. package/dist/roof/glazing-panel-editor.d.ts.map +1 -1
  248. package/dist/roof/glazing-panel-editor.js +40 -13
  249. package/dist/roof/glazing-panel.d.ts.map +1 -1
  250. package/dist/roof/glazing-panel.js +73 -9
  251. package/dist/roof/paint.d.ts +19 -0
  252. package/dist/roof/paint.d.ts.map +1 -0
  253. package/dist/roof/paint.js +158 -0
  254. package/dist/roof/panel.d.ts.map +1 -1
  255. package/dist/roof/panel.js +90 -22
  256. package/dist/roof/renderer.d.ts.map +1 -1
  257. package/dist/roof/renderer.js +13 -2
  258. package/dist/roof/roof-footprint-source.d.ts +17 -0
  259. package/dist/roof/roof-footprint-source.d.ts.map +1 -1
  260. package/dist/roof/roof-footprint-source.js +14 -0
  261. package/dist/roof/roof-footprint.d.ts +36 -2
  262. package/dist/roof/roof-footprint.d.ts.map +1 -1
  263. package/dist/roof/roof-footprint.js +124 -2
  264. package/dist/roof/roof-materials.d.ts.map +1 -1
  265. package/dist/roof/roof-materials.js +10 -1
  266. package/dist/roof/roof-placement-mode.d.ts +0 -2
  267. package/dist/roof/roof-placement-mode.d.ts.map +1 -1
  268. package/dist/roof/roof-placement-mode.js +8 -6
  269. package/dist/roof/roof-plan-creases.d.ts +50 -0
  270. package/dist/roof/roof-plan-creases.d.ts.map +1 -0
  271. package/dist/roof/roof-plan-creases.js +194 -0
  272. package/dist/roof/roof-ridge-mode.d.ts +20 -0
  273. package/dist/roof/roof-ridge-mode.d.ts.map +1 -0
  274. package/dist/roof/roof-ridge-mode.js +16 -0
  275. package/dist/roof/tool.d.ts +17 -4
  276. package/dist/roof/tool.d.ts.map +1 -1
  277. package/dist/roof/tool.js +211 -113
  278. package/dist/roof/wall-catch.d.ts +106 -0
  279. package/dist/roof/wall-catch.d.ts.map +1 -0
  280. package/dist/roof/wall-catch.js +267 -0
  281. package/dist/roof-segment/build-up-section.d.ts +9 -0
  282. package/dist/roof-segment/build-up-section.d.ts.map +1 -0
  283. package/dist/roof-segment/build-up-section.js +191 -0
  284. package/dist/roof-segment/definition.d.ts.map +1 -1
  285. package/dist/roof-segment/definition.js +50 -5
  286. package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
  287. package/dist/roof-segment/floorplan-affordances.js +68 -19
  288. package/dist/roof-segment/floorplan.d.ts.map +1 -1
  289. package/dist/roof-segment/floorplan.js +16 -12
  290. package/dist/roof-segment/paint.d.ts +3 -1
  291. package/dist/roof-segment/paint.d.ts.map +1 -1
  292. package/dist/roof-segment/paint.js +43 -2
  293. package/dist/roof-segment/panel-model.d.ts +23 -0
  294. package/dist/roof-segment/panel-model.d.ts.map +1 -0
  295. package/dist/roof-segment/panel-model.js +64 -0
  296. package/dist/roof-segment/panel.d.ts.map +1 -1
  297. package/dist/roof-segment/panel.js +96 -14
  298. package/dist/roof-segment/parametrics.d.ts.map +1 -1
  299. package/dist/roof-segment/parametrics.js +4 -0
  300. package/dist/roof-segment/renderer.d.ts.map +1 -1
  301. package/dist/roof-segment/renderer.js +26 -5
  302. package/dist/separator/definition.d.ts.map +1 -1
  303. package/dist/separator/definition.js +10 -12
  304. package/dist/separator/floorplan-affordances.d.ts +9 -0
  305. package/dist/separator/floorplan-affordances.d.ts.map +1 -0
  306. package/dist/separator/floorplan-affordances.js +23 -0
  307. package/dist/separator/floorplan.d.ts +9 -0
  308. package/dist/separator/floorplan.d.ts.map +1 -0
  309. package/dist/separator/floorplan.js +54 -0
  310. package/dist/separator/renderer.d.ts +4 -0
  311. package/dist/separator/renderer.d.ts.map +1 -1
  312. package/dist/separator/renderer.js +21 -6
  313. package/dist/separator/selection.d.ts +10 -0
  314. package/dist/separator/selection.d.ts.map +1 -0
  315. package/dist/separator/selection.js +35 -0
  316. package/dist/shared/build-up-controls.d.ts +88 -0
  317. package/dist/shared/build-up-controls.d.ts.map +1 -0
  318. package/dist/shared/build-up-controls.js +139 -0
  319. package/dist/shared/curtain-opening-limits.d.ts.map +1 -1
  320. package/dist/shared/curtain-opening-limits.js +44 -14
  321. package/dist/shared/item-interaction-actions.d.ts.map +1 -1
  322. package/dist/shared/item-interaction-actions.js +11 -2
  323. package/dist/shared/layer-thickness.d.ts +2 -0
  324. package/dist/shared/layer-thickness.d.ts.map +1 -0
  325. package/dist/shared/layer-thickness.js +3 -0
  326. package/dist/shared/move-roof-tool.d.ts.map +1 -1
  327. package/dist/shared/move-roof-tool.js +100 -5
  328. package/dist/shared/node-batch/batchable.d.ts +2 -0
  329. package/dist/shared/node-batch/batchable.d.ts.map +1 -1
  330. package/dist/shared/node-batch/batchable.js +4 -0
  331. package/dist/shared/node-batch/candidates.d.ts +21 -5
  332. package/dist/shared/node-batch/candidates.d.ts.map +1 -1
  333. package/dist/shared/node-batch/candidates.js +85 -50
  334. package/dist/shared/node-batch/system.d.ts.map +1 -1
  335. package/dist/shared/node-batch/system.js +24 -15
  336. package/dist/shared/opening-casing-move.d.ts +16 -0
  337. package/dist/shared/opening-casing-move.d.ts.map +1 -0
  338. package/dist/shared/opening-casing-move.js +33 -0
  339. package/dist/shared/opening-casing-section.d.ts +15 -0
  340. package/dist/shared/opening-casing-section.d.ts.map +1 -0
  341. package/dist/shared/opening-casing-section.js +38 -0
  342. package/dist/shared/opening-casing.d.ts +26 -0
  343. package/dist/shared/opening-casing.d.ts.map +1 -0
  344. package/dist/shared/opening-casing.js +80 -0
  345. package/dist/shared/opening-depth-position.d.ts +13 -0
  346. package/dist/shared/opening-depth-position.d.ts.map +1 -0
  347. package/dist/shared/opening-depth-position.js +34 -0
  348. package/dist/shared/opening-documentation.d.ts.map +1 -1
  349. package/dist/shared/opening-documentation.js +17 -8
  350. package/dist/shared/opening-guides-runtime.d.ts +2 -1
  351. package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
  352. package/dist/shared/opening-guides-runtime.js +11 -7
  353. package/dist/shared/opening-labels.d.ts +11 -0
  354. package/dist/shared/opening-labels.d.ts.map +1 -0
  355. package/dist/shared/opening-labels.js +46 -0
  356. package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
  357. package/dist/shared/opening-placement-dimensions.js +11 -9
  358. package/dist/shared/opening-plane-offset.d.ts +4 -3
  359. package/dist/shared/opening-plane-offset.d.ts.map +1 -1
  360. package/dist/shared/opening-plane-offset.js +7 -4
  361. package/dist/shared/opening-swap.d.ts +8 -0
  362. package/dist/shared/opening-swap.d.ts.map +1 -0
  363. package/dist/shared/opening-swap.js +18 -0
  364. package/dist/shared/polygon-vertex-affordance.d.ts +19 -0
  365. package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
  366. package/dist/shared/polygon-vertex-affordance.js +65 -6
  367. package/dist/shared/roof-opening-host.d.ts +2 -1
  368. package/dist/shared/roof-opening-host.d.ts.map +1 -1
  369. package/dist/shared/roof-opening-host.js +14 -5
  370. package/dist/shared/roof-wall-opening-cut.d.ts.map +1 -1
  371. package/dist/shared/roof-wall-opening-cut.js +14 -6
  372. package/dist/shared/roof-wall-opening-placement.d.ts +2 -1
  373. package/dist/shared/roof-wall-opening-placement.d.ts.map +1 -1
  374. package/dist/shared/roof-wall-opening-placement.js +6 -4
  375. package/dist/shared/run-hanger-inspector.d.ts.map +1 -1
  376. package/dist/shared/run-hanger-inspector.js +39 -5
  377. package/dist/shared/system-check-panel.d.ts.map +1 -1
  378. package/dist/shared/system-check-panel.js +94 -15
  379. package/dist/shared/wall-attach-target.d.ts.map +1 -1
  380. package/dist/shared/wall-attach-target.js +6 -3
  381. package/dist/shelf/definition.d.ts.map +1 -1
  382. package/dist/shelf/definition.js +2 -0
  383. package/dist/site/ground-hole.d.ts +3 -3
  384. package/dist/site/ground-hole.js +3 -3
  385. package/dist/site/ground-veil.d.ts +5 -12
  386. package/dist/site/ground-veil.d.ts.map +1 -1
  387. package/dist/site/ground-veil.js +9 -33
  388. package/dist/site/panel.d.ts.map +1 -1
  389. package/dist/site/panel.js +52 -12
  390. package/dist/site/renderer.d.ts.map +1 -1
  391. package/dist/site/renderer.js +52 -23
  392. package/dist/skylight/panel.d.ts.map +1 -1
  393. package/dist/skylight/panel.js +49 -19
  394. package/dist/slab/deck-geometry.d.ts +28 -0
  395. package/dist/slab/deck-geometry.d.ts.map +1 -0
  396. package/dist/slab/deck-geometry.js +320 -0
  397. package/dist/slab/definition.d.ts +2 -1
  398. package/dist/slab/definition.d.ts.map +1 -1
  399. package/dist/slab/definition.js +6 -1
  400. package/dist/slab/dependency-tracker.d.ts.map +1 -1
  401. package/dist/slab/dependency-tracker.js +3 -0
  402. package/dist/slab/floorplan-affordances.d.ts +500 -0
  403. package/dist/slab/floorplan-affordances.d.ts.map +1 -1
  404. package/dist/slab/geometry.d.ts.map +1 -1
  405. package/dist/slab/geometry.js +46 -9
  406. package/dist/slab/panel.d.ts.map +1 -1
  407. package/dist/slab/panel.js +97 -21
  408. package/dist/slab/renderer.d.ts +11 -0
  409. package/dist/slab/renderer.d.ts.map +1 -0
  410. package/dist/slab/renderer.js +19 -0
  411. package/dist/slab/system.d.ts.map +1 -1
  412. package/dist/slab/system.js +12 -1
  413. package/dist/solar-panel/panel.d.ts.map +1 -1
  414. package/dist/solar-panel/panel.js +49 -14
  415. package/dist/stair/construction-controls.d.ts +3 -1
  416. package/dist/stair/construction-controls.d.ts.map +1 -1
  417. package/dist/stair/construction-controls.js +75 -12
  418. package/dist/stair/paint.d.ts +6 -0
  419. package/dist/stair/paint.d.ts.map +1 -1
  420. package/dist/stair/panel.d.ts.map +1 -1
  421. package/dist/stair/panel.js +243 -51
  422. package/dist/stair/parametrics.d.ts.map +1 -1
  423. package/dist/stair/parametrics.js +7 -0
  424. package/dist/stair/placement-defaults.d.ts +18 -0
  425. package/dist/stair/placement-defaults.d.ts.map +1 -0
  426. package/dist/stair/placement-defaults.js +27 -0
  427. package/dist/stair/railing-controls.d.ts.map +1 -1
  428. package/dist/stair/railing-controls.js +78 -18
  429. package/dist/stair/renderer.d.ts.map +1 -1
  430. package/dist/stair/renderer.js +16 -10
  431. package/dist/stair/structure-controls.d.ts +18 -0
  432. package/dist/stair/structure-controls.d.ts.map +1 -0
  433. package/dist/stair/structure-controls.js +275 -0
  434. package/dist/stair/tool.d.ts.map +1 -1
  435. package/dist/stair/tool.js +13 -9
  436. package/dist/stair/use-stair-render-data.d.ts +41 -0
  437. package/dist/stair/use-stair-render-data.d.ts.map +1 -1
  438. package/dist/stair-segment/panel.d.ts.map +1 -1
  439. package/dist/stair-segment/panel.js +65 -18
  440. package/dist/turbine-vent/panel.d.ts.map +1 -1
  441. package/dist/turbine-vent/panel.js +14 -5
  442. package/dist/unit/unit-panel.d.ts.map +1 -1
  443. package/dist/unit/unit-panel.js +28 -12
  444. package/dist/wall/actions.d.ts +1 -1
  445. package/dist/wall/actions.d.ts.map +1 -1
  446. package/dist/wall/actions.js +17 -13
  447. package/dist/wall/construction-dimensions.d.ts +6 -0
  448. package/dist/wall/construction-dimensions.d.ts.map +1 -1
  449. package/dist/wall/construction-dimensions.js +8 -0
  450. package/dist/wall/contextual-dimensions.d.ts +6 -0
  451. package/dist/wall/contextual-dimensions.d.ts.map +1 -1
  452. package/dist/wall/contextual-dimensions.js +104 -17
  453. package/dist/wall/curtain-opening-frame.d.ts.map +1 -1
  454. package/dist/wall/curtain-opening-frame.js +6 -4
  455. package/dist/wall/curtain-wall-layout.d.ts +1 -1
  456. package/dist/wall/curtain-wall-layout.d.ts.map +1 -1
  457. package/dist/wall/curtain-wall-layout.js +6 -4
  458. package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
  459. package/dist/wall/curtain-wall-materials.js +8 -3
  460. package/dist/wall/curtain-wall-panel.d.ts.map +1 -1
  461. package/dist/wall/curtain-wall-panel.js +241 -37
  462. package/dist/wall/curve-tool.d.ts.map +1 -1
  463. package/dist/wall/curve-tool.js +2 -3
  464. package/dist/wall/definition.d.ts.map +1 -1
  465. package/dist/wall/definition.js +20 -5
  466. package/dist/wall/floorplan-affordances.d.ts.map +1 -1
  467. package/dist/wall/floorplan-affordances.js +9 -6
  468. package/dist/wall/floorplan-move.d.ts.map +1 -1
  469. package/dist/wall/floorplan-move.js +66 -16
  470. package/dist/wall/floorplan.d.ts +4 -5
  471. package/dist/wall/floorplan.d.ts.map +1 -1
  472. package/dist/wall/floorplan.js +62 -46
  473. package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
  474. package/dist/wall/move-endpoint-tool.js +1 -0
  475. package/dist/wall/move-tool.d.ts.map +1 -1
  476. package/dist/wall/move-tool.js +77 -12
  477. package/dist/wall/paint.d.ts +2 -2
  478. package/dist/wall/paint.d.ts.map +1 -1
  479. package/dist/wall/paint.js +11 -4
  480. package/dist/wall/panel-model.d.ts +17 -2
  481. package/dist/wall/panel-model.d.ts.map +1 -1
  482. package/dist/wall/panel-model.js +158 -18
  483. package/dist/wall/panel.d.ts +8 -0
  484. package/dist/wall/panel.d.ts.map +1 -1
  485. package/dist/wall/panel.js +228 -156
  486. package/dist/wall/parametrics.d.ts +1 -1
  487. package/dist/wall/parametrics.d.ts.map +1 -1
  488. package/dist/wall/parametrics.js +14 -1
  489. package/dist/wall/railing-wall-adapter.d.ts +7 -0
  490. package/dist/wall/railing-wall-adapter.d.ts.map +1 -0
  491. package/dist/wall/railing-wall-adapter.js +38 -0
  492. package/dist/wall/railing-wall-floorplan.d.ts +8 -0
  493. package/dist/wall/railing-wall-floorplan.d.ts.map +1 -0
  494. package/dist/wall/railing-wall-floorplan.js +27 -0
  495. package/dist/wall/railing-wall-geometry.d.ts +12 -0
  496. package/dist/wall/railing-wall-geometry.d.ts.map +1 -0
  497. package/dist/wall/railing-wall-geometry.js +51 -0
  498. package/dist/wall/railing-wall-guard.d.ts +81 -0
  499. package/dist/wall/railing-wall-guard.d.ts.map +1 -0
  500. package/dist/wall/railing-wall-guard.js +435 -0
  501. package/dist/wall/railing-wall-materials.d.ts +11 -0
  502. package/dist/wall/railing-wall-materials.d.ts.map +1 -0
  503. package/dist/wall/railing-wall-materials.js +31 -0
  504. package/dist/wall/railing-wall-panel-model.d.ts +30 -0
  505. package/dist/wall/railing-wall-panel-model.d.ts.map +1 -0
  506. package/dist/wall/railing-wall-panel-model.js +117 -0
  507. package/dist/wall/railing-wall-panel.d.ts +17 -0
  508. package/dist/wall/railing-wall-panel.d.ts.map +1 -0
  509. package/dist/wall/railing-wall-panel.js +42 -0
  510. package/dist/wall/rectangle-command.d.ts +79 -1
  511. package/dist/wall/rectangle-command.d.ts.map +1 -1
  512. package/dist/wall/rectangle-tool.d.ts.map +1 -1
  513. package/dist/wall/rectangle-tool.js +2 -0
  514. package/dist/wall/renderer.d.ts.map +1 -1
  515. package/dist/wall/renderer.js +3 -1
  516. package/dist/wall/skirting-floor-gaps.d.ts +8 -0
  517. package/dist/wall/skirting-floor-gaps.d.ts.map +1 -0
  518. package/dist/wall/skirting-floor-gaps.js +36 -0
  519. package/dist/wall/system.d.ts +0 -14
  520. package/dist/wall/system.d.ts.map +1 -1
  521. package/dist/wall/system.js +6 -1
  522. package/dist/wall/tool.d.ts +16 -0
  523. package/dist/wall/tool.d.ts.map +1 -1
  524. package/dist/wall/tool.js +160 -47
  525. package/dist/wall/treatments.d.ts +3 -0
  526. package/dist/wall/treatments.d.ts.map +1 -1
  527. package/dist/wall/treatments.js +30 -7
  528. package/dist/window/actions.d.ts +7 -0
  529. package/dist/window/actions.d.ts.map +1 -0
  530. package/dist/window/actions.js +29 -0
  531. package/dist/window/definition.d.ts.map +1 -1
  532. package/dist/window/definition.js +11 -2
  533. package/dist/window/floorplan-move.d.ts.map +1 -1
  534. package/dist/window/floorplan-move.js +5 -0
  535. package/dist/window/floorplan.d.ts +2 -0
  536. package/dist/window/floorplan.d.ts.map +1 -1
  537. package/dist/window/floorplan.js +58 -1
  538. package/dist/window/mechanism.d.ts.map +1 -1
  539. package/dist/window/mechanism.js +21 -1
  540. package/dist/window/move-tool.d.ts.map +1 -1
  541. package/dist/window/move-tool.js +10 -3
  542. package/dist/window/paint.d.ts +2 -7
  543. package/dist/window/paint.d.ts.map +1 -1
  544. package/dist/window/paint.js +31 -3
  545. package/dist/window/panel.d.ts.map +1 -1
  546. package/dist/window/panel.js +311 -69
  547. package/dist/window/placement.d.ts.map +1 -1
  548. package/dist/window/placement.js +5 -1
  549. package/dist/window/swing.d.ts +13 -0
  550. package/dist/window/swing.d.ts.map +1 -0
  551. package/dist/window/swing.js +16 -0
  552. package/dist/window/tool.d.ts.map +1 -1
  553. package/dist/window/tool.js +19 -14
  554. package/dist/zone/floorplan-affordances.d.ts +136 -0
  555. package/dist/zone/floorplan-affordances.d.ts.map +1 -1
  556. package/dist/zone/quantities-panel.d.ts.map +1 -1
  557. package/dist/zone/quantities-panel.js +34 -9
  558. package/dist/zone/renderer.d.ts.map +1 -1
  559. package/dist/zone/renderer.js +9 -5
  560. package/package.json +14 -14
  561. package/dist/site/generic-foundation-geometry.d.ts +0 -16
  562. package/dist/site/generic-foundation-geometry.d.ts.map +0 -1
  563. package/dist/site/generic-foundation-geometry.js +0 -75
  564. package/dist/site/generic-foundation.d.ts +0 -4
  565. package/dist/site/generic-foundation.d.ts.map +0 -1
  566. package/dist/site/generic-foundation.js +0 -91
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, getRoofSegmentDeckReach, getSegmentSlopeFrame, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, isGlazedRoofSegment, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, roofTypeHasRakes, useScene, } from '@pascal-app/core';
3
+ import { createDefaultRidgeVentsForSegment, getConicalRoofCoverage, getRoofSegmentDeckReach, getSegmentSlopeFrame, isAutoGutterEnabled, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, isGlazedRoofSegment, normalizeRoofSegmentTrim, ROOF_SHAPE_DEFAULTS, roofBuildUpPatch, roofSegmentEaveProfile, roofTypeHasRakes, usePascalI18n, useScene, } from '@pascal-app/core';
4
4
  import { ActionButton, ActionGroup, duplicateNodeAndPickUp, PanelSection, PanelWrapper, SegmentedControl, SliderControl, ToggleControl, triggerSFX, useEditor, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Check, Copy, Move, Pencil, RotateCcw, Trash2 } from 'lucide-react';
@@ -8,21 +8,42 @@ import { useCallback } from 'react';
8
8
  import { BarrelRoofPanel } from '../roof/barrel-panel.js';
9
9
  import { RoofGlazingPanel } from '../roof/glazing-panel.js';
10
10
  import { commitSeatedRoofEdit } from '../roof/roof-level-target.js';
11
+ import { RoofBuildUpSection } from './build-up-section.js';
11
12
  const ROOF_TYPE_OPTIONS = [
12
- { label: 'Hip', value: 'hip' },
13
- { label: 'Gable', value: 'gable' },
14
- { label: 'Shed', value: 'shed' },
13
+ { label: /* i18n */ { id: 'node.roofSegment.panel.hip', message: 'Hip' }, value: 'hip' },
14
+ { label: /* i18n */ { id: 'node.roofSegment.panel.gable', message: 'Gable' }, value: 'gable' },
15
+ { label: /* i18n */ { id: 'node.roofSegment.panel.shed', message: 'Shed' }, value: 'shed' },
15
16
  ];
16
17
  const ROOF_TYPE_OPTIONS_2 = [
17
- { label: 'Flat', value: 'flat' },
18
- { label: 'Gambrel', value: 'gambrel' },
19
- { label: 'Dutch', value: 'dutch' },
20
- { label: 'Mansard', value: 'mansard' },
18
+ { label: /* i18n */ { id: 'node.roofSegment.panel.flat', message: 'Flat' }, value: 'flat' },
19
+ {
20
+ label: /* i18n */ { id: 'node.roofSegment.panel.gambrel', message: 'Gambrel' },
21
+ value: 'gambrel',
22
+ },
23
+ { label: /* i18n */ { id: 'node.roofSegment.panel.dutch', message: 'Dutch' }, value: 'dutch' },
24
+ {
25
+ label: /* i18n */ { id: 'node.roofSegment.panel.mansard', message: 'Mansard' },
26
+ value: 'mansard',
27
+ },
21
28
  ];
22
29
  const ROOF_TYPE_OPTIONS_3 = [
23
- { label: 'Conical', value: 'conical' },
24
- { label: 'Barrel', value: 'barrel' },
30
+ {
31
+ label: /* i18n */ { id: 'node.roofSegment.panel.conical', message: 'Conical' },
32
+ value: 'conical',
33
+ },
34
+ { label: /* i18n */ { id: 'node.roofSegment.panel.barrel', message: 'Barrel' }, value: 'barrel' },
25
35
  ];
36
+ // How the rafter tails are cut at the eaves, the fascia and soffit with them (core's `roofEaveProfile`).
37
+ const EAVE_CUT_OPTIONS = [
38
+ { label: /* i18n */ { id: 'node.roofSegment.panel.plumb', message: 'Plumb' }, value: 'plumb' },
39
+ { label: /* i18n */ { id: 'node.roofSegment.panel.square', message: 'Square' }, value: 'square' },
40
+ {
41
+ label: /* i18n */ { id: 'node.roofSegment.panel.plumbLevel', message: 'Plumb + level' },
42
+ value: 'plumb-level',
43
+ },
44
+ ];
45
+ /** The sloped forms whose tails are cut at their eaves by the plane's eave cut. */
46
+ const EAVE_CUT_ROOF_TYPES = new Set(['gable', 'hip', 'shed']);
26
47
  // Carpenter / roofer convention: rise over a 12" run, converted to degrees.
27
48
  // atan(3/12) ≈ 14.04°, atan(6/12) ≈ 26.57°, atan(9/12) ≈ 36.87°, atan(12/12) = 45°.
28
49
  const PITCH_PRESETS = [
@@ -49,6 +70,13 @@ const EMPTY_TRIM = {
49
70
  backRightX: 0,
50
71
  backRightZ: 0,
51
72
  };
73
+ /** The planes of a roof that take layers: its segments, glazed ones aside. */
74
+ function roofLayerPlaneIds(children, nodes) {
75
+ return children.filter((id) => {
76
+ const child = nodes[id];
77
+ return child?.type === 'roof-segment' && !isGlazedRoofSegment(child);
78
+ });
79
+ }
52
80
  function hasSegmentTrim(node) {
53
81
  return Object.values(normalizeRoofSegmentTrim(node)).some((value) => value > 0);
54
82
  }
@@ -66,11 +94,13 @@ function metadataRecord(metadata) {
66
94
  return {};
67
95
  }
68
96
  export default function RoofSegmentPanel() {
97
+ const i18n = usePascalI18n();
69
98
  const selectedId = useViewer((s) => s.selection.selectedIds[0]);
70
99
  const setSelection = useViewer((s) => s.setSelection);
71
100
  const updateNode = useScene((s) => s.updateNode);
72
101
  const setMovingNode = useEditor((s) => s.setMovingNode);
73
102
  const setRoofHostDragArmedId = useEditor((s) => s.setRoofHostDragArmedId);
103
+ const unit = useViewer((s) => s.unit);
74
104
  const node = useScene((s) => selectedId ? s.nodes[selectedId] : undefined);
75
105
  const autoRidgeVentEnabled = useScene((s) => {
76
106
  const current = selectedId
@@ -80,6 +110,14 @@ export default function RoofSegmentPanel() {
80
110
  return false;
81
111
  return isAutoRidgeVentEnabled(current, s.nodes);
82
112
  });
113
+ // How many planes of this roof take layers: "Apply to all planes" shows once there are two.
114
+ const roofPlaneCount = useScene((s) => {
115
+ const current = selectedId
116
+ ? s.nodes[selectedId]
117
+ : undefined;
118
+ const roof = current?.parentId ? s.nodes[current.parentId] : undefined;
119
+ return roof?.type === 'roof' ? roofLayerPlaneIds(roof.children, s.nodes).length : 0;
120
+ });
83
121
  const autoGutterEnabled = useScene((s) => {
84
122
  const current = selectedId
85
123
  ? s.nodes[selectedId]
@@ -94,6 +132,17 @@ export default function RoofSegmentPanel() {
94
132
  // Reshaped or moved onto the walls that carry it, its roof goes to the level above them.
95
133
  commitSeatedRoofEdit([{ id: selectedId, data: updates }], selectedId);
96
134
  }, [selectedId]);
135
+ const handleApplyToRoof = useCallback(() => {
136
+ const scene = useScene.getState();
137
+ const current = selectedId ? scene.nodes[selectedId] : undefined;
138
+ if (current?.type !== 'roof-segment' || !current.buildUp)
139
+ return;
140
+ const roof = current.parentId ? scene.nodes[current.parentId] : undefined;
141
+ if (roof?.type !== 'roof')
142
+ return;
143
+ const patch = roofBuildUpPatch(current.buildUp);
144
+ scene.updateNodes(roofLayerPlaneIds(roof.children, scene.nodes).map((id) => ({ id, data: patch })));
145
+ }, [selectedId]);
97
146
  const handleRoofTypeChange = useCallback((roofType) => {
98
147
  if (isManagedLeanToRoofSegment(node?.metadata))
99
148
  return;
@@ -239,9 +288,42 @@ export default function RoofSegmentPanel() {
239
288
  const reach = getRoofSegmentDeckReach(node);
240
289
  const halfWall = node.wallThickness / 2;
241
290
  const { cosTheta } = getSegmentSlopeFrame(node);
242
- return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name || 'Roof Segment', width: 300, children: [_jsx(RoofGlazingPanel, { segments: [node] }), _jsxs(PanelSection, { title: "Roof Type", children: [_jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_2, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_3, value: node.roofType, disabled: managedLeanToRoofSegment })] }), node.roofType !== 'conical' && (_jsxs(PanelSection, { title: "Trim", children: [_jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: showTrimPlanes ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Pencil, { className: "h-3.5 w-3.5" })), label: showTrimPlanes ? 'Done editing' : 'Edit footprint', onClick: () => (showTrimPlanes ? handleBack() : handleTrimEditing(true)) }), _jsx(ActionButton, { className: "disabled:cursor-not-allowed disabled:opacity-40", disabled: !hasSegmentTrim(node), icon: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }), label: "Reset", onClick: handleResetTrim })] }), node.roofType !== 'shed' && node.roofType !== 'flat' && node.roofType !== 'barrel' && (_jsx(ToggleControl, { checked: autoRidgeVentEnabled, label: "Auto ridge vent", onChange: handleAutoRidgeVentToggle }))] })), node.roofType !== 'conical' && (_jsx(PanelSection, { title: "Drainage", children: _jsx(ToggleControl, { checked: autoGutterEnabled, label: "Auto gutters", onChange: handleAutoGutterToggle }) })), _jsx(PanelSection, { title: "Footprint", children: node.roofType === 'conical' ? (_jsx(SliderControl, { label: "Diameter", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v, depth: v }), precision: 2, step: 0.5, unit: "m", value: node.width })) : (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: node.roofType === 'barrel' ? 'Length' : 'Width', max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.5, unit: "m", value: node.width }), _jsx(SliderControl, { label: node.roofType === 'barrel' ? 'Span' : 'Depth', max: 1000, min: 0.5, onChange: (v) => handleUpdate({ depth: v }), precision: 2, step: 0.5, unit: "m", value: node.depth })] })) }), node.roofType === 'conical' && (_jsxs(PanelSection, { title: "Conical Shape", children: [_jsx(ToggleControl, { checked: !conicalCoverage.fullCircle, label: "Clipped version", onChange: (checked) => handleUpdate({ conicalFullCircle: !checked }) }), !conicalCoverage.fullCircle && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Start Angle", max: 180, min: -180, onChange: (degrees) => handleUpdate({ conicalStartAngle: (degrees * Math.PI) / 180 }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((conicalCoverage.startAngle * 180) / Math.PI) }), _jsx(SliderControl, { label: "Arc", max: 345, min: 15, onChange: (degrees) => handleUpdate({
291
+ return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name || i18n._({ id: 'node.roofSegment.panel.roofSegment', message: 'Roof Segment' }), width: 300, children: [_jsx(RoofGlazingPanel, { segments: [node] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.roofType', message: 'Roof Type' }), children: [_jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS.map((option) => ({ ...option, label: i18n._(option.label) })), value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_2.map((option) => ({
292
+ ...option,
293
+ label: i18n._(option.label),
294
+ })), value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_3.map((option) => ({
295
+ ...option,
296
+ label: i18n._(option.label),
297
+ })), value: node.roofType, disabled: managedLeanToRoofSegment })] }), node.roofType !== 'conical' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.trim', message: 'Trim' }), children: [_jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: showTrimPlanes ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Pencil, { className: "h-3.5 w-3.5" })), label: showTrimPlanes
298
+ ? i18n._({ id: 'node.roofSegment.panel.doneEditing', message: 'Done editing' })
299
+ : i18n._({
300
+ id: 'node.roofSegment.panel.editFootprint',
301
+ message: 'Edit footprint',
302
+ }), onClick: () => (showTrimPlanes ? handleBack() : handleTrimEditing(true)) }), _jsx(ActionButton, { className: "disabled:cursor-not-allowed disabled:opacity-40", disabled: !hasSegmentTrim(node), icon: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.reset', message: 'Reset' }), onClick: handleResetTrim })] }), node.roofType !== 'shed' && node.roofType !== 'flat' && node.roofType !== 'barrel' && (_jsx(ToggleControl, { checked: autoRidgeVentEnabled, label: i18n._({
303
+ id: 'node.roofSegment.panel.autoRidgeVent',
304
+ message: 'Auto ridge vent',
305
+ }), onChange: handleAutoRidgeVentToggle }))] })), node.roofType !== 'conical' && (_jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.drainage', message: 'Drainage' }), children: _jsx(ToggleControl, { checked: autoGutterEnabled, label: i18n._({ id: 'node.roofSegment.panel.autoGutters', message: 'Auto gutters' }), onChange: handleAutoGutterToggle }) })), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.footprint', message: 'Footprint' }), children: node.roofType === 'conical' ? (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.diameter', message: 'Diameter' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v, depth: v }), precision: 2, step: 0.5, unit: "m", value: node.width })) : (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: node.roofType === 'barrel'
306
+ ? i18n._({ id: 'node.roofSegment.panel.length', message: 'Length' })
307
+ : i18n._({ id: 'node.roofSegment.panel.width', message: 'Width' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.5, unit: "m", value: node.width }), _jsx(SliderControl, { label: node.roofType === 'barrel'
308
+ ? i18n._({ id: 'node.roofSegment.panel.span', message: 'Span' })
309
+ : i18n._({ id: 'node.roofSegment.panel.depth', message: 'Depth' }), max: 1000, min: 0.5, onChange: (v) => handleUpdate({ depth: v }), precision: 2, step: 0.5, unit: "m", value: node.depth })] })) }), node.roofType === 'conical' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.conicalShape', message: 'Conical Shape' }), children: [_jsx(ToggleControl, { checked: !conicalCoverage.fullCircle, label: i18n._({
310
+ id: 'node.roofSegment.panel.clippedVersion',
311
+ message: 'Clipped version',
312
+ }), onChange: (checked) => handleUpdate({ conicalFullCircle: !checked }) }), !conicalCoverage.fullCircle && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.startAngle', message: 'Start Angle' }), max: 180, min: -180, onChange: (degrees) => handleUpdate({ conicalStartAngle: (degrees * Math.PI) / 180 }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((conicalCoverage.startAngle * 180) / Math.PI) }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.arc', message: 'Arc' }), max: 345, min: 15, onChange: (degrees) => handleUpdate({
243
313
  conicalSweepAngle: (Math.sign(conicalCoverage.sweepAngle) * degrees * Math.PI) / 180,
244
- }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title: "Wall Height", children: _jsx(SliderControl, { label: "Wall", max: 1000, min: 0, onChange: (v) => handleUpdate({ wallHeight: v }), precision: 2, step: 0.1, unit: "m", value: node.wallHeight }) }), node.roofType === 'barrel' ? (_jsx(BarrelRoofPanel, { node: node })) : (_jsxs(PanelSection, { title: "Pitch", children: [_jsx(SliderControl, { label: "Angle", max: 60, min: 0, onChange: (v) => handleUpdate({ pitch: v }), precision: 0, step: 1, unit: "\u00B0", value: Math.round(node.pitch) }), _jsx("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: PITCH_PRESETS.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleUpdate({ pitch: preset.deg }) }, preset.label))) })] })), node.roofType === 'gambrel' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Kink Depth", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Kink Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerHeightRatio * 100) / 100 })] })), node.roofType === 'mansard' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Waist Width", max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ mansardSteepWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ mansardSteepHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepHeightRatio * 100) / 100 })] })), node.roofType === 'dutch' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Waist Width", max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ dutchHipWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ dutchHipHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipHeightRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Length", max: 1, min: 0.1, onChange: (v) => handleUpdate({ dutchWaistLengthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round((node.dutchWaistLengthRatio ?? ROOF_SHAPE_DEFAULTS.dutchWaistLengthRatio) * 100) / 100 }), _jsx(SliderControl, { label: "Top Rake Thick.", max: 0.5, min: 0.01, onChange: (v) => handleUpdate({ dutchTopRakeThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchTopRakeThickness ?? ROOF_SHAPE_DEFAULTS.dutchTopRakeThickness }), _jsx(SliderControl, { label: "Top Rake Length", max: 3, min: 0, onChange: (v) => handleUpdate({ dutchGabletRake: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchGabletRake ?? ROOF_SHAPE_DEFAULTS.dutchGabletRake })] })), _jsxs(PanelSection, { title: "Structure", children: [_jsx(SliderControl, { label: "Wall Thick.", max: 1, min: 0.05, onChange: (v) => handleUpdate({ wallThickness: v }), precision: 2, step: 0.05, unit: "m", value: node.wallThickness }), !isGlazedRoofSegment(node) && (_jsx(SliderControl, { label: "Deck Thick.", max: 0.3, min: 0.04, onChange: (v) => handleUpdate({ deckThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.deckThickness })), node.roofType === 'barrel' ? (_jsx(SliderControl, { label: "End overhang", max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })) : (_jsx(SliderControl, { label: "Eave overhang", max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v / cosTheta }), precision: 2, step: 0.05, unit: "m", value: reach.z - halfWall })), roofTypeHasRakes(node.roofType) && (_jsx(SliderControl, { label: "Gable overhang", max: 3, min: 0, onChange: (v) => handleUpdate({ gableOverhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })), !isGlazedRoofSegment(node) && (_jsx(SliderControl, { label: "Shingle Thick.", max: 0.3, min: 0.02, onChange: (v) => handleUpdate({ shingleThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.shingleThickness })), _jsx(ToggleControl, { checked: node.fascia ?? false, label: "Fascia", onChange: (checked) => handleUpdate({ fascia: checked }) }), node.fascia && (_jsx(SliderControl, { label: "Fascia height", max: 0.6, min: 0.1, onChange: (v) => handleUpdate({ fasciaHeight: v }), precision: 2, step: 0.01, unit: "m", value: node.fasciaHeight ?? 0.184 }))] }), _jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
314
+ }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.wallHeight', message: 'Wall Height' }), children: _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.wall', message: 'Wall' }), max: 1000, min: 0, onChange: (v) => handleUpdate({ wallHeight: v }), precision: 2, step: 0.1, unit: "m", value: node.wallHeight }) }), node.roofType === 'barrel' ? (_jsx(BarrelRoofPanel, { node: node })) : (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.pitch', message: 'Pitch' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.angle', message: 'Angle' }), max: 60, min: 0, onChange: (v) => handleUpdate({ pitch: v }), precision: 0, step: 1, unit: "\u00B0", value: Math.round(node.pitch) }), _jsx("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: PITCH_PRESETS.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleUpdate({ pitch: preset.deg }) }, preset.label))) })] })), node.roofType === 'gambrel' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.kinkDepth', message: 'Kink Depth' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.kinkHeight', message: 'Kink Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerHeightRatio * 100) / 100 })] })), node.roofType === 'mansard' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistWidth', message: 'Waist Width' }), max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ mansardSteepWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistHeight', message: 'Waist Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ mansardSteepHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepHeightRatio * 100) / 100 })] })), node.roofType === 'dutch' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.shape', message: 'Shape' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistWidth', message: 'Waist Width' }), max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ dutchHipWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistHeight', message: 'Waist Height' }), max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ dutchHipHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipHeightRatio * 100) / 100 }), _jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.waistLength', message: 'Waist Length' }), max: 1, min: 0.1, onChange: (v) => handleUpdate({ dutchWaistLengthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round((node.dutchWaistLengthRatio ?? ROOF_SHAPE_DEFAULTS.dutchWaistLengthRatio) * 100) / 100 }), _jsx(SliderControl, { label: i18n._({
315
+ id: 'node.roofSegment.panel.topRakeThick',
316
+ message: 'Top Rake Thick.',
317
+ }), max: 0.5, min: 0.01, onChange: (v) => handleUpdate({ dutchTopRakeThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchTopRakeThickness ?? ROOF_SHAPE_DEFAULTS.dutchTopRakeThickness }), _jsx(SliderControl, { label: i18n._({
318
+ id: 'node.roofSegment.panel.topRakeLength',
319
+ message: 'Top Rake Length',
320
+ }), max: 3, min: 0, onChange: (v) => handleUpdate({ dutchGabletRake: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchGabletRake ?? ROOF_SHAPE_DEFAULTS.dutchGabletRake })] })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.structure', message: 'Structure' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.wallThick', message: 'Wall Thick.' }), max: 1, min: 0.05, onChange: (v) => handleUpdate({ wallThickness: v }), precision: 2, step: 0.05, unit: "m", value: node.wallThickness }), !(isGlazedRoofSegment(node) || node.buildUp) && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.deckThick', message: 'Deck Thick.' }), max: 0.3, min: 0.04, onChange: (v) => handleUpdate({ deckThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.deckThickness })), node.roofType === 'barrel' ? (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.endOverhang', message: 'End overhang' }), max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })) : (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.eaveOverhang', message: 'Eave overhang' }), max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v / cosTheta }), precision: 2, step: 0.05, unit: "m", value: reach.z - halfWall })), roofTypeHasRakes(node.roofType) && (_jsx(SliderControl, { label: i18n._({
321
+ id: 'node.roofSegment.panel.gableOverhang',
322
+ message: 'Gable overhang',
323
+ }), max: 3, min: 0, onChange: (v) => handleUpdate({ gableOverhang: v }), precision: 2, step: 0.05, unit: "m", value: reach.x - halfWall })), !(isGlazedRoofSegment(node) || node.buildUp) && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.shingleThick', message: 'Shingle Thick.' }), max: 0.3, min: 0.02, onChange: (v) => handleUpdate({ shingleThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.shingleThickness })), EAVE_CUT_ROOF_TYPES.has(node.roofType) && node.pitch > 0 && (_jsxs("div", { children: [_jsx("div", { className: "px-1 pb-1 text-[10px] text-muted-foreground uppercase tracking-wide", children: i18n._({ id: 'node.roofSegment.panel.eaveCut', message: 'Eave cut' }) }), _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ eaveCut: v }), options: EAVE_CUT_OPTIONS.map((option) => ({
324
+ ...option,
325
+ label: i18n._(option.label),
326
+ })), value: node.eaveCut ?? 'plumb' })] })), _jsx(ToggleControl, { checked: node.fascia ?? false, label: i18n._({ id: 'node.roofSegment.panel.fascia', message: 'Fascia' }), onChange: (checked) => handleUpdate({ fascia: checked }) }), node.fascia && (_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.fasciaHeight', message: 'Fascia height' }), max: 0.6, min: 0.1, onChange: (v) => handleUpdate({ fasciaHeight: v }), precision: 2, step: 0.01, unit: "m", value: node.fasciaHeight ?? roofSegmentEaveProfile(node).fascia.height }))] }), !isGlazedRoofSegment(node) && (_jsx(RoofBuildUpSection, { node: node, onApplyToRoof: roofPlaneCount > 1 ? handleApplyToRoof : undefined, onUpdate: handleUpdate, unit: unit })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.position', message: 'Position' }), children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
245
327
  const pos = [...node.position];
246
328
  pos[0] = v;
247
329
  handleUpdate({ position: pos });
@@ -253,7 +335,7 @@ export default function RoofSegmentPanel() {
253
335
  const pos = [...node.position];
254
336
  pos[2] = v;
255
337
  handleUpdate({ position: pos });
256
- }, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), (node.roofType !== 'conical' || !conicalCoverage.fullCircle) && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (degrees) => {
338
+ }, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), (node.roofType !== 'conical' || !conicalCoverage.fullCircle) && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roofSegment.panel.rotation', message: 'Rotation' }), max: 180, min: -180, onChange: (degrees) => {
257
339
  handleUpdate({ rotation: (degrees * Math.PI) / 180 });
258
340
  }, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
259
341
  triggerSFX('sfx:item-rotate');
@@ -261,5 +343,5 @@ export default function RoofSegmentPanel() {
261
343
  } }), _jsx(ActionButton, { label: "+45\u00B0", onClick: () => {
262
344
  triggerSFX('sfx:item-rotate');
263
345
  handleUpdate({ rotation: node.rotation + Math.PI / 4 });
264
- } })] })] }))] }), _jsx(PanelSection, { title: "Actions", children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: "Move", onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: "Duplicate", onClick: handleDuplicate }), _jsx(ActionButton, { className: "hover:bg-red-500/20", icon: _jsx(Trash2, { className: "h-3.5 w-3.5 text-red-600 dark:text-red-400" }), label: "Delete", onClick: handleDelete })] }) })] }));
346
+ } })] })] }))] }), _jsx(PanelSection, { title: i18n._({ id: 'node.roofSegment.panel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.move', message: 'Move' }), onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roofSegment.panel.duplicate', message: 'Duplicate' }), onClick: handleDuplicate }), _jsx(ActionButton, { className: "hover:bg-red-500/20", icon: _jsx(Trash2, { className: "h-3.5 w-3.5 text-red-600 dark:text-red-400" }), label: i18n._({ id: 'node.roofSegment.panel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
265
347
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/roof-segment/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAoB,MAAM,kBAAkB,CAAA;AAEpG,eAAO,MAAM,sBAAsB,EAAE,oBAAoB,CAAC,eAAe,CA6LxE,CAAA"}
1
+ {"version":3,"file":"parametrics.d.ts","sourceRoot":"","sources":["../../src/roof-segment/parametrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,eAAe,EAAoB,MAAM,kBAAkB,CAAA;AAEpG,eAAO,MAAM,sBAAsB,EAAE,oBAAoB,CAAC,eAAe,CAiMxE,CAAA"}
@@ -140,6 +140,8 @@ export const roofSegmentParametrics = {
140
140
  min: 0.04,
141
141
  max: 0.3,
142
142
  step: 0.01,
143
+ // Layers set it: edited here it would part from them.
144
+ visibleIf: (node) => !node.buildUp,
143
145
  },
144
146
  { key: 'overhang', kind: 'number', unit: 'm', min: 0, max: 1, step: 0.05 },
145
147
  {
@@ -160,6 +162,8 @@ export const roofSegmentParametrics = {
160
162
  min: 0.02,
161
163
  max: 0.3,
162
164
  step: 0.01,
165
+ // Layers set it: edited here it would part from them.
166
+ visibleIf: (node) => !node.buildUp,
163
167
  },
164
168
  {
165
169
  key: 'wallShell',
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,eAAe,EAKrB,MAAM,kBAAkB,CAAA;AAiBzB,eAAO,MAAM,mBAAmB,yBAA0B;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,gCAkMlF,CAAA;eAEc,mBAAmB"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof-segment/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,eAAe,EAKrB,MAAM,kBAAkB,CAAA;AAkBzB,eAAO,MAAM,mBAAmB,yBAA0B;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,gCA4NlF,CAAA;eAEc,mBAAmB"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { getEffectiveNode, getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, getSegmentFasciaMaterial, isGlazedRoofSegment, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
4
- import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, resolveMaterialRef, SHADOW_ONLY_LAYER, useNodeEvents, useViewer, } from '@pascal-app/viewer';
3
+ import { getEffectiveNode, getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, getRoofWallBandMaterial, getSegmentFasciaMaterial, isGlazedRoofSegment, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
4
+ import { createMaterial, getRoofMaterialArray, levelWallCladdingRef, levelWallFaceRef, resolveMaterialRef, SHADOW_ONLY_LAYER, useNodeEvents, useViewer, } from '@pascal-app/viewer';
5
5
  import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
6
6
  import * as THREE from 'three';
7
7
  import { syncGlazedRoofShadow } from '../roof/glazed-geometry.js';
@@ -51,8 +51,11 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
51
51
  // slot 1 → 'wall' (deck top & shingle eave bands)
52
52
  // slot 2 → 'wall' (interior)
53
53
  // slot 3 → 'top' (shingle / roof surface)
54
+ // slot 4 → the heel band (its own, the roof's, else the walls' below)
55
+ // slot 5 / 6 → the left / right gable (its own, else slot 0's)
54
56
  // The gable band is clad like the walls below it (their assemblies).
55
57
  const wallCladdingRef = useScene((state) => parentNode ? levelWallCladdingRef(state.nodes, parentNode) : null);
58
+ const wallFaceRef = useScene((state) => parentNode ? levelWallFaceRef(state.nodes, parentNode) : null);
56
59
  // biome-ignore lint/correctness/useExhaustiveDependencies: deps deliberately list the build inputs; depending on the whole object would rebuild on unrelated field changes.
57
60
  const customMaterial = useMemo(() => {
58
61
  const resolveSlot = (role) => {
@@ -69,8 +72,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
69
72
  // Themed parent-roof array (per-role scene-theme colours) — used both as the
70
73
  // full fallback and to fill any individual untextured slot below.
71
74
  const themedArray = parentNode
72
- ? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials)
75
+ ? getRoofMaterialArray(parentNode, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials, wallFaceRef)
73
76
  : null;
77
+ const resolveSpec = (spec) => spec
78
+ ? (resolveMaterialRef(spec.materialPreset, sceneMaterials, shading) ??
79
+ (spec.material !== undefined ? createMaterial(spec.material, shading) : null))
80
+ : null;
81
+ const heel = resolveSpec(getRoofWallBandMaterial(node, 'heel'));
82
+ const gableLeft = resolveSpec(getRoofWallBandMaterial(node, 'gable-left'));
83
+ const gableRight = resolveSpec(getRoofWallBandMaterial(node, 'gable-right'));
74
84
  const edge = resolveSlot('edge');
75
85
  const wall = resolveSlot('wall');
76
86
  const top = resolveSlot('top');
@@ -80,7 +90,7 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
80
90
  ? (resolveMaterialRef(fasciaSpec.materialPreset, sceneMaterials, shading) ??
81
91
  (fasciaSpec.material !== undefined ? createMaterial(fasciaSpec.material, shading) : null))
82
92
  : null;
83
- if (!(edge || wall || top || fascia)) {
93
+ if (!(edge || wall || top || fascia || heel || gableLeft || gableRight)) {
84
94
  return themedArray;
85
95
  }
86
96
  // Some slots have explicit materials; fill the rest from the themed array so
@@ -88,11 +98,15 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
88
98
  // Per-role only, then the themed parent slot — no cross-role fallback, so
89
99
  // painting one segment surface never bleeds onto its other surfaces.
90
100
  const slot = (i) => themedArray?.[i] ?? new THREE.MeshStandardMaterial();
101
+ const trim = edge ?? slot(0);
91
102
  return [
92
- edge ?? slot(0),
103
+ trim,
93
104
  wall ?? slot(1),
94
105
  fascia ?? wall ?? slot(2),
95
106
  top ?? slot(3),
107
+ heel ?? slot(4),
108
+ gableLeft ?? trim,
109
+ gableRight ?? trim,
96
110
  ];
97
111
  }, [
98
112
  node.material,
@@ -106,6 +120,13 @@ export const RoofSegmentRenderer = ({ node: storedNode }) => {
106
120
  node.wallMaterialPreset,
107
121
  node.fasciaMaterial,
108
122
  node.fasciaMaterialPreset,
123
+ node.heelMaterial,
124
+ node.heelMaterialPreset,
125
+ node.gableLeftMaterial,
126
+ node.gableLeftMaterialPreset,
127
+ node.gableRightMaterial,
128
+ node.gableRightMaterialPreset,
129
+ wallFaceRef,
109
130
  parentNode,
110
131
  sceneMaterials,
111
132
  shading,
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/separator/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErE,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,aAAa,CAqCpE,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/separator/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAIrE,eAAO,MAAM,mBAAmB,EAAE,cAAc,CAAC,OAAO,aAAa,CAiCpE,CAAA"}
@@ -1,6 +1,10 @@
1
1
  import { SeparatorNode } from '@pascal-app/core';
2
+ import { buildSeparatorFloorplan } from './floorplan.js';
3
+ import { separatorMoveEndpointAffordance } from './floorplan-affordances.js';
2
4
  export const separatorDefinition = {
3
5
  kind: 'separator',
6
+ // Its pushes and end drags snap as a wall's do.
7
+ snapProfile: 'structural',
4
8
  bake: 'strip',
5
9
  schemaVersion: 1,
6
10
  schema: SeparatorNode,
@@ -18,18 +22,12 @@ export const separatorDefinition = {
18
22
  dirtyTracking: false,
19
23
  rendersChildren: false,
20
24
  renderer: { kind: 'parametric', module: () => import('./renderer.js') },
21
- floorplan: (node) => ({
22
- kind: 'line',
23
- x1: node.start[0],
24
- y1: node.start[1],
25
- x2: node.end[0],
26
- y2: node.end[1],
27
- stroke: '#818cf8',
28
- strokeWidth: 2,
29
- strokeDasharray: '6 4',
30
- vectorEffect: 'non-scaling-stroke',
31
- pointerEvents: 'stroke',
32
- }),
25
+ floorplan: buildSeparatorFloorplan,
26
+ // An invisible wall moves as a wall does, taking the ones joined to it along:
27
+ // its side arrows push it (the plan's `move-arrow`s, the 3D selection
28
+ // handles) and its ends drag, on the plan and in 3D.
29
+ floorplanAffordances: { 'move-endpoint': separatorMoveEndpointAffordance },
30
+ affordanceTools: { selection: () => import('./selection.js') },
33
31
  presentation: {
34
32
  icon: { kind: 'iconify', name: 'lucide:split' },
35
33
  label: 'Separator',
@@ -0,0 +1,9 @@
1
+ import type { FloorplanAffordance, SeparatorNode } from '@pascal-app/core';
2
+ /**
3
+ * An invisible wall's end handle on the plan, the 2D twin of its 3D grip: the
4
+ * same snapping, preview and commit (`beginSeparatorEndDrag`), the pointer read
5
+ * by the floor plan. The invisible walls joined at that end follow it; Alt
6
+ * leaves them where they are.
7
+ */
8
+ export declare const separatorMoveEndpointAffordance: FloorplanAffordance<SeparatorNode>;
9
+ //# sourceMappingURL=floorplan-affordances.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/separator/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EAEnB,aAAa,EACd,MAAM,kBAAkB,CAAA;AAKzB;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,EAAE,mBAAmB,CAAC,aAAa,CAe9E,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { beginSeparatorEndDrag } from '@pascal-app/editor';
2
+ /**
3
+ * An invisible wall's end handle on the plan, the 2D twin of its 3D grip: the
4
+ * same snapping, preview and commit (`beginSeparatorEndDrag`), the pointer read
5
+ * by the floor plan. The invisible walls joined at that end follow it; Alt
6
+ * leaves them where they are.
7
+ */
8
+ export const separatorMoveEndpointAffordance = {
9
+ start({ node, payload }) {
10
+ const { endpoint } = payload;
11
+ const drag = beginSeparatorEndDrag(node.id, endpoint);
12
+ return {
13
+ affectedIds: drag?.affectedIds ?? [node.id],
14
+ apply({ planPoint, modifiers }) {
15
+ drag?.move([planPoint[0], planPoint[1]], modifiers.altKey);
16
+ },
17
+ canCommit: () => drag?.canCommit() ?? false,
18
+ commit() {
19
+ drag?.commit();
20
+ },
21
+ };
22
+ },
23
+ };
@@ -0,0 +1,9 @@
1
+ import type { FloorplanGeometry, GeometryContext, SeparatorNode } from '@pascal-app/core';
2
+ /**
3
+ * An invisible wall on the plan: a dashed line. Selected, it shows a wall's own
4
+ * handles — an end handle at each end (drag it; the invisible walls joined
5
+ * there follow) and a push arrow off each side (the wall push, the ones joined
6
+ * to it following).
7
+ */
8
+ export declare function buildSeparatorFloorplan(node: SeparatorNode, ctx: GeometryContext): FloorplanGeometry;
9
+ //# sourceMappingURL=floorplan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorplan.d.ts","sourceRoot":"","sources":["../../src/separator/floorplan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAMzF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,eAAe,GACnB,iBAAiB,CA2CnB"}
@@ -0,0 +1,54 @@
1
+ import { WALL_PUSH_AFFORDANCE } from '@pascal-app/editor';
2
+ /** How far off the line (m) a selected invisible wall's side arrows sit. */
3
+ const SIDE_ARROW_OFFSET = 0.12;
4
+ /**
5
+ * An invisible wall on the plan: a dashed line. Selected, it shows a wall's own
6
+ * handles — an end handle at each end (drag it; the invisible walls joined
7
+ * there follow) and a push arrow off each side (the wall push, the ones joined
8
+ * to it following).
9
+ */
10
+ export function buildSeparatorFloorplan(node, ctx) {
11
+ const line = {
12
+ kind: 'line',
13
+ x1: node.start[0],
14
+ y1: node.start[1],
15
+ x2: node.end[0],
16
+ y2: node.end[1],
17
+ stroke: '#818cf8',
18
+ strokeWidth: 2,
19
+ strokeDasharray: '6 4',
20
+ vectorEffect: 'non-scaling-stroke',
21
+ pointerEvents: 'stroke',
22
+ };
23
+ if (!ctx.viewState?.selected)
24
+ return line;
25
+ const children = [line];
26
+ for (const endpoint of ['start', 'end'])
27
+ children.push({
28
+ kind: 'endpoint-handle',
29
+ point: [node[endpoint][0], node[endpoint][1]],
30
+ state: 'idle',
31
+ affordance: 'move-endpoint',
32
+ payload: { separatorId: node.id, endpoint },
33
+ });
34
+ const dx = node.end[0] - node.start[0];
35
+ const dz = node.end[1] - node.start[1];
36
+ const length = Math.hypot(dx, dz);
37
+ if (length > 1e-6) {
38
+ const middle = [(node.start[0] + node.end[0]) / 2, (node.start[1] + node.end[1]) / 2];
39
+ for (const side of ['a', 'b']) {
40
+ // Side `a` is the +normal one, as a wall's front.
41
+ const sign = side === 'a' ? 1 : -1;
42
+ const nx = (-dz / length) * sign;
43
+ const nz = (dx / length) * sign;
44
+ children.push({
45
+ kind: 'move-arrow',
46
+ point: [middle[0] + nx * SIDE_ARROW_OFFSET, middle[1] + nz * SIDE_ARROW_OFFSET],
47
+ angle: Math.atan2(nz, nx),
48
+ affordance: WALL_PUSH_AFFORDANCE,
49
+ payload: { wallId: node.id, side },
50
+ });
51
+ }
52
+ }
53
+ return { kind: 'group', children };
54
+ }
@@ -1,4 +1,8 @@
1
1
  import { type SeparatorNode } from '@pascal-app/core';
2
+ /**
3
+ * An invisible wall in 3D: a dashed line on the floor, shown while its room or
4
+ * it is selected. A push or end drag moves it live (`useLiveNodeOverrides`).
5
+ */
2
6
  export default function SeparatorRenderer({ node }: {
3
7
  node: SeparatorNode;
4
8
  }): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/separator/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAyB,MAAM,kBAAkB,CAAA;AAU5E,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,+BAgD1E"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/separator/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,kBAAkB,CAAA;AAUlG;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,+BAgE1E"}
@@ -1,26 +1,41 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useRegistry, useScene } from '@pascal-app/core';
4
- import { useEditor } from '@pascal-app/editor';
3
+ import { useLiveNodeOverrides, useRegistry, useScene } from '@pascal-app/core';
4
+ import { separatorFloorElevation, useEditor } from '@pascal-app/editor';
5
5
  import { useNodeEvents, useViewer } from '@pascal-app/viewer';
6
6
  import { useEffect, useMemo, useRef } from 'react';
7
7
  import { BufferGeometry, Float32BufferAttribute } from 'three';
8
8
  import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu';
9
9
  const separatorMaterial = new LineBasicNodeMaterial({ color: '#818cf8', depthWrite: false });
10
10
  const hitMaterial = new MeshBasicNodeMaterial({ transparent: true, opacity: 0, depthWrite: false });
11
+ /**
12
+ * An invisible wall in 3D: a dashed line on the floor, shown while its room or
13
+ * it is selected. A push or end drag moves it live (`useLiveNodeOverrides`).
14
+ */
11
15
  export default function SeparatorRenderer({ node }) {
12
16
  const ref = useRef(null);
13
17
  useRegistry(node.id, 'separator', ref);
14
18
  const roomId = useEditor((s) => s.room?.zoneId);
15
19
  const viewerRoomId = useViewer((s) => s.selection.zoneId);
20
+ const selected = useViewer((s) => s.selection.selectedIds.includes(node.id));
16
21
  const zone = useScene((s) => {
17
22
  const id = roomId ?? viewerRoomId;
18
23
  return id ? s.nodes[id] : undefined;
19
24
  });
20
- const visible = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id);
25
+ const inRoom = zone?.type === 'zone' && zone.boundarySeparatorIds.includes(node.id);
26
+ const visible = inRoom || selected;
27
+ // Selected on its own, it lies on the floor of a room it closes.
28
+ const ownFloor = useScene((s) => selected && !inRoom ? separatorFloorElevation(s.nodes, node.id) : null);
29
+ const live = useLiveNodeOverrides((s) => s.overrides.get(node.id));
30
+ const start = live?.start ?? node.start;
31
+ const end = live?.end ?? node.end;
21
32
  const events = useNodeEvents(node, 'separator');
22
- const y = zone?.type === 'zone' ? (zone.floor?.elevation ?? 0.05) + 0.02 : 0.07;
23
- const dx = node.end[0] - node.start[0], dz = node.end[1] - node.start[1];
33
+ const y = zone?.type === 'zone' && inRoom
34
+ ? (zone.floor?.elevation ?? 0.05) + 0.02
35
+ : ownFloor !== null
36
+ ? ownFloor + 0.02
37
+ : 0.07;
38
+ const dx = end[0] - start[0], dz = end[1] - start[1];
24
39
  const length = Math.hypot(dx, dz);
25
40
  const geometry = useMemo(() => {
26
41
  const positions = [];
@@ -32,5 +47,5 @@ export default function SeparatorRenderer({ node }) {
32
47
  return new BufferGeometry().setAttribute('position', new Float32BufferAttribute(positions, 3));
33
48
  }, [length]);
34
49
  useEffect(() => () => geometry.dispose(), [geometry]);
35
- return (_jsx("group", { ref: ref, visible: visible, children: visible && (_jsxs(_Fragment, { children: [_jsx("lineSegments", { geometry: geometry, material: separatorMaterial, position: [node.start[0], y, node.start[1]], rotation: [0, -Math.atan2(dz, dx), 0], raycast: () => { } }), _jsx("mesh", { ...events, material: hitMaterial, position: [(node.start[0] + node.end[0]) / 2, y, (node.start[1] + node.end[1]) / 2], rotation: [0, -Math.atan2(dz, dx), 0], children: _jsx("boxGeometry", { args: [length, 0.03, 0.1] }) })] })) }));
50
+ return (_jsx("group", { ref: ref, visible: visible, children: visible && (_jsxs(_Fragment, { children: [_jsx("lineSegments", { geometry: geometry, material: separatorMaterial, position: [start[0], y, start[1]], rotation: [0, -Math.atan2(dz, dx), 0], raycast: () => { } }), _jsx("mesh", { ...events, material: hitMaterial, position: [(start[0] + end[0]) / 2, y, (start[1] + end[1]) / 2], rotation: [0, -Math.atan2(dz, dx), 0], children: _jsx("boxGeometry", { args: [length, 0.03, 0.1] }) })] })) }));
36
51
  }
@@ -0,0 +1,10 @@
1
+ import { type SelectionAffordanceProps } from '@pascal-app/editor';
2
+ /**
3
+ * A selected invisible wall's 3D handles, the twins of its plan ones: a push
4
+ * arrow off each side (the wall push: the invisible walls joined to it follow
5
+ * and those T'd into it stretch) and a grip at each end (drag it across the
6
+ * floor; the ones joined there follow). They lie on the floor of the room it
7
+ * closes, where its dashed line is drawn, and hide while a drag runs.
8
+ */
9
+ export default function SeparatorSelectionAffordance({ node, readOnly }: SelectionAffordanceProps): import("react").JSX.Element | null;
10
+ //# sourceMappingURL=selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/separator/selection.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,wBAAwB,EAO9B,MAAM,oBAAoB,CAAA;AAK3B;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,4BAA4B,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,wBAAwB,sCAmChG"}
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { sceneRegistry, useScene } from '@pascal-app/core';
4
+ import { SeparatorEndGrip, separatorFloorElevation, separatorPushHandles, useEditor, useInteractionScope, WallPushArrow, } from '@pascal-app/editor';
5
+ import { createPortal } from '@react-three/fiber';
6
+ import { useEffect, useState } from 'react';
7
+ /**
8
+ * A selected invisible wall's 3D handles, the twins of its plan ones: a push
9
+ * arrow off each side (the wall push: the invisible walls joined to it follow
10
+ * and those T'd into it stretch) and a grip at each end (drag it across the
11
+ * floor; the ones joined there follow). They lie on the floor of the room it
12
+ * closes, where its dashed line is drawn, and hide while a drag runs.
13
+ */
14
+ export default function SeparatorSelectionAffordance({ node, readOnly }) {
15
+ const editing = useEditor((s) => s.mode === 'select' && !s.isFloorplanHovered);
16
+ const idle = useInteractionScope((s) => s.scope.kind === 'idle');
17
+ const floor = useScene((s) => separatorFloorElevation(s.nodes, node.id));
18
+ const levelId = node.parentId;
19
+ const [level, setLevel] = useState(null);
20
+ useEffect(() => {
21
+ let frame = 0;
22
+ const resolve = () => {
23
+ const next = levelId ? (sceneRegistry.nodes.get(levelId) ?? null) : null;
24
+ setLevel((current) => (current === next ? current : next));
25
+ if (!next && levelId)
26
+ frame = window.requestAnimationFrame(resolve);
27
+ };
28
+ resolve();
29
+ return () => window.cancelAnimationFrame(frame);
30
+ }, [levelId]);
31
+ if (node.type !== 'separator' || readOnly || !editing || !idle || !level || !levelId)
32
+ return null;
33
+ const separator = node;
34
+ return createPortal(_jsxs(_Fragment, { children: [separatorPushHandles(separator, floor).map((handle) => (_jsx(WallPushArrow, { handle: handle, levelId: levelId }, handle.key))), ['start', 'end'].map((endpoint) => (_jsx(SeparatorEndGrip, { endpoint: endpoint, height: floor + 0.02, levelId: levelId, separator: separator }, endpoint)))] }), level);
35
+ }