@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,10 +1,11 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { emitter, useScene } from '@pascal-app/core';
3
+ import { emitter, usePascalI18n, useScene } from '@pascal-app/core';
4
4
  import { useMemo } from 'react';
5
5
  import { planRunHangerSlots } from './run-hangers.js';
6
6
  import SystemCheckPanel from './system-check-panel.js';
7
7
  export default function RunHangerInspector({ node }) {
8
+ const i18n = usePascalI18n();
8
9
  const nodes = useScene((state) => state.nodes);
9
10
  const slots = useMemo(() => planRunHangerSlots(node, nodes), [node, nodes]);
10
11
  if (!node.autoHangers)
@@ -22,12 +23,32 @@ export default function RunHangerInspector({ node }) {
22
23
  },
23
24
  });
24
25
  };
25
- return (_jsxs(_Fragment, { children: [_jsx(SystemCheckPanel, { nodeId: node.id, nodes: nodes }), _jsxs("section", { className: "space-y-2 border-t pt-3", children: [_jsx("h3", { className: "text-sm font-medium", children: "Individual hangers" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Positions are measured along each path segment. Changing spacing regenerates the numbered slots." }), _jsx("div", { className: "max-h-72 space-y-3 overflow-y-auto", children: slots.map((slot, index) => {
26
+ return (_jsxs(_Fragment, { children: [_jsx(SystemCheckPanel, { nodeId: node.id, nodes: nodes }), _jsxs("section", { className: "space-y-2 border-t pt-3", children: [_jsx("h3", { className: "text-sm font-medium", children: i18n._({
27
+ id: 'node.shared.runHangerInspector.individualHangers',
28
+ message: 'Individual hangers',
29
+ }) }), _jsx("p", { className: "text-xs text-muted-foreground", children: i18n._({
30
+ id: 'node.shared.runHangerInspector.positionsAreMeasuredAlongEachPath',
31
+ message: 'Positions are measured along each path segment. Changing spacing regenerates the numbered slots.',
32
+ }) }), _jsx("div", { className: "max-h-72 space-y-3 overflow-y-auto", children: slots.map((slot, index) => {
26
33
  const a = node.path[slot.segmentIndex];
27
34
  const b = node.path[slot.segmentIndex + 1];
28
35
  const length = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
29
36
  const hostId = node.hangerOverrides?.[slot.id]?.hostId ?? '';
30
- return (_jsxs("div", { className: "space-y-1 rounded border p-2 text-xs", children: [_jsxs("div", { className: "flex justify-between", children: [_jsxs("span", { children: ["Hanger ", index + 1, " \u00B7 segment ", slot.segmentIndex + 1] }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: slot.skipped, onChange: (event) => update(slot.id, { skipped: event.target.checked }) }), ' ', "Skip"] })] }), !slot.skipped && !slot.hanger && (_jsx("p", { role: "status", className: "text-amber-600 dark:text-amber-400", children: "No support within reach. Move the hanger or choose another host." })), _jsxs("label", { className: "flex justify-between", children: ["Position (m)", _jsx("input", { "aria-label": `Hanger ${index + 1} position in metres`, type: "number", min: 0, max: length, step: 0.1, defaultValue: Number((slot.fraction * length).toFixed(3)), className: "w-20 bg-transparent", onBlur: (event) => {
37
+ return (_jsxs("div", { className: "space-y-1 rounded border p-2 text-xs", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { children: i18n._({
38
+ id: 'node.shared.runHangerInspector.hangerOnSegment',
39
+ message: 'Hanger {number} · segment {segment}',
40
+ values: { number: index + 1, segment: slot.segmentIndex + 1 },
41
+ }) }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: slot.skipped, onChange: (event) => update(slot.id, { skipped: event.target.checked }) }), ' ', i18n._({ id: 'node.shared.runHangerInspector.skip', message: 'Skip' })] })] }), !slot.skipped && !slot.hanger && (_jsx("p", { role: "status", className: "text-amber-600 dark:text-amber-400", children: i18n._({
42
+ id: 'node.shared.runHangerInspector.noSupportWithinReachMoveThe',
43
+ message: 'No support within reach. Move the hanger or choose another host.',
44
+ }) })), _jsxs("label", { className: "flex justify-between", children: [i18n._({
45
+ id: 'node.shared.runHangerInspector.positionM',
46
+ message: 'Position (m)',
47
+ }), _jsx("input", { "aria-label": i18n._({
48
+ id: 'node.shared.runHangerInspector.positionLabel',
49
+ message: 'Hanger {number} position in metres',
50
+ values: { number: index + 1 },
51
+ }), type: "number", min: 0, max: length, step: 0.1, defaultValue: Number((slot.fraction * length).toFixed(3)), className: "w-20 bg-transparent", onBlur: (event) => {
31
52
  const value = event.target.valueAsNumber;
32
53
  if (Number.isFinite(value) &&
33
54
  value >= 0 &&
@@ -36,8 +57,21 @@ export default function RunHangerInspector({ node }) {
36
57
  update(slot.id, { fraction: value / length });
37
58
  else
38
59
  event.target.value = String(Number((slot.fraction * length).toFixed(3)));
39
- } }, `${slot.id}:${slot.fraction}`)] }), _jsxs("select", { "aria-label": `Hanger ${index + 1} support`, value: hostId, className: "w-full bg-background", onChange: (event) => update(slot.id, { hostId: event.target.value }), children: [_jsx("option", { value: "", children: "Automatic support" }), hostId && !hosts.some((host) => host.id === hostId) && (_jsx("option", { value: hostId, children: "Missing support" })), hosts.map((host) => (_jsxs("option", { value: host.id, children: [host.name || host.type, " \u00B7 ", host.id.slice(-6)] }, host.id)))] }), slot.hanger && (_jsx("button", { type: "button", className: "underline", onClick: () => emitter.emit('camera-controls:focus', {
60
+ } }, `${slot.id}:${slot.fraction}`)] }), _jsxs("select", { "aria-label": i18n._({
61
+ id: 'node.shared.runHangerInspector.supportLabel',
62
+ message: 'Hanger {number} support',
63
+ values: { number: index + 1 },
64
+ }), value: hostId, className: "w-full bg-background", onChange: (event) => update(slot.id, { hostId: event.target.value }), children: [_jsx("option", { value: "", children: i18n._({
65
+ id: 'node.shared.runHangerInspector.automaticSupport',
66
+ message: 'Automatic support',
67
+ }) }), hostId && !hosts.some((host) => host.id === hostId) && (_jsx("option", { value: hostId, children: i18n._({
68
+ id: 'node.shared.runHangerInspector.missingSupport',
69
+ message: 'Missing support',
70
+ }) })), hosts.map((host) => (_jsxs("option", { value: host.id, children: [host.name || host.type, " \u00B7 ", host.id.slice(-6)] }, host.id)))] }), slot.hanger && (_jsx("button", { type: "button", className: "underline", onClick: () => emitter.emit('camera-controls:focus', {
40
71
  nodeId: slot.hanger.hostId,
41
- }), children: "Reveal support" }))] }, slot.id));
72
+ }), children: i18n._({
73
+ id: 'node.shared.runHangerInspector.revealSupport',
74
+ message: 'Reveal support',
75
+ }) }))] }, slot.id));
42
76
  }) })] })] }));
