@pascal-app/nodes 1.0.6 → 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,21 +1,25 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { DEFAULT_LEVEL_HEIGHT, planStairFlightHeightEdit, resolveStairTotalRise, stairSegmentConstructionError, stairSegmentDetailError, useScene, } from '@pascal-app/core';
3
+ import { DEFAULT_LEVEL_HEIGHT, planStairFlightHeightEdit, resolveStairTotalRise, stairSegmentConstructionError, stairSegmentDetailError, 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 { Copy, Move, Trash2 } from 'lucide-react';
7
7
  import { useCallback } from 'react';
8
8
  import { StairConstructionControls } from '../stair/construction-controls.js';
9
9
  const SEGMENT_TYPE_OPTIONS = [
10
- { label: 'Flight', value: 'stair' },
11
- { label: 'Landing', value: 'landing' },
10
+ { label: /* i18n */ { id: 'node.stairSegment.panel.flight', message: 'Flight' }, value: 'stair' },
11
+ {
12
+ label: /* i18n */ { id: 'node.stairSegment.panel.landing', message: 'Landing' },
13
+ value: 'landing',
14
+ },
12
15
  ];
13
16
  const ATTACHMENT_SIDE_OPTIONS = [
14
- { label: 'Front', value: 'front' },
15
- { label: 'Left', value: 'left' },
16
- { label: 'Right', value: 'right' },
17
+ { label: /* i18n */ { id: 'node.stairSegment.panel.front', message: 'Front' }, value: 'front' },
18
+ { label: /* i18n */ { id: 'node.stairSegment.panel.left', message: 'Left' }, value: 'left' },
19
+ { label: /* i18n */ { id: 'node.stairSegment.panel.right', message: 'Right' }, value: 'right' },
17
20
  ];
18
21
  export default function StairSegmentPanel() {
22
+ const i18n = usePascalI18n();
19
23
  const selectedId = useViewer((s) => s.selection.selectedIds[0]);
20
24
  const setSelection = useViewer((s) => s.setSelection);
21
25
  const updateNode = useScene((s) => s.updateNode);
@@ -103,7 +107,8 @@ export default function StairSegmentPanel() {
103
107
  }, [selectedId, node, setSelection]);
104
108
  if (!(node && node.type === 'stair-segment' && selectedId))
105
109
  return null;
106
- return (_jsxs(PanelWrapper, { icon: "/icons/stairs.webp", onBack: handleBack, onClose: handleClose, title: node.name || 'Stair Segment', width: 300, children: [_jsx(PanelSection, { title: "Type", children: _jsx(SegmentedControl, { onChange: (v) => {
110
+ return (_jsxs(PanelWrapper, { icon: "/icons/stairs.webp", onBack: handleBack, onClose: handleClose, title: node.name ||
111
+ i18n._({ id: 'node.stairSegment.panel.stairSegment', message: 'Stair Segment' }), width: 300, children: [_jsx(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.type', message: 'Type' }), children: _jsx(SegmentedControl, { onChange: (v) => {
107
112
  const updates = { segmentType: v };
108
113
  if (v === 'landing') {
109
114
  updates.winder = undefined;
@@ -117,7 +122,13 @@ export default function StairSegmentPanel() {
117
122
  updates.length = 3.0;
118
123
  }
119
124
  handleUpdate(updates);
120
- }, options: SEGMENT_TYPE_OPTIONS, value: node.segmentType }) }), !isFirstSegment && (_jsx(PanelSection, { title: "Attachment", children: _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ attachmentSide: v }), options: ATTACHMENT_SIDE_OPTIONS, value: node.attachmentSide }) })), (stairSegmentDetailError(node) ?? stairSegmentConstructionError(node, parentStair)) ? (_jsx("div", { role: "alert", className: "px-3 text-xs", children: stairSegmentDetailError(node) ?? stairSegmentConstructionError(node, parentStair) })) : null, node.segmentType === 'stair' && (_jsxs(PanelSection, { title: "Flight shape", children: [_jsx(SegmentedControl, { value: node.winder ? 'winder' : 'straight', onChange: (value) => handleUpdate({
125
+ }, options: SEGMENT_TYPE_OPTIONS.map((option) => ({
126
+ ...option,
127
+ label: i18n._(option.label),
128
+ })), value: node.segmentType }) }), !isFirstSegment && (_jsx(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.attachment', message: 'Attachment' }), children: _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ attachmentSide: v }), options: ATTACHMENT_SIDE_OPTIONS.map((option) => ({
129
+ ...option,
130
+ label: i18n._(option.label),
131
+ })), value: node.attachmentSide }) })), (stairSegmentDetailError(node) ?? stairSegmentConstructionError(node, parentStair)) ? (_jsx("div", { role: "alert", className: "px-3 text-xs", children: stairSegmentDetailError(node) ?? stairSegmentConstructionError(node, parentStair) })) : null, node.segmentType === 'stair' && (_jsxs(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.flightShape', message: 'Flight shape' }), children: [_jsx(SegmentedControl, { value: node.winder ? 'winder' : 'straight', onChange: (value) => handleUpdate({
121
132
  winder: value === 'winder'
122
133
  ? {
123
134
  turn: 'left',
@@ -127,15 +138,51 @@ export default function StairSegmentPanel() {
127
138
  }
128
139
  : undefined,
129
140
  }), options: [
130
- { label: 'Straight', value: 'straight' },
131
- { label: 'Winder', value: 'winder' },
141
+ {
142
+ label: i18n._({ id: 'node.stairSegment.panel.straight', message: 'Straight' }),
143
+ value: 'straight',
144
+ },
145
+ {
146
+ label: i18n._({ id: 'node.stairSegment.panel.winder', message: 'Winder' }),
147
+ value: 'winder',
148
+ },
132
149
  ] }), node.winder && (_jsxs(_Fragment, { children: [_jsx(SegmentedControl, { value: node.winder.turn, onChange: (turn) => handleUpdate({ winder: { ...node.winder, turn } }), options: [
133
- { label: 'Left turn', value: 'left' },
134
- { label: 'Right turn', value: 'right' },
135
- ] }), _jsx(SliderControl, { label: "Inner gap", unit: "m", min: 0, precision: 2, step: 0.05, value: node.winder.innerGap, onChange: (innerGap) => handleUpdate({ winder: { ...node.winder, innerGap } }) }), _jsx(SliderControl, { label: "Walking line offset", unit: "m", min: 0.001, max: node.width, precision: 2, step: 0.05, value: node.winder.walkingLineOffset, onChange: (walkingLineOffset) => handleUpdate({ winder: { ...node.winder, walkingLineOffset } }) }), _jsx(SegmentedControl, { value: node.winder.division, onChange: (division) => handleUpdate({ winder: { ...node.winder, division } }), options: [
136
- { label: 'Equal going', value: 'equal-going' },
137
- { label: 'Equal angle', value: 'equal-angle' },
138
- ] })] }))] })), _jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Width", min: 0.001, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.1, unit: "m", value: node.width }), !node.winder && (_jsx(SliderControl, { label: "Length", min: 0.001, onChange: (v) => handleUpdate({ length: v }), precision: 2, step: 0.1, unit: "m", value: node.length })), node.segmentType === 'stair' && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Height", min: 0.001, onChange: handleFlightHeightChange, precision: 2, step: 0.1, unit: "m", value: node.height }), parentFollowsLevel && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: "Editing switches the stair to Custom rise" })), _jsx(SliderControl, { label: "Steps", min: 2, onChange: (v) => handleUpdate({ stepCount: Math.round(v) }), precision: 0, step: 1, unit: "", value: node.stepCount })] }))] }), _jsx(PanelSection, { title: "Structure", children: _jsxs("div", { className: "space-y-3", children: [_jsx(StairConstructionControls, { node: node, inherited: parentConstruction, onChange: (construction) => handleUpdate({ construction }) }), !(node.construction ?? parentConstruction) ? (_jsx(ToggleControl, { checked: node.fillToFloor, label: "Fill to floor", onChange: (checked) => handleUpdate({ fillToFloor: checked }) })) : null, !(node.construction ?? parentConstruction) && !node.fillToFloor && (_jsx(SliderControl, { label: "Thickness", min: 0.001, onChange: (v) => handleUpdate({ thickness: v }), precision: 2, step: 0.05, unit: "m", value: node.thickness ?? 0.25 }))] }) }), _jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
150
+ {
151
+ label: i18n._({ id: 'node.stairSegment.panel.leftTurn', message: 'Left turn' }),
152
+ value: 'left',
153
+ },
154
+ {
155
+ label: i18n._({
156
+ id: 'node.stairSegment.panel.rightTurn',
157
+ message: 'Right turn',
158
+ }),
159
+ value: 'right',
160
+ },
161
+ ] }), _jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.innerGap', message: 'Inner gap' }), unit: "m", min: 0, precision: 2, step: 0.05, value: node.winder.innerGap, onChange: (innerGap) => handleUpdate({ winder: { ...node.winder, innerGap } }) }), _jsx(SliderControl, { label: i18n._({
162
+ id: 'node.stairSegment.panel.walkingLineOffset',
163
+ message: 'Walking line offset',
164
+ }), unit: "m", min: 0.001, max: node.width, precision: 2, step: 0.05, value: node.winder.walkingLineOffset, onChange: (walkingLineOffset) => handleUpdate({ winder: { ...node.winder, walkingLineOffset } }) }), _jsx(SegmentedControl, { value: node.winder.division, onChange: (division) => handleUpdate({ winder: { ...node.winder, division } }), options: [
165
+ {
166
+ label: i18n._({
167
+ id: 'node.stairSegment.panel.equalGoing',
168
+ message: 'Equal going',
169
+ }),
170
+ value: 'equal-going',
171
+ },
172
+ {
173
+ label: i18n._({
174
+ id: 'node.stairSegment.panel.equalAngle',
175
+ message: 'Equal angle',
176
+ }),
177
+ value: 'equal-angle',
178
+ },
179
+ ] })] }))] })), _jsxs(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.dimensions', message: 'Dimensions' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.width', message: 'Width' }), min: 0.001, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.1, unit: "m", value: node.width }), !node.winder && (_jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.length', message: 'Length' }), min: 0.001, onChange: (v) => handleUpdate({ length: v }), precision: 2, step: 0.1, unit: "m", value: node.length })), node.segmentType === 'stair' && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.height', message: 'Height' }), min: 0.001, onChange: handleFlightHeightChange, precision: 2, step: 0.1, unit: "m", value: node.height }), parentFollowsLevel && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: i18n._({
180
+ id: 'node.stairSegment.panel.editingSwitchesTheStairToCustom',
181
+ message: 'Editing switches the stair to Custom rise',
182
+ }) })), _jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.steps', message: 'Steps' }), min: 2, onChange: (v) => handleUpdate({ stepCount: Math.round(v) }), precision: 0, step: 1, unit: "", value: node.stepCount })] }))] }), _jsx(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.structure', message: 'Structure' }), children: _jsxs("div", { className: "space-y-3", children: [_jsx(StairConstructionControls, { node: node, inherited: parentConstruction, onChange: (construction) => handleUpdate({ construction }) }), !(node.construction ?? parentConstruction) ? (_jsx(ToggleControl, { checked: node.fillToFloor, label: i18n._({
183
+ id: 'node.stairSegment.panel.fillToFloor',
184
+ message: 'Fill to floor',
185
+ }), onChange: (checked) => handleUpdate({ fillToFloor: checked }) })) : null, !(node.construction ?? parentConstruction) && !node.fillToFloor && (_jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.thickness', message: 'Thickness' }), min: 0.001, onChange: (v) => handleUpdate({ thickness: v }), precision: 2, step: 0.05, unit: "m", value: node.thickness ?? 0.25 }))] }) }), _jsxs(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.position', message: 'Position' }), children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
139
186
  const pos = [...node.position];
140
187
  pos[0] = v;
141
188
  handleUpdate({ position: pos });
@@ -147,7 +194,7 @@ export default function StairSegmentPanel() {
147
194
  const pos = [...node.position];
148
195
  pos[2] = v;
149
196
  handleUpdate({ position: pos });
150
- }, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), _jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (degrees) => {
197
+ }, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), _jsx(SliderControl, { label: i18n._({ id: 'node.stairSegment.panel.rotation', message: 'Rotation' }), max: 180, min: -180, onChange: (degrees) => {
151
198
  handleUpdate({ rotation: (degrees * Math.PI) / 180 });
152
199
  }, 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: () => {
153
200
  triggerSFX('sfx:item-rotate');
@@ -155,5 +202,5 @@ export default function StairSegmentPanel() {
155
202
  } }), _jsx(ActionButton, { label: "+45\u00B0", onClick: () => {
156
203
  triggerSFX('sfx:item-rotate');
157
204
  handleUpdate({ rotation: node.rotation + Math.PI / 4 });
158
- } })] })] }), _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 })] }) })] }));
205
+ } })] })] }), _jsx(PanelSection, { title: i18n._({ id: 'node.stairSegment.panel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.stairSegment.panel.move', message: 'Move' }), onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.stairSegment.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.stairSegment.panel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
159
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/turbine-vent/panel.tsx"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCAyRvC"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/turbine-vent/panel.tsx"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCA4SvC"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { getActiveRoofHeight, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
3
+ import { getActiveRoofHeight, useLiveNodeOverrides, usePascalI18n, useScene, } from '@pascal-app/core';
4
4
  import { ActionButton, ActionGroup, duplicateNodeAndPickUp, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Copy, Move, Pause, Play, Trash2 } from 'lucide-react';
@@ -15,6 +15,7 @@ const DEFAULT_SPIN_SPEED = 0.8;
15
15
  * Mirrors the box-vent panel.
16
16
  */
17
17
  export default function TurbineVentPanel() {
18
+ const i18n = usePascalI18n();
18
19
  const selectedId = useViewer((s) => s.selection.selectedIds[0]);
19
20
  const setSelection = useViewer((s) => s.setSelection);
20
21
  const updateNode = useScene((s) => s.updateNode);
@@ -102,8 +103,16 @@ export default function TurbineVentPanel() {
102
103
  }, [node, handleUpdate]);
103
104
  if (!(node && node.type === 'turbine-vent' && selectedId))
104
105
  return null;
105
- return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: node.roofSegmentId ? handleBack : undefined, onClose: handleClose, title: node.name || 'Turbine Vent', width: 300, children: [_jsx(PanelSection, { title: "Style", children: _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ style: v }), options: [
106
- { label: 'Globe', value: 'globe' },
107
- { label: 'Cylinder', value: 'cylinder' },
108
- ], value: node.style ?? 'globe' }) }), _jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Diameter", max: 1000, min: 0.15, onChange: (v) => previewProp({ diameter: v }), onCommit: (v) => handleUpdate({ diameter: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.diameter }), _jsx(SliderControl, { label: "Height", max: 1000, min: 0.2, onChange: (v) => previewProp({ height: v }), onCommit: (v) => handleUpdate({ height: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.height }), _jsx(SliderControl, { label: "Neck Height", max: Math.max(0.04, node.height * 0.5), min: 0.02, onChange: (v) => previewProp({ neckHeight: v }), onCommit: (v) => handleUpdate({ neckHeight: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.neckHeight ?? 0.09 }), _jsx(SliderControl, { label: "Vanes", max: 36, min: 6, onChange: (v) => previewProp({ vaneCount: Math.round(v) }), onCommit: (v) => handleUpdate({ vaneCount: Math.round(v) }), precision: 0, restoreOnCommit: false, step: 1, unit: "", value: Math.round(node.vaneCount ?? 20) })] }), _jsxs(PanelSection, { title: "Motion", children: [_jsx(ActionGroup, { children: _jsx(ActionButton, { icon: isSpinning ? _jsx(Pause, { className: "h-3.5 w-3.5" }) : _jsx(Play, { className: "h-3.5 w-3.5" }), label: isSpinning ? 'Pause' : 'Play', onClick: handleToggleSpin }) }), _jsx(SliderControl, { label: "Spin Speed", max: 4, min: 0, onChange: (v) => previewProp({ spinSpeed: v }), onCommit: (v) => handleUpdate({ spinSpeed: v }), precision: 1, restoreOnCommit: false, step: 0.1, unit: "rad/s", value: Math.round((node.spinSpeed ?? 0) * 10) / 10 })] }), _jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: "X", max: Math.round(((segment?.width ?? 10) / 2) * 100) / 100, min: -Math.round(((segment?.width ?? 10) / 2) * 100) / 100, onChange: (v) => previewProp({ position: [v, node.position[1] ?? 0, node.position[2] ?? 0] }), onCommit: (v) => handleUpdate({ position: [v, node.position[1] ?? 0, node.position[2] ?? 0] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[0] ?? 0 }), _jsx(SliderControl, { label: "Y", max: Math.max((segment?.wallHeight ?? 3) + (segment ? getActiveRoofHeight(segment) : 3) + 2, (node.position[1] ?? 0) + 0.1), min: Math.min(0, (node.position[1] ?? 0) - 0.5), onChange: (v) => previewProp({ position: [node.position[0] ?? 0, v, node.position[2] ?? 0] }), onCommit: (v) => handleUpdate({ position: [node.position[0] ?? 0, v, node.position[2] ?? 0] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[1] ?? 0 }), _jsx(SliderControl, { label: "Z", max: Math.round(((segment?.depth ?? 10) / 2) * 100) / 100, min: -Math.round(((segment?.depth ?? 10) / 2) * 100) / 100, onChange: (v) => previewProp({ position: [node.position[0] ?? 0, node.position[1] ?? 0, v] }), onCommit: (v) => handleUpdate({ position: [node.position[0] ?? 0, node.position[1] ?? 0, v] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[2] ?? 0 }), _jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (deg) => previewProp({ rotation: (deg * Math.PI) / 180 }), onCommit: (deg) => handleUpdate({ rotation: (deg * Math.PI) / 180 }), precision: 0, restoreOnCommit: false, step: 1, unit: "\u00B0", value: Math.round(((node.rotation ?? 0) * 180) / Math.PI) })] }), _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 })] }) })] }));
106
+ return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: node.roofSegmentId ? handleBack : undefined, onClose: handleClose, title: node.name || i18n._({ id: 'node.turbineVent.panel.turbineVent', message: 'Turbine Vent' }), width: 300, children: [_jsx(PanelSection, { title: i18n._({ id: 'node.turbineVent.panel.style', message: 'Style' }), children: _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ style: v }), options: [
107
+ {
108
+ label: i18n._({ id: 'node.turbineVent.panel.globe', message: 'Globe' }),
109
+ value: 'globe',
110
+ },
111
+ {
112
+ label: i18n._({ id: 'node.turbineVent.panel.cylinder', message: 'Cylinder' }),
113
+ value: 'cylinder',
114
+ },
115
+ ], value: node.style ?? 'globe' }) }), _jsxs(PanelSection, { title: i18n._({ id: 'node.turbineVent.panel.dimensions', message: 'Dimensions' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.diameter', message: 'Diameter' }), max: 1000, min: 0.15, onChange: (v) => previewProp({ diameter: v }), onCommit: (v) => handleUpdate({ diameter: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.diameter }), _jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.height', message: 'Height' }), max: 1000, min: 0.2, onChange: (v) => previewProp({ height: v }), onCommit: (v) => handleUpdate({ height: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.height }), _jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.neckHeight', message: 'Neck Height' }), max: Math.max(0.04, node.height * 0.5), min: 0.02, onChange: (v) => previewProp({ neckHeight: v }), onCommit: (v) => handleUpdate({ neckHeight: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.neckHeight ?? 0.09 }), _jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.vanes', message: 'Vanes' }), max: 36, min: 6, onChange: (v) => previewProp({ vaneCount: Math.round(v) }), onCommit: (v) => handleUpdate({ vaneCount: Math.round(v) }), precision: 0, restoreOnCommit: false, step: 1, unit: "", value: Math.round(node.vaneCount ?? 20) })] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.turbineVent.panel.motion', message: 'Motion' }), children: [_jsx(ActionGroup, { children: _jsx(ActionButton, { icon: isSpinning ? _jsx(Pause, { className: "h-3.5 w-3.5" }) : _jsx(Play, { className: "h-3.5 w-3.5" }), label: isSpinning
116
+ ? i18n._({ id: 'node.turbineVent.panel.pause', message: 'Pause' })
117
+ : i18n._({ id: 'node.turbineVent.panel.play', message: 'Play' }), onClick: handleToggleSpin }) }), _jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.spinSpeed', message: 'Spin Speed' }), max: 4, min: 0, onChange: (v) => previewProp({ spinSpeed: v }), onCommit: (v) => handleUpdate({ spinSpeed: v }), precision: 1, restoreOnCommit: false, step: 0.1, unit: "rad/s", value: Math.round((node.spinSpeed ?? 0) * 10) / 10 })] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.turbineVent.panel.position', message: 'Position' }), children: [_jsx(SliderControl, { label: "X", max: Math.round(((segment?.width ?? 10) / 2) * 100) / 100, min: -Math.round(((segment?.width ?? 10) / 2) * 100) / 100, onChange: (v) => previewProp({ position: [v, node.position[1] ?? 0, node.position[2] ?? 0] }), onCommit: (v) => handleUpdate({ position: [v, node.position[1] ?? 0, node.position[2] ?? 0] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[0] ?? 0 }), _jsx(SliderControl, { label: "Y", max: Math.max((segment?.wallHeight ?? 3) + (segment ? getActiveRoofHeight(segment) : 3) + 2, (node.position[1] ?? 0) + 0.1), min: Math.min(0, (node.position[1] ?? 0) - 0.5), onChange: (v) => previewProp({ position: [node.position[0] ?? 0, v, node.position[2] ?? 0] }), onCommit: (v) => handleUpdate({ position: [node.position[0] ?? 0, v, node.position[2] ?? 0] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[1] ?? 0 }), _jsx(SliderControl, { label: "Z", max: Math.round(((segment?.depth ?? 10) / 2) * 100) / 100, min: -Math.round(((segment?.depth ?? 10) / 2) * 100) / 100, onChange: (v) => previewProp({ position: [node.position[0] ?? 0, node.position[1] ?? 0, v] }), onCommit: (v) => handleUpdate({ position: [node.position[0] ?? 0, node.position[1] ?? 0, v] }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[2] ?? 0 }), _jsx(SliderControl, { label: i18n._({ id: 'node.turbineVent.panel.rotation', message: 'Rotation' }), max: 180, min: -180, onChange: (deg) => previewProp({ rotation: (deg * Math.PI) / 180 }), onCommit: (deg) => handleUpdate({ rotation: (deg * Math.PI) / 180 }), precision: 0, restoreOnCommit: false, step: 1, unit: "\u00B0", value: Math.round(((node.rotation ?? 0) * 180) / Math.PI) })] }), _jsx(PanelSection, { title: i18n._({ id: 'node.turbineVent.panel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.turbineVent.panel.move', message: 'Move' }), onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.turbineVent.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.turbineVent.panel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
109
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"unit-panel.d.ts","sourceRoot":"","sources":["../../src/unit/unit-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,QAAQ,EAGd,MAAM,kBAAkB,CAAA;AAgCzB,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,+BA2J7D"}
1
+ {"version":3,"file":"unit-panel.d.ts","sourceRoot":"","sources":["../../src/unit/unit-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAA;AA+BzB,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,+BA4L7D"}
@@ -1,22 +1,22 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { buildUnitReport, getLevelDisplayName, UNIT_KINDS, unitWarnings, useScene, } from '@pascal-app/core';
4
- import { ActionButton, ActionGroup, formatAreaLabel, PanelSection, PanelWrapper, triggerSFX, } from '@pascal-app/editor';
3
+ import { buildUnitReport, getLevelDisplayName, UNIT_KINDS, unitWarnings, usePascalI18n, useScene, } from '@pascal-app/core';
4
+ import { ActionButton, ActionGroup, displayRoomName, formatAreaLabel, PanelSection, PanelWrapper, triggerSFX, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { Trash2, X } from 'lucide-react';
7
7
  import { useCallback, useMemo } from 'react';
8
8
  import { PanelSelect, PanelTextField } from '../shared/panel-fields.js';
9
9
  const UNIT_KIND_LABELS = {
10
- apartment: 'Apartment',
11
- 'hotel-room': 'Hotel room',
12
- commercial: 'Commercial',
13
- common: 'Common',
10
+ apartment: /* i18n */ { id: 'node.unit.kind.apartment', message: 'Apartment' },
11
+ 'hotel-room': /* i18n */ { id: 'node.unit.kind.hotelRoom', message: 'Hotel room' },
12
+ commercial: /* i18n */ { id: 'node.unit.kind.commercial', message: 'Commercial' },
13
+ common: /* i18n */ { id: 'node.unit.kind.common', message: 'Common' },
14
14
  };
15
- const UNIT_KIND_OPTIONS = UNIT_KINDS.map((value) => ({ label: UNIT_KIND_LABELS[value], value }));
16
15
  function ReportRow({ label, value }) {
17
16
  return (_jsxs("div", { className: "flex items-baseline gap-2 rounded-md border border-border/50 bg-background/35 px-2.5 py-2 text-xs", children: [_jsx("span", { className: "text-muted-foreground", children: label }), _jsx("span", { className: "ml-auto font-mono font-medium text-foreground tabular-nums", children: value })] }));
18
17
  }
19
18
  export default function UnitPanel({ node }) {
19
+ const i18n = usePascalI18n();
20
20
  const nodes = useScene((state) => state.nodes);
21
21
  const updateNode = useScene((state) => state.updateNode);
22
22
  const setSelection = useViewer((state) => state.setSelection);
@@ -53,14 +53,30 @@ export default function UnitPanel({ node }) {
53
53
  }, [node.id, setSelection]);
54
54
  const warningMessages = warnings.map((warning) => {
55
55
  if (warning.code === 'non-adjacent-levels') {
56
- return 'Members sit on levels that are not adjacent.';
56
+ return i18n._({
57
+ id: 'node.unit.panel.nonAdjacentLevels',
58
+ message: 'Members sit on levels that are not adjacent.',
59
+ });
57
60
  }
58
- return 'No zones assigned yet.';
61
+ return i18n._({ id: 'node.unit.panel.noZonesAssigned', message: 'No zones assigned yet.' });
59
62
  });
60
- return (_jsxs(PanelWrapper, { icon: "/icons/zone.webp", onClose: handleClose, title: node.name || 'Unit', width: 320, children: [_jsxs(PanelSection, { title: "Unit", children: [_jsx(PanelTextField, { label: "Name", onCommit: (name) => update({ name }), value: node.name }), _jsx(PanelSelect, { label: "Kind", onChange: (kind) => update({ kind: kind }), options: UNIT_KIND_OPTIONS, value: node.kind }), _jsxs("label", { className: "flex h-10 items-center justify-between gap-3 rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Color" }), _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-muted-foreground text-xs", children: node.color }), _jsx("input", { className: "h-6 w-8 cursor-pointer rounded border border-border/50 bg-transparent", onChange: (event) => update({ color: event.target.value }), type: "color", value: node.color })] })] })] }), _jsxs(PanelSection, { title: "Members", children: [report.members.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs leading-snug", children: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused." })) : (report.members.map((member) => (_jsxs("div", { className: "flex h-9 items-center gap-2 rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 text-xs", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-foreground", children: member.name || memberFallbackName(nodes, member.zoneId) }), _jsx("span", { className: "shrink-0 truncate text-muted-foreground", children: member.levelId ? levelNameById.get(member.levelId) : '' }), _jsx("span", { className: "shrink-0 font-mono text-muted-foreground tabular-nums", children: formatAreaLabel(member.areaM2, areaUnit, 1) }), _jsx("button", { "aria-label": `Remove ${member.name || 'zone'} from unit`, className: "shrink-0 rounded-full p-1 text-muted-foreground transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e] hover:text-foreground", onClick: () => removeMember(member.zoneId), type: "button", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }, member.zoneId)))), warningMessages.length > 0 ? (_jsx("ul", { className: "flex flex-col gap-1 text-amber-700 dark:text-amber-300 text-xs leading-snug", children: warningMessages.map((message, index) => (_jsx("li", { children: message }, warnings[index]?.code))) })) : null] }), _jsxs(PanelSection, { title: "Report", children: [_jsx(ReportRow, { label: "Members", value: String(report.memberCount) }), _jsx(ReportRow, { label: "Levels", value: levelSpanLabel }), _jsx(ReportRow, { label: "Gross area", value: formatAreaLabel(report.grossAreaM2, areaUnit, 2) })] }), _jsx(PanelSection, { title: "Actions", children: _jsxs(ActionGroup, { children: [focusedUnitId !== node.id && (_jsx(ActionButton, { className: "rounded-full", label: "Focus", onClick: () => useViewer.getState().setFocusedUnit(node.id) })), _jsx(ActionButton, { className: "text-destructive hover:text-destructive", icon: _jsx(Trash2, { className: "h-3.5 w-3.5" }), label: "Delete", onClick: handleDelete })] }) })] }));
63
+ return (_jsxs(PanelWrapper, { icon: "/icons/zone.webp", onClose: handleClose, title: node.name || i18n._({ id: 'node.unit.unitPanel.unit', message: 'Unit' }), width: 320, children: [_jsxs(PanelSection, { title: i18n._({ id: 'node.unit.unitPanel.unit', message: 'Unit' }), children: [_jsx(PanelTextField, { label: i18n._({ id: 'node.unit.unitPanel.name', message: 'Name' }), onCommit: (name) => update({ name }), value: node.name }), _jsx(PanelSelect, { label: i18n._({ id: 'node.unit.unitPanel.kind', message: 'Kind' }), onChange: (kind) => update({ kind: kind }), options: UNIT_KINDS.map((value) => ({ label: i18n._(UNIT_KIND_LABELS[value]), value })), value: node.kind }), _jsxs("label", { className: "flex h-10 items-center justify-between gap-3 rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.unit.unitPanel.color', message: 'Color' }) }), _jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-muted-foreground text-xs", children: node.color }), _jsx("input", { className: "h-6 w-8 cursor-pointer rounded border border-border/50 bg-transparent", onChange: (event) => update({ color: event.target.value }), type: "color", value: node.color })] })] })] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.unit.unitPanel.members', message: 'Members' }), children: [report.members.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs leading-snug", children: i18n._({
64
+ id: 'node.unit.unitPanel.noRoomsYetPickThisUnit',
65
+ message: "No rooms yet. Pick this unit from a room's panel, or draw zones while it is focused.",
66
+ }) })) : (report.members.map((member) => (_jsxs("div", { className: "flex h-9 items-center gap-2 rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 text-xs", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-foreground", children: member.name
67
+ ? displayRoomName(member.name, i18n)
68
+ : memberFallbackName(nodes, member.zoneId, i18n) }), _jsx("span", { className: "shrink-0 truncate text-muted-foreground", children: member.levelId ? levelNameById.get(member.levelId) : '' }), _jsx("span", { className: "shrink-0 font-mono text-muted-foreground tabular-nums", children: formatAreaLabel(member.areaM2, areaUnit, 1) }), _jsx("button", { "aria-label": member.name
69
+ ? i18n._({
70
+ id: 'node.unit.panel.removeMember',
71
+ message: 'Remove {name} from unit',
72
+ values: { name: displayRoomName(member.name, i18n) },
73
+ })
74
+ : i18n._({ id: 'node.unit.panel.removeZone', message: 'Remove zone from unit' }), className: "shrink-0 rounded-full p-1 text-muted-foreground transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e] hover:text-foreground", onClick: () => removeMember(member.zoneId), type: "button", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] }, member.zoneId)))), warningMessages.length > 0 ? (_jsx("ul", { className: "flex flex-col gap-1 text-amber-700 dark:text-amber-300 text-xs leading-snug", children: warningMessages.map((message, index) => (_jsx("li", { children: message }, warnings[index]?.code))) })) : null] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.unit.unitPanel.report', message: 'Report' }), children: [_jsx(ReportRow, { label: i18n._({ id: 'node.unit.unitPanel.members', message: 'Members' }), value: String(report.memberCount) }), _jsx(ReportRow, { label: i18n._({ id: 'node.unit.unitPanel.levels', message: 'Levels' }), value: levelSpanLabel }), _jsx(ReportRow, { label: i18n._({ id: 'node.unit.unitPanel.grossArea', message: 'Gross area' }), value: formatAreaLabel(report.grossAreaM2, areaUnit, 2) })] }), _jsx(PanelSection, { title: i18n._({ id: 'node.unit.unitPanel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [focusedUnitId !== node.id && (_jsx(ActionButton, { className: "rounded-full", label: i18n._({ id: 'node.unit.unitPanel.focus', message: 'Focus' }), onClick: () => useViewer.getState().setFocusedUnit(node.id) })), _jsx(ActionButton, { className: "text-destructive hover:text-destructive", icon: _jsx(Trash2, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.unit.unitPanel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
61
75
  }
62
76
  /** An unnamed member reads as what it is: a room, or another zone. */
63
- function memberFallbackName(nodes, zoneId) {
77
+ function memberFallbackName(nodes, zoneId, i18n) {
64
78
  const zone = nodes[zoneId];
65
- return zone?.type === 'zone' && zone.spaceRole === 'room' ? 'Room' : 'Zone';
79
+ return zone?.type === 'zone' && zone.spaceRole === 'room'
80
+ ? i18n._({ id: 'node.unit.panel.memberRoom', message: 'Room' })
81
+ : i18n._({ id: 'node.unit.panel.memberZone', message: 'Zone' });
66
82
  }
@@ -1,3 +1,3 @@
1
- /** The wall's action-menu contributions: Split (one wall) and Merge (several). */
1
+ /** The wall's action-menu contributions: Split (one wall), Merge (several). */
2
2
  export default function WallActions(): import("react").JSX.Element;
3
3
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/wall/actions.tsx"],"names":[],"mappings":"AAuBA,kFAAkF;AAClF,MAAM,CAAC,OAAO,UAAU,WAAW,gCAOlC"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/wall/actions.tsx"],"names":[],"mappings":"AAmBA,+EAA+E;AAC/E,MAAM,CAAC,OAAO,UAAU,WAAW,gCAOlC"}
@@ -1,33 +1,35 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { planWallMerge, runAsSingleSceneHistoryStep, useScene, } from '@pascal-app/core';
4
- import { captureElementActionOrigin, completeElementAction, Tooltip, TooltipContent, TooltipTrigger, triggerSFX, } from '@pascal-app/editor';
3
+ import { planWallMerge, runAsSingleSceneHistoryStep, usePascalI18n, useScene, } from '@pascal-app/core';
4
+ import { ActionMenuButton, captureElementActionOrigin, completeElementAction, triggerSFX, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { FoldHorizontal, Scissors } from 'lucide-react';
7
7
  import { useMemo } from 'react';
8
8
  import { openWallSplit } from './split-session.js';
9
- const BUTTON = 'tooltip-trigger rounded-md p-1.5 text-muted-foreground hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50';
10
- /** The wall's action-menu contributions: Split (one wall) and Merge (several). */
9
+ /** The wall's action-menu contributions: Split (one wall), Merge (several). */
11
10
  export default function WallActions() {
12
11
  return (_jsxs(_Fragment, { children: [_jsx(SplitWallAction, {}), _jsx(MergeWallsAction, {})] }));
13
12
  }
14
13
  function SplitWallAction() {
14
+ const i18n = usePascalI18n();
15
15
  const selected = useViewer((s) => s.selection.selectedIds);
16
16
  const wall = useScene((s) => selected.length === 1 ? s.nodes[selected[0]] : undefined);
17
17
  const readOnly = useScene((s) => s.readOnly);
18
18
  if (wall?.type !== 'wall')
19
19
  return null;
20
- return (_jsx("button", { type: "button", "aria-label": "Split wall", title: "Split wall", disabled: readOnly, className: BUTTON, onClick: (event) => {
20
+ return (_jsx(ActionMenuButton, { disabled: readOnly, label: i18n._({ id: 'node.wall.actions.splitWall', message: 'Split wall' }), onClick: (event) => {
21
21
  event.stopPropagation();
22
22
  openWallSplit(wall);
23
23
  }, children: _jsx(Scissors, { className: "size-4" }) }));
24
24
  }
25
25
  /** Joins selected walls that continue each other into one — the inverse of Split. */
26
26
  function MergeWallsAction() {
27
+ const i18n = usePascalI18n();
27
28
  const selected = useViewer((s) => s.selection.selectedIds);
28
29
  const nodes = useScene((s) => s.nodes);
29
30
  const readOnly = useScene((s) => s.readOnly);
30
- // null: not a wall selection (render nothing); otherwise why it can't merge, or null.
31
+ // null: not a wall selection (render nothing); otherwise why it can't merge (undefined when the
32
+ // plan gave no reason of its own), or null.
31
33
  const merge = useMemo(() => {
32
34
  if (selected.length < 2 || selected.some((id) => nodes[id]?.type !== 'wall'))
33
35
  return null;
@@ -36,13 +38,19 @@ function MergeWallsAction() {
36
38
  return { reason: null };
37
39
  }
38
40
  catch (error) {
39
- return { reason: error instanceof Error ? error.message : 'These walls cannot be merged.' };
41
+ return { reason: error instanceof Error ? error.message : undefined };
40
42
  }
41
43
  }, [nodes, selected]);
42
44
  if (!merge)
43
45
  return null;
44
- const { reason } = merge;
45
- const button = (_jsx("button", { type: "button", "aria-label": "Merge walls", title: reason ? undefined : 'Merge walls', disabled: readOnly || reason !== null, className: BUTTON, onClick: (event) => {
46
+ // Worded here rather than in the memo, so a change of language reaches it.
47
+ const reason = merge.reason === undefined
48
+ ? i18n._({
49
+ id: 'node.wall.actions.theseWallsCannotBeMerged',
50
+ message: 'These walls cannot be merged.',
51
+ })
52
+ : merge.reason;
53
+ return (_jsx(ActionMenuButton, { disabled: readOnly || reason !== null, disabledReason: reason ?? undefined, label: i18n._({ id: 'node.wall.actions.mergeWalls', message: 'Merge walls' }), onClick: (event) => {
46
54
  event.stopPropagation();
47
55
  const plan = planWallMerge(useScene.getState().nodes, selected);
48
56
  // Walls drilled from one room go back to it; otherwise the merged wall stays selected.
@@ -54,8 +62,4 @@ function MergeWallsAction() {
54
62
  else
55
63
  useViewer.getState().setSelection({ selectedIds: [plan.wallId] });
56
64
  }, children: _jsx(FoldHorizontal, { className: "size-4" }) }));
57
- if (!reason)
58
- return button;
59
- // A disabled button gets no hover events, so the reason hangs off a wrapper.
60
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "inline-flex", children: button }) }), _jsx(TooltipContent, { side: "top", children: reason })] }));
61
65
  }
@@ -3,6 +3,12 @@ import { type ConstructionDimensionDrawingStandard } from '../shared/constructio
3
3
  import { type ConstructionLengthProfile, type ConstructionLinearUnit } from '../shared/construction-length.js';
4
4
  export { formatConstructionLength } from '../shared/construction-length.js';
5
5
  export type ConstructionDimensionTier = 'opening-widths' | 'openings' | 'partitions' | 'structure' | 'jogs' | 'overall' | 'structural-overall' | 'interior' | 'interior-overall';
6
+ /**
7
+ * Which face chain a tier belongs to: the clear spans drawn inside the rooms
8
+ * are interior (ID); the facade strings — openings, partitions, columns, jogs
9
+ * and the overall sizes — are measured outside the building (OD).
10
+ */
11
+ export declare function constructionDimensionFace(tier: ConstructionDimensionTier): 'interior' | 'exterior';
6
12
  export type PlannedConstructionDimension = {
7
13
  tier: ConstructionDimensionTier;
8
14
  start: FloorplanPoint;
@@ -1 +1 @@
1
- {"version":3,"file":"construction-dimensions.d.ts","sourceRoot":"","sources":["../../src/wall/construction-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGZ,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,EAMpB,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,KAAK,oCAAoC,EAE1C,MAAM,4CAA4C,CAAA;AACnD,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAE5B,MAAM,+BAA+B,CAAA;AAItC,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAUxE,MAAM,MAAM,yBAAyB,GACjC,gBAAgB,GAChB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,MAAM,GACN,SAAS,GACT,oBAAoB,GACpB,UAAU,GACV,kBAAkB,CAAA;AAYtB,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,yBAAyB,CAAA;IAC/B,KAAK,EAAE,cAAc,CAAA;IACrB,GAAG,EAAE,cAAc,CAAA;IACnB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,YAAY,CAAC,EAAE,cAAc,CAAA;IAC7B,YAAY,EAAE,cAAc,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,6BAA6B,GAAG,WAAW,CACrD,MAAM,EACN,SAAS,4BAA4B,EAAE,CACxC,CAAA;AAiBD,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,GAAE,oCAA8E,GACvF,6BAA6B,CA6L/B;AAmGD,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,SAAS,4BAA4B,EAAE,EAChD,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,yBAAoC,EAC7C,QAAQ,GAAE,oCAA8E,GACvF,iBAAiB,EAAE,CA2BrB;AAmCD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,QAAQ,EACd,EACE,IAAI,EACJ,MAAM,EACN,OAAkB,EAClB,QAAkD,EAClD,QAAa,GACd,EAAE;IACD,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,QAAQ,CAAC,EAAE,oCAAoC,CAAA;IAC/C,QAAQ,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;CACnC,GACA,iBAAiB,EAAE,CA+CrB;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,EACpB,EACE,IAAI,EACJ,MAAM,EACN,OAAkB,EAClB,QAAkD,GACnD,EAAE;IACD,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,QAAQ,CAAC,EAAE,oCAAoC,CAAA;CAChD,GACA,iBAAiB,EAAE,CAsErB"}
1
+ {"version":3,"file":"construction-dimensions.d.ts","sourceRoot":"","sources":["../../src/wall/construction-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGZ,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,EAMpB,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,KAAK,oCAAoC,EAE1C,MAAM,4CAA4C,CAAA;AACnD,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAE5B,MAAM,+BAA+B,CAAA;AAItC,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAUxE,MAAM,MAAM,yBAAyB,GACjC,gBAAgB,GAChB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,MAAM,GACN,SAAS,GACT,oBAAoB,GACpB,UAAU,GACV,kBAAkB,CAAA;AAEtB;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,yBAAyB,GAC9B,UAAU,GAAG,UAAU,CAEzB;AAYD,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,yBAAyB,CAAA;IAC/B,KAAK,EAAE,cAAc,CAAA;IACrB,GAAG,EAAE,cAAc,CAAA;IACnB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,YAAY,CAAC,EAAE,cAAc,CAAA;IAC7B,YAAY,EAAE,cAAc,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,6BAA6B,GAAG,WAAW,CACrD,MAAM,EACN,SAAS,4BAA4B,EAAE,CACxC,CAAA;AAiBD,wBAAgB,uCAAuC,CACrD,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,GAAE,oCAA8E,GACvF,6BAA6B,CA6L/B;AAmGD,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,SAAS,4BAA4B,EAAE,EAChD,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,yBAAoC,EAC7C,QAAQ,GAAE,oCAA8E,GACvF,iBAAiB,EAAE,CA2BrB;AAmCD,wBAAgB,qCAAqC,CACnD,IAAI,EAAE,QAAQ,EACd,EACE,IAAI,EACJ,MAAM,EACN,OAAkB,EAClB,QAAkD,EAClD,QAAa,GACd,EAAE;IACD,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,QAAQ,CAAC,EAAE,oCAAoC,CAAA;IAC/C,QAAQ,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;CACnC,GACA,iBAAiB,EAAE,CA+CrB;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,EACpB,EACE,IAAI,EACJ,MAAM,EACN,OAAkB,EAClB,QAAkD,GACnD,EAAE;IACD,IAAI,EAAE,sBAAsB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,yBAAyB,CAAA;IACnC,QAAQ,CAAC,EAAE,oCAAoC,CAAA;CAChD,GACA,iBAAiB,EAAE,CAsErB"}
@@ -10,6 +10,14 @@ const FACADE_LINE_TOLERANCE = 0.03;
10
10
  const FACADE_DIRECTION_TOLERANCE = 0.001;
11
11
  const COLUMN_ROW_TOLERANCE = 0.05;
12
12
  const EXTERIOR_CORNER_DATUM_POLICY = 'structural-face';
13
+ /**
14
+ * Which face chain a tier belongs to: the clear spans drawn inside the rooms
15
+ * are interior (ID); the facade strings — openings, partitions, columns, jogs
16
+ * and the overall sizes — are measured outside the building (OD).
17
+ */
18
+ export function constructionDimensionFace(tier) {
19
+ return tier === 'interior' || tier === 'interior-overall' ? 'interior' : 'exterior';
20
+ }
13
21
  const TIER_ORDER = [
14
22
  'opening-widths',
15
23
  'openings',
@@ -7,6 +7,12 @@ type OpeningDimensionOptions = {
7
7
  showClearancesWhileMoving: boolean;
8
8
  useExteriorNormal: boolean;
9
9
  };
10
+ /**
11
+ * A selected wall's length, to its faces rather than its centerline: the
12
+ * interior face (ID) on the room side and the exterior face (OD) outside, as
13
+ * the dimension-faces preference asks. An interior partition has no outside,
14
+ * so it shows its clear span between the walls it runs to.
15
+ */
10
16
  export declare function buildWallContextualDimensions(node: WallNode, ctx: GeometryContext): FloorplanGeometry | null;
11
17
  export declare function buildWallHostedOpeningContextualDimensions(node: WallHostedOpening, ctx: GeometryContext, options: OpeningDimensionOptions): FloorplanGeometry | null;
12
18
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"contextual-dimensions.d.ts","sourceRoot":"","sources":["../../src/wall/contextual-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAKpB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAGzB,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,uBAAuB,GAAG;IAC7B,yBAAyB,EAAE,OAAO,CAAA;IAClC,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AA+ID,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CA8C1B;AAED,wBAAgB,0CAA0C,CACxD,IAAI,EAAE,iBAAiB,EACvB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,uBAAuB,GAC/B,iBAAiB,GAAG,IAAI,CAyE1B"}
1
+ {"version":3,"file":"contextual-dimensions.d.ts","sourceRoot":"","sources":["../../src/wall/contextual-dimensions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,eAAe,EAKpB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAOzB,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,uBAAuB,GAAG;IAC7B,yBAAyB,EAAE,OAAO,CAAA;IAClC,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAgOD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,eAAe,GACnB,iBAAiB,GAAG,IAAI,CAiD1B;AAED,wBAAgB,0CAA0C,CACxD,IAAI,EAAE,iBAAiB,EACvB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,uBAAuB,GAC/B,iBAAiB,GAAG,IAAI,CAyE1B"}
@@ -1,5 +1,5 @@
1
1
  import { getWallCurveFrameAt, getWallCurveLength, getWallFaceOffsets, isCurvedWall, } from '@pascal-app/core';
2
- import { formatLinearMeasurement, readFloorplanMetricNotationOverride } from '@pascal-app/editor';
2
+ import { formatLinearMeasurement, readFloorplanContext, readFloorplanMetricNotationOverride, } from '@pascal-app/editor';
3
3
  const WALL_CONNECTION_TOLERANCE = 0.03;
4
4
  function formatLength(value, ctx) {
5
5
  return formatLinearMeasurement(value, ctx.viewState?.unit ?? 'metric', readFloorplanMetricNotationOverride(ctx) ?? 'meters');
@@ -49,7 +49,9 @@ function pointSegmentDistance(point, start, end) {
49
49
  const t = Math.max(0, Math.min(1, ((point[0] - start[0]) * dx + (point[1] - start[1]) * dy) / lengthSquared));
50
50
  return Math.hypot(point[0] - (start[0] + dx * t), point[1] - (start[1] + dy * t));
51
51
  }
52
- function structuralFaceProjections(wallStart, wallTangent, connectedWall) {
52
+ function structuralFaceProjections(
53
+ /** A point on the measured line (the centerline or one face) at the wall's start. */
54
+ wallStart, wallTangent, connectedWall) {
53
55
  if (isCurvedWall(connectedWall))
54
56
  return [];
55
57
  const dx = connectedWall.end[0] - connectedWall.start[0];
@@ -110,6 +112,83 @@ function wallStudFaceSpan(wall, siblings) {
110
112
  ];
111
113
  return { start, end, length: Math.max(0, endProjection - startProjection) };
112
114
  }
115
+ function nearPlanPoint(left, right) {
116
+ return Math.hypot(left[0] - right[0], left[1] - right[1]) <= WALL_CONNECTION_TOLERANCE;
117
+ }
118
+ /**
119
+ * One face of a straight wall, from end to end. `inner` stops at the near
120
+ * face of each connected wall (an interior face, the room size); `outer`
121
+ * runs on to the far face of a wall that turns the corner with it (an
122
+ * exterior face, the outside size). A wall that only abuts another (a T)
123
+ * stops at its near face either way, and a free end at the end cap.
124
+ */
125
+ function wallFaceSpan(wall, side, siblings, reach) {
126
+ const dx = wall.end[0] - wall.start[0];
127
+ const dy = wall.end[1] - wall.start[1];
128
+ const length = Math.hypot(dx, dy);
129
+ if (length <= 1e-6)
130
+ return null;
131
+ const tangent = [dx / length, dy / length];
132
+ const offset = getWallFaceOffsets(wall)[side];
133
+ const origin = [
134
+ wall.start[0] - tangent[1] * offset,
135
+ wall.start[1] + tangent[0] * offset,
136
+ ];
137
+ const resolveEnd = (endpoint, atStart) => {
138
+ const rest = atStart ? 0 : length;
139
+ let near = null;
140
+ let far = null;
141
+ for (const sibling of siblings) {
142
+ if (sibling.type !== 'wall' || sibling.id === wall.id)
143
+ continue;
144
+ if (pointSegmentDistance(endpoint, sibling.start, sibling.end) > WALL_CONNECTION_TOLERANCE) {
145
+ continue;
146
+ }
147
+ const corner = nearPlanPoint(endpoint, sibling.start) || nearPlanPoint(endpoint, sibling.end);
148
+ for (const projection of structuralFaceProjections(origin, tangent, sibling)) {
149
+ const inward = atStart ? projection : length - projection;
150
+ if (inward > 0 && inward < length) {
151
+ if (near === null || inward > (atStart ? near : length - near))
152
+ near = projection;
153
+ }
154
+ else if (corner && inward < 0 && inward > -length) {
155
+ if (far === null || inward < (atStart ? far : length - far))
156
+ far = projection;
157
+ }
158
+ }
159
+ }
160
+ if (reach === 'outer' && far !== null)
161
+ return far;
162
+ return near ?? rest;
163
+ };
164
+ const startProjection = resolveEnd(wall.start, true);
165
+ const endProjection = resolveEnd(wall.end, false);
166
+ if (endProjection - startProjection <= 1e-6)
167
+ return null;
168
+ return {
169
+ start: [origin[0] + tangent[0] * startProjection, origin[1] + tangent[1] * startProjection],
170
+ end: [origin[0] + tangent[0] * endProjection, origin[1] + tangent[1] * endProjection],
171
+ length: endProjection - startProjection,
172
+ };
173
+ }
174
+ function faceDimension(span, offsetNormal, ctx) {
175
+ return {
176
+ kind: 'dimension',
177
+ start: span.start,
178
+ end: span.end,
179
+ offsetNormal,
180
+ offsetDistance: 0.34,
181
+ extensionOvershoot: 0.08,
182
+ text: formatLength(span.length, ctx),
183
+ stroke: selectedStroke(ctx),
184
+ };
185
+ }
186
+ /**
187
+ * A selected wall's length, to its faces rather than its centerline: the
188
+ * interior face (ID) on the room side and the exterior face (OD) outside, as
189
+ * the dimension-faces preference asks. An interior partition has no outside,
190
+ * so it shows its clear span between the walls it runs to.
191
+ */
113
192
  export function buildWallContextualDimensions(node, ctx) {
114
193
  const length = getWallCurveLength(node);
115
194
  if (!Number.isFinite(length) || length <= 1e-6)
@@ -131,22 +210,30 @@ export function buildWallContextualDimensions(node, ctx) {
131
210
  const chordLength = Math.hypot(dx, dy);
132
211
  if (chordLength <= 1e-6)
133
212
  return null;
134
- const offsetNormal = contextualWallDimensionNormal(node, [-dy / chordLength, dx / chordLength], ctx.siblings);
135
- const span = node.frontSide === 'interior' && node.backSide === 'interior'
136
- ? wallStudFaceSpan(node, ctx.siblings)
137
- : { start: node.start, end: node.end, length: chordLength };
138
- if (span.length <= 1e-6)
213
+ const front = [-dy / chordLength, dx / chordLength];
214
+ const offsetNormal = contextualWallDimensionNormal(node, front, ctx.siblings);
215
+ if (node.frontSide === 'interior' && node.backSide === 'interior') {
216
+ const span = wallStudFaceSpan(node, ctx.siblings);
217
+ return span.length <= 1e-6 ? null : faceDimension(span, offsetNormal, ctx);
218
+ }
219
+ // `offsetNormal` points out of the wall's exterior (or its best guess at it).
220
+ const exteriorSide = offsetNormal[0] * front[0] + offsetNormal[1] * front[1] > 0 ? 'a' : 'b';
221
+ const interiorNormal = [cleanZero(-offsetNormal[0]), cleanZero(-offsetNormal[1])];
222
+ const faces = readFloorplanContext(ctx).wallDimensionFaces;
223
+ const inner = wallFaceSpan(node, exteriorSide === 'a' ? 'b' : 'a', ctx.siblings, 'inner');
224
+ const outer = wallFaceSpan(node, exteriorSide, ctx.siblings, 'outer');
225
+ const interior = faces === 'exterior' ? null : inner;
226
+ const exterior = faces === 'interior' ? null : outer;
227
+ if (interior && exterior && Math.abs(interior.length - exterior.length) < 0.001) {
228
+ return faceDimension(exterior, offsetNormal, ctx);
229
+ }
230
+ const children = [
231
+ ...(interior ? [faceDimension(interior, interiorNormal, ctx)] : []),
232
+ ...(exterior ? [faceDimension(exterior, offsetNormal, ctx)] : []),
233
+ ];
234
+ if (children.length === 0)
139
235
  return null;
140
- return {
141
- kind: 'dimension',
142
- start: span.start,
143
- end: span.end,
144
- offsetNormal,
145
- offsetDistance: 0.34,
146
- extensionOvershoot: 0.08,
147
- text: formatLength(span.length, ctx),
148
- stroke: selectedStroke(ctx),
149
- };
236
+ return children.length === 1 ? children[0] : { kind: 'group', children };
150
237
  }
151
238
  export function buildWallHostedOpeningContextualDimensions(node, ctx, options) {
152
239
  const wall = ctx.parent;
@@ -1 +1 @@
1
- {"version":3,"file":"curtain-opening-frame.d.ts","sourceRoot":"","sources":["../../src/wall/curtain-opening-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAIb,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,KAAK,cAAc,EAAgC,OAAO,EAAE,MAAM,OAAO,CAAA;AAElF,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,QAsBvF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,EAAE,KAAK,EAAE,MAAM;;;EAqClF;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,QAAQ,GAAG,UAAU,EAC9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM;IA8BJ,KAAK;IAAwB,MAAM;IAA+B,MAAM;EAClF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CASzB"}
1
+ {"version":3,"file":"curtain-opening-frame.d.ts","sourceRoot":"","sources":["../../src/wall/curtain-opening-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAMb,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,KAAK,cAAc,EAAgC,OAAO,EAAE,MAAM,OAAO,CAAA;AAElF,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,QAsBvF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,EAAE,KAAK,EAAE,MAAM;;;EAuClF;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,QAAQ,GAAG,UAAU,EAC9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM;IA8BJ,KAAK;IAAwB,MAAM;IAA+B,MAAM;EAClF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CASzB"}