43
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"system-check-panel.d.ts","sourceRoot":"","sources":["../../src/shared/system-check-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAIf,MAAM,kBAAkB,CAAA;AA0BzB,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,MAAM,EACN,KAAK,GACN,EAAE;IACD,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;CAClC,+BAyMA"}
1
+ {"version":3,"file":"system-check-panel.d.ts","sourceRoot":"","sources":["../../src/shared/system-check-panel.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAMf,MAAM,kBAAkB,CAAA;AAqDzB,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,MAAM,EACN,KAAK,GACN,EAAE;IACD,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;CAClC,+BAyQA"}
@@ -1,21 +1,49 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { emitter, getLevelElevations, summarizeSystemFor, } from '@pascal-app/core';
3
+ import { emitter, formatFixed, getLevelElevations, summarizeSystemFor, usePascalI18n, } from '@pascal-app/core';
4
4
  import { useViewer } from '@pascal-app/viewer';
5
5
  import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Crosshair, ShieldCheck, XCircle, } from 'lucide-react';
6
6
  import { useId, useMemo, useState } from 'react';
7
7
  import { checkDistributionSystems } from './system-checks.js';
8
8
  const CATEGORIES = [
9
- { id: 'all', label: 'All findings' },
10
- { id: 'open-end', label: 'Open ends' },
11
- { id: 'connection-mismatch', label: 'Connections' },
12
- { id: 'disconnected-branch', label: 'Separate branches' },
13
- { id: 'possible-intersection', label: 'Intersections' },
14
- { id: 'drainage', label: 'Drainage' },
15
- { id: 'unsupported-hanger', label: 'Hangers' },
9
+ {
10
+ id: 'all',
11
+ label: /* i18n */ { id: 'node.shared.systemCheckPanel.allFindings', message: 'All findings' },
12
+ },
13
+ {
14
+ id: 'open-end',
15
+ label: /* i18n */ { id: 'node.shared.systemCheckPanel.openEnds', message: 'Open ends' },
16
+ },
17
+ {
18
+ id: 'connection-mismatch',
19
+ label: /* i18n */ { id: 'node.shared.systemCheckPanel.connections', message: 'Connections' },
20
+ },
21
+ {
22
+ id: 'disconnected-branch',
23
+ label: /* i18n */ {
24
+ id: 'node.shared.systemCheckPanel.separateBranches',
25
+ message: 'Separate branches',
26
+ },
27
+ },
28
+ {
29
+ id: 'possible-intersection',
30
+ label: /* i18n */ {
31
+ id: 'node.shared.systemCheckPanel.intersections',
32
+ message: 'Intersections',
33
+ },
34
+ },
35
+ {
36
+ id: 'drainage',
37
+ label: /* i18n */ { id: 'node.shared.systemCheckPanel.drainage', message: 'Drainage' },
38
+ },
39
+ {
40
+ id: 'unsupported-hanger',
41
+ label: /* i18n */ { id: 'node.shared.systemCheckPanel.hangers', message: 'Hangers' },
42
+ },
16
43
  ];
17
44
  const categoryFor = (code) => ['slope-too-flat', 'slope-too-steep', 'trap-arm-too-long'].includes(code) ? 'drainage' : code;
18
45
  export default function SystemCheckPanel({ nodeId, nodes, }) {
46
+ const i18n = usePascalI18n();
19
47
  const contentId = useId();
20
48
  const [open, setOpen] = useState(false);
21
49
  const [filter, setFilter] = useState('all');
@@ -47,16 +75,67 @@ export default function SystemCheckPanel({ nodeId, nodes, }) {
47
75
  emitter.emit('camera-controls:focus', { nodeId: id });
48
76
  emitter.emit('selection:find-node', node);
49
77
  };
50
- return (_jsxs("section", { className: "border-t border-border/50", children: [_jsxs("button", { type: "button", className: "flex w-full items-center gap-2 px-3 py-3 text-left text-xs font-medium transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", "aria-expanded": open, "aria-controls": contentId, onClick: () => setOpen((value) => !value), children: [_jsx(ShieldCheck, { className: "size-4 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "flex-1", children: "System checks" }), open && (_jsx("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-[10px] tabular-nums text-muted-foreground", children: findings.length })), _jsx(ChevronDown, { className: `size-3.5 text-muted-foreground transition-transform ${open ? '' : '-rotate-90'}`, "aria-hidden": "true" })] }), open && (_jsxs("div", { id: contentId, className: "space-y-3 px-3 pb-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [_jsx("span", { children: "All systems" }), summary && (_jsxs("span", { className: "tabular-nums", title: "Selected connected system", children: ["Selected: ", summary.runCount, " ", summary.runCount === 1 ? 'run' : 'runs', " \u00B7", ' ', summary.runLengthM.toFixed(1), " m"] }))] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2.5 py-2", children: [_jsx(XCircle, { className: `size-4 ${errorCount ? 'text-red-500' : 'text-muted-foreground'}`, "aria-hidden": "true" }), _jsx("span", { className: "text-sm font-semibold tabular-nums", children: errorCount }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: "Errors" })] }), _jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2.5 py-2", children: [_jsx(AlertTriangle, { className: `size-4 ${warningCount ? 'text-amber-500' : 'text-muted-foreground'}`, "aria-hidden": "true" }), _jsx("span", { className: "text-sm font-semibold tabular-nums", children: warningCount }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: "Warnings" })] })] }), _jsxs("div", { className: "relative", children: [_jsx("select", { "aria-label": "Filter system checks", value: filter, onChange: (event) => setFilter(event.target.value), className: "h-9 w-full appearance-none rounded-lg border border-border bg-background px-3 pr-8 text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", children: CATEGORIES.map((category) => (_jsxs("option", { value: category.id, children: [category.label, " (", category.id === 'all'
78
+ return (_jsxs("section", { className: "border-t border-border/50", children: [_jsxs("button", { type: "button", className: "flex w-full items-center gap-2 px-3 py-3 text-left text-xs font-medium transition-colors hover:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring", "aria-expanded": open, "aria-controls": contentId, onClick: () => setOpen((value) => !value), children: [_jsx(ShieldCheck, { className: "size-4 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "flex-1", children: i18n._({ id: 'node.shared.systemCheckPanel.systemChecks', message: 'System checks' }) }), open && (_jsx("span", { className: "rounded-md bg-muted px-1.5 py-0.5 text-[10px] tabular-nums text-muted-foreground", children: findings.length })), _jsx(ChevronDown, { className: `size-3.5 text-muted-foreground transition-transform ${open ? '' : '-rotate-90'}`, "aria-hidden": "true" })] }), open && (_jsxs("div", { id: contentId, className: "space-y-3 px-3 pb-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: [_jsx("span", { children: i18n._({ id: 'node.shared.systemCheckPanel.allSystems', message: 'All systems' }) }), summary && (_jsx("span", { className: "tabular-nums", title: i18n._({
79
+ id: 'node.shared.systemCheckPanel.selectedConnectedSystem',
80
+ message: 'Selected connected system',
81
+ }), children: i18n._({
82
+ id: 'node.shared.systemCheckPanel.selectedRuns',
83
+ message: 'Selected: {count, plural, one {{number} run} other {{number} runs}} · {length} m',
84
+ values: {
85
+ count: summary.runCount,
86
+ number: String(summary.runCount),
87
+ length: formatFixed(summary.runLengthM, 1, i18n.getLocale()),
88
+ },
89
+ }) }))] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2.5 py-2", children: [_jsx(XCircle, { className: `size-4 ${errorCount ? 'text-red-500' : 'text-muted-foreground'}`, "aria-hidden": "true" }), _jsx("span", { className: "text-sm font-semibold tabular-nums", children: errorCount }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: i18n._({ id: 'node.shared.systemCheckPanel.errors', message: 'Errors' }) })] }), _jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2.5 py-2", children: [_jsx(AlertTriangle, { className: `size-4 ${warningCount ? 'text-amber-500' : 'text-muted-foreground'}`, "aria-hidden": "true" }), _jsx("span", { className: "text-sm font-semibold tabular-nums", children: warningCount }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: i18n._({ id: 'node.shared.systemCheckPanel.warnings', message: 'Warnings' }) })] })] }), _jsxs("div", { className: "relative", children: [_jsx("select", { "aria-label": i18n._({
90
+ id: 'node.shared.systemCheckPanel.filterSystemChecks',
91
+ message: 'Filter system checks',
92
+ }), value: filter, onChange: (event) => setFilter(event.target.value), className: "h-9 w-full appearance-none rounded-lg border border-border bg-background px-3 pr-8 text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring", children: CATEGORIES.map((category) => (_jsxs("option", { value: category.id, children: [i18n._(category.label), " (", category.id === 'all'
51
93
  ? findings.length
52
94
  : findings.filter((finding) => categoryFor(finding.code) === category.id)
53
- .length, ")"] }, category.id))) }), _jsx(ChevronDown, { className: "pointer-events-none absolute right-3 top-3 size-3.5 text-muted-foreground", "aria-hidden": "true" })] }), visibleFindings.length ? (_jsx("ul", { className: "max-h-72 space-y-2 overflow-y-auto overscroll-contain pr-1", "aria-label": "System findings", children: visibleFindings.map((finding, index) => {
95
+ .length, ")"] }, category.id))) }), _jsx(ChevronDown, { className: "pointer-events-none absolute right-3 top-3 size-3.5 text-muted-foreground", "aria-hidden": "true" })] }), visibleFindings.length ? (_jsx("ul", { className: "max-h-72 space-y-2 overflow-y-auto overscroll-contain pr-1", "aria-label": i18n._({
96
+ id: 'node.shared.systemCheckPanel.systemFindings',
97
+ message: 'System findings',
98
+ }), children: visibleFindings.map((finding, index) => {
54
99
  const error = finding.severity === 'error';
55
100
  const Icon = error ? XCircle : AlertTriangle;
56
- const label = CATEGORIES.find((category) => category.id === categoryFor(finding.code))?.label ??
57
- 'System finding';
58
- return (_jsxs("li", { className: "overflow-hidden rounded-lg border border-border/60 bg-muted/10 p-2.5", children: [_jsxs("div", { className: "mb-1.5 flex items-center gap-2", children: [_jsx(Icon, { className: `size-3.5 shrink-0 ${error ? 'text-red-500' : 'text-amber-500'}`, "aria-hidden": "true" }), _jsx("span", { className: "min-w-0 flex-1 text-xs font-medium", children: label }), _jsx("span", { className: `text-[10px] font-medium ${error ? 'text-red-600 dark:text-red-400' : 'text-amber-700 dark:text-amber-400'}`, children: error ? 'Error' : 'Warning' })] }), _jsx("p", { className: "break-words text-[11px] leading-relaxed text-muted-foreground", children: finding.message }), _jsx("div", { className: "mt-2 flex flex-wrap gap-1.5", children: finding.nodeIds.map((id) => (_jsxs("button", { type: "button", disabled: !nodes[id], title: `Locate ${nodes[id]?.name || nodes[id]?.type || 'item'} (${id})`, onClick: () => reveal(id), className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border/60 bg-background px-2 py-1 text-[10px] transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50", children: [_jsx(Crosshair, { className: "size-3 shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "truncate", children: nodes[id]?.name ||
101
+ const category = CATEGORIES.find((entry) => entry.id === categoryFor(finding.code));
102
+ const label = category
103
+ ? i18n._(category.label)
104
+ : i18n._({
105
+ id: 'node.shared.systemCheckPanel.systemFinding',
106
+ message: 'System finding',
107
+ });
108
+ return (_jsxs("li", { className: "overflow-hidden rounded-lg border border-border/60 bg-muted/10 p-2.5", children: [_jsxs("div", { className: "mb-1.5 flex items-center gap-2", children: [_jsx(Icon, { className: `size-3.5 shrink-0 ${error ? 'text-red-500' : 'text-amber-500'}`, "aria-hidden": "true" }), _jsx("span", { className: "min-w-0 flex-1 text-xs font-medium", children: label }), _jsx("span", { className: `text-[10px] font-medium ${error ? 'text-red-600 dark:text-red-400' : 'text-amber-700 dark:text-amber-400'}`, children: error
109
+ ? i18n._({ id: 'node.shared.systemCheckPanel.error', message: 'Error' })
110
+ : i18n._({
111
+ id: 'node.shared.systemCheckPanel.warning',
112
+ message: 'Warning',
113
+ }) })] }), _jsx("p", { className: "break-words text-[11px] leading-relaxed text-muted-foreground", children: finding.message }), _jsx("div", { className: "mt-2 flex flex-wrap gap-1.5", children: finding.nodeIds.map((id) => (_jsxs("button", { type: "button", disabled: !nodes[id], title: i18n._({
114
+ id: 'node.shared.systemCheckPanel.locate',
115
+ message: 'Locate {name} ({id})',
116
+ values: { name: nodes[id]?.name || nodes[id]?.type || id, id },
117
+ }), onClick: () => reveal(id), className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border/60 bg-background px-2 py-1 text-[10px] transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50", children: [_jsx(Crosshair, { className: "size-3 shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("span", { className: "truncate", children: nodes[id]?.name ||
59
118
  nodes[id]?.type.replaceAll('-', ' ') ||
60
- 'Missing item' }), _jsx(ChevronRight, { className: "size-3 shrink-0 text-muted-foreground", "aria-hidden": "true" })] }, id))) })] }, `${finding.code}:${finding.nodeIds.join(':')}:${index}`));
61
- }) })) : (_jsxs("div", { role: "status", className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border px-3 py-5 text-center", children: [_jsx(CheckCircle2, { className: "size-5 text-emerald-500", "aria-hidden": "true" }), _jsx("span", { className: "text-xs font-medium", children: findings.length ? 'No findings in this category' : 'No findings' }), filter !== 'all' && (_jsx("button", { type: "button", className: "text-[11px] text-muted-foreground underline underline-offset-4 hover:text-foreground", onClick: () => setFilter('all'), children: "Show all findings" }))] })), _jsxs("details", { className: "text-[10px] leading-relaxed text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer hover:text-foreground", children: "About these checks" }), _jsx("p", { className: "pt-1.5", children: "Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances." })] })] }))] }));
119
+ i18n._({
120
+ id: 'node.shared.systemCheckPanel.missingItem',
121
+ message: 'Missing item',
122
+ }) }), _jsx(ChevronRight, { className: "size-3 shrink-0 text-muted-foreground", "aria-hidden": "true" })] }, id))) })] }, `${finding.code}:${finding.nodeIds.join(':')}:${index}`));
123
+ }) })) : (_jsxs("div", { role: "status", className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border px-3 py-5 text-center", children: [_jsx(CheckCircle2, { className: "size-5 text-emerald-500", "aria-hidden": "true" }), _jsx("span", { className: "text-xs font-medium", children: findings.length
124
+ ? i18n._({
125
+ id: 'node.shared.systemCheckPanel.noFindingsInThisCategory',
126
+ message: 'No findings in this category',
127
+ })
128
+ : i18n._({
129
+ id: 'node.shared.systemCheckPanel.noFindings',
130
+ message: 'No findings',
131
+ }) }), filter !== 'all' && (_jsx("button", { type: "button", className: "text-[11px] text-muted-foreground underline underline-offset-4 hover:text-foreground", onClick: () => setFilter('all'), children: i18n._({
132
+ id: 'node.shared.systemCheckPanel.showAllFindings',
133
+ message: 'Show all findings',
134
+ }) }))] })), _jsxs("details", { className: "text-[10px] leading-relaxed text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer hover:text-foreground", children: i18n._({
135
+ id: 'node.shared.systemCheckPanel.aboutTheseChecks',
136
+ message: 'About these checks',
137
+ }) }), _jsx("p", { className: "pt-1.5", children: i18n._({
138
+ id: 'node.shared.systemCheckPanel.openEndsAndSeparateBranchesMay',
139
+ message: 'Open ends and separate branches may be intentional. Intersection checks use bounding boxes; inspect openings and clearances.',
140
+ }) })] })] }))] }));
62
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wall-attach-target.d.ts","sourceRoot":"","sources":["../../src/shared/wall-attach-target.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAUd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,QAAQ,CAAA;IACd,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAA;IACpB,iDAAiD;IACjD,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IACtB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,MAAM,SAAI,GACT,CAAC,MAAM,EAAE,MAAM,CAAC,CAKlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,SAAS,GAAG,IAAI,EAC/B,aAAa,CAAC,EAAE,SAAS,GACxB,OAAO,GAAG,IAAI,CA+BhB;AAWD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG;IACvD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAyCD,8EAA8E;AAC9E,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,WAAW,SAAuB,GACjC,kBAAkB,GAAG,IAAI,CA0C3B;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,SAAS,GAAG,IAAI,EAC/B,aAAa,CAAC,EAAE,SAAS,GACxB,OAAO,GAAG,IAAI,CAehB;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,MAAM,GAAG,IAAI,CAiChB;AAED;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAE/D;wEACwE;AACxE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAA;IACjB;+BAC2B;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,sDAAsD;IACtD,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;CAC1B,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,GAAG,gBAAgB,CAOnB"}
1
+ {"version":3,"file":"wall-attach-target.d.ts","sourceRoot":"","sources":["../../src/shared/wall-attach-target.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAYd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,QAAQ,CAAA;IACd,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAA;IACpB,iDAAiD;IACjD,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IACtB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,MAAM,SAAI,GACT,CAAC,MAAM,EAAE,MAAM,CAAC,CAKlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,SAAS,GAAG,IAAI,EAC/B,aAAa,CAAC,EAAE,SAAS,GACxB,OAAO,GAAG,IAAI,CA+BhB;AAWD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG;IACvD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAyCD,8EAA8E;AAC9E,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,WAAW,SAAuB,GACjC,kBAAkB,GAAG,IAAI,CA0C3B;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,aAAa,EAAE,SAAS,GAAG,IAAI,EAC/B,aAAa,CAAC,EAAE,SAAS,GACxB,OAAO,GAAG,IAAI,CAehB;AA2BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,MAAM,GAAG,IAAI,CAiChB;AAED;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAE/D;wEACwE;AACxE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAA;IACjB;+BAC2B;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,sDAAsD;IACtD,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;CAC1B,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,GAAG,gBAAgB,CAOnB"}
@@ -1,4 +1,4 @@
1
- import { collectLevelWallSegments, getScaledDimensions, getWallArcData, getWallCurveFrameAt, getWallCurveLength, isCurvedWall, nearestWallSegment, WALL_SNAP_DISTANCE_M, } from '@pascal-app/core';
1
+ import { collectLevelWallSegments, getDoorOpeningSize, getScaledDimensions, getWallArcData, getWallCurveFrameAt, getWallCurveLength, isCurvedWall, nearestWallSegment, openingHostFacing, WALL_SNAP_DISTANCE_M, } from '@pascal-app/core';
2
2
  export function projectWallLocalPointToPlan(wall, localX, localZ = 0) {
3
3
  const angle = -Math.atan2(wall.end[1] - wall.start[1], wall.end[0] - wall.start[0]);
4
4
  const c = Math.cos(angle);
@@ -156,8 +156,11 @@ const ALONG_WALL_ALIGN_THRESHOLD_M = 0.08;
156
156
  * footprint. */
157
157
  function wallAttachmentSpan(node) {
158
158
  if (node.type === 'door' || node.type === 'window') {
159
- const n = node;
160
- return { center: n.position[0], half: n.width / 2 };
159
+ const size = getDoorOpeningSize(node);
160
+ return {
161
+ center: node.position[0] - size.leafOffsetX * openingHostFacing(node),
162
+ half: size.width / 2,
163
+ };
161
164
  }
162
165
  if (node.type === 'item') {
163
166
  const item = node;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/shelf/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAUpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA2HpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CA2J5D,CAAA"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/shelf/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAWpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA2HpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CA4J5D,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { shelfSlots } from '@pascal-app/core';
2
+ import { staticBatchable } from '../shared/node-batch/batchable.js';
2
3
  import { restingFloorplanAffectedIds } from '../shared/resting-surface-plan.js';
3
4
  import { sanitizeShelfDimensions } from './dimensions.js';
4
5
  import { buildShelfFloorplan } from './floorplan.js';
@@ -154,6 +155,7 @@ export const shelfDefinition = {
154
155
  // catalog materials into `slots`.
155
156
  }),
156
157
  capabilities: {
158
+ batchable: staticBatchable,
157
159
  reveal: { phase: 'furnishing', style: 'drop', height: 0.3 },
158
160
  revealOnEdit: ['width', 'depth', 'height', 'thickness', 'rows', 'columns', 'style'],
159
161
  movable: { axes: ['x', 'z'], gridSnap: true },
@@ -8,7 +8,7 @@ import { type UndergroundEdge } from '@pascal-app/viewer';
8
8
  * in a soft feather and a thin light line marks the cut itself.
9
9
  *
10
10
  * The footprint is a signed-distance field baked on the CPU into a small texture when the
11
- * footprints change (the polygons the grade ring is drawn from), so the ground's mask costs one
11
+ * footprints change, so the ground's mask costs one
12
12
  * texture fetch and one noise lookup per fragment, whatever the building's outline. How far the
13
13
  * hole is open (0 to 1, eased, 0 in a capture) is the viewer's `groundHoleOpenNode`.
14
14
  */
@@ -70,8 +70,8 @@ export declare function groundHoleShadowNode(): () => any;
70
70
  */
71
71
  export declare function groundHoleColorNode(shadeColor: string): import("three/webgpu").Node<"vec3">;
72
72
  /**
73
- * Feeds the hole the footprints it is cut over (the polygons the grade ring runs along: the level
74
- * shown and the ones between it and grade), and says to the rest of the viewer whether the scene
73
+ * Feeds the hole the footprints it is cut over (the level shown and the ones between it and
74
+ * grade), and says to the rest of the viewer whether the scene
75
75
  * has a level below grade at all (`present`): the ground materials carry the hole's mask, and the
76
76
  * eye's fill light is mounted, from then on, once, so that changing floors only changes uniforms.
77
77
  *
@@ -18,7 +18,7 @@ import { EDGE_LOOKS } from './underground-edge.js';
18
18
  * in a soft feather and a thin light line marks the cut itself.
19
19
  *
20
20
  * The footprint is a signed-distance field baked on the CPU into a small texture when the
21
- * footprints change (the polygons the grade ring is drawn from), so the ground's mask costs one
21
+ * footprints change, so the ground's mask costs one
22
22
  * texture fetch and one noise lookup per fragment, whatever the building's outline. How far the
23
23
  * hole is open (0 to 1, eased, 0 in a capture) is the viewer's `groundHoleOpenNode`.
24
24
  */
@@ -263,8 +263,8 @@ export function groundHoleColorNode(shadeColor) {
263
263
  return mix(shaded, lineColor, line);
264
264
  }
265
265
  /**
266
- * Feeds the hole the footprints it is cut over (the polygons the grade ring runs along: the level
267
- * shown and the ones between it and grade), and says to the rest of the viewer whether the scene
266
+ * Feeds the hole the footprints it is cut over (the level shown and the ones between it and
267
+ * grade), and says to the rest of the viewer whether the scene
268
268
  * has a level below grade at all (`present`): the ground materials carry the hole's mask, and the
269
269
  * eye's fill light is mounted, from then on, once, so that changing floors only changes uniforms.
270
270
  *
@@ -1,4 +1,3 @@
1
- import type { TerrainField } from '@pascal-app/core';
2
1
  import { type BufferGeometry, type Material } from 'three';
3
2
  import { MeshBasicNodeMaterial } from 'three/webgpu';
4
3
  /** Presentation-only meshes are never picked: clicks fall through to what lies under them. */
@@ -16,24 +15,18 @@ export declare function horizonVeilMaterial(groundColor: string, lot: ReadonlyAr
16
15
  cz: number;
17
16
  radius: number;
18
17
  }): MeshBasicNodeMaterial;
19
- /** The grade ring's ribbon along one outline where the ground meets a level below grade. */
20
- export declare function gradeRingGeometry(outline: ReadonlyArray<Point>, field: TerrainField | null): BufferGeometry;
21
- export declare function gradeRingMaterial(): MeshBasicNodeMaterial;
22
18
  /**
23
19
  * Drawn only while the ground is veiled: the veil of one solid ground surface (the same geometry
24
- * in the same place), or the grade ring. A direct child of the site, as the surfaces are, so the
25
- * captures find it (`siteGround`) and hide it with the site's other surfaces.
26
- *
27
- * `shows` says when a live view draws it: `'window'` (a sheet: only where the ground window veils
28
- * a hillside in the eye's way; wholesale the ground is a hole, not a sheet) or `'veiled'` (the
29
- * ring: wherever any ground is veiled). A capture shows both by setting `visible` itself.
20
+ * in the same place). A direct child of the site, as the surfaces are, so the captures find it
21
+ * (`siteGround`) and hide it with the site's other surfaces. A live view draws it only where the
22
+ * ground window veils a hillside in the eye's way (wholesale the ground is a hole, not a sheet); a
23
+ * capture shows it by setting `visible` itself.
30
24
  */
31
- export declare function GroundVeil({ geometry, material, position, rotation, shows, }: {
25
+ export declare function GroundVeil({ geometry, material, position, rotation, }: {
32
26
  geometry: BufferGeometry;
33
27
  material: Material;
34
28
  position?: [number, number, number];
35
29
  rotation?: [number, number, number];
36
- shows?: 'window' | 'veiled';
37
30
  }): import("react").JSX.Element;
38
31
  export {};
39
32
  //# sourceMappingURL=ground-veil.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ground-veil.d.ts","sourceRoot":"","sources":["../../src/site/ground-veil.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAUpD,OAAO,EAAE,KAAK,cAAc,EAAc,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAatE,OAAO,EAAE,qBAAqB,EAAa,MAAM,cAAc,CAAA;AAW/D,8FAA8F;AAC9F,eAAO,MAAM,WAAW,YAAW,CAAA;AAKnC,KAAK,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AA6BtC,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,yBAErD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,EACzB,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,yBAMnD;AASD,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAC7B,KAAK,EAAE,YAAY,GAAG,IAAI,GACzB,cAAc,CAGhB;AAED,wBAAgB,iBAAiB,0BAShC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAC5B,+BAiBA"}
1
+ {"version":3,"file":"ground-veil.d.ts","sourceRoot":"","sources":["../../src/site/ground-veil.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,cAAc,EAAc,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEtE,OAAO,EAAE,qBAAqB,EAAa,MAAM,cAAc,CAAA;AAQ/D,8FAA8F;AAC9F,eAAO,MAAM,WAAW,YAAW,CAAA;AAKnC,KAAK,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AA6BtC,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,yBAErD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,EACzB,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,yBAMnD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC,+BAaA"}
@@ -1,16 +1,13 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { anyGroundVeiled, groundWindowEnabledNode, inGroundWindowNode, SITE_GROUND, UNDERGROUND_RING, undergroundAmbianceNode, useViewer, } from '@pascal-app/viewer';
2
+ import { groundWindowEnabledNode, inGroundWindowNode, SITE_GROUND, useViewer, } from '@pascal-app/viewer';
3
3
  import { DoubleSide } from 'three';
4
- import { color, float, mix, mrt, output, positionWorld, select, smoothstep, vec2, vec4, } from 'three/tsl';
4
+ import { color, float, mrt, output, positionWorld, select, smoothstep, vec2, vec4 } from 'three/tsl';
5
5
  import { MeshBasicNodeMaterial } from 'three/webgpu';
6
- import { buildPatternedRibbon } from './line-ribbon.js';
7
6
  import { insideLotNode } from './lot-mask.js';
8
- import { buildDrapedPolyline } from './terrain-drape.js';
9
7
  // The ground over a level below grade. Wholesale (a level fully below grade, the ground on Auto)
10
8
  // the solid ground stays and a hole opens in it (`ground-hole.ts`); the veil sheets here are the
11
9
  // faint see-through ground of the ground window (a hillside in the eye's way) and of a capture
12
- // (which sets the solid ground aside and shows them), and the grade ring is drawn where the ground
13
- // meets the level below grade, in either.
10
+ // (which sets the solid ground aside and shows them).
14
11
  /** Presentation-only meshes are never picked: clicks fall through to what lies under them. */
15
12
  export const noopRaycast = () => { };
16
13
  /** How much of the ground shows as a veil: enough to read where grade is, and no more. */
@@ -52,35 +49,14 @@ export function horizonVeilMaterial(groundColor, lot, bounds) {
52
49
  const outsideLot = insideLotNode(lot, positionWorld.xz).not();
53
50
  return veilMaterial(groundColor, select(outsideLot, fade, float(0)));
54
51
  }
55
- /** The grade ring: dark as the lot line, a little narrower, just over the ground. */
56
- const GRADE_RING_COLOR = '#1c1917';
57
- const GRADE_RING_WIDTH = 0.16;
58
- const GRADE_RING_LIFT = 0.015;
59
- /** One run, never broken: a ribbon pattern with no gap. */
60
- const UNBROKEN = [Number.POSITIVE_INFINITY, 0];
61
- /** The grade ring's ribbon along one outline where the ground meets a level below grade. */
62
- export function gradeRingGeometry(outline, field) {
63
- const drape = buildDrapedPolyline({ points: outline, field, lift: GRADE_RING_LIFT, closed: true });
64
- return buildPatternedRibbon(drape.positions, UNBROKEN, GRADE_RING_WIDTH);
65
- }
66
- export function gradeRingMaterial() {
67
- const material = new MeshBasicNodeMaterial({ color: GRADE_RING_COLOR, side: DoubleSide });
68
- // Under the ground's ambiance the ring is a light rim: a dark ring would vanish in the dark mode.
69
- material.colorNode = mix(color(GRADE_RING_COLOR), color(UNDERGROUND_RING), undergroundAmbianceNode());
70
- return material;
71
- }
72
52
  /**
73
53
  * Drawn only while the ground is veiled: the veil of one solid ground surface (the same geometry
74
- * in the same place), or the grade ring. A direct child of the site, as the surfaces are, so the
75
- * captures find it (`siteGround`) and hide it with the site's other surfaces.
76
- *
77
- * `shows` says when a live view draws it: `'window'` (a sheet: only where the ground window veils
78
- * a hillside in the eye's way; wholesale the ground is a hole, not a sheet) or `'veiled'` (the
79
- * ring: wherever any ground is veiled). A capture shows both by setting `visible` itself.
54
+ * in the same place). A direct child of the site, as the surfaces are, so the captures find it
55
+ * (`siteGround`) and hide it with the site's other surfaces. A live view draws it only where the
56
+ * ground window veils a hillside in the eye's way (wholesale the ground is a hole, not a sheet); a
57
+ * capture shows it by setting `visible` itself.
80
58
  */
81
- export function GroundVeil({ geometry, material, position, rotation, shows = 'window', }) {
82
- const veiled = useViewer((state) => shows === 'veiled'
83
- ? anyGroundVeiled(state)
84
- : state.groundMode === 'auto' && state.groundWindowVeiled);
59
+ export function GroundVeil({ geometry, material, position, rotation, }) {
60
+ const veiled = useViewer((state) => state.groundMode === 'auto' && state.groundWindowVeiled);
85
61
  return (_jsx("mesh", { geometry: geometry, material: material, position: position, raycast: noopRaycast, rotation: rotation, userData: { [SITE_GROUND]: 'veil', pascalExport: 'strip' }, visible: veiled }));
86
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/site/panel.tsx"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,wBAAgB,aAAa,uCA+W5B;eAWc,aAAa"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/site/panel.tsx"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,wBAAgB,aAAa,uCAyc5B;eAWc,aAAa"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useScene } from '@pascal-app/core';
3
+ import { usePascalI18n, useScene } from '@pascal-app/core';
4
4
  import { ActionButton, ActionGroup, describeSiteEdges, dropInLot, PanelSection, PanelWrapper, useParcelProvider, } from '@pascal-app/editor';
5
5
  import { useViewer } from '@pascal-app/viewer';
6
6
  import { MapPin, Search } from 'lucide-react';
@@ -14,6 +14,7 @@ const METRES_PER_FOOT = 0.3048;
14
14
  * (`setParcelProvider`) and is hidden when the host has none.
15
15
  */
16
16
  export function SiteNodePanel() {
17
+ const i18n = usePascalI18n();
17
18
  const selectedId = useViewer((s) => s.selection.selectedIds[0]);
18
19
  // The selected site node, else THE site node: the sidebar's Site header
19
20
  // mounts this panel directly, where nothing may be selected.
@@ -84,11 +85,14 @@ export function SiteNodePanel() {
84
85
  return;
85
86
  const address = query.trim();
86
87
  if (!address) {
87
- setStatus('Type an address first.');
88
+ setStatus(i18n._({ id: 'node.site.panel.typeAnAddressFirst', message: 'Type an address first.' }));
88
89
  return;
89
90
  }
90
91
  setBusy(true);
91
- setStatus('Looking up the parcel and the streets around it…');
92
+ setStatus(i18n._({
93
+ id: 'node.site.panel.lookingUpTheParcel',
94
+ message: 'Looking up the parcel and the streets around it…',
95
+ }));
92
96
  try {
93
97
  const result = await dropInLot({
94
98
  address,
@@ -102,12 +106,14 @@ export function SiteNodePanel() {
102
106
  setStatus(result.message);
103
107
  }
104
108
  catch (error) {
105
- setStatus(error instanceof Error ? error.message : 'Parcel lookup failed.');
109
+ setStatus(error instanceof Error
110
+ ? error.message
111
+ : i18n._({ id: 'node.site.panel.parcelLookupFailed', message: 'Parcel lookup failed.' }));
106
112
  }
107
113
  finally {
108
114
  setBusy(false);
109
115
  }
110
- }, [node, picked, query]);
116
+ }, [node, picked, query, i18n]);
111
117
  if (!node)
112
118
  return null;
113
119
  const setbacks = node.setbacks;
@@ -130,17 +136,28 @@ export function SiteNodePanel() {
130
136
  [key]: feet * METRES_PER_FOOT,
131
137
  },
132
138
  });
133
- }, placeholder: optional ? 'side' : '0' }, `${key}-${setbacks?.[key] ?? 'none'}`), _jsx("span", { className: "text-muted-foreground text-xs", children: "ft" })] })] }, key));
134
- return (_jsxs(PanelWrapper, { title: "Site", children: [parcelProvider ? (_jsxs(PanelSection, { title: "Address", children: [_jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Street address" }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => {
139
+ }, placeholder: optional ? i18n._({ id: 'node.site.panel.side', message: 'side' }) : '0' }, `${key}-${setbacks?.[key] ?? 'none'}`), _jsx("span", { className: "text-muted-foreground text-xs", children: "ft" })] })] }, key));
140
+ return (_jsxs(PanelWrapper, { title: i18n._({ id: 'node.site.panel.site', message: 'Site' }), children: [parcelProvider ? (_jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.address', message: 'Address' }), children: [_jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.streetAddress', message: 'Street address' }) }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => {
135
141
  setQuery(event.target.value);
136
142
  setPicked(null);
137
- }, placeholder: "1200 W Cass St, Tampa, FL", value: query })] }), suggestions.length > 0 ? (_jsx("ul", { className: "max-h-44 space-y-0.5 overflow-y-auto rounded-md border border-border/70 bg-card p-1", children: suggestions.map((s) => (_jsx("li", { children: _jsxs("button", { className: "flex w-full items-start gap-2 rounded px-2 py-1.5 text-left text-foreground text-xs hover:bg-muted", onClick: () => {
143
+ }, placeholder: i18n._({
144
+ id: 'node.site.panel.n1200WCassStTampaFl',
145
+ message: '1200 W Cass St, Tampa, FL',
146
+ }), value: query })] }), suggestions.length > 0 ? (_jsx("ul", { className: "max-h-44 space-y-0.5 overflow-y-auto rounded-md border border-border/70 bg-card p-1", children: suggestions.map((s) => (_jsx("li", { children: _jsxs("button", { className: "flex w-full items-start gap-2 rounded px-2 py-1.5 text-left text-foreground text-xs hover:bg-muted", onClick: () => {
138
147
  setPicked(s);
139
148
  setQuery(s.label ?? [s.line1, s.line2].filter(Boolean).join(', '));
140
149
  setSuggestions([]);
141
- }, type: "button", children: [_jsx(MapPin, { className: "mt-0.5 size-3 shrink-0 text-muted-foreground" }), _jsx("span", { children: s.label ?? [s.line1, s.line2].filter(Boolean).join(', ') })] }) }, `${s.label}-${s.lat}-${s.lng}`))) })) : null, _jsx(ActionGroup, { children: _jsx(ActionButton, { disabled: busy, icon: _jsx(Search, { className: "size-4" }), label: busy ? 'Finding…' : 'Find parcel', onClick: findParcel }) }), status ? _jsx("p", { className: "text-muted-foreground text-xs", children: status }) : null] })) : null, node.parcel ? (_jsxs(PanelSection, { title: "Parcel", children: [_jsx(Row, { label: "APN", value: node.parcel.apn || '—' }), _jsx(Row, { label: "County", value: node.parcel.county || '—' }), _jsx(Row, { label: "Lot area", value: node.parcel.lotAreaSqFt
150
+ }, type: "button", children: [_jsx(MapPin, { className: "mt-0.5 size-3 shrink-0 text-muted-foreground" }), _jsx("span", { children: s.label ?? [s.line1, s.line2].filter(Boolean).join(', ') })] }) }, `${s.label}-${s.lat}-${s.lng}`))) })) : null, _jsx(ActionGroup, { children: _jsx(ActionButton, { disabled: busy, icon: _jsx(Search, { className: "size-4" }), label: busy
151
+ ? i18n._({ id: 'node.site.panel.finding', message: 'Finding…' })
152
+ : i18n._({ id: 'node.site.panel.findParcel', message: 'Find parcel' }), onClick: findParcel }) }), status ? _jsx("p", { className: "text-muted-foreground text-xs", children: status }) : null] })) : null, node.parcel ? (_jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.parcel', message: 'Parcel' }), children: [_jsx(Row, { label: i18n._({ id: 'node.site.panel.apn', message: 'APN' }), value: node.parcel.apn || '—' }), _jsx(Row, { label: i18n._({ id: 'node.site.panel.county', message: 'County' }), value: node.parcel.county || '—' }), _jsx(Row, { label: i18n._({ id: 'node.site.panel.lotArea', message: 'Lot area' }), value: node.parcel.lotAreaSqFt
142
153
  ? `${Math.round(node.parcel.lotAreaSqFt).toLocaleString()} sq ft`
143
- : '—' }), _jsx(Row, { label: "Source", value: node.parcel.layer || node.parcel.source || '—' }), node.parcel.notes?.length ? (_jsx("p", { className: "text-muted-foreground text-xs leading-snug", children: node.parcel.notes.join(' ') })) : null] })) : null, _jsxs(PanelSection, { title: "Setbacks", children: [setbackField('front', 'Front'), setbackField('side', 'Side'), setbackField('rear', 'Rear'), setbackField('left', 'Left (override)', true), setbackField('right', 'Right (override)', true), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Source / citation" }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", defaultValue: node.setbacksSource ?? '', onBlur: (event) => update({ setbacksSource: event.target.value || undefined }), placeholder: "e.g. Tampa LDC \u00A727-156" }, node.setbacksSource ?? '')] }), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Zone" }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", defaultValue: node.zone ?? '', onBlur: (event) => update({ zone: event.target.value || undefined }), placeholder: "e.g. RS-60" }, node.zone ?? '')] })] }), _jsxs(PanelSection, { title: "Project look", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Save the current lighting and display as this project's default. Personal display changes stay in this browser." }), _jsxs(ActionGroup, { children: [_jsx(ActionButton, { label: "Save current look", onClick: () => {
154
+ : '—' }), _jsx(Row, { label: i18n._({ id: 'node.site.panel.source', message: 'Source' }), value: node.parcel.layer || node.parcel.source || '—' }), node.parcel.notes?.length ? (_jsx("p", { className: "text-muted-foreground text-xs leading-snug", children: node.parcel.notes.join(' ') })) : null] })) : null, _jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.setbacks', message: 'Setbacks' }), children: [setbackField('front', i18n._({ id: 'node.site.setback.front', message: 'Front' })), setbackField('side', i18n._({ id: 'node.site.setback.side', message: 'Side' })), setbackField('rear', i18n._({ id: 'node.site.setback.rear', message: 'Rear' })), setbackField('left', i18n._({ id: 'node.site.setback.leftOverride', message: 'Left (override)' }), true), setbackField('right', i18n._({ id: 'node.site.setback.rightOverride', message: 'Right (override)' }), true), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.sourceCitation', message: 'Source / citation' }) }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", defaultValue: node.setbacksSource ?? '', onBlur: (event) => update({ setbacksSource: event.target.value || undefined }), placeholder: i18n._({
155
+ id: 'node.site.panel.eGTampaLdc27156',
156
+ message: 'e.g. Tampa LDC §27-156',
157
+ }) }, node.setbacksSource ?? '')] }), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.zone', message: 'Zone' }) }), _jsx("input", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", defaultValue: node.zone ?? '', onBlur: (event) => update({ zone: event.target.value || undefined }), placeholder: i18n._({ id: 'node.site.panel.eGRs60', message: 'e.g. RS-60' }) }, node.zone ?? '')] })] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.projectLook', message: 'Project look' }), children: [_jsx("p", { className: "text-muted-foreground text-xs", children: i18n._({
158
+ id: 'node.site.panel.saveTheCurrentLightingAndDisplay',
159
+ message: "Save the current lighting and display as this project's default. Personal display changes stay in this browser.",
160
+ }) }), _jsxs(ActionGroup, { children: [_jsx(ActionButton, { label: i18n._({ id: 'node.site.panel.saveCurrentLook', message: 'Save current look' }), onClick: () => {
144
161
  const viewer = useViewer.getState();
145
162
  const look = viewer.sceneAppearance;
146
163
  update({
@@ -164,9 +181,32 @@ export function SiteNodePanel() {
164
181
  },
165
182
  });
166
183
  viewer.resetProjectLook();
167
- } }), _jsx(ActionButton, { label: "Use project look", onClick: () => useViewer.getState().resetProjectLook() })] })] }), _jsxs(PanelSection, { title: "Terrain", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { checked: node.showGround !== false, onChange: (event) => update({ showGround: event.target.checked }), type: "checkbox" }), _jsx("span", { className: "text-muted-foreground", children: "Show ground" })] }), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Contour interval (site plan and 3D)" }), _jsxs("select", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => update({ contourIntervalIn: Number(event.target.value) }), value: String(node.contourIntervalIn ?? 12), children: [_jsx("option", { value: "0", children: "none" }), _jsx("option", { value: "6", children: "every 6 in" }), _jsx("option", { value: "12", children: "every 12 in" }), _jsx("option", { value: "24", children: "every 24 in" })] })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { checked: node.contours3d ?? false, onChange: (event) => update({ contours3d: event.target.checked }), type: "checkbox" }), _jsx("span", { className: "text-muted-foreground", children: "Show the contour lines in 3D" })] }), node.terrainContours ? (_jsxs("p", { className: "text-muted-foreground text-xs", children: [node.terrainContours.lines.length, " surveyed lines at ", node.terrainContours.intervalFt, ' ', "ft (", node.terrainContours.datum, ") \u2014 ", node.terrainContours.source ?? 'survey'] })) : (_jsx("p", { className: "text-muted-foreground text-xs", children: "No surveyed lines \u2014 contours are drawn from the sculpted ground." }))] }), _jsxs(PanelSection, { title: "Orientation", children: [_jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "Front (street) edge" }), _jsxs("select", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => update({
184
+ } }), _jsx(ActionButton, { label: i18n._({ id: 'node.site.panel.useProjectLook', message: 'Use project look' }), onClick: () => useViewer.getState().resetProjectLook() })] })] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.terrain', message: 'Terrain' }), children: [_jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { checked: node.showGround !== false, onChange: (event) => update({ showGround: event.target.checked }), type: "checkbox" }), _jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.showGround', message: 'Show ground' }) })] }), _jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({
185
+ id: 'node.site.panel.contourIntervalSitePlanAnd3d',
186
+ message: 'Contour interval (site plan and 3D)',
187
+ }) }), _jsxs("select", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => update({ contourIntervalIn: Number(event.target.value) }), value: String(node.contourIntervalIn ?? 12), children: [_jsx("option", { value: "0", children: i18n._({ id: 'node.site.panel.none', message: 'none' }) }), _jsx("option", { value: "6", children: i18n._({ id: 'node.site.panel.every6In', message: 'every 6 in' }) }), _jsx("option", { value: "12", children: i18n._({ id: 'node.site.panel.every12In', message: 'every 12 in' }) }), _jsx("option", { value: "24", children: i18n._({ id: 'node.site.panel.every24In', message: 'every 24 in' }) })] })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { checked: node.contours3d ?? false, onChange: (event) => update({ contours3d: event.target.checked }), type: "checkbox" }), _jsx("span", { className: "text-muted-foreground", children: i18n._({
188
+ id: 'node.site.panel.showTheContourLinesIn3d',
189
+ message: 'Show the contour lines in 3D',
190
+ }) })] }), node.terrainContours ? (_jsx("p", { className: "text-muted-foreground text-xs", children: i18n._({
191
+ id: 'node.site.panel.surveyedContours',
192
+ message: '{count, plural, one {{lineCount} surveyed line} other {{lineCount} surveyed lines}} at {interval} ft ({datum}) — {source}',
193
+ values: {
194
+ count: node.terrainContours.lines.length,
195
+ lineCount: String(node.terrainContours.lines.length),
196
+ interval: node.terrainContours.intervalFt,
197
+ datum: node.terrainContours.datum,
198
+ source: node.terrainContours.source ??
199
+ i18n._({ id: 'node.site.panel.survey', message: 'survey' }),
200
+ },
201
+ }) })) : (_jsx("p", { className: "text-muted-foreground text-xs", children: i18n._({
202
+ id: 'node.site.panel.noSurveyedLinesContoursAreDrawn',
203
+ message: 'No surveyed lines — contours are drawn from the sculpted ground.',
204
+ }) }))] }), _jsxs(PanelSection, { title: i18n._({ id: 'node.site.panel.orientation', message: 'Orientation' }), children: [_jsxs("label", { className: "space-y-1 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.frontStreetEdge', message: 'Front (street) edge' }) }), _jsxs("select", { className: "w-full rounded-md border border-border/70 bg-background px-2 py-1.5 text-foreground", onChange: (event) => update({
168
205
  frontEdge: event.target.value === '' ? undefined : Number(event.target.value),
169
- }), value: node.frontEdge == null ? '' : String(node.frontEdge), children: [_jsx("option", { value: "", children: "Auto \u2014 most north-facing edge" }), edges.map((edge) => (_jsx("option", { value: String(edge.index), children: edge.label }, edge.index)))] })] }), _jsxs("label", { className: "flex items-center justify-between gap-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: "North rotation" }), _jsxs("span", { className: "flex items-center gap-1", children: [_jsx("input", { className: "w-20 rounded-md border border-border/70 bg-background px-2 py-1 text-right text-foreground", defaultValue: String(Math.round((((node.northRotation ?? 0) * 180) / Math.PI) * 10) / 10), inputMode: "decimal", onFocus: (event) => event.target.select(), onBlur: (event) => {
206
+ }), value: node.frontEdge == null ? '' : String(node.frontEdge), children: [_jsx("option", { value: "", children: i18n._({
207
+ id: 'node.site.panel.autoMostNorthFacingEdge',
208
+ message: 'Auto — most north-facing edge',
209
+ }) }), edges.map((edge) => (_jsx("option", { value: String(edge.index), children: edge.label }, edge.index)))] })] }), _jsxs("label", { className: "flex items-center justify-between gap-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: i18n._({ id: 'node.site.panel.northRotation', message: 'North rotation' }) }), _jsxs("span", { className: "flex items-center gap-1", children: [_jsx("input", { className: "w-20 rounded-md border border-border/70 bg-background px-2 py-1 text-right text-foreground", defaultValue: String(Math.round((((node.northRotation ?? 0) * 180) / Math.PI) * 10) / 10), inputMode: "decimal", onFocus: (event) => event.target.select(), onBlur: (event) => {
170
210
  const deg = Number(event.target.value.trim());
171
211
  if (!Number.isFinite(deg))
172
212
  return